summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/bearer/corewlan/qcorewlanengine.mm38
-rw-r--r--src/plugins/doc/snippets/code/src_plugins_platforms_qnx_qqnxwindow.cpp52
-rw-r--r--src/plugins/imageformats/jpeg/qjpeghandler.cpp6
-rw-r--r--src/plugins/platforms/android/androidjniinput.cpp30
-rw-r--r--src/plugins/platforms/android/androidjniinput.h4
-rw-r--r--src/plugins/platforms/android/qandroidinputcontext.cpp368
-rw-r--r--src/plugins/platforms/android/qandroidinputcontext.h41
-rw-r--r--src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp16
-rw-r--r--src/plugins/platforms/android/qandroidplatformmenubar.h2
-rw-r--r--src/plugins/platforms/cocoa/cocoa.pro16
-rw-r--r--src/plugins/platforms/cocoa/main.mm2
-rw-r--r--src/plugins/platforms/cocoa/messages.cpp18
-rw-r--r--src/plugins/platforms/cocoa/messages.h10
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.h5
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.mm8
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h9
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm86
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplication.h3
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplication.mm8
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h26
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm95
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.mm179
-rw-r--r--src/plugins/platforms/cocoa/qcocoaclipboard.mm6
-rw-r--r--src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm31
-rw-r--r--src/plugins/platforms/cocoa/qcocoacursor.mm20
-rw-r--r--src/plugins/platforms/cocoa/qcocoadrag.mm12
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.h5
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm132
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm66
-rw-r--r--src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm70
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.h31
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm616
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.h57
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.mm122
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.h11
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm59
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintrospection.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoakeymapper.h13
-rw-r--r--src/plugins/platforms/cocoa/qcocoakeymapper.mm29
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm80
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.h7
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.mm130
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.h3
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.mm202
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuloader.h36
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuloader.mm158
-rw-r--r--src/plugins/platforms/cocoa/qcocoanativeinterface.mm48
-rw-r--r--src/plugins/platforms/cocoa/qcocoansmenu.h22
-rw-r--r--src/plugins/platforms/cocoa/qcocoansmenu.mm151
-rw-r--r--src/plugins/platforms/cocoa/qcocoaprintdevice.mm22
-rw-r--r--src/plugins/platforms/cocoa/qcocoascreen.h14
-rw-r--r--src/plugins/platforms/cocoa/qcocoascreen.mm272
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemsettings.mm78
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemtrayicon.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm90
-rw-r--r--src/plugins/platforms/cocoa/qcocoatheme.h6
-rw-r--r--src/plugins/platforms/cocoa/qcocoatheme.mm89
-rw-r--r--src/plugins/platforms/cocoa/qcocoavulkaninstance.h75
-rw-r--r--src/plugins/platforms/cocoa/qcocoavulkaninstance.mm95
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.h26
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm827
-rw-r--r--src/plugins/platforms/cocoa/qmacclipboard.h4
-rw-r--r--src/plugins/platforms/cocoa/qmacclipboard.mm14
-rw-r--r--src/plugins/platforms/cocoa/qmultitouch_mac.mm2
-rw-r--r--src/plugins/platforms/cocoa/qnsview.h96
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm1939
-rw-r--r--src/plugins/platforms/cocoa/qnsview_accessibility.mm (renamed from src/plugins/platforms/cocoa/qnsviewaccessibility.mm)43
-rw-r--r--src/plugins/platforms/cocoa/qnsview_complextext.mm315
-rw-r--r--src/plugins/platforms/cocoa/qnsview_dragging.mm300
-rw-r--r--src/plugins/platforms/cocoa/qnsview_drawing.mm167
-rw-r--r--src/plugins/platforms/cocoa/qnsview_gestures.mm169
-rw-r--r--src/plugins/platforms/cocoa/qnsview_keys.mm262
-rw-r--r--src/plugins/platforms/cocoa/qnsview_menus.mm133
-rw-r--r--src/plugins/platforms/cocoa/qnsview_mouse.mm624
-rw-r--r--src/plugins/platforms/cocoa/qnsview_tablet.mm223
-rw-r--r--src/plugins/platforms/cocoa/qnsview_touch.mm100
-rw-r--r--src/plugins/platforms/cocoa/qnswindow.h1
-rw-r--r--src/plugins/platforms/cocoa/qnswindow.mm72
-rw-r--r--src/plugins/platforms/cocoa/qnswindowdelegate.h14
-rw-r--r--src/plugins/platforms/cocoa/qnswindowdelegate.mm41
-rw-r--r--src/plugins/platforms/cocoa/qpaintengine_mac.mm56
-rw-r--r--src/plugins/platforms/cocoa/qpaintengine_mac_p.h8
-rw-r--r--src/plugins/platforms/cocoa/qprintengine_mac.mm10
-rw-r--r--src/plugins/platforms/cocoa/qprintengine_mac_p.h2
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp6
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp4
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h4
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h2
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h2
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h10
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp4
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h2
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.cpp2
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.h4
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp6
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h2
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp8
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h2
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp2
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfshooks.cpp2
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsintegration.cpp3
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/eglfs_brcm.pro1
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro1
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp115
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro1
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro1
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp6
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp5
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/eglfs_kms_vsp2.pro1
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/eglfs_mali.pro1
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/eglfs_rcar.pro1
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/eglfs_viv.pro1
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/eglfs_viv_wl.pro1
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro1
-rw-r--r--src/plugins/platforms/eglfs/eglfsdeviceintegration.pro2
-rw-r--r--src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h6
-rw-r--r--src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm14
-rw-r--r--src/plugins/platforms/ios/qiosclipboard.mm24
-rw-r--r--src/plugins/platforms/ios/qioseventdispatcher.mm39
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.mm15
-rw-r--r--src/plugins/platforms/ios/qiosintegration.mm8
-rw-r--r--src/plugins/platforms/ios/qiosmenu.mm32
-rw-r--r--src/plugins/platforms/ios/qiosmessagedialog.h1
-rw-r--r--src/plugins/platforms/ios/qiosmessagedialog.mm20
-rw-r--r--src/plugins/platforms/ios/qiosoptionalplugininterface.h4
-rw-r--r--src/plugins/platforms/ios/qiosscreen.mm35
-rw-r--r--src/plugins/platforms/ios/qiostextinputoverlay.mm85
-rw-r--r--src/plugins/platforms/ios/qiostextresponder.h10
-rw-r--r--src/plugins/platforms/ios/qiostextresponder.mm56
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.h2
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.mm36
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm6
-rw-r--r--src/plugins/platforms/ios/quiaccessibilityelement.h7
-rw-r--r--src/plugins/platforms/ios/quiaccessibilityelement.mm13
-rw-r--r--src/plugins/platforms/ios/quiview.h15
-rw-r--r--src/plugins/platforms/ios/quiview.mm117
-rw-r--r--src/plugins/platforms/ios/quiview_accessibility.mm7
-rw-r--r--src/plugins/platforms/platforms.pro2
-rw-r--r--src/plugins/platforms/qnx/qqnxglcontext.cpp2
-rw-r--r--src/plugins/platforms/qnx/qqnxglobal.cpp6
-rw-r--r--src/plugins/platforms/qnx/qqnxintegration.cpp70
-rw-r--r--src/plugins/platforms/qnx/qqnxintegration.h22
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp45
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventhandler.h2
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventthread.cpp156
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventthread.h26
-rw-r--r--src/plugins/platforms/qnx/qqnxwindow.cpp37
-rw-r--r--src/plugins/platforms/wasm/main.cpp54
-rw-r--r--src/plugins/platforms/wasm/qtloader.js516
-rw-r--r--src/plugins/platforms/wasm/qtlogo.svg67
-rw-r--r--src/plugins/platforms/wasm/qwasmbackingstore.cpp165
-rw-r--r--src/plugins/platforms/wasm/qwasmbackingstore.h70
-rw-r--r--src/plugins/platforms/wasm/qwasmcompositor.cpp721
-rw-r--r--src/plugins/platforms/wasm/qwasmcompositor.h169
-rw-r--r--src/plugins/platforms/wasm/qwasmcursor.cpp131
-rw-r--r--src/plugins/platforms/wasm/qwasmcursor.h43
-rw-r--r--src/plugins/platforms/wasm/qwasmeventdispatcher.cpp181
-rw-r--r--src/plugins/platforms/wasm/qwasmeventdispatcher.h64
-rw-r--r--src/plugins/platforms/wasm/qwasmeventtranslator.cpp555
-rw-r--r--src/plugins/platforms/wasm/qwasmeventtranslator.h210
-rw-r--r--src/plugins/platforms/wasm/qwasmfontdatabase.cpp86
-rw-r--r--src/plugins/platforms/wasm/qwasmfontdatabase.h49
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.cpp219
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.h92
-rw-r--r--src/plugins/platforms/wasm/qwasmopenglcontext.cpp147
-rw-r--r--src/plugins/platforms/wasm/qwasmopenglcontext.h63
-rw-r--r--src/plugins/platforms/wasm/qwasmscreen.cpp118
-rw-r--r--src/plugins/platforms/wasm/qwasmscreen.h82
-rw-r--r--src/plugins/platforms/wasm/qwasmstylepixmaps_p.h183
-rw-r--r--src/plugins/platforms/wasm/qwasmtheme.cpp50
-rw-r--r--src/plugins/platforms/wasm/qwasmtheme.h56
-rw-r--r--src/plugins/platforms/wasm/qwasmwindow.cpp401
-rw-r--r--src/plugins/platforms/wasm/qwasmwindow.h127
-rw-r--r--src/plugins/platforms/wasm/wasm.json3
-rw-r--r--src/plugins/platforms/wasm/wasm.pro65
-rw-r--r--src/plugins/platforms/wasm/wasm_shell.html61
-rw-r--r--src/plugins/platforms/windows/main.cpp2
-rw-r--r--src/plugins/platforms/windows/openglblacklists/default.json11
-rw-r--r--src/plugins/platforms/windows/qtwindowsglobal.h26
-rw-r--r--src/plugins/platforms/windows/qwin10helpers.cpp4
-rw-r--r--src/plugins/platforms/windows/qwin10helpers.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsbackingstore.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowsbackingstore.h4
-rw-r--r--src/plugins/platforms/windows/qwindowsclipboard.cpp31
-rw-r--r--src/plugins/platforms/windows/qwindowsclipboard.h3
-rw-r--r--src/plugins/platforms/windows/qwindowscombase.h4
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp211
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.h42
-rw-r--r--src/plugins/platforms/windows/qwindowscursor.cpp33
-rw-r--r--src/plugins/platforms/windows/qwindowscursor.h14
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.cpp59
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.h6
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.cpp73
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.h6
-rw-r--r--src/plugins/platforms/windows/qwindowsdropdataobject.cpp8
-rw-r--r--src/plugins/platforms/windows/qwindowsdropdataobject.h2
-rw-r--r--src/plugins/platforms/windows/qwindowseglcontext.cpp16
-rw-r--r--src/plugins/platforms/windows/qwindowseglcontext.h4
-rw-r--r--src/plugins/platforms/windows/qwindowsgdiintegration.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowsgdiintegration.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowsglcontext.cpp18
-rw-r--r--src/plugins/platforms/windows/qwindowsglcontext.h14
-rw-r--r--src/plugins/platforms/windows/qwindowsinputcontext.cpp19
-rw-r--r--src/plugins/platforms/windows/qwindowsinputcontext.h7
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.cpp48
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.h11
-rw-r--r--src/plugins/platforms/windows/qwindowsinternalmimedata.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowsinternalmimedata.h2
-rw-r--r--src/plugins/platforms/windows/qwindowskeymapper.cpp165
-rw-r--r--src/plugins/platforms/windows/qwindowskeymapper.h10
-rw-r--r--src/plugins/platforms/windows/qwindowsmenu.h8
-rw-r--r--src/plugins/platforms/windows/qwindowsmime.cpp90
-rw-r--r--src/plugins/platforms/windows/qwindowsmime.h6
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.cpp175
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.h4
-rw-r--r--src/plugins/platforms/windows/qwindowsnativeinterface.cpp17
-rw-r--r--src/plugins/platforms/windows/qwindowsole.cpp21
-rw-r--r--src/plugins/platforms/windows/qwindowsole.h10
-rw-r--r--src/plugins/platforms/windows/qwindowsopenglcontext.h14
-rw-r--r--src/plugins/platforms/windows/qwindowsopengltester.cpp112
-rw-r--r--src/plugins/platforms/windows/qwindowsopengltester.h13
-rw-r--r--src/plugins/platforms/windows/qwindowspointerhandler.cpp667
-rw-r--r--src/plugins/platforms/windows/qwindowspointerhandler.h82
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.cpp34
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.h8
-rw-r--r--src/plugins/platforms/windows/qwindowsservices.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowsservices.h4
-rw-r--r--src/plugins/platforms/windows/qwindowssystemtrayicon.h2
-rw-r--r--src/plugins/platforms/windows/qwindowstabletsupport.cpp35
-rw-r--r--src/plugins/platforms/windows/qwindowstabletsupport.h35
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.cpp36
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.h7
-rw-r--r--src/plugins/platforms/windows/qwindowsthreadpoolrunner.h14
-rw-r--r--src/plugins/platforms/windows/qwindowsvulkaninstance.cpp33
-rw-r--r--src/plugins/platforms/windows/qwindowsvulkaninstance.h7
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp195
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.h21
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp17
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h8
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.cpp12
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h12
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.cpp15
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h16
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.cpp13
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h12
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.cpp13
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h8
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp17
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h42
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.cpp26
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.h15
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.cpp13
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h20
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp13
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h16
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp15
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h12
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.cpp13
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h10
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.cpp13
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h12
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp13
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h24
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp31
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h43
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.cpp13
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h10
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp8
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiautils.h16
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.cpp13
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h12
-rw-r--r--src/plugins/platforms/windows/windows.pri6
-rw-r--r--src/plugins/platforms/winrt/main.cpp2
-rw-r--r--src/plugins/platforms/winrt/qwinrtbackingstore.cpp22
-rw-r--r--src/plugins/platforms/winrt/qwinrtbackingstore.h5
-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.cpp5
-rw-r--r--src/plugins/platforms/winrt/qwinrtcursor.cpp65
-rw-r--r--src/plugins/platforms/winrt/qwinrtcursor.h3
-rw-r--r--src/plugins/platforms/winrt/qwinrtdrag.cpp27
-rw-r--r--src/plugins/platforms/winrt/qwinrtdrag.h4
-rw-r--r--src/plugins/platforms/winrt/qwinrteglcontext.h2
-rw-r--r--src/plugins/platforms/winrt/qwinrteventdispatcher.h2
-rw-r--r--src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp30
-rw-r--r--src/plugins/platforms/winrt/qwinrtfiledialoghelper.h2
-rw-r--r--src/plugins/platforms/winrt/qwinrtfileengine.cpp25
-rw-r--r--src/plugins/platforms/winrt/qwinrtfileengine.h4
-rw-r--r--src/plugins/platforms/winrt/qwinrtinputcontext.cpp6
-rw-r--r--src/plugins/platforms/winrt/qwinrtintegration.cpp17
-rw-r--r--src/plugins/platforms/winrt/qwinrtintegration.h5
-rw-r--r--src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp11
-rw-r--r--src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h2
-rw-r--r--src/plugins/platforms/winrt/qwinrtscreen.cpp136
-rw-r--r--src/plugins/platforms/winrt/qwinrtscreen.h11
-rw-r--r--src/plugins/platforms/winrt/qwinrtservices.cpp10
-rw-r--r--src/plugins/platforms/winrt/qwinrtservices.h2
-rw-r--r--src/plugins/platforms/winrt/qwinrtwindow.cpp2
-rw-r--r--src/plugins/platforms/winrt/qwinrtwindow.h2
-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.cpp789
-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.cpp158
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.h76
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.cpp141
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.h75
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.cpp167
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.h76
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.cpp232
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.h83
-rw-r--r--src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.cpp497
-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.cpp136
-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.pro4
-rw-r--r--src/plugins/platforms/xcb/README27
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp4
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp8
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.cpp207
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.h31
-rw-r--r--src/plugins/platforms/xcb/qxcbclipboard.cpp124
-rw-r--r--src/plugins/platforms/xcb/qxcbclipboard.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp972
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h169
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp599
-rw-r--r--src/plugins/platforms/xcb/qxcbcursor.cpp6
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.cpp336
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.h15
-rw-r--r--src/plugins/platforms/xcb/qxcbeventdispatcher.cpp162
-rw-r--r--src/plugins/platforms/xcb/qxcbeventdispatcher.h117
-rw-r--r--src/plugins/platforms/xcb/qxcbeventqueue.cpp383
-rw-r--r--src/plugins/platforms/xcb/qxcbeventqueue.h162
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp42
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.h1
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp869
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.h5
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.cpp72
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.h15
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp22
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.h4
-rw-r--r--src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp41
-rw-r--r--src/plugins/platforms/xcb/qxcbsystemtraytracker.h4
-rw-r--r--src/plugins/platforms/xcb/qxcbvulkaninstance.cpp29
-rw-r--r--src/plugins/platforms/xcb/qxcbvulkaninstance.h3
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp416
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h26
-rw-r--r--src/plugins/platforms/xcb/xcb-static/xcb-static.pro5
-rw-r--r--src/plugins/platforms/xcb/xcb_qpa_lib.pro20
-rw-r--r--src/plugins/platformthemes/flatpak/flatpak.json3
-rw-r--r--src/plugins/platformthemes/flatpak/flatpak.pro17
-rw-r--r--src/plugins/platformthemes/platformthemes.pro2
-rw-r--r--src/plugins/platformthemes/xdgdesktopportal/main.cpp (renamed from src/plugins/platformthemes/flatpak/main.cpp)16
-rw-r--r--src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp (renamed from src/plugins/platformthemes/flatpak/qflatpakfiledialog.cpp)128
-rw-r--r--src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog_p.h (renamed from src/plugins/platformthemes/flatpak/qflatpakfiledialog_p.h)28
-rw-r--r--src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp (renamed from src/plugins/platformthemes/flatpak/qflatpaktheme.cpp)84
-rw-r--r--src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h (renamed from src/plugins/platformthemes/flatpak/qflatpaktheme.h)18
-rw-r--r--src/plugins/platformthemes/xdgdesktopportal/xdgdesktopportal.json3
-rw-r--r--src/plugins/platformthemes/xdgdesktopportal/xdgdesktopportal.pro17
-rw-r--r--src/plugins/printsupport/cups/qcupsprintengine.cpp13
-rw-r--r--src/plugins/printsupport/cups/qcupsprintengine_p.h1
-rw-r--r--src/plugins/printsupport/cups/qcupsprintersupport.cpp78
-rw-r--r--src/plugins/printsupport/cups/qppdprintdevice.cpp80
-rw-r--r--src/plugins/printsupport/cups/qppdprintdevice.h2
-rw-r--r--src/plugins/printsupport/windows/qwindowsprintdevice.cpp149
-rw-r--r--src/plugins/printsupport/windows/qwindowsprintdevice.h51
-rw-r--r--src/plugins/printsupport/windows/qwindowsprintersupport.h3
-rw-r--r--src/plugins/sqldrivers/configure.json2
-rw-r--r--src/plugins/sqldrivers/configure.pri14
-rw-r--r--src/plugins/sqldrivers/mysql/qsql_mysql.cpp12
-rw-r--r--src/plugins/sqldrivers/odbc/qsql_odbc.cpp11
-rw-r--r--src/plugins/sqldrivers/psql/qsql_psql.cpp7
-rw-r--r--src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp44
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac.mm136
-rw-r--r--src/plugins/styles/windowsvista/qwindowsvistastyle.cpp32
-rw-r--r--src/plugins/styles/windowsvista/qwindowsvistastyle_p.h43
-rw-r--r--src/plugins/styles/windowsvista/qwindowsxpstyle.cpp16
-rw-r--r--src/plugins/styles/windowsvista/qwindowsxpstyle_p.h42
407 files changed, 22293 insertions, 8255 deletions
diff --git a/src/plugins/bearer/corewlan/qcorewlanengine.mm b/src/plugins/bearer/corewlan/qcorewlanengine.mm
index 341d3bccf2..c3dd49ff3e 100644
--- a/src/plugins/bearer/corewlan/qcorewlanengine.mm
+++ b/src/plugins/bearer/corewlan/qcorewlanengine.mm
@@ -62,33 +62,29 @@ extern "C" { // Otherwise it won't find CWKeychain* symbols at link time
#include <ifaddrs.h>
@interface QT_MANGLE_NAMESPACE(QNSListener) : NSObject <CWEventDelegate>
-{
- NSNotificationCenter *notificationCenter;
- CWWiFiClient *client;
- QCoreWlanEngine *engine;
- NSLock *locker;
-}
-- (void)powerStateDidChangeForWiFiInterfaceWithName:(NSString *)interfaceName;
-- (void)remove;
-- (void)setEngine:(QCoreWlanEngine *)coreEngine;
-- (QCoreWlanEngine *)engine;
-- (void)dealloc;
@property (assign) QCoreWlanEngine* engine;
@end
-@implementation QT_MANGLE_NAMESPACE(QNSListener)
+@implementation QT_MANGLE_NAMESPACE(QNSListener) {
+ NSNotificationCenter *notificationCenter;
+ CWWiFiClient *client;
+ QCoreWlanEngine *engine;
+ NSLock *locker;
+}
-- (id) init
+- (instancetype)init
{
- [locker lock];
- QMacAutoReleasePool pool;
- notificationCenter = [NSNotificationCenter defaultCenter];
- client = [CWWiFiClient sharedWiFiClient];
- client.delegate = self;
- [client startMonitoringEventWithType:CWEventTypePowerDidChange error:nil];
- [locker unlock];
+ 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;
}
@@ -300,7 +296,7 @@ void QScanThread::getUserConfigurations()
if(airportPlist != nil) {
NSDictionary *prefNetDict = [airportPlist objectForKey:@"PreferredNetworks"];
- NSArray *thisSsidarray = [prefNetDict valueForKey:@"SSID_STR"];
+ NSArray<NSString *> *thisSsidarray = [prefNetDict valueForKey:@"SSID_STR"];
for (NSString *ssidkey in thisSsidarray) {
QString thisSsid = QString::fromNSString(ssidkey);
if(!userProfiles.contains(thisSsid)) {
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
new file mode 100644
index 0000000000..ce82533c3e
--- /dev/null
+++ b/src/plugins/doc/snippets/code/src_plugins_platforms_qnx_qqnxwindow.cpp
@@ -0,0 +1,52 @@
+/***************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+//! [0]
+ QQuickView *view = new QQuickView(parent);
+ view->create();
+ QGuiApplication::platformNativeInterface()->setWindowProperty(view->handle(), "qnxWindowGroup",
+ group);
+//! [0]
+
+//! [1]
+ QQuickView *view = new QQuickView(parent);
+ view->create();
+ QGuiApplication::platformNativeInterface()->setWindowProperty(view->handle(), "qnxWindowGroup",
+ QVariant());
+//! [1]
diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.cpp b/src/plugins/imageformats/jpeg/qjpeghandler.cpp
index 1cdc28c077..e52a19703c 100644
--- a/src/plugins/imageformats/jpeg/qjpeghandler.cpp
+++ b/src/plugins/imageformats/jpeg/qjpeghandler.cpp
@@ -493,10 +493,10 @@ static inline void set_text(const QImage &image, j_compress_ptr cinfo, const QSt
{
const QMap<QString, QString> text = qt_getImageText(image, description);
for (auto it = text.begin(), end = text.end(); it != end; ++it) {
- QByteArray comment = it.key().toLatin1();
+ QByteArray comment = it.key().toUtf8();
if (!comment.isEmpty())
comment += ": ";
- comment += it.value().toLatin1();
+ comment += it.value().toUtf8();
if (comment.length() > 65530)
comment.truncate(65530);
jpeg_write_marker(cinfo, JPEG_COM, (const JOCTET *)comment.constData(), comment.size());
@@ -904,7 +904,7 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
for (jpeg_saved_marker_ptr marker = info.marker_list; marker != NULL; marker = marker->next) {
if (marker->marker == JPEG_COM) {
QString key, value;
- QString s = QString::fromLatin1((const char *)marker->data, marker->data_length);
+ QString s = QString::fromUtf8((const char *)marker->data, marker->data_length);
int index = s.indexOf(QLatin1String(": "));
if (index == -1 || s.indexOf(QLatin1Char(' ')) < index) {
key = QLatin1String("Description");
diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp
index dabab553c2..9cdc5de0e1 100644
--- a/src/plugins/platforms/android/androidjniinput.cpp
+++ b/src/plugins/platforms/android/androidjniinput.cpp
@@ -58,7 +58,6 @@ using namespace QtAndroid;
namespace QtAndroidInput
{
-
static bool m_ignoreMouseEvents = false;
static bool m_softwareKeyboardVisible = false;
static QRect m_softwareKeyboardRect;
@@ -124,11 +123,12 @@ namespace QtAndroidInput
return m_softwareKeyboardRect;
}
- void updateHandles(int mode, QPoint cursor, QPoint anchor, bool rtl)
+ void updateHandles(int mode, QPoint editMenuPos, uint32_t editButtons, QPoint cursor, QPoint anchor, bool rtl)
{
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "updateHandles", "(IIIIIZ)V",
- mode, cursor.x(), cursor.y(), anchor.x(),
- anchor.y(), rtl);
+ QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "updateHandles", "(IIIIIIIIZ)V",
+ 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)
@@ -173,7 +173,7 @@ namespace QtAndroidInput
QWindowSystemInterface::handleMouseEvent(tlw,
localPos,
globalPos,
- Qt::MouseButtons(Qt::LeftButton));
+ Qt::MouseButtons(m_mouseGrabber ? Qt::LeftButton : Qt::NoButton));
}
static void mouseWheel(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y, jfloat hdelta, jfloat vdelta)
@@ -195,6 +195,20 @@ namespace QtAndroidInput
angleDelta);
}
+ void releaseMouse(int x, int y)
+ {
+ 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));
+ }
+
static void longPress(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
{
QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext();
@@ -805,8 +819,10 @@ namespace QtAndroidInput
QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext();
if (inputContext && qGuiApp) {
inputContext->emitInputPanelVisibleChanged();
- if (!visibility)
+ if (!visibility) {
inputContext->emitKeyboardRectChanged();
+ QMetaObject::invokeMethod(inputContext, "hideSelectionHandles", Qt::QueuedConnection);
+ }
}
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << "@@@ KEYBOARDVISIBILITYCHANGED" << inputContext;
diff --git a/src/plugins/platforms/android/androidjniinput.h b/src/plugins/platforms/android/androidjniinput.h
index c09b426f49..2e2470ae8f 100644
--- a/src/plugins/platforms/android/androidjniinput.h
+++ b/src/plugins/platforms/android/androidjniinput.h
@@ -58,9 +58,11 @@ namespace QtAndroidInput
// Software keyboard support
// cursor/selection handles
- void updateHandles(int handleCount, QPoint cursor = QPoint(), QPoint anchor = QPoint(), bool rtl = false);
+ 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 releaseMouse(int x, int y);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp
index c46a435db1..c5cd0b92d9 100644
--- a/src/plugins/platforms/android/qandroidinputcontext.cpp
+++ b/src/plugins/platforms/android/qandroidinputcontext.cpp
@@ -64,6 +64,29 @@
QT_BEGIN_NAMESPACE
+template <typename T>
+class ScopedValueChangeBack
+{
+public:
+ ScopedValueChangeBack(T &variable, T newValue)
+ : m_oldValue(variable),
+ m_variable(variable)
+ {
+ m_variable = newValue;
+ }
+ inline void setOldValue()
+ {
+ m_variable = m_oldValue;
+ }
+ ~ScopedValueChangeBack()
+ {
+ setOldValue();
+ }
+private:
+ T m_oldValue;
+ T &m_variable;
+};
+
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";
@@ -76,6 +99,11 @@ static jfieldID m_selectionStartFieldID = 0;
static jfieldID m_startOffsetFieldID = 0;
static jfieldID m_textFieldID = 0;
+static void runOnQtThread(const std::function<void()> &func)
+{
+ QMetaObject::invokeMethod(m_androidInputContext, "safeCall", Qt::BlockingQueuedConnection, Q_ARG(std::function<void()>, func));
+}
+
static jboolean beginBatchEdit(JNIEnv */*env*/, jobject /*thiz*/)
{
if (!m_androidInputContext)
@@ -84,10 +112,9 @@ static jboolean beginBatchEdit(JNIEnv */*env*/, jobject /*thiz*/)
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug("@@@ BEGINBATCH");
#endif
-
- return m_androidInputContext->beginBatchEdit();
-
- return JNI_TRUE;
+ jboolean res;
+ runOnQtThread([&res]{res = m_androidInputContext->beginBatchEdit();});
+ return res;
}
static jboolean endBatchEdit(JNIEnv */*env*/, jobject /*thiz*/)
@@ -99,9 +126,9 @@ static jboolean endBatchEdit(JNIEnv */*env*/, jobject /*thiz*/)
qDebug("@@@ ENDBATCH");
#endif
- return m_androidInputContext->endBatchEdit();
-
- return JNI_TRUE;
+ jboolean res;
+ runOnQtThread([&res]{res = m_androidInputContext->endBatchEdit();});
+ return res;
}
@@ -118,7 +145,9 @@ static jboolean commitText(JNIEnv *env, jobject /*thiz*/, jstring text, jint new
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << "@@@ COMMIT" << str << newCursorPosition;
#endif
- return m_androidInputContext->commitText(str, newCursorPosition);
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->commitText(str, newCursorPosition);});
+ return res;
}
static jboolean deleteSurroundingText(JNIEnv */*env*/, jobject /*thiz*/, jint leftLength, jint rightLength)
@@ -129,7 +158,9 @@ static jboolean deleteSurroundingText(JNIEnv */*env*/, jobject /*thiz*/, jint le
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << "@@@ DELETE" << leftLength << rightLength;
#endif
- return m_androidInputContext->deleteSurroundingText(leftLength, rightLength);
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->deleteSurroundingText(leftLength, rightLength);});
+ return res;
}
static jboolean finishComposingText(JNIEnv */*env*/, jobject /*thiz*/)
@@ -140,7 +171,9 @@ static jboolean finishComposingText(JNIEnv */*env*/, jobject /*thiz*/)
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug("@@@ FINISH");
#endif
- return m_androidInputContext->finishComposingText();
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->finishComposingText();});
+ return res;
}
static jint getCursorCapsMode(JNIEnv */*env*/, jobject /*thiz*/, jint reqModes)
@@ -148,7 +181,9 @@ static jint getCursorCapsMode(JNIEnv */*env*/, jobject /*thiz*/, jint reqModes)
if (!m_androidInputContext)
return 0;
- return m_androidInputContext->getCursorCapsMode(reqModes);
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->getCursorCapsMode(reqModes);});
+ return res;
}
static jobject getExtractedText(JNIEnv *env, jobject /*thiz*/, int hintMaxChars, int hintMaxLines, jint flags)
@@ -156,8 +191,8 @@ static jobject getExtractedText(JNIEnv *env, jobject /*thiz*/, int hintMaxChars,
if (!m_androidInputContext)
return 0;
- const QAndroidInputContext::ExtractedText &extractedText =
- m_androidInputContext->getExtractedText(hintMaxChars, hintMaxLines, flags);
+ 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;
@@ -182,7 +217,8 @@ static jstring getSelectedText(JNIEnv *env, jobject /*thiz*/, jint flags)
if (!m_androidInputContext)
return 0;
- const QString &text = m_androidInputContext->getSelectedText(flags);
+ QString text;
+ runOnQtThread([&]{text = m_androidInputContext->getSelectedText(flags);});
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << "@@@ GETSEL" << text;
#endif
@@ -196,7 +232,8 @@ static jstring getTextAfterCursor(JNIEnv *env, jobject /*thiz*/, jint length, ji
if (!m_androidInputContext)
return 0;
- const QString &text = m_androidInputContext->getTextAfterCursor(length, flags);
+ QString text;
+ runOnQtThread([&]{text = m_androidInputContext->getTextAfterCursor(length, flags);});
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << "@@@ GETA" << length << text;
#endif
@@ -208,7 +245,8 @@ static jstring getTextBeforeCursor(JNIEnv *env, jobject /*thiz*/, jint length, j
if (!m_androidInputContext)
return 0;
- const QString &text = m_androidInputContext->getTextBeforeCursor(length, flags);
+ QString text;
+ runOnQtThread([&]{text = m_androidInputContext->getTextBeforeCursor(length, flags);});
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << "@@@ GETB" << length << text;
#endif
@@ -228,7 +266,9 @@ static jboolean setComposingText(JNIEnv *env, jobject /*thiz*/, jstring text, ji
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << "@@@ SET" << str << newCursorPosition;
#endif
- return m_androidInputContext->setComposingText(str, newCursorPosition);
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->setComposingText(str, newCursorPosition);});
+ return res;
}
static jboolean setComposingRegion(JNIEnv */*env*/, jobject /*thiz*/, jint start, jint end)
@@ -239,7 +279,9 @@ static jboolean setComposingRegion(JNIEnv */*env*/, jobject /*thiz*/, jint start
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << "@@@ SETR" << start << end;
#endif
- return m_androidInputContext->setComposingRegion(start, end);
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->setComposingRegion(start, end);});
+ return res;
}
@@ -251,7 +293,10 @@ static jboolean setSelection(JNIEnv */*env*/, jobject /*thiz*/, jint start, jint
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << "@@@ SETSEL" << start << end;
#endif
- return m_androidInputContext->setSelection(start, end);
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->setSelection(start, end);});
+ return res;
+
}
static jboolean selectAll(JNIEnv */*env*/, jobject /*thiz*/)
@@ -262,7 +307,9 @@ static jboolean selectAll(JNIEnv */*env*/, jobject /*thiz*/)
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug("@@@ SELALL");
#endif
- return m_androidInputContext->selectAll();
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->selectAll();});
+ return res;
}
static jboolean cut(JNIEnv */*env*/, jobject /*thiz*/)
@@ -273,7 +320,9 @@ static jboolean cut(JNIEnv */*env*/, jobject /*thiz*/)
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug("@@@");
#endif
- return m_androidInputContext->cut();
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->cut();});
+ return res;
}
static jboolean copy(JNIEnv */*env*/, jobject /*thiz*/)
@@ -284,7 +333,9 @@ static jboolean copy(JNIEnv */*env*/, jobject /*thiz*/)
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug("@@@");
#endif
- return m_androidInputContext->copy();
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->copy();});
+ return res;
}
static jboolean copyURL(JNIEnv */*env*/, jobject /*thiz*/)
@@ -295,7 +346,9 @@ static jboolean copyURL(JNIEnv */*env*/, jobject /*thiz*/)
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug("@@@");
#endif
- return m_androidInputContext->copyURL();
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->copyURL();});
+ return res;
}
static jboolean paste(JNIEnv */*env*/, jobject /*thiz*/)
@@ -306,7 +359,9 @@ static jboolean paste(JNIEnv */*env*/, jobject /*thiz*/)
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug("@@@ PASTE");
#endif
- return m_androidInputContext->paste();
+ jboolean res;
+ runOnQtThread([&]{res = m_androidInputContext->paste();});
+ return res;
}
static jboolean updateCursorPosition(JNIEnv */*env*/, jobject /*thiz*/)
@@ -317,7 +372,8 @@ static jboolean updateCursorPosition(JNIEnv */*env*/, jobject /*thiz*/)
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug("@@@ UPDATECURSORPOS");
#endif
- m_androidInputContext->updateCursorPosition();
+
+ runOnQtThread([&]{m_androidInputContext->updateCursorPosition();});
return true;
}
@@ -365,7 +421,7 @@ static QRect inputItemRectangle()
QAndroidInputContext::QAndroidInputContext()
: QPlatformInputContext(), m_composingTextStart(-1), m_blockUpdateSelection(false),
- m_cursorHandleShown(CursorHandleNotShown), m_batchEditNestingLevel(0), m_focusObject(0)
+ m_handleMode(Hidden), m_batchEditNestingLevel(0), m_focusObject(0)
{
jclass clazz = QJNIEnvironmentPrivate::findClass(QtNativeInputConnectionClassName);
if (Q_UNLIKELY(!clazz)) {
@@ -445,10 +501,17 @@ QAndroidInputContext::QAndroidInputContext()
auto im = qGuiApp->inputMethod();
if (!im->inputItemClipRectangle().contains(im->anchorRectangle()) ||
!im->inputItemClipRectangle().contains(im->cursorRectangle())) {
- m_cursorHandleShown = CursorHandleNotShown;
+ m_handleMode = Hidden;
updateSelectionHandles();
}
});
+ m_hideCursorHandleTimer.setInterval(4000);
+ m_hideCursorHandleTimer.setSingleShot(true);
+ m_hideCursorHandleTimer.setTimerType(Qt::VeryCoarseTimer);
+ connect(&m_hideCursorHandleTimer, &QTimer::timeout, this, [this]{
+ m_handleMode = Hidden;
+ updateSelectionHandles();
+ });
}
QAndroidInputContext::~QAndroidInputContext()
@@ -486,9 +549,9 @@ void QAndroidInputContext::reset()
{
clear();
m_batchEditNestingLevel = 0;
- m_cursorHandleShown = QAndroidInputContext::CursorHandleNotShown;
+ m_handleMode = Hidden;
if (qGuiApp->focusObject()) {
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe(Qt::ImEnabled);
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(Qt::ImEnabled);
if (!query.isNull() && query->value(Qt::ImEnabled).toBool()) {
QtAndroidInput::resetSoftwareKeyboard();
return;
@@ -504,7 +567,7 @@ void QAndroidInputContext::commit()
void QAndroidInputContext::updateCursorPosition()
{
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (!query.isNull() && !m_blockUpdateSelection && !m_batchEditNestingLevel) {
const int cursorPos = getAbsoluteCursorPosition(query);
const int composeLength = m_composingText.length();
@@ -542,9 +605,9 @@ void QAndroidInputContext::updateSelectionHandles()
return;
auto im = qGuiApp->inputMethod();
- if (!m_focusObject || (m_cursorHandleShown == CursorHandleNotShown)) {
+ if (!m_focusObject || ((m_handleMode & 0xff) == Hidden)) {
// Hide the handles
- QtAndroidInput::updateHandles(0);
+ QtAndroidInput::updateHandles(Hidden);
return;
}
QWindow *window = qGuiApp->focusWindow();
@@ -552,25 +615,34 @@ void QAndroidInputContext::updateSelectionHandles()
? QHighDpiScaling::factor(window)
: QHighDpiScaling::factor(QtAndroid::androidPlatformIntegration()->screen());
- QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition | Qt::ImEnabled | Qt::ImCurrentSelection);
+ QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition | Qt::ImEnabled | Qt::ImCurrentSelection | Qt::ImHints | Qt::ImSurroundingText);
QCoreApplication::sendEvent(m_focusObject, &query);
+
int cpos = query.value(Qt::ImCursorPosition).toInt();
int anchor = query.value(Qt::ImAnchorPosition).toInt();
if (cpos == anchor || im->anchorRectangle().isNull()) {
if (!query.value(Qt::ImEnabled).toBool()) {
- QtAndroidInput::updateHandles(0);
+ QtAndroidInput::updateHandles(Hidden);
return;
}
auto curRect = im->cursorRectangle();
QPoint cursorPoint(curRect.center().x(), curRect.bottom());
- QPoint editMenuPoint(curRect.center().x(), curRect.top());
- QtAndroidInput::updateHandles(m_cursorHandleShown, cursorPoint * pixelDensity,
- editMenuPoint * pixelDensity);
+ QPoint editMenuPoint(curRect.x(), curRect.y());
+ m_handleMode &= ShowEditPopup;
+ m_handleMode |= ShowCursor;
+ uint32_t buttons = 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();
return;
}
+ m_handleMode = ShowSelection | ShowEditPopup ;
auto leftRect = im->cursorRectangle();
auto rightRect = im->anchorRectangle();
if (cpos > anchor)
@@ -578,13 +650,10 @@ void QAndroidInputContext::updateSelectionHandles()
QPoint leftPoint(leftRect.bottomLeft().toPoint() * pixelDensity);
QPoint righPoint(rightRect.bottomRight().toPoint() * pixelDensity);
- QtAndroidInput::updateHandles(CursorHandleShowSelection, leftPoint, righPoint,
+ QPoint editPoint(leftRect.united(rightRect).topLeft().toPoint() * pixelDensity);
+ QtAndroidInput::updateHandles(m_handleMode, editPoint, EditContext::AllButtons, leftPoint, righPoint,
query.value(Qt::ImCurrentSelection).toString().isRightToLeft());
-
- if (m_cursorHandleShown == CursorHandleShowPopup) {
- // make sure the popup does not reappear when the selection menu closes
- m_cursorHandleShown = QAndroidInputContext::CursorHandleNotShown;
- }
+ m_hideCursorHandleTimer.stop();
}
/*
@@ -594,8 +663,10 @@ void QAndroidInputContext::updateSelectionHandles()
*/
void QAndroidInputContext::handleLocationChanged(int handleId, int x, int y)
{
- if (m_batchEditNestingLevel.load() || m_blockUpdateSelection)
+ if (m_batchEditNestingLevel.load() || m_blockUpdateSelection) {
+ qWarning() << "QAndroidInputContext::handleLocationChanged returned";
return;
+ }
finishComposingText();
@@ -669,34 +740,86 @@ void QAndroidInputContext::handleLocationChanged(int handleId, int x, int y)
void QAndroidInputContext::touchDown(int x, int y)
{
- if (m_focusObject && inputItemRectangle().contains(x, y) && !m_cursorHandleShown) {
+ if (m_focusObject && inputItemRectangle().contains(x, y)) {
// If the user touch the input rectangle, we can show the cursor handle
- m_cursorHandleShown = QAndroidInputContext::CursorHandleShowNormal;
+ m_handleMode = ShowCursor;
+ // The VK will appear in a moment, stop the timer
+ m_hideCursorHandleTimer.stop();
+ finishComposingText();
updateSelectionHandles();
}
}
void QAndroidInputContext::longPress(int x, int y)
{
+ static bool noHandles = qEnvironmentVariableIntValue("QT_QPA_NO_TEXT_HANDLES");
+ if (noHandles)
+ return;
+
if (m_focusObject && inputItemRectangle().contains(x, y)) {
- // Show the paste menu if there is something to paste.
- m_cursorHandleShown = QAndroidInputContext::CursorHandleShowPopup;
+ finishComposingText();
+
+ // Release left button, otherwise the following events will cancel the menu popup
+ QtAndroidInput::releaseMouse(x, y);
+
+ handleLocationChanged(1, x, y);
+ ScopedValueChangeBack<bool> svcb(m_blockUpdateSelection, true);
+
+ QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition | Qt::ImTextBeforeCursor | Qt::ImTextAfterCursor);
+ QCoreApplication::sendEvent(m_focusObject, &query);
+ int cursor = query.value(Qt::ImCursorPosition).toInt();
+ int anchor = cursor;
+ QString before = query.value(Qt::ImTextBeforeCursor).toString();
+ QString after = query.value(Qt::ImTextAfterCursor).toString();
+ for (const auto &ch : after) {
+ if (!ch.isLetterOrNumber())
+ break;
+ ++anchor;
+ }
+
+ for (auto itch = before.rbegin(); itch != after.rend(); ++itch) {
+ if (!itch->isLetterOrNumber())
+ break;
+ --cursor;
+ }
+ if (cursor == anchor || cursor < 0 || cursor - anchor > 500) {
+ m_handleMode = ShowCursor | ShowEditPopup;
+ updateSelectionHandles();
+ return;
+ }
+ QList<QInputMethodEvent::Attribute> imAttributes;
+ imAttributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, cursor, 0, QVariant()));
+ imAttributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, anchor, cursor - anchor, QVariant()));
+ QInputMethodEvent event(QString(), imAttributes);
+ QGuiApplication::sendEvent(m_focusObject, &event);
+
+ m_handleMode = ShowSelection | ShowEditPopup;
updateSelectionHandles();
}
}
void QAndroidInputContext::keyDown()
{
- if (m_cursorHandleShown) {
+ if (m_handleMode) {
// When the user enter text on the keyboard, we hide the cursor handle
- m_cursorHandleShown = QAndroidInputContext::CursorHandleNotShown;
+ m_handleMode = Hidden;
+ updateSelectionHandles();
+ }
+}
+
+void QAndroidInputContext::hideSelectionHandles()
+{
+ if (m_handleMode & ShowSelection) {
+ m_handleMode = Hidden;
updateSelectionHandles();
+ } else {
+ m_hideCursorHandleTimer.start();
}
}
void QAndroidInputContext::update(Qt::InputMethodQueries queries)
{
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe(queries);
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(queries);
if (query.isNull())
return;
#warning TODO extract the needed data from query
@@ -728,7 +851,7 @@ void QAndroidInputContext::showInputPanel()
connect(qGuiApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)), this, SLOT(showInputPanelLater(Qt::ApplicationState)));
return;
}
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return;
@@ -752,6 +875,14 @@ void QAndroidInputContext::showInputPanelLater(Qt::ApplicationState state)
showInputPanel();
}
+void QAndroidInputContext::safeCall(const std::function<void()> &func, Qt::ConnectionType conType)
+{
+ if (qGuiApp->thread() == QThread::currentThread())
+ func();
+ else
+ QMetaObject::invokeMethod(this, "safeCall", conType, Q_ARG(std::function<void()>, func));
+}
+
void QAndroidInputContext::hideInputPanel()
{
QtAndroidInput::hideSoftwareKeyboard();
@@ -810,17 +941,15 @@ jboolean QAndroidInputContext::endBatchEdit()
*/
jboolean QAndroidInputContext::commitText(const QString &text, jint newCursorPosition)
{
- bool updateSelectionWasBlocked = m_blockUpdateSelection;
- m_blockUpdateSelection = true;
-
+ ScopedValueChangeBack<bool> svcb(m_blockUpdateSelection, true);
QInputMethodEvent event;
event.setCommitString(text);
- sendInputMethodEventThreadSafe(&event);
+ sendInputMethodEvent(&event);
clear();
// Qt has now put the cursor at the end of the text, corresponding to newCursorPosition == 1
if (newCursorPosition != 1) {
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (!query.isNull()) {
QList<QInputMethodEvent::Attribute> attributes;
const int localPos = query->value(Qt::ImCursorPosition).toInt();
@@ -832,15 +961,14 @@ jboolean QAndroidInputContext::commitText(const QString &text, jint newCursorPos
newLocalPos, 0));
}
}
- m_blockUpdateSelection = updateSelectionWasBlocked;
-
+ svcb.setOldValue();
updateCursorPosition();
return JNI_TRUE;
}
jboolean QAndroidInputContext::deleteSurroundingText(jint leftLength, jint rightLength)
{
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return JNI_TRUE;
@@ -854,7 +982,7 @@ jboolean QAndroidInputContext::deleteSurroundingText(jint leftLength, jint right
QInputMethodEvent event;
event.setCommitString(QString(), -leftLength, leftLength+rightLength);
- sendInputMethodEventThreadSafe(&event);
+ sendInputMethodEvent(&event);
clear();
return JNI_TRUE;
@@ -866,7 +994,7 @@ jboolean QAndroidInputContext::finishComposingText()
if (m_composingText.isEmpty())
return JNI_TRUE; // not composing
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return JNI_FALSE;
@@ -879,7 +1007,7 @@ jboolean QAndroidInputContext::finishComposingText()
QInputMethodEvent event(QString(), attributes);
event.setCommitString(m_composingText);
- sendInputMethodEventThreadSafe(&event);
+ sendInputMethodEvent(&event);
clear();
return JNI_TRUE;
@@ -888,7 +1016,7 @@ jboolean QAndroidInputContext::finishComposingText()
jint QAndroidInputContext::getCursorCapsMode(jint /*reqModes*/)
{
jint res = 0;
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return res;
@@ -922,7 +1050,7 @@ const QAndroidInputContext::ExtractedText &QAndroidInputContext::getExtractedTex
// updateExtractedText(View, int, ExtractedText) whenever you call
// updateSelection(View, int, int, int, int)." QTBUG-37980
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return m_extractedText;
@@ -967,7 +1095,7 @@ const QAndroidInputContext::ExtractedText &QAndroidInputContext::getExtractedTex
QString QAndroidInputContext::getSelectedText(jint /*flags*/)
{
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return QString();
@@ -977,13 +1105,13 @@ QString QAndroidInputContext::getSelectedText(jint /*flags*/)
QString QAndroidInputContext::getTextAfterCursor(jint length, jint /*flags*/)
{
//### the preedit text could theoretically be after the cursor
- QVariant textAfter = queryFocusObjectThreadSafe(Qt::ImTextAfterCursor, QVariant(length));
+ QVariant textAfter = QInputMethod::queryFocusObject(Qt::ImTextAfterCursor, QVariant(length));
if (textAfter.isValid()) {
return textAfter.toString().left(length);
}
//compatibility code for old controls that do not implement the new API
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return QString();
@@ -997,12 +1125,12 @@ QString QAndroidInputContext::getTextAfterCursor(jint length, jint /*flags*/)
QString QAndroidInputContext::getTextBeforeCursor(jint length, jint /*flags*/)
{
- QVariant textBefore = queryFocusObjectThreadSafe(Qt::ImTextBeforeCursor, QVariant(length));
+ QVariant textBefore = QInputMethod::queryFocusObject(Qt::ImTextBeforeCursor, QVariant(length));
if (textBefore.isValid())
return textBefore.toString().rightRef(length) + m_composingText;
//compatibility code for old controls that do not implement the new API
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return QString();
@@ -1028,7 +1156,7 @@ QString QAndroidInputContext::getTextBeforeCursor(jint length, jint /*flags*/)
jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCursorPosition)
{
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return JNI_FALSE;
@@ -1050,7 +1178,7 @@ jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCur
QVariant(underlined)));
QInputMethodEvent event(m_composingText, attributes);
- sendInputMethodEventThreadSafe(&event);
+ sendInputMethodEvent(&event);
QMetaObject::invokeMethod(this, "keyDown");
@@ -1074,7 +1202,7 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end)
if (wasComposing)
finishComposingText();
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return JNI_FALSE;
@@ -1095,8 +1223,7 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end)
int localStart = start - blockPosition; // Qt uses position inside block
int currentCursor = wasComposing ? m_composingCursor : blockPosition + localPos;
- bool updateSelectionWasBlocked = m_blockUpdateSelection;
- m_blockUpdateSelection = true;
+ ScopedValueChangeBack<bool> svcb(m_blockUpdateSelection, true);
QString text = query->value(Qt::ImSurroundingText).toString();
@@ -1120,12 +1247,10 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end)
QInputMethodEvent event(m_composingText, attributes);
event.setCommitString(QString(), relativeStart, length);
- sendInputMethodEventThreadSafe(&event);
-
- m_blockUpdateSelection = updateSelectionWasBlocked;
+ sendInputMethodEvent(&event);
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- QSharedPointer<QInputMethodQueryEvent> query2 = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query2 = focusObjectInputMethodQuery();
if (!query2.isNull()) {
qDebug() << "Setting. Prev local cpos:" << localPos << "block pos:" <<blockPosition << "comp.start:" << m_composingTextStart << "rel.start:" << relativeStart << "len:" << length << "cpos attr:" << localPos - localStart;
qDebug() << "New cursor pos" << getAbsoluteCursorPosition(query2);
@@ -1137,7 +1262,7 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end)
jboolean QAndroidInputContext::setSelection(jint start, jint end)
{
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe();
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return JNI_FALSE;
@@ -1168,26 +1293,31 @@ jboolean QAndroidInputContext::setSelection(jint start, jint end)
end - start));
}
QInputMethodEvent event(m_composingText, attributes);
- sendInputMethodEventThreadSafe(&event);
+ sendInputMethodEvent(&event);
updateCursorPosition();
return JNI_TRUE;
}
jboolean QAndroidInputContext::selectAll()
{
+ finishComposingText();
+ m_handleMode = ShowCursor;
sendShortcut(QKeySequence::SelectAll);
return JNI_TRUE;
}
jboolean QAndroidInputContext::cut()
{
- m_cursorHandleShown = CursorHandleNotShown;
+ finishComposingText();
+ m_handleMode = ShowCursor;
sendShortcut(QKeySequence::Cut);
return JNI_TRUE;
}
jboolean QAndroidInputContext::copy()
{
+ finishComposingText();
+ m_handleMode = ShowCursor;
sendShortcut(QKeySequence::Copy);
return JNI_TRUE;
}
@@ -1201,7 +1331,7 @@ jboolean QAndroidInputContext::copyURL()
jboolean QAndroidInputContext::paste()
{
finishComposingText();
- m_cursorHandleShown = CursorHandleNotShown;
+ m_handleMode = ShowCursor;
sendShortcut(QKeySequence::Paste);
return JNI_TRUE;
}
@@ -1217,65 +1347,24 @@ void QAndroidInputContext::sendShortcut(const QKeySequence &sequence)
}
}
-Q_INVOKABLE QVariant QAndroidInputContext::queryFocusObjectUnsafe(Qt::InputMethodQuery query, QVariant argument)
-{
- return QInputMethod::queryFocusObject(query, argument);
-}
-
-QVariant QAndroidInputContext::queryFocusObjectThreadSafe(Qt::InputMethodQuery query, QVariant argument)
-{
- QVariant retval;
+QSharedPointer<QInputMethodQueryEvent> QAndroidInputContext::focusObjectInputMethodQuery(Qt::InputMethodQueries queries) {
if (!qGuiApp)
- return retval;
- const bool inMainThread = qGuiApp->thread() == QThread::currentThread();
- if (QAndroidEventDispatcherStopper::stopped() && !inMainThread)
- return retval;
- AndroidDeadlockProtector protector;
- if (!inMainThread && !protector.acquire())
- return retval;
-
- QMetaObject::invokeMethod(this, "queryFocusObjectUnsafe",
- inMainThread ? Qt::DirectConnection : Qt::BlockingQueuedConnection,
- Q_RETURN_ARG(QVariant, retval),
- Q_ARG(Qt::InputMethodQuery, query),
- Q_ARG(QVariant, argument));
+ return {};
- return retval;
-}
-
-QSharedPointer<QInputMethodQueryEvent> QAndroidInputContext::focusObjectInputMethodQueryThreadSafe(Qt::InputMethodQueries queries) {
- QSharedPointer<QInputMethodQueryEvent> retval;
- if (!qGuiApp)
- return QSharedPointer<QInputMethodQueryEvent>();
- const bool inMainThread = qGuiApp->thread() == QThread::currentThread();
- if (QAndroidEventDispatcherStopper::stopped() && !inMainThread)
- return QSharedPointer<QInputMethodQueryEvent>();
- AndroidDeadlockProtector protector;
- if (!inMainThread && !protector.acquire())
- return QSharedPointer<QInputMethodQueryEvent>();
-
- QInputMethodQueryEvent *queryEvent = 0;
- QMetaObject::invokeMethod(this, "focusObjectInputMethodQueryUnsafe",
- inMainThread ? Qt::DirectConnection : Qt::BlockingQueuedConnection,
- Q_RETURN_ARG(QInputMethodQueryEvent*, queryEvent),
- Q_ARG(Qt::InputMethodQueries, queries));
-
- return QSharedPointer<QInputMethodQueryEvent>(queryEvent);
-}
-
-QInputMethodQueryEvent *QAndroidInputContext::focusObjectInputMethodQueryUnsafe(Qt::InputMethodQueries queries)
-{
QObject *focusObject = qGuiApp->focusObject();
if (!focusObject)
- return 0;
+ return {};
QInputMethodQueryEvent *ret = new QInputMethodQueryEvent(queries);
QCoreApplication::sendEvent(focusObject, ret);
- return ret;
+ return QSharedPointer<QInputMethodQueryEvent>(ret);
}
-void QAndroidInputContext::sendInputMethodEventUnsafe(QInputMethodEvent *event)
+void QAndroidInputContext::sendInputMethodEvent(QInputMethodEvent *event)
{
+ if (!qGuiApp)
+ return;
+
QObject *focusObject = qGuiApp->focusObject();
if (!focusObject)
return;
@@ -1283,19 +1372,4 @@ void QAndroidInputContext::sendInputMethodEventUnsafe(QInputMethodEvent *event)
QCoreApplication::sendEvent(focusObject, event);
}
-void QAndroidInputContext::sendInputMethodEventThreadSafe(QInputMethodEvent *event)
-{
- if (!qGuiApp)
- return;
- const bool inMainThread = qGuiApp->thread() == QThread::currentThread();
- if (QAndroidEventDispatcherStopper::stopped() && !inMainThread)
- return;
- AndroidDeadlockProtector protector;
- if (!inMainThread && !protector.acquire())
- return;
- QMetaObject::invokeMethod(this, "sendInputMethodEventUnsafe",
- inMainThread ? Qt::DirectConnection : Qt::BlockingQueuedConnection,
- Q_ARG(QInputMethodEvent*, event));
-}
-
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidinputcontext.h b/src/plugins/platforms/android/qandroidinputcontext.h
index e7692bf720..bd3edb30f0 100644
--- a/src/plugins/platforms/android/qandroidinputcontext.h
+++ b/src/plugins/platforms/android/qandroidinputcontext.h
@@ -42,8 +42,10 @@
#define ANDROIDINPUTCONTEXT_H
#include <qpa/qplatforminputcontext.h>
+#include <functional>
#include <jni.h>
#include <qevent.h>
+#include <QTimer>
QT_BEGIN_NAMESPACE
@@ -58,6 +60,22 @@ class QAndroidInputContext: public QPlatformInputContext
};
public:
+ enum EditContext : uint32_t {
+ CutButton = 1 << 0,
+ CopyButton = 1 << 1,
+ PasteButton = 1 << 2,
+ SelectAllButton = 1 << 3,
+ AllButtons = CutButton | CopyButton | PasteButton | SelectAllButton
+ };
+
+ enum HandleMode {
+ Hidden = 0,
+ ShowCursor = 1,
+ ShowSelection = 2,
+ ShowEditPopup = 0x100
+ };
+ Q_DECLARE_FLAGS(HandleModes, HandleMode)
+
struct ExtractedText
{
ExtractedText() { clear(); }
@@ -118,25 +136,21 @@ public:
jboolean paste();
public slots:
+ void safeCall(const std::function<void()> &func, Qt::ConnectionType conType = Qt::BlockingQueuedConnection);
void updateCursorPosition();
void updateSelectionHandles();
void handleLocationChanged(int handleId, int x, int y);
void touchDown(int x, int y);
void longPress(int x, int y);
void keyDown();
+ void hideSelectionHandles();
private slots:
void showInputPanelLater(Qt::ApplicationState);
private:
- void sendInputMethodEventThreadSafe(QInputMethodEvent *event);
- Q_INVOKABLE void sendInputMethodEventUnsafe(QInputMethodEvent *event);
-
- QSharedPointer<QInputMethodQueryEvent> focusObjectInputMethodQueryThreadSafe(Qt::InputMethodQueries queries = Qt::ImQueryAll);
- Q_INVOKABLE QInputMethodQueryEvent *focusObjectInputMethodQueryUnsafe(Qt::InputMethodQueries queries);
-
- Q_INVOKABLE QVariant queryFocusObjectUnsafe(Qt::InputMethodQuery query, QVariant argument);
- QVariant queryFocusObjectThreadSafe(Qt::InputMethodQuery query, QVariant argument);
+ void sendInputMethodEvent(QInputMethodEvent *event);
+ QSharedPointer<QInputMethodQueryEvent> focusObjectInputMethodQuery(Qt::InputMethodQueries queries = Qt::ImQueryAll);
private:
ExtractedText m_extractedText;
@@ -145,17 +159,12 @@ private:
int m_composingCursor;
QMetaObject::Connection m_updateCursorPosConnection;
bool m_blockUpdateSelection;
- enum CursorHandleShowMode {
- CursorHandleNotShown,
- CursorHandleShowNormal = 1,
- CursorHandleShowSelection = 2,
- CursorHandleShowPopup = 3
- };
- CursorHandleShowMode m_cursorHandleShown;
+ HandleModes m_handleMode;
QAtomicInt m_batchEditNestingLevel;
QObject *m_focusObject;
+ QTimer m_hideCursorHandleTimer;
};
-
+Q_DECLARE_OPERATORS_FOR_FLAGS(QAndroidInputContext::HandleModes)
QT_END_NAMESPACE
#endif // ANDROIDINPUTCONTEXT_H
diff --git a/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp b/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp
index ced35c4cfa..9218afa7f5 100644
--- a/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp
+++ b/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2018 The Qt Company Ltd.
** Copyright (C) 2013 BogDan Vatra <bogdan@kde.org>
** Contact: https://www.qt.io/licensing/
**
@@ -117,6 +118,15 @@ bool QAndroidPlatformMessageDialogHelper::show(Qt::WindowFlags windowFlags
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());
+ }
+ }
+
for (int i = QPlatformDialogHelper::FirstButton; i < QPlatformDialogHelper::LastButton; i<<=1) {
StandardButton b = static_cast<StandardButton>(i);
if (buttonRole(b) == role && (opt->standardButtons() & i)) {
@@ -144,6 +154,12 @@ void QAndroidPlatformMessageDialogHelper::dialogResult(int buttonID)
QPlatformDialogHelper::StandardButton standardButton = static_cast<QPlatformDialogHelper::StandardButton>(buttonID);
QPlatformDialogHelper::ButtonRole role = QPlatformDialogHelper::buttonRole(standardButton);
+ if (buttonID > QPlatformDialogHelper::LastButton) {
+ const QMessageDialogOptions::CustomButton *custom = options()->customButton(buttonID);
+ Q_ASSERT(custom);
+ role = custom->role;
+ }
+
emit clicked(standardButton, role);
}
diff --git a/src/plugins/platforms/android/qandroidplatformmenubar.h b/src/plugins/platforms/android/qandroidplatformmenubar.h
index 0316ea9362..f5935b8177 100644
--- a/src/plugins/platforms/android/qandroidplatformmenubar.h
+++ b/src/plugins/platforms/android/qandroidplatformmenubar.h
@@ -61,7 +61,7 @@ public:
void handleReparent(QWindow *newParentWindow) override;
QPlatformMenu *menuForTag(quintptr tag) const override;
- QWindow *parentWindow() const;
+ QWindow *parentWindow() const override;
PlatformMenusType menus() const;
QMutex *menusListMutex();
diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro
index 2694cb3607..8d65cf328f 100644
--- a/src/plugins/platforms/cocoa/cocoa.pro
+++ b/src/plugins/platforms/cocoa/cocoa.pro
@@ -8,7 +8,6 @@ SOURCES += main.mm \
qcocoawindow.mm \
qnsview.mm \
qnswindow.mm \
- qnsviewaccessibility.mm \
qnswindowdelegate.mm \
qcocoanativeinterface.mm \
qcocoaeventdispatcher.mm \
@@ -72,19 +71,25 @@ HEADERS += qcocoaintegration.h \
qtConfig(opengl.*) {
SOURCES += qcocoaglcontext.mm
-
HEADERS += qcocoaglcontext.h
}
+qtConfig(vulkan) {
+ SOURCES += qcocoavulkaninstance.mm
+ HEADERS += qcocoavulkaninstance.h
+}
+
RESOURCES += qcocoaresources.qrc
-LIBS += -framework AppKit -framework Carbon -framework IOKit -framework QuartzCore -lcups
+LIBS += -framework AppKit -framework CoreServices -framework Carbon -framework IOKit -framework QuartzCore -framework CoreVideo -framework Metal -lcups
QT += \
core-private gui-private \
accessibility_support-private clipboard_support-private theme_support-private \
fontdatabase_support-private graphics_support-private
+qtConfig(vulkan): QT += vulkan_support-private
+
CONFIG += no_app_extension_api_only
qtHaveModule(widgets) {
@@ -122,11 +127,6 @@ qtHaveModule(widgets) {
OTHER_FILES += cocoa.json
-# Acccessibility debug support
-# DEFINES += QT_COCOA_ENABLE_ACCESSIBILITY_INSPECTOR
-# include ($$PWD/../../../../util/accessibilityinspector/accessibilityinspector.pri)
-
-
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QCocoaIntegrationPlugin
!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
diff --git a/src/plugins/platforms/cocoa/main.mm b/src/plugins/platforms/cocoa/main.mm
index f9bfdc7dc7..89ecdf46f9 100644
--- a/src/plugins/platforms/cocoa/main.mm
+++ b/src/plugins/platforms/cocoa/main.mm
@@ -60,7 +60,7 @@ QPlatformIntegration * QCocoaIntegrationPlugin::create(const QString& system, co
if (system.compare(QLatin1String("cocoa"), Qt::CaseInsensitive) == 0)
return new QCocoaIntegration(paramList);
- return 0;
+ return nullptr;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/messages.cpp b/src/plugins/platforms/cocoa/messages.cpp
index 8eea1e654e..06e3dd454e 100644
--- a/src/plugins/platforms/cocoa/messages.cpp
+++ b/src/plugins/platforms/cocoa/messages.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -39,7 +39,8 @@
#include "messages.h"
-#include <QCoreApplication>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qregularexpression.h>
// Translatable messages should go into this .cpp file for them to be picked up by lupdate.
@@ -52,13 +53,13 @@ QString msgAboutQt()
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","Preferences..."),
- QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Quit %1"),
- QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","About %1")
+ QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Quit %1")
};
QString qt_mac_applicationmenu_string(int type)
@@ -77,8 +78,13 @@ 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) || caption.endsWith(aboutString, Qt::CaseInsensitive))
+ 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)
diff --git a/src/plugins/platforms/cocoa/messages.h b/src/plugins/platforms/cocoa/messages.h
index e41898fe59..3a9eaf604e 100644
--- a/src/plugins/platforms/cocoa/messages.h
+++ b/src/plugins/platforms/cocoa/messages.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -46,13 +46,13 @@
QT_BEGIN_NAMESPACE
enum {
- ServicesAppMenuItem = 0,
+ AboutAppMenuItem = 0,
+ PreferencesAppMenuItem,
+ ServicesAppMenuItem,
HideAppMenuItem,
HideOthersAppMenuItem,
ShowAllAppMenuItem,
- PreferencesAppMenuItem,
- QuitAppMenuItem,
- AboutAppMenuItem
+ QuitAppMenuItem
};
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.h b/src/plugins/platforms/cocoa/qcocoaaccessibility.h
index e456364555..457c158ddc 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.h
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.h
@@ -46,6 +46,8 @@
#ifndef QT_NO_ACCESSIBILITY
+@class QT_MANGLE_NAMESPACE(QMacAccessibilityElement);
+
QT_BEGIN_NAMESPACE
class QCocoaAccessibility : public QPlatformAccessibility
@@ -82,9 +84,8 @@ namespace QCocoaAccessible {
NSString *macRole(QAccessibleInterface *interface);
NSString *macSubrole(QAccessibleInterface *interface);
bool shouldBeIgnored(QAccessibleInterface *interface);
-NSArray *unignoredChildren(QAccessibleInterface *interface);
+NSArray<QT_MANGLE_NAMESPACE(QMacAccessibilityElement) *> *unignoredChildren(QAccessibleInterface *interface);
NSString *getTranslatedAction(const QString &qtAction);
-NSMutableArray *createTranslatedActionsList(const QStringList &qtActions);
QString translateAction(NSString *nsAction, QAccessibleInterface *interface);
bool hasValueAttribute(QAccessibleInterface *interface);
id getValueAttribute(QAccessibleInterface *interface);
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
index 654e6210c8..368cf56c80 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
@@ -256,12 +256,12 @@ bool shouldBeIgnored(QAccessibleInterface *interface)
return false;
}
-NSArray *unignoredChildren(QAccessibleInterface *interface)
+NSArray<QMacAccessibilityElement *> *unignoredChildren(QAccessibleInterface *interface)
{
int numKids = interface->childCount();
// qDebug() << "Children for: " << axid << iface << " are: " << numKids;
- NSMutableArray *kids = [NSMutableArray arrayWithCapacity:numKids];
+ NSMutableArray<QMacAccessibilityElement *> *kids = [NSMutableArray<QMacAccessibilityElement *> arrayWithCapacity:numKids];
for (int i = 0; i < numKids; ++i) {
QAccessibleInterface *child = interface->child(i);
if (!child || !child->isValid() || child->state().invalid || child->state().invisible)
@@ -310,7 +310,7 @@ NSString *getTranslatedAction(const QString &qtAction)
// NSAccessibilityCancelAction;
// NSAccessibilityDeleteAction;
- return 0;
+ return nil;
}
@@ -386,7 +386,7 @@ id getValueAttribute(QAccessibleInterface *interface)
}
if (interface->state().checkable) {
- return [NSNumber numberWithInt: (interface->state().checked ? 1 : 0)];
+ return interface->state().checked ? @(1) : @(0);
}
return nil;
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
index 07f3f3a99e..914aaa2b1b 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
@@ -52,13 +52,10 @@
@class QT_MANGLE_NAMESPACE(QMacAccessibilityElement);
-@interface QT_MANGLE_NAMESPACE(QMacAccessibilityElement) : NSObject {
- NSString *role;
- QAccessible::Id axid;
-}
+@interface QT_MANGLE_NAMESPACE(QMacAccessibilityElement) : NSObject
-- (id)initWithId:(QAccessible::Id)anId;
-+ (QT_MANGLE_NAMESPACE(QMacAccessibilityElement) *)elementWithId:(QAccessible::Id)anId;
+- (instancetype)initWithId:(QAccessible::Id)anId;
++ (instancetype)elementWithId:(QAccessible::Id)anId;
@end
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
index df2336d08b..03dc895ffb 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
@@ -99,9 +99,12 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
*end = curEnd;
}
-@implementation QMacAccessibilityElement
+@implementation QMacAccessibilityElement {
+ NSString *role;
+ QAccessible::Id axid;
+}
-- (id)initWithId:(QAccessible::Id)anId
+- (instancetype)initWithId:(QAccessible::Id)anId
{
Q_ASSERT((int)anId < 0);
self = [super init];
@@ -115,7 +118,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
return self;
}
-+ (id)elementWithId:(QAccessible::Id)anId
++ (instancetype)elementWithId:(QAccessible::Id)anId
{
Q_ASSERT(anId);
if (!anId)
@@ -168,22 +171,15 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
{
QStringRef textBefore = QStringRef(&text, 0, index);
int newlines = textBefore.count(QLatin1Char('\n'));
- return [NSNumber numberWithInt: newlines];
+ return @(newlines);
}
- (BOOL) accessibilityNotifiesWhenDestroyed {
return YES;
}
-- (NSArray *)accessibilityAttributeNames {
- static NSArray *defaultAttributes = nil;
-
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
- return defaultAttributes;
-
- if (defaultAttributes == nil) {
- defaultAttributes = [[NSArray alloc] initWithObjects:
+- (NSArray<NSString *> *)accessibilityAttributeNames {
+ static NSArray<NSString *> *defaultAttributes = [@[
NSAccessibilityRoleAttribute,
NSAccessibilityRoleDescriptionAttribute,
NSAccessibilitySubroleAttribute,
@@ -196,35 +192,36 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
NSAccessibilitySizeAttribute,
NSAccessibilityTitleAttribute,
NSAccessibilityDescriptionAttribute,
- NSAccessibilityEnabledAttribute,
- nil];
- }
+ NSAccessibilityEnabledAttribute
+ ] retain];
+
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface || !iface->isValid())
+ return defaultAttributes;
- NSMutableArray *attributes = [[NSMutableArray alloc] initWithCapacity : [defaultAttributes count]];
- [attributes addObjectsFromArray : defaultAttributes];
+ NSMutableArray<NSString *> *attributes = [[NSMutableArray<NSString *> alloc] initWithCapacity:defaultAttributes.count];
+ [attributes addObjectsFromArray:defaultAttributes];
if (QCocoaAccessible::hasValueAttribute(iface)) {
- [attributes addObject : NSAccessibilityValueAttribute];
+ [attributes addObject:NSAccessibilityValueAttribute];
}
if (iface->textInterface()) {
- [attributes addObjectsFromArray: [[NSArray alloc] initWithObjects:
+ [attributes addObjectsFromArray:@[
NSAccessibilityNumberOfCharactersAttribute,
NSAccessibilitySelectedTextAttribute,
NSAccessibilitySelectedTextRangeAttribute,
NSAccessibilityVisibleCharacterRangeAttribute,
- NSAccessibilityInsertionPointLineNumberAttribute,
- nil
+ NSAccessibilityInsertionPointLineNumberAttribute
]];
// TODO: multi-selection: NSAccessibilitySelectedTextRangesAttribute,
}
if (iface->valueInterface()) {
- [attributes addObjectsFromArray: [[NSArray alloc] initWithObjects:
+ [attributes addObjectsFromArray:@[
NSAccessibilityMinValueAttribute,
- NSAccessibilityMaxValueAttribute,
- nil
+ NSAccessibilityMaxValueAttribute
]];
}
@@ -261,13 +258,13 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
- (id) minValueAttribute:(QAccessibleInterface*)iface {
if (QAccessibleValueInterface *val = iface->valueInterface())
- return [NSNumber numberWithDouble: val->minimumValue().toDouble()];
+ return @(val->minimumValue().toDouble());
return nil;
}
- (id) maxValueAttribute:(QAccessibleInterface*)iface {
if (QAccessibleValueInterface *val = iface->valueInterface())
- return [NSNumber numberWithDouble: val->maximumValue().toDouble()];
+ return @(val->maximumValue().toDouble());
return nil;
}
@@ -289,7 +286,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
} else if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
// Just check if the app thinks we're focused.
id focusedElement = [NSApp accessibilityAttributeValue:NSAccessibilityFocusedUIElementAttribute];
- return [NSNumber numberWithBool:[focusedElement isEqual:self]];
+ return @([focusedElement isEqual:self]);
} else if ([attribute isEqualToString:NSAccessibilityParentAttribute]) {
return NSAccessibilityUnignoredAncestor([self parentElement]);
} else if ([attribute isEqualToString:NSAccessibilityWindowAttribute]) {
@@ -312,7 +309,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
} else if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute]) {
return iface->text(QAccessible::Description).toNSString();
} else if ([attribute isEqualToString:NSAccessibilityEnabledAttribute]) {
- return [NSNumber numberWithBool:!iface->state().disabled];
+ return @(!iface->state().disabled);
} else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
// VoiceOver asks for the value attribute for all elements. Return nil
// if we don't want the element to have a value attribute.
@@ -323,7 +320,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
} else if ([attribute isEqualToString:NSAccessibilityNumberOfCharactersAttribute]) {
if (QAccessibleTextInterface *text = iface->textInterface())
- return [NSNumber numberWithInt: text->characterCount()];
+ return @(text->characterCount());
return nil;
} else if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) {
if (QAccessibleTextInterface *text = iface->textInterface()) {
@@ -357,7 +354,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
int position = text->cursorPosition();
convertLineOffset(text, &line, &position);
}
- return [NSNumber numberWithInt: line];
+ return @(line);
}
return nil;
} else if ([attribute isEqualToString:NSAccessibilityMinValueAttribute]) {
@@ -378,18 +375,17 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
if (iface->textInterface()) {
- return [[NSArray alloc] initWithObjects:
- NSAccessibilityStringForRangeParameterizedAttribute,
- NSAccessibilityLineForIndexParameterizedAttribute,
- NSAccessibilityRangeForLineParameterizedAttribute,
- NSAccessibilityRangeForPositionParameterizedAttribute,
-// NSAccessibilityRangeForIndexParameterizedAttribute,
- NSAccessibilityBoundsForRangeParameterizedAttribute,
-// NSAccessibilityRTFForRangeParameterizedAttribute,
- NSAccessibilityStyleRangeForIndexParameterizedAttribute,
- NSAccessibilityAttributedStringForRangeParameterizedAttribute,
- nil
- ];
+ return @[
+ NSAccessibilityStringForRangeParameterizedAttribute,
+ NSAccessibilityLineForIndexParameterizedAttribute,
+ NSAccessibilityRangeForLineParameterizedAttribute,
+ NSAccessibilityRangeForPositionParameterizedAttribute,
+// NSAccessibilityRangeForIndexParameterizedAttribute,
+ NSAccessibilityBoundsForRangeParameterizedAttribute,
+// NSAccessibilityRTFForRangeParameterizedAttribute,
+ NSAccessibilityStyleRangeForIndexParameterizedAttribute,
+ NSAccessibilityAttributedStringForRangeParameterizedAttribute
+ ];
}
return nil;
@@ -416,7 +412,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
return nil;
int line = -1;
convertLineOffset(iface->textInterface(), &line, &index);
- return [NSNumber numberWithInt:line];
+ return @(line);
}
if ([attribute isEqualToString: NSAccessibilityRangeForLineParameterizedAttribute]) {
int line = [parameter intValue];
@@ -573,7 +569,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
return NSAccessibilityUnignoredAncestor(self);
// find the deepest child at the point
- QAccessibleInterface *childOfChildInterface = 0;
+ QAccessibleInterface *childOfChildInterface = nullptr;
do {
childOfChildInterface = childInterface->childAt(screenPoint.x(), screenPoint.y());
if (childOfChildInterface && childOfChildInterface->isValid())
diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.h b/src/plugins/platforms/cocoa/qcocoaapplication.h
index 66a92686bc..15530d8281 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplication.h
+++ b/src/plugins/platforms/cocoa/qcocoaapplication.h
@@ -89,8 +89,7 @@
#import <AppKit/AppKit.h>
-@interface QT_MANGLE_NAMESPACE(QNSApplication) : NSApplication {
-}
+@interface QT_MANGLE_NAMESPACE(QNSApplication) : NSApplication
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSApplication);
diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.mm b/src/plugins/platforms/cocoa/qcocoaapplication.mm
index d0f27795b6..340191622a 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplication.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplication.mm
@@ -113,11 +113,11 @@ static const QByteArray q_macLocalEventType = QByteArrayLiteral("mac_generic_NSE
static bool qt_filterEvent(NSEvent *event)
{
if (qApp && qApp->eventDispatcher()->
- filterNativeEvent(q_macLocalEventType, static_cast<void*>(event), 0))
+ filterNativeEvent(q_macLocalEventType, static_cast<void*>(event), nullptr))
return true;
- if ([event type] == NSApplicationDefined) {
- switch (static_cast<short>([event subtype])) {
+ if (event.type == NSEventTypeApplicationDefined) {
+ switch (static_cast<short>(event.subtype)) {
case QtCocoaEventSubTypePostMessage:
qt_sendPostedMessage(event);
return true;
@@ -137,7 +137,7 @@ static void qt_maybeSendKeyEquivalentUpEvent(NSEvent *event)
// and forward the key event to the key (focus) window.
// However, non-Qt windows will not (and should not) get
// any special treatment, only QWindow-owned NSWindows.
- if (event.type == NSKeyUp && (event.modifierFlags & NSCommandKeyMask)) {
+ if (event.type == NSEventTypeKeyUp && (event.modifierFlags & NSEventModifierFlagCommand)) {
NSWindow *targetWindow = event.window;
if ([targetWindow.class conformsToProtocol:@protocol(QNSWindowProtocol)])
[targetWindow sendEvent:event];
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
index 59c71017e3..0816730c54 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -90,20 +90,18 @@
#include <qglobal.h>
#include <private/qcore_mac_p.h>
-@class QT_MANGLE_NAMESPACE(QCocoaMenuLoader);
+Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QCocoaNSMenuItem));
-@interface QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) : NSObject <NSApplicationDelegate> {
- bool startedQuit;
- NSMenu *dockMenu;
- NSObject <NSApplicationDelegate> *reflectionDelegate;
- bool inLaunch;
-}
-+ (QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate)*)sharedDelegate;
-- (void)setDockMenu:(NSMenu *)newMenu;
-- (void)setReflectionDelegate:(NSObject <NSApplicationDelegate> *)oldDelegate;
-- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent;
-- (void) removeAppleEventHandlers;
-- (bool) inLaunch;
+@interface QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) : NSObject <NSApplicationDelegate>
+@property (nonatomic, retain) NSMenu *dockMenu;
++ (instancetype)sharedDelegate;
+- (void)setReflectionDelegate:(NSObject<NSApplicationDelegate> *)oldDelegate;
+- (void)removeAppleEventHandlers;
+- (bool)inLaunch;
+@end
+
+@interface QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) (MenuAPI)
+- (void)qt_itemFired:(QT_MANGLE_NAMESPACE(QCocoaNSMenuItem) *)item;
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaApplicationDelegate);
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
index a94e0dc517..221a8b0866 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -73,9 +73,12 @@
#import "qcocoaapplicationdelegate.h"
-#import "qnswindowdelegate.h"
-#import "qcocoamenuloader.h"
#include "qcocoaintegration.h"
+#include "qcocoamenu.h"
+#include "qcocoamenuloader.h"
+#include "qcocoamenuitem.h"
+#include "qcocoansmenu.h"
+
#include <qevent.h>
#include <qurl.h>
#include <qdebug.h>
@@ -86,7 +89,11 @@
QT_USE_NAMESPACE
-@implementation QCocoaApplicationDelegate
+@implementation QCocoaApplicationDelegate {
+ bool startedQuit;
+ NSObject <NSApplicationDelegate> *reflectionDelegate;
+ bool inLaunch;
+}
+ (instancetype)sharedDelegate
{
@@ -102,7 +109,7 @@ QT_USE_NAMESPACE
return shared;
}
-- (id)init
+- (instancetype)init
{
self = [super init];
if (self) {
@@ -125,7 +132,7 @@ QT_USE_NAMESPACE
- (void)dealloc
{
- [dockMenu release];
+ [_dockMenu release];
if (reflectionDelegate) {
[[NSApplication sharedApplication] setDelegate:reflectionDelegate];
[reflectionDelegate release];
@@ -135,23 +142,16 @@ QT_USE_NAMESPACE
[super dealloc];
}
-- (void)setDockMenu:(NSMenu*)newMenu
-{
- [newMenu retain];
- [dockMenu release];
- dockMenu = newMenu;
-}
-
- (NSMenu *)applicationDockMenu:(NSApplication *)sender
{
Q_UNUSED(sender);
// Manually invoke the delegate's -menuWillOpen: method.
// See QTBUG-39604 (and its fix) for details.
- [[dockMenu delegate] menuWillOpen:dockMenu];
- return [[dockMenu retain] autorelease];
+ [self.dockMenu.delegate menuWillOpen:self.dockMenu];
+ return [[self.dockMenu retain] autorelease];
}
-- (BOOL) canQuit
+- (BOOL)canQuit
{
[[NSApp mainMenu] cancelTracking];
@@ -219,7 +219,7 @@ QT_USE_NAMESPACE
return NSTerminateCancel;
}
-- (void) applicationWillFinishLaunching:(NSNotification *)notification
+- (void)applicationWillFinishLaunching:(NSNotification *)notification
{
Q_UNUSED(notification);
@@ -249,14 +249,14 @@ QT_USE_NAMESPACE
}
// called by QCocoaIntegration's destructor before resetting the application delegate to nil
-- (void) removeAppleEventHandlers
+- (void)removeAppleEventHandlers
{
NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager];
[eventManager removeEventHandlerForEventClass:kCoreEventClass andEventID:kAEQuitApplication];
[eventManager removeEventHandlerForEventClass:kInternetEventClass andEventID:kAEGetURL];
}
-- (bool) inLaunch
+- (bool)inLaunch
{
return inLaunch;
}
@@ -267,13 +267,11 @@ QT_USE_NAMESPACE
inLaunch = false;
if (qEnvironmentVariableIsEmpty("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM")) {
- if (__builtin_available(macOS 10.12, *)) {
- // 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];
- }
+ // 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];
}
}
@@ -440,3 +438,48 @@ QT_USE_NAMESPACE
}
@end
+
+@implementation QCocoaApplicationDelegate (Menus)
+
+- (BOOL)validateMenuItem:(NSMenuItem*)item
+{
+ 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
+ return item.hasSubmenu || (item.enabled && (item.action != @selector(qt_itemFired:)));
+
+ // Menu-holding items are always enabled, as it's conventional in Cocoa
+ if (platformItem->menu())
+ return YES;
+
+ return platformItem->isEnabled();
+}
+
+@end
+
+@implementation QCocoaApplicationDelegate (MenuAPI)
+
+- (void)qt_itemFired:(QCocoaNSMenuItem *)item
+{
+ if (item.hasSubmenu)
+ return;
+
+ auto *nativeItem = qt_objc_cast<QCocoaNSMenuItem *>(item);
+ Q_ASSERT_X(nativeItem, qPrintable(__FUNCTION__), "Triggered menu item is not a QCocoaNSMenuItem.");
+ auto *platformItem = nativeItem.platformMenuItem;
+ // Menu-holding items also get a target to play nicely
+ // with NSMenuValidation but should not trigger.
+ if (!platformItem || platformItem->menu())
+ return;
+
+ QScopedScopeLevelCounter scopeLevelCounter(QGuiApplicationPrivate::instance()->threadData);
+ QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers:[NSEvent modifierFlags]];
+
+ static QMetaMethod activatedSignal = QMetaMethod::fromSignal(&QCocoaMenuItem::activated);
+ activatedSignal.invoke(platformItem, Qt::QueuedConnection);
+}
+
+@end
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
index 1343fbc45a..81a0a7d040 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
@@ -44,8 +44,6 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcCocoaBackingStore, "qt.qpa.cocoa.backingstore");
-
QCocoaBackingStore::QCocoaBackingStore(QWindow *window)
: QRasterBackingStore(window)
{
@@ -69,11 +67,6 @@ QImage::Format QCocoaBackingStore::format() const
return QRasterBackingStore::format();
}
-#if !QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_12)
-static const NSCompositingOperation NSCompositingOperationCopy = NSCompositeCopy;
-static const NSCompositingOperation NSCompositingOperationSourceOver = NSCompositeSourceOver;
-#endif
-
/*!
Flushes the given \a region from the specified \a window onto the
screen.
@@ -101,13 +94,13 @@ void QCocoaBackingStore::flush(QWindow *window, const QRegion &region, const QPo
QNSView *topLevelView = qnsview_cast(static_cast<QCocoaWindow *>(topLevelWindow->handle())->view());
QNSView *view = qnsview_cast(static_cast<QCocoaWindow *>(window->handle())->view());
- if (lcCocoaBackingStore().isDebugEnabled()) {
+ if (lcQpaBackingStore().isDebugEnabled()) {
QString targetViewDescription;
if (view != topLevelView) {
QDebug targetDebug(&targetViewDescription);
targetDebug << "onto" << topLevelView << "at" << offset;
}
- qCDebug(lcCocoaBackingStore) << "Flushing" << region << "of" << view << qPrintable(targetViewDescription);
+ qCDebug(lcQpaBackingStore) << "Flushing" << region << "of" << view << qPrintable(targetViewDescription);
}
// Prevent potentially costly color conversion by assigning the display color space
@@ -127,118 +120,120 @@ void QCocoaBackingStore::flush(QWindow *window, const QRegion &region, const QPo
// FIXME: Figure out if there's a way to do partial updates
view.layer.contents = (__bridge id)static_cast<CGImageRef>(cgImage);
if (view != topLevelView) {
+ const CGSize topLevelSize = topLevelView.bounds.size;
view.layer.contentsRect = CGRectApplyAffineTransform(
[view convertRect:view.bounds toView:topLevelView],
// The contentsRect is in unit coordinate system
- CGAffineTransformMakeScale(1.0 / m_image.width(), 1.0 / m_image.height()));
+ CGAffineTransformMakeScale(1.0 / topLevelSize.width, 1.0 / topLevelSize.height));
+ }
+ } else {
+ // 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 QWidgetBackingStore 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;
}
- return;
- }
-
- // 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 QWidgetBackingStore 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();
+ 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;
+ // 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"];
+ 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");
+ // 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");
- // Create temporary image to use for blitting, without copying image data
- NSImage *backingStoreImage = [[[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize] autorelease];
+ // 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))));
+ 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()));
+ 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();
+ CGRect viewRect = viewLocalRect.toCGRect();
- if (windowHasUnifiedToolbar())
- NSDrawWindowBackground(viewRect);
+ if (windowHasUnifiedToolbar())
+ NSDrawWindowBackground(viewRect);
- [backingStoreImage drawInRect:viewRect fromRect:backingStoreRect.toCGRect()
- operation:compositingOperation fraction:1.0 respectFlipped:YES hints:nil];
+ [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()];
+ 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 either CALayer or NSWindow backingstore
+
QCocoaWindow *topLevelCocoaWindow = static_cast<QCocoaWindow *>(topLevelWindow->handle());
if (Q_UNLIKELY(topLevelCocoaWindow->m_needsInvalidateShadow)) {
[topLevelView.window invalidateShadow];
topLevelCocoaWindow->m_needsInvalidateShadow = false;
}
-
- // -------------------------------------------------------------------------
-
- if (shouldHandleViewLockManually)
- [view unlockFocus];
-
- if (drawingOutsideOfDisplayCycle) {
- redrawRoundedBottomCorners([view convertRect:region.boundingRect().toCGRect() toView:nil]);
- [view.window flushWindow];
- }
}
/*
diff --git a/src/plugins/platforms/cocoa/qcocoaclipboard.mm b/src/plugins/platforms/cocoa/qcocoaclipboard.mm
index b4745900dc..a35c153084 100644
--- a/src/plugins/platforms/cocoa/qcocoaclipboard.mm
+++ b/src/plugins/platforms/cocoa/qcocoaclipboard.mm
@@ -56,13 +56,13 @@ QMimeData *QCocoaClipboard::mimeData(QClipboard::Mode mode)
pasteBoard->sync();
return pasteBoard->mimeData();
}
- return 0;
+ return nullptr;
}
void QCocoaClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
{
if (QMacPasteboard *pasteBoard = pasteboardForMode(mode)) {
- if (data == 0) {
+ if (!data) {
pasteBoard->clear();
}
@@ -90,7 +90,7 @@ QMacPasteboard *QCocoaClipboard::pasteboardForMode(QClipboard::Mode mode) const
else if (mode == QClipboard::FindBuffer)
return m_find.data();
else
- return 0;
+ return nullptr;
}
void QCocoaClipboard::handleApplicationStateChanged(Qt::ApplicationState state)
diff --git a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
index aa6124507d..d7850b1481 100644
--- a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
@@ -50,7 +50,14 @@
QT_USE_NAMESPACE
@interface QT_MANGLE_NAMESPACE(QNSColorPanelDelegate) : NSObject<NSWindowDelegate, QNSPanelDelegate>
-{
+- (void)restoreOriginalContentView;
+- (void)updateQtColor;
+- (void)finishOffWithCode:(NSInteger)code;
+@end
+
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
+
+@implementation QNSColorPanelDelegate {
@public
NSColorPanel *mColorPanel;
QCocoaColorDialogHelper *mHelper;
@@ -61,22 +68,14 @@ QT_USE_NAMESPACE
BOOL mDialogIsExecuting;
BOOL mResultSet;
BOOL mClosingDueToKnownButton;
-};
-- (void)restoreOriginalContentView;
-- (void)updateQtColor;
-- (void)finishOffWithCode:(NSInteger)code;
-@end
-
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
-
-@implementation QNSColorPanelDelegate
+}
-- (id)init
+- (instancetype)init
{
self = [super init];
mColorPanel = [NSColorPanel sharedColorPanel];
- mHelper = 0;
- mStolenContentView = 0;
+ mHelper = nullptr;
+ mStolenContentView = nil;
mPanelButtons = nil;
mResultCode = NSModalResponseCancel;
mDialogIsExecuting = false;
@@ -116,9 +115,9 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
[self restoreOriginalContentView];
} else if (!mStolenContentView) {
// steal the color panel's contents view
- mStolenContentView = [mColorPanel contentView];
+ mStolenContentView = mColorPanel.contentView;
[mStolenContentView retain];
- [mColorPanel setContentView:0];
+ mColorPanel.contentView = nil;
// create a new content view and add the stolen one as a subview
mPanelButtons = [[QNSPanelContentsWrapper alloc] initWithPanelDelegate:self];
@@ -310,7 +309,7 @@ public:
void cleanup(QCocoaColorDialogHelper *helper)
{
if (mDelegate->mHelper == helper)
- mDelegate->mHelper = 0;
+ mDelegate->mHelper = nullptr;
}
bool exec()
diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm
index 8c98dc69f7..87a57c78c8 100644
--- a/src/plugins/platforms/cocoa/qcocoacursor.mm
+++ b/src/plugins/platforms/cocoa/qcocoacursor.mm
@@ -80,15 +80,15 @@ void QCocoaCursor::setPos(const QPoint &position)
pos.x = position.x();
pos.y = position.y();
- CGEventRef e = CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, kCGMouseButtonLeft);
+ CGEventRef e = CGEventCreateMouseEvent(nullptr, kCGEventMouseMoved, pos, kCGMouseButtonLeft);
CGEventPost(kCGHIDEventTap, e);
CFRelease(e);
}
NSCursor *QCocoaCursor::convertCursor(QCursor *cursor)
{
- if (cursor == nullptr)
- return 0;
+ if (!cursor)
+ return nil;
const Qt::CursorShape newShape = cursor->shape();
NSCursor *cocoaCursor;
@@ -138,11 +138,11 @@ NSCursor *QCocoaCursor::convertCursor(QCursor *cursor)
cocoaCursor = m_cursors.value(newShape);
if (cocoaCursor && cursor->shape() == Qt::BitmapCursor) {
[cocoaCursor release];
- cocoaCursor = 0;
+ cocoaCursor = nil;
}
- if (cocoaCursor == 0) {
+ if (!cocoaCursor) {
cocoaCursor = createCursorData(cursor);
- if (cocoaCursor == 0)
+ if (!cocoaCursor)
return [NSCursor arrowCursor];
m_cursors.insert(newShape, cocoaCursor);
@@ -211,8 +211,8 @@ NSCursor *QCocoaCursor::createCursorData(QCursor *cursor)
0x07, 0xf0, 0x0f, 0xf8, 0x0f, 0xf8, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0,
0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0 };
#endif
- const uchar *cursorData = 0;
- const uchar *cursorMaskData = 0;
+ const uchar *cursorData = nullptr;
+ const uchar *cursorMaskData = nullptr;
QPoint hotspot = cursor->hotSpot();
switch (cursor->shape()) {
@@ -269,7 +269,7 @@ NSCursor *QCocoaCursor::createCursorData(QCursor *cursor)
#endif
default:
qWarning("Qt: QCursor::update: Invalid cursor shape %d", cursor->shape());
- return 0;
+ return nil;
}
// Create an NSCursor from image data if this a self-provided cursor.
@@ -279,7 +279,7 @@ NSCursor *QCocoaCursor::createCursorData(QCursor *cursor)
return (createCursorFromBitmap(&bitmap, &mask, hotspot));
}
- return 0; // should not happen, all cases covered above
+ return nil; // should not happen, all cases covered above
}
NSCursor *QCocoaCursor::createCursorFromBitmap(const QBitmap *bitmap, const QBitmap *mask, const QPoint hotspot)
diff --git a/src/plugins/platforms/cocoa/qcocoadrag.mm b/src/plugins/platforms/cocoa/qcocoadrag.mm
index e1f36b47a1..09433194a6 100644
--- a/src/plugins/platforms/cocoa/qcocoadrag.mm
+++ b/src/plugins/platforms/cocoa/qcocoadrag.mm
@@ -50,10 +50,10 @@ QT_BEGIN_NAMESPACE
static const int dragImageMaxChars = 26;
QCocoaDrag::QCocoaDrag() :
- m_drag(0)
+ m_drag(nullptr)
{
- m_lastEvent = 0;
- m_lastView = 0;
+ m_lastEvent = nil;
+ m_lastView = nil;
}
QCocoaDrag::~QCocoaDrag()
@@ -73,7 +73,7 @@ QMimeData *QCocoaDrag::dragMimeData()
if (m_drag)
return m_drag->mimeData();
- return 0;
+ return nullptr;
}
Qt::DropAction QCocoaDrag::defaultAction(Qt::DropActions possibleActions,
@@ -140,7 +140,7 @@ Qt::DropAction QCocoaDrag::drag(QDrag *o)
NSPoint event_location = [m_lastEvent locationInWindow];
NSWindow *theWindow = [m_lastEvent window];
- Q_ASSERT(theWindow != nil);
+ Q_ASSERT(theWindow);
event_location.x -= hotSpot.x();
CGFloat flippedY = pmDeviceIndependentSize.height() - hotSpot.y();
event_location.y -= flippedY;
@@ -157,7 +157,7 @@ Qt::DropAction QCocoaDrag::drag(QDrag *o)
[nsimage release];
- m_drag = 0;
+ m_drag = nullptr;
return m_executed_drop_action;
}
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
index 2ffc1395ba..ebf33cf4e2 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
@@ -110,8 +110,8 @@ class QCocoaEventDispatcher : public QAbstractEventDispatcher
Q_DECLARE_PRIVATE(QCocoaEventDispatcher)
public:
- QCocoaEventDispatcher(QAbstractEventDispatcherPrivate &priv, QObject *parent = 0);
- explicit QCocoaEventDispatcher(QObject *parent = 0);
+ QCocoaEventDispatcher(QAbstractEventDispatcherPrivate &priv, QObject *parent = nullptr);
+ explicit QCocoaEventDispatcher(QObject *parent = nullptr);
~QCocoaEventDispatcher();
bool processEvents(QEventLoop::ProcessEventsFlags flags);
@@ -153,6 +153,7 @@ public:
void maybeStopCFRunLoopTimer();
static void runLoopTimerCallback(CFRunLoopTimerRef, void *info);
static void activateTimersSourceCallback(void *info);
+ bool processTimers();
// Set 'blockSendPostedEvents' to true if you _really_ need
// to make sure that qt events are not posted while calling
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
index bf9ba4eccf..b0f2b6d940 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
@@ -120,20 +120,26 @@ void QCocoaEventDispatcherPrivate::runLoopTimerCallback(CFRunLoopTimerRef, void
void QCocoaEventDispatcherPrivate::activateTimersSourceCallback(void *info)
{
QCocoaEventDispatcherPrivate *d = static_cast<QCocoaEventDispatcherPrivate *>(info);
- (void) d->timerInfoList.activateTimers();
- d->maybeStartCFRunLoopTimer();
+ d->processTimers();
d->maybeCancelWaitForMoreEvents();
}
+bool QCocoaEventDispatcherPrivate::processTimers()
+{
+ int activated = timerInfoList.activateTimers();
+ maybeStartCFRunLoopTimer();
+ return activated > 0;
+}
+
void QCocoaEventDispatcherPrivate::maybeStartCFRunLoopTimer()
{
if (timerInfoList.isEmpty()) {
// no active timers, so the CFRunLoopTimerRef should not be active either
- Q_ASSERT(runLoopTimerRef == 0);
+ Q_ASSERT(!runLoopTimerRef);
return;
}
- if (runLoopTimerRef == 0) {
+ if (!runLoopTimerRef) {
// start the CFRunLoopTimer
CFAbsoluteTime ttf = CFAbsoluteTimeGetCurrent();
CFTimeInterval interval;
@@ -150,11 +156,11 @@ void QCocoaEventDispatcherPrivate::maybeStartCFRunLoopTimer()
}
ttf += interval;
- CFRunLoopTimerContext info = { 0, this, 0, 0, 0 };
+ CFRunLoopTimerContext info = { 0, this, nullptr, nullptr, nullptr };
// create the timer with a large interval, as recommended by the CFRunLoopTimerSetNextFireDate()
// documentation, since we will adjust the timer's time-to-fire as needed to keep Qt timers working
- runLoopTimerRef = CFRunLoopTimerCreate(0, ttf, oneyear, 0, 0, QCocoaEventDispatcherPrivate::runLoopTimerCallback, &info);
- Q_ASSERT(runLoopTimerRef != 0);
+ runLoopTimerRef = CFRunLoopTimerCreate(nullptr, ttf, oneyear, 0, 0, QCocoaEventDispatcherPrivate::runLoopTimerCallback, &info);
+ Q_ASSERT(runLoopTimerRef);
CFRunLoopAddTimer(mainRunLoop(), runLoopTimerRef, kCFRunLoopCommonModes);
} else {
@@ -180,12 +186,12 @@ void QCocoaEventDispatcherPrivate::maybeStartCFRunLoopTimer()
void QCocoaEventDispatcherPrivate::maybeStopCFRunLoopTimer()
{
- if (runLoopTimerRef == 0)
+ if (!runLoopTimerRef)
return;
CFRunLoopTimerInvalidate(runLoopTimerRef);
CFRelease(runLoopTimerRef);
- runLoopTimerRef = 0;
+ runLoopTimerRef = nullptr;
}
void QCocoaEventDispatcher::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *obj)
@@ -293,25 +299,25 @@ static bool IsMouseOrKeyEvent( NSEvent* event )
switch( [event type] )
{
- case NSLeftMouseDown:
- case NSLeftMouseUp:
- case NSRightMouseDown:
- case NSRightMouseUp:
- case NSMouseMoved: // ??
- case NSLeftMouseDragged:
- case NSRightMouseDragged:
- case NSMouseEntered:
- case NSMouseExited:
- case NSKeyDown:
- case NSKeyUp:
- case NSFlagsChanged: // key modifiers changed?
- case NSCursorUpdate: // ??
- case NSScrollWheel:
- case NSTabletPoint:
- case NSTabletProximity:
- case NSOtherMouseDown:
- case NSOtherMouseUp:
- case NSOtherMouseDragged:
+ case NSEventTypeLeftMouseDown:
+ case NSEventTypeLeftMouseUp:
+ case NSEventTypeRightMouseDown:
+ case NSEventTypeRightMouseUp:
+ case NSEventTypeMouseMoved: // ??
+ case NSEventTypeLeftMouseDragged:
+ case NSEventTypeRightMouseDragged:
+ case NSEventTypeMouseEntered:
+ case NSEventTypeMouseExited:
+ case NSEventTypeKeyDown:
+ case NSEventTypeKeyUp:
+ case NSEventTypeFlagsChanged: // key modifiers changed?
+ case NSEventTypeCursorUpdate: // ??
+ case NSEventTypeScrollWheel:
+ case NSEventTypeTabletPoint:
+ case NSEventTypeTabletProximity:
+ case NSEventTypeOtherMouseDown:
+ case NSEventTypeOtherMouseUp:
+ case NSEventTypeOtherMouseDragged:
#ifndef QT_NO_GESTURES
case NSEventTypeGesture: // touch events
case NSEventTypeMagnify:
@@ -335,7 +341,7 @@ static inline void qt_mac_waitForMoreEvents(NSString *runLoopMode = NSDefaultRun
// at least one event occur. Setting 'dequeuing' to 'no' in the following call
// causes it to hang under certain circumstances (QTBUG-28283), so we tell it
// to dequeue instead, just to repost the event again:
- NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:[NSDate distantFuture]
inMode:runLoopMode
dequeue:YES];
@@ -368,13 +374,13 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
break;
QMacAutoReleasePool pool;
- NSEvent* event = 0;
+ NSEvent* event = nil;
// First, send all previously excluded input events, if any:
if (!excludeUserEvents) {
while (!d->queuedUserInputEvents.isEmpty()) {
event = static_cast<NSEvent *>(d->queuedUserInputEvents.takeFirst());
- if (!filterNativeEvent("NSEvent", event, 0)) {
+ if (!filterNativeEvent("NSEvent", event, nullptr)) {
[NSApp sendEvent:event];
retVal = true;
}
@@ -432,7 +438,7 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
retVal = true;
} else {
int lastSerialCopy = d->lastSerial;
- bool hadModalSession = d->currentModalSessionCached != 0;
+ const bool hadModalSession = d->currentModalSessionCached;
// We cannot block the thread (and run in a tight loop).
// Instead we will process all current pending events and return.
d->ensureNSAppInitialized();
@@ -460,7 +466,7 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
// Dispatch all non-user events (but que non-user events up for later). In
// this case, we need more control over which events gets dispatched, and
// cannot use [NSApp runModalSession:session]:
- event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ event = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:nil
inMode:NSModalPanelRunLoopMode
dequeue: YES];
@@ -471,15 +477,15 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
d->queuedUserInputEvents.append(event);
continue;
}
- if (!filterNativeEvent("NSEvent", event, 0)) {
+ if (!filterNativeEvent("NSEvent", event, nullptr)) {
[NSApp sendEvent:event];
retVal = true;
}
}
- } while (!d->interrupt && event != nil);
+ } while (!d->interrupt && event);
} else do {
// INVARIANT: No modal window is executing.
- event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ event = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:nil
inMode:NSDefaultRunLoopMode
dequeue: YES];
@@ -492,18 +498,17 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
continue;
}
}
- if (!filterNativeEvent("NSEvent", event, 0)) {
+ if (!filterNativeEvent("NSEvent", event, nullptr)) {
[NSApp sendEvent:event];
retVal = true;
}
}
- } while (!d->interrupt && event != nil);
+ } while (!d->interrupt && event);
if ((d->processEventsFlags & QEventLoop::EventLoopExec) == 0) {
- // when called "manually", always send posted events and timers
+ // When called "manually", always process posted events and timers
d->processPostedEvents();
- retVal = d->timerInfoList.activateTimers() > 0 || retVal;
- d->maybeStartCFRunLoopTimer();
+ retVal = d->processTimers() || retVal;
}
// be sure to return true if the posted event source fired
@@ -514,7 +519,7 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
// event recursion to ensure that we spin the correct modal session.
// We do the interruptLater at the end of the function to ensure that we don't
// disturb the 'wait for more events' below (as deleteLater will post an event):
- if (hadModalSession && d->currentModalSessionCached == 0)
+ if (hadModalSession && !d->currentModalSessionCached)
interruptLater = true;
}
bool canWait = (d->threadData->canWait
@@ -611,11 +616,11 @@ void QCocoaEventDispatcherPrivate::temporarilyStopAllModalSessions()
QCocoaModalSessionInfo &info = cocoaModalSessionStack[i];
if (info.session) {
[NSApp endModalSession:info.session];
- info.session = 0;
+ info.session = nullptr;
[(NSWindow*) info.nswindow release];
}
}
- currentModalSessionCached = 0;
+ currentModalSessionCached = nullptr;
}
NSModalSession QCocoaEventDispatcherPrivate::currentModalSession()
@@ -626,7 +631,7 @@ NSModalSession QCocoaEventDispatcherPrivate::currentModalSession()
return currentModalSessionCached;
if (cocoaModalSessionStack.isEmpty())
- return 0;
+ return nullptr;
int sessionCount = cocoaModalSessionStack.size();
for (int i=0; i<sessionCount; ++i) {
@@ -637,6 +642,8 @@ NSModalSession QCocoaEventDispatcherPrivate::currentModalSession()
if (!info.session) {
QMacAutoReleasePool pool;
QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(info.window->handle());
+ if (!cocoaWindow)
+ continue;
NSWindow *nswindow = cocoaWindow->nativeWindow();
if (!nswindow)
continue;
@@ -647,6 +654,15 @@ NSModalSession QCocoaEventDispatcherPrivate::currentModalSession()
[(NSWindow*) info.nswindow retain];
QRect rect = cocoaWindow->geometry();
info.session = [NSApp beginModalSessionForWindow:nswindow];
+
+ // The call to beginModalSessionForWindow above processes events and may
+ // have deleted or destroyed the window. Check if it's still valid.
+ if (!info.window)
+ continue;
+ cocoaWindow = static_cast<QCocoaWindow *>(info.window->handle());
+ if (!cocoaWindow)
+ continue;
+
if (rect != cocoaWindow->geometry())
cocoaWindow->setGeometry(rect);
}
@@ -717,9 +733,9 @@ void QCocoaEventDispatcherPrivate::cleanupModalSessions()
currentModalSessionCached = info.session;
break;
}
- currentModalSessionCached = 0;
+ currentModalSessionCached = nullptr;
if (info.session) {
- Q_ASSERT(info.nswindow != 0);
+ Q_ASSERT(info.nswindow);
[NSApp endModalSession:info.session];
[(NSWindow *)info.nswindow release];
}
@@ -746,10 +762,10 @@ void QCocoaEventDispatcherPrivate::beginModalSession(QWindow *window)
// currentModalSession). A QCocoaModalSessionInfo is considered pending to be stopped if
// the window pointer is zero, and the session pointer is non-zero (it will be fully
// stopped in cleanupModalSessions()).
- QCocoaModalSessionInfo info = {window, 0, 0};
+ QCocoaModalSessionInfo info = {window, nullptr, nullptr};
cocoaModalSessionStack.push(info);
updateChildrenWorksWhenModal();
- currentModalSessionCached = 0;
+ currentModalSessionCached = nullptr;
}
void QCocoaEventDispatcherPrivate::endModalSession(QWindow *window)
@@ -768,12 +784,12 @@ void QCocoaEventDispatcherPrivate::endModalSession(QWindow *window)
if (!info.window)
endedSessions++;
if (info.window == window) {
- info.window = 0;
+ info.window = nullptr;
if (i + endedSessions == stackSize-1) {
// The top sessions ended. Interrupt the event dispatcher to
// start spinning the correct session immediately.
q->interrupt();
- currentModalSessionCached = 0;
+ currentModalSessionCached = nullptr;
cleanupModalSessionsNeeded = true;
}
}
@@ -782,13 +798,13 @@ void QCocoaEventDispatcherPrivate::endModalSession(QWindow *window)
QCocoaEventDispatcherPrivate::QCocoaEventDispatcherPrivate()
: processEventsFlags(0),
- runLoopTimerRef(0),
+ runLoopTimerRef(nullptr),
blockSendPostedEvents(false),
currentExecIsNSAppRun(false),
nsAppRunCalledByQt(false),
cleanupModalSessionsNeeded(false),
processEventsCalled(0),
- currentModalSessionCached(0),
+ currentModalSessionCached(nullptr),
lastSerial(-1),
interrupt(false)
{
@@ -925,8 +941,8 @@ void QCocoaEventDispatcherPrivate::cancelWaitForMoreEvents()
// In case the event dispatcher is waiting for more
// events somewhere, we post a dummy event to wake it up:
QMacAutoReleasePool pool;
- [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined location:NSZeroPoint
- modifierFlags:0 timestamp:0. windowNumber:0 context:0
+ [NSApp postEvent:[NSEvent otherEventWithType:NSEventTypeApplicationDefined location:NSZeroPoint
+ modifierFlags:0 timestamp:0. windowNumber:0 context:nil
subtype:QtCocoaEventSubTypeWakeup data1:0 data2:0] atStart:NO];
}
@@ -1008,7 +1024,7 @@ QCocoaEventDispatcher::~QCocoaEventDispatcher()
CFRelease(d->firstTimeObserver);
}
-QtCocoaInterruptDispatcher* QtCocoaInterruptDispatcher::instance = 0;
+QtCocoaInterruptDispatcher* QtCocoaInterruptDispatcher::instance = nullptr;
QtCocoaInterruptDispatcher::QtCocoaInterruptDispatcher() : cancelled(false)
{
@@ -1025,7 +1041,7 @@ QtCocoaInterruptDispatcher::~QtCocoaInterruptDispatcher()
{
if (cancelled)
return;
- instance = 0;
+ instance = nullptr;
QCocoaEventDispatcher::instance()->interrupt();
}
@@ -1035,7 +1051,7 @@ void QtCocoaInterruptDispatcher::cancelInterruptLater()
return;
instance->cancelled = true;
delete instance;
- instance = 0;
+ instance = nullptr;
}
void QtCocoaInterruptDispatcher::interruptLater()
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
index 94f2125bad..e7243ec250 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
@@ -50,7 +50,6 @@
#include <private/qguiapplication_p.h>
#include "qt_mac_p.h"
#include "qcocoahelpers.h"
-#include "qcocoamenubar.h"
#include "qcocoaeventdispatcher.h"
#include <qregexp.h>
#include <qbuffer.h>
@@ -81,23 +80,6 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
@interface QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate)
: NSObject<NSOpenSavePanelDelegate>
-{
- @public
- NSOpenPanel *mOpenPanel;
- NSSavePanel *mSavePanel;
- NSView *mAccessoryView;
- NSPopUpButton *mPopUpButton;
- NSTextField *mTextField;
- QCocoaFileDialogHelper *mHelper;
- NSString *mCurrentDir;
-
- int mReturnCode;
-
- SharedPointerFileDialogOptions mOptions;
- QString *mCurrentSelection;
- QStringList *mNameFilterDropDownList;
- QStringList *mSelectedNameFilter;
-}
- (NSString *)strip:(const QString &)label;
- (BOOL)panel:(id)sender shouldEnableURL:(NSURL *)url;
@@ -117,12 +99,27 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSOpenSavePanelDelegate);
-@implementation QNSOpenSavePanelDelegate
+@implementation QNSOpenSavePanelDelegate {
+ @public
+ NSOpenPanel *mOpenPanel;
+ NSSavePanel *mSavePanel;
+ NSView *mAccessoryView;
+ NSPopUpButton *mPopUpButton;
+ NSTextField *mTextField;
+ QCocoaFileDialogHelper *mHelper;
+ NSString *mCurrentDir;
+
+ int mReturnCode;
+
+ SharedPointerFileDialogOptions mOptions;
+ QString *mCurrentSelection;
+ QStringList *mNameFilterDropDownList;
+ QStringList *mSelectedNameFilter;
+}
-- (id)initWithAcceptMode:
- (const QString &)selectFile
- options:(SharedPointerFileDialogOptions)options
- helper:(QCocoaFileDialogHelper *)helper
+- (instancetype)initWithAcceptMode:(const QString &)selectFile
+ options:(SharedPointerFileDialogOptions)options
+ helper:(QCocoaFileDialogHelper *)helper
{
self = [super init];
mOptions = options;
@@ -132,7 +129,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSOpenSavePanelDelegate);
} else {
mSavePanel = [NSSavePanel savePanel];
[mSavePanel setCanSelectHiddenExtension:YES];
- mOpenPanel = 0;
+ mOpenPanel = nil;
}
if ([mSavePanel respondsToSelector:@selector(setLevel:)])
@@ -222,7 +219,6 @@ static QString strippedText(QString s)
|| [self panel:nil shouldEnableURL:url];
[self updateProperties];
- QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder();
[mSavePanel setNameFieldStringValue:selectable ? info.fileName().toNSString() : @""];
[mOpenPanel beginWithCompletionHandler:^(NSInteger result){
@@ -252,9 +248,7 @@ static QString strippedText(QString s)
// Make sure we don't interrupt the runModal call below.
QCocoaEventDispatcher::clearCurrentThreadCocoaEventDispatcherInterruptFlag();
- QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder();
mReturnCode = [mSavePanel runModal];
- QCocoaMenuBar::resetKnownMenuItemsToQt();
QAbstractEventDispatcher::instance()->interrupt();
return (mReturnCode == NSModalResponseOK);
@@ -274,7 +268,6 @@ static QString strippedText(QString s)
|| [self panel:nil shouldEnableURL:url];
[self updateProperties];
- QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder();
[mSavePanel setDirectoryURL: [NSURL fileURLWithPath:mCurrentDir]];
[mSavePanel setNameFieldStringValue:selectable ? info.fileName().toNSString() : @""];
@@ -292,7 +285,7 @@ static QString strippedText(QString s)
BOOL hidden = NO;
if (url) {
CFBooleanRef isHiddenProperty;
- if (CFURLCopyResourcePropertyForKey((__bridge CFURLRef)url, kCFURLIsHiddenKey, &isHiddenProperty, NULL)) {
+ if (CFURLCopyResourcePropertyForKey((__bridge CFURLRef)url, kCFURLIsHiddenKey, &isHiddenProperty, nullptr)) {
hidden = CFBooleanGetValue(isHiddenProperty);
CFRelease(isHiddenProperty);
}
@@ -406,9 +399,9 @@ static QString strippedText(QString s)
{
if (mOpenPanel) {
QList<QUrl> result;
- NSArray* array = [mOpenPanel URLs];
- for (NSUInteger i=0; i<[array count]; ++i) {
- QString path = QString::fromNSString([[array objectAtIndex:i] path]).normalized(QString::NormalizationForm_C);
+ NSArray<NSURL *> *array = [mOpenPanel URLs];
+ for (NSURL *url in array) {
+ QString path = QString::fromNSString(url.path).normalized(QString::NormalizationForm_C);
result << QUrl::fromLocalFile(path);
}
return result;
@@ -522,8 +515,8 @@ static QString strippedText(QString s)
NSRect textRect = { { 0.0, 3.0 }, { 100.0, 25.0 } };
mTextField = [[NSTextField alloc] initWithFrame:textRect];
[[mTextField cell] setFont:[NSFont systemFontOfSize:
- [NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
- [mTextField setAlignment:NSRightTextAlignment];
+ [NSFont systemFontSizeForControlSize:NSControlSizeRegular]]];
+ [mTextField setAlignment:NSTextAlignmentRight];
[mTextField setEditable:false];
[mTextField setSelectable:false];
[mTextField setBordered:false];
@@ -576,7 +569,7 @@ static QString strippedText(QString s)
QT_BEGIN_NAMESPACE
QCocoaFileDialogHelper::QCocoaFileDialogHelper()
- :mDelegate(0)
+ : mDelegate(nil)
{
}
@@ -586,7 +579,7 @@ QCocoaFileDialogHelper::~QCocoaFileDialogHelper()
return;
QMacAutoReleasePool pool;
[mDelegate release];
- mDelegate = 0;
+ mDelegate = nil;
}
void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_selectionChanged(const QString &newPath)
@@ -596,7 +589,6 @@ void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_selectionChanged(const QSt
void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_panelClosed(bool accepted)
{
- QCocoaMenuBar::resetKnownMenuItemsToQt();
if (accepted) {
emit accept();
} else {
diff --git a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm
index 815882ab06..8c0af97a68 100644
--- a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm
@@ -74,7 +74,15 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont)
}
@interface QT_MANGLE_NAMESPACE(QNSFontPanelDelegate) : NSObject<NSWindowDelegate, QNSPanelDelegate>
-{
+- (void)restoreOriginalContentView;
+- (void)updateQtFont;
+- (void)changeFont:(id)sender;
+- (void)finishOffWithCode:(NSInteger)code;
+@end
+
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate);
+
+@implementation QNSFontPanelDelegate {
@public
NSFontPanel *mFontPanel;
QCocoaFontDialogHelper *mHelper;
@@ -84,34 +92,24 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont)
NSInteger mResultCode;
BOOL mDialogIsExecuting;
BOOL mResultSet;
-};
-- (void)restoreOriginalContentView;
-- (void)updateQtFont;
-- (void)changeFont:(id)sender;
-- (void)finishOffWithCode:(NSInteger)code;
-@end
-
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate);
-
-@implementation QNSFontPanelDelegate
+}
-- (id)init
+- (instancetype)init
{
- self = [super init];
- mFontPanel = [NSFontPanel sharedFontPanel];
- mHelper = 0;
- mStolenContentView = 0;
- mPanelButtons = 0;
- mResultCode = NSModalResponseCancel;
- mDialogIsExecuting = false;
- mResultSet = false;
-
- [mFontPanel setRestorable:NO];
- [mFontPanel setDelegate:self];
+ if ((self = [super init])) {
+ mFontPanel = [NSFontPanel sharedFontPanel];
+ mHelper = nullptr;
+ mStolenContentView = nil;
+ mPanelButtons = nil;
+ mResultCode = NSModalResponseCancel;
+ mDialogIsExecuting = false;
+ mResultSet = false;
- [NSFontManager sharedFontManager].target = self; // Action is changeFont:
+ [mFontPanel setRestorable:NO];
+ [mFontPanel setDelegate:self];
- [mFontPanel retain];
+ [mFontPanel retain];
+ }
return self;
}
@@ -119,7 +117,6 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate);
{
[mStolenContentView release];
[mFontPanel setDelegate:nil];
- [NSFontManager sharedFontManager].target = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
@@ -135,9 +132,9 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate);
[self restoreOriginalContentView];
} else if (!mStolenContentView) {
// steal the font panel's contents view
- mStolenContentView = [mFontPanel contentView];
+ mStolenContentView = mFontPanel.contentView;
[mStolenContentView retain];
- [mFontPanel setContentView:0];
+ mFontPanel.contentView = nil;
// create a new content view and add the stolen one as a subview
mPanelButtons = [[QNSPanelContentsWrapper alloc] initWithPanelDelegate:self];
@@ -159,7 +156,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate);
// return stolen stuff to its rightful owner
[mStolenContentView removeFromSuperview];
[mFontPanel setContentView:mStolenContentView];
- mStolenContentView = 0;
+ mStolenContentView = nil;
[mPanelButtons release];
mPanelButtons = nil;
}
@@ -191,7 +188,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate);
// Get selected font
NSFontManager *fontManager = [NSFontManager sharedFontManager];
NSFont *selectedFont = [fontManager selectedFont];
- if (selectedFont == nil) {
+ if (!selectedFont) {
selectedFont = [NSFont systemFontOfSize:[NSFont systemFontSize]];
}
NSFont *panelFont = [fontManager convertFont:selectedFont];
@@ -224,6 +221,13 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate);
return (mResultCode == NSModalResponseOK);
}
+// Future proofing in case _NSTargetForSendAction checks this
+// property before sending us the changeFont: message.
+- (BOOL)worksWhenModal
+{
+ return YES;
+}
+
- (QPlatformDialogHelper::DialogCode)dialogResultCode
{
return (mResultCode == NSModalResponseOK) ? QPlatformDialogHelper::Accepted : QPlatformDialogHelper::Rejected;
@@ -295,7 +299,7 @@ public:
void cleanup(QCocoaFontDialogHelper *helper)
{
if (mDelegate->mHelper == helper)
- mDelegate->mHelper = 0;
+ mDelegate->mHelper = nullptr;
}
bool exec()
@@ -329,7 +333,7 @@ public:
void setCurrentFont(const QFont &font)
{
NSFontManager *mgr = [NSFontManager sharedFontManager];
- const NSFont *nsFont = 0;
+ NSFont *nsFont = nil;
int weight = 5;
NSFontTraitMask mask = 0;
@@ -347,7 +351,7 @@ public:
weight:weight
size:fontInfo.pointSize()];
- [mgr setSelectedFont:const_cast<NSFont *>(nsFont) isMultiple:NO];
+ [mgr setSelectedFont:nsFont isMultiple:NO];
mDelegate->mQtFont = font;
}
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h
index 0530aa8201..eefb1cd0fb 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.h
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h
@@ -41,6 +41,7 @@
#define QCOCOAGLCONTEXT_H
#include <QtCore/QPointer>
+#include <QtCore/private/qcore_mac_p.h>
#include <qpa/qplatformopenglcontext.h>
#include <QtGui/QOpenGLContext>
#include <QtGui/QWindow>
@@ -52,39 +53,35 @@ QT_BEGIN_NAMESPACE
class QCocoaGLContext : public QPlatformOpenGLContext
{
public:
- QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, const QVariant &nativeHandle);
+ QCocoaGLContext(QOpenGLContext *context);
~QCocoaGLContext();
- QSurfaceFormat format() const override;
-
- void swapBuffers(QPlatformSurface *surface) override;
-
bool makeCurrent(QPlatformSurface *surface) override;
+ void swapBuffers(QPlatformSurface *surface) override;
void doneCurrent() override;
- QFunctionPointer getProcAddress(const char *procName) override;
-
void update();
- static NSOpenGLPixelFormat *createNSOpenGLPixelFormat(const QSurfaceFormat &format);
- NSOpenGLContext *nsOpenGLContext() const;
-
+ QSurfaceFormat format() const override;
bool isSharing() const override;
bool isValid() const override;
- void windowWasHidden();
+ NSOpenGLContext *nativeContext() const;
- QVariant nativeHandle() const;
+ QFunctionPointer getProcAddress(const char *procName) override;
private:
- void setActiveWindow(QWindow *window);
+ static NSOpenGLPixelFormat *pixelFormatForSurfaceFormat(const QSurfaceFormat &format);
+
+ bool setDrawable(QPlatformSurface *surface);
void updateSurfaceFormat();
- NSOpenGLContext *m_context;
- NSOpenGLContext *m_shareContext;
+ NSOpenGLContext *m_context = nil;
+ NSOpenGLContext *m_shareContext = nil;
QSurfaceFormat m_format;
- QPointer<QWindow> m_currentWindow;
- bool m_didCheckForSoftwareContext;
+ bool m_didCheckForSoftwareContext = false;
+ QVarLengthArray<QMacScopedObserver, 3> m_updateObservers;
+ QAtomicInt m_needsUpdate = false;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
index 7ffe0003d3..1e1b3907ed 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
@@ -41,14 +41,11 @@
#include "qcocoawindow.h"
#include "qcocoahelpers.h"
#include <qdebug.h>
-#include <QtCore/private/qcore_mac_p.h>
#include <QtPlatformHeaders/qcocoanativecontext.h>
#include <dlfcn.h>
#import <AppKit/AppKit.h>
-QT_BEGIN_NAMESPACE
-
static inline QByteArray getGlString(GLenum param)
{
if (const GLubyte *s = glGetString(param))
@@ -56,109 +53,66 @@ static inline QByteArray getGlString(GLenum param)
return QByteArray();
}
-#if !defined(GL_CONTEXT_FLAGS)
-#define GL_CONTEXT_FLAGS 0x821E
-#endif
-
-#if !defined(GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)
-#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x0001
-#endif
-
-#if !defined(GL_CONTEXT_PROFILE_MASK)
-#define GL_CONTEXT_PROFILE_MASK 0x9126
-#endif
-
-#if !defined(GL_CONTEXT_CORE_PROFILE_BIT)
-#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
-#endif
-
-#if !defined(GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
-#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
-#endif
-
-static void updateFormatFromContext(QSurfaceFormat *format)
+@implementation NSOpenGLPixelFormat (QtHelpers)
+- (GLint)qt_getAttribute:(NSOpenGLPixelFormatAttribute)attribute
{
- Q_ASSERT(format);
-
- // Update the version, profile, and context bit of the format
- int major = 0, minor = 0;
- QByteArray versionString(getGlString(GL_VERSION));
- if (QPlatformOpenGLContext::parseOpenGLVersion(versionString, major, minor)) {
- format->setMajorVersion(major);
- format->setMinorVersion(minor);
- }
-
- format->setProfile(QSurfaceFormat::NoProfile);
-
- Q_ASSERT(format->renderableType() == QSurfaceFormat::OpenGL);
- if (format->version() < qMakePair(3, 0)) {
- format->setOption(QSurfaceFormat::DeprecatedFunctions);
- return;
- }
-
- // Version 3.0 onwards - check if it includes deprecated functionality
- GLint value = 0;
- glGetIntegerv(GL_CONTEXT_FLAGS, &value);
- if (!(value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT))
- format->setOption(QSurfaceFormat::DeprecatedFunctions);
-
- // Debug context option not supported on OS X
-
- if (format->version() < qMakePair(3, 2))
- return;
-
- // Version 3.2 and newer have a profile
- value = 0;
- glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value);
+ int value = 0;
+ [self getValues:&value forAttribute:attribute forVirtualScreen:0];
+ return value;
+}
+@end
- if (value & GL_CONTEXT_CORE_PROFILE_BIT)
- format->setProfile(QSurfaceFormat::CoreProfile);
- else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
- format->setProfile(QSurfaceFormat::CompatibilityProfile);
+@implementation NSOpenGLContext (QtHelpers)
+- (GLint)qt_getParameter:(NSOpenGLContextParameter)parameter
+{
+ int value = 0;
+ [self getValues:&value forParameter:parameter];
+ return value;
}
+@end
- // NSOpenGLContext is not re-entrant (https://openradar.appspot.com/37064579)
-static QMutex s_contextMutex;
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcQpaOpenGLContext, "qt.qpa.openglcontext", QtWarningMsg);
-QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share,
- const QVariant &nativeHandle)
- : m_context(nil),
- m_shareContext(nil),
- m_format(format),
- m_didCheckForSoftwareContext(false)
+QCocoaGLContext::QCocoaGLContext(QOpenGLContext *context)
+ : QPlatformOpenGLContext(), m_format(context->format())
{
+ QVariant nativeHandle = context->nativeHandle();
if (!nativeHandle.isNull()) {
if (!nativeHandle.canConvert<QCocoaNativeContext>()) {
- qWarning("QCocoaGLContext: Requires a QCocoaNativeContext");
+ qCWarning(lcQpaOpenGLContext, "QOpenGLContext native handle must be a QCocoaNativeContext");
return;
}
- QCocoaNativeContext handle = nativeHandle.value<QCocoaNativeContext>();
- NSOpenGLContext *context = handle.context();
- if (!context) {
- qWarning("QCocoaGLContext: No NSOpenGLContext given");
+ m_context = nativeHandle.value<QCocoaNativeContext>().context();
+ if (!m_context) {
+ qCWarning(lcQpaOpenGLContext, "QCocoaNativeContext's NSOpenGLContext can not be null");
return;
}
- m_context = context;
+
[m_context retain];
- m_shareContext = share ? static_cast<QCocoaGLContext *>(share)->nsOpenGLContext() : nil;
- // OpenGL surfaces can be ordered either above(default) or below the NSWindow.
- const GLint order = qt_mac_resolveOption(1, "QT_MAC_OPENGL_SURFACE_ORDER");
- [m_context setValues:&order forParameter:NSOpenGLCPSurfaceOrder];
+
+ // 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;
}
- // we only support OpenGL contexts under Cocoa
+ // ----------- Default case, we own the NSOpenGLContext -----------
+
+ // We only support OpenGL contexts under Cocoa
if (m_format.renderableType() == QSurfaceFormat::DefaultRenderableType)
m_format.setRenderableType(QSurfaceFormat::OpenGL);
if (m_format.renderableType() != QSurfaceFormat::OpenGL)
return;
- QMacAutoReleasePool pool; // For the SG Canvas render thread
-
- m_shareContext = share ? static_cast<QCocoaGLContext *>(share)->nsOpenGLContext() : nil;
+ if (QPlatformOpenGLContext *shareContext = context->shareHandle()) {
+ m_shareContext = static_cast<QCocoaGLContext *>(shareContext)->nativeContext();
- if (m_shareContext) {
// Allow sharing between 3.2 Core and 4.1 Core profile versions in
// cases where NSOpenGLContext creates a 4.1 context where a 3.2
// context was requested. Due to the semantics of QSurfaceFormat
@@ -167,312 +121,359 @@ QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLCo
GLint shareContextRequestedProfile;
[m_shareContext.pixelFormat getValues:&shareContextRequestedProfile
forAttribute:NSOpenGLPFAOpenGLProfile forVirtualScreen:0];
- auto shareContextActualProfile = share->format().version();
+ auto shareContextActualProfile = shareContext->format().version();
- if (shareContextRequestedProfile == NSOpenGLProfileVersion3_2Core &&
- shareContextActualProfile >= qMakePair(4, 1)) {
-
- // There is a mismatch, downgrade requested format to make the
- // NSOpenGLPFAOpenGLProfile attributes match. (NSOpenGLContext will
- // fail to create a new context if there is a mismatch).
+ if (shareContextRequestedProfile == NSOpenGLProfileVersion3_2Core
+ && shareContextActualProfile >= qMakePair(4, 1)) {
+ // There is a mismatch. Downgrade requested format to make the
+ // NSOpenGLPFAOpenGLProfile attributes match. (NSOpenGLContext
+ // will fail to create a new context if there is a mismatch).
if (m_format.version() >= qMakePair(4, 1))
m_format.setVersion(3, 2);
}
}
- // create native context for the requested pixel format and share
- NSOpenGLPixelFormat *pixelFormat = createNSOpenGLPixelFormat(m_format);
+ // ------------------------- Create NSOpenGLContext -------------------------
+
+ NSOpenGLPixelFormat *pixelFormat = [pixelFormatForSurfaceFormat(m_format) autorelease];
m_context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:m_shareContext];
- // retry without sharing on context creation failure.
if (!m_context && m_shareContext) {
- m_shareContext = nil;
+ qCWarning(lcQpaOpenGLContext, "Could not create NSOpenGLContext with shared context, "
+ "falling back to unshared context.");
m_context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
- if (m_context)
- qWarning("QCocoaGLContext: Falling back to unshared context.");
+ m_shareContext = nil;
}
- // give up if we still did not get a native context
- [pixelFormat release];
if (!m_context) {
- qWarning("QCocoaGLContext: Failed to create context.");
+ qCWarning(lcQpaOpenGLContext, "Failed to create NSOpenGLContext");
return;
}
- const GLint interval = format.swapInterval() >= 0 ? format.swapInterval() : 1;
+ // --------------------- Set NSOpenGLContext properties ---------------------
+
+ const GLint interval = m_format.swapInterval() >= 0 ? m_format.swapInterval() : 1;
[m_context setValues:&interval forParameter:NSOpenGLCPSwapInterval];
- if (format.alphaBufferSize() > 0) {
+ if (m_format.alphaBufferSize() > 0) {
int zeroOpacity = 0;
[m_context setValues:&zeroOpacity forParameter:NSOpenGLCPSurfaceOpacity];
}
-
- // OpenGL surfaces can be ordered either above(default) or below the NSWindow.
+ // 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];
updateSurfaceFormat();
}
-QCocoaGLContext::~QCocoaGLContext()
+NSOpenGLPixelFormat *QCocoaGLContext::pixelFormatForSurfaceFormat(const QSurfaceFormat &format)
{
- if (m_currentWindow && m_currentWindow.data()->handle())
- static_cast<QCocoaWindow *>(m_currentWindow.data()->handle())->setCurrentContext(0);
+ QVector<NSOpenGLPixelFormatAttribute> attrs;
- [m_context release];
-}
+ attrs << NSOpenGLPFAOpenGLProfile;
+ if (format.profile() == QSurfaceFormat::CoreProfile) {
+ if (format.version() >= qMakePair(4, 1))
+ attrs << NSOpenGLProfileVersion4_1Core;
+ else if (format.version() >= qMakePair(3, 2))
+ attrs << NSOpenGLProfileVersion3_2Core;
+ else
+ attrs << NSOpenGLProfileVersionLegacy;
+ } else {
+ attrs << NSOpenGLProfileVersionLegacy;
+ }
-QVariant QCocoaGLContext::nativeHandle() const
-{
- return QVariant::fromValue<QCocoaNativeContext>(QCocoaNativeContext(m_context));
-}
+ switch (format.swapBehavior()) {
+ case QSurfaceFormat::SingleBuffer:
+ break; // The NSOpenGLPixelFormat default, no attribute to set
+ case QSurfaceFormat::DefaultSwapBehavior:
+ // Technically this should be single-buffered, but we force double-buffered
+ // FIXME: Why do we force double-buffered?
+ Q_FALLTHROUGH();
+ case QSurfaceFormat::DoubleBuffer:
+ attrs.append(NSOpenGLPFADoubleBuffer);
+ break;
+ case QSurfaceFormat::TripleBuffer:
+ attrs.append(NSOpenGLPFATripleBuffer);
+ break;
+ }
-QSurfaceFormat QCocoaGLContext::format() const
-{
- return m_format;
-}
+ if (format.depthBufferSize() > 0)
+ attrs << NSOpenGLPFADepthSize << format.depthBufferSize();
+ if (format.stencilBufferSize() > 0)
+ attrs << NSOpenGLPFAStencilSize << format.stencilBufferSize();
+ if (format.alphaBufferSize() > 0)
+ attrs << NSOpenGLPFAAlphaSize << format.alphaBufferSize();
+ if (format.redBufferSize() > 0 && format.greenBufferSize() > 0 && format.blueBufferSize() > 0) {
+ const int colorSize = format.redBufferSize() + format.greenBufferSize() + format.blueBufferSize();
+ attrs << NSOpenGLPFAColorSize << colorSize << NSOpenGLPFAMinimumPolicy;
+ }
-void QCocoaGLContext::windowWasHidden()
-{
- // If the window is hidden, we need to unset the m_currentWindow
- // variable so that succeeding makeCurrent's will not abort prematurely
- // because of the optimization in setActiveWindow.
- // Doing a full doneCurrent here is not preferable, because the GL context
- // might be rendering in a different thread at this time.
- m_currentWindow.clear();
-}
+ if (format.samples() > 0) {
+ attrs << NSOpenGLPFAMultisample
+ << NSOpenGLPFASampleBuffers << NSOpenGLPixelFormatAttribute(1)
+ << NSOpenGLPFASamples << NSOpenGLPixelFormatAttribute(format.samples());
+ }
-void QCocoaGLContext::swapBuffers(QPlatformSurface *surface)
-{
- if (surface->surface()->surfaceClass() == QSurface::Offscreen)
- return; // Nothing to do
+ // Allow rendering on GPUs without a connected display
+ attrs << NSOpenGLPFAAllowOfflineRenderers;
- QWindow *window = static_cast<QCocoaWindow *>(surface)->window();
- setActiveWindow(window);
+ // FIXME: Pull this information out of the NSView
+ QByteArray useLayer = qgetenv("QT_MAC_WANTS_LAYER");
+ if (!useLayer.isEmpty() && useLayer.toInt() > 0) {
+ // Disable the software rendering fallback. This makes compositing
+ // OpenGL and raster NSViews using Core Animation layers possible.
+ attrs << NSOpenGLPFANoRecovery;
+ }
- QMutexLocker locker(&s_contextMutex);
- [m_context flushBuffer];
+ attrs << 0; // 0-terminate array
+ return [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs.constData()];
}
-bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface)
+/*!
+ Updates the surface format of this context based on properties of
+ the native context and GL state, so that the result of creating
+ the context is reflected back in QOpenGLContext.
+*/
+void QCocoaGLContext::updateSurfaceFormat()
{
- Q_ASSERT(surface->surface()->supportsOpenGL());
-
- QMacAutoReleasePool pool;
+ NSOpenGLContext *oldContext = [NSOpenGLContext currentContext];
[m_context makeCurrentContext];
- if (surface->surface()->surfaceClass() == QSurface::Offscreen)
- return true;
+ // --------------------- Query GL state ---------------------
- QWindow *window = static_cast<QCocoaWindow *>(surface)->window();
- setActiveWindow(window);
-
- // Disable high-resolution surfaces when using the software renderer, which has the
- // problem that the system silently falls back to a to using a low-resolution buffer
- // when a high-resolution buffer is requested. This is not detectable using the NSWindow
- // convertSizeToBacking and backingScaleFactor APIs. A typical result of this is that Qt
- // will display a quarter of the window content when running in a virtual machine.
- if (!m_didCheckForSoftwareContext) {
- m_didCheckForSoftwareContext = true;
-
- const GLubyte* renderer = glGetString(GL_RENDERER);
- if (qstrcmp((const char *)renderer, "Apple Software Renderer") == 0) {
- NSView *view = static_cast<QCocoaWindow *>(surface)->m_view;
- [view setWantsBestResolutionOpenGLSurface:NO];
- }
+ int major = 0, minor = 0;
+ QByteArray versionString(getGlString(GL_VERSION));
+ if (QPlatformOpenGLContext::parseOpenGLVersion(versionString, major, minor)) {
+ m_format.setMajorVersion(major);
+ m_format.setMinorVersion(minor);
}
- update();
- return true;
-}
+ m_format.setProfile(QSurfaceFormat::NoProfile);
+ if (m_format.version() >= qMakePair(3, 2)) {
+ GLint value = 0;
+ glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value);
+ if (value & GL_CONTEXT_CORE_PROFILE_BIT)
+ m_format.setProfile(QSurfaceFormat::CoreProfile);
+ else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
+ m_format.setProfile(QSurfaceFormat::CompatibilityProfile);
+ }
-void QCocoaGLContext::setActiveWindow(QWindow *window)
-{
- if (window == m_currentWindow.data())
- return;
+ m_format.setOption(QSurfaceFormat::DeprecatedFunctions, [&]() {
+ if (m_format.version() < qMakePair(3, 0)) {
+ return true;
+ } else {
+ GLint value = 0;
+ glGetIntegerv(GL_CONTEXT_FLAGS, &value);
+ return !(value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT);
+ }
+ }());
- if (m_currentWindow && m_currentWindow.data()->handle())
- static_cast<QCocoaWindow *>(m_currentWindow.data()->handle())->setCurrentContext(0);
+ // Debug contexts not supported on macOS
+ m_format.setOption(QSurfaceFormat::DebugContext, false);
- Q_ASSERT(window->handle());
+ // Nor are stereo buffers (deprecated in macOS 10.12)
+ m_format.setOption(QSurfaceFormat::StereoBuffers, false);
- m_currentWindow = window;
+ // ------------------ Query the pixel format ------------------
- QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle());
- cocoaWindow->setCurrentContext(this);
+ NSOpenGLPixelFormat *pixelFormat = m_context.pixelFormat;
- Q_ASSERT(!cocoaWindow->isForeignWindow());
- [qnsview_cast(cocoaWindow->view()) setQCocoaGLContext:this];
-}
+ int colorSize = [pixelFormat qt_getAttribute:NSOpenGLPFAColorSize];
+ colorSize /= 4; // The attribute includes the alpha component
+ m_format.setRedBufferSize(colorSize);
+ m_format.setGreenBufferSize(colorSize);
+ m_format.setBlueBufferSize(colorSize);
-void QCocoaGLContext::updateSurfaceFormat()
-{
- // At present it is impossible to turn an option off on a QSurfaceFormat (see
- // https://codereview.qt-project.org/#change,70599). So we have to populate
- // the actual surface format from scratch
- QSurfaceFormat requestedFormat = m_format;
- m_format = QSurfaceFormat();
- m_format.setRenderableType(QSurfaceFormat::OpenGL);
-
- // CoreGL doesn't require a drawable to make the context current
- CGLContextObj oldContext = CGLGetCurrentContext();
- CGLContextObj ctx = static_cast<CGLContextObj>([m_context CGLContextObj]);
- CGLSetCurrentContext(ctx);
-
- // Get the data that OpenGL provides
- updateFormatFromContext(&m_format);
-
- // Get the data contained within the pixel format
- CGLPixelFormatObj cglPixelFormat = static_cast<CGLPixelFormatObj>(CGLGetPixelFormat(ctx));
- NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithCGLPixelFormatObj:cglPixelFormat];
-
- int colorSize = -1;
- [pixelFormat getValues:&colorSize forAttribute:NSOpenGLPFAColorSize forVirtualScreen:0];
- if (colorSize > 0) {
- // This seems to return the total color buffer depth, including alpha
- m_format.setRedBufferSize(colorSize / 4);
- m_format.setGreenBufferSize(colorSize / 4);
- m_format.setBlueBufferSize(colorSize / 4);
- }
+ // Surfaces on macOS always have an alpha channel, but unless the user requested
+ // one via setAlphaBufferSize(), which triggered setting NSOpenGLCPSurfaceOpacity
+ // to make the surface non-opaque, we don't want to report back the actual alpha
+ // size, as that will make the user believe the alpha channel can be used for
+ // something useful, when in reality it can't, due to the surface being opaque.
+ if (m_format.alphaBufferSize() > 0)
+ m_format.setAlphaBufferSize([pixelFormat qt_getAttribute:NSOpenGLPFAAlphaSize]);
- // The pixel format always seems to return 8 for alpha. However, the framebuffer only
- // seems to have alpha enabled if we requested it explicitly. I can't find any other
- // attribute to check explicitly for this so we use our best guess for alpha.
- int alphaSize = -1;
- [pixelFormat getValues:&alphaSize forAttribute:NSOpenGLPFAAlphaSize forVirtualScreen:0];
- if (alphaSize > 0 && requestedFormat.alphaBufferSize() > 0)
- m_format.setAlphaBufferSize(alphaSize);
-
- int depthSize = -1;
- [pixelFormat getValues:&depthSize forAttribute:NSOpenGLPFADepthSize forVirtualScreen:0];
- if (depthSize > 0)
- m_format.setDepthBufferSize(depthSize);
-
- int stencilSize = -1;
- [pixelFormat getValues:&stencilSize forAttribute:NSOpenGLPFAStencilSize forVirtualScreen:0];
- if (stencilSize > 0)
- m_format.setStencilBufferSize(stencilSize);
-
- int samples = -1;
- [pixelFormat getValues:&samples forAttribute:NSOpenGLPFASamples forVirtualScreen:0];
- if (samples > 0)
- m_format.setSamples(samples);
-
- int doubleBuffered = -1;
- int tripleBuffered = -1;
- [pixelFormat getValues:&doubleBuffered forAttribute:NSOpenGLPFADoubleBuffer forVirtualScreen:0];
- [pixelFormat getValues:&tripleBuffered forAttribute:NSOpenGLPFATripleBuffer forVirtualScreen:0];
-
- if (tripleBuffered == 1)
+ m_format.setDepthBufferSize([pixelFormat qt_getAttribute:NSOpenGLPFADepthSize]);
+ m_format.setStencilBufferSize([pixelFormat qt_getAttribute:NSOpenGLPFAStencilSize]);
+ m_format.setSamples([pixelFormat qt_getAttribute:NSOpenGLPFASamples]);
+
+ if ([pixelFormat qt_getAttribute:NSOpenGLPFATripleBuffer])
m_format.setSwapBehavior(QSurfaceFormat::TripleBuffer);
- else if (doubleBuffered == 1)
+ else if ([pixelFormat qt_getAttribute:NSOpenGLPFADoubleBuffer])
m_format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
else
m_format.setSwapBehavior(QSurfaceFormat::SingleBuffer);
- int steroBuffers = -1;
- [pixelFormat getValues:&steroBuffers forAttribute:NSOpenGLPFAStereo forVirtualScreen:0];
- if (steroBuffers == 1)
- m_format.setOption(QSurfaceFormat::StereoBuffers);
+ // ------------------- Query the context -------------------
- [pixelFormat release];
+ m_format.setSwapInterval([m_context qt_getParameter:NSOpenGLCPSwapInterval]);
- GLint swapInterval = -1;
- [m_context getValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
- if (swapInterval >= 0)
- m_format.setSwapInterval(swapInterval);
+ if (oldContext)
+ [oldContext makeCurrentContext];
+ else
+ [NSOpenGLContext clearCurrentContext];
+}
- // Restore the original context
- CGLSetCurrentContext(oldContext);
+QCocoaGLContext::~QCocoaGLContext()
+{
+ [m_context release];
}
-void QCocoaGLContext::doneCurrent()
+bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface)
{
- if (m_currentWindow && m_currentWindow.data()->handle())
- static_cast<QCocoaWindow *>(m_currentWindow.data()->handle())->setCurrentContext(0);
+ qCDebug(lcQpaOpenGLContext) << "Making" << m_context << "current"
+ << "in" << QThread::currentThread() << "for" << surface;
+
+ Q_ASSERT(surface->surface()->supportsOpenGL());
- m_currentWindow.clear();
+ if (!setDrawable(surface))
+ return false;
- [NSOpenGLContext clearCurrentContext];
-}
+ [m_context makeCurrentContext];
-QFunctionPointer QCocoaGLContext::getProcAddress(const char *procName)
-{
- return (QFunctionPointer)dlsym(RTLD_DEFAULT, procName);
-}
+ if (surface->surface()->surfaceClass() == QSurface::Window) {
+ // Disable high-resolution surfaces when using the software renderer, which has the
+ // problem that the system silently falls back to a to using a low-resolution buffer
+ // when a high-resolution buffer is requested. This is not detectable using the NSWindow
+ // convertSizeToBacking and backingScaleFactor APIs. A typical result of this is that Qt
+ // will display a quarter of the window content when running in a virtual machine.
+ if (!m_didCheckForSoftwareContext) {
+ // FIXME: This ensures we check only once per context,
+ // but the context may be used for multiple surfaces.
+ m_didCheckForSoftwareContext = true;
+
+ const GLubyte* renderer = glGetString(GL_RENDERER);
+ if (qstrcmp((const char *)renderer, "Apple Software Renderer") == 0) {
+ NSView *view = static_cast<QCocoaWindow *>(surface)->m_view;
+ [view setWantsBestResolutionOpenGLSurface:NO];
+ }
+ }
-void QCocoaGLContext::update()
-{
- QMutexLocker locker(&s_contextMutex);
- [m_context update];
+ if (m_needsUpdate.fetchAndStoreRelaxed(false))
+ update();
+ }
+
+ return true;
}
-NSOpenGLPixelFormat *QCocoaGLContext::createNSOpenGLPixelFormat(const QSurfaceFormat &format)
+/*!
+ Sets the drawable object of the NSOpenGLContext, which is the
+ frame buffer that is the target of OpenGL drawing operations.
+*/
+bool QCocoaGLContext::setDrawable(QPlatformSurface *surface)
{
- QVector<NSOpenGLPixelFormatAttribute> attrs;
+ // Make sure any surfaces released during this process are deallocated
+ // straight away, otherwise we may run out of surfaces when spinning a
+ // render-loop that doesn't return to one of the outer pools.
+ QMacAutoReleasePool pool;
- if (format.swapBehavior() == QSurfaceFormat::DoubleBuffer
- || format.swapBehavior() == QSurfaceFormat::DefaultSwapBehavior)
- attrs.append(NSOpenGLPFADoubleBuffer);
- else if (format.swapBehavior() == QSurfaceFormat::TripleBuffer)
- attrs.append(NSOpenGLPFATripleBuffer);
+ if (!surface || surface->surface()->surfaceClass() == QSurface::Offscreen) {
+ // 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;
+ [m_context clearDrawable];
+ return true;
+ }
+ Q_ASSERT(surface->surface()->surfaceClass() == QSurface::Window);
+ QNSView *view = qnsview_cast(static_cast<QCocoaWindow *>(surface)->view());
- // Select OpenGL profile
- attrs << NSOpenGLPFAOpenGLProfile;
- if (format.profile() == QSurfaceFormat::CoreProfile) {
- if (format.version() >= qMakePair(4, 1))
- attrs << NSOpenGLProfileVersion4_1Core;
- else if (format.version() >= qMakePair(3, 2))
- attrs << NSOpenGLProfileVersion3_2Core;
- else
- attrs << NSOpenGLProfileVersionLegacy;
+ if (view == m_context.view)
+ return true;
+
+ // 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
+ // associate the view with the context. That way we will guarantee that
+ // as long as the view is the drawable of the context we will know about
+ // any updates to the view that require surface invalidation.
+
+ auto updateCallback = [this, view]() {
+ Q_ASSERT(QThread::currentThread() == qApp->thread());
+ if (m_context.view != view)
+ return;
+ m_needsUpdate = true;
+ };
+
+ m_updateObservers.clear();
+
+ if (view.layer) {
+ m_updateObservers.append(QMacScopedObserver(view, NSViewFrameDidChangeNotification, updateCallback));
+ m_updateObservers.append(QMacScopedObserver(view.window, NSWindowDidChangeScreenNotification, updateCallback));
} else {
- attrs << NSOpenGLProfileVersionLegacy;
+ m_updateObservers.append(QMacScopedObserver(view, NSViewGlobalFrameDidChangeNotification, updateCallback));
}
- if (format.depthBufferSize() > 0)
- attrs << NSOpenGLPFADepthSize << format.depthBufferSize();
- if (format.stencilBufferSize() > 0)
- attrs << NSOpenGLPFAStencilSize << format.stencilBufferSize();
- if (format.alphaBufferSize() > 0)
- attrs << NSOpenGLPFAAlphaSize << format.alphaBufferSize();
- if ((format.redBufferSize() > 0) &&
- (format.greenBufferSize() > 0) &&
- (format.blueBufferSize() > 0)) {
- const int colorSize = format.redBufferSize() +
- format.greenBufferSize() +
- format.blueBufferSize();
- attrs << NSOpenGLPFAColorSize << colorSize << NSOpenGLPFAMinimumPolicy;
- }
+ m_updateObservers.append(QMacScopedObserver([NSApplication sharedApplication],
+ NSApplicationDidChangeScreenParametersNotification, updateCallback));
- if (format.samples() > 0) {
- attrs << NSOpenGLPFAMultisample
- << NSOpenGLPFASampleBuffers << (NSOpenGLPixelFormatAttribute) 1
- << NSOpenGLPFASamples << (NSOpenGLPixelFormatAttribute) format.samples();
+ // 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
+ if ((m_context.view = view) != view) {
+ qCInfo(lcQpaOpenGLContext) << "Failed to set" << view << "as drawable for" << m_context;
+ m_updateObservers.clear();
+ return false;
}
- if (format.stereo())
- attrs << NSOpenGLPFAStereo;
+ qCInfo(lcQpaOpenGLContext) << "Set drawable for" << m_context << "to" << m_context.view;
+ return true;
+}
- attrs << NSOpenGLPFAAllowOfflineRenderers;
+// 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;
- QByteArray useLayer = qgetenv("QT_MAC_WANTS_LAYER");
- if (!useLayer.isEmpty() && useLayer.toInt() > 0) {
- // Disable the software rendering fallback. This makes compositing
- // OpenGL and raster NSViews using Core Animation layers possible.
- attrs << NSOpenGLPFANoRecovery;
+void QCocoaGLContext::update()
+{
+ // Make sure any surfaces released during this process are deallocated
+ // straight away, otherwise we may run out of surfaces when spinning a
+ // render-loop that doesn't return to one of the outer pools.
+ QMacAutoReleasePool pool;
+
+ QMutexLocker locker(&s_reentrancyMutex);
+ qCInfo(lcQpaOpenGLContext) << "Updating" << m_context << "for" << m_context.view;
+ [m_context update];
+}
+
+void QCocoaGLContext::swapBuffers(QPlatformSurface *surface)
+{
+ qCDebug(lcQpaOpenGLContext) << "Swapping" << m_context
+ << "in" << QThread::currentThread() << "to" << surface;
+
+ if (surface->surface()->surfaceClass() == QSurface::Offscreen)
+ return; // Nothing to do
+
+ if (!setDrawable(surface)) {
+ qCWarning(lcQpaOpenGLContext) << "Can't flush" << m_context
+ << "without" << surface << "as drawable";
+ return;
}
- attrs << 0;
+ QMutexLocker locker(&s_reentrancyMutex);
+ [m_context flushBuffer];
+}
- return [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs.constData()];
+void QCocoaGLContext::doneCurrent()
+{
+ qCDebug(lcQpaOpenGLContext) << "Clearing current context"
+ << [NSOpenGLContext currentContext] << "in" << QThread::currentThread();
+
+ // Note: We do not need to clear the current drawable here.
+ // As long as there is no current context, GL calls will
+ // do nothing.
+
+ [NSOpenGLContext clearCurrentContext];
}
-NSOpenGLContext *QCocoaGLContext::nsOpenGLContext() const
+QSurfaceFormat QCocoaGLContext::format() const
{
- return m_context;
+ return m_format;
}
bool QCocoaGLContext::isValid() const
@@ -485,5 +486,14 @@ bool QCocoaGLContext::isSharing() const
return m_shareContext != nil;
}
-QT_END_NAMESPACE
+NSOpenGLContext *QCocoaGLContext::nativeContext() const
+{
+ return m_context;
+}
+QFunctionPointer QCocoaGLContext::getProcAddress(const char *procName)
+{
+ return (QFunctionPointer)dlsym(RTLD_DEFAULT, procName);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h
index 84632c1487..953bf331bb 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.h
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.h
@@ -62,25 +62,33 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSView));
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcQpaCocoaWindow)
-Q_DECLARE_LOGGING_CATEGORY(lcQpaCocoaDrawing)
-Q_DECLARE_LOGGING_CATEGORY(lcQpaCocoaMouse)
+Q_DECLARE_LOGGING_CATEGORY(lcQpaWindow)
+Q_DECLARE_LOGGING_CATEGORY(lcQpaDrawing)
+Q_DECLARE_LOGGING_CATEGORY(lcQpaMouse)
+Q_DECLARE_LOGGING_CATEGORY(lcQpaScreen)
class QPixmap;
class QString;
// Conversion functions
-QStringList qt_mac_NSArrayToQStringList(void *nsarray);
-void *qt_mac_QStringListToNSMutableArrayVoid(const QStringList &list);
-
-inline NSMutableArray *qt_mac_QStringListToNSMutableArray(const QStringList &qstrlist)
-{ return reinterpret_cast<NSMutableArray *>(qt_mac_QStringListToNSMutableArrayVoid(qstrlist)); }
+QStringList qt_mac_NSArrayToQStringList(NSArray<NSString *> *nsarray);
+NSMutableArray<NSString *> *qt_mac_QStringListToNSMutableArray(const QStringList &list);
NSDragOperation qt_mac_mapDropAction(Qt::DropAction action);
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
@@ -91,6 +99,12 @@ QPointF qt_mac_flip(const QPointF &pos, const QRectF &reference);
QRectF qt_mac_flip(const QRectF &rect, const QRectF &reference);
Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum);
+Qt::MouseButton cocoaButton2QtButton(NSEvent *event);
+
+QEvent::Type cocoaEvent2QtMouseEvent(NSEvent *event);
+
+Qt::MouseButtons cocoaMouseButtons2QtMouseButtons(NSInteger pressedMouseButtons);
+Qt::MouseButtons currentlyPressedMouseButtons();
// strip out '&' characters, and convert "&&" to a single '&', in menu
// text - since menu text is sometimes decorated with these for Windows
@@ -170,12 +184,7 @@ QT_END_NAMESPACE
- (void)onCancelClicked;
@end
-@interface QT_MANGLE_NAMESPACE(QNSPanelContentsWrapper) : NSView {
- NSButton *_okButton;
- NSButton *_cancelButton;
- NSView *_panelContents;
- NSEdgeInsets _panelContentsMargins;
-}
+@interface QT_MANGLE_NAMESPACE(QNSPanelContentsWrapper) : NSView
@property (nonatomic, readonly) NSButton *okButton;
@property (nonatomic, readonly) NSButton *cancelButton;
@@ -187,6 +196,7 @@ QT_END_NAMESPACE
- (NSButton *)createButtonWithTitle:(const char *)title;
- (void)layout;
+
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSPanelContentsWrapper);
@@ -285,26 +295,17 @@ public:
}
private:
- template <std::size_t... Ts>
- struct index {};
-
- template <std::size_t N, std::size_t... Ts>
- struct gen_seq : gen_seq<N - 1, N - 1, Ts...> {};
-
- template <std::size_t... Ts>
- struct gen_seq<0, Ts...> : index<Ts...> {};
-
template <typename ReturnType, bool V>
using if_requires_stret = typename std::enable_if<objc_msgsend_requires_stret<ReturnType>::value == V, ReturnType>::type;
- template <typename ReturnType, std::size_t... Is>
- if_requires_stret<ReturnType, false> msgSendSuper(std::tuple<Args...>& args, index<Is...>)
+ template <typename ReturnType, int... Is>
+ if_requires_stret<ReturnType, false> msgSendSuper(std::tuple<Args...>& args, QtPrivate::IndexesList<Is...>)
{
return qt_msgSendSuper<ReturnType>(m_receiver, m_selector, std::get<Is>(args)...);
}
- template <typename ReturnType, std::size_t... Is>
- if_requires_stret<ReturnType, true> msgSendSuper(std::tuple<Args...>& args, index<Is...>)
+ 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)...);
}
@@ -312,7 +313,7 @@ private:
template <typename ReturnType>
ReturnType msgSendSuper(std::tuple<Args...>& args)
{
- return msgSendSuper<ReturnType>(args, gen_seq<sizeof...(Args)>{});
+ return msgSendSuper<ReturnType>(args, QtPrivate::makeIndexSequence<sizeof...(Args)>{});
}
id m_receiver;
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
index e5954f277c..0f5ddfa49a 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
@@ -57,29 +57,28 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcQpaCocoaWindow, "qt.qpa.cocoa.window");
-Q_LOGGING_CATEGORY(lcQpaCocoaDrawing, "qt.qpa.cocoa.drawing");
-Q_LOGGING_CATEGORY(lcQpaCocoaMouse, "qt.qpa.cocoa.mouse");
+Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window");
+Q_LOGGING_CATEGORY(lcQpaDrawing, "qt.qpa.drawing");
+Q_LOGGING_CATEGORY(lcQpaMouse, "qt.qpa.input.mouse");
+Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.screen");
//
// Conversion Functions
//
-QStringList qt_mac_NSArrayToQStringList(void *nsarray)
+QStringList qt_mac_NSArrayToQStringList(NSArray<NSString *> *array)
{
QStringList result;
- NSArray *array = static_cast<NSArray *>(nsarray);
- for (NSUInteger i=0; i<[array count]; ++i)
- result << QString::fromNSString([array objectAtIndex:i]);
+ for (NSString *string in array)
+ result << QString::fromNSString(string);
return result;
}
-void *qt_mac_QStringListToNSMutableArrayVoid(const QStringList &list)
+NSMutableArray<NSString *> *qt_mac_QStringListToNSMutableArray(const QStringList &list)
{
- NSMutableArray *result = [NSMutableArray arrayWithCapacity:list.size()];
- for (int i=0; i<list.size(); ++i){
- [result addObject:list[i].toNSString()];
- }
+ NSMutableArray<NSString *> *result = [NSMutableArray<NSString *> arrayWithCapacity:list.size()];
+ for (const QString &string : list)
+ [result addObject:string.toNSString()];
return result;
}
@@ -93,6 +92,7 @@ struct dndenum_mapper
static dndenum_mapper dnd_enums[] = {
{ NSDragOperationLink, Qt::LinkAction, true },
{ NSDragOperationMove, Qt::MoveAction, true },
+ { NSDragOperationDelete, Qt::MoveAction, true },
{ NSDragOperationCopy, Qt::CopyAction, true },
{ NSDragOperationGeneric, Qt::CopyAction, false },
{ NSDragOperationEvery, Qt::ActionMask, false },
@@ -161,10 +161,7 @@ Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions)
*/
QNSView *qnsview_cast(NSView *view)
{
- if (![view isKindOfClass:[QNSView class]])
- return nil;
-
- return static_cast<QNSView *>(view);
+ return qt_objc_cast<QNSView *>(view);
}
//
@@ -282,6 +279,90 @@ Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum)
return Qt::NoButton;
}
+/*!
+ \fn Qt::MouseButton cocoaButton2QtButton(NSEvent *event)
+
+ Returns the Qt::Button that corresponds to an NSEvent.buttonNumber.
+
+ \note AppKit will use buttonNumber 0 to indicate both "left button"
+ and "no button". Only NSEvents that describes mouse press/release/dragging
+ events (e.g NSEventTypeOtherMouseDown) will contain a valid
+ button number.
+
+ \note Wacom tablet might not return the correct button number for NSEvent buttonNumber
+ on right clicks. Decide here that the button is the "right" button.
+*/
+Qt::MouseButton cocoaButton2QtButton(NSEvent *event)
+{
+ switch (event.type) {
+ case NSEventTypeMouseMoved:
+ return Qt::NoButton;
+
+ case NSEventTypeRightMouseUp:
+ case NSEventTypeRightMouseDown:
+ case NSEventTypeRightMouseDragged:
+ return Qt::RightButton;
+
+ default:
+ break;
+ }
+
+ return cocoaButton2QtButton(event.buttonNumber);
+}
+
+/*!
+ \fn QEvent::Type cocoaEvent2QtMouseEvent(NSEvent *event)
+
+ Returns the QEvent::Type that corresponds to an NSEvent.type.
+*/
+QEvent::Type cocoaEvent2QtMouseEvent(NSEvent *event)
+{
+ switch (event.type) {
+ case NSEventTypeLeftMouseDown:
+ case NSEventTypeRightMouseDown:
+ case NSEventTypeOtherMouseDown:
+ return QEvent::MouseButtonPress;
+
+ case NSEventTypeLeftMouseUp:
+ case NSEventTypeRightMouseUp:
+ case NSEventTypeOtherMouseUp:
+ return QEvent::MouseButtonRelease;
+
+ case NSEventTypeLeftMouseDragged:
+ case NSEventTypeRightMouseDragged:
+ case NSEventTypeOtherMouseDragged:
+ return QEvent::MouseMove;
+
+ case NSEventTypeMouseMoved:
+ return QEvent::MouseMove;
+
+ default:
+ break;
+ }
+
+ return QEvent::None;
+}
+
+/*!
+ \fn Qt::MouseButtons cocoaMouseButtons2QtMouseButtons(NSInteger pressedMouseButtons)
+
+ Returns the Qt::MouseButtons that corresponds to an NSEvent.pressedMouseButtons.
+*/
+Qt::MouseButtons cocoaMouseButtons2QtMouseButtons(NSInteger pressedMouseButtons)
+{
+ return static_cast<Qt::MouseButton>(pressedMouseButtons & Qt::MouseButtonMask);
+}
+
+/*!
+ \fn Qt::MouseButtons currentlyPressedMouseButtons()
+
+ Returns the Qt::MouseButtons that corresponds to an NSEvent.pressedMouseButtons.
+*/
+Qt::MouseButtons currentlyPressedMouseButtons()
+{
+ return cocoaMouseButtons2QtMouseButtons(NSEvent.pressedMouseButtons);
+}
+
QString qt_mac_removeAmpersandEscapes(QString s)
{
return QPlatformTheme::removeMnemonics(s).trimmed();
@@ -298,7 +379,12 @@ QT_END_NAMESPACE
the target-action for the OK/Cancel buttons and making
sure the layout is consistent.
*/
-@implementation QNSPanelContentsWrapper
+@implementation QNSPanelContentsWrapper {
+ NSButton *_okButton;
+ NSButton *_cancelButton;
+ NSView *_panelContents;
+ NSEdgeInsets _panelContentsMargins;
+}
@synthesize okButton = _okButton;
@synthesize cancelButton = _cancelButton;
@@ -346,7 +432,7 @@ QT_END_NAMESPACE
// FIXME: Not obvious, from Cocoa's documentation, that QString::toNSString() makes a deep copy
button.title = (NSString *)cleanTitle.toCFString();
((NSButtonCell *)button.cell).font =
- [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]];
+ [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSControlSizeRegular]];
[self addSubview:button];
return button;
}
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h
index 301771fd53..7de7e073de 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.h
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.h
@@ -51,6 +51,9 @@
#include "qcocoadrag.h"
#include "qcocoaservices.h"
#include "qcocoakeymapper.h"
+#if QT_CONFIG(vulkan)
+#include "qcocoavulkaninstance.h"
+#endif
#include <QtCore/QScopedPointer>
#include <qpa/qplatformintegration.h>
@@ -86,6 +89,11 @@ public:
QAbstractEventDispatcher *createEventDispatcher() const override;
+#if QT_CONFIG(vulkan)
+ QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) const override;
+ QCocoaVulkanInstance *getCocoaVulkanInstance() const;
+#endif
+
QCoreTextFontDatabase *fontDatabase() const override;
QCocoaNativeInterface *nativeInterface() const override;
QPlatformInputContext *inputContext() const override;
@@ -144,6 +152,9 @@ private:
QScopedPointer<QCocoaServices> mServices;
QScopedPointer<QCocoaKeyMapper> mKeyboardMapper;
+#if QT_CONFIG(vulkan)
+ mutable QCocoaVulkanInstance *mCocoaVulkanInstance = nullptr;
+#endif
QHash<QWindow *, NSToolbar *> mToolbars;
QList<QCocoaWindow *> m_popupWindowStack;
};
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index 55b3805df3..612290c9bd 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -59,6 +59,8 @@
#include <qpa/qplatformoffscreensurface.h>
#include <QtCore/qcoreapplication.h>
+#include <QtPlatformHeaders/qcocoanativecontext.h>
+
#include <QtGui/private/qcoregraphics_p.h>
#ifdef QT_WIDGETS_LIB
@@ -94,11 +96,11 @@ static QCocoaIntegration::Options parseOptions(const QStringList &paramList)
return options;
}
-QCocoaIntegration *QCocoaIntegration::mInstance = 0;
+QCocoaIntegration *QCocoaIntegration::mInstance = nullptr;
QCocoaIntegration::QCocoaIntegration(const QStringList &paramList)
: mOptions(parseOptions(paramList))
- , mFontDb(0)
+ , mFontDb(nullptr)
#ifndef QT_NO_ACCESSIBILITY
, mAccessibility(new QCocoaAccessibility)
#endif
@@ -110,7 +112,7 @@ QCocoaIntegration::QCocoaIntegration(const QStringList &paramList)
, mServices(new QCocoaServices)
, mKeyboardMapper(new QCocoaKeyMapper)
{
- if (mInstance != 0)
+ if (mInstance)
qWarning("Creating multiple Cocoa platform integrations is not supported");
mInstance = this;
@@ -186,7 +188,7 @@ QCocoaIntegration::QCocoaIntegration(const QStringList &paramList)
QCocoaIntegration::~QCocoaIntegration()
{
- mInstance = 0;
+ mInstance = nullptr;
qt_resetNSApplicationSendEvent();
@@ -196,7 +198,7 @@ QCocoaIntegration::~QCocoaIntegration()
QCocoaApplicationDelegate *delegate = [QCocoaApplicationDelegate sharedDelegate];
[delegate removeAppleEventHandlers];
// reset the application delegate
- [[NSApplication sharedApplication] setDelegate: 0];
+ [[NSApplication sharedApplication] setDelegate:nil];
}
#ifndef QT_NO_CLIPBOARD
@@ -225,15 +227,13 @@ QCocoaIntegration::Options QCocoaIntegration::options() const
return mOptions;
}
-Q_LOGGING_CATEGORY(lcCocoaScreen, "qt.qpa.cocoa.screens");
-
/*!
\brief Synchronizes the screen list, adds new screens, removes deleted ones
*/
void QCocoaIntegration::updateScreens()
{
- NSArray *scrs = [NSScreen screens];
- NSMutableArray *screens = [NSMutableArray arrayWithArray:scrs];
+ NSArray<NSScreen *> *scrs = [NSScreen screens];
+ NSMutableArray<NSScreen *> *screens = [NSMutableArray<NSScreen *> arrayWithArray:scrs];
if ([screens count] == 0)
if ([NSScreen mainScreen])
[screens addObject:[NSScreen mainScreen]];
@@ -244,7 +244,7 @@ void QCocoaIntegration::updateScreens()
uint screenCount = [screens count];
for (uint i = 0; i < screenCount; i++) {
NSScreen* scr = [screens objectAtIndex:i];
- CGDirectDisplayID dpy = [[[scr deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue];
+ CGDirectDisplayID dpy = scr.qt_displayId;
// If this screen is a mirror and is not the primary one of the mirror set, ignore it.
// Exception: The NSScreen API has been observed to a return a screen list with one
// mirrored, non-primary screen when Qt is running as a startup item. Always use the
@@ -254,8 +254,8 @@ void QCocoaIntegration::updateScreens()
if (primary != kCGNullDirectDisplay && primary != dpy)
continue;
}
- QCocoaScreen* screen = NULL;
- foreach (QCocoaScreen* existingScr, mScreens)
+ QCocoaScreen* screen = nullptr;
+ foreach (QCocoaScreen* existingScr, mScreens) {
// NSScreen documentation says do not cache the array returned from [NSScreen screens].
// However in practice, we can identify a screen by its pointer: if resolution changes,
// the NSScreen object will be the same instance, just with different values.
@@ -263,14 +263,14 @@ void QCocoaIntegration::updateScreens()
screen = existingScr;
break;
}
+ }
if (screen) {
remainingScreens.remove(screen);
- screen->updateGeometry();
- qCDebug(lcCocoaScreen) << "Updated properties of" << screen;
+ screen->updateProperties();
} else {
screen = new QCocoaScreen(i);
mScreens.append(screen);
- qCDebug(lcCocoaScreen) << "Adding" << screen;
+ qCDebug(lcQpaScreen) << "Adding" << screen;
screenAdded(screen);
}
siblings << screen;
@@ -287,7 +287,7 @@ void QCocoaIntegration::updateScreens()
mScreens.removeOne(screen);
// Prevent stale references to NSScreen during destroy
screen->m_screenIndex = -1;
- qCDebug(lcCocoaScreen) << "Removing" << screen;
+ qCDebug(lcQpaScreen) << "Removing" << screen;
destroyScreen(screen);
}
}
@@ -296,7 +296,7 @@ QCocoaScreen *QCocoaIntegration::screenForNSScreen(NSScreen *nsScreen)
{
NSUInteger index = [[NSScreen screens] indexOfObject:nsScreen];
if (index == NSNotFound)
- return 0;
+ return nullptr;
if (index >= unsigned(mScreens.count()))
updateScreens();
@@ -306,7 +306,7 @@ QCocoaScreen *QCocoaIntegration::screenForNSScreen(NSScreen *nsScreen)
return screen;
}
- return 0;
+ return nullptr;
}
bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) const
@@ -361,10 +361,8 @@ QPlatformOffscreenSurface *QCocoaIntegration::createPlatformOffscreenSurface(QOf
#ifndef QT_NO_OPENGL
QPlatformOpenGLContext *QCocoaIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
- QCocoaGLContext *glContext = new QCocoaGLContext(context->format(),
- context->shareHandle(),
- context->nativeHandle());
- context->setNativeHandle(glContext->nativeHandle());
+ QCocoaGLContext *glContext = new QCocoaGLContext(context);
+ context->setNativeHandle(QVariant::fromValue<QCocoaNativeContext>(glContext->nativeContext()));
return glContext;
}
#endif
@@ -379,6 +377,19 @@ QAbstractEventDispatcher *QCocoaIntegration::createEventDispatcher() const
return new QCocoaEventDispatcher;
}
+#if QT_CONFIG(vulkan)
+QPlatformVulkanInstance *QCocoaIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const
+{
+ mCocoaVulkanInstance = new QCocoaVulkanInstance(instance);
+ return mCocoaVulkanInstance;
+}
+
+QCocoaVulkanInstance *QCocoaIntegration::getCocoaVulkanInstance() const
+{
+ return mCocoaVulkanInstance;
+}
+#endif
+
QCoreTextFontDatabase *QCocoaIntegration::fontDatabase() const
{
return mFontDb.data();
@@ -480,14 +491,14 @@ void QCocoaIntegration::pushPopupWindow(QCocoaWindow *window)
QCocoaWindow *QCocoaIntegration::popPopupWindow()
{
if (m_popupWindowStack.isEmpty())
- return 0;
+ return nullptr;
return m_popupWindowStack.takeLast();
}
QCocoaWindow *QCocoaIntegration::activePopupWindow() const
{
if (m_popupWindowStack.isEmpty())
- return 0;
+ return nullptr;
return m_popupWindowStack.front();
}
diff --git a/src/plugins/platforms/cocoa/qcocoaintrospection.h b/src/plugins/platforms/cocoa/qcocoaintrospection.h
index 1d984b9857..20001ac71d 100644
--- a/src/plugins/platforms/cocoa/qcocoaintrospection.h
+++ b/src/plugins/platforms/cocoa/qcocoaintrospection.h
@@ -76,7 +76,7 @@
QT_BEGIN_NAMESPACE
-void qt_cocoa_change_implementation(Class baseClass, SEL originalSel, Class proxyClass, SEL replacementSel = 0, SEL backupSel = 0);
+void qt_cocoa_change_implementation(Class baseClass, SEL originalSel, Class proxyClass, SEL replacementSel = nil, SEL backupSel = nil);
void qt_cocoa_change_back_implementation(Class baseClass, SEL originalSel, SEL backupSel);
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.h b/src/plugins/platforms/cocoa/qcocoakeymapper.h
index a75e275077..2624f19978 100644
--- a/src/plugins/platforms/cocoa/qcocoakeymapper.h
+++ b/src/plugins/platforms/cocoa/qcocoakeymapper.h
@@ -89,15 +89,12 @@ public:
void clearMappings();
private:
- QCFType<TISInputSourceRef> currentInputSource;
+ QCFType<TISInputSourceRef> currentInputSource = nullptr;
- enum { NullMode, UnicodeMode, OtherMode } keyboard_mode;
- union {
- const UCKeyboardLayout *unicode;
- void *other;
- } keyboard_layout_format;
- KeyboardLayoutKind keyboard_kind;
- UInt32 keyboard_dead;
+ enum { NullMode, UnicodeMode, OtherMode } keyboard_mode = NullMode;
+ const UCKeyboardLayout *keyboard_layout_format = nullptr;
+ KeyboardLayoutKind keyboard_kind = kKLKCHRuchrKind;
+ UInt32 keyboard_dead = 0;
KeyboardLayoutItem *keyLayout[256];
};
diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.mm b/src/plugins/platforms/cocoa/qcocoakeymapper.mm
index 80140505d1..350ae4b9be 100644
--- a/src/plugins/platforms/cocoa/qcocoakeymapper.mm
+++ b/src/plugins/platforms/cocoa/qcocoakeymapper.mm
@@ -341,8 +341,6 @@ static int qt_mac_get_key(int modif, const QChar &key, int virtualKey)
QCocoaKeyMapper::QCocoaKeyMapper()
{
memset(keyLayout, 0, sizeof(keyLayout));
- keyboard_layout_format.unicode = 0;
- currentInputSource = 0;
}
QCocoaKeyMapper::~QCocoaKeyMapper()
@@ -352,31 +350,38 @@ QCocoaKeyMapper::~QCocoaKeyMapper()
Qt::KeyboardModifiers QCocoaKeyMapper::queryKeyboardModifiers()
{
- return qt_mac_get_modifiers(GetCurrentEventKeyModifiers());
+ return qt_mac_get_modifiers(GetCurrentKeyModifiers());
}
bool QCocoaKeyMapper::updateKeyboard()
{
- const UCKeyboardLayout *uchrData = 0;
+ const UCKeyboardLayout *uchrData = nullptr;
QCFType<TISInputSourceRef> source = TISCopyInputMethodKeyboardLayoutOverride();
if (!source)
source = TISCopyCurrentKeyboardInputSource();
if (keyboard_mode != NullMode && source == currentInputSource) {
return false;
}
- Q_ASSERT(source != 0);
+ Q_ASSERT(source);
CFDataRef data = static_cast<CFDataRef>(TISGetInputSourceProperty(source,
kTISPropertyUnicodeKeyLayoutData));
- uchrData = data ? reinterpret_cast<const UCKeyboardLayout *>(CFDataGetBytePtr(data)) : 0;
+ uchrData = data ? reinterpret_cast<const UCKeyboardLayout *>(CFDataGetBytePtr(data)) : nullptr;
keyboard_kind = LMGetKbdType();
if (uchrData) {
- keyboard_layout_format.unicode = 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;
}
@@ -386,7 +391,7 @@ void QCocoaKeyMapper::deleteLayouts()
for (int i = 0; i < 255; ++i) {
if (keyLayout[i]) {
delete keyLayout[i];
- keyLayout[i] = 0;
+ keyLayout[i] = nullptr;
}
}
}
@@ -399,10 +404,8 @@ void QCocoaKeyMapper::clearMappings()
void QCocoaKeyMapper::updateKeyMap(unsigned short macVirtualKey, QChar unicodeKey)
{
- if (updateKeyboard()) {
- // ### Qt 4 did this:
- // QKeyMapper::changeKeyboard();
- }
+ updateKeyboard();
+
if (keyLayout[macVirtualKey])
return;
@@ -414,7 +417,7 @@ void QCocoaKeyMapper::updateKeyMap(unsigned short macVirtualKey, QChar unicodeKe
keyLayout[macVirtualKey]->qtKey[i] = 0;
const UInt32 keyModifier = ((qt_mac_get_mac_modifiers(ModsTbl[i]) >> 8) & 0xFF);
- OSStatus err = UCKeyTranslate(keyboard_layout_format.unicode, macVirtualKey, kUCKeyActionDown, keyModifier,
+ 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]);
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.h b/src/plugins/platforms/cocoa/qcocoamenu.h
index 6db4e04c61..34d8428188 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.h
+++ b/src/plugins/platforms/cocoa/qcocoamenu.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** 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/
**
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index a788ac7d45..7b96fca3f9 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -1,5 +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/
**
@@ -53,7 +54,7 @@
QT_BEGIN_NAMESPACE
QCocoaMenu::QCocoaMenu() :
- m_attachedItem(0),
+ m_attachedItem(nil),
m_updateTimer(0),
m_enabled(true),
m_parentEnabled(true),
@@ -62,14 +63,14 @@ QCocoaMenu::QCocoaMenu() :
{
QMacAutoReleasePool pool;
- m_nativeMenu = [[QCocoaNSMenu alloc] initWithQPAMenu:this];
+ m_nativeMenu = [[QCocoaNSMenu alloc] initWithPlatformMenu:this];
}
QCocoaMenu::~QCocoaMenu()
{
- foreach (QCocoaMenuItem *item, m_menuItems) {
+ for (auto *item : qAsConst(m_menuItems)) {
if (item->menuParent() == this)
- item->setMenuParent(0);
+ item->setMenuParent(nullptr);
}
[m_nativeMenu release];
@@ -79,7 +80,7 @@ void QCocoaMenu::setText(const QString &text)
{
QMacAutoReleasePool pool;
QString stripped = qt_mac_removeAmpersandEscapes(text);
- [m_nativeMenu setTitle:stripped.toNSString()];
+ m_nativeMenu.title = stripped.toNSString();
}
void QCocoaMenu::setMinimumWidth(int width)
@@ -132,7 +133,7 @@ void QCocoaMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *
void QCocoaMenu::insertNative(QCocoaMenuItem *item, QCocoaMenuItem *beforeItem)
{
- setItemTargetAction(item);
+ item->resolveTargetAction();
NSMenuItem *nativeItem = item->nsItem();
// Someone's adding new items after aboutToShow() was emitted
if (isOpen() && nativeItem && item->menu())
@@ -187,25 +188,25 @@ void QCocoaMenu::removeMenuItem(QPlatformMenuItem *menuItem)
}
if (cocoaItem->menuParent() == this)
- cocoaItem->setMenuParent(0);
+ cocoaItem->setMenuParent(nullptr);
// Ignore any parent enabled state
cocoaItem->setParentEnabled(true);
m_menuItems.removeOne(cocoaItem);
if (!cocoaItem->isMerged()) {
- if (m_nativeMenu != [cocoaItem->nsItem() menu]) {
+ if (m_nativeMenu != cocoaItem->nsItem().menu) {
qWarning("Item to remove does not belong to this menu");
return;
}
- [m_nativeMenu removeItem: cocoaItem->nsItem()];
+ [m_nativeMenu removeItem:cocoaItem->nsItem()];
}
}
QCocoaMenuItem *QCocoaMenu::itemOrNull(int index) const
{
if ((index < 0) || (index >= m_menuItems.size()))
- return 0;
+ return nullptr;
return m_menuItems.at(index);
}
@@ -247,8 +248,8 @@ void QCocoaMenu::syncMenuItem_helper(QPlatformMenuItem *menuItem, bool menubarUp
// native item was changed for some reason
if (oldItem) {
if (wasMerged) {
- [oldItem setEnabled:NO];
- [oldItem setHidden:YES];
+ oldItem.enabled = NO;
+ oldItem.hidden = YES;
} else {
[m_nativeMenu removeItem:oldItem];
}
@@ -278,31 +279,27 @@ void QCocoaMenu::syncSeparatorsCollapsible(bool enable)
bool previousIsSeparator = true; // setting to true kills all the separators placed at the top.
NSMenuItem *previousItem = nil;
- NSArray *itemArray = [m_nativeMenu itemArray];
- for (unsigned int i = 0; i < [itemArray count]; ++i) {
- NSMenuItem *item = reinterpret_cast<NSMenuItem *>([itemArray objectAtIndex:i]);
- if ([item isSeparatorItem]) {
- QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([item tag]);
- if (cocoaItem)
+ for (NSMenuItem *item in m_nativeMenu.itemArray) {
+ if (item.separatorItem) {
+ if (auto *cocoaItem = qt_objc_cast<QCocoaNSMenuItem *>(item).platformMenuItem)
cocoaItem->setVisible(!previousIsSeparator);
- [item setHidden:previousIsSeparator];
+ item.hidden = previousIsSeparator;
}
- if (![item isHidden]) {
+ if (!item.hidden) {
previousItem = item;
- previousIsSeparator = ([previousItem isSeparatorItem]);
+ previousIsSeparator = previousItem.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) {
- QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([previousItem tag]);
- if (cocoaItem)
+ if (auto *cocoaItem = qt_objc_cast<QCocoaNSMenuItem *>(previousItem).platformMenuItem)
cocoaItem->setVisible(false);
- [previousItem setHidden:YES];
+ previousItem.hidden = YES;
}
} else {
- foreach (QCocoaMenuItem *item, m_menuItems) {
+ for (auto *item : qAsConst(m_menuItems)) {
if (!item->isSeparator())
continue;
@@ -324,7 +321,7 @@ void QCocoaMenu::setEnabled(bool enabled)
bool QCocoaMenu::isEnabled() const
{
- return m_attachedItem ? [m_attachedItem isEnabled] : m_enabled && m_parentEnabled;
+ return m_attachedItem ? m_attachedItem.enabled : m_enabled && m_parentEnabled;
}
void QCocoaMenu::setVisible(bool visible)
@@ -337,11 +334,11 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
QMacAutoReleasePool pool;
QPoint pos = QPoint(targetRect.left(), targetRect.top() + targetRect.height());
- QCocoaWindow *cocoaWindow = parentWindow ? static_cast<QCocoaWindow *>(parentWindow->handle()) : 0;
+ QCocoaWindow *cocoaWindow = parentWindow ? static_cast<QCocoaWindow *>(parentWindow->handle()) : nullptr;
NSView *view = cocoaWindow ? cocoaWindow->view() : nil;
NSMenuItem *nsItem = item ? ((QCocoaMenuItem *)item)->nsItem() : nil;
- QScreen *screen = 0;
+ QScreen *screen = nullptr;
if (parentWindow)
screen = parentWindow->screen();
if (!screen && !QGuiApplication::screens().isEmpty())
@@ -360,9 +357,9 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
// respect the menu's minimum width.
NSPopUpButtonCell *popupCell = [[[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]
autorelease];
- [popupCell setAltersStateOfSelectedItem:NO];
- [popupCell setTransparent:YES];
- [popupCell setMenu:m_nativeMenu];
+ popupCell.altersStateOfSelectedItem = NO;
+ popupCell.transparent = YES;
+ popupCell.menu = m_nativeMenu;
[popupCell selectItem:nsItem];
QCocoaScreen *cocoaScreen = static_cast<QCocoaScreen *>(screen->handle());
@@ -394,7 +391,7 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
if (view) {
// Finally, we need to synthesize an event.
- NSEvent *menuEvent = [NSEvent mouseEventWithType:NSRightMouseDown
+ NSEvent *menuEvent = [NSEvent mouseEventWithType:NSEventTypeRightMouseDown
location:nsPos
modifierFlags:0
timestamp:0
@@ -405,7 +402,7 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
pressure:1.0];
[NSMenu popUpContextMenu:m_nativeMenu withEvent:menuEvent forView:view];
} else {
- [m_nativeMenu popUpMenuPositioningItem:nsItem atLocation:nsPos inView:0];
+ [m_nativeMenu popUpMenuPositioningItem:nsItem atLocation:nsPos inView:nil];
}
}
@@ -425,17 +422,17 @@ QPlatformMenuItem *QCocoaMenu::menuItemAt(int position) const
if (0 <= position && position < m_menuItems.count())
return m_menuItems.at(position);
- return 0;
+ return nullptr;
}
QPlatformMenuItem *QCocoaMenu::menuItemForTag(quintptr tag) const
{
- foreach (QCocoaMenuItem *item, m_menuItems) {
+ for (auto *item : qAsConst(m_menuItems)) {
if (item->tag() == tag)
return item;
}
- return 0;
+ return nullptr;
}
QList<QCocoaMenuItem *> QCocoaMenu::items() const
@@ -446,7 +443,7 @@ QList<QCocoaMenuItem *> QCocoaMenu::items() const
QList<QCocoaMenuItem *> QCocoaMenu::merged() const
{
QList<QCocoaMenuItem *> result;
- foreach (QCocoaMenuItem *item, m_menuItems) {
+ for (auto *item : qAsConst(m_menuItems)) {
if (item->menu()) { // recurse into submenus
result.append(item->menu()->merged());
continue;
@@ -467,7 +464,7 @@ void QCocoaMenu::propagateEnabledState(bool enabled)
if (!m_enabled && enabled) // Some ancestor was enabled, but this menu is not
return;
- foreach (QCocoaMenuItem *item, m_menuItems) {
+ for (auto *item : qAsConst(m_menuItems)) {
if (QCocoaMenu *menu = item->menu())
menu->propagateEnabledState(enabled);
else
@@ -495,11 +492,4 @@ NSMenuItem *QCocoaMenu::attachedItem() const
return m_attachedItem;
}
-void QCocoaMenu::setItemTargetAction(QCocoaMenuItem *item) const
-{
- auto *nsItem = item->nsItem();
- nsItem.target = m_nativeMenu;
- nsItem.action = @selector(qt_itemFired:);
-}
-
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.h b/src/plugins/platforms/cocoa/qcocoamenubar.h
index 6f3aca3a51..50b6e69720 100644
--- a/src/plugins/platforms/cocoa/qcocoamenubar.h
+++ b/src/plugins/platforms/cocoa/qcocoamenubar.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** 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/
**
@@ -60,17 +60,16 @@ public:
void removeMenu(QPlatformMenu *menu) override;
void syncMenu(QPlatformMenu *menuItem) override;
void handleReparent(QWindow *newParentWindow) override;
+ QWindow *parentWindow() const override;
QPlatformMenu *menuForTag(quintptr tag) const override;
inline NSMenu *nsMenu() const
{ return m_nativeMenu; }
- static void redirectKnownMenuItemsToFirstResponder();
- static void resetKnownMenuItemsToQt();
static void updateMenuBarImmediately();
QList<QCocoaMenuItem*> merged() const;
- NSMenuItem *itemForRole(QPlatformMenuItem::MenuRole r);
+ NSMenuItem *itemForRole(QPlatformMenuItem::MenuRole role);
QCocoaWindow *cocoaWindow() const;
void syncMenu_helper(QPlatformMenu *menu, bool menubarUpdate);
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm
index 61ac5eb7f0..30bff78a36 100644
--- a/src/plugins/platforms/cocoa/qcocoamenubar.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm
@@ -1,5 +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/
**
@@ -67,7 +68,7 @@ QCocoaMenuBar::~QCocoaMenuBar()
#ifdef QT_COCOA_ENABLE_MENU_DEBUG
qDebug() << "~QCocoaMenuBar" << this;
#endif
- foreach (QCocoaMenu *menu, m_menus) {
+ for (auto menu : qAsConst(m_menus)) {
if (!menu)
continue;
NSMenuItem *item = nativeItemForMenu(menu);
@@ -79,14 +80,13 @@ QCocoaMenuBar::~QCocoaMenuBar()
static_menubars.removeOne(this);
if (!m_window.isNull() && m_window->menubar() == this) {
- m_window->setMenubar(0);
+ m_window->setMenubar(nullptr);
// Delete the children first so they do not cause
// the native menu items to be hidden after
// the menu bar was updated
qDeleteAll(children());
updateMenuBarImmediately();
- resetKnownMenuItemsToQt();
}
}
@@ -199,8 +199,8 @@ void QCocoaMenuBar::syncMenu_helper(QPlatformMenu *menu, bool menubarUpdate)
// If the NSMenu has no visble 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])
- if (![item isSeparatorItem] && ![item isHidden]) {
+ for (NSMenuItem *item in cocoaMenu->nsMenu().itemArray)
+ if (!item.separatorItem && !item.hidden) {
shouldHide = NO;
break;
}
@@ -230,7 +230,7 @@ void QCocoaMenuBar::handleReparent(QWindow *newParentWindow)
if (!m_window.isNull())
m_window->setMenubar(nullptr);
- if (newParentWindow == nullptr) {
+ if (!newParentWindow) {
m_window.clear();
} else {
newParentWindow->create();
@@ -241,82 +241,28 @@ void QCocoaMenuBar::handleReparent(QWindow *newParentWindow)
updateMenuBarImmediately();
}
+QWindow *QCocoaMenuBar::parentWindow() const
+{
+ return m_window ? m_window->window() : nullptr;
+}
+
+
QCocoaWindow *QCocoaMenuBar::findWindowForMenubar()
{
if (qApp->focusWindow())
return static_cast<QCocoaWindow*>(qApp->focusWindow()->handle());
- return NULL;
+ return nullptr;
}
QCocoaMenuBar *QCocoaMenuBar::findGlobalMenubar()
{
- foreach (QCocoaMenuBar *mb, static_menubars) {
- if (mb->m_window.isNull())
- return mb;
+ for (auto *menubar : qAsConst(static_menubars)) {
+ if (menubar->m_window.isNull())
+ return menubar;
}
- return NULL;
-}
-
-void QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder()
-{
- // QTBUG-17291: http://forums.macrumors.com/showthread.php?t=1249452
- // When a dialog is opened, shortcuts for actions inside the dialog (cut, paste, ...)
- // continue to go through the same menu items which claimed those shortcuts.
- // They are not keystrokes which we can intercept in any other way; the OS intercepts them.
- // The menu items had to be created by the application. That's why we need roles
- // to identify those "special" menu items which can be useful even when non-Qt
- // native widgets are in focus. When the native widget is focused it will be the
- // first responder, so the menu item needs to have its target be the first responder;
- // this is done by setting it to nil.
-
- // This function will find all menu items on all menus which have
- // "special" roles, set the target and also set the standard actions which
- // apply to those roles. But afterwards it is necessary to call
- // resetKnownMenuItemsToQt() to put back the target and action so that
- // those menu items will go back to invoking their associated QActions.
- foreach (QCocoaMenuBar *mb, static_menubars)
- foreach (QCocoaMenu *m, mb->m_menus)
- foreach (QCocoaMenuItem *i, m->items()) {
- bool known = true;
- switch (i->effectiveRole()) {
- case QPlatformMenuItem::CutRole:
- [i->nsItem() setAction:@selector(cut:)];
- break;
- case QPlatformMenuItem::CopyRole:
- [i->nsItem() setAction:@selector(copy:)];
- break;
- case QPlatformMenuItem::PasteRole:
- [i->nsItem() setAction:@selector(paste:)];
- break;
- case QPlatformMenuItem::SelectAllRole:
- [i->nsItem() setAction:@selector(selectAll:)];
- break;
- // We may discover later that there are other roles/actions which
- // are meaningful to standard native widgets; they can be added.
- default:
- known = false;
- break;
- }
- if (known)
- [i->nsItem() setTarget:nil];
- }
-}
-
-void QCocoaMenuBar::resetKnownMenuItemsToQt()
-{
- // Undo the effect of redirectKnownMenuItemsToFirstResponder():
- // reset the menu items' target/action.
- foreach (QCocoaMenuBar *mb, static_menubars) {
- foreach (QCocoaMenu *m, mb->m_menus) {
- foreach (QCocoaMenuItem *i, m->items()) {
- if (i->effectiveRole() >= QPlatformMenuItem::ApplicationSpecificRole) {
- m->setItemTargetAction(i);
- }
- }
- }
- }
+ return nullptr;
}
void QCocoaMenuBar::updateMenuBarImmediately()
@@ -325,7 +271,7 @@ void QCocoaMenuBar::updateMenuBarImmediately()
QCocoaMenuBar *mb = findGlobalMenubar();
QCocoaWindow *cw = findWindowForMenubar();
- QWindow *win = cw ? cw->window() : 0;
+ QWindow *win = cw ? cw->window() : nullptr;
if (win && (win->flags() & Qt::Popup) == Qt::Popup) {
// context menus, comboboxes, etc. don't need to update the menubar,
// but if an application has only Qt::Tool window(s) on start,
@@ -353,7 +299,7 @@ void QCocoaMenuBar::updateMenuBarImmediately()
#endif
bool disableForModal = mb->shouldDisable(cw);
- foreach (QCocoaMenu *menu, mb->m_menus) {
+ for (auto menu : qAsConst(mb->m_menus)) {
if (!menu)
continue;
NSMenuItem *item = mb->nativeItemForMenu(menu);
@@ -368,16 +314,16 @@ void QCocoaMenuBar::updateMenuBarImmediately()
[loader ensureAppMenuInMenu:mb->nsMenu()];
NSMutableSet *mergedItems = [[NSMutableSet setWithCapacity:mb->merged().count()] retain];
- foreach (QCocoaMenuItem *m, mb->merged()) {
- [mergedItems addObject:m->nsItem()];
- m->syncMerged();
+ for (auto mergedItem : mb->merged()) {
+ [mergedItems addObject:mergedItem->nsItem()];
+ mergedItem->syncMerged();
}
// hide+disable all mergeable items we're not currently using
for (NSMenuItem *mergeable in [loader mergeable]) {
if (![mergedItems containsObject:mergeable]) {
- [mergeable setHidden:YES];
- [mergeable setEnabled:NO];
+ mergeable.hidden = YES;
+ mergeable.enabled = NO;
}
}
@@ -389,7 +335,7 @@ void QCocoaMenuBar::updateMenuBarImmediately()
QList<QCocoaMenuItem*> QCocoaMenuBar::merged() const
{
QList<QCocoaMenuItem*> r;
- foreach (QCocoaMenu* menu, m_menus)
+ for (auto menu : qAsConst(m_menus))
r.append(menu->merged());
return r;
@@ -409,11 +355,11 @@ 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.
- foreach (QWindow *w, topWindows) {
- if (w->isVisible() && w->modality() == Qt::ApplicationModal) {
+ for (auto *window : qAsConst(topWindows)) {
+ if (window->isVisible() && window->modality() == Qt::ApplicationModal) {
// check for other visible windows
- foreach (QWindow *other, topWindows) {
- if ((w != other) && (other->isVisible())) {
+ for (auto *other : qAsConst(topWindows)) {
+ if ((window != other) && (other->isVisible())) {
// INVARIANT: we found another visible window
// on screen other than our modalWidget. We therefore
// disable the menu bar to follow normal modality logic:
@@ -433,21 +379,21 @@ bool QCocoaMenuBar::shouldDisable(QCocoaWindow *active) const
QPlatformMenu *QCocoaMenuBar::menuForTag(quintptr tag) const
{
- foreach (QCocoaMenu *menu, m_menus) {
+ for (auto menu : qAsConst(m_menus))
if (menu->tag() == tag)
return menu;
- }
- return 0;
+ return nullptr;
}
-NSMenuItem *QCocoaMenuBar::itemForRole(QPlatformMenuItem::MenuRole r)
+NSMenuItem *QCocoaMenuBar::itemForRole(QPlatformMenuItem::MenuRole role)
{
- foreach (QCocoaMenu *m, m_menus)
- foreach (QCocoaMenuItem *i, m->items())
- if (i->effectiveRole() == r)
- return i->nsItem();
- return nullptr;
+ for (auto menu : qAsConst(m_menus))
+ for (auto *item : menu->items())
+ if (item->effectiveRole() == role)
+ return item->nsItem();
+
+ return nil;
}
QCocoaWindow *QCocoaMenuBar::cocoaWindow() const
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.h b/src/plugins/platforms/cocoa/qcocoamenuitem.h
index 2b598ee3a0..20fc741fb8 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.h
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** 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/
**
@@ -108,6 +108,7 @@ public:
QCocoaMenu *menu() const { return m_menu; }
MenuRole effectiveRole() const;
+ void resolveTargetAction();
private:
QString mergeText();
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
index f8f9648822..21faa6d985 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
@@ -1,5 +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/
**
@@ -41,6 +42,7 @@
#include "qcocoamenuitem.h"
+#include "qcocoansmenu.h"
#include "qcocoamenu.h"
#include "qcocoamenubar.h"
#include "messages.h"
@@ -49,7 +51,6 @@
#include "qcocoaapplication.h" // for custom application category
#include "qcocoamenuloader.h"
#include <QtGui/private/qcoregraphics_p.h>
-#include <QtCore/qregularexpression.h>
#include <QtCore/QDebug>
@@ -60,13 +61,13 @@ 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 ? NSControlKeyMask : NSCommandKeyMask);
+ ret |= (dontSwap ? NSEventModifierFlagControl : NSEventModifierFlagCommand);
if ((accel_key & Qt::META) == Qt::META)
- ret |= (dontSwap ? NSCommandKeyMask : NSControlKeyMask);
+ ret |= (dontSwap ? NSEventModifierFlagCommand : NSEventModifierFlagControl);
if ((accel_key & Qt::ALT) == Qt::ALT)
- ret |= NSAlternateKeyMask;
+ ret |= NSEventModifierFlagOption;
if ((accel_key & Qt::SHIFT) == Qt::SHIFT)
- ret |= NSShiftKeyMask;
+ ret |= NSEventModifierFlagShift;
return ret;
}
@@ -92,9 +93,9 @@ NSUInteger keySequenceModifierMask(const QKeySequence &accel)
#endif
QCocoaMenuItem::QCocoaMenuItem() :
- m_native(NULL),
+ m_native(nil),
m_itemView(nil),
- m_menu(NULL),
+ m_menu(nullptr),
m_role(NoRole),
m_iconSize(16),
m_textSynced(false),
@@ -112,9 +113,9 @@ QCocoaMenuItem::~QCocoaMenuItem()
QMacAutoReleasePool pool;
if (m_menu && m_menu->menuParent() == this)
- m_menu->setMenuParent(0);
+ m_menu->setMenuParent(nullptr);
if (m_merged) {
- [m_native setHidden:YES];
+ m_native.hidden = YES;
} else {
if (m_menu && m_menu->attachedItem() == m_native)
m_menu->setAttachedItem(nil);
@@ -140,7 +141,7 @@ void QCocoaMenuItem::setMenu(QPlatformMenu *menu)
return;
if (m_menu && m_menu->menuParent() == this) {
- m_menu->setMenuParent(0);
+ m_menu->setMenuParent(nullptr);
// Free the menu from its parent's influence
m_menu->propagateEnabledState(true);
if (m_native && m_menu->attachedItem() == m_native)
@@ -210,82 +211,75 @@ void QCocoaMenuItem::setNativeContents(WId item)
return;
[m_itemView release];
m_itemView = [itemView retain];
- [m_itemView setAutoresizesSubviews:YES];
- [m_itemView setAutoresizingMask:NSViewWidthSizable];
- [m_itemView setHidden:NO];
- [m_itemView setNeedsDisplay:YES];
+ m_itemView.autoresizesSubviews = YES;
+ m_itemView.autoresizingMask = NSViewWidthSizable;
+ m_itemView.hidden = NO;
+ m_itemView.needsDisplay = YES;
}
NSMenuItem *QCocoaMenuItem::sync()
{
- if (m_isSeparator != [m_native isSeparatorItem]) {
+ if (m_isSeparator != m_native.separatorItem) {
[m_native release];
- if (m_isSeparator) {
- m_native = [[NSMenuItem separatorItem] retain];
- [m_native setTag:reinterpret_cast<NSInteger>(this)];
- } else
+ if (m_isSeparator)
+ m_native = [[QCocoaNSMenuItem separatorItemWithPlatformMenuItem:this] retain];
+ else
m_native = nil;
}
if ((m_role != NoRole && !m_textSynced) || m_merged) {
- NSMenuItem *mergeItem = nil;
+ QCocoaMenuBar *menubar = nullptr;
+ if (m_role == TextHeuristicRole) {
+ // Recognized menu roles are only found in the first menus below the menubar
+ QObject *p = menuParent();
+ int depth = 1;
+ while (depth < 3 && p && !(menubar = qobject_cast<QCocoaMenuBar *>(p))) {
+ ++depth;
+ QCocoaMenuObject *menuObject = dynamic_cast<QCocoaMenuObject *>(p);
+ Q_ASSERT(menuObject);
+ p = menuObject->menuParent();
+ }
+
+ if (menubar && depth < 3)
+ m_detectedRole = detectMenuRole(m_text);
+ else
+ m_detectedRole = NoRole;
+ }
+
QCocoaMenuLoader *loader = [QCocoaMenuLoader sharedMenuLoader];
- switch (m_role) {
- case ApplicationSpecificRole:
- mergeItem = [loader appSpecificMenuItem:reinterpret_cast<NSInteger>(this)];
- break;
+ NSMenuItem *mergeItem = nil;
+ const auto role = effectiveRole();
+ switch (role) {
case AboutRole:
mergeItem = [loader aboutMenuItem];
break;
case AboutQtRole:
mergeItem = [loader aboutQtMenuItem];
break;
+ case PreferencesRole:
+ mergeItem = [loader preferencesMenuItem];
+ break;
+ case ApplicationSpecificRole:
+ mergeItem = [loader appSpecificMenuItem:this];
+ break;
case QuitRole:
mergeItem = [loader quitMenuItem];
break;
- case PreferencesRole:
- mergeItem = [loader preferencesMenuItem];
+ case CutRole:
+ case CopyRole:
+ case PasteRole:
+ case SelectAllRole:
+ if (menubar)
+ mergeItem = menubar->itemForRole(role);
break;
- case TextHeuristicRole: {
- QObject *p = menuParent();
- int depth = 1;
- QCocoaMenuBar *menubar = 0;
- while (depth < 3 && p && !(menubar = qobject_cast<QCocoaMenuBar *>(p))) {
- ++depth;
- QCocoaMenuObject *menuObject = dynamic_cast<QCocoaMenuObject *>(p);
- Q_ASSERT(menuObject);
- p = menuObject->menuParent();
- }
- if (depth == 3 || !menubar)
- break; // Menu item too deep in the hierarchy, or not connected to any menubar
-
- m_detectedRole = detectMenuRole(m_text);
- switch (m_detectedRole) {
- case QPlatformMenuItem::AboutRole:
- if (m_text.indexOf(QRegularExpression(QString::fromLatin1("qt$"),
- QRegularExpression::CaseInsensitiveOption)) == -1)
- mergeItem = [loader aboutMenuItem];
- else
- mergeItem = [loader aboutQtMenuItem];
- break;
- case QPlatformMenuItem::PreferencesRole:
- mergeItem = [loader preferencesMenuItem];
- break;
- case QPlatformMenuItem::QuitRole:
- mergeItem = [loader quitMenuItem];
- break;
- default:
- if (m_detectedRole >= CutRole && m_detectedRole < RoleCount && menubar)
- mergeItem = menubar->itemForRole(m_detectedRole);
- if (!m_text.isEmpty())
- m_textSynced = true;
- break;
- }
+ case NoRole:
+ // The heuristic couldn't resolve the menu role
+ m_textSynced = false;
break;
- }
-
default:
- qWarning() << "Menu item" << m_text << "has unsupported role" << m_role;
+ if (!m_text.isEmpty())
+ m_textSynced = true;
+ break;
}
if (mergeItem) {
@@ -294,7 +288,8 @@ NSMenuItem *QCocoaMenuItem::sync()
[mergeItem retain];
[m_native release];
m_native = mergeItem;
- [m_native setTag:reinterpret_cast<NSInteger>(this)];
+ if (auto *nativeItem = qt_objc_cast<QCocoaNSMenuItem *>(m_native))
+ nativeItem.platformMenuItem = this;
} else if (m_merged) {
// was previously merged, but no longer
[m_native release];
@@ -306,14 +301,14 @@ NSMenuItem *QCocoaMenuItem::sync()
}
if (!m_native) {
- m_native = [[NSMenuItem alloc] initWithTitle:m_text.toNSString()
- action:nil
- keyEquivalent:@""];
- [m_native setTag:reinterpret_cast<NSInteger>(this)];
+ m_native = [[QCocoaNSMenuItem alloc] initWithPlatformMenuItem:this];
+ m_native.title = m_text.toNSString();
}
- [m_native setHidden: !m_isVisible];
- [m_native setView:m_itemView];
+ resolveTargetAction();
+
+ m_native.hidden = !m_isVisible;
+ m_native.view = m_itemView;
QString text = mergeText();
#ifndef QT_NO_SHORTCUT
@@ -331,39 +326,35 @@ NSMenuItem *QCocoaMenuItem::sync()
NSFont *customMenuFont = [NSFont fontWithName:m_font.family().toNSString()
size:m_font.pointSize()];
if (customMenuFont) {
- NSArray *keys = [NSArray arrayWithObjects:NSFontAttributeName, nil];
- NSArray *objects = [NSArray arrayWithObjects:customMenuFont, nil];
- NSDictionary *attributes = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
NSAttributedString *str = [[[NSAttributedString alloc] initWithString:finalString.toNSString()
- attributes:attributes] autorelease];
- [m_native setAttributedTitle: str];
+ attributes:@{NSFontAttributeName: customMenuFont}] autorelease];
+ m_native.attributedTitle = str;
useAttributedTitle = true;
}
}
- if (!useAttributedTitle) {
- [m_native setTitle:finalString.toNSString()];
- }
+ if (!useAttributedTitle)
+ m_native.title = finalString.toNSString();
#ifndef QT_NO_SHORTCUT
if (accel.count() == 1) {
- [m_native setKeyEquivalent:keySequenceToKeyEqivalent(accel)];
- [m_native setKeyEquivalentModifierMask:keySequenceModifierMask(accel)];
+ m_native.keyEquivalent = keySequenceToKeyEqivalent(accel);
+ m_native.keyEquivalentModifierMask = keySequenceModifierMask(accel);
} else
#endif
{
- [m_native setKeyEquivalent:@""];
- [m_native setKeyEquivalentModifierMask:NSCommandKeyMask];
+ m_native.keyEquivalent = @"";
+ m_native.keyEquivalentModifierMask = NSEventModifierFlagCommand;
}
NSImage *img = nil;
if (!m_icon.isNull()) {
img = qt_mac_create_nsimage(m_icon, m_iconSize);
- [img setSize:NSMakeSize(m_iconSize, m_iconSize)];
+ img.size = CGSizeMake(m_iconSize, m_iconSize);
}
- [m_native setImage:img];
+ m_native.image = img;
[img release];
- [m_native setState:m_checked ? NSOnState : NSOffState];
+ m_native.state = m_checked ? NSOnState : NSOffState;
return m_native;
}
@@ -408,8 +399,8 @@ void QCocoaMenuItem::syncMerged()
qWarning("Trying to sync a non-merged item");
return;
}
- [m_native setTag:reinterpret_cast<NSInteger>(this)];
- [m_native setHidden: !m_isVisible];
+
+ m_native.hidden = !m_isVisible;
}
void QCocoaMenuItem::setParentEnabled(bool enabled)
@@ -434,4 +425,39 @@ void QCocoaMenuItem::setIconSize(int size)
m_iconSize = size;
}
+void QCocoaMenuItem::resolveTargetAction()
+{
+ if (m_native.separatorItem)
+ return;
+
+ // Some items created by QCocoaMenuLoader are not
+ // instances of QCocoaNSMenuItem and have their
+ // target/action set as Interface Builder would.
+ if (![m_native isMemberOfClass:[QCocoaNSMenuItem class]])
+ return;
+
+ // Use the responder chain and ensure native modal dialogs
+ // continue receiving cut/copy/paste/etc. key equivalents.
+ SEL roleAction;
+ switch (effectiveRole()) {
+ case CutRole:
+ roleAction = @selector(cut:);
+ break;
+ case CopyRole:
+ roleAction = @selector(copy:);
+ break;
+ case PasteRole:
+ roleAction = @selector(paste:);
+ break;
+ case SelectAllRole:
+ roleAction = @selector(selectAll:);
+ break;
+ default:
+ roleAction = @selector(qt_itemFired:);
+ }
+
+ m_native.action = roleAction;
+ m_native.target = nil;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.h b/src/plugins/platforms/cocoa/qcocoamenuloader.h
index 95f347646c..5e83327854 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuloader.h
+++ b/src/plugins/platforms/cocoa/qcocoamenuloader.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -54,42 +54,20 @@
#import <AppKit/AppKit.h>
#include <QtCore/private/qcore_mac_p.h>
-@interface QT_MANGLE_NAMESPACE(QCocoaMenuLoader) : NSResponder
-{
- IBOutlet NSMenu *theMenu;
- IBOutlet NSMenu *appMenu;
- IBOutlet NSMenuItem *quitItem;
- IBOutlet NSMenuItem *preferencesItem;
- IBOutlet NSMenuItem *aboutItem;
- IBOutlet NSMenuItem *aboutQtItem;
- IBOutlet NSMenuItem *hideItem;
- NSMenuItem *lastAppSpecificItem;
- NSMenuItem *servicesItem;
- NSMenuItem *hideAllOthersItem;
- NSMenuItem *showAllItem;
-}
+QT_FORWARD_DECLARE_CLASS(QCocoaMenuItem);
+
+@interface QT_MANGLE_NAMESPACE(QCocoaMenuLoader) : NSObject
+ (instancetype)sharedMenuLoader;
-- (instancetype)init;
-- (void)ensureAppMenuInMenu:(NSMenu *)menu;
-- (void)removeActionsFromAppMenu;
-- (NSMenu *)applicationMenu;
- (NSMenu *)menu;
+- (void)ensureAppMenuInMenu:(NSMenu *)menu;
- (NSMenuItem *)quitMenuItem;
- (NSMenuItem *)preferencesMenuItem;
- (NSMenuItem *)aboutMenuItem;
- (NSMenuItem *)aboutQtMenuItem;
- (NSMenuItem *)hideMenuItem;
-- (NSMenuItem *)appSpecificMenuItem:(NSInteger)tag;
-- (IBAction)terminate:(id)sender;
-- (IBAction)orderFrontStandardAboutPanel:(id)sender;
-- (IBAction)hideOtherApplications:(id)sender;
-- (IBAction)unhideAllApplications:(id)sender;
-- (IBAction)hide:(id)sender;
-- (IBAction)qtDispatcherToQPAMenuItem:(id)sender;
-- (void)orderFrontCharacterPalette:(id)sender;
-- (BOOL)validateMenuItem:(NSMenuItem*)menuItem;
+- (NSMenuItem *)appSpecificMenuItem:(QCocoaMenuItem *)platformItem;
- (void)qtTranslateApplicationMenu;
-- (NSArray *)mergeable;
+- (NSArray<NSMenuItem *> *)mergeable;
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaMenuLoader);
diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.mm b/src/plugins/platforms/cocoa/qcocoamenuloader.mm
index 4432d3e27a..da0fc5c6a1 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuloader.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuloader.mm
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -41,6 +41,7 @@
#include "messages.h"
#include "qcocoahelpers.h"
+#include "qcocoansmenu.h"
#include "qcocoamenubar.h"
#include "qcocoamenuitem.h"
#include "qcocoaintegration.h"
@@ -50,7 +51,19 @@
#include <QtCore/qcoreapplication.h>
#include <QtGui/private/qguiapplication_p.h>
-@implementation QCocoaMenuLoader
+@implementation QCocoaMenuLoader {
+ NSMenu *theMenu;
+ NSMenu *appMenu;
+ NSMenuItem *quitItem;
+ NSMenuItem *preferencesItem;
+ NSMenuItem *aboutItem;
+ NSMenuItem *aboutQtItem;
+ NSMenuItem *hideItem;
+ NSMenuItem *lastAppSpecificItem;
+ NSMenuItem *servicesItem;
+ NSMenuItem *hideAllOthersItem;
+ NSMenuItem *showAllItem;
+}
+ (instancetype)sharedMenuLoader
{
@@ -83,17 +96,19 @@
appItem.submenu = appMenu;
// About Application
- aboutItem = [[NSMenuItem alloc] initWithTitle:[@"About " stringByAppendingString:appName]
- action:@selector(orderFrontStandardAboutPanel:)
- keyEquivalent:@""];
+ aboutItem = [[QCocoaNSMenuItem alloc] init];
+ aboutItem.title = [@"About " stringByAppendingString:appName];
+ // FIXME This seems useless since barely adding a QAction
+ // with AboutRole role will reset the target/action
aboutItem.target = self;
+ aboutItem.action = @selector(orderFrontStandardAboutPanel:);
// Disable until a QAction is associated
aboutItem.enabled = NO;
aboutItem.hidden = YES;
[appMenu addItem:aboutItem];
// About Qt (shameless self-promotion)
- aboutQtItem = [[NSMenuItem alloc] init];
+ aboutQtItem = [[QCocoaNSMenuItem alloc] init];
aboutQtItem.title = @"About Qt";
// Disable until a QAction is associated
aboutQtItem.enabled = NO;
@@ -103,15 +118,19 @@
[appMenu addItem:[NSMenuItem separatorItem]];
// Preferences
- preferencesItem = [[NSMenuItem alloc] initWithTitle:@"Preferences…"
- action:@selector(qtDispatcherToQPAMenuItem:)
- keyEquivalent:@","];
- preferencesItem.target = self;
+ preferencesItem = [[QCocoaNSMenuItem alloc] init];
+ preferencesItem.title = @"Preferences…";
+ preferencesItem.keyEquivalent = @",";
// Disable until a QAction is associated
preferencesItem.enabled = NO;
preferencesItem.hidden = YES;
[appMenu addItem:preferencesItem];
+ // We'll be adding app specific items after this. The macOS HIG state that,
+ // "In general, a Preferences menu item should be the first app-specific menu item."
+ // https://developer.apple.com/macos/human-interface-guidelines/menus/menu-bar-menus/
+ lastAppSpecificItem = preferencesItem;
+
[appMenu addItem:[NSMenuItem separatorItem]];
// Services item and menu
@@ -136,7 +155,7 @@
action:@selector(hideOtherApplications:)
keyEquivalent:@"h"];
hideAllOthersItem.target = self;
- hideAllOthersItem.keyEquivalentModifierMask = NSCommandKeyMask | NSAlternateKeyMask;
+ hideAllOthersItem.keyEquivalentModifierMask = NSEventModifierFlagCommand | NSEventModifierFlagOption;
[appMenu addItem:hideAllOthersItem];
// Show All
@@ -149,10 +168,13 @@
[appMenu addItem:[NSMenuItem separatorItem]];
// Quit Application
- quitItem = [[NSMenuItem alloc] initWithTitle:[@"Quit " stringByAppendingString:appName]
- action:@selector(terminate:)
- keyEquivalent:@"q"];
- quitItem.target = self;
+ quitItem = [[QCocoaNSMenuItem alloc] init];
+ quitItem.title = [@"Quit " stringByAppendingString:appName];
+ quitItem.keyEquivalent = @"q";
+ // This will remain true until synced with a QCocoaMenuItem.
+ // This way, we will always have a functional Quit menu item
+ // even if no QAction is added.
+ quitItem.action = @selector(terminate:);
[appMenu addItem:quitItem];
}
@@ -184,7 +206,7 @@
// windows with different menu bars), we never recreate this menu, but
// instead pull it out the current menu bar and place into the new one:
NSMenu *mainMenu = [NSApp mainMenu];
- if ([NSApp mainMenu] == menu)
+ if (mainMenu == menu)
return; // nothing to do (menu is the current menu bar)!
#ifndef QT_NAMESPACE
@@ -205,17 +227,11 @@
unparentAppMenu(appMenu.supermenu);
NSMenuItem *appMenuItem = [[NSMenuItem alloc] initWithTitle:@"Apple"
- action:nil keyEquivalent:@""];
- [appMenuItem setSubmenu:appMenu];
+ action:nil keyEquivalent:@""];
+ appMenuItem.submenu = appMenu;
[menu insertItem:appMenuItem atIndex:0];
}
-- (void)removeActionsFromAppMenu
-{
- for (NSMenuItem *item in [appMenu itemArray])
- [item setTag:0];
-}
-
- (NSMenu *)menu
{
return [[theMenu retain] autorelease];
@@ -251,41 +267,32 @@
return [[hideItem retain] autorelease];
}
-- (NSMenuItem *)appSpecificMenuItem:(NSInteger)tag
+- (NSMenuItem *)appSpecificMenuItem:(QCocoaMenuItem *)platformItem
{
- NSMenuItem *item = [appMenu itemWithTag:tag];
-
- // No reason to create the item if it already exists. See QTBUG-27202.
- if (item)
- return [[item retain] autorelease];
+ // No reason to create the item if it already exists.
+ for (NSMenuItem *item in appMenu.itemArray)
+ if (qt_objc_cast<QCocoaNSMenuItem *>(item).platformMenuItem == platformItem)
+ return [[item retain] autorelease];
// Create an App-Specific menu item, insert it into the menu and return
// it as an autorelease item.
- item = [[NSMenuItem alloc] init];
+ QCocoaNSMenuItem *item;
+ if (platformItem->isSeparator())
+ item = [[QCocoaNSMenuItem separatorItemWithPlatformMenuItem:platformItem] retain];
+ else
+ item = [[QCocoaNSMenuItem alloc] initWithPlatformMenuItem:platformItem];
+
+ const auto location = [appMenu indexOfItem:lastAppSpecificItem];
- NSInteger location;
- if (lastAppSpecificItem == nil) {
- location = [appMenu indexOfItem:aboutQtItem];
- } else {
- location = [appMenu indexOfItem:lastAppSpecificItem];
+ if (!lastAppSpecificItem.separatorItem)
[lastAppSpecificItem release];
- }
lastAppSpecificItem = item; // Keep track of this for later (i.e., don't release it)
+
[appMenu insertItem:item atIndex:location + 1];
return [[item retain] autorelease];
}
-- (BOOL) acceptsFirstResponder
-{
- return YES;
-}
-
-- (void)terminate:(id)sender
-{
- [NSApp terminate:sender];
-}
-
- (void)orderFrontStandardAboutPanel:(id)sender
{
[NSApp orderFrontStandardAboutPanel:sender];
@@ -308,61 +315,36 @@
- (void)qtTranslateApplicationMenu
{
-
#ifndef QT_NO_TRANSLATION
- [servicesItem setTitle:qt_mac_applicationmenu_string(ServicesAppMenuItem).toNSString()];
- [hideItem setTitle:qt_mac_applicationmenu_string(HideAppMenuItem).arg(qt_mac_applicationName()).toNSString()];
- [hideAllOthersItem setTitle:qt_mac_applicationmenu_string(HideOthersAppMenuItem).toNSString()];
- [showAllItem setTitle:qt_mac_applicationmenu_string(ShowAllAppMenuItem).toNSString()];
- [preferencesItem setTitle:qt_mac_applicationmenu_string(PreferencesAppMenuItem).toNSString()];
- [quitItem setTitle:qt_mac_applicationmenu_string(QuitAppMenuItem).arg(qt_mac_applicationName()).toNSString()];
- [aboutItem setTitle:qt_mac_applicationmenu_string(AboutAppMenuItem).arg(qt_mac_applicationName()).toNSString()];
+ aboutItem.title = qt_mac_applicationmenu_string(AboutAppMenuItem).arg(qt_mac_applicationName()).toNSString();
+ preferencesItem.title = qt_mac_applicationmenu_string(PreferencesAppMenuItem).toNSString();
+ servicesItem.title = qt_mac_applicationmenu_string(ServicesAppMenuItem).toNSString();
+ hideItem.title = qt_mac_applicationmenu_string(HideAppMenuItem).arg(qt_mac_applicationName()).toNSString();
+ hideAllOthersItem.title = qt_mac_applicationmenu_string(HideOthersAppMenuItem).toNSString();
+ showAllItem.title = qt_mac_applicationmenu_string(ShowAllAppMenuItem).toNSString();
+ quitItem.title = qt_mac_applicationmenu_string(QuitAppMenuItem).arg(qt_mac_applicationName()).toNSString();
#endif
}
-- (IBAction)qtDispatcherToQPAMenuItem:(id)sender
-{
- NSMenuItem *item = static_cast<NSMenuItem *>(sender);
- if (item == quitItem) {
- // We got here because someone was once the quitItem, but it has been
- // abandoned (e.g., the menubar was deleted). In the meantime, just do
- // normal QApplication::quit().
- qApp->quit();
- return;
- }
-
- if ([item tag]) {
- QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([item tag]);
- QScopedScopeLevelCounter scopeLevelCounter(QGuiApplicationPrivate::instance()->threadData);
- cocoaItem->activated();
- }
-}
-
-- (void)orderFrontCharacterPalette:(id)sender
-{
- [NSApp orderFrontCharacterPalette:sender];
-}
-
- (BOOL)validateMenuItem:(NSMenuItem*)menuItem
{
- if ([menuItem action] == @selector(hideOtherApplications:)
- || [menuItem action] == @selector(unhideAllApplications:)) {
+ if (menuItem.action == @selector(hideOtherApplications:)
+ || menuItem.action == @selector(unhideAllApplications:))
return [NSApp validateMenuItem:menuItem];
- } else if ([menuItem action] == @selector(hide:)) {
+
+ if (menuItem.action == @selector(hide:)) {
if (QCocoaIntegration::instance()->activePopupWindow())
return NO;
return [NSApp validateMenuItem:menuItem];
- } else if ([menuItem tag]) {
- QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([menuItem tag]);
- return cocoaItem->isEnabled();
- } else {
- return [menuItem isEnabled];
}
+
+ return menuItem.enabled;
}
-- (NSArray*) mergeable
+- (NSArray<NSMenuItem *> *)mergeable
{
- // don't include the quitItem here, since we want it always visible and enabled regardless
+ // Don't include the quitItem here, since we want it always visible and enabled regardless
+ // Note that lastAppSpecificItem may be nil, so we can't use @[] here.
return [NSArray arrayWithObjects:preferencesItem, aboutItem, aboutQtItem, lastAppSpecificItem, nil];
}
diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
index 955b147bfd..7979e430ac 100644
--- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
+++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
@@ -71,6 +71,10 @@
#include <AppKit/AppKit.h>
+#if QT_CONFIG(vulkan)
+#include <MoltenVK/mvk_vulkan.h>
+#endif
+
QT_BEGIN_NAMESPACE
QCocoaNativeInterface::QCocoaNativeInterface()
@@ -81,31 +85,32 @@ QCocoaNativeInterface::QCocoaNativeInterface()
void *QCocoaNativeInterface::nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context)
{
if (!context)
- return 0;
+ return nullptr;
if (resourceString.toLower() == "nsopenglcontext")
return nsOpenGLContextForContext(context);
if (resourceString.toLower() == "cglcontextobj")
return cglContextForContext(context);
- return 0;
+ return nullptr;
}
#endif
void *QCocoaNativeInterface::nativeResourceForWindow(const QByteArray &resourceString, QWindow *window)
{
if (!window->handle())
- return 0;
+ return nullptr;
if (resourceString == "nsview") {
return static_cast<QCocoaWindow *>(window->handle())->m_view;
-#ifndef QT_NO_OPENGL
- } else if (resourceString == "nsopenglcontext") {
- return static_cast<QCocoaWindow *>(window->handle())->currentContext()->nsOpenGLContext();
-#endif
} else if (resourceString == "nswindow") {
return static_cast<QCocoaWindow *>(window->handle())->nativeWindow();
+#if QT_CONFIG(vulkan)
+ } else if (resourceString == "vkSurface") {
+ if (QVulkanInstance *instance = window->vulkanInstance())
+ return static_cast<QCocoaVulkanInstance *>(instance->handle())->createSurface(window);
+#endif
}
- return 0;
+ return nullptr;
}
QPlatformNativeInterface::NativeResourceForIntegrationFunction QCocoaNativeInterface::nativeResourceFunctionForIntegration(const QByteArray &resource)
@@ -143,7 +148,7 @@ QPlatformNativeInterface::NativeResourceForIntegrationFunction QCocoaNativeInter
if (resource.toLower() == "testcontentborderposition")
return NativeResourceForIntegrationFunction(QCocoaNativeInterface::testContentBorderPosition);
- return 0;
+ return nullptr;
}
QPlatformPrinterSupport *QCocoaNativeInterface::createPlatformPrinterSupport()
@@ -152,7 +157,7 @@ QPlatformPrinterSupport *QCocoaNativeInterface::createPlatformPrinterSupport()
return new QCocoaPrinterSupport();
#else
qFatal("Printing is not supported when Qt is configured with -no-widgets");
- return 0;
+ return nullptr;
#endif
}
@@ -166,7 +171,7 @@ void *QCocoaNativeInterface::NSPrintInfoForPrintEngine(QPrintEngine *printEngine
#else
Q_UNUSED(printEngine);
qFatal("Printing is not supported when Qt is configured with -no-widgets");
- return 0;
+ return nullptr;
#endif
}
@@ -180,10 +185,10 @@ QPixmap QCocoaNativeInterface::defaultBackgroundPixmapForQWizard()
CFURLRef url = (CFURLRef)CFArrayGetValueAtIndex(urls, 0);
QCFType<CFBundleRef> bundle = CFBundleCreate(kCFAllocatorDefault, url);
if (bundle) {
- url = CFBundleCopyResourceURL(bundle, CFSTR("Background"), CFSTR("png"), 0);
+ url = CFBundleCopyResourceURL(bundle, CFSTR("Background"), CFSTR("png"), nullptr);
if (url) {
- QCFType<CGImageSourceRef> imageSource = CGImageSourceCreateWithURL(url, 0);
- QCFType<CGImageRef> image = CGImageSourceCreateImageAtIndex(imageSource, 0, 0);
+ QCFType<CGImageSourceRef> imageSource = CGImageSourceCreateWithURL(url, nullptr);
+ QCFType<CGImageRef> image = CGImageSourceCreateImageAtIndex(imageSource, 0, nullptr);
if (image) {
int width = CGImageGetWidth(image);
int height = CGImageGetHeight(image);
@@ -213,18 +218,16 @@ void *QCocoaNativeInterface::cglContextForContext(QOpenGLContext* context)
NSOpenGLContext *nsOpenGLContext = static_cast<NSOpenGLContext*>(nsOpenGLContextForContext(context));
if (nsOpenGLContext)
return [nsOpenGLContext CGLContextObj];
- return 0;
+ return nullptr;
}
void *QCocoaNativeInterface::nsOpenGLContextForContext(QOpenGLContext* context)
{
if (context) {
- QCocoaGLContext *cocoaGLContext = static_cast<QCocoaGLContext *>(context->handle());
- if (cocoaGLContext) {
- return cocoaGLContext->nsOpenGLContext();
- }
+ if (QCocoaGLContext *cocoaGLContext = static_cast<QCocoaGLContext *>(context->handle()))
+ return cocoaGLContext->nativeContext();
}
- return 0;
+ return nullptr;
}
#endif
@@ -256,7 +259,7 @@ void QCocoaNativeInterface::setDockMenu(QPlatformMenu *platformMenu)
QMacAutoReleasePool pool;
QCocoaMenu *cocoaPlatformMenu = static_cast<QCocoaMenu *>(platformMenu);
NSMenu *menu = cocoaPlatformMenu->nsMenu();
- [[QCocoaApplicationDelegate sharedDelegate] setDockMenu:menu];
+ [QCocoaApplicationDelegate sharedDelegate].dockMenu = menu;
}
void *QCocoaNativeInterface::qMenuToNSMenu(QPlatformMenu *platformMenu)
@@ -285,8 +288,9 @@ QImage QCocoaNativeInterface::cgImageToQImage(CGImageRef image)
void QCocoaNativeInterface::setEmbeddedInForeignView(QPlatformWindow *window, bool embedded)
{
+ Q_UNUSED(embedded); // "embedded" state is now automatically detected
QCocoaWindow *cocoaPlatformWindow = static_cast<QCocoaWindow *>(window);
- cocoaPlatformWindow->setEmbeddedInForeignView(embedded);
+ cocoaPlatformWindow->setEmbeddedInForeignView();
}
void QCocoaNativeInterface::registerTouchWindow(QWindow *window, bool enable)
diff --git a/src/plugins/platforms/cocoa/qcocoansmenu.h b/src/plugins/platforms/cocoa/qcocoansmenu.h
index a9c3e4fff9..6cbb6e4a01 100644
--- a/src/plugins/platforms/cocoa/qcocoansmenu.h
+++ b/src/plugins/platforms/cocoa/qcocoansmenu.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -53,12 +53,10 @@
#import <AppKit/AppKit.h>
-#include <QtCore/qpointer.h>
#include <qcocoahelpers.h>
QT_FORWARD_DECLARE_CLASS(QCocoaMenu);
-typedef QPointer<QCocoaMenu> QCocoaMenuPointer;
-
+QT_FORWARD_DECLARE_CLASS(QCocoaMenuItem);
@interface QT_MANGLE_NAMESPACE(QCocoaNSMenuDelegate) : NSObject <NSMenuDelegate>
@@ -72,18 +70,24 @@ typedef QPointer<QCocoaMenu> QCocoaMenuPointer;
@interface QT_MANGLE_NAMESPACE(QCocoaNSMenu) : NSMenu
-@property (readonly, nonatomic) QCocoaMenuPointer qpaMenu;
+@property (readonly, nonatomic) QCocoaMenu *platformMenu;
+
+- (instancetype)initWithPlatformMenu:(QCocoaMenu *)menu;
+
+@end
-- (instancetype)initWithQPAMenu:(QCocoaMenu *)menu;
+@interface QT_MANGLE_NAMESPACE(QCocoaNSMenuItem) : NSMenuItem
-- (void)qt_itemFired:(NSMenuItem *)item;
+@property (nonatomic) QCocoaMenuItem *platformMenuItem;
-- (BOOL)worksWhenModal;
-- (BOOL)validateMenuItem:(NSMenuItem*)item; // NSMenuValidation
++ (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 19a0f950e4..65b0832d9f 100644
--- a/src/plugins/platforms/cocoa/qcocoansmenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoansmenu.mm
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -44,17 +44,15 @@
#include "qcocoawindow.h"
#import "qnsview.h"
-#include <QtCore/qmetaobject.h>
-#include <QtCore/private/qthread_p.h>
-#include <QtGui/private/qguiapplication_p.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qcoreevent.h>
-static NSString *qt_mac_removePrivateUnicode(NSString* string)
+static NSString *qt_mac_removePrivateUnicode(NSString *string)
{
- int len = [string length];
- if (len) {
- QVarLengthArray <unichar, 10> characters(len);
+ if (const int len = string.length) {
+ QVarLengthArray<unichar, 10> characters(len);
bool changed = false;
- for (int i = 0; i<len; i++) {
+ for (int i = 0; i < len; i++) {
characters[i] = [string characterAtIndex:i];
// check if they belong to key codes in private unicode range
// currently we need to handle only the NSDeleteFunctionKey
@@ -70,11 +68,14 @@ static NSString *qt_mac_removePrivateUnicode(NSString* string)
}
@implementation QCocoaNSMenu
+{
+ QPointer<QCocoaMenu> _platformMenu;
+}
-- (instancetype)initWithQPAMenu:(QCocoaMenu *)menu
+- (instancetype)initWithPlatformMenu:(QCocoaMenu *)menu
{
if ((self = [super initWithTitle:@"Untitled"])) {
- _qpaMenu = menu;
+ _platformMenu = menu;
self.autoenablesItems = YES;
self.delegate = [QCocoaNSMenuDelegate sharedMenuDelegate];
}
@@ -82,46 +83,58 @@ static NSString *qt_mac_removePrivateUnicode(NSString* string)
return self;
}
-// Cocoa will query the menu item's target for the worksWhenModal selector.
-// So we need to implement this to allow the items to be handled correctly
-// when a modal dialog is visible. See documentation for NSMenuItem.target.
-- (BOOL)worksWhenModal
+- (QCocoaMenu *)platformMenu
{
- if (!QGuiApplication::modalWindow())
- return YES;
- if (const auto *mb = qobject_cast<QCocoaMenuBar *>(self.qpaMenu->menuParent()))
- return QGuiApplication::modalWindow()->handle() == mb->cocoaWindow() ? YES : NO;
- return YES;
+ return _platformMenu.data();
}
-- (void)qt_itemFired:(NSMenuItem *)item
+@end
+
+@implementation QCocoaNSMenuItem
{
- auto *qpaItem = reinterpret_cast<QCocoaMenuItem *>(item.tag);
- // Menu-holding items also get a target to play nicely
- // with NSMenuValidation but should not trigger.
- if (!qpaItem || qpaItem->menu())
- return;
+ QPointer<QCocoaMenuItem> _platformMenuItem;
+}
- QScopedScopeLevelCounter scopeLevelCounter(QGuiApplicationPrivate::instance()->threadData);
- QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers:[NSEvent modifierFlags]];
++ (instancetype)separatorItemWithPlatformMenuItem:(QCocoaMenuItem *)menuItem
+{
+ // Safe because +[NSMenuItem separatorItem] invokes [[self alloc] init]
+ auto *item = qt_objc_cast<QCocoaNSMenuItem *>([self separatorItem]);
+ Q_ASSERT_X(item, qPrintable(__FUNCTION__),
+ "Did +[NSMenuItem separatorItem] not invoke [[self alloc] init]?");
+ if (item)
+ item.platformMenuItem = menuItem;
+
+ return item;
+}
- static QMetaMethod activatedSignal = QMetaMethod::fromSignal(&QCocoaMenuItem::activated);
- activatedSignal.invoke(qpaItem, Qt::QueuedConnection);
+- (instancetype)initWithPlatformMenuItem:(QCocoaMenuItem *)menuItem
+{
+ if ((self = [super initWithTitle:@"" action:nil keyEquivalent:@""])) {
+ _platformMenuItem = menuItem;
+ }
+
+ return self;
}
-- (BOOL)validateMenuItem:(NSMenuItem*)item
+- (instancetype)init
{
- auto *qpaItem = reinterpret_cast<QCocoaMenuItem *>(item.tag);
- // Menu-holding items are always enabled, as it's conventional in Cocoa
- if (!qpaItem || qpaItem->menu())
- return YES;
+ return [self initWithPlatformMenuItem:nullptr];
+}
- return qpaItem->isEnabled();
+- (QCocoaMenuItem *)platformMenuItem
+{
+ return _platformMenuItem.data();
+}
+
+- (void)setPlatformMenuItem:(QCocoaMenuItem *)menuItem
+{
+ _platformMenuItem = menuItem;
}
@end
-#define CHECK_MENU_CLASS(menu) Q_ASSERT([menu isMemberOfClass:[QCocoaNSMenu class]])
+#define CHECK_MENU_CLASS(menu) Q_ASSERT_X([menu isMemberOfClass:[QCocoaNSMenu class]], \
+ __FUNCTION__, "Menu is not a QCocoaNSMenu")
@implementation QCocoaNSMenuDelegate
@@ -153,14 +166,15 @@ static NSString *qt_mac_removePrivateUnicode(NSString* string)
if (shouldCancel)
return NO;
- const auto &qpaMenu = static_cast<QCocoaNSMenu *>(menu).qpaMenu;
- if (qpaMenu.isNull())
+ const auto &platformMenu = static_cast<QCocoaNSMenu *>(menu).platformMenu;
+ if (!platformMenu)
return YES;
- auto *menuItem = reinterpret_cast<QCocoaMenuItem *>(item.tag);
- if (qpaMenu->items().contains(menuItem)) {
- if (QCocoaMenu *itemSubmenu = menuItem->menu())
- itemSubmenu->setAttachedItem(item);
+ if (auto *platformItem = qt_objc_cast<QCocoaNSMenuItem *>(item).platformMenuItem) {
+ if (platformMenu->items().contains(platformItem)) {
+ if (auto *itemSubmenu = platformItem->menu())
+ itemSubmenu->setAttachedItem(item);
+ }
}
return YES;
@@ -169,32 +183,31 @@ static NSString *qt_mac_removePrivateUnicode(NSString* string)
- (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item
{
CHECK_MENU_CLASS(menu);
- auto *qpaItem = reinterpret_cast<QCocoaMenuItem *>(item.tag);
- if (qpaItem)
- qpaItem->hovered();
+ if (auto *platformItem = qt_objc_cast<QCocoaNSMenuItem *>(item).platformMenuItem)
+ emit platformItem->hovered();
}
- (void)menuWillOpen:(NSMenu *)menu
{
CHECK_MENU_CLASS(menu);
- const auto &qpaMenu = static_cast<QCocoaNSMenu *>(menu).qpaMenu;
- if (qpaMenu.isNull())
+ auto *platformMenu = static_cast<QCocoaNSMenu *>(menu).platformMenu;
+ if (!platformMenu)
return;
- qpaMenu->setIsOpen(true);
- emit qpaMenu->aboutToShow();
+ platformMenu->setIsOpen(true);
+ emit platformMenu->aboutToShow();
}
- (void)menuDidClose:(NSMenu *)menu
{
CHECK_MENU_CLASS(menu);
- const auto &qpaMenu = static_cast<QCocoaNSMenu *>(menu).qpaMenu;
- if (qpaMenu.isNull())
+ auto *platformMenu = static_cast<QCocoaNSMenu *>(menu).platformMenu;
+ if (!platformMenu)
return;
- qpaMenu->setIsOpen(false);
+ platformMenu->setIsOpen(false);
// wrong, but it's the best we can do
- emit qpaMenu->aboutToHide();
+ emit platformMenu->aboutToHide();
}
- (BOOL)menuHasKeyEquivalent:(NSMenu *)menu forEvent:(NSEvent *)event target:(id *)target action:(SEL *)action
@@ -212,7 +225,8 @@ static NSString *qt_mac_removePrivateUnicode(NSString* string)
CHECK_MENU_CLASS(menu);
// Interested only in Shift, Cmd, Ctrl & Alt Keys, so ignoring masks like, Caps lock, Num Lock ...
- static const NSUInteger mask = NSShiftKeyMask | NSControlKeyMask | NSCommandKeyMask | NSAlternateKeyMask;
+ static const NSUInteger mask = NSEventModifierFlagShift | NSEventModifierFlagControl
+ | NSEventModifierFlagCommand | NSEventModifierFlagOption;
// Change the private unicode keys to the ones used in setting the "Key Equivalents"
NSString *characters = qt_mac_removePrivateUnicode(event.charactersIgnoringModifiers);
@@ -229,30 +243,17 @@ static NSString *qt_mac_removePrivateUnicode(NSString* string)
}
if (keyEquivalentItem) {
- if (!keyEquivalentItem.target) {
- // This item was modified by QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder
- // and it looks like we're running a modal session for NSOpenPanel/NSSavePanel.
- // QCocoaFileDialogHelper is actually the only place we use this and we run NSOpenPanel modal
- // (modal sheet, window modal, application modal).
- // Whatever the current first responder is, let's give it a chance
- // and do not touch the Qt's focusObject (which is different from some native view
- // having a focus inside NSSave/OpenPanel.
- *target = nil;
- *action = keyEquivalentItem.action;
- return YES;
- }
-
QObject *object = qApp->focusObject();
if (object) {
QChar ch;
int keyCode;
- ulong nativeModifiers = [event modifierFlags];
- Qt::KeyboardModifiers modifiers = [QNSView convertKeyModifiers: nativeModifiers];
- NSString *charactersIgnoringModifiers = [event charactersIgnoringModifiers];
- NSString *characters = [event characters];
+ ulong nativeModifiers = event.modifierFlags;
+ Qt::KeyboardModifiers modifiers = [QNSView convertKeyModifiers:nativeModifiers];
+ NSString *charactersIgnoringModifiers = event.charactersIgnoringModifiers;
+ NSString *characters = event.characters;
- if ([charactersIgnoringModifiers length] > 0) { // convert the first character into a key code
- if ((modifiers & Qt::ControlModifier) && ([characters length] != 0)) {
+ if (charactersIgnoringModifiers.length > 0) { // convert the first character into a key code
+ if ((modifiers & Qt::ControlModifier) && characters.length > 0) {
ch = QChar([characters characterAtIndex:0]);
} else {
ch = QChar([charactersIgnoringModifiers characterAtIndex:0]);
@@ -269,7 +270,7 @@ static NSString *qt_mac_removePrivateUnicode(NSString* string)
accel_ev.ignore();
QCoreApplication::sendEvent(object, &accel_ev);
if (accel_ev.isAccepted()) {
- [[NSApp keyWindow] sendEvent: event];
+ [[NSApp keyWindow] sendEvent:event];
*target = nil;
*action = nil;
return YES;
diff --git a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm
index 0c54a3b771..7605dc9d1a 100644
--- a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm
+++ b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm
@@ -69,17 +69,17 @@ static QPrint::DuplexMode macToDuplexMode(const PMDuplexMode &mode)
QCocoaPrintDevice::QCocoaPrintDevice()
: QPlatformPrintDevice(),
- m_printer(0),
- m_session(0),
- m_ppd(0)
+ m_printer(nullptr),
+ m_session(nullptr),
+ m_ppd(nullptr)
{
}
QCocoaPrintDevice::QCocoaPrintDevice(const QString &id)
: QPlatformPrintDevice(id),
- m_printer(0),
- m_session(0),
- m_ppd(0)
+ m_printer(nullptr),
+ m_session(nullptr),
+ m_ppd(nullptr)
{
if (!id.isEmpty()) {
m_printer = PMPrinterCreateFromPrinterID(id.toCFString());
@@ -413,7 +413,7 @@ QPrint::ColorMode QCocoaPrintDevice::defaultColorMode() const
ppd_option_t *colorModel = ppdFindOption(m_ppd, "DefaultColorModel");
if (!colorModel)
colorModel = ppdFindOption(m_ppd, "ColorModel");
- if (!colorModel || (colorModel && !qstrcmp(colorModel->defchoice, "Gray")))
+ if (!colorModel || qstrcmp(colorModel->defchoice, "Gray") != 0)
return QPrint::Color;
}
return QPrint::GrayScale;
@@ -447,11 +447,11 @@ bool QCocoaPrintDevice::openPpdFile()
{
if (m_ppd)
ppdClose(m_ppd);
- m_ppd = 0;
- CFURLRef ppdURL = NULL;
+ m_ppd = nullptr;
+ CFURLRef ppdURL = nullptr;
char ppdPath[MAXPATHLEN];
if (PMPrinterCopyDescriptionURL(m_printer, kPMPPDDescriptionType, &ppdURL) == noErr
- && ppdURL != NULL) {
+ && ppdURL) {
if (CFURLGetFileSystemRepresentation(ppdURL, true, (UInt8*)ppdPath, sizeof(ppdPath)))
m_ppd = ppdOpenFile(ppdPath);
CFRelease(ppdURL);
@@ -474,7 +474,7 @@ PMPaper QCocoaPrintDevice::macPaper(const QPageSize &pageSize) const
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 = 0;
+ PMPaper paper = nullptr;
PMPaperMargins paperMargins;
paperMargins.left = m_customMargins.left();
paperMargins.right = m_customMargins.right();
diff --git a/src/plugins/platforms/cocoa/qcocoascreen.h b/src/plugins/platforms/cocoa/qcocoascreen.h
index 3d59c3de79..9ded98df32 100644
--- a/src/plugins/platforms/cocoa/qcocoascreen.h
+++ b/src/plugins/platforms/cocoa/qcocoascreen.h
@@ -75,7 +75,11 @@ public:
// Additional methods
void setVirtualSiblings(const QList<QPlatformScreen *> &siblings) { m_siblings = siblings; }
NSScreen *nativeScreen() const;
- void updateGeometry();
+ void updateProperties();
+
+ void requestUpdate();
+ void deliverUpdateRequests();
+ bool isRunningDisplayLink() const;
static QCocoaScreen *primaryScreen();
@@ -96,6 +100,10 @@ public:
QSizeF m_physicalSize;
QCocoaCursor *m_cursor;
QList<QPlatformScreen *> m_siblings;
+
+ CVDisplayLinkRef m_displayLink = nullptr;
+ dispatch_source_t m_displayLinkSource = nullptr;
+ QAtomicInt m_pendingUpdates;
};
#ifndef QT_NO_DEBUG_STREAM
@@ -104,5 +112,9 @@ QDebug operator<<(QDebug debug, const QCocoaScreen *screen);
QT_END_NAMESPACE
+@interface NSScreen (QtExtras)
+@property(readonly) CGDirectDisplayID qt_displayId;
+@end
+
#endif
diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm
index 3e8261dfc2..f82ef202b1 100644
--- a/src/plugins/platforms/cocoa/qcocoascreen.mm
+++ b/src/plugins/platforms/cocoa/qcocoascreen.mm
@@ -47,6 +47,10 @@
#include <IOKit/graphics/IOGraphicsLib.h>
+#include <QtGui/private/qwindow_p.h>
+
+#include <QtCore/private/qeventdispatcher_cf_p.h>
+
QT_BEGIN_NAMESPACE
class QCoreTextFontEngine;
@@ -55,18 +59,22 @@ class QFontEngineFT;
QCocoaScreen::QCocoaScreen(int screenIndex)
: QPlatformScreen(), m_screenIndex(screenIndex), m_refreshRate(60.0)
{
- updateGeometry();
+ updateProperties();
m_cursor = new QCocoaCursor;
}
QCocoaScreen::~QCocoaScreen()
{
delete m_cursor;
+
+ CVDisplayLinkRelease(m_displayLink);
+ if (m_displayLinkSource)
+ dispatch_release(m_displayLinkSource);
}
NSScreen *QCocoaScreen::nativeScreen() const
{
- NSArray *screens = [NSScreen screens];
+ NSArray<NSScreen *> *screens = [NSScreen screens];
// Stale reference, screen configuration has changed
if (m_screenIndex < 0 || (NSUInteger)m_screenIndex >= [screens count])
@@ -107,12 +115,17 @@ static QString displayName(CGDirectDisplayID displayID)
return QString();
}
-void QCocoaScreen::updateGeometry()
+void QCocoaScreen::updateProperties()
{
NSScreen *nsScreen = nativeScreen();
if (!nsScreen)
return;
+ const QRect previousGeometry = m_geometry;
+ const QRect previousAvailableGeometry = m_availableGeometry;
+ const QDpi previousLogicalDpi = m_logicalDpi;
+ const qreal previousRefreshRate = m_refreshRate;
+
// The reference screen for the geometry is always the primary screen
QRectF primaryScreenGeometry = QRectF::fromCGRect([[NSScreen screens] firstObject].frame);
m_geometry = qt_mac_flip(QRectF::fromCGRect(nsScreen.frame), primaryScreenGeometry).toRect();
@@ -121,8 +134,7 @@ void QCocoaScreen::updateGeometry()
m_format = QImage::Format_RGB32;
m_depth = NSBitsPerPixelFromDepth([nsScreen depth]);
- NSDictionary *devDesc = [nsScreen deviceDescription];
- CGDirectDisplayID dpy = [[devDesc objectForKey:@"NSScreenNumber"] unsignedIntValue];
+ CGDirectDisplayID dpy = nsScreen.qt_displayId;
CGSize size = CGDisplayScreenSize(dpy);
m_physicalSize = QSizeF(size.width, size.height);
m_logicalDpi.first = 72;
@@ -135,25 +147,230 @@ void QCocoaScreen::updateGeometry()
m_name = displayName(dpy);
- QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), availableGeometry());
- QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(), m_logicalDpi.first, m_logicalDpi.second);
- QWindowSystemInterface::handleScreenRefreshRateChange(screen(), m_refreshRate);
-
- // When a screen changes its geometry, AppKit will send us a NSWindowDidMoveNotification
- // for each window, resulting in calls to handleGeometryChange(), but this happens before
- // the NSApplicationDidChangeScreenParametersNotification, so when we map the new geometry
- // (which is correct at that point) to the screen using QCocoaScreen::mapFromNative(), we
- // end up using the stale screen geometry, and the new window geometry we report is wrong.
- // To make sure we finally report the correct window geometry, we need to do another pass
- // of geometry reporting, now that the screen properties have been updates. FIXME: Ideally
- // this would be solved by not caching the screen properties in QCocoaScreen, but that
- // requires more research.
- for (QWindow *window : windows()) {
- if (QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow*>(window->handle()))
- cocoaWindow->handleGeometryChange();
+ const bool didChangeGeometry = m_geometry != previousGeometry || m_availableGeometry != previousAvailableGeometry;
+
+ 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);
+
+ qCDebug(lcQpaScreen) << "Updated properties for" << this;
+
+ if (didChangeGeometry) {
+ // When a screen changes its geometry, AppKit will send us a NSWindowDidMoveNotification
+ // for each window, resulting in calls to handleGeometryChange(), but this happens before
+ // the NSApplicationDidChangeScreenParametersNotification, so when we map the new geometry
+ // (which is correct at that point) to the screen using QCocoaScreen::mapFromNative(), we
+ // end up using the stale screen geometry, and the new window geometry we report is wrong.
+ // To make sure we finally report the correct window geometry, we need to do another pass
+ // of geometry reporting, now that the screen properties have been updates. FIXME: Ideally
+ // this would be solved by not caching the screen properties in QCocoaScreen, but that
+ // requires more research.
+ for (QWindow *window : windows()) {
+ if (QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow*>(window->handle()))
+ cocoaWindow->handleGeometryChange();
+ }
+ }
+}
+
+// ----------------------- Display link -----------------------
+
+Q_LOGGING_CATEGORY(lcQpaScreenUpdates, "qt.qpa.screen.updates", QtCriticalMsg);
+
+void QCocoaScreen::requestUpdate()
+{
+ if (!m_displayLink) {
+ CVDisplayLinkCreateWithCGDisplay(nativeScreen().qt_displayId, &m_displayLink);
+ 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
+ // frame. It will repeatedly spin this loop until no longer receiving any mouse drag events,
+ // and will then update the frame (effectively coalescing/compressing the events). Unfortunately
+ // the events are pulled out using -[NSApplication nextEventMatchingEventMask:untilDate:inMode:dequeue:]
+ // which internally uses CFRunLoopRunSpecific, so the event loop will also process GCD queues and other
+ // runloop sources that have been added to the tracking mode. This includes the GCD display-link
+ // source that we use to marshal the display-link callback over to the main thread. If the
+ // subsequent delivery of the update-request on the main thread stalls due to inefficient
+ // user code, the NSEventThread will have had time to deliver additional mouse drag events,
+ // and the logic in -[NSWindow _resizeWithEvent:] will keep on compressing events and never
+ // get to the point of actually updating the window frame, making it seem like the window
+ // is stuck in its original size. Only when the user stops moving their mouse, and the event
+ // queue is completely drained of drag events, will the window frame be updated.
+
+ // By keeping an event tap listening for drag events, registered as a version 1 runloop source,
+ // we prevent the GCD source from being prioritized, giving the resize logic enough time
+ // to finish coalescing the events. This is incidental, but conveniently gives us the behavior
+ // we are looking for, interleaving display-link updates and resize events.
+ static CFMachPortRef eventTap = []() {
+ CFMachPortRef eventTap = CGEventTapCreateForPid(getpid(), kCGTailAppendEventTap,
+ kCGEventTapOptionListenOnly, NSEventMaskLeftMouseDragged,
+ [](CGEventTapProxy, CGEventType type, CGEventRef event, void *) -> CGEventRef {
+ if (type == kCGEventTapDisabledByTimeout)
+ qCWarning(lcQpaScreenUpdates) << "Event tap disabled due to timeout!";
+ return event; // Listen only tap, so what we return doesn't really matter
+ }, nullptr);
+ CGEventTapEnable(eventTap, false); // Event taps are normally enabled when created
+ static CFRunLoopSourceRef runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
+
+ NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
+ [center addObserverForName:NSWindowWillStartLiveResizeNotification object:nil queue:nil
+ usingBlock:^(NSNotification *notification) {
+ qCDebug(lcQpaScreenUpdates) << "Live resize of" << notification.object
+ << "started. Enabling event tap";
+ CGEventTapEnable(eventTap, true);
+ }];
+ [center addObserverForName:NSWindowDidEndLiveResizeNotification object:nil queue:nil
+ usingBlock:^(NSNotification *notification) {
+ qCDebug(lcQpaScreenUpdates) << "Live resize of" << notification.object
+ << "ended. Disabling event tap";
+ CGEventTapEnable(eventTap, false);
+ }];
+ return eventTap;
+ }();
+ Q_UNUSED(eventTap);
+ }
+
+ if (!CVDisplayLinkIsRunning(m_displayLink)) {
+ qCDebug(lcQpaScreenUpdates) << "Starting display link for" << this;
+ CVDisplayLinkStart(m_displayLink);
+ }
+}
+
+// Helper to allow building up debug output in multiple steps
+struct DeferredDebugHelper
+{
+ DeferredDebugHelper(const QLoggingCategory &cat) {
+ if (cat.isDebugEnabled())
+ debug = new QDebug(QMessageLogger().debug(cat).nospace());
+ }
+ ~DeferredDebugHelper() {
+ flushOutput();
+ }
+ void flushOutput() {
+ if (debug) {
+ delete debug;
+ debug = nullptr;
+ }
+ }
+ QDebug *debug = nullptr;
+};
+
+#define qDeferredDebug(helper) if (Q_UNLIKELY(helper.debug)) *helper.debug
+
+void QCocoaScreen::deliverUpdateRequests()
+{
+ if (!QGuiApplication::instance())
+ return;
+
+ // The CVDisplayLink callback is a notification that it's a good time to produce a new frame.
+ // Since the callback is delivered on a separate thread we have to marshal it over to the
+ // main thread, as Qt requires update requests to be delivered there. This needs to happen
+ // asynchronously, as otherwise we may end up deadlocking if the main thread calls back
+ // into any of the CVDisplayLink APIs.
+ if (QThread::currentThread() != QGuiApplication::instance()->thread()) {
+ // We're explicitly not using the data of the GCD source to track the pending updates,
+ // as the data isn't reset to 0 until after the event handler, and also doesn't update
+ // during the event handler, both of which we need to track late frames.
+ const int pendingUpdates = ++m_pendingUpdates;
+
+ DeferredDebugHelper screenUpdates(lcQpaScreenUpdates());
+ qDeferredDebug(screenUpdates) << "display link callback for screen " << m_screenIndex;
+
+ if (const int framesAheadOfDelivery = pendingUpdates - 1) {
+ // If we have more than one update pending it means that a previous display link callback
+ // has not been fully processed on the main thread, either because GCD hasn't delivered
+ // it on the main thread yet, because the processing of the update request is taking
+ // too long, or because the update request was deferred due to window live resizing.
+ qDeferredDebug(screenUpdates) << ", " << framesAheadOfDelivery << " frame(s) ahead";
+
+ // We skip the frame completely if we're live-resizing, to not put any extra
+ // strain on the main thread runloop. Otherwise we assume we should push frames
+ // as fast as possible, and hopefully the callback will be delivered on the
+ // main thread just when the previous finished.
+ if (qt_apple_sharedApplication().keyWindow.inLiveResize) {
+ qDeferredDebug(screenUpdates) << "; waiting for main thread to catch up";
+ return;
+ }
+ }
+
+ qDeferredDebug(screenUpdates) << "; signaling dispatch source";
+
+ if (!m_displayLinkSource) {
+ m_displayLinkSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue());
+ dispatch_source_set_event_handler(m_displayLinkSource, ^{
+ deliverUpdateRequests();
+ });
+ dispatch_resume(m_displayLinkSource);
+ }
+
+ dispatch_source_merge_data(m_displayLinkSource, 1);
+
+ } else {
+ DeferredDebugHelper screenUpdates(lcQpaScreenUpdates());
+ qDeferredDebug(screenUpdates) << "gcd event handler on main thread";
+
+ const int pendingUpdates = m_pendingUpdates;
+ if (pendingUpdates > 1)
+ qDeferredDebug(screenUpdates) << ", " << (pendingUpdates - 1) << " frame(s) behind display link";
+
+ screenUpdates.flushOutput();
+
+ bool pauseUpdates = true;
+
+ auto windows = QGuiApplication::allWindows();
+ for (int i = 0; i < windows.size(); ++i) {
+ QWindow *window = windows.at(i);
+ QPlatformWindow *platformWindow = window->handle();
+ if (!platformWindow)
+ continue;
+
+ if (!platformWindow->hasPendingUpdateRequest())
+ continue;
+
+ if (window->screen() != screen())
+ continue;
+
+ // Skip windows that are not doing update requests via display link
+ if (!(window->format().swapInterval() > 0))
+ continue;
+
+ platformWindow->deliverUpdateRequest();
+
+ // Another update request was triggered, keep the display link running
+ if (platformWindow->hasPendingUpdateRequest())
+ pauseUpdates = false;
+ }
+
+ if (pauseUpdates) {
+ // Pause the display link if there are no pending update requests
+ qCDebug(lcQpaScreenUpdates) << "Stopping display link for" << this;
+ CVDisplayLinkStop(m_displayLink);
+ }
+
+ if (const int missedUpdates = m_pendingUpdates.fetchAndStoreRelaxed(0) - pendingUpdates) {
+ qCWarning(lcQpaScreenUpdates) << "main thread missed" << missedUpdates
+ << "update(s) from display link during update request delivery";
+ }
}
}
+bool QCocoaScreen::isRunningDisplayLink() const
+{
+ return m_displayLink && CVDisplayLinkIsRunning(m_displayLink);
+}
+
+// -----------------------------------------------------------
+
qreal QCocoaScreen::devicePixelRatio() const
{
QMacAutoReleasePool pool;
@@ -179,7 +396,7 @@ QWindow *QCocoaScreen::topLevelAt(const QPoint &point) const
// 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 = 0;
+ QWindow *window = nullptr;
do {
// Get the top-most window, below any previously rejected window.
topWindowNumber = [NSWindow windowNumberAtPoint:screenPoint
@@ -187,7 +404,7 @@ QWindow *QCocoaScreen::topLevelAt(const QPoint &point) const
// Continue the search if the window does not belong to this process.
NSWindow *nsWindow = [NSApp windowWithWindowNumber:topWindowNumber];
- if (nsWindow == 0)
+ if (!nsWindow)
continue;
// Continue the search if the window does not belong to Qt.
@@ -324,3 +541,12 @@ QDebug operator<<(QDebug debug, const QCocoaScreen *screen)
#endif // !QT_NO_DEBUG_STREAM
QT_END_NAMESPACE
+
+@implementation NSScreen (QtExtras)
+
+- (CGDirectDisplayID)qt_displayId
+{
+ return [self.deviceDescription[@"NSScreenNumber"] unsignedIntValue];
+}
+
+@end
diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm
index bad91a2d5d..672b0e4f25 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm
+++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm
@@ -45,6 +45,16 @@
#include <QtGui/qfont.h>
#include <QtGui/private/qcoregraphics_p.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);
+@end
+#endif
+
QT_BEGIN_NAMESPACE
QPalette * qt_mac_createSystemPalette()
@@ -65,18 +75,25 @@ QPalette * qt_mac_createSystemPalette()
palette->setBrush(QPalette::Disabled, QPalette::Text, dark);
palette->setBrush(QPalette::Disabled, QPalette::ButtonText, dark);
palette->setBrush(QPalette::Disabled, QPalette::Base, backgroundBrush);
+ palette->setBrush(QPalette::Active, QPalette::Base, backgroundBrush);
+ palette->setBrush(QPalette::Inactive, QPalette::Base, backgroundBrush);
palette->setColor(QPalette::Disabled, QPalette::Dark, QColor(191, 191, 191));
palette->setColor(QPalette::Active, QPalette::Dark, QColor(191, 191, 191));
palette->setColor(QPalette::Inactive, QPalette::Dark, QColor(191, 191, 191));
// System palette initialization:
- palette->setBrush(QPalette::Active, QPalette::Highlight,
- qt_mac_toQBrush([NSColor selectedControlColor]));
- QBrush br = qt_mac_toQBrush([NSColor secondarySelectedControlColor]);
- palette->setBrush(QPalette::Inactive, QPalette::Highlight, br);
- palette->setBrush(QPalette::Disabled, QPalette::Highlight, br);
+ 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);
+ }
- palette->setBrush(QPalette::Shadow, background.darker(170));
+ palette->setBrush(QPalette::Shadow, qt_mac_toQColor([NSColor shadowColor]));
qc = qt_mac_toQColor([NSColor controlTextColor]);
palette->setColor(QPalette::Active, QPalette::Text, qc);
@@ -98,10 +115,11 @@ QPalette * qt_mac_createSystemPalette()
struct QMacPaletteMap {
inline QMacPaletteMap(QPlatformTheme::Palette p, NSColor *a, NSColor *i) :
- paletteRole(p), active(a), inactive(i) { }
+ active(a), inactive(i), paletteRole(p) { }
+ NSColor *active;
+ NSColor *inactive;
QPlatformTheme::Palette paletteRole;
- NSColor *active, *inactive;
};
#define MAC_PALETTE_ENTRY(pal, active, inactive) \
@@ -131,7 +149,7 @@ QHash<QPlatformTheme::Palette, QPalette*> qt_mac_createRolePalettes()
QColor qc;
for (int i = 0; i < mac_widget_colors_count; i++) {
QPalette &pal = *qt_mac_createSystemPalette();
- if (mac_widget_colors[i].active != 0) {
+ if (mac_widget_colors[i].active) {
qc = qt_mac_toQColor(mac_widget_colors[i].active);
pal.setColor(QPalette::Active, QPalette::Text, qc);
pal.setColor(QPalette::Inactive, QPalette::Text, qc);
@@ -146,7 +164,18 @@ QHash<QPlatformTheme::Palette, QPalette*> qt_mac_createRolePalettes()
}
if (mac_widget_colors[i].paletteRole == QPlatformTheme::MenuPalette
|| mac_widget_colors[i].paletteRole == QPlatformTheme::MenuBarPalette) {
- pal.setBrush(QPalette::Highlight, qt_mac_toQColor([NSColor selectedMenuItemColor]));
+ 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];
+ }
+ pal.setBrush(QPalette::Highlight, qt_mac_toQColor(selectedMenuItemColor));
qc = qt_mac_toQColor([NSColor labelColor]);
pal.setBrush(QPalette::ButtonText, qc);
pal.setBrush(QPalette::Text, qc);
@@ -164,22 +193,41 @@ QHash<QPlatformTheme::Palette, QPalette*> qt_mac_createRolePalettes()
pal.setColor(QPalette::Active, QPalette::ButtonText,
pal.color(QPalette::Active, QPalette::Text));
} 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));
+ }
+ pal.setBrush(QPalette::Base, qt_mac_toQBrush(baseColors[0]));
+ pal.setBrush(QPalette::AlternateBase, qt_mac_toQBrush(baseColors[1]));
pal.setBrush(QPalette::Active, QPalette::Highlight,
- qt_mac_toQBrush([NSColor alternateSelectedControlColor]));
+ qt_mac_toQBrush(activeHighlightColor));
pal.setBrush(QPalette::Active, QPalette::HighlightedText,
qt_mac_toQBrush([NSColor alternateSelectedControlTextColor]));
pal.setBrush(QPalette::Inactive, QPalette::Text,
- pal.brush(QPalette::Active, QPalette::Text));
- pal.setBrush(QPalette::Inactive, QPalette::HighlightedText,
- pal.brush(QPalette::Active, QPalette::Text));
+ pal.brush(QPalette::Active, QPalette::Text));
} else if (mac_widget_colors[i].paletteRole == QPlatformTheme::TextEditPalette) {
+ pal.setBrush(QPalette::Active, QPalette::Base, qt_mac_toQColor([NSColor textBackgroundColor]));
pal.setBrush(QPalette::Inactive, QPalette::Text,
pal.brush(QPalette::Active, QPalette::Text));
pal.setBrush(QPalette::Inactive, QPalette::HighlightedText,
pal.brush(QPalette::Active, QPalette::Text));
- } else if (mac_widget_colors[i].paletteRole == QPlatformTheme::TextLineEditPalette) {
+ } else if (mac_widget_colors[i].paletteRole == QPlatformTheme::TextLineEditPalette
+ || mac_widget_colors[i].paletteRole == QPlatformTheme::ComboBoxPalette) {
+ pal.setBrush(QPalette::Active, QPalette::Base, qt_mac_toQColor([NSColor textBackgroundColor]));
pal.setBrush(QPalette::Disabled, QPalette::Base,
pal.brush(QPalette::Active, QPalette::Base));
+ } else if (mac_widget_colors[i].paletteRole == QPlatformTheme::LabelPalette) {
+ qc = qt_mac_toQColor([NSColor labelColor]);
+ pal.setBrush(QPalette::Inactive, QPalette::ToolTipText, qc);
}
palettes.insert(mac_widget_colors[i].paletteRole, &pal);
}
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
index 2f1a1e42a9..d831612c22 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
@@ -55,7 +55,7 @@ class QSystemTrayIconSys;
class Q_GUI_EXPORT QCocoaSystemTrayIcon : public QPlatformSystemTrayIcon
{
public:
- QCocoaSystemTrayIcon() : m_sys(0) {}
+ QCocoaSystemTrayIcon() : m_sys(nullptr) {}
void init() override;
void cleanup() override;
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
index 5e6913a89a..0158895441 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
@@ -95,31 +95,16 @@ QT_USE_NAMESPACE
@class QT_MANGLE_NAMESPACE(QNSImageView);
@interface QT_MANGLE_NAMESPACE(QNSStatusItem) : NSObject <NSUserNotificationCenterDelegate>
-{
-@public
- QCocoaSystemTrayIcon *systray;
- NSStatusItem *item;
- QCocoaMenu *menu;
- QIcon icon;
- QT_MANGLE_NAMESPACE(QNSImageView) *imageCell;
-}
--(id)initWithSysTray:(QCocoaSystemTrayIcon *)systray;
--(void)dealloc;
--(NSStatusItem*)item;
--(QRectF)geometry;
+@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;
-- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification;
-- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification;
@end
-@interface QT_MANGLE_NAMESPACE(QNSImageView) : NSImageView {
- BOOL down;
- QT_MANGLE_NAMESPACE(QNSStatusItem) *parent;
-}
--(id)initWithParent:(QT_MANGLE_NAMESPACE(QNSStatusItem)*)myParent;
--(void)menuTrackingDone:(NSNotification*)notification;
--(void)mousePressed:(NSEvent *)mouseEvent button:(Qt::MouseButton)mouseButton;
+@interface QT_MANGLE_NAMESPACE(QNSImageView) : NSImageView
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSStatusItem);
@@ -162,7 +147,7 @@ QRect QCocoaSystemTrayIcon::geometry() const
void QCocoaSystemTrayIcon::cleanup()
{
delete m_sys;
- m_sys = 0;
+ m_sys = nullptr;
}
static bool heightCompareFunction (QSize a, QSize b) { return (a.height() < b.height()); }
@@ -178,7 +163,7 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
if (!m_sys)
return;
- m_sys->item->icon = icon;
+ m_sys->item.icon = icon;
// The reccomended maximum title bar icon height is 18 points
// (device independent pixels). The menu height on past and
@@ -249,8 +234,8 @@ void QCocoaSystemTrayIcon::updateMenu(QPlatformMenu *menu)
if (!m_sys)
return;
- m_sys->item->menu = static_cast<QCocoaMenu *>(menu);
- if (menu && [m_sys->item->menu->nsMenu() numberOfItems] > 0) {
+ 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];
@@ -289,23 +274,29 @@ void QCocoaSystemTrayIcon::showMessage(const QString &title, const QString &mess
}
QT_END_NAMESPACE
-@implementation QNSImageView
--(id)initWithParent:(QNSStatusItem*)myParent {
+@implementation NSStatusItem (Qt)
+@end
+
+@implementation QNSImageView {
+ BOOL down;
+ QT_MANGLE_NAMESPACE(QNSStatusItem) *parent;
+}
+
+- (instancetype)initWithParent:(QNSStatusItem *)myParent {
self = [super init];
parent = myParent;
down = NO;
return self;
}
--(void)menuTrackingDone:(NSNotification*)notification
+- (void)menuTrackingDone:(NSNotification *)__unused notification
{
- Q_UNUSED(notification);
down = NO;
[self setNeedsDisplay:YES];
}
--(void)mousePressed:(NSEvent *)mouseEvent button:(Qt::MouseButton)mouseButton
+- (void)mousePressed:(NSEvent *)mouseEvent
{
down = YES;
int clickCount = [mouseEvent clickCount];
@@ -315,16 +306,16 @@ QT_END_NAMESPACE
[self menuTrackingDone:nil];
[parent doubleClickSelector:self];
} else {
- [parent triggerSelector:self button:mouseButton];
+ [parent triggerSelector:self button:cocoaButton2QtButton(mouseEvent)];
}
}
--(void)mouseDown:(NSEvent *)mouseEvent
+- (void)mouseDown:(NSEvent *)mouseEvent
{
- [self mousePressed:mouseEvent button:Qt::LeftButton];
+ [self mousePressed:mouseEvent];
}
--(void)mouseUp:(NSEvent *)mouseEvent
+- (void)mouseUp:(NSEvent *)mouseEvent
{
Q_UNUSED(mouseEvent);
[self menuTrackingDone:nil];
@@ -332,10 +323,10 @@ QT_END_NAMESPACE
- (void)rightMouseDown:(NSEvent *)mouseEvent
{
- [self mousePressed:mouseEvent button:Qt::RightButton];
+ [self mousePressed:mouseEvent];
}
--(void)rightMouseUp:(NSEvent *)mouseEvent
+- (void)rightMouseUp:(NSEvent *)mouseEvent
{
Q_UNUSED(mouseEvent);
[self menuTrackingDone:nil];
@@ -343,29 +334,36 @@ QT_END_NAMESPACE
- (void)otherMouseDown:(NSEvent *)mouseEvent
{
- [self mousePressed:mouseEvent button:cocoaButton2QtButton([mouseEvent buttonNumber])];
+ [self mousePressed:mouseEvent];
}
--(void)otherMouseUp:(NSEvent *)mouseEvent
+- (void)otherMouseUp:(NSEvent *)mouseEvent
{
Q_UNUSED(mouseEvent);
[self menuTrackingDone:nil];
}
--(void)drawRect:(NSRect)rect {
+- (void)drawRect:(NSRect)rect {
[[parent item] drawStatusBarBackgroundInRect:rect withHighlight:down];
[super drawRect:rect];
}
@end
-@implementation QNSStatusItem
+@implementation QNSStatusItem {
+ QCocoaSystemTrayIcon *systray;
+ NSStatusItem *item;
+ QT_MANGLE_NAMESPACE(QNSImageView) *imageCell;
+}
+
+@synthesize menu = menu;
+@synthesize icon = icon;
--(id)initWithSysTray:(QCocoaSystemTrayIcon *)sys
+- (instancetype)initWithSysTray:(QCocoaSystemTrayIcon *)sys
{
self = [super init];
if (self) {
item = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain];
- menu = 0;
+ menu = nullptr;
systray = sys;
imageCell = [[QNSImageView alloc] initWithParent:self];
[item setView: imageCell];
@@ -373,19 +371,19 @@ QT_END_NAMESPACE
return self;
}
--(void)dealloc {
+- (void)dealloc {
[[NSStatusBar systemStatusBar] removeStatusItem:item];
[[NSNotificationCenter defaultCenter] removeObserver:imageCell];
[imageCell release];
[item release];
[super dealloc];
-
}
--(NSStatusItem*)item {
+- (NSStatusItem *)item {
return item;
}
--(QRectF)geometry {
+
+- (QRectF)geometry {
if (NSWindow *window = [[item view] window]) {
if (QCocoaScreen *screen = QCocoaIntegration::instance()->screenForNSScreen([window screen]))
return screen->mapFromNative([window frame]);
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h
index 69eaf8db56..c42fa7d2e8 100644
--- a/src/plugins/platforms/cocoa/qcocoatheme.h
+++ b/src/plugins/platforms/cocoa/qcocoatheme.h
@@ -43,7 +43,7 @@
#include <QtCore/QHash>
#include <qpa/qplatformtheme.h>
-Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QCocoaThemeNotificationReceiver));
+Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QCocoaThemeAppAppearanceObserver));
QT_BEGIN_NAMESPACE
@@ -78,11 +78,13 @@ public:
static const char *name;
+ void handleSystemThemeChange();
+
private:
mutable QPalette *m_systemPalette;
mutable QHash<QPlatformTheme::Palette, QPalette*> m_palettes;
mutable QHash<QPlatformTheme::Font, QFont*> m_fonts;
- mutable QT_MANGLE_NAMESPACE(QCocoaThemeNotificationReceiver) *m_notificationReceiver;
+ QT_MANGLE_NAMESPACE(QCocoaThemeAppAppearanceObserver) *m_appearanceObserver;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm
index 93f0400916..a2229159b5 100644
--- a/src/plugins/platforms/cocoa/qcocoatheme.mm
+++ b/src/plugins/platforms/cocoa/qcocoatheme.mm
@@ -42,6 +42,7 @@
#include "qcocoatheme.h"
#include "messages.h"
+#include <QtCore/QOperatingSystemVersion>
#include <QtCore/QVariant>
#include "qcocoasystemsettings.h"
@@ -75,30 +76,50 @@
#endif
#endif
-#include <Carbon/Carbon.h>
+#include <CoreServices/CoreServices.h>
-@interface QT_MANGLE_NAMESPACE(QCocoaThemeNotificationReceiver) : NSObject {
-QCocoaTheme *mPrivate;
-}
-- (id)initWithPrivate:(QCocoaTheme *)priv;
-- (void)systemColorsDidChange:(NSNotification *)notification;
+#if !QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
+@interface NSApplication (MojaveForwardDeclarations)
+@property (readonly, strong) NSAppearance *effectiveAppearance NS_AVAILABLE_MAC(10_14);
@end
+#endif
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaThemeNotificationReceiver);
+@interface QT_MANGLE_NAMESPACE(QCocoaThemeAppAppearanceObserver) : NSObject
+@property (readonly, nonatomic) QCocoaTheme *theme;
+- (instancetype)initWithTheme:(QCocoaTheme *)theme;
+@end
-@implementation QCocoaThemeNotificationReceiver
-- (id)initWithPrivate:(QCocoaTheme *)priv
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaThemeAppAppearanceObserver);
+
+@implementation QCocoaThemeAppAppearanceObserver
+- (instancetype)initWithTheme:(QCocoaTheme *)theme
{
- self = [super init];
- mPrivate = priv;
+ if ((self = [super init])) {
+ _theme = theme;
+ [NSApp addObserver:self forKeyPath:@"effectiveAppearance" options:NSKeyValueObservingOptionNew context:nullptr];
+ }
return self;
}
-- (void)systemColorsDidChange:(NSNotification *)notification
+- (void)dealloc
{
- Q_UNUSED(notification);
- mPrivate->reset();
- QWindowSystemInterface::handleThemeChange(nullptr);
+ [NSApp removeObserver:self forKeyPath:@"effectiveAppearance"];
+ [super dealloc];
+}
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
+ change:(NSDictionary<NSKeyValueChangeKey, id> *)change context:(void *)context
+{
+ Q_UNUSED(change);
+ Q_UNUSED(context);
+
+ Q_ASSERT(object == NSApp);
+ Q_ASSERT([keyPath isEqualToString:@"effectiveAppearance"]);
+
+ if (__builtin_available(macOS 10.14, *))
+ NSAppearance.currentAppearance = NSApp.effectiveAppearance;
+
+ self.theme->handleSystemThemeChange();
}
@end
@@ -107,19 +128,22 @@ QT_BEGIN_NAMESPACE
const char *QCocoaTheme::name = "cocoa";
QCocoaTheme::QCocoaTheme()
- :m_systemPalette(0)
+ : m_systemPalette(nullptr), m_appearanceObserver(nil)
{
- m_notificationReceiver = [[QT_MANGLE_NAMESPACE(QCocoaThemeNotificationReceiver) alloc] initWithPrivate:this];
- [[NSNotificationCenter defaultCenter] addObserver:m_notificationReceiver
- selector:@selector(systemColorsDidChange:)
- name:NSSystemColorsDidChangeNotification
- object:nil];
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave)
+ m_appearanceObserver = [[QCocoaThemeAppAppearanceObserver alloc] initWithTheme:this];
+
+ [[NSNotificationCenter defaultCenter] addObserverForName:NSSystemColorsDidChangeNotification
+ object:nil queue:nil usingBlock:^(NSNotification *) {
+ handleSystemThemeChange();
+ }];
}
QCocoaTheme::~QCocoaTheme()
{
- [[NSNotificationCenter defaultCenter] removeObserver:m_notificationReceiver];
- [m_notificationReceiver release];
+ if (m_appearanceObserver)
+ [m_appearanceObserver release];
+
reset();
qDeleteAll(m_fonts);
}
@@ -132,6 +156,15 @@ void QCocoaTheme::reset()
m_palettes.clear();
}
+void QCocoaTheme::handleSystemThemeChange()
+{
+ reset();
+ m_systemPalette = qt_mac_createSystemPalette();
+ m_palettes = qt_mac_createRolePalettes();
+
+ QWindowSystemInterface::handleThemeChange(nullptr);
+}
+
bool QCocoaTheme::usePlatformNativeDialog(DialogType dialogType) const
{
if (dialogType == QPlatformTheme::FileDialog)
@@ -147,7 +180,7 @@ bool QCocoaTheme::usePlatformNativeDialog(DialogType dialogType) const
return false;
}
-QPlatformDialogHelper * QCocoaTheme::createPlatformDialogHelper(DialogType dialogType) const
+QPlatformDialogHelper *QCocoaTheme::createPlatformDialogHelper(DialogType dialogType) const
{
switch (dialogType) {
#if defined(QT_WIDGETS_LIB) && QT_CONFIG(filedialog)
@@ -163,7 +196,7 @@ QPlatformDialogHelper * QCocoaTheme::createPlatformDialogHelper(DialogType dialo
return new QCocoaFontDialogHelper();
#endif
default:
- return 0;
+ return nullptr;
}
}
@@ -183,9 +216,9 @@ const QPalette *QCocoaTheme::palette(Palette type) const
} else {
if (m_palettes.isEmpty())
m_palettes = qt_mac_createRolePalettes();
- return m_palettes.value(type, 0);
+ return m_palettes.value(type, nullptr);
}
- return 0;
+ return nullptr;
}
QHash<QPlatformTheme::Font, QFont *> qt_mac_createRoleFonts()
@@ -199,7 +232,7 @@ const QFont *QCocoaTheme::font(Font type) const
if (m_fonts.isEmpty()) {
m_fonts = qt_mac_createRoleFonts();
}
- return m_fonts.value(type, 0);
+ return m_fonts.value(type, nullptr);
}
//! \internal
diff --git a/src/plugins/platforms/cocoa/qcocoavulkaninstance.h b/src/plugins/platforms/cocoa/qcocoavulkaninstance.h
new file mode 100644
index 0000000000..5fe6a612af
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qcocoavulkaninstance.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QCOCOAVULKANINSTANCE_H
+#define QCOCOAVULKANINSTANCE_H
+
+// Include mvk_vulkan.h first. The order is important since
+// mvk_vulkan.h just defines VK_USE_PLATFORM_MACOS_MVK (or the IOS
+// variant) and includes vulkan.h. If something else included vulkan.h
+// before this then we wouldn't get the MVK specifics...
+#include <MoltenVK/mvk_vulkan.h>
+
+#include <QtCore/QHash>
+#include <QtVulkanSupport/private/qbasicvulkanplatforminstance_p.h>
+
+#include <AppKit/AppKit.h>
+
+QT_BEGIN_NAMESPACE
+
+class QCocoaVulkanInstance : public QBasicPlatformVulkanInstance
+{
+public:
+ QCocoaVulkanInstance(QVulkanInstance *instance);
+ ~QCocoaVulkanInstance();
+
+ void createOrAdoptInstance() override;
+
+ VkSurfaceKHR *createSurface(QWindow *window);
+ VkSurfaceKHR createSurface(NSView *view);
+private:
+ QVulkanInstance *m_instance = nullptr;
+ QLibrary m_lib;
+ VkSurfaceKHR m_nullSurface = nullptr;
+ PFN_vkCreateMacOSSurfaceMVK m_createSurface = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QXCBVULKANINSTANCE_H
diff --git a/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm b/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm
new file mode 100644
index 0000000000..b00fde6c6f
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "qcocoavulkaninstance.h"
+#include "qcocoawindow.h"
+
+QT_BEGIN_NAMESPACE
+
+QCocoaVulkanInstance::QCocoaVulkanInstance(QVulkanInstance *instance)
+ : m_instance(instance)
+{
+ loadVulkanLibrary(QStringLiteral("vulkan"));
+}
+
+QCocoaVulkanInstance::~QCocoaVulkanInstance()
+{
+}
+
+void QCocoaVulkanInstance::createOrAdoptInstance()
+{
+ initInstance(m_instance, QByteArrayList());
+}
+
+VkSurfaceKHR *QCocoaVulkanInstance::createSurface(QWindow *window)
+{
+ QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle());
+ if (cocoaWindow->m_vulkanSurface)
+ destroySurface(cocoaWindow->m_vulkanSurface);
+ cocoaWindow->m_vulkanSurface = createSurface(cocoaWindow->m_view);
+ return &cocoaWindow->m_vulkanSurface;
+}
+
+VkSurfaceKHR QCocoaVulkanInstance::createSurface(NSView *view)
+{
+ if (!m_createSurface) {
+ m_createSurface = reinterpret_cast<PFN_vkCreateMacOSSurfaceMVK>(
+ m_vkGetInstanceProcAddr(m_vkInst, "vkCreateMacOSSurfaceMVK"));
+ }
+ if (!m_createSurface) {
+ qWarning("Failed to find vkCreateMacOSSurfaceMVK");
+ return m_nullSurface;
+ }
+
+ VkMacOSSurfaceCreateInfoMVK surfaceInfo;
+ surfaceInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
+ surfaceInfo.pNext = nullptr;
+ surfaceInfo.flags = 0;
+ surfaceInfo.pView = view;
+
+ VkSurfaceKHR surface = nullptr;
+ VkResult err = m_createSurface(m_vkInst, &surfaceInfo, nullptr, &surface);
+ if (err != VK_SUCCESS)
+ qWarning("Failed to create Vulkan surface: %d", err);
+
+ return surface;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h
index fb91c53a7a..8f1bdb8af0 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.h
+++ b/src/plugins/platforms/cocoa/qcocoawindow.h
@@ -53,6 +53,10 @@
#include "qnswindow.h"
#include "qt_mac_p.h"
+#if QT_CONFIG(vulkan)
+#include <MoltenVK/mvk_vulkan.h>
+#endif
+
QT_BEGIN_NAMESPACE
#ifndef QT_NO_DEBUG_STREAM
@@ -112,6 +116,7 @@ public:
void raise() override;
void lower() override;
bool isExposed() const override;
+ bool isEmbedded() const override;
bool isOpaque() const;
void propagateSizeHints() override;
void setOpacity(qreal level) override;
@@ -124,6 +129,8 @@ public:
bool isForeignWindow() const override;
void requestUpdate() override;
+ void deliverUpdateRequest() override;
+
void requestActivateWindow() override;
WId winId() const override;
@@ -132,7 +139,7 @@ public:
NSView *view() const;
NSWindow *nativeWindow() const;
- void setEmbeddedInForeignView(bool subwindow);
+ void setEmbeddedInForeignView();
Q_NOTIFICATION_HANDLER(NSViewFrameDidChangeNotification) void viewDidChangeFrame();
Q_NOTIFICATION_HANDLER(NSViewGlobalFrameDidChangeNotification) void viewDidChangeGlobalFrame();
@@ -162,11 +169,6 @@ public:
NSUInteger windowStyleMask(Qt::WindowFlags flags);
void setWindowZoomButton(Qt::WindowFlags flags);
-#ifndef QT_NO_OPENGL
- void setCurrentContext(QCocoaGLContext *context);
- QCocoaGLContext *currentContext() const;
-#endif
-
bool setWindowModified(bool modified) override;
void setFrameStrutEventsEnabled(bool enabled) override;
@@ -237,11 +239,6 @@ public: // for QNSView
NSView *m_view;
QCocoaNSWindow *m_nsWindow;
- // TODO merge to one variable if possible
- bool m_viewIsEmbedded; // true if the m_view is actually embedded in a "foreign" NSView hiearchy
- bool m_viewIsToBeEmbedded; // true if the m_view is intended to be embedded in a "foreign" NSView hiearchy
-
- Qt::WindowFlags m_windowFlags;
Qt::WindowStates m_lastReportedWindowState;
Qt::WindowModality m_windowModality;
QPointer<QWindow> m_enterLeaveTargetWindow;
@@ -251,9 +248,6 @@ public: // for QNSView
bool m_inSetVisible;
bool m_inSetGeometry;
bool m_inSetStyleMask;
-#ifndef QT_NO_OPENGL
- QCocoaGLContext *m_glContext;
-#endif
QCocoaMenuBar *m_menubar;
bool m_needsInvalidateShadow;
@@ -283,6 +277,10 @@ public: // for QNSView
};
QHash<quintptr, BorderRange> m_contentBorderAreas; // identifer -> uppper/lower
QHash<quintptr, bool> m_enabledContentBorderAreas; // identifer -> enabled state (true/false)
+
+#if QT_CONFIG(vulkan)
+ VkSurfaceKHR m_vulkanSurface = nullptr;
+#endif
};
#ifndef QT_NO_DEBUG_STREAM
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 00c3f7c22c..98e48a8b70 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -117,24 +117,19 @@ static void qRegisterNotificationCallbacks()
return;
}
- if (lcCocoaNotifications().isDebugEnabled()) {
- if (cocoaWindows.isEmpty()) {
- qCDebug(lcCocoaNotifications) << "Could not find forwarding target for" <<
- qPrintable(notificationName) << "from" << notification.object;
- } else {
- QVector<QCocoaWindow *> debugWindows;
- for (QCocoaWindow *cocoaWindow : cocoaWindows)
- debugWindows += cocoaWindow;
- qCDebug(lcCocoaNotifications) << "Forwarding" << qPrintable(notificationName) <<
- "to" << debugWindows;
- }
+ if (lcCocoaNotifications().isDebugEnabled() && !cocoaWindows.isEmpty()) {
+ QVector<QCocoaWindow *> debugWindows;
+ for (QCocoaWindow *cocoaWindow : cocoaWindows)
+ debugWindows += cocoaWindow;
+ qCDebug(lcCocoaNotifications) << "Forwarding" << qPrintable(notificationName) <<
+ "to" << debugWindows;
}
// FIXME: Could be a foreign window, look up by iterating top level QWindows
for (QCocoaWindow *cocoaWindow : cocoaWindows) {
if (!method.invoke(cocoaWindow, Qt::DirectConnection)) {
- qCWarning(lcQpaCocoaWindow) << "Failed to invoke NSNotification callback for"
+ qCWarning(lcQpaWindow) << "Failed to invoke NSNotification callback for"
<< notification.name << "on" << cocoaWindow;
}
}
@@ -148,9 +143,7 @@ const int QCocoaWindow::NoAlertRequest = -1;
QCocoaWindow::QCocoaWindow(QWindow *win, WId nativeHandle)
: QPlatformWindow(win)
, m_view(nil)
- , m_nsWindow(0)
- , m_viewIsEmbedded(false)
- , m_viewIsToBeEmbedded(false)
+ , m_nsWindow(nil)
, m_lastReportedWindowState(Qt::WindowNoState)
, m_windowModality(Qt::NonModal)
, m_windowUnderMouse(false)
@@ -158,10 +151,7 @@ QCocoaWindow::QCocoaWindow(QWindow *win, WId nativeHandle)
, m_inSetVisible(false)
, m_inSetGeometry(false)
, m_inSetStyleMask(false)
-#ifndef QT_NO_OPENGL
- , m_glContext(0)
-#endif
- , m_menubar(0)
+ , m_menubar(nullptr)
, m_needsInvalidateShadow(false)
, m_hasModalSession(false)
, m_frameStrutEventsEnabled(false)
@@ -173,7 +163,7 @@ QCocoaWindow::QCocoaWindow(QWindow *win, WId nativeHandle)
, m_topContentBorderThickness(0)
, m_bottomContentBorderThickness(0)
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::QCocoaWindow" << window();
+ qCDebug(lcQpaWindow) << "QCocoaWindow::QCocoaWindow" << window();
if (nativeHandle) {
m_view = reinterpret_cast<NSView *>(nativeHandle);
@@ -183,41 +173,24 @@ QCocoaWindow::QCocoaWindow(QWindow *win, WId nativeHandle)
void QCocoaWindow::initialize()
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::initialize" << window();
+ qCDebug(lcQpaWindow) << "QCocoaWindow::initialize" << window();
QMacAutoReleasePool pool;
- if (!m_view) {
+ if (!m_view)
m_view = [[QNSView alloc] initWithCocoaWindow:this];
- // Enable high-dpi OpenGL for retina displays. Enabling has the side
- // effect that Cocoa will start calling glViewport(0, 0, width, height),
- // overriding any glViewport calls in application code. This is usually not a
- // problem, except if the appilcation wants to have a "custom" viewport.
- // (like the hellogl example)
- if (window()->supportsOpenGL()) {
- BOOL enable = qt_mac_resolveOption(YES, window(), "_q_mac_wantsBestResolutionOpenGLSurface",
- "QT_MAC_WANTS_BEST_RESOLUTION_OPENGL_SURFACE");
- [m_view setWantsBestResolutionOpenGLSurface:enable];
- // See also QCocoaGLContext::makeCurrent for software renderer workarounds.
- }
- BOOL enable = qt_mac_resolveOption(NO, window(), "_q_mac_wantsLayer",
- "QT_MAC_WANTS_LAYER");
- [m_view setWantsLayer:enable];
- }
setGeometry(initialGeometry(window(), windowGeometry(), defaultWindowWidth, defaultWindowHeight));
recreateWindowIfNeeded();
window()->setGeometry(geometry());
- if (window()->isTopLevel())
- setWindowIcon(window()->icon());
m_initialized = true;
}
QCocoaWindow::~QCocoaWindow()
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::~QCocoaWindow" << window();
+ qCDebug(lcQpaWindow) << "QCocoaWindow::~QCocoaWindow" << window();
QMacAutoReleasePool pool;
[m_nsWindow makeFirstResponder:nil];
@@ -232,10 +205,16 @@ QCocoaWindow::~QCocoaWindow()
if (!isForeignWindow())
[[NSNotificationCenter defaultCenter] removeObserver:m_view];
- // While it is unlikely that this window will be in the popup stack
- // during deletetion we clear any pointers here to make sure.
- if (QCocoaIntegration::instance()) {
- QCocoaIntegration::instance()->popupWindowStack()->removeAll(this);
+ 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)
+ auto vulcanInstance = cocoaIntegration->getCocoaVulkanInstance();
+ if (vulcanInstance)
+ vulcanInstance->destroySurface(m_vulkanSurface);
+#endif
}
[m_view release];
@@ -255,7 +234,7 @@ QSurfaceFormat QCocoaWindow::format() const
void QCocoaWindow::setGeometry(const QRect &rectIn)
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setGeometry" << window() << rectIn;
+ qCDebug(lcQpaWindow) << "QCocoaWindow::setGeometry" << window() << rectIn;
QBoolBlocker inSetGeometry(m_inSetGeometry, true);
@@ -283,7 +262,7 @@ QRect QCocoaWindow::geometry() const
// QWindows that are embedded in a NSView hiearchy 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 (m_viewIsEmbedded) {
+ if (isEmbedded()) {
NSPoint windowPoint = [m_view convertPoint:NSMakePoint(0, 0) toView:nil];
NSRect screenRect = [[m_view window] convertRectToScreen:NSMakeRect(windowPoint.x, windowPoint.y, 1, 1)];
NSPoint screenPoint = screenRect.origin;
@@ -297,12 +276,12 @@ QRect QCocoaWindow::geometry() const
void QCocoaWindow::setCocoaGeometry(const QRect &rect)
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setCocoaGeometry" << window() << rect;
+ qCDebug(lcQpaWindow) << "QCocoaWindow::setCocoaGeometry" << window() << rect;
QMacAutoReleasePool pool;
QPlatformWindow::setGeometry(rect);
- if (m_viewIsEmbedded) {
+ if (isEmbedded()) {
if (!isForeignWindow()) {
[m_view setFrame:NSMakeRect(0, 0, rect.width(), rect.height())];
}
@@ -321,12 +300,12 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect)
void QCocoaWindow::setVisible(bool visible)
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setVisible" << window() << visible;
+ qCDebug(lcQpaWindow) << "QCocoaWindow::setVisible" << window() << visible;
m_inSetVisible = true;
QMacAutoReleasePool pool;
- QCocoaWindow *parentCocoaWindow = 0;
+ QCocoaWindow *parentCocoaWindow = nullptr;
if (window()->transientParent())
parentCocoaWindow = static_cast<QCocoaWindow *>(window()->transientParent()->handle());
@@ -355,9 +334,9 @@ void QCocoaWindow::setVisible(bool visible)
// Since this isn't a native popup, the window manager doesn't close the popup when you click outside
NSWindow *nativeParentWindow = parentCocoaWindow->nativeWindow();
NSUInteger parentStyleMask = nativeParentWindow.styleMask;
- if ((m_resizableTransientParent = (parentStyleMask & NSResizableWindowMask))
- && !(nativeParentWindow.styleMask & NSFullScreenWindowMask))
- nativeParentWindow.styleMask &= ~NSResizableWindowMask;
+ if ((m_resizableTransientParent = (parentStyleMask & NSWindowStyleMaskResizable))
+ && !(nativeParentWindow.styleMask & NSWindowStyleMaskFullScreen))
+ nativeParentWindow.styleMask &= ~NSWindowStyleMaskResizable;
}
}
@@ -378,13 +357,13 @@ void QCocoaWindow::setVisible(bool visible)
} else if (window()->modality() != Qt::NonModal) {
// show the window as application modal
QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher());
- Q_ASSERT(cocoaEventDispatcher != 0);
+ Q_ASSERT(cocoaEventDispatcher);
QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(cocoaEventDispatcher));
cocoaEventDispatcherPrivate->beginModalSession(window());
m_hasModalSession = true;
} else if ([m_view.window canBecomeKeyWindow]) {
QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher());
- QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = 0;
+ QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = nullptr;
if (cocoaEventDispatcher)
cocoaEventDispatcherPrivate = static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(cocoaEventDispatcher));
@@ -402,12 +381,15 @@ void QCocoaWindow::setVisible(bool visible)
((NSPanel *)m_view.window).worksWhenModal = YES;
if (!(parentCocoaWindow && window()->transientParent()->isActive()) && window()->type() == Qt::Popup) {
removeMonitor();
- monitor = [NSEvent addGlobalMonitorForEventsMatchingMask:NSLeftMouseDownMask|NSRightMouseDownMask|NSOtherMouseDownMask|NSMouseMovedMask handler:^(NSEvent *e) {
- QPointF localPoint = QCocoaScreen::mapFromNative([NSEvent mouseLocation]);
- const auto button = e.type == NSEventTypeMouseMoved ? Qt::NoButton : cocoaButton2QtButton([e buttonNumber]);
- const auto eventType = e.type == NSEventTypeMouseMoved ? QEvent::MouseMove : QEvent::MouseButtonPress;
- QWindowSystemInterface::handleMouseEvent(window(), window()->mapFromGlobal(localPoint.toPoint()), localPoint,
- Qt::MouseButtons(uint(NSEvent.pressedMouseButtons & 0xFFFF)), button, eventType);
+ 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);
}];
}
}
@@ -420,12 +402,8 @@ void QCocoaWindow::setVisible(bool visible)
[m_view setHidden:NO];
} else {
// qDebug() << "close" << this;
-#ifndef QT_NO_OPENGL
- if (m_glContext)
- m_glContext->windowWasHidden();
-#endif
QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher());
- QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = 0;
+ QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = nullptr;
if (cocoaEventDispatcher)
cocoaEventDispatcherPrivate = static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(cocoaEventDispatcher));
if (isContentView()) {
@@ -463,9 +441,9 @@ void QCocoaWindow::setVisible(bool visible)
if (parentCocoaWindow && window()->type() == Qt::Popup) {
NSWindow *nativeParentWindow = parentCocoaWindow->nativeWindow();
if (m_resizableTransientParent
- && !(nativeParentWindow.styleMask & NSFullScreenWindowMask))
+ && !(nativeParentWindow.styleMask & NSWindowStyleMaskFullScreen))
// A window should not be resizable while a transient popup is open
- nativeParentWindow.styleMask |= NSResizableWindowMask;
+ nativeParentWindow.styleMask |= NSWindowStyleMaskResizable;
}
}
@@ -493,7 +471,8 @@ NSInteger QCocoaWindow::windowLevel(Qt::WindowFlags flags)
// Any "special" window should be in at least the same level as its parent.
if (type != Qt::Window) {
const QWindow * const transientParent = window()->transientParent();
- const QCocoaWindow * const transientParentWindow = transientParent ? static_cast<QCocoaWindow *>(transientParent->handle()) : 0;
+ const QCocoaWindow * const transientParentWindow = transientParent ?
+ static_cast<QCocoaWindow *>(transientParent->handle()) : nullptr;
if (transientParentWindow)
windowLevel = qMax([transientParentWindow->nativeWindow() level], windowLevel);
}
@@ -507,39 +486,39 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags)
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 resizeable.
- const bool resizeable = !(flags & Qt::CustomizeWindowHint) || (type == Qt::Tool);
+ // 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 || !resizeable) ? NSBorderlessWindowMask : NSResizableWindowMask;
+ 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 |= NSTitledWindowMask;
+ styleMask |= NSWindowStyleMaskTitled;
if (flags & Qt::WindowCloseButtonHint)
- styleMask |= NSClosableWindowMask;
+ styleMask |= NSWindowStyleMaskClosable;
if (flags & Qt::WindowMinimizeButtonHint)
- styleMask |= NSMiniaturizableWindowMask;
+ styleMask |= NSWindowStyleMaskMiniaturizable;
if (flags & Qt::WindowMaximizeButtonHint)
- styleMask |= NSResizableWindowMask;
+ styleMask |= NSWindowStyleMaskResizable;
} else {
- styleMask |= NSClosableWindowMask | NSTitledWindowMask;
+ styleMask |= NSWindowStyleMaskClosable | NSWindowStyleMaskTitled;
if (type != Qt::Dialog)
- styleMask |= NSMiniaturizableWindowMask;
+ styleMask |= NSWindowStyleMaskMiniaturizable;
}
if (type == Qt::Tool)
- styleMask |= NSUtilityWindowMask;
+ styleMask |= NSWindowStyleMaskUtilityWindow;
if (m_drawContentBorderGradient)
- styleMask |= NSTexturedBackgroundWindowMask;
+ styleMask |= NSWindowStyleMaskTexturedBackground;
// Don't wipe fullscreen state
- if (m_view.window.styleMask & NSFullScreenWindowMask)
- styleMask |= NSFullScreenWindowMask;
+ if (m_view.window.styleMask & NSWindowStyleMaskFullScreen)
+ styleMask |= NSWindowStyleMaskFullScreen;
return styleMask;
}
@@ -562,54 +541,283 @@ void QCocoaWindow::setWindowZoomButton(Qt::WindowFlags flags)
void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags)
{
- if (isContentView()) {
- // While setting style mask we can have handleGeometryChange calls on a content
- // view with null geometry, reporting an invalid coordinates as a result.
- m_inSetStyleMask = true;
- m_view.window.styleMask = windowStyleMask(flags);
- m_inSetStyleMask = false;
- m_view.window.level = this->windowLevel(flags);
-
- m_view.window.hasShadow = !(flags & Qt::NoDropShadowWindowHint);
-
- if (!(flags & Qt::FramelessWindowHint))
- setWindowTitle(window()->title());
-
- Qt::WindowType type = window()->type();
- if ((type & Qt::Popup) != Qt::Popup && (type & Qt::Dialog) != Qt::Dialog) {
- NSWindowCollectionBehavior behavior = m_view.window.collectionBehavior;
- if ((flags & Qt::WindowFullscreenButtonHint) || m_view.window.qt_fullScreen) {
- behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
- behavior &= ~NSWindowCollectionBehaviorFullScreenAuxiliary;
- } else {
- behavior |= NSWindowCollectionBehaviorFullScreenAuxiliary;
- behavior &= ~NSWindowCollectionBehaviorFullScreenPrimary;
- }
- m_view.window.collectionBehavior = behavior;
+ if (!isContentView())
+ return;
+
+ // While setting style mask we can have handleGeometryChange calls on a content
+ // view with null geometry, reporting an invalid coordinates as a result.
+ m_inSetStyleMask = true;
+ m_view.window.styleMask = windowStyleMask(flags);
+ m_inSetStyleMask = false;
+
+ Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
+ if ((type & Qt::Popup) != Qt::Popup && (type & Qt::Dialog) != Qt::Dialog) {
+ NSWindowCollectionBehavior behavior = m_view.window.collectionBehavior;
+ if ((flags & Qt::WindowFullscreenButtonHint) || m_view.window.qt_fullScreen) {
+ behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
+ behavior &= ~NSWindowCollectionBehaviorFullScreenAuxiliary;
+ } else {
+ behavior |= NSWindowCollectionBehaviorFullScreenAuxiliary;
+ behavior &= ~NSWindowCollectionBehaviorFullScreenPrimary;
}
- setWindowZoomButton(flags);
-
- // Make window ignore mouse events if WindowTransparentForInput is set.
- // Note that ignoresMouseEvents has a special initial state where events
- // are ignored (passed through) based on window transparency, and that
- // setting the property to false does not return us to that state. Instead,
- // this makes the window capture all mouse events. Take care to only
- // set the property if needed. FIXME: recreate window if needed or find
- // some other way to implement WindowTransparentForInput.
- bool ignoreMouse = flags & Qt::WindowTransparentForInput;
- if (m_view.window.ignoresMouseEvents != ignoreMouse)
- m_view.window.ignoresMouseEvents = ignoreMouse;
+ m_view.window.collectionBehavior = behavior;
}
- m_windowFlags = flags;
+ // Set styleMask and collectionBehavior before applying window level, as
+ // the window level change will trigger verification of the two properties.
+ m_view.window.level = this->windowLevel(flags);
+
+ m_view.window.hasShadow = !(flags & Qt::NoDropShadowWindowHint);
+
+ if (!(flags & Qt::FramelessWindowHint))
+ setWindowTitle(window()->title());
+
+ setWindowZoomButton(flags);
+
+ // Make window ignore mouse events if WindowTransparentForInput is set.
+ // Note that ignoresMouseEvents has a special initial state where events
+ // are ignored (passed through) based on window transparency, and that
+ // setting the property to false does not return us to that state. Instead,
+ // this makes the window capture all mouse events. Take care to only
+ // set the property if needed. FIXME: recreate window if needed or find
+ // some other way to implement WindowTransparentForInput.
+ bool ignoreMouse = flags & Qt::WindowTransparentForInput;
+ if (m_view.window.ignoresMouseEvents != ignoreMouse)
+ m_view.window.ignoresMouseEvents = ignoreMouse;
}
+// ----------------------- Window state -----------------------
+
+/*!
+ Changes the state of the NSWindow, going in/out of minimize/zoomed/fullscreen
+
+ When this is called from QWindow::setWindowState(), the QWindow state has not been
+ updated yet, so window()->windowState() will reflect the previous state that was
+ reported to QtGui.
+*/
void QCocoaWindow::setWindowState(Qt::WindowStates state)
{
if (window()->isVisible())
applyWindowState(state); // Window state set for hidden windows take effect when show() is called
}
+void QCocoaWindow::applyWindowState(Qt::WindowStates requestedState)
+{
+ if (!isContentView())
+ return;
+
+ const Qt::WindowState currentState = windowState();
+ const Qt::WindowState newState = QWindowPrivate::effectiveState(requestedState);
+
+ if (newState == currentState)
+ return;
+
+ qCDebug(lcQpaWindow) << "Applying" << newState << "to" << window() << "in" << currentState;
+
+ const NSSize contentSize = m_view.frame.size;
+ if (contentSize.width <= 0 || contentSize.height <= 0) {
+ // If content view width or height is 0 then the window animations will crash so
+ // do nothing. We report the current state back to reflect the failed operation.
+ qWarning("invalid window content view size, check your window geometry");
+ handleWindowStateChanged(HandleUnconditionally);
+ return;
+ }
+
+ const NSWindow *nsWindow = m_view.window;
+
+ if (nsWindow.styleMask & NSWindowStyleMaskUtilityWindow
+ && newState & (Qt::WindowMinimized | Qt::WindowFullScreen)) {
+ qWarning() << window()->type() << "windows can not be made" << newState;
+ handleWindowStateChanged(HandleUnconditionally);
+ return;
+ }
+
+ const id sender = nsWindow;
+
+ // First we need to exit states that can't transition directly to other states
+ switch (currentState) {
+ case Qt::WindowMinimized:
+ [nsWindow deminiaturize:sender];
+ Q_ASSERT_X(windowState() != Qt::WindowMinimized, "QCocoaWindow",
+ "[NSWindow deminiaturize:] is synchronous");
+ break;
+ case Qt::WindowFullScreen: {
+ toggleFullScreen();
+ // Exiting fullscreen is not synchronous, so we need to wait for the
+ // NSWindowDidExitFullScreenNotification before continuing to apply
+ // the new state.
+ return;
+ }
+ default:;
+ }
+
+ // Then we apply the new state if needed
+ if (newState == windowState())
+ return;
+
+ switch (newState) {
+ case Qt::WindowFullScreen:
+ toggleFullScreen();
+ break;
+ case Qt::WindowMaximized:
+ toggleMaximized();
+ break;
+ case Qt::WindowMinimized:
+ [nsWindow miniaturize:sender];
+ break;
+ case Qt::WindowNoState:
+ if (windowState() == Qt::WindowMaximized)
+ toggleMaximized();
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+}
+
+Qt::WindowState QCocoaWindow::windowState() const
+{
+ // FIXME: Support compound states (Qt::WindowStates)
+
+ 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;
+
+ // 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;
+}
+
+void QCocoaWindow::toggleMaximized()
+{
+ const NSWindow *window = m_view.window;
+
+ // The NSWindow needs to be resizable, otherwise the window will
+ // not be possible to zoom back to non-zoomed state.
+ const bool wasResizable = window.styleMask & NSWindowStyleMaskResizable;
+ window.styleMask |= NSWindowStyleMaskResizable;
+
+ const id sender = window;
+ [window zoom:sender];
+
+ if (!wasResizable)
+ window.styleMask &= ~NSWindowStyleMaskResizable;
+}
+
+void QCocoaWindow::toggleFullScreen()
+{
+ const NSWindow *window = m_view.window;
+
+ // The window needs to have the correct collection behavior for the
+ // toggleFullScreen call to have an effect. The collection behavior
+ // will be reset in windowDidEnterFullScreen/windowDidLeaveFullScreen.
+ window.collectionBehavior |= NSWindowCollectionBehaviorFullScreenPrimary;
+
+ const id sender = window;
+ [window toggleFullScreen:sender];
+}
+
+void QCocoaWindow::windowWillEnterFullScreen()
+{
+ if (!isContentView())
+ return;
+
+ // 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.
+ m_view.window.styleMask |= NSWindowStyleMaskResizable;
+}
+
+bool QCocoaWindow::isTransitioningToFullScreen() const
+{
+ NSWindow *window = m_view.window;
+ return window.styleMask & NSWindowStyleMaskFullScreen && !window.qt_fullScreen;
+}
+
+void QCocoaWindow::windowDidEnterFullScreen()
+{
+ if (!isContentView())
+ return;
+
+ Q_ASSERT_X(m_view.window.qt_fullScreen, "QCocoaWindow",
+ "FullScreen category processes window notifications first");
+
+ // Reset to original styleMask
+ setWindowFlags(window()->flags());
+
+ handleWindowStateChanged();
+}
+
+void QCocoaWindow::windowWillExitFullScreen()
+{
+ if (!isContentView())
+ return;
+
+ // The NSWindow needs to be resizable, otherwise we'll end up with
+ // a weird zoom animation. The styleMask will be reset below.
+ m_view.window.styleMask |= NSWindowStyleMaskResizable;
+}
+
+void QCocoaWindow::windowDidExitFullScreen()
+{
+ if (!isContentView())
+ return;
+
+ Q_ASSERT_X(!m_view.window.qt_fullScreen, "QCocoaWindow",
+ "FullScreen category processes window notifications first");
+
+ // Reset to original styleMask
+ setWindowFlags(window()->flags());
+
+ Qt::WindowState requestedState = window()->windowState();
+
+ // Deliver update of QWindow state
+ handleWindowStateChanged();
+
+ if (requestedState != windowState() && requestedState != Qt::WindowFullScreen) {
+ // We were only going out of full screen as an intermediate step before
+ // progressing into the final step, so re-sync the desired state.
+ applyWindowState(requestedState);
+ }
+}
+
+void QCocoaWindow::windowDidMiniaturize()
+{
+ if (!isContentView())
+ return;
+
+ handleWindowStateChanged();
+}
+
+void QCocoaWindow::windowDidDeminiaturize()
+{
+ if (!isContentView())
+ return;
+
+ handleWindowStateChanged();
+}
+
+void QCocoaWindow::handleWindowStateChanged(HandleFlags flags)
+{
+ Qt::WindowState currentState = windowState();
+ if (!(flags & HandleUnconditionally) && currentState == m_lastReportedWindowState)
+ return;
+
+ qCDebug(lcQpaWindow) << "QCocoaWindow::handleWindowStateChanged" <<
+ m_lastReportedWindowState << "-->" << currentState;
+
+ QWindowSystemInterface::handleWindowStateChanged<QWindowSystemInterface::SynchronousDelivery>(
+ window(), currentState, m_lastReportedWindowState);
+ m_lastReportedWindowState = currentState;
+}
+
+// ------------------------------------------------------------
+
void QCocoaWindow::setWindowTitle(const QString &title)
{
if (!isContentView())
@@ -680,7 +888,7 @@ bool QCocoaWindow::isAlertState() const
void QCocoaWindow::raise()
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::raise" << window();
+ qCDebug(lcQpaWindow) << "QCocoaWindow::raise" << window();
// ### handle spaces (see Qt 4 raise_sys in qwidget_mac.mm)
if (!isContentView())
@@ -705,7 +913,7 @@ void QCocoaWindow::raise()
void QCocoaWindow::lower()
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::lower" << window();
+ qCDebug(lcQpaWindow) << "QCocoaWindow::lower" << window();
if (!isContentView())
return;
@@ -718,6 +926,22 @@ bool QCocoaWindow::isExposed() const
return !m_exposedRect.isEmpty();
}
+bool QCocoaWindow::isEmbedded() const
+{
+ // Child QWindows are not embedded
+ if (window()->parent())
+ return false;
+
+ // Top-level QWindows with non-Qt NSWindows are embedded
+ if (m_view.window)
+ return !([m_view.window isKindOfClass:[QNSWindow class]] ||
+ [m_view.window isKindOfClass:[QNSPanel class]]);
+
+ // The window has no QWindow parent but also no NSWindow,
+ // conservatively reuturn false.
+ return false;
+}
+
bool QCocoaWindow::isOpaque() const
{
// OpenGL surfaces can be ordered either above(default) or below the NSWindow.
@@ -737,7 +961,7 @@ void QCocoaWindow::propagateSizeHints()
if (!isContentView())
return;
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::propagateSizeHints" << window()
+ qCDebug(lcQpaWindow) << "QCocoaWindow::propagateSizeHints" << window()
<< "min:" << windowMinimumSize() << "max:" << windowMaximumSize()
<< "increment:" << windowSizeIncrement()
<< "base:" << windowBaseSize();
@@ -754,7 +978,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(m_windowFlags);
+ setWindowZoomButton(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.
@@ -771,7 +995,7 @@ void QCocoaWindow::propagateSizeHints()
void QCocoaWindow::setOpacity(qreal level)
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setOpacity" << level;
+ qCDebug(lcQpaWindow) << "QCocoaWindow::setOpacity" << level;
if (!isContentView())
return;
@@ -780,7 +1004,7 @@ void QCocoaWindow::setOpacity(qreal level)
void QCocoaWindow::setMask(const QRegion &region)
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setMask" << window() << region;
+ qCDebug(lcQpaWindow) << "QCocoaWindow::setMask" << window() << region;
if (m_view.layer) {
if (!region.isEmpty()) {
@@ -803,18 +1027,12 @@ void QCocoaWindow::setMask(const QRegion &region)
// time, and so would not result in an updated backingstore.
m_needsInvalidateShadow = true;
[m_view setNeedsDisplay:YES];
-
- // FIXME: [NSWindow invalidateShadow] has no effect when in layer-backed mode,
- // so if the mask is changed after the initial mask is applied, it will not
- // result in any visual change to the shadow. This is an Apple bug, and there
- // may be ways to work around it, such as calling setFrame on the window to
- // trigger some internal invalidation, but that needs more research.
}
}
bool QCocoaWindow::setKeyboardGrabEnabled(bool grab)
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setKeyboardGrabEnabled" << window() << grab;
+ qCDebug(lcQpaWindow) << "QCocoaWindow::setKeyboardGrabEnabled" << window() << grab;
if (!isContentView())
return false;
@@ -826,7 +1044,7 @@ bool QCocoaWindow::setKeyboardGrabEnabled(bool grab)
bool QCocoaWindow::setMouseGrabEnabled(bool grab)
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setMouseGrabEnabled" << window() << grab;
+ qCDebug(lcQpaWindow) << "QCocoaWindow::setMouseGrabEnabled" << window() << grab;
if (!isContentView())
return false;
@@ -843,10 +1061,10 @@ WId QCocoaWindow::winId() const
void QCocoaWindow::setParent(const QPlatformWindow *parentWindow)
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setParent" << window() << (parentWindow ? parentWindow->window() : 0);
+ qCDebug(lcQpaWindow) << "QCocoaWindow::setParent" << window() << (parentWindow ? parentWindow->window() : 0);
// recreate the window for compatibility
- bool unhideAfterRecreate = parentWindow && !m_viewIsToBeEmbedded && ![m_view isHidden];
+ bool unhideAfterRecreate = parentWindow && !isEmbedded() && ![m_view isHidden];
recreateWindowIfNeeded();
if (unhideAfterRecreate)
[m_view setHidden:NO];
@@ -863,9 +1081,8 @@ NSWindow *QCocoaWindow::nativeWindow() const
return m_view.window;
}
-void QCocoaWindow::setEmbeddedInForeignView(bool embedded)
+void QCocoaWindow::setEmbeddedInForeignView()
{
- m_viewIsToBeEmbedded = embedded;
// Release any previosly created NSWindow.
[m_nsWindow closeAndRelease];
m_nsWindow = 0;
@@ -948,8 +1165,8 @@ void QCocoaWindow::windowDidBecomeKey()
QWindowSystemInterface::handleEnterEvent(m_enterLeaveTargetWindow, windowPoint, screenPoint);
}
- if (!windowIsPopupType() && !qnsview_cast(m_view).isMenuView)
- QWindowSystemInterface::handleWindowActivated(window());
+ if (!windowIsPopupType())
+ QWindowSystemInterface::handleWindowActivated<QWindowSystemInterface::SynchronousDelivery>(window());
}
void QCocoaWindow::windowDidResignKey()
@@ -966,82 +1183,8 @@ void QCocoaWindow::windowDidResignKey()
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() && !qnsview_cast(m_view).isMenuView)
- QWindowSystemInterface::handleWindowActivated(0);
- }
-}
-
-void QCocoaWindow::windowDidMiniaturize()
-{
- if (!isContentView())
- return;
-
- handleWindowStateChanged();
-}
-
-void QCocoaWindow::windowDidDeminiaturize()
-{
- if (!isContentView())
- return;
-
- handleWindowStateChanged();
-}
-
-void QCocoaWindow::windowWillEnterFullScreen()
-{
- if (!isContentView())
- return;
-
- // 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.
- m_view.window.styleMask |= NSResizableWindowMask;
-}
-
-void QCocoaWindow::windowDidEnterFullScreen()
-{
- if (!isContentView())
- return;
-
- Q_ASSERT_X(m_view.window.qt_fullScreen, "QCocoaWindow",
- "FullScreen category processes window notifications first");
-
- // Reset to original styleMask
- setWindowFlags(m_windowFlags);
-
- handleWindowStateChanged();
-}
-
-void QCocoaWindow::windowWillExitFullScreen()
-{
- if (!isContentView())
- return;
-
- // The NSWindow needs to be resizable, otherwise we'll end up with
- // a weird zoom animation. The styleMask will be reset below.
- m_view.window.styleMask |= NSResizableWindowMask;
-}
-
-void QCocoaWindow::windowDidExitFullScreen()
-{
- if (!isContentView())
- return;
-
- Q_ASSERT_X(!m_view.window.qt_fullScreen, "QCocoaWindow",
- "FullScreen category processes window notifications first");
-
- // Reset to original styleMask
- setWindowFlags(m_windowFlags);
-
- Qt::WindowState requestedState = window()->windowState();
-
- // Deliver update of QWindow state
- handleWindowStateChanged();
-
- if (requestedState != windowState() && requestedState != Qt::WindowFullScreen) {
- // We were only going out of full screen as an intermediate step before
- // progressing into the final step, so re-sync the desired state.
- applyWindowState(requestedState);
+ if (!windowIsPopupType())
+ QWindowSystemInterface::handleWindowActivated<QWindowSystemInterface::SynchronousDelivery>(0);
}
}
@@ -1068,8 +1211,24 @@ void QCocoaWindow::windowDidChangeScreen()
if (!window())
return;
- if (QCocoaScreen *cocoaScreen = QCocoaIntegration::instance()->screenForNSScreen(m_view.window.screen))
- QWindowSystemInterface::handleWindowScreenChanged(window(), cocoaScreen->screen());
+ const bool wasRunningDisplayLink = static_cast<QCocoaScreen *>(screen())->isRunningDisplayLink();
+
+ if (QCocoaScreen *newScreen = QCocoaIntegration::instance()->screenForNSScreen(m_view.window.screen)) {
+ if (newScreen == screen()) {
+ // Screen properties have changed. Will be handled by
+ // NSApplicationDidChangeScreenParametersNotification
+ // in QCocoaIntegration::updateScreens().
+ return;
+ }
+
+ qCDebug(lcQpaWindow) << window() << "moved to" << newScreen;
+ QWindowSystemInterface::handleWindowScreenChanged<QWindowSystemInterface::SynchronousDelivery>(window(), newScreen->screen());
+
+ if (hasPendingUpdateRequest() && wasRunningDisplayLink)
+ requestUpdate(); // Restart display-link on new screen
+ } else {
+ qCWarning(lcQpaWindow) << "Failed to get QCocoaScreen for" << m_view.window.screen;
+ }
}
void QCocoaWindow::windowWillClose()
@@ -1083,7 +1242,7 @@ void QCocoaWindow::windowWillClose()
bool QCocoaWindow::windowShouldClose()
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::windowShouldClose" << window();
+ 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
@@ -1104,22 +1263,14 @@ void QCocoaWindow::handleGeometryChange()
if (!m_initialized)
return;
- // Don't send the geometry change if the QWindow is designated to be
- // embedded in a foreign view hierarchy but has not actually been
- // embedded yet - it's too early.
- if (m_viewIsToBeEmbedded && !m_viewIsEmbedded)
- return;
-
// It can happen that the current NSWindow is nil (if we are changing styleMask
// from/to borderless, and the content view is being re-parented), which results
// in invalid coordinates.
if (m_inSetStyleMask && !m_view.window)
return;
- const bool isEmbedded = m_viewIsToBeEmbedded || m_viewIsEmbedded;
-
QRect newGeometry;
- if (isContentView() && !isEmbedded) {
+ if (isContentView() && !isEmbedded()) {
// Content views are positioned at (0, 0) in the window, so we resolve via the window
CGRect contentRect = [m_view.window contentRectForFrameRect:m_view.window.frame];
@@ -1130,7 +1281,7 @@ void QCocoaWindow::handleGeometryChange()
newGeometry = QRectF::fromCGRect(m_view.frame).toRect();
}
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::handleGeometryChange" << window()
+ qCDebug(lcQpaWindow) << "QCocoaWindow::handleGeometryChange" << window()
<< "current" << geometry() << "new" << newGeometry;
QWindowSystemInterface::handleGeometryChange(window(), newGeometry);
@@ -1162,24 +1313,10 @@ void QCocoaWindow::handleExposeEvent(const QRegion &region)
m_exposedRect = QRect();
}
- qCDebug(lcQpaCocoaDrawing) << "QCocoaWindow::handleExposeEvent" << window() << region << "isExposed" << isExposed();
+ qCDebug(lcQpaDrawing) << "QCocoaWindow::handleExposeEvent" << window() << region << "isExposed" << isExposed();
QWindowSystemInterface::handleExposeEvent<QWindowSystemInterface::SynchronousDelivery>(window(), region);
}
-void QCocoaWindow::handleWindowStateChanged(HandleFlags flags)
-{
- Qt::WindowState currentState = windowState();
- if (!(flags & HandleUnconditionally) && currentState == m_lastReportedWindowState)
- return;
-
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::handleWindowStateChanged" <<
- m_lastReportedWindowState << "-->" << currentState;
-
- QWindowSystemInterface::handleWindowStateChanged<QWindowSystemInterface::SynchronousDelivery>(
- window(), currentState, m_lastReportedWindowState);
- m_lastReportedWindowState = currentState;
-}
-
// --------------------------------------------------------------------------
bool QCocoaWindow::windowIsPopupType(Qt::WindowType type) const
@@ -1192,18 +1329,6 @@ bool QCocoaWindow::windowIsPopupType(Qt::WindowType type) const
return ((type & Qt::Popup) == Qt::Popup);
}
-#ifndef QT_NO_OPENGL
-void QCocoaWindow::setCurrentContext(QCocoaGLContext *context)
-{
- m_glContext = context;
-}
-
-QCocoaGLContext *QCocoaWindow::currentContext() const
-{
- return m_glContext;
-}
-#endif
-
/*!
Checks if the window is the content view of its immediate NSWindow.
@@ -1230,6 +1355,7 @@ void QCocoaWindow::recreateWindowIfNeeded()
QPlatformWindow *parentWindow = QPlatformWindow::parent();
+ const bool isEmbeddedView = isEmbedded();
RecreationReasons recreateReason = RecreationNotNeeded;
QCocoaWindow *oldParentCocoaWindow = nullptr;
@@ -1246,7 +1372,7 @@ void QCocoaWindow::recreateWindowIfNeeded()
if (m_windowModality != window()->modality())
recreateReason |= WindowModalityChanged;
- const bool shouldBeContentView = !parentWindow && !(m_viewIsToBeEmbedded || m_viewIsEmbedded);
+ const bool shouldBeContentView = !parentWindow && !isEmbeddedView;
if (isContentView() != shouldBeContentView)
recreateReason |= ContentViewChanged;
@@ -1258,7 +1384,7 @@ void QCocoaWindow::recreateWindowIfNeeded()
if (isPanel != shouldBePanel)
recreateReason |= PanelChanged;
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::recreateWindowIfNeeded" << window() << recreateReason;
+ qCDebug(lcQpaWindow) << "QCocoaWindow::recreateWindowIfNeeded" << window() << recreateReason;
if (recreateReason == RecreationNotNeeded)
return;
@@ -1268,33 +1394,28 @@ void QCocoaWindow::recreateWindowIfNeeded()
// Remove current window (if any)
if ((isContentView() && !shouldBeContentView) || (recreateReason & PanelChanged)) {
if (m_nsWindow) {
- qCDebug(lcQpaCocoaWindow) << "Getting rid of existing window" << m_nsWindow;
+ qCDebug(lcQpaWindow) << "Getting rid of existing window" << m_nsWindow;
if (m_nsWindow.observationInfo) {
- qCCritical(lcQpaCocoaWindow) << m_nsWindow << "has active key-value observers (KVO)!"
+ 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()) {
+ if (isContentView() && !isEmbeddedView) {
// We explicitly disassociate m_view from the window's contentView,
// as AppKit does not automatically do this in response to removing
// the view from the NSThemeFrame subview list, so we might end up
// with a NSWindow contentView pointing to a deallocated NSView.
m_view.window.contentView = nil;
}
- m_nsWindow = 0;
+ m_nsWindow = nil;
}
}
- if (shouldBeContentView) {
- bool noPreviousWindow = m_nsWindow == 0;
- QCocoaNSWindow *newWindow = nullptr;
- if (noPreviousWindow)
- newWindow = createNSWindow(shouldBePanel);
-
+ if (shouldBeContentView && !m_nsWindow) {
// Move view to new NSWindow if needed
- if (newWindow) {
- qCDebug(lcQpaCocoaWindow) << "Ensuring that" << m_view << "is content view for" << newWindow;
+ if (auto *newWindow = createNSWindow(shouldBePanel)) {
+ qCDebug(lcQpaWindow) << "Ensuring that" << m_view << "is content view for" << newWindow;
[m_view setPostsFrameChangedNotifications:NO];
[newWindow setContentView:m_view];
[m_view setPostsFrameChangedNotifications:YES];
@@ -1304,14 +1425,14 @@ void QCocoaWindow::recreateWindowIfNeeded()
}
}
- if (m_viewIsToBeEmbedded) {
+ 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());
+ setWindowFilePath(window()->filePath()); // Also sets window icon
setWindowState(window()->windowState());
} else {
// Child windows have no NSWindow, link the NSViews instead.
@@ -1334,14 +1455,28 @@ void QCocoaWindow::recreateWindowIfNeeded()
// top-level QWindows may have an attached NSToolBar, call
// update function which will attach to the NSWindow.
- if (!parentWindow)
+ if (!parentWindow && !isEmbeddedView)
updateNSToolbar();
}
void QCocoaWindow::requestUpdate()
{
- qCDebug(lcQpaCocoaDrawing) << "QCocoaWindow::requestUpdate" << window();
- QPlatformWindow::requestUpdate();
+ const int swapInterval = format().swapInterval();
+ qCDebug(lcQpaDrawing) << "QCocoaWindow::requestUpdate" << window() << "swapInterval" << swapInterval;
+
+ if (swapInterval > 0) {
+ // Vsync is enabled, deliver via CVDisplayLink
+ static_cast<QCocoaScreen *>(screen())->requestUpdate();
+ } else {
+ // Fall back to the un-throttled timer-based callback
+ QPlatformWindow::requestUpdate();
+ }
+}
+
+void QCocoaWindow::deliverUpdateRequest()
+{
+ qCDebug(lcQpaDrawing) << "Delivering update request to" << window();
+ QPlatformWindow::deliverUpdateRequest();
}
void QCocoaWindow::requestActivateWindow()
@@ -1375,7 +1510,7 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel)
}
if (!targetScreen) {
- qCWarning(lcQpaCocoaWindow) << "Window position" << rect << "outside any known screen, using primary screen";
+ qCWarning(lcQpaWindow) << "Window position" << rect << "outside any known screen, using primary screen";
targetScreen = QGuiApplication::primaryScreen();
// AppKit will only reposition a window that's outside the target screen area if
// the window has a title bar. If left out, the window ends up with no screen.
@@ -1399,8 +1534,10 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel)
Q_ASSERT_X(nsWindow.screen == cocoaScreen->nativeScreen(), "QCocoaWindow",
"Resulting NSScreen should match the requested NSScreen");
- if (targetScreen != window()->screen())
- QWindowSystemInterface::handleWindowScreenChanged(window(), targetScreen);
+ if (targetScreen != window()->screen()) {
+ QWindowSystemInterface::handleWindowScreenChanged<
+ QWindowSystemInterface::SynchronousDelivery>(window(), targetScreen);
+ }
nsWindow.delegate = [[QNSWindowDelegate alloc] initWithQCocoaWindow:this];
@@ -1473,138 +1610,6 @@ void QCocoaWindow::removeMonitor()
monitor = nil;
}
-/*!
- Applies the given state to the NSWindow, going in/out of minimize/zoomed/fullscreen
-
- When this is called from QWindow::setWindowState(), the QWindow state has not been
- updated yet, so window()->windowState() will reflect the previous state that was
- reported to QtGui.
-*/
-void QCocoaWindow::applyWindowState(Qt::WindowStates requestedState)
-{
- if (!isContentView())
- return;
-
- const Qt::WindowState currentState = windowState();
- const Qt::WindowState newState = QWindowPrivate::effectiveState(requestedState);
-
- if (newState == currentState)
- return;
-
- const NSSize contentSize = m_view.frame.size;
- if (contentSize.width <= 0 || contentSize.height <= 0) {
- // If content view width or height is 0 then the window animations will crash so
- // do nothing. We report the current state back to reflect the failed operation.
- qWarning("invalid window content view size, check your window geometry");
- handleWindowStateChanged(HandleUnconditionally);
- return;
- }
-
- const NSWindow *nsWindow = m_view.window;
-
- if (nsWindow.styleMask & NSUtilityWindowMask
- && newState & (Qt::WindowMinimized | Qt::WindowFullScreen)) {
- qWarning() << window()->type() << "windows can not be made" << newState;
- handleWindowStateChanged(HandleUnconditionally);
- return;
- }
-
- const id sender = nsWindow;
-
- // First we need to exit states that can't transition directly to other states
- switch (currentState) {
- case Qt::WindowMinimized:
- [nsWindow deminiaturize:sender];
- Q_ASSERT_X(windowState() != Qt::WindowMinimized, "QCocoaWindow",
- "[NSWindow deminiaturize:] is synchronous");
- break;
- case Qt::WindowFullScreen: {
- toggleFullScreen();
- // Exiting fullscreen is not synchronous, so we need to wait for the
- // NSWindowDidExitFullScreenNotification before continuing to apply
- // the new state.
- return;
- }
- default:;
- }
-
- // Then we apply the new state if needed
- if (newState == windowState())
- return;
-
- switch (newState) {
- case Qt::WindowFullScreen:
- toggleFullScreen();
- break;
- case Qt::WindowMaximized:
- toggleMaximized();
- break;
- case Qt::WindowMinimized:
- [nsWindow miniaturize:sender];
- break;
- case Qt::WindowNoState:
- if (windowState() == Qt::WindowMaximized)
- toggleMaximized();
- break;
- default:
- Q_UNREACHABLE();
- }
-}
-
-void QCocoaWindow::toggleMaximized()
-{
- const NSWindow *window = m_view.window;
-
- // The NSWindow needs to be resizable, otherwise the window will
- // not be possible to zoom back to non-zoomed state.
- const bool wasResizable = window.styleMask & NSResizableWindowMask;
- window.styleMask |= NSResizableWindowMask;
-
- const id sender = window;
- [window zoom:sender];
-
- if (!wasResizable)
- window.styleMask &= ~NSResizableWindowMask;
-}
-
-void QCocoaWindow::toggleFullScreen()
-{
- const NSWindow *window = m_view.window;
-
- // The window needs to have the correct collection behavior for the
- // toggleFullScreen call to have an effect. The collection behavior
- // will be reset in windowDidEnterFullScreen/windowDidLeaveFullScreen.
- window.collectionBehavior |= NSWindowCollectionBehaviorFullScreenPrimary;
-
- const id sender = window;
- [window toggleFullScreen:sender];
-}
-
-bool QCocoaWindow::isTransitioningToFullScreen() const
-{
- NSWindow *window = m_view.window;
- return window.styleMask & NSFullScreenWindowMask && !window.qt_fullScreen;
-}
-
-Qt::WindowState QCocoaWindow::windowState() const
-{
- // FIXME: Support compound states (Qt::WindowStates)
-
- 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;
-
- // 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;
-}
-
bool QCocoaWindow::setWindowModified(bool modified)
{
if (!isContentView())
@@ -1685,7 +1690,7 @@ void QCocoaWindow::applyContentBorderThickness(NSWindow *window)
return;
if (!m_drawContentBorderGradient) {
- window.styleMask = window.styleMask & ~NSTexturedBackgroundWindowMask;
+ window.styleMask = window.styleMask & ~NSWindowStyleMaskTexturedBackground;
[window.contentView.superview setNeedsDisplay:YES];
window.titlebarAppearsTransparent = NO;
return;
@@ -1711,7 +1716,7 @@ void QCocoaWindow::applyContentBorderThickness(NSWindow *window)
int effectiveBottomContentBorderThickness = m_bottomContentBorderThickness;
- [window setStyleMask:[window styleMask] | NSTexturedBackgroundWindowMask];
+ [window setStyleMask:[window styleMask] | NSWindowStyleMaskTexturedBackground];
window.titlebarAppearsTransparent = YES;
// Setting titlebarAppearsTransparent to YES means that the border thickness has to account
diff --git a/src/plugins/platforms/cocoa/qmacclipboard.h b/src/plugins/platforms/cocoa/qmacclipboard.h
index 1d229a55d2..f2f460c048 100644
--- a/src/plugins/platforms/cocoa/qmacclipboard.h
+++ b/src/plugins/platforms/cocoa/qmacclipboard.h
@@ -54,7 +54,7 @@ public:
enum DataRequestType { EagerRequest, LazyRequest };
private:
struct Promise {
- Promise() : itemId(0), convertor(0) { }
+ Promise() : itemId(0), convertor(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);
@@ -79,7 +79,7 @@ private:
public:
QMacPasteboard(PasteboardRef p, uchar mime_type=0);
QMacPasteboard(uchar mime_type);
- QMacPasteboard(CFStringRef name=0, uchar mime_type=0);
+ QMacPasteboard(CFStringRef name=nullptr, uchar mime_type=0);
~QMacPasteboard();
bool hasFlavor(QString flavor) const;
diff --git a/src/plugins/platforms/cocoa/qmacclipboard.mm b/src/plugins/platforms/cocoa/qmacclipboard.mm
index f3467fdc73..5939003c64 100644
--- a/src/plugins/platforms/cocoa/qmacclipboard.mm
+++ b/src/plugins/platforms/cocoa/qmacclipboard.mm
@@ -75,7 +75,7 @@ QMacPasteboard::Promise::Promise(int itemId, QMacInternalPasteboardMime *c, QStr
// Request the data from the application immediately for eager requests.
if (dataRequestType == QMacPasteboard::EagerRequest) {
variantData = md->variantData(m);
- mimeData = 0;
+ mimeData = nullptr;
} else {
mimeData = md;
}
@@ -94,8 +94,8 @@ QMacPasteboard::QMacPasteboard(uchar mt)
{
mac_mime_source = false;
mime_type = mt ? mt : uchar(QMacInternalPasteboardMime::MIME_ALL);
- paste = 0;
- OSStatus err = PasteboardCreate(0, &paste);
+ paste = nullptr;
+ OSStatus err = PasteboardCreate(nullptr, &paste);
if (err == noErr) {
PasteboardSetPromiseKeeper(paste, promiseKeeper, this);
} else {
@@ -108,7 +108,7 @@ QMacPasteboard::QMacPasteboard(CFStringRef name, uchar mt)
{
mac_mime_source = false;
mime_type = mt ? mt : uchar(QMacInternalPasteboardMime::MIME_ALL);
- paste = 0;
+ paste = nullptr;
OSStatus err = PasteboardCreate(name, &paste);
if (err == noErr) {
PasteboardSetPromiseKeeper(paste, promiseKeeper, this);
@@ -165,7 +165,7 @@ OSStatus QMacPasteboard::promiseKeeper(PasteboardRef paste, PasteboardItemID id,
// 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(0, (UInt8*)ba.constData(), ba.size());
+ QCFType<CFDataRef> data = CFDataCreate(nullptr, (UInt8*)ba.constData(), ba.size());
PasteboardPutItemFlavor(paste, id, flavor, data, kPasteboardFlavorNoFlags);
return noErr;
}
@@ -196,7 +196,7 @@ OSStatus QMacPasteboard::promiseKeeper(PasteboardRef paste, PasteboardItemID id,
if (md.size() <= promise.offset)
return cantGetFlavorErr;
const QByteArray &ba = md[promise.offset];
- QCFType<CFDataRef> data = CFDataCreate(0, (UInt8*)ba.constData(), ba.size());
+ QCFType<CFDataRef> data = CFDataCreate(nullptr, (UInt8*)ba.constData(), ba.size());
PasteboardPutItemFlavor(paste, id, flavor, data, kPasteboardFlavorNoFlags);
return noErr;
}
@@ -553,7 +553,7 @@ QMacPasteboard::sync() const
const bool fromGlobal = PasteboardSynchronize(paste) & kPasteboardModified;
if (fromGlobal)
- const_cast<QMacPasteboard *>(this)->setMimeData(0);
+ const_cast<QMacPasteboard *>(this)->setMimeData(nullptr);
#ifdef DEBUG_PASTEBOARD
if (fromGlobal)
diff --git a/src/plugins/platforms/cocoa/qmultitouch_mac.mm b/src/plugins/platforms/cocoa/qmultitouch_mac.mm
index 9eca4d2d43..10652dc6a1 100644
--- a/src/plugins/platforms/cocoa/qmultitouch_mac.mm
+++ b/src/plugins/platforms/cocoa/qmultitouch_mac.mm
@@ -107,7 +107,7 @@ QCocoaTouch *QCocoaTouch::findQCocoaTouch(NSTouch *nstouch)
qint64 identity = qint64([nstouch identity]);
if (_currentTouches.contains(identity))
return _currentTouches.value(identity);
- return 0;
+ return nullptr;
}
Qt::TouchPointState QCocoaTouch::toTouchPointState(NSTouchPhase nsState)
diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h
index e2ea862cd5..b40dfe0d14 100644
--- a/src/plugins/platforms/cocoa/qnsview.h
+++ b/src/plugins/platforms/cocoa/qnsview.h
@@ -41,111 +41,45 @@
#define QNSVIEW_H
#include <AppKit/AppKit.h>
-
-#include <QtCore/QPointer>
-#include <QtCore/QSet>
-#include <QtGui/QImage>
-#include <QtGui/QAccessible>
+#include <MetalKit/MetalKit.h>
#include "private/qcore_mac_p.h"
QT_BEGIN_NAMESPACE
class QCocoaWindow;
class QCocoaGLContext;
+class QPointF;
QT_END_NAMESPACE
Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
+Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QCocoaNSMenuItem));
-@interface QT_MANGLE_NAMESPACE(QNSView) : NSView <NSTextInputClient> {
- QPointer<QCocoaWindow> m_platformWindow;
- NSTrackingArea *m_trackingArea;
- Qt::MouseButtons m_buttons;
- Qt::MouseButtons m_acceptedMouseDowns;
- Qt::MouseButtons m_frameStrutButtons;
- QString m_composingText;
- QPointer<QObject> m_composingFocusObject;
- bool m_sendKeyEvent;
- QStringList *currentCustomDragTypes;
- bool m_dontOverrideCtrlLMB;
- bool m_sendUpAsRightButton;
- Qt::KeyboardModifiers currentWheelModifiers;
-#ifndef QT_NO_OPENGL
- QCocoaGLContext *m_glContext;
- bool m_shouldSetGLContextinDrawRect;
-#endif
- NSString *m_inputSource;
- QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) *m_mouseMoveHelper;
- bool m_resendKeyEvent;
- bool m_scrolling;
- bool m_updatingDrag;
- NSEvent *m_currentlyInterpretedKeyEvent;
- bool m_isMenuView;
- QSet<quint32> m_acceptedKeyDowns;
- bool m_updateRequested;
-}
+@interface QT_MANGLE_NAMESPACE(QNSView) : NSView
@property (nonatomic, retain) NSCursor *cursor;
-- (id)init;
-- (id)initWithCocoaWindow:(QCocoaWindow *)platformWindow;
-#ifndef QT_NO_OPENGL
-- (void)setQCocoaGLContext:(QCocoaGLContext *)context;
-#endif
-- (void)drawRect:(NSRect)dirtyRect;
-- (void)textInputContextKeyboardSelectionDidChangeNotification : (NSNotification *) textInputContextKeyboardSelectionDidChangeNotification;
-- (void)viewDidHide;
-- (void)removeFromSuperview;
-- (void)cancelComposingText;
-
-- (BOOL)isFlipped;
-- (BOOL)acceptsFirstResponder;
-- (BOOL)becomeFirstResponder;
-- (BOOL)isOpaque;
+- (instancetype)initWithCocoaWindow:(QCocoaWindow *)platformWindow;
- (void)convertFromScreen:(NSPoint)mouseLocation toWindowPoint:(QPointF *)qtWindowPoint andScreenPoint:(QPointF *)qtScreenPoint;
-- (void)resetMouseButtons;
+@end
-- (void)requestUpdate;
-
-- (void)handleMouseEvent:(NSEvent *)theEvent;
-- (bool)handleMouseDownEvent:(NSEvent *)theEvent withButton:(int)buttonNumber;
-- (bool)handleMouseDraggedEvent:(NSEvent *)theEvent withButton:(int)buttonNumber;
-- (bool)handleMouseUpEvent:(NSEvent *)theEvent withButton:(int)buttonNumber;
-- (void)mouseDown:(NSEvent *)theEvent;
-- (void)mouseDragged:(NSEvent *)theEvent;
-- (void)mouseUp:(NSEvent *)theEvent;
-- (void)mouseMovedImpl:(NSEvent *)theEvent;
-- (void)mouseEnteredImpl:(NSEvent *)theEvent;
-- (void)mouseExitedImpl:(NSEvent *)theEvent;
-- (void)rightMouseDown:(NSEvent *)theEvent;
-- (void)rightMouseDragged:(NSEvent *)theEvent;
-- (void)rightMouseUp:(NSEvent *)theEvent;
-- (void)otherMouseDown:(NSEvent *)theEvent;
-- (void)otherMouseDragged:(NSEvent *)theEvent;
-- (void)otherMouseUp:(NSEvent *)theEvent;
+@interface QT_MANGLE_NAMESPACE(QNSView) (MouseAPI)
- (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent;
+- (void)resetMouseButtons;
+@end
-#ifndef QT_NO_TABLETEVENT
-- (bool)handleTabletEvent: (NSEvent *)theEvent;
-- (void)tabletPoint: (NSEvent *)theEvent;
-- (void)tabletProximity: (NSEvent *)theEvent;
-#endif
-
-- (int) convertKeyCode : (QChar)keyCode;
-+ (Qt::KeyboardModifiers) convertKeyModifiers : (ulong)modifierFlags;
-- (bool)handleKeyEvent:(NSEvent *)theEvent eventType:(int)eventType;
-- (void)keyDown:(NSEvent *)theEvent;
-- (void)keyUp:(NSEvent *)theEvent;
-
-- (void)registerDragTypes;
-- (NSDragOperation)handleDrag:(id <NSDraggingInfo>)sender;
+@interface QT_MANGLE_NAMESPACE(QNSView) (KeysAPI)
++ (Qt::KeyboardModifiers)convertKeyModifiers:(ulong)modifierFlags;
+@end
+@interface QT_MANGLE_NAMESPACE(QNSView) (ComplexTextAPI)
+- (void)unmarkText;
+- (void)cancelComposingText;
@end
@interface QT_MANGLE_NAMESPACE(QNSView) (QtExtras)
@property (nonatomic, readonly) QCocoaWindow *platformWindow;
-@property (nonatomic, readonly) BOOL isMenuView;
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSView);
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 1c400a1ec9..9bd53ed334 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -51,7 +51,11 @@
#include <qpa/qwindowsysteminterface.h>
#include <QtGui/QTextFormat>
#include <QtCore/QDebug>
+#include <QtCore/QPointer>
+#include <QtCore/QSet>
#include <QtCore/qsysinfo.h>
+#include <QtGui/QAccessible>
+#include <QtGui/QImage>
#include <private/qguiapplication_p.h>
#include <private/qcoregraphics_p.h>
#include <private/qwindow_p.h>
@@ -61,94 +65,112 @@
#endif
#include "qcocoaintegration.h"
-#ifdef QT_COCOA_ENABLE_ACCESSIBILITY_INSPECTOR
-#include <accessibilityinspector.h>
-#endif
+// Private interface
+@interface QT_MANGLE_NAMESPACE(QNSView) ()
+- (BOOL)isTransparentForUserInput;
+@end
-Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch")
-#ifndef QT_NO_GESTURES
-Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures")
-#endif
-Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
+@interface QT_MANGLE_NAMESPACE(QNSView) (Drawing) <CALayerDelegate>
+- (BOOL)wantsLayerHelper;
+@end
@interface QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) : NSObject
-{
- QNSView *view;
-}
-
-- (id)initWithView:(QNSView *)theView;
-
+- (instancetype)initWithView:(QNSView *)theView;
- (void)mouseMoved:(NSEvent *)theEvent;
- (void)mouseEntered:(NSEvent *)theEvent;
- (void)mouseExited:(NSEvent *)theEvent;
- (void)cursorUpdate:(NSEvent *)theEvent;
-
@end
-@implementation QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper)
-
-- (id)initWithView:(QNSView *)theView
-{
- self = [super init];
- if (self) {
- view = theView;
- }
- return self;
-}
-
-- (void)mouseMoved:(NSEvent *)theEvent
-{
- [view mouseMovedImpl:theEvent];
-}
+@interface QT_MANGLE_NAMESPACE(QNSView) (Mouse)
+- (NSPoint)screenMousePoint:(NSEvent *)theEvent;
+- (void)mouseMovedImpl:(NSEvent *)theEvent;
+- (void)mouseEnteredImpl:(NSEvent *)theEvent;
+- (void)mouseExitedImpl:(NSEvent *)theEvent;
+@end
-- (void)mouseEntered:(NSEvent *)theEvent
-{
- [view mouseEnteredImpl:theEvent];
-}
+@interface QT_MANGLE_NAMESPACE(QNSView) (Touch)
+@end
-- (void)mouseExited:(NSEvent *)theEvent
-{
- [view mouseExitedImpl:theEvent];
-}
+@interface QT_MANGLE_NAMESPACE(QNSView) (Tablet)
+- (bool)handleTabletEvent:(NSEvent *)theEvent;
+@end
-- (void)cursorUpdate:(NSEvent *)theEvent
-{
- [view cursorUpdate:theEvent];
-}
+@interface QT_MANGLE_NAMESPACE(QNSView) (Gestures)
+@end
+@interface QT_MANGLE_NAMESPACE(QNSView) (Dragging)
+-(void)registerDragTypes;
@end
-// Private interface
-@interface QT_MANGLE_NAMESPACE(QNSView) ()
-- (BOOL)isTransparentForUserInput;
+@interface QT_MANGLE_NAMESPACE(QNSView) (Keys)
@end
-@implementation QT_MANGLE_NAMESPACE(QNSView)
+@interface QT_MANGLE_NAMESPACE(QNSView) (ComplexText) <NSTextInputClient>
+- (void)textInputContextKeyboardSelectionDidChangeNotification:(NSNotification *)textInputContextKeyboardSelectionDidChangeNotification;
+@end
-- (id) init
-{
- if (self = [super initWithFrame:NSZeroRect]) {
+@implementation QT_MANGLE_NAMESPACE(QNSView) {
+ QPointer<QCocoaWindow> m_platformWindow;
+ NSTrackingArea *m_trackingArea;
+ Qt::MouseButtons m_buttons;
+ Qt::MouseButtons m_acceptedMouseDowns;
+ Qt::MouseButtons m_frameStrutButtons;
+ QString m_composingText;
+ QPointer<QObject> m_composingFocusObject;
+ bool m_sendKeyEvent;
+ bool m_dontOverrideCtrlLMB;
+ bool m_sendUpAsRightButton;
+ Qt::KeyboardModifiers m_currentWheelModifiers;
+ NSString *m_inputSource;
+ QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) *m_mouseMoveHelper;
+ bool m_resendKeyEvent;
+ bool m_scrolling;
+ bool m_updatingDrag;
+ NSEvent *m_currentlyInterpretedKeyEvent;
+ QSet<quint32> m_acceptedKeyDowns;
+}
+
+- (instancetype)initWithCocoaWindow:(QCocoaWindow *)platformWindow
+{
+ if ((self = [super initWithFrame:NSZeroRect])) {
+ m_platformWindow = platformWindow;
m_buttons = Qt::NoButton;
m_acceptedMouseDowns = Qt::NoButton;
m_frameStrutButtons = Qt::NoButton;
m_sendKeyEvent = false;
-#ifndef QT_NO_OPENGL
- m_glContext = 0;
- m_shouldSetGLContextinDrawRect = false;
-#endif
- currentCustomDragTypes = 0;
- m_dontOverrideCtrlLMB = false;
m_sendUpAsRightButton = false;
- m_inputSource = 0;
+ m_inputSource = nil;
m_mouseMoveHelper = [[QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) alloc] initWithView:self];
m_resendKeyEvent = false;
m_scrolling = false;
m_updatingDrag = false;
- m_currentlyInterpretedKeyEvent = 0;
- m_isMenuView = false;
+ m_currentlyInterpretedKeyEvent = nil;
+ m_dontOverrideCtrlLMB = qt_mac_resolveOption(false, platformWindow->window(),
+ "_q_platform_MacDontOverrideCtrlLMB", "QT_MAC_DONT_OVERRIDE_CTRL_LMB");
+ m_trackingArea = nil;
+
self.focusRingType = NSFocusRingTypeNone;
self.cursor = nil;
- m_updateRequested = false;
+ self.wantsLayer = [self wantsLayerHelper];
+
+ // Enable high-DPI OpenGL for retina displays. Enabling has the side
+ // effect that Cocoa will start calling glViewport(0, 0, width, height),
+ // overriding any glViewport calls in application code. This is usually not a
+ // problem, except if the application wants to have a "custom" viewport.
+ // (like the hellogl example)
+ if (m_platformWindow->window()->supportsOpenGL()) {
+ self.wantsBestResolutionOpenGLSurface = qt_mac_resolveOption(YES, m_platformWindow->window(),
+ "_q_mac_wantsBestResolutionOpenGLSurface", "QT_MAC_WANTS_BEST_RESOLUTION_OPENGL_SURFACE");
+ // See also QCocoaGLContext::makeCurrent for software renderer workarounds.
+ }
+
+ [self registerDragTypes];
+
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(textInputContextKeyboardSelectionDidChangeNotification:)
+ name:NSTextInputContextKeyboardSelectionDidChangeNotification
+ object:nil];
}
return self;
}
@@ -163,47 +185,9 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
[[NSNotificationCenter defaultCenter] removeObserver:self];
[m_mouseMoveHelper release];
- delete currentCustomDragTypes;
-
[super dealloc];
}
-- (id)initWithCocoaWindow:(QCocoaWindow *)platformWindow
-{
- self = [self init];
- if (!self)
- return 0;
-
- m_platformWindow = platformWindow;
- m_sendKeyEvent = false;
- m_dontOverrideCtrlLMB = qt_mac_resolveOption(false, platformWindow->window(), "_q_platform_MacDontOverrideCtrlLMB", "QT_MAC_DONT_OVERRIDE_CTRL_LMB");
- m_trackingArea = nil;
-
-#ifdef QT_COCOA_ENABLE_ACCESSIBILITY_INSPECTOR
- // prevent rift in space-time continuum, disable
- // accessibility for the accessibility inspector's windows.
- static bool skipAccessibilityForInspectorWindows = false;
- if (!skipAccessibilityForInspectorWindows) {
-
- // m_accessibleRoot = window->accessibleRoot();
-
- AccessibilityInspector *inspector = new AccessibilityInspector(window);
- skipAccessibilityForInspectorWindows = true;
- inspector->inspectWindow(window);
- skipAccessibilityForInspectorWindows = false;
- }
-#endif
-
- [self registerDragTypes];
-
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(textInputContextKeyboardSelectionDidChangeNotification:)
- name:NSTextInputContextKeyboardSelectionDidChangeNotification
- object:nil];
-
- return self;
-}
-
- (NSString *)description
{
NSMutableString *description = [NSMutableString stringWithString:[super description]];
@@ -220,33 +204,18 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
return description;
}
-#ifndef QT_NO_OPENGL
-- (void) setQCocoaGLContext:(QCocoaGLContext *)context
-{
- m_glContext = context;
- [m_glContext->nsOpenGLContext() setView:self];
- if (![m_glContext->nsOpenGLContext() view]) {
- //was unable to set view
- m_shouldSetGLContextinDrawRect = true;
- }
-}
-#endif
-
- (void)viewDidMoveToSuperview
{
if (!m_platformWindow)
return;
- if (!(m_platformWindow->m_viewIsToBeEmbedded))
+ if (!m_platformWindow->isEmbedded())
return;
if ([self superview]) {
- m_platformWindow->m_viewIsEmbedded = true;
QWindowSystemInterface::handleGeometryChange(m_platformWindow->window(), m_platformWindow->geometry());
[self setNeedsDisplay:YES];
QWindowSystemInterface::flushWindowSystemEvents();
- } else {
- m_platformWindow->m_viewIsEmbedded = false;
}
}
@@ -268,15 +237,6 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
return focusWindow;
}
-- (void)textInputContextKeyboardSelectionDidChangeNotification : (NSNotification *) textInputContextKeyboardSelectionDidChangeNotification
-{
- Q_UNUSED(textInputContextKeyboardSelectionDidChangeNotification)
- if (([NSApp keyWindow] == [self window]) && [[self window] firstResponder] == self) {
- QCocoaInputContext *ic = qobject_cast<QCocoaInputContext *>(QCocoaIntegration::instance()->inputContext());
- ic->updateLocale();
- }
-}
-
- (void)viewDidHide
{
if (!m_platformWindow->isExposed())
@@ -294,107 +254,6 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
[super removeFromSuperview];
}
-- (BOOL) isOpaque
-{
- if (!m_platformWindow)
- return true;
- return m_platformWindow->isOpaque();
-}
-
-- (void)requestUpdate
-{
- if (self.needsDisplay) {
- // If the view already has needsDisplay set it means that there may be code waiting for
- // a real expose event, so we can't issue setNeedsDisplay now as a way to trigger an
- // update request. We will re-trigger requestUpdate from drawRect.
- return;
- }
-
- [self setNeedsDisplay:YES];
- m_updateRequested = true;
-}
-
-- (void)setNeedsDisplayInRect:(NSRect)rect
-{
- [super setNeedsDisplayInRect:rect];
- m_updateRequested = false;
-}
-
-- (void)drawRect:(NSRect)dirtyRect
-{
- Q_UNUSED(dirtyRect);
-
- 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();
-
- qCDebug(lcQpaCocoaDrawing) << "[QNSView drawRect:]" << m_platformWindow->window() << exposedRegion;
- [self updateRegion:exposedRegion];
-}
-
-- (void)updateRegion:(QRegion)dirtyRegion
-{
-#ifndef QT_NO_OPENGL
- if (m_glContext && m_shouldSetGLContextinDrawRect) {
- [m_glContext->nsOpenGLContext() setView:self];
- m_shouldSetGLContextinDrawRect = false;
- }
-#endif
-
- QWindowPrivate *windowPrivate = qt_window_private(m_platformWindow->window());
-
- if (m_updateRequested) {
- Q_ASSERT(windowPrivate->updateRequestPending);
- qCDebug(lcQpaCocoaWindow) << "Delivering update request to" << m_platformWindow->window();
- windowPrivate->deliverUpdateRequest();
- m_updateRequested = false;
- } else {
- m_platformWindow->handleExposeEvent(dirtyRegion);
- }
-
- if (m_updateRequested && windowPrivate->updateRequestPending) {
- // A call to QWindow::requestUpdate was issued during event delivery above,
- // but AppKit will reset the needsDisplay state of the view after completing
- // the current display cycle, so we need to defer the request to redisplay.
- // FIXME: Perhaps this should be a trigger to enable CADisplayLink?
- qCDebug(lcQpaCocoaDrawing) << "[QNSView drawRect:] issuing deferred setNeedsDisplay due to pending update request";
- dispatch_async(dispatch_get_main_queue (), ^{ [self requestUpdate]; });
- }
-}
-
-- (BOOL)wantsUpdateLayer
-{
- return YES;
-}
-
-- (void)updateLayer
-{
- if (!m_platformWindow)
- return;
-
- qCDebug(lcQpaCocoaDrawing) << "[QNSView updateLayer]" << m_platformWindow->window();
-
- // FIXME: Find out if there's a way to resolve the dirty rect like in drawRect:
- [self updateRegion:QRectF::fromCGRect(self.bounds).toRect()];
-}
-
-- (void)viewDidChangeBackingProperties
-{
- if (self.layer)
- self.layer.contentsScale = self.window.backingScaleFactor;
-}
-
-- (BOOL)isFlipped
-{
- return YES;
-}
-
- (BOOL)isTransparentForUserInput
{
return m_platformWindow->window() &&
@@ -407,7 +266,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
return NO;
if ([self isTransparentForUserInput])
return NO;
- if (!m_platformWindow->windowIsPopupType() && !m_isMenuView)
+ if (!m_platformWindow->windowIsPopupType())
QWindowSystemInterface::handleWindowActivated([self topLevelWindow]);
return YES;
}
@@ -416,8 +275,6 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
{
if (!m_platformWindow)
return NO;
- if (m_isMenuView)
- return NO;
if (m_platformWindow->shouldRefuseKeyWindowAndFirstResponder())
return NO;
if ([self isTransparentForUserInput])
@@ -427,16 +284,6 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
return YES;
}
-- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
-{
- Q_UNUSED(theEvent)
- if (!m_platformWindow)
- return NO;
- if ([self isTransparentForUserInput])
- return NO;
- return YES;
-}
-
- (NSView *)hitTest:(NSPoint)aPoint
{
NSView *candidate = [super hitTest:aPoint];
@@ -476,1611 +323,22 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
*qtScreenPoint = QCocoaScreen::mapFromNative(mouseLocation);
}
-- (void)resetMouseButtons
-{
- m_buttons = Qt::NoButton;
- m_frameStrutButtons = Qt::NoButton;
-}
-
-- (NSPoint) screenMousePoint:(NSEvent *)theEvent
-{
- NSPoint screenPoint;
- if (theEvent) {
- NSPoint windowPoint = [theEvent locationInWindow];
- if (qIsNaN(windowPoint.x) || qIsNaN(windowPoint.y)) {
- screenPoint = [NSEvent mouseLocation];
- } else {
- NSRect screenRect = [[theEvent window] convertRectToScreen:NSMakeRect(windowPoint.x, windowPoint.y, 1, 1)];
- screenPoint = screenRect.origin;
- }
- } else {
- screenPoint = [NSEvent mouseLocation];
- }
- 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->m_windowFlags.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);
-
- Qt::KeyboardModifiers keyboardModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]];
- QWindowSystemInterface::handleMouseEvent(targetView->m_platformWindow->window(), timestamp, qtWindowPoint, qtScreenPoint,
- m_buttons, keyboardModifiers, Qt::MouseEventNotSynthesized);
-}
-
-- (void)handleFrameStrutMouseEvent:(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)
- return;
-
- NSEventType ty = [theEvent type];
- switch (ty) {
- case NSLeftMouseDown:
- m_frameStrutButtons |= Qt::LeftButton;
- break;
- case NSLeftMouseUp:
- m_frameStrutButtons &= ~Qt::LeftButton;
- break;
- case NSRightMouseDown:
- m_frameStrutButtons |= Qt::RightButton;
- break;
- case NSLeftMouseDragged:
- m_frameStrutButtons |= Qt::LeftButton;
- break;
- case NSRightMouseDragged:
- m_frameStrutButtons |= Qt::RightButton;
- break;
- case NSRightMouseUp:
- m_frameStrutButtons &= ~Qt::RightButton;
- break;
- case NSOtherMouseDown:
- m_frameStrutButtons |= cocoaButton2QtButton([theEvent buttonNumber]);
- break;
- case NSOtherMouseUp:
- m_frameStrutButtons &= ~cocoaButton2QtButton([theEvent buttonNumber]);
- default:
- break;
- }
-
- NSWindow *window = [self window];
- NSPoint windowPoint = [theEvent locationInWindow];
-
- int windowScreenY = [window frame].origin.y + [window frame].size.height;
- NSPoint windowCoord = [self convertPoint:[self frame].origin toView:nil];
- int viewScreenY = [window convertRectToScreen:NSMakeRect(windowCoord.x, windowCoord.y, 0, 0)].origin.y;
- int titleBarHeight = windowScreenY - viewScreenY;
-
- NSPoint nsViewPoint = [self convertPoint: windowPoint fromView: nil];
- QPoint qtWindowPoint = QPoint(nsViewPoint.x, titleBarHeight + nsViewPoint.y);
- NSPoint screenPoint = [window convertRectToScreen:NSMakeRect(windowPoint.x, windowPoint.y, 0, 0)].origin;
- QPoint qtScreenPoint = QCocoaScreen::mapFromNative(screenPoint).toPoint();
-
- ulong timestamp = [theEvent timestamp] * 1000;
- QWindowSystemInterface::handleFrameStrutMouseEvent(m_platformWindow->window(), timestamp, qtWindowPoint, qtScreenPoint, m_frameStrutButtons);
-}
-
-- (bool)handleMouseDownEvent:(NSEvent *)theEvent withButton:(int)buttonNumber
-{
- if ([self isTransparentForUserInput])
- return false;
-
- Qt::MouseButton button = cocoaButton2QtButton(buttonNumber);
-
- QPointF qtWindowPoint;
- QPointF qtScreenPoint;
- [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
- Q_UNUSED(qtScreenPoint);
-
- // Maintain masked state for the button for use by MouseDragged and MouseUp.
- QRegion mask = m_platformWindow->window()->mask();
- const bool masked = !mask.isEmpty() && !mask.contains(qtWindowPoint.toPoint());
- if (masked)
- m_acceptedMouseDowns &= ~button;
- else
- m_acceptedMouseDowns |= button;
-
- // Forward masked out events to the next responder
- if (masked)
- return false;
-
- m_buttons |= button;
-
- [self handleMouseEvent:theEvent];
- return true;
-}
-
-- (bool)handleMouseDraggedEvent:(NSEvent *)theEvent withButton:(int)buttonNumber
-{
- if ([self isTransparentForUserInput])
- return false;
-
- Qt::MouseButton button = cocoaButton2QtButton(buttonNumber);
-
- // Forward the event to the next responder if Qt did not accept the
- // corresponding mouse down for this button
- if (!(m_acceptedMouseDowns & button) == button)
- return false;
-
- [self handleMouseEvent:theEvent];
- return true;
-}
-
-- (bool)handleMouseUpEvent:(NSEvent *)theEvent withButton:(int)buttonNumber
-{
- if ([self isTransparentForUserInput])
- return false;
-
- Qt::MouseButton button = cocoaButton2QtButton(buttonNumber);
-
- // Forward the event to the next responder if Qt did not accept the
- // corresponding mouse down for this button
- if (!(m_acceptedMouseDowns & button) == button)
- return false;
-
- if (m_sendUpAsRightButton && button == Qt::LeftButton)
- button = Qt::RightButton;
- if (button == Qt::RightButton)
- m_sendUpAsRightButton = false;
-
- m_buttons &= ~button;
-
- [self handleMouseEvent:theEvent];
- return true;
-}
-
-- (void)mouseDown:(NSEvent *)theEvent
-{
- if ([self isTransparentForUserInput])
- 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) {
- Qt::WindowType type = QCocoaIntegration::instance()->activePopupWindow()->window()->type();
- while (QCocoaWindow *popup = QCocoaIntegration::instance()->popPopupWindow()) {
- 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)
- return;
- }
- }
-
- QPointF qtWindowPoint;
- QPointF qtScreenPoint;
- [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
- Q_UNUSED(qtScreenPoint);
-
- QRegion mask = m_platformWindow->window()->mask();
- const bool masked = !mask.isEmpty() && !mask.contains(qtWindowPoint.toPoint());
- // Maintain masked state for the button for use by MouseDragged and Up.
- if (masked)
- m_acceptedMouseDowns &= ~Qt::LeftButton;
- else
- m_acceptedMouseDowns |= Qt::LeftButton;
-
- // Forward masked out events to the next responder
- if (masked) {
- [super mouseDown:theEvent];
- 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;
- }
- [self handleMouseEvent:theEvent];
- }
-}
-
-- (void)mouseDragged:(NSEvent *)theEvent
-{
- const bool accepted = [self handleMouseDraggedEvent:theEvent withButton:[theEvent buttonNumber]];
- if (!accepted)
- [super mouseDragged:theEvent];
-}
-
-- (void)mouseUp:(NSEvent *)theEvent
-{
- const bool accepted = [self handleMouseUpEvent:theEvent withButton:[theEvent buttonNumber]];
- if (!accepted)
- [super mouseUp:theEvent];
-}
-
-- (void)rightMouseDown:(NSEvent *)theEvent
-{
- // Wacom tablet might not return the correct button number for NSEvent buttonNumber
- // on right clicks. Decide here that the button is the "right" button and forward
- // the button number to the mouse (and tablet) handler.
- const bool accepted = [self handleMouseDownEvent:theEvent withButton:1];
- if (!accepted)
- [super rightMouseDown:theEvent];
-}
-
-- (void)rightMouseDragged:(NSEvent *)theEvent
-{
- const bool accepted = [self handleMouseDraggedEvent:theEvent withButton:1];
- if (!accepted)
- [super rightMouseDragged:theEvent];
-}
-
-- (void)rightMouseUp:(NSEvent *)theEvent
-{
- const bool accepted = [self handleMouseUpEvent:theEvent withButton:1];
- if (!accepted)
- [super rightMouseUp:theEvent];
-}
-
-- (void)otherMouseDown:(NSEvent *)theEvent
-{
- const bool accepted = [self handleMouseDownEvent:theEvent withButton:[theEvent buttonNumber]];
- if (!accepted)
- [super otherMouseDown:theEvent];
-}
-
-- (void)otherMouseDragged:(NSEvent *)theEvent
-{
- const bool accepted = [self handleMouseDraggedEvent:theEvent withButton:[theEvent buttonNumber]];
- if (!accepted)
- [super otherMouseDragged:theEvent];
-}
-
-- (void)otherMouseUp:(NSEvent *)theEvent
-{
- const bool accepted = [self handleMouseUpEvent:theEvent withButton:[theEvent buttonNumber]];
- if (!accepted)
- [super otherMouseUp:theEvent];
-}
-
-- (void)updateTrackingAreas
-{
- [super updateTrackingAreas];
-
- QMacAutoReleasePool pool;
-
- // NSTrackingInVisibleRect keeps care of updating once the tracking is set up, so bail out early
- if (m_trackingArea && [[self trackingAreas] containsObject:m_trackingArea])
- return;
-
- // Ideally, we shouldn't have NSTrackingMouseMoved events included below, it should
- // only be turned on if mouseTracking, hover is on or a tool tip is set.
- // Unfortunately, Qt will send "tooltip" events on mouse moves, so we need to
- // turn it on in ALL case. That means EVERY QWindow gets to pay the cost of
- // mouse moves delivered to it (Apple recommends keeping it OFF because there
- // is a performance hit). So it goes.
- NSUInteger trackingOptions = NSTrackingMouseEnteredAndExited | NSTrackingActiveInActiveApp
- | NSTrackingInVisibleRect | NSTrackingMouseMoved | NSTrackingCursorUpdate;
- [m_trackingArea release];
- m_trackingArea = [[NSTrackingArea alloc] initWithRect:[self frame]
- options:trackingOptions
- owner:m_mouseMoveHelper
- userInfo:nil];
- [self addTrackingArea:m_trackingArea];
-}
-
-- (void)cursorUpdate:(NSEvent *)theEvent
-{
- qCDebug(lcQpaCocoaMouse) << "[QNSView cursorUpdate:]" << self.cursor;
-
- // 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 (self.cursor)
- [self.cursor set];
- else
- [super cursorUpdate:theEvent];
-}
-
-- (void)mouseMovedImpl:(NSEvent *)theEvent
-{
- 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;
- }
- }
-
- // 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())
- return;
-
- [self handleMouseEvent: theEvent];
-}
-
-- (void)mouseEnteredImpl:(NSEvent *)theEvent
-{
- Q_UNUSED(theEvent)
- if (!m_platformWindow)
- return;
-
- m_platformWindow->m_windowUnderMouse = true;
-
- if ([self isTransparentForUserInput])
- return;
-
- // Top-level windows generate enter events for sub-windows.
- if (!m_platformWindow->isContentView())
- return;
-
- QPointF windowPoint;
- QPointF screenPoint;
- [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- m_platformWindow->m_enterLeaveTargetWindow = m_platformWindow->childWindowAt(windowPoint.toPoint());
- QWindowSystemInterface::handleEnterEvent(m_platformWindow->m_enterLeaveTargetWindow, windowPoint, screenPoint);
-}
-
-- (void)mouseExitedImpl:(NSEvent *)theEvent
-{
- Q_UNUSED(theEvent);
- if (!m_platformWindow)
- return;
-
- m_platformWindow->m_windowUnderMouse = false;
-
- if ([self isTransparentForUserInput])
- return;
-
- // Top-level windows generate leave events for sub-windows.
- if (!m_platformWindow->isContentView())
- return;
-
- QWindowSystemInterface::handleLeaveEvent(m_platformWindow->m_enterLeaveTargetWindow);
- m_platformWindow->m_enterLeaveTargetWindow = 0;
-}
-
-#ifndef QT_NO_TABLETEVENT
-struct QCocoaTabletDeviceData
-{
- QTabletEvent::TabletDevice device;
- QTabletEvent::PointerType pointerType;
- uint capabilityMask;
- qint64 uid;
-};
-
-typedef QHash<uint, QCocoaTabletDeviceData> QCocoaTabletDeviceDataHash;
-Q_GLOBAL_STATIC(QCocoaTabletDeviceDataHash, tabletDeviceDataHash)
-
-- (bool)handleTabletEvent: (NSEvent *)theEvent
-{
- static bool ignoreButtonMapping = qEnvironmentVariableIsSet("QT_MAC_TABLET_IGNORE_BUTTON_MAPPING");
-
- if (!m_platformWindow)
- return false;
-
- NSEventType eventType = [theEvent type];
- if (eventType != NSTabletPoint && [theEvent subtype] != NSTabletPointEventSubtype)
- return false; // Not a tablet event.
-
- ulong timestamp = [theEvent timestamp] * 1000;
-
- QPointF windowPoint;
- 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;
- }
- const QCocoaTabletDeviceData &deviceData = tabletDeviceDataHash->value(deviceId);
-
- bool down = (eventType != NSMouseMoved);
-
- qreal pressure;
- if (down) {
- pressure = [theEvent pressure];
- } else {
- pressure = 0.0;
- }
-
- NSPoint tilt = [theEvent tilt];
- int xTilt = qRound(tilt.x * 60.0);
- int yTilt = qRound(tilt.y * -60.0);
- qreal tangentialPressure = 0;
- qreal rotation = 0;
- int z = 0;
- if (deviceData.capabilityMask & 0x0200)
- z = [theEvent absoluteZ];
-
- if (deviceData.capabilityMask & 0x0800)
- 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::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);
- return true;
-}
-
-- (void)tabletPoint:(NSEvent *)theEvent
-{
- if ([self isTransparentForUserInput])
- return [super tabletPoint:theEvent];
-
- [self handleTabletEvent: theEvent];
-}
-
-static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
-{
- 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.
- // I'm not sure how to handle it for consumer devices, but I'll test that in a bit.
- 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;
- } 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 NSUnknownPointingDevice:
- default:
- deviceData.pointerType = QTabletEvent::UnknownPointer;
- break;
- case NSPenPointingDevice:
- deviceData.pointerType = QTabletEvent::Pen;
- break;
- case NSCursorPointingDevice:
- deviceData.pointerType = QTabletEvent::Cursor;
- break;
- case NSEraserPointingDevice:
- deviceData.pointerType = QTabletEvent::Eraser;
- break;
- }
-
- deviceData.device = wacomTabletDevice(theEvent);
-
- // 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);
- }
-
- qCDebug(lcQpaTablet, "proximity change on tablet %d: current tool %d type %d unique ID %lld",
- deviceId, deviceData.device, deviceData.pointerType, deviceData.uid);
+@end
- if (entering) {
- QWindowSystemInterface::handleTabletEnterProximityEvent(timestamp, deviceData.device, deviceData.pointerType, deviceData.uid);
- } else {
- QWindowSystemInterface::handleTabletLeaveProximityEvent(timestamp, deviceData.device, deviceData.pointerType, deviceData.uid);
- }
-}
+#include "qnsview_drawing.mm"
+#include "qnsview_mouse.mm"
+#include "qnsview_touch.mm"
+#include "qnsview_gestures.mm"
+#include "qnsview_tablet.mm"
+#include "qnsview_dragging.mm"
+#include "qnsview_keys.mm"
+#include "qnsview_complextext.mm"
+#include "qnsview_menus.mm"
+#ifndef QT_NO_ACCESSIBILITY
+#include "qnsview_accessibility.mm"
#endif
-- (bool)shouldSendSingleTouch
-{
- if (!m_platformWindow)
- return true;
-
- // QtWidgets expects single-point touch events, QtDeclarative does not.
- // Until there is an API we solve this by looking at the window class type.
- return m_platformWindow->window()->inherits("QWidgetWindow");
-}
-
-- (void)touchesBeganWithEvent:(NSEvent *)event
-{
- if (!m_platformWindow)
- return;
-
- const NSTimeInterval timestamp = [event timestamp];
- const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
- qCDebug(lcQpaTouch) << "touchesBeganWithEvent" << points << "from device" << hex << [event deviceID];
- QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
-}
-
-- (void)touchesMovedWithEvent:(NSEvent *)event
-{
- if (!m_platformWindow)
- return;
-
- const NSTimeInterval timestamp = [event timestamp];
- const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
- qCDebug(lcQpaTouch) << "touchesMovedWithEvent" << points << "from device" << hex << [event deviceID];
- QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
-}
-
-- (void)touchesEndedWithEvent:(NSEvent *)event
-{
- if (!m_platformWindow)
- return;
-
- const NSTimeInterval timestamp = [event timestamp];
- const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
- qCDebug(lcQpaTouch) << "touchesEndedWithEvent" << points << "from device" << hex << [event deviceID];
- QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
-}
-
-- (void)touchesCancelledWithEvent:(NSEvent *)event
-{
- if (!m_platformWindow)
- return;
-
- const NSTimeInterval timestamp = [event timestamp];
- const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
- qCDebug(lcQpaTouch) << "touchesCancelledWithEvent" << points << "from device" << hex << [event deviceID];
- QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
-}
-
-#ifndef QT_NO_GESTURES
-
-- (bool)handleGestureAsBeginEnd:(NSEvent *)event
-{
- if (QOperatingSystemVersion::current() < QOperatingSystemVersion::OSXElCapitan)
- return false;
-
- if ([event phase] == NSEventPhaseBegan) {
- [self beginGestureWithEvent:event];
- return true;
- }
-
- if ([event phase] == NSEventPhaseEnded) {
- [self endGestureWithEvent:event];
- return true;
- }
-
- return false;
-}
-- (void)magnifyWithEvent:(NSEvent *)event
-{
- if (!m_platformWindow)
- return;
-
- if ([self handleGestureAsBeginEnd:event])
- return;
-
- qCDebug(lcQpaGestures) << "magnifyWithEvent" << [event magnification] << "from device" << hex << [event deviceID];
- const NSTimeInterval timestamp = [event timestamp];
- 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);
-}
-
-- (void)smartMagnifyWithEvent:(NSEvent *)event
-{
- if (!m_platformWindow)
- return;
-
- static bool zoomIn = true;
- qCDebug(lcQpaGestures) << "smartMagnifyWithEvent" << zoomIn << "from device" << hex << [event deviceID];
- const NSTimeInterval timestamp = [event timestamp];
- 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);
- zoomIn = !zoomIn;
-}
-
-- (void)rotateWithEvent:(NSEvent *)event
-{
- if (!m_platformWindow)
- return;
-
- if ([self handleGestureAsBeginEnd:event])
- return;
-
- const NSTimeInterval timestamp = [event timestamp];
- 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);
-}
-
-- (void)swipeWithEvent:(NSEvent *)event
-{
- if (!m_platformWindow)
- return;
-
- qCDebug(lcQpaGestures) << "swipeWithEvent" << [event deltaX] << [event deltaY] << "from device" << hex << [event deviceID];
- const NSTimeInterval timestamp = [event timestamp];
- QPointF windowPoint;
- QPointF screenPoint;
- [self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
-
- qreal angle = 0.0f;
- if ([event deltaX] == 1)
- angle = 180.0f;
- else if ([event deltaX] == -1)
- angle = 0.0f;
- else if ([event deltaY] == 1)
- angle = 90.0f;
- 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);
-}
-
-- (void)beginGestureWithEvent:(NSEvent *)event
-{
- if (!m_platformWindow)
- return;
-
- const NSTimeInterval timestamp = [event timestamp];
- QPointF windowPoint;
- QPointF screenPoint;
- [self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- qCDebug(lcQpaGestures) << "beginGestureWithEvent @" << windowPoint << "from device" << hex << [event deviceID];
- QWindowSystemInterface::handleGestureEvent(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::BeginNativeGesture,
- windowPoint, screenPoint);
-}
-
-- (void)endGestureWithEvent:(NSEvent *)event
-{
- if (!m_platformWindow)
- return;
-
- qCDebug(lcQpaGestures) << "endGestureWithEvent" << "from device" << hex << [event deviceID];
- const NSTimeInterval timestamp = [event timestamp];
- 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);
-}
-#endif // QT_NO_GESTURES
-
-#if QT_CONFIG(wheelevent)
-- (void)scrollWheel:(NSEvent *)theEvent
-{
- if (!m_platformWindow)
- return;
-
- if ([self isTransparentForUserInput])
- return [super scrollWheel:theEvent];
-
- QPoint angleDelta;
- Qt::MouseEventSource source = Qt::MouseEventNotSynthesized;
- if ([theEvent hasPreciseScrollingDeltas]) {
- // The mouse device contains pixel scroll wheel support (Mighty Mouse, Trackpad).
- // 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([theEvent scrollingDeltaX] * pixelsToDegrees);
- angleDelta.setY([theEvent scrollingDeltaY] * pixelsToDegrees);
- source = Qt::MouseEventSynthesizedBySystem;
- } else {
- // Remove acceleration, and use either -120 or 120 as delta:
- angleDelta.setX(qBound(-120, int([theEvent deltaX] * 10000), 120));
- angleDelta.setY(qBound(-120, int([theEvent deltaY] * 10000), 120));
- }
-
- QPoint pixelDelta;
- if ([theEvent hasPreciseScrollingDeltas]) {
- pixelDelta.setX([theEvent scrollingDeltaX]);
- pixelDelta.setY([theEvent scrollingDeltaY]);
- } else {
- // docs: "In the case of !hasPreciseScrollingDeltas, multiply the delta with the line width."
- // scrollingDeltaX seems to return a minimum value of 0.1 in this case, map that to two pixels.
- const CGFloat lineWithEstimate = 20.0;
- pixelDelta.setX([theEvent scrollingDeltaX] * lineWithEstimate);
- pixelDelta.setY([theEvent scrollingDeltaY] * lineWithEstimate);
- }
-
- QPointF qt_windowPoint;
- QPointF qt_screenPoint;
- [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qt_windowPoint andScreenPoint:&qt_screenPoint];
- NSTimeInterval timestamp = [theEvent timestamp];
- ulong qt_timestamp = timestamp * 1000;
-
- // 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
- // flick in order to avoid changing the interpretation of the events
- // mid-stream. One example of this happening would be when pressing cmd
- // 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.
- NSEventPhase momentumPhase = [theEvent momentumPhase];
- if (momentumPhase == NSEventPhaseNone) {
- currentWheelModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]];
- }
-
- NSEventPhase phase = [theEvent phase];
- Qt::ScrollPhase ph = Qt::ScrollUpdate;
-
- // MayBegin is likely to happen. We treat it the same as an actual begin.
- if (phase == NSEventPhaseMayBegin) {
- m_scrolling = true;
- ph = Qt::ScrollBegin;
- } else if (phase == NSEventPhaseBegan) {
- // If MayBegin did not happen, Began is the actual beginning.
- if (!m_scrolling)
- ph = Qt::ScrollBegin;
- m_scrolling = true;
- } else if (phase == NSEventPhaseEnded || phase == NSEventPhaseCancelled ||
- momentumPhase == NSEventPhaseEnded || momentumPhase == NSEventPhaseCancelled) {
- ph = Qt::ScrollEnd;
- m_scrolling = false;
- } else if (phase == NSEventPhaseNone && momentumPhase == NSEventPhaseNone) {
- ph = Qt::NoScrollPhase;
- }
- // "isInverted": natural OS X scrolling, inverted from the Qt/other platform/Jens perspective.
- bool isInverted = [theEvent isDirectionInvertedFromDevice];
-
- qCDebug(lcQpaCocoaMouse) << "scroll wheel @ window pos" << qt_windowPoint << "delta px" << pixelDelta << "angle" << angleDelta << "phase" << ph << (isInverted ? "inverted" : "");
- QWindowSystemInterface::handleWheelEvent(m_platformWindow->window(), qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, currentWheelModifiers, ph, source, isInverted);
-}
-#endif // QT_CONFIG(wheelevent)
-
-- (int) convertKeyCode : (QChar)keyChar
-{
- return qt_mac_cocoaKey2QtKey(keyChar);
-}
-
-+ (Qt::KeyboardModifiers) convertKeyModifiers : (ulong)modifierFlags
-{
- const bool dontSwapCtrlAndMeta = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta);
- Qt::KeyboardModifiers qtMods =Qt::NoModifier;
- if (modifierFlags & NSShiftKeyMask)
- qtMods |= Qt::ShiftModifier;
- if (modifierFlags & NSControlKeyMask)
- qtMods |= dontSwapCtrlAndMeta ? Qt::ControlModifier : Qt::MetaModifier;
- if (modifierFlags & NSAlternateKeyMask)
- qtMods |= Qt::AltModifier;
- if (modifierFlags & NSCommandKeyMask)
- qtMods |= dontSwapCtrlAndMeta ? Qt::MetaModifier : Qt::ControlModifier;
- if (modifierFlags & NSNumericPadKeyMask)
- qtMods |= Qt::KeypadModifier;
- return qtMods;
-}
-
-- (bool)handleKeyEvent:(NSEvent *)nsevent eventType:(int)eventType
-{
- 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];
- }
-
- // 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];
- }
-
- // 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);
-
- 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->m_windowFlags.testFlag(Qt::ToolTip))
- window = popup->window();
- }
-
- if (eventType == QEvent::KeyPress) {
-
- if (m_composingText.isEmpty()) {
- m_sendKeyEvent = !QWindowSystemInterface::handleShortcutEvent(window, timestamp, keyCode,
- modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1);
-
- // Handling a shortcut may result in closing the window
- if (!m_platformWindow)
- 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
- m_currentlyInterpretedKeyEvent = nsevent;
- [self interpretKeyEvents:[NSArray arrayWithObject:nsevent]];
- m_currentlyInterpretedKeyEvent = 0;
- }
- }
- }
- 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();
- }
- m_sendKeyEvent = false;
- m_resendKeyEvent = false;
- return accepted;
-}
-
-- (void)keyDown:(NSEvent *)nsevent
-{
- if ([self isTransparentForUserInput])
- return [super keyDown:nsevent];
-
- const bool accepted = [self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)];
-
- // When Qt is used to implement a plugin for a native application we
- // want to propagate unhandled events to other native views. However,
- // Qt does not always set the accepted state correctly (in particular
- // for return key events), so do this for plugin applications only
- // to prevent incorrect forwarding in the general case.
- const bool shouldPropagate = QCoreApplication::testAttribute(Qt::AA_PluginApplication) && !accepted;
-
- // Track keyDown acceptance/forward state for later acceptance of the keyUp.
- if (!shouldPropagate)
- m_acceptedKeyDowns.insert([nsevent keyCode]);
-
- if (shouldPropagate)
- [super keyDown:nsevent];
-}
-
-- (void)keyUp:(NSEvent *)nsevent
-{
- if ([self isTransparentForUserInput])
- return [super keyUp:nsevent];
-
- const bool keyUpAccepted = [self handleKeyEvent:nsevent eventType:int(QEvent::KeyRelease)];
-
- // Propagate the keyUp if neither Qt accepted it nor the corresponding KeyDown was
- // accepted. Qt text controls wil often not use and ignore keyUp events, but we
- // want to avoid propagating unmatched keyUps.
- const bool keyDownAccepted = m_acceptedKeyDowns.remove([nsevent keyCode]);
- if (!keyUpAccepted && !keyDownAccepted)
- [super keyUp:nsevent];
-}
-
-- (void)cancelOperation:(id)sender
-{
- Q_UNUSED(sender);
-
- NSEvent *currentEvent = [NSApp currentEvent];
- if (!currentEvent || currentEvent.type != NSKeyDown)
- 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)
- 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)];
-}
-
-- (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[] = {
- { NSShiftKeyMask, Qt::Key_Shift },
- { NSControlKeyMask, Qt::Key_Meta },
- { NSCommandKeyMask, Qt::Key_Control },
- { NSAlternateKeyMask, Qt::Key_Alt },
- { NSAlphaShiftKeyMask, 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)
- continue;
-
- Qt::Key qtCode = modifier_key_symbols[i].qt_code;
- 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;
- }
- QWindowSystemInterface::handleKeyEvent(m_platformWindow->window(),
- timestamp,
- (lastKnownModifiers & mac_mask) ? QEvent::KeyRelease : QEvent::KeyPress,
- qtCode,
- qmodifiers ^ [QNSView convertKeyModifiers:mac_mask]);
- }
-}
-
-- (void) insertNewline:(id)sender
-{
- Q_UNUSED(sender);
- m_resendKeyEvent = true;
-}
-
-- (void) doCommandBySelector:(SEL)aSelector
-{
- [self tryToPerform:aSelector with:self];
-}
-
-- (void) insertText:(id)aString replacementRange:(NSRange)replacementRange
-{
- Q_UNUSED(replacementRange)
-
- 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;
- }
-
- 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));
- };
- }
- 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;
- }
- }
- }
-
- m_composingText.clear();
- m_composingFocusObject = nullptr;
-}
-
-- (void) setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
-{
- 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;
- }
- } else {
- // No attributes specified, take only the preedit text.
- preeditString = QString::fromCFString(reinterpret_cast<CFStringRef>(aString));
- }
-
- if (attrs.isEmpty()) {
- QTextCharFormat format;
- format.setFontUnderline(true);
- attrs<<QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
- 0, preeditString.length(), format);
- }
-
- m_composingText = preeditString;
-
- 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;
- }
- }
- }
-}
-
-- (void)cancelComposingText
-{
- if (m_composingText.isEmpty())
- return;
-
- 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);
- }
- }
- }
-
- m_composingText.clear();
- m_composingFocusObject = nullptr;
-}
-
-- (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);
- }
- }
- }
- }
- m_composingText.clear();
- m_composingFocusObject = nullptr;
-}
-
-- (BOOL) hasMarkedText
-{
- return (m_composingText.isEmpty() ? NO: YES);
-}
-
-- (NSAttributedString *) attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
-{
- 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;
-
- QString selectedText = queryEvent.value(Qt::ImCurrentSelection).toString();
- if (selectedText.isEmpty())
- return nil;
-
- 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];
-}
-
-- (NSRange) markedRange
-{
- NSRange range;
- if (!m_composingText.isEmpty()) {
- range.location = 0;
- range.length = m_composingText.length();
- } else {
- range.location = NSNotFound;
- range.length = 0;
- }
- return range;
-}
-
-- (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();
- }
- return selectedRange;
-}
-
-- (NSRect) firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
-{
- Q_UNUSED(aRange)
- Q_UNUSED(actualRange)
- QObject *fo = m_platformWindow->window()->focusObject();
- if (!fo)
- return NSZeroRect;
-
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
- if (!QCoreApplication::sendEvent(fo, &queryEvent))
- return NSZeroRect;
- if (!queryEvent.value(Qt::ImEnabled).toBool())
- return NSZeroRect;
-
- if (!m_platformWindow->window())
- return NSZeroRect;
-
- // The returned rect is always based on the internal cursor.
- QRect mr = qApp->inputMethod()->cursorRectangle().toRect();
- mr.moveBottomLeft(m_platformWindow->window()->mapToGlobal(mr.bottomLeft()));
- return QCocoaScreen::mapToNative(mr);
-}
-
-- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint
-{
- // We don't support cursor movements using mouse while composing.
- Q_UNUSED(aPoint);
- return NSNotFound;
-}
-
-- (NSArray*)validAttributesForMarkedText
-{
- if (!m_platformWindow)
- return nil;
-
- if (m_platformWindow->window() != QGuiApplication::focusWindow())
- return nil;
-
- QObject *fo = m_platformWindow->window()->focusObject();
- if (!fo)
- return nil;
-
- QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
- if (!QCoreApplication::sendEvent(fo, &queryEvent))
- return nil;
- if (!queryEvent.value(Qt::ImEnabled).toBool())
- return nil;
-
- // Support only underline color/style.
- return [NSArray arrayWithObjects:NSUnderlineColorAttributeName,
- NSUnderlineStyleAttributeName, nil];
-}
-
--(void)registerDragTypes
-{
- QMacAutoReleasePool pool;
- QStringList customTypes = qt_mac_enabledDraggedTypes();
- if (currentCustomDragTypes == 0 || *currentCustomDragTypes != customTypes) {
- if (currentCustomDragTypes == 0)
- currentCustomDragTypes = new QStringList();
- *currentCustomDragTypes = customTypes;
- const NSString* mimeTypeGeneric = @"com.trolltech.qt.MimeTypeName";
- NSMutableArray *supportedTypes = [NSMutableArray arrayWithObjects:NSColorPboardType,
- NSFilenamesPboardType, NSStringPboardType,
- NSFilenamesPboardType, NSPostScriptPboardType, NSTIFFPboardType,
- NSRTFPboardType, NSTabularTextPboardType, NSFontPboardType,
- NSRulerPboardType, NSFileContentsPboardType, NSColorPboardType,
- NSRTFDPboardType, NSHTMLPboardType,
- NSURLPboardType, NSPDFPboardType, NSVCardPboardType,
- NSFilesPromisePboardType, NSInkTextPboardType,
- NSMultipleTextSelectionPboardType, mimeTypeGeneric, nil];
- // Add custom types supported by the application.
- for (int i = 0; i < customTypes.size(); i++) {
- [supportedTypes addObject:customTypes[i].toNSString()];
- }
- [self registerForDraggedTypes:supportedTypes];
- }
-}
-
-static QWindow *findEventTargetWindow(QWindow *candidate)
-{
- while (candidate) {
- if (!(candidate->flags() & Qt::WindowTransparentForInput))
- return candidate;
- candidate = candidate->parent();
- }
- return candidate;
-}
-
-static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint point)
-{
- return target->mapFromGlobal(source->mapToGlobal(point));
-}
-
-- (NSDragOperation)draggingSession:(NSDraggingSession *)session
- sourceOperationMaskForDraggingContext:(NSDraggingContext)context
-{
- Q_UNUSED(session);
- Q_UNUSED(context);
- QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
- return qt_mac_mapDropActions(nativeDrag->currentDrag()->supportedActions());
-}
-
-- (BOOL)ignoreModifierKeysForDraggingSession:(NSDraggingSession *)session
-{
- Q_UNUSED(session);
- // According to the "Dragging Sources" chapter on Cocoa DnD Programming
- // (https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/DragandDrop/Concepts/dragsource.html),
- // if the control, option, or command key is pressed, the source’s
- // operation mask is filtered to only contain a reduced set of operations.
- //
- // 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;
-}
-
-- (BOOL)wantsPeriodicDraggingUpdates
-{
- // From the documentation:
- //
- // "If the destination returns NO, these messages are sent only when the mouse moves
- // or a modifier flag changes. Otherwise the destination gets the default behavior,
- // where it receives periodic dragging-updated messages even if nothing changes."
- //
- // We do not want these constant drag update events while mouse is stationary,
- // since we do all animations (autoscroll) with timers.
- return NO;
-}
-
-
-- (BOOL)wantsPeriodicDraggingUpdates:(void *)dummy
-{
- // This method never gets called. It's a workaround for Apple's
- // bug: they first respondsToSelector : @selector(wantsPeriodicDraggingUpdates:)
- // (note ':') and then call -wantsPeriodicDraggingUpdate (without colon).
- // So, let's make them happy.
- Q_UNUSED(dummy);
-
- return NO;
-}
-
-- (void)updateCursorFromDragResponse:(QPlatformDragQtResponse)response drag:(QCocoaDrag *)drag
-{
- const QPixmap pixmapCursor = drag->currentDrag()->dragCursor(response.acceptedAction());
- NSCursor *nativeCursor = nil;
-
- if (pixmapCursor.isNull()) {
- switch (response.acceptedAction()) {
- case Qt::CopyAction:
- nativeCursor = [NSCursor dragCopyCursor];
- break;
- case Qt::LinkAction:
- nativeCursor = [NSCursor dragLinkCursor];
- break;
- case Qt::IgnoreAction:
- // Uncomment the next lines if forbiden cursor wanted on non droppable targets.
- /*nativeCursor = [NSCursor operationNotAllowedCursor];
- break;*/
- case Qt::MoveAction:
- default:
- nativeCursor = [NSCursor arrowCursor];
- break;
- }
- }
- else {
- NSImage *nsimage = qt_mac_create_nsimage(pixmapCursor);
- nsimage.size = NSSizeFromCGSize((pixmapCursor.size() / pixmapCursor.devicePixelRatioF()).toCGSize());
- nativeCursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSZeroPoint];
- [nsimage release];
- }
-
- // change the cursor
- [nativeCursor set];
-
- // Make sure the cursor is updated correctly if the mouse does not move and window is under cursor
- // by creating a fake move event, unless on 10.14 and later where doing so will trigger a security
- // warning dialog. FIXME: Find a way to update the cursor without fake mouse events.
- if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave)
- return;
-
- if (m_updatingDrag)
- return;
-
- const QPoint mousePos(QCursor::pos());
- CGEventRef moveEvent(CGEventCreateMouseEvent(
- NULL, kCGEventMouseMoved,
- CGPointMake(mousePos.x(), mousePos.y()),
- kCGMouseButtonLeft // ignored
- ));
- CGEventPost(kCGHIDEventTap, moveEvent);
- CFRelease(moveEvent);
-}
-
-- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
-{
- return [self handleDrag : sender];
-}
-
-- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
-{
- m_updatingDrag = true;
- const NSDragOperation ret([self handleDrag : sender]);
- m_updatingDrag = false;
-
- return ret;
-}
-
-// Sends drag update to Qt, return the action
-- (NSDragOperation)handleDrag:(id <NSDraggingInfo>)sender
-{
- if (!m_platformWindow)
- return NSDragOperationNone;
-
- NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil];
- QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
- Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]);
-
- QWindow *target = findEventTargetWindow(m_platformWindow->window());
- if (!target)
- return NSDragOperationNone;
-
- // update these so selecting move/copy/link works
- QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers: [[NSApp currentEvent] modifierFlags]];
-
- QPlatformDragQtResponse response(false, Qt::IgnoreAction, QRect());
- QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
- if (nativeDrag->currentDrag()) {
- // The drag was started from within the application
- response = QWindowSystemInterface::handleDrag(target, nativeDrag->dragMimeData(), mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint), qtAllowed);
- [self updateCursorFromDragResponse:response drag:nativeDrag];
- } else {
- QCocoaDropData mimeData([sender draggingPasteboard]);
- response = QWindowSystemInterface::handleDrag(target, &mimeData, mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint), qtAllowed);
- }
-
- return qt_mac_mapDropAction(response.acceptedAction());
-}
-
-- (void)draggingExited:(id <NSDraggingInfo>)sender
-{
- if (!m_platformWindow)
- return;
-
- QWindow *target = findEventTargetWindow(m_platformWindow->window());
- if (!target)
- return;
-
- NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil];
- QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
-
- // Send 0 mime data to indicate drag exit
- QWindowSystemInterface::handleDrag(target, 0, mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint), Qt::IgnoreAction);
-}
-
-// called on drop, send the drop to Qt and return if it was accepted.
-- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
-{
- if (!m_platformWindow)
- return false;
-
- QWindow *target = findEventTargetWindow(m_platformWindow->window());
- if (!target)
- return false;
-
- NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil];
- QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
- Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]);
-
- QPlatformDropQtResponse response(false, Qt::IgnoreAction);
- QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
- if (nativeDrag->currentDrag()) {
- // The drag was started from within the application
- response = QWindowSystemInterface::handleDrop(target, nativeDrag->dragMimeData(), mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint), qtAllowed);
- } else {
- QCocoaDropData mimeData([sender draggingPasteboard]);
- response = QWindowSystemInterface::handleDrop(target, &mimeData, mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint), qtAllowed);
- }
- if (response.isAccepted()) {
- QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
- nativeDrag->setAcceptedAction(response.acceptedAction());
- }
- return response.isAccepted();
-}
-
-- (void)draggingSession:(NSDraggingSession *)session
- endedAtPoint:(NSPoint)screenPoint
- operation:(NSDragOperation)operation
-{
- Q_UNUSED(session);
- Q_UNUSED(operation);
-
- if (!m_platformWindow)
- return;
-
- QWindow *target = findEventTargetWindow(m_platformWindow->window());
- if (!target)
- return;
-
- // keep our state, and QGuiApplication state (buttons member) in-sync,
- // or future mouse events will be processed incorrectly
- NSUInteger pmb = [NSEvent pressedMouseButtons];
- for (int buttonNumber = 0; buttonNumber < 32; buttonNumber++) { // see cocoaButton2QtButton() for the 32 value
- if (!(pmb & (1 << buttonNumber)))
- m_buttons &= ~cocoaButton2QtButton(buttonNumber);
- }
-
- NSPoint windowPoint = [self.window convertRectFromScreen:NSMakeRect(screenPoint.x, screenPoint.y, 1, 1)].origin;
- NSPoint nsViewPoint = [self convertPoint: windowPoint fromView: nil]; // NSView/QWindow coordinates
- QPoint qtWindowPoint(nsViewPoint.x, nsViewPoint.y);
- QPoint qtScreenPoint = QCocoaScreen::mapFromNative(screenPoint).toPoint();
-
- QWindowSystemInterface::handleMouseEvent(target, mapWindowCoordinates(m_platformWindow->window(), target, qtWindowPoint), qtScreenPoint, m_buttons);
-}
-
-@end
+// -----------------------------------------------------
@implementation QT_MANGLE_NAMESPACE(QNSView) (QtExtras)
@@ -2089,9 +347,4 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
return m_platformWindow.data();;
}
-- (BOOL)isMenuView
-{
- return m_isMenuView;
-}
-
@end
diff --git a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm b/src/plugins/platforms/cocoa/qnsview_accessibility.mm
index 645a93edf7..32ec0b74d4 100644
--- a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qnsview_accessibility.mm
@@ -37,57 +37,54 @@
**
****************************************************************************/
-#include "qnsview.h"
-#include "qcocoahelpers.h"
+// This file is included from qnsview.mm, and only used to organize the code
+
#include "qcocoaaccessibility.h"
#include "qcocoaaccessibilityelement.h"
#include "qcocoaintegration.h"
#include <QtGui/qaccessible.h>
-#include <QtCore/QDebug>
#import <AppKit/NSAccessibility.h>
-#ifndef QT_NO_ACCESSIBILITY
-
-@implementation QNSView (QNSViewAccessibility)
+@implementation QT_MANGLE_NAMESPACE(QNSView) (Accessibility)
-- (id)childAccessibleElement {
- if (m_platformWindow.isNull())
+- (id)childAccessibleElement
+{
+ QCocoaWindow *platformWindow = self.platformWindow;
+ if (!platformWindow || !platformWindow->window()->accessibleRoot())
return nil;
- if (!m_platformWindow->window()->accessibleRoot())
- return nil;
-
- QAccessible::Id childId = QAccessible::uniqueId(m_platformWindow->window()->accessibleRoot());
- return [QMacAccessibilityElement elementWithId: childId];
+ QAccessible::Id childId = QAccessible::uniqueId(platformWindow->window()->accessibleRoot());
+ return [QMacAccessibilityElement elementWithId:childId];
}
// The QNSView is a container that the user does not interact directly with:
// Remove it from the user-visible accessibility tree.
-- (BOOL)accessibilityIsIgnored {
+- (BOOL)accessibilityIsIgnored
+{
return YES;
}
-- (id)accessibilityAttributeValue:(NSString *)attribute {
+- (id)accessibilityAttributeValue:(NSString *)attribute
+{
// activate accessibility updates
QCocoaIntegration::instance()->accessibility()->setActive(true);
- if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
+ if ([attribute isEqualToString:NSAccessibilityChildrenAttribute])
return NSAccessibilityUnignoredChildrenForOnlyChild([self childAccessibleElement]);
- } else {
+ else
return [super accessibilityAttributeValue:attribute];
- }
}
-- (id)accessibilityHitTest:(NSPoint)point {
- return [[self childAccessibleElement] accessibilityHitTest: point];
+- (id)accessibilityHitTest:(NSPoint)point
+{
+ return [[self childAccessibleElement] accessibilityHitTest:point];
}
-- (id)accessibilityFocusedUIElement {
+- (id)accessibilityFocusedUIElement
+{
return [[self childAccessibleElement] accessibilityFocusedUIElement];
}
@end
-
-#endif // QT_NO_ACCESSIBILITY
diff --git a/src/plugins/platforms/cocoa/qnsview_complextext.mm b/src/plugins/platforms/cocoa/qnsview_complextext.mm
new file mode 100644
index 0000000000..d357082d33
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qnsview_complextext.mm
@@ -0,0 +1,315 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+// This file is included from qnsview.mm, and only used to organize the code
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (ComplexTextAPI)
+
+- (void)cancelComposingText
+{
+ if (m_composingText.isEmpty())
+ return;
+
+ 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);
+ }
+ }
+ }
+
+ m_composingText.clear();
+ m_composingFocusObject = nullptr;
+}
+
+- (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);
+ }
+ }
+ }
+ }
+ m_composingText.clear();
+ m_composingFocusObject = nullptr;
+}
+
+@end
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (ComplexText)
+
+- (void)insertNewline:(id)sender
+{
+ Q_UNUSED(sender);
+ m_resendKeyEvent = true;
+}
+
+- (void)doCommandBySelector:(SEL)aSelector
+{
+ [self tryToPerform:aSelector with:self];
+}
+
+- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange
+{
+ Q_UNUSED(replacementRange)
+
+ 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;
+ }
+
+ 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));
+ };
+ }
+ 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;
+ }
+ }
+ }
+
+ m_composingText.clear();
+ m_composingFocusObject = nullptr;
+}
+
+- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
+{
+ 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;
+ }
+ } else {
+ // No attributes specified, take only the preedit text.
+ preeditString = QString::fromCFString(reinterpret_cast<CFStringRef>(aString));
+ }
+
+ if (attrs.isEmpty()) {
+ QTextCharFormat format;
+ format.setFontUnderline(true);
+ attrs<<QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
+ 0, preeditString.length(), format);
+ }
+
+ m_composingText = preeditString;
+
+ 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;
+ }
+ }
+ }
+}
+
+- (BOOL)hasMarkedText
+{
+ return (m_composingText.isEmpty() ? NO: YES);
+}
+
+- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
+{
+ 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;
+
+ QString selectedText = queryEvent.value(Qt::ImCurrentSelection).toString();
+ if (selectedText.isEmpty())
+ return nil;
+
+ 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];
+}
+
+- (NSRange)markedRange
+{
+ NSRange range;
+ if (!m_composingText.isEmpty()) {
+ range.location = 0;
+ range.length = m_composingText.length();
+ } else {
+ range.location = NSNotFound;
+ range.length = 0;
+ }
+ return range;
+}
+
+- (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();
+ }
+ return selectedRange;
+}
+
+- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
+{
+ Q_UNUSED(aRange)
+ Q_UNUSED(actualRange)
+
+ QObject *fo = m_platformWindow->window()->focusObject();
+ if (!fo)
+ return NSZeroRect;
+
+ QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
+ if (!QCoreApplication::sendEvent(fo, &queryEvent))
+ return NSZeroRect;
+ if (!queryEvent.value(Qt::ImEnabled).toBool())
+ return NSZeroRect;
+
+ // The returned rect is always based on the internal cursor.
+ QRect mr = qApp->inputMethod()->cursorRectangle().toRect();
+ mr.moveBottomLeft(m_platformWindow->window()->mapToGlobal(mr.bottomLeft()));
+ return QCocoaScreen::mapToNative(mr);
+}
+
+- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint
+{
+ // We don't support cursor movements using mouse while composing.
+ Q_UNUSED(aPoint);
+ return NSNotFound;
+}
+
+- (NSArray<NSString *> *)validAttributesForMarkedText
+{
+ if (!m_platformWindow)
+ return nil;
+
+ if (m_platformWindow->window() != QGuiApplication::focusWindow())
+ return nil;
+
+ QObject *fo = m_platformWindow->window()->focusObject();
+ if (!fo)
+ return nil;
+
+ QInputMethodQueryEvent queryEvent(Qt::ImEnabled);
+ if (!QCoreApplication::sendEvent(fo, &queryEvent))
+ return nil;
+ if (!queryEvent.value(Qt::ImEnabled).toBool())
+ return nil;
+
+ // Support only underline color/style.
+ return @[NSUnderlineColorAttributeName, NSUnderlineStyleAttributeName];
+}
+
+- (void)textInputContextKeyboardSelectionDidChangeNotification:(NSNotification *)textInputContextKeyboardSelectionDidChangeNotification
+{
+ Q_UNUSED(textInputContextKeyboardSelectionDidChangeNotification)
+ if (([NSApp keyWindow] == self.window) && self.window.firstResponder == self) {
+ QCocoaInputContext *ic = qobject_cast<QCocoaInputContext *>(QCocoaIntegration::instance()->inputContext());
+ ic->updateLocale();
+ }
+}
+
+@end
diff --git a/src/plugins/platforms/cocoa/qnsview_dragging.mm b/src/plugins/platforms/cocoa/qnsview_dragging.mm
new file mode 100644
index 0000000000..1c38c5326c
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qnsview_dragging.mm
@@ -0,0 +1,300 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+// This file is included from qnsview.mm, and only used to organize the code
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (Dragging)
+
+-(void)registerDragTypes
+{
+ QMacAutoReleasePool pool;
+
+ 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]];
+
+ // Add custom types supported by the application.
+ for (const QString &customType : qt_mac_enabledDraggedTypes())
+ [supportedTypes addObject:customType.toNSString()];
+
+ [self registerForDraggedTypes:supportedTypes];
+}
+
+static QWindow *findEventTargetWindow(QWindow *candidate)
+{
+ while (candidate) {
+ if (!(candidate->flags() & Qt::WindowTransparentForInput))
+ return candidate;
+ candidate = candidate->parent();
+ }
+ return candidate;
+}
+
+static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint point)
+{
+ return target->mapFromGlobal(source->mapToGlobal(point));
+}
+
+- (NSDragOperation)draggingSession:(NSDraggingSession *)session
+ sourceOperationMaskForDraggingContext:(NSDraggingContext)context
+{
+ Q_UNUSED(session);
+ Q_UNUSED(context);
+ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
+ return qt_mac_mapDropActions(nativeDrag->currentDrag()->supportedActions());
+}
+
+- (BOOL)ignoreModifierKeysForDraggingSession:(NSDraggingSession *)session
+{
+ Q_UNUSED(session);
+ // According to the "Dragging Sources" chapter on Cocoa DnD Programming
+ // (https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/DragandDrop/Concepts/dragsource.html),
+ // if the control, option, or command key is pressed, the source’s
+ // operation mask is filtered to only contain a reduced set of operations.
+ //
+ // 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;
+}
+
+- (BOOL)wantsPeriodicDraggingUpdates
+{
+ // From the documentation:
+ //
+ // "If the destination returns NO, these messages are sent only when the mouse moves
+ // or a modifier flag changes. Otherwise the destination gets the default behavior,
+ // where it receives periodic dragging-updated messages even if nothing changes."
+ //
+ // We do not want these constant drag update events while mouse is stationary,
+ // since we do all animations (autoscroll) with timers.
+ return NO;
+}
+
+
+- (BOOL)wantsPeriodicDraggingUpdates:(void *)dummy
+{
+ // This method never gets called. It's a workaround for Apple's
+ // bug: they first respondsToSelector : @selector(wantsPeriodicDraggingUpdates:)
+ // (note ':') and then call -wantsPeriodicDraggingUpdate (without colon).
+ // So, let's make them happy.
+ Q_UNUSED(dummy);
+
+ return NO;
+}
+
+- (void)updateCursorFromDragResponse:(QPlatformDragQtResponse)response drag:(QCocoaDrag *)drag
+{
+ const QPixmap pixmapCursor = drag->currentDrag()->dragCursor(response.acceptedAction());
+ NSCursor *nativeCursor = nil;
+
+ if (pixmapCursor.isNull()) {
+ switch (response.acceptedAction()) {
+ case Qt::CopyAction:
+ nativeCursor = [NSCursor dragCopyCursor];
+ break;
+ case Qt::LinkAction:
+ nativeCursor = [NSCursor dragLinkCursor];
+ break;
+ case Qt::IgnoreAction:
+ // Uncomment the next lines if forbiden cursor wanted on non droppable targets.
+ /*nativeCursor = [NSCursor operationNotAllowedCursor];
+ break;*/
+ case Qt::MoveAction:
+ default:
+ nativeCursor = [NSCursor arrowCursor];
+ break;
+ }
+ }
+ else {
+ NSImage *nsimage = qt_mac_create_nsimage(pixmapCursor);
+ nsimage.size = NSSizeFromCGSize((pixmapCursor.size() / pixmapCursor.devicePixelRatioF()).toCGSize());
+ nativeCursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSZeroPoint];
+ [nsimage release];
+ }
+
+ // change the cursor
+ [nativeCursor set];
+
+ // Make sure the cursor is updated correctly if the mouse does not move and window is under cursor
+ // by creating a fake move event, unless on 10.14 and later where doing so will trigger a security
+ // warning dialog. FIXME: Find a way to update the cursor without fake mouse events.
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave)
+ return;
+
+ if (m_updatingDrag)
+ return;
+
+ const QPoint mousePos(QCursor::pos());
+ CGEventRef moveEvent(CGEventCreateMouseEvent(
+ NULL, kCGEventMouseMoved,
+ CGPointMake(mousePos.x(), mousePos.y()),
+ kCGMouseButtonLeft // ignored
+ ));
+ CGEventPost(kCGHIDEventTap, moveEvent);
+ CFRelease(moveEvent);
+}
+
+- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
+{
+ return [self handleDrag : sender];
+}
+
+- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
+{
+ m_updatingDrag = true;
+ const NSDragOperation ret([self handleDrag : sender]);
+ m_updatingDrag = false;
+
+ return ret;
+}
+
+// Sends drag update to Qt, return the action
+- (NSDragOperation)handleDrag:(id <NSDraggingInfo>)sender
+{
+ if (!m_platformWindow)
+ return NSDragOperationNone;
+
+ NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil];
+ QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
+ Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]);
+
+ QWindow *target = findEventTargetWindow(m_platformWindow->window());
+ if (!target)
+ return NSDragOperationNone;
+
+ const auto modifiers = [QNSView convertKeyModifiers:NSApp.currentEvent.modifierFlags];
+ const auto buttons = currentlyPressedMouseButtons();
+ const auto point = mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint);
+
+ QPlatformDragQtResponse response(false, Qt::IgnoreAction, QRect());
+ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
+ if (nativeDrag->currentDrag()) {
+ // The drag was started from within the application
+ response = QWindowSystemInterface::handleDrag(target, nativeDrag->dragMimeData(),
+ point, qtAllowed, buttons, modifiers);
+ [self updateCursorFromDragResponse:response drag:nativeDrag];
+ } else {
+ QCocoaDropData mimeData([sender draggingPasteboard]);
+ response = QWindowSystemInterface::handleDrag(target, &mimeData,
+ point, qtAllowed, buttons, modifiers);
+ }
+
+ return qt_mac_mapDropAction(response.acceptedAction());
+}
+
+- (void)draggingExited:(id <NSDraggingInfo>)sender
+{
+ if (!m_platformWindow)
+ return;
+
+ QWindow *target = findEventTargetWindow(m_platformWindow->window());
+ if (!target)
+ return;
+
+ NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil];
+ QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
+
+ // Send 0 mime data to indicate drag exit
+ QWindowSystemInterface::handleDrag(target, nullptr,
+ mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint),
+ Qt::IgnoreAction, Qt::NoButton, Qt::NoModifier);
+}
+
+// called on drop, send the drop to Qt and return if it was accepted.
+- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
+{
+ if (!m_platformWindow)
+ return false;
+
+ QWindow *target = findEventTargetWindow(m_platformWindow->window());
+ if (!target)
+ return false;
+
+ NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil];
+ QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
+ Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]);
+
+ QPlatformDropQtResponse response(false, Qt::IgnoreAction);
+ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
+ const auto modifiers = [QNSView convertKeyModifiers:NSApp.currentEvent.modifierFlags];
+ const auto buttons = currentlyPressedMouseButtons();
+ const auto point = mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint);
+
+ if (nativeDrag->currentDrag()) {
+ // The drag was started from within the application
+ response = QWindowSystemInterface::handleDrop(target, nativeDrag->dragMimeData(),
+ point, qtAllowed, buttons, modifiers);
+ } else {
+ QCocoaDropData mimeData([sender draggingPasteboard]);
+ response = QWindowSystemInterface::handleDrop(target, &mimeData,
+ point, qtAllowed, buttons, modifiers);
+ }
+ return response.isAccepted();
+}
+
+- (void)draggingSession:(NSDraggingSession *)session
+ endedAtPoint:(NSPoint)screenPoint
+ operation:(NSDragOperation)operation
+{
+ Q_UNUSED(session);
+ Q_UNUSED(screenPoint);
+
+ if (!m_platformWindow)
+ return;
+
+ QWindow *target = findEventTargetWindow(m_platformWindow->window());
+ if (!target)
+ return;
+
+ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
+ nativeDrag->setAcceptedAction(qt_mac_mapNSDragOperation(operation));
+
+ m_buttons = currentlyPressedMouseButtons();
+}
+
+@end
diff --git a/src/plugins/platforms/cocoa/qnsview_drawing.mm b/src/plugins/platforms/cocoa/qnsview_drawing.mm
new file mode 100644
index 0000000000..4f9d17504d
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qnsview_drawing.mm
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+// This file is included from qnsview.mm, and only used to organize the code
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (Drawing)
+
+- (BOOL)isOpaque
+{
+ if (!m_platformWindow)
+ return true;
+ return m_platformWindow->isOpaque();
+}
+
+- (BOOL)isFlipped
+{
+ return YES;
+}
+
+- (void)drawRect:(NSRect)dirtyRect
+{
+ Q_UNUSED(dirtyRect);
+
+ 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();
+
+ qCDebug(lcQpaDrawing) << "[QNSView drawRect:]" << m_platformWindow->window() << exposedRegion;
+ m_platformWindow->handleExposeEvent(exposedRegion);
+}
+
+- (BOOL)shouldUseMetalLayer
+{
+ // MetalSurface needs a layer, and so does VulkanSurface (via MoltenVK)
+ QSurface::SurfaceType surfaceType = m_platformWindow->window()->surfaceType();
+ return surfaceType == QWindow::MetalSurface || surfaceType == QWindow::VulkanSurface;
+}
+
+- (BOOL)wantsLayerHelper
+{
+ Q_ASSERT(m_platformWindow);
+
+ bool wantsLayer = qt_mac_resolveOption(true, m_platformWindow->window(),
+ "_q_mac_wantsLayer", "QT_MAC_WANTS_LAYER");
+
+ bool layerForSurfaceType = [self shouldUseMetalLayer];
+
+ return wantsLayer || layerForSurfaceType;
+}
+
+- (CALayer *)makeBackingLayer
+{
+ if ([self shouldUseMetalLayer]) {
+ // Check if Metal is supported. If it isn't then it's most likely
+ // too late at this point and the QWindow will be non-functional,
+ // but we can at least print a warning.
+ if (![MTLCreateSystemDefaultDevice() autorelease]) {
+ qWarning() << "QWindow initialization error: Metal is not supported";
+ return [super makeBackingLayer];
+ }
+
+ CAMetalLayer *layer = [CAMetalLayer layer];
+
+ // Set the contentsScale for the layer. This is normally done in
+ // viewDidChangeBackingProperties, however on startup that function
+ // is called before the layer is created here. The layer's drawableSize
+ // is updated from layoutSublayersOfLayer as usual.
+ layer.contentsScale = self.window.backingScaleFactor;
+
+ return layer;
+ }
+
+ return [super makeBackingLayer];
+}
+
+- (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy
+{
+ // We need to set this explicitly since the super implementation
+ // returns LayerContentsRedrawNever for custom layers like CAMetalLayer.
+ return NSViewLayerContentsRedrawDuringViewResize;
+}
+
+- (void)updateMetalLayerDrawableSize:(CAMetalLayer *)layer
+{
+ CGSize drawableSize = layer.bounds.size;
+ drawableSize.width *= layer.contentsScale;
+ drawableSize.height *= layer.contentsScale;
+ layer.drawableSize = drawableSize;
+}
+
+- (void)layoutSublayersOfLayer:(CALayer *)layer
+{
+ if ([layer isKindOfClass:CAMetalLayer.class])
+ [self updateMetalLayerDrawableSize:static_cast<CAMetalLayer* >(layer)];
+}
+
+- (void)displayLayer:(CALayer *)layer
+{
+ Q_ASSERT(layer == self.layer);
+
+ if (!m_platformWindow)
+ return;
+
+ qCDebug(lcQpaDrawing) << "[QNSView displayLayer]" << m_platformWindow->window();
+
+ // FIXME: Find out if there's a way to resolve the dirty rect like in drawRect:
+ m_platformWindow->handleExposeEvent(QRectF::fromCGRect(self.bounds).toRect());
+}
+
+- (void)viewDidChangeBackingProperties
+{
+ CALayer *layer = self.layer;
+ if (!layer)
+ return;
+
+ layer.contentsScale = self.window.backingScaleFactor;
+
+ // Metal layers must be manually updated on e.g. screen change
+ if ([layer isKindOfClass:CAMetalLayer.class]) {
+ [self updateMetalLayerDrawableSize:static_cast<CAMetalLayer* >(layer)];
+ [self setNeedsDisplay:YES];
+ }
+}
+
+@end
diff --git a/src/plugins/platforms/cocoa/qnsview_gestures.mm b/src/plugins/platforms/cocoa/qnsview_gestures.mm
new file mode 100644
index 0000000000..61d551ee0e
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qnsview_gestures.mm
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+// This file is included from qnsview.mm, and only used to organize the code
+
+#ifndef QT_NO_GESTURES
+
+Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures")
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (Gestures)
+
+- (bool)handleGestureAsBeginEnd:(NSEvent *)event
+{
+ if (QOperatingSystemVersion::current() < QOperatingSystemVersion::OSXElCapitan)
+ return false;
+
+ if ([event phase] == NSEventPhaseBegan) {
+ [self beginGestureWithEvent:event];
+ return true;
+ }
+
+ if ([event phase] == NSEventPhaseEnded) {
+ [self endGestureWithEvent:event];
+ return true;
+ }
+
+ return false;
+}
+- (void)magnifyWithEvent:(NSEvent *)event
+{
+ if (!m_platformWindow)
+ return;
+
+ if ([self handleGestureAsBeginEnd:event])
+ return;
+
+ qCDebug(lcQpaGestures) << "magnifyWithEvent" << [event magnification] << "from device" << hex << [event deviceID];
+ const NSTimeInterval timestamp = [event timestamp];
+ 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);
+}
+
+- (void)smartMagnifyWithEvent:(NSEvent *)event
+{
+ if (!m_platformWindow)
+ return;
+
+ static bool zoomIn = true;
+ qCDebug(lcQpaGestures) << "smartMagnifyWithEvent" << zoomIn << "from device" << hex << [event deviceID];
+ const NSTimeInterval timestamp = [event timestamp];
+ 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);
+ zoomIn = !zoomIn;
+}
+
+- (void)rotateWithEvent:(NSEvent *)event
+{
+ if (!m_platformWindow)
+ return;
+
+ if ([self handleGestureAsBeginEnd:event])
+ return;
+
+ const NSTimeInterval timestamp = [event timestamp];
+ 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);
+}
+
+- (void)swipeWithEvent:(NSEvent *)event
+{
+ if (!m_platformWindow)
+ return;
+
+ qCDebug(lcQpaGestures) << "swipeWithEvent" << [event deltaX] << [event deltaY] << "from device" << hex << [event deviceID];
+ const NSTimeInterval timestamp = [event timestamp];
+ QPointF windowPoint;
+ QPointF screenPoint;
+ [self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+
+ qreal angle = 0.0f;
+ if ([event deltaX] == 1)
+ angle = 180.0f;
+ else if ([event deltaX] == -1)
+ angle = 0.0f;
+ else if ([event deltaY] == 1)
+ angle = 90.0f;
+ 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);
+}
+
+- (void)beginGestureWithEvent:(NSEvent *)event
+{
+ if (!m_platformWindow)
+ return;
+
+ const NSTimeInterval timestamp = [event timestamp];
+ QPointF windowPoint;
+ QPointF screenPoint;
+ [self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ qCDebug(lcQpaGestures) << "beginGestureWithEvent @" << windowPoint << "from device" << hex << [event deviceID];
+ QWindowSystemInterface::handleGestureEvent(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::BeginNativeGesture,
+ windowPoint, screenPoint);
+}
+
+- (void)endGestureWithEvent:(NSEvent *)event
+{
+ if (!m_platformWindow)
+ return;
+
+ qCDebug(lcQpaGestures) << "endGestureWithEvent" << "from device" << hex << [event deviceID];
+ const NSTimeInterval timestamp = [event timestamp];
+ 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);
+}
+
+@end
+
+#endif // QT_NO_GESTURES
diff --git a/src/plugins/platforms/cocoa/qnsview_keys.mm b/src/plugins/platforms/cocoa/qnsview_keys.mm
new file mode 100644
index 0000000000..ad751279bb
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qnsview_keys.mm
@@ -0,0 +1,262 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+// This file is included from qnsview.mm, and only used to organize the code
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (KeysAPI)
+
++ (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;
+}
+
+@end
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (Keys)
+
+- (int)convertKeyCode:(QChar)keyChar
+{
+ return qt_mac_cocoaKey2QtKey(keyChar);
+}
+
+- (bool)handleKeyEvent:(NSEvent *)nsevent eventType:(int)eventType
+{
+ 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];
+ }
+
+ // 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];
+ }
+
+ // 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);
+
+ 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();
+ }
+
+ if (eventType == QEvent::KeyPress) {
+
+ if (m_composingText.isEmpty()) {
+ m_sendKeyEvent = !QWindowSystemInterface::handleShortcutEvent(window, timestamp, keyCode,
+ modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1);
+
+ // Handling a shortcut may result in closing the window
+ if (!m_platformWindow)
+ 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
+ m_currentlyInterpretedKeyEvent = nsevent;
+ [self interpretKeyEvents:@[nsevent]];
+ m_currentlyInterpretedKeyEvent = 0;
+ }
+ }
+ }
+ 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();
+ }
+ m_sendKeyEvent = false;
+ m_resendKeyEvent = false;
+ return accepted;
+}
+
+- (void)keyDown:(NSEvent *)nsevent
+{
+ if ([self isTransparentForUserInput])
+ return [super keyDown:nsevent];
+
+ const bool accepted = [self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)];
+
+ // When Qt is used to implement a plugin for a native application we
+ // want to propagate unhandled events to other native views. However,
+ // Qt does not always set the accepted state correctly (in particular
+ // for return key events), so do this for plugin applications only
+ // to prevent incorrect forwarding in the general case.
+ const bool shouldPropagate = QCoreApplication::testAttribute(Qt::AA_PluginApplication) && !accepted;
+
+ // Track keyDown acceptance/forward state for later acceptance of the keyUp.
+ if (!shouldPropagate)
+ m_acceptedKeyDowns.insert([nsevent keyCode]);
+
+ if (shouldPropagate)
+ [super keyDown:nsevent];
+}
+
+- (void)keyUp:(NSEvent *)nsevent
+{
+ if ([self isTransparentForUserInput])
+ return [super keyUp:nsevent];
+
+ const bool keyUpAccepted = [self handleKeyEvent:nsevent eventType:int(QEvent::KeyRelease)];
+
+ // Propagate the keyUp if neither Qt accepted it nor the corresponding KeyDown was
+ // accepted. Qt text controls wil often not use and ignore keyUp events, but we
+ // want to avoid propagating unmatched keyUps.
+ const bool keyDownAccepted = m_acceptedKeyDowns.remove([nsevent keyCode]);
+ if (!keyUpAccepted && !keyDownAccepted)
+ [super keyUp:nsevent];
+}
+
+- (void)cancelOperation:(id)sender
+{
+ Q_UNUSED(sender);
+
+ 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)
+ 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)];
+}
+
+- (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[] = {
+ { 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)
+ continue;
+
+ Qt::Key qtCode = modifier_key_symbols[i].qt_code;
+ 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;
+ }
+ QWindowSystemInterface::handleKeyEvent(m_platformWindow->window(),
+ timestamp,
+ (lastKnownModifiers & mac_mask) ? QEvent::KeyRelease : QEvent::KeyPress,
+ qtCode,
+ qmodifiers ^ [QNSView convertKeyModifiers:mac_mask]);
+ }
+}
+
+@end
diff --git a/src/plugins/platforms/cocoa/qnsview_menus.mm b/src/plugins/platforms/cocoa/qnsview_menus.mm
new file mode 100644
index 0000000000..f0489552aa
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qnsview_menus.mm
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+// 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>
+
+static bool selectorIsCutCopyPaste(SEL selector)
+{
+ return (selector == @selector(cut:)
+ || selector == @selector(copy:)
+ || selector == @selector(paste:)
+ || selector == @selector(selectAll:));
+}
+
+@interface QT_MANGLE_NAMESPACE(QNSView) (Menus)
+- (void)qt_itemFired:(QCocoaNSMenuItem *)item;
+@end
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (Menus)
+
+- (BOOL)validateMenuItem:(NSMenuItem*)item
+{
+ 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)
+ return NO;
+
+ // Menu-holding items are always enabled, as it's conventional in Cocoa
+ 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()) {
+ QCocoaMenuBar *menubar = nullptr;
+
+ QObject *menuParent = platformItem->menuParent();
+ while (menuParent && !(menubar = qobject_cast<QCocoaMenuBar *>(menuParent))) {
+ auto *menuObject = dynamic_cast<QCocoaMenuObject *>(menuParent);
+ menuParent = menuObject->menuParent();
+ }
+
+ if (menubar && menubar->cocoaWindow() != self.platformWindow)
+ return NO;
+ }
+
+ return platformItem->isEnabled();
+}
+
+- (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);
+
+ return [super respondsToSelector:selector];
+}
+
+- (void)qt_itemFired:(QCocoaNSMenuItem *)item
+{
+ auto *appDelegate = [QCocoaApplicationDelegate sharedDelegate];
+ [appDelegate qt_itemFired:item];
+}
+
+- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
+{
+ if (selectorIsCutCopyPaste(selector)) {
+ NSMethodSignature *itemFiredSign = [super methodSignatureForSelector:@selector(qt_itemFired:)];
+ return itemFiredSign;
+ }
+
+ return [super methodSignatureForSelector:selector];
+}
+
+- (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];
+}
+
+@end
diff --git a/src/plugins/platforms/cocoa/qnsview_mouse.mm b/src/plugins/platforms/cocoa/qnsview_mouse.mm
new file mode 100644
index 0000000000..3d6471005d
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qnsview_mouse.mm
@@ -0,0 +1,624 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+// This file is included from qnsview.mm, and only used to organize the code
+
+@implementation QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) {
+ QNSView *view;
+}
+
+- (instancetype)initWithView:(QNSView *)theView
+{
+ if ((self = [super init]))
+ view = theView;
+
+ return self;
+}
+
+- (void)mouseMoved:(NSEvent *)theEvent
+{
+ [view mouseMovedImpl:theEvent];
+}
+
+- (void)mouseEntered:(NSEvent *)theEvent
+{
+ [view mouseEnteredImpl:theEvent];
+}
+
+- (void)mouseExited:(NSEvent *)theEvent
+{
+ [view mouseExitedImpl:theEvent];
+}
+
+- (void)cursorUpdate:(NSEvent *)theEvent
+{
+ [view cursorUpdate:theEvent];
+}
+
+@end
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (MouseAPI)
+
+- (void)resetMouseButtons
+{
+ m_buttons = Qt::NoButton;
+ m_frameStrutButtons = Qt::NoButton;
+}
+
+- (void)handleFrameStrutMouseEvent:(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)
+ 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:
+ m_frameStrutButtons &= ~Qt::RightButton;
+ break;
+ case NSEventTypeOtherMouseDown:
+ m_frameStrutButtons |= cocoaButton2QtButton(theEvent.buttonNumber);
+ break;
+ case NSEventTypeOtherMouseUp:
+ m_frameStrutButtons &= ~cocoaButton2QtButton(theEvent.buttonNumber);
+ default:
+ break;
+ }
+
+ NSWindow *window = [self window];
+ NSPoint windowPoint = [theEvent locationInWindow];
+
+ int windowScreenY = [window frame].origin.y + [window frame].size.height;
+ NSPoint windowCoord = [self convertPoint:[self frame].origin toView:nil];
+ int viewScreenY = [window convertRectToScreen:NSMakeRect(windowCoord.x, windowCoord.y, 0, 0)].origin.y;
+ int titleBarHeight = windowScreenY - viewScreenY;
+
+ NSPoint nsViewPoint = [self convertPoint: windowPoint fromView: nil];
+ QPoint qtWindowPoint = QPoint(nsViewPoint.x, titleBarHeight + nsViewPoint.y);
+ NSPoint screenPoint = [window convertRectToScreen:NSMakeRect(windowPoint.x, windowPoint.y, 0, 0)].origin;
+ QPoint qtScreenPoint = QCocoaScreen::mapFromNative(screenPoint).toPoint();
+
+ ulong timestamp = [theEvent timestamp] * 1000;
+ QWindowSystemInterface::handleFrameStrutMouseEvent(m_platformWindow->window(), timestamp, qtWindowPoint, qtScreenPoint, m_frameStrutButtons);
+}
+@end
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (Mouse)
+
+- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
+{
+ Q_UNUSED(theEvent)
+ if (!m_platformWindow)
+ return NO;
+ if ([self isTransparentForUserInput])
+ return NO;
+ return YES;
+}
+
+- (NSPoint)screenMousePoint:(NSEvent *)theEvent
+{
+ NSPoint screenPoint;
+ if (theEvent) {
+ NSPoint windowPoint = [theEvent locationInWindow];
+ if (qIsNaN(windowPoint.x) || qIsNaN(windowPoint.y)) {
+ screenPoint = [NSEvent mouseLocation];
+ } else {
+ NSRect screenRect = [[theEvent window] convertRectToScreen:NSMakeRect(windowPoint.x, windowPoint.y, 1, 1)];
+ screenPoint = screenRect.origin;
+ }
+ } else {
+ screenPoint = [NSEvent mouseLocation];
+ }
+ 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];
+ const auto buttons = currentlyPressedMouseButtons();
+ auto button = cocoaButton2QtButton(theEvent);
+ if (button == Qt::LeftButton && m_sendUpAsRightButton)
+ button = Qt::RightButton;
+ const auto eventType = cocoaEvent2QtMouseEvent(theEvent);
+
+ QWindowSystemInterface::handleMouseEvent(targetView->m_platformWindow->window(),
+ timestamp, qtWindowPoint, qtScreenPoint,
+ buttons, button, eventType, modifiers);
+}
+
+- (bool)handleMouseDownEvent:(NSEvent *)theEvent
+{
+ if ([self isTransparentForUserInput])
+ return false;
+
+ const auto button = cocoaButton2QtButton(theEvent);
+
+ QPointF qtWindowPoint;
+ QPointF qtScreenPoint;
+ [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
+ Q_UNUSED(qtScreenPoint);
+
+ // Maintain masked state for the button for use by MouseDragged and MouseUp.
+ QRegion mask = m_platformWindow->window()->mask();
+ const bool masked = !mask.isEmpty() && !mask.contains(qtWindowPoint.toPoint());
+ if (masked)
+ m_acceptedMouseDowns &= ~button;
+ else
+ m_acceptedMouseDowns |= button;
+
+ // Forward masked out events to the next responder
+ if (masked)
+ return false;
+
+ m_buttons |= button;
+
+ [self handleMouseEvent:theEvent];
+ return true;
+}
+
+- (bool)handleMouseDraggedEvent:(NSEvent *)theEvent
+{
+ if ([self isTransparentForUserInput])
+ return false;
+
+ const auto button = cocoaButton2QtButton(theEvent);
+
+ // Forward the event to the next responder if Qt did not accept the
+ // corresponding mouse down for this button
+ if (!(m_acceptedMouseDowns & button) == button)
+ return false;
+
+ [self handleMouseEvent:theEvent];
+ return true;
+}
+
+- (bool)handleMouseUpEvent:(NSEvent *)theEvent
+{
+ if ([self isTransparentForUserInput])
+ return false;
+
+ auto button = cocoaButton2QtButton(theEvent);
+
+ // Forward the event to the next responder if Qt did not accept the
+ // corresponding mouse down for this button
+ if (!(m_acceptedMouseDowns & button) == button)
+ return false;
+
+ if (m_sendUpAsRightButton && button == Qt::LeftButton)
+ button = Qt::RightButton;
+
+ m_buttons &= ~button;
+
+ [self handleMouseEvent:theEvent];
+
+ if (button == Qt::RightButton)
+ m_sendUpAsRightButton = false;
+
+ return true;
+}
+
+- (void)mouseDown:(NSEvent *)theEvent
+{
+ if ([self isTransparentForUserInput])
+ 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) {
+ Qt::WindowType type = QCocoaIntegration::instance()->activePopupWindow()->window()->type();
+ while (QCocoaWindow *popup = QCocoaIntegration::instance()->popPopupWindow()) {
+ 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)
+ return;
+ }
+ }
+
+ QPointF qtWindowPoint;
+ QPointF qtScreenPoint;
+ [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
+ Q_UNUSED(qtScreenPoint);
+
+ QRegion mask = m_platformWindow->window()->mask();
+ const bool masked = !mask.isEmpty() && !mask.contains(qtWindowPoint.toPoint());
+ // Maintain masked state for the button for use by MouseDragged and Up.
+ if (masked)
+ m_acceptedMouseDowns &= ~Qt::LeftButton;
+ else
+ m_acceptedMouseDowns |= Qt::LeftButton;
+
+ // Forward masked out events to the next responder
+ if (masked) {
+ [super mouseDown:theEvent];
+ 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;
+ }
+ [self handleMouseEvent:theEvent];
+ }
+}
+
+- (void)mouseDragged:(NSEvent *)theEvent
+{
+ const bool accepted = [self handleMouseDraggedEvent:theEvent];
+ if (!accepted)
+ [super mouseDragged:theEvent];
+}
+
+- (void)mouseUp:(NSEvent *)theEvent
+{
+ const bool accepted = [self handleMouseUpEvent:theEvent];
+ if (!accepted)
+ [super mouseUp:theEvent];
+}
+
+- (void)rightMouseDown:(NSEvent *)theEvent
+{
+ const bool accepted = [self handleMouseDownEvent:theEvent];
+ if (!accepted)
+ [super rightMouseDown:theEvent];
+}
+
+- (void)rightMouseDragged:(NSEvent *)theEvent
+{
+ const bool accepted = [self handleMouseDraggedEvent:theEvent];
+ if (!accepted)
+ [super rightMouseDragged:theEvent];
+}
+
+- (void)rightMouseUp:(NSEvent *)theEvent
+{
+ const bool accepted = [self handleMouseUpEvent:theEvent];
+ if (!accepted)
+ [super rightMouseUp:theEvent];
+}
+
+- (void)otherMouseDown:(NSEvent *)theEvent
+{
+ const bool accepted = [self handleMouseDownEvent:theEvent];
+ if (!accepted)
+ [super otherMouseDown:theEvent];
+}
+
+- (void)otherMouseDragged:(NSEvent *)theEvent
+{
+ const bool accepted = [self handleMouseDraggedEvent:theEvent];
+ if (!accepted)
+ [super otherMouseDragged:theEvent];
+}
+
+- (void)otherMouseUp:(NSEvent *)theEvent
+{
+ const bool accepted = [self handleMouseUpEvent:theEvent];
+ if (!accepted)
+ [super otherMouseUp:theEvent];
+}
+
+- (void)updateTrackingAreas
+{
+ [super updateTrackingAreas];
+
+ QMacAutoReleasePool pool;
+
+ // NSTrackingInVisibleRect keeps care of updating once the tracking is set up, so bail out early
+ if (m_trackingArea && [[self trackingAreas] containsObject:m_trackingArea])
+ return;
+
+ // Ideally, we shouldn't have NSTrackingMouseMoved events included below, it should
+ // only be turned on if mouseTracking, hover is on or a tool tip is set.
+ // Unfortunately, Qt will send "tooltip" events on mouse moves, so we need to
+ // turn it on in ALL case. That means EVERY QWindow gets to pay the cost of
+ // mouse moves delivered to it (Apple recommends keeping it OFF because there
+ // is a performance hit). So it goes.
+ NSUInteger trackingOptions = NSTrackingMouseEnteredAndExited | NSTrackingActiveInActiveApp
+ | NSTrackingInVisibleRect | NSTrackingMouseMoved | NSTrackingCursorUpdate;
+ [m_trackingArea release];
+ m_trackingArea = [[NSTrackingArea alloc] initWithRect:[self frame]
+ options:trackingOptions
+ owner:m_mouseMoveHelper
+ userInfo:nil];
+ [self addTrackingArea:m_trackingArea];
+}
+
+- (void)cursorUpdate:(NSEvent *)theEvent
+{
+ qCDebug(lcQpaMouse) << "[QNSView cursorUpdate:]" << self.cursor;
+
+ // 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 (self.cursor)
+ [self.cursor set];
+ else
+ [super cursorUpdate:theEvent];
+}
+
+- (void)mouseMovedImpl:(NSEvent *)theEvent
+{
+ 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;
+ }
+ }
+
+ // 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())
+ return;
+
+ [self handleMouseEvent: theEvent];
+}
+
+- (void)mouseEnteredImpl:(NSEvent *)theEvent
+{
+ Q_UNUSED(theEvent)
+ if (!m_platformWindow)
+ return;
+
+ m_platformWindow->m_windowUnderMouse = true;
+
+ if ([self isTransparentForUserInput])
+ return;
+
+ // Top-level windows generate enter events for sub-windows.
+ if (!m_platformWindow->isContentView())
+ return;
+
+ QPointF windowPoint;
+ QPointF screenPoint;
+ [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ m_platformWindow->m_enterLeaveTargetWindow = m_platformWindow->childWindowAt(windowPoint.toPoint());
+ QWindowSystemInterface::handleEnterEvent(m_platformWindow->m_enterLeaveTargetWindow, windowPoint, screenPoint);
+}
+
+- (void)mouseExitedImpl:(NSEvent *)theEvent
+{
+ Q_UNUSED(theEvent);
+ if (!m_platformWindow)
+ return;
+
+ m_platformWindow->m_windowUnderMouse = false;
+
+ if ([self isTransparentForUserInput])
+ return;
+
+ // Top-level windows generate leave events for sub-windows.
+ if (!m_platformWindow->isContentView())
+ return;
+
+ QWindowSystemInterface::handleLeaveEvent(m_platformWindow->m_enterLeaveTargetWindow);
+ m_platformWindow->m_enterLeaveTargetWindow = 0;
+}
+
+#if QT_CONFIG(wheelevent)
+- (void)scrollWheel:(NSEvent *)theEvent
+{
+ if (!m_platformWindow)
+ return;
+
+ if ([self isTransparentForUserInput])
+ return [super scrollWheel:theEvent];
+
+ QPoint angleDelta;
+ Qt::MouseEventSource source = Qt::MouseEventNotSynthesized;
+ if ([theEvent hasPreciseScrollingDeltas]) {
+ // The mouse device contains pixel scroll wheel support (Mighty Mouse, Trackpad).
+ // 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([theEvent scrollingDeltaX] * pixelsToDegrees);
+ angleDelta.setY([theEvent scrollingDeltaY] * pixelsToDegrees);
+ source = Qt::MouseEventSynthesizedBySystem;
+ } else {
+ // Remove acceleration, and use either -120 or 120 as delta:
+ angleDelta.setX(qBound(-120, int([theEvent deltaX] * 10000), 120));
+ angleDelta.setY(qBound(-120, int([theEvent deltaY] * 10000), 120));
+ }
+
+ QPoint pixelDelta;
+ if ([theEvent hasPreciseScrollingDeltas]) {
+ pixelDelta.setX([theEvent scrollingDeltaX]);
+ pixelDelta.setY([theEvent scrollingDeltaY]);
+ } else {
+ // docs: "In the case of !hasPreciseScrollingDeltas, multiply the delta with the line width."
+ // scrollingDeltaX seems to return a minimum value of 0.1 in this case, map that to two pixels.
+ const CGFloat lineWithEstimate = 20.0;
+ pixelDelta.setX([theEvent scrollingDeltaX] * lineWithEstimate);
+ pixelDelta.setY([theEvent scrollingDeltaY] * lineWithEstimate);
+ }
+
+ QPointF qt_windowPoint;
+ QPointF qt_screenPoint;
+ [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qt_windowPoint andScreenPoint:&qt_screenPoint];
+ NSTimeInterval timestamp = [theEvent timestamp];
+ ulong qt_timestamp = timestamp * 1000;
+
+ Qt::ScrollPhase phase = Qt::NoScrollPhase;
+ if (theEvent.phase == NSEventPhaseMayBegin || theEvent.phase == NSEventPhaseBegan) {
+ // MayBegin is likely to happen. We treat it the same as an actual begin,
+ // and follow it with an update when the actual begin is delivered.
+ phase = m_scrolling ? Qt::ScrollUpdate : Qt::ScrollBegin;
+ m_scrolling = true;
+ } else if (theEvent.phase == NSEventPhaseStationary || theEvent.phase == NSEventPhaseChanged) {
+ phase = Qt::ScrollUpdate;
+ } else if (theEvent.phase == NSEventPhaseEnded) {
+ // A scroll event phase may be followed by a momentum phase after the user releases
+ // the finger, and in that case we don't want to send a Qt::ScrollEnd until after
+ // the momentum phase has ended. Unfortunately there isn't any guaranteed way of
+ // knowing whether or not a NSEventPhaseEnded will be followed by a momentum phase.
+ // The best we can do is to look at the event queue and hope that the system has
+ // 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
+ }
+ 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
+ } else if (theEvent.momentumPhase == NSEventPhaseChanged) {
+ phase = Qt::ScrollMomentum;
+ } else if (theEvent.phase == NSEventPhaseCancelled
+ || theEvent.momentumPhase == NSEventPhaseEnded
+ || theEvent.momentumPhase == NSEventPhaseCancelled) {
+ phase = Qt::ScrollEnd;
+ m_scrolling = false;
+ } else {
+ Q_ASSERT(theEvent.momentumPhase != NSEventPhaseStationary);
+ }
+
+ // 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
+ // flick in order to avoid changing the interpretation of the events
+ // mid-stream. One example of this happening would be when pressing cmd
+ // 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]];
+
+ // "isInverted": natural OS X scrolling, inverted from the Qt/other platform/Jens perspective.
+ bool isInverted = [theEvent isDirectionInvertedFromDevice];
+
+ qCDebug(lcQpaMouse) << "scroll wheel @ window pos" << qt_windowPoint << "delta px" << pixelDelta
+ << "angle" << angleDelta << "phase" << phase << (isInverted ? "inverted" : "");
+ QWindowSystemInterface::handleWheelEvent(m_platformWindow->window(), qt_timestamp, qt_windowPoint,
+ qt_screenPoint, pixelDelta, angleDelta, m_currentWheelModifiers, phase, source, isInverted);
+}
+#endif // QT_CONFIG(wheelevent)
+
+@end
diff --git a/src/plugins/platforms/cocoa/qnsview_tablet.mm b/src/plugins/platforms/cocoa/qnsview_tablet.mm
new file mode 100644
index 0000000000..43b0aa0960
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qnsview_tablet.mm
@@ -0,0 +1,223 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+// 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")
+
+struct QCocoaTabletDeviceData
+{
+ QTabletEvent::TabletDevice device;
+ QTabletEvent::PointerType pointerType;
+ uint capabilityMask;
+ qint64 uid;
+};
+
+typedef QHash<uint, QCocoaTabletDeviceData> QCocoaTabletDeviceDataHash;
+Q_GLOBAL_STATIC(QCocoaTabletDeviceDataHash, tabletDeviceDataHash)
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (Tablet)
+
+- (bool)handleTabletEvent:(NSEvent *)theEvent
+{
+ static bool ignoreButtonMapping = qEnvironmentVariableIsSet("QT_MAC_TABLET_IGNORE_BUTTON_MAPPING");
+
+ if (!m_platformWindow)
+ return false;
+
+ NSEventType eventType = [theEvent type];
+ if (eventType != NSEventTypeTabletPoint && [theEvent subtype] != NSEventSubtypeTabletPoint)
+ return false; // Not a tablet event.
+
+ ulong timestamp = [theEvent timestamp] * 1000;
+
+ QPointF windowPoint;
+ 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;
+ }
+ const QCocoaTabletDeviceData &deviceData = tabletDeviceDataHash->value(deviceId);
+
+ bool down = (eventType != NSEventTypeMouseMoved);
+
+ qreal pressure;
+ if (down) {
+ pressure = [theEvent pressure];
+ } else {
+ pressure = 0.0;
+ }
+
+ NSPoint tilt = [theEvent tilt];
+ int xTilt = qRound(tilt.x * 60.0);
+ int yTilt = qRound(tilt.y * -60.0);
+ qreal tangentialPressure = 0;
+ qreal rotation = 0;
+ int z = 0;
+ if (deviceData.capabilityMask & 0x0200)
+ z = [theEvent absoluteZ];
+
+ if (deviceData.capabilityMask & 0x0800)
+ 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::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);
+ return true;
+}
+
+- (void)tabletPoint:(NSEvent *)theEvent
+{
+ if ([self isTransparentForUserInput])
+ return [super tabletPoint:theEvent];
+
+ [self handleTabletEvent: theEvent];
+}
+
+static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
+{
+ 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.
+ // I'm not sure how to handle it for consumer devices, but I'll test that in a bit.
+ 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;
+ } 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;
+ break;
+ case NSPointingDeviceTypePen:
+ deviceData.pointerType = QTabletEvent::Pen;
+ break;
+ case NSPointingDeviceTypeCursor:
+ deviceData.pointerType = QTabletEvent::Cursor;
+ break;
+ case NSPointingDeviceTypeEraser:
+ deviceData.pointerType = QTabletEvent::Eraser;
+ break;
+ }
+
+ deviceData.device = wacomTabletDevice(theEvent);
+
+ // 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);
+ }
+
+ qCDebug(lcQpaTablet, "proximity change on tablet %d: current tool %d type %d unique ID %lld",
+ deviceId, deviceData.device, deviceData.pointerType, deviceData.uid);
+
+ if (entering) {
+ QWindowSystemInterface::handleTabletEnterProximityEvent(timestamp, deviceData.device, deviceData.pointerType, deviceData.uid);
+ } else {
+ QWindowSystemInterface::handleTabletLeaveProximityEvent(timestamp, deviceData.device, deviceData.pointerType, deviceData.uid);
+ }
+}
+@end
+
+#endif
diff --git a/src/plugins/platforms/cocoa/qnsview_touch.mm b/src/plugins/platforms/cocoa/qnsview_touch.mm
new file mode 100644
index 0000000000..e789213f70
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qnsview_touch.mm
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+// This file is included from qnsview.mm, and only used to organize the code
+
+Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch")
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (Touch)
+
+- (bool)shouldSendSingleTouch
+{
+ if (!m_platformWindow)
+ return true;
+
+ // QtWidgets expects single-point touch events, QtDeclarative does not.
+ // Until there is an API we solve this by looking at the window class type.
+ return m_platformWindow->window()->inherits("QWidgetWindow");
+}
+
+- (void)touchesBeganWithEvent:(NSEvent *)event
+{
+ if (!m_platformWindow)
+ return;
+
+ const NSTimeInterval timestamp = [event timestamp];
+ const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
+ qCDebug(lcQpaTouch) << "touchesBeganWithEvent" << points << "from device" << hex << [event deviceID];
+ QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
+}
+
+- (void)touchesMovedWithEvent:(NSEvent *)event
+{
+ if (!m_platformWindow)
+ return;
+
+ const NSTimeInterval timestamp = [event timestamp];
+ const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
+ qCDebug(lcQpaTouch) << "touchesMovedWithEvent" << points << "from device" << hex << [event deviceID];
+ QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
+}
+
+- (void)touchesEndedWithEvent:(NSEvent *)event
+{
+ if (!m_platformWindow)
+ return;
+
+ const NSTimeInterval timestamp = [event timestamp];
+ const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
+ qCDebug(lcQpaTouch) << "touchesEndedWithEvent" << points << "from device" << hex << [event deviceID];
+ QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
+}
+
+- (void)touchesCancelledWithEvent:(NSEvent *)event
+{
+ if (!m_platformWindow)
+ return;
+
+ const NSTimeInterval timestamp = [event timestamp];
+ const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
+ qCDebug(lcQpaTouch) << "touchesCancelledWithEvent" << points << "from device" << hex << [event deviceID];
+ QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
+}
+
+@end
diff --git a/src/plugins/platforms/cocoa/qnswindow.h b/src/plugins/platforms/cocoa/qnswindow.h
index ea690b69e3..64f1ed0802 100644
--- a/src/plugins/platforms/cocoa/qnswindow.h
+++ b/src/plugins/platforms/cocoa/qnswindow.h
@@ -67,6 +67,7 @@ QT_FORWARD_DECLARE_CLASS(QCocoaWindow)
- (void)dealloc;
- (BOOL)isOpaque;
- (NSColor *)backgroundColor;
+- (NSString *)description;
@property (nonatomic, readonly) QCocoaWindow *platformWindow;
@end
diff --git a/src/plugins/platforms/cocoa/qnswindow.mm b/src/plugins/platforms/cocoa/qnswindow.mm
index cb13b7d184..1b9dd95cbc 100644
--- a/src/plugins/platforms/cocoa/qnswindow.mm
+++ b/src/plugins/platforms/cocoa/qnswindow.mm
@@ -38,7 +38,6 @@
****************************************************************************/
#include "qnswindow.h"
-#include "qnswindowdelegate.h"
#include "qcocoawindow.h"
#include "qcocoahelpers.h"
#include "qcocoaeventdispatcher.h"
@@ -46,18 +45,18 @@
#include <qpa/qwindowsysteminterface.h>
#include <qoperatingsystemversion.h>
-Q_LOGGING_CATEGORY(lcCocoaEvents, "qt.qpa.cocoa.events");
+Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events");
static bool isMouseEvent(NSEvent *ev)
{
switch ([ev type]) {
- case NSLeftMouseDown:
- case NSLeftMouseUp:
- case NSRightMouseDown:
- case NSRightMouseUp:
- case NSMouseMoved:
- case NSLeftMouseDragged:
- case NSRightMouseDragged:
+ case NSEventTypeLeftMouseDown:
+ case NSEventTypeLeftMouseUp:
+ case NSEventTypeRightMouseDown:
+ case NSEventTypeRightMouseUp:
+ case NSEventTypeMouseMoved:
+ case NSEventTypeLeftMouseDragged:
+ case NSEventTypeRightMouseDragged:
return true;
default:
return false;
@@ -72,7 +71,7 @@ static bool isMouseEvent(NSEvent *ev)
[center addObserverForName:NSWindowDidEnterFullScreenNotification object:nil queue:nil
usingBlock:^(NSNotification *notification) {
objc_setAssociatedObject(notification.object, @selector(qt_fullScreen),
- [NSNumber numberWithBool:YES], OBJC_ASSOCIATION_RETAIN);
+ @(YES), OBJC_ASSOCIATION_RETAIN);
}
];
[center addObserverForName:NSWindowDidExitFullScreenNotification object:nil queue:nil
@@ -187,22 +186,22 @@ static bool isMouseEvent(NSEvent *ev)
/*!
Borderless windows need a transparent background
- Technically windows with NSTexturedBackgroundWindowMask (such
- as windows with unified toolbars) need to draw the textured
+ Technically windows with NSWindowStyleMaskTexturedBackground
+ (such as windows with unified toolbars) need to draw the textured
background of the NSWindow, and can't have a transparent
- background, but as NSBorderlessWindowMask is 0, you can't
- have a window with NSTexturedBackgroundWindowMask that is
+ background, but as NSWindowStyleMaskBorderless is 0, you can't
+ have a window with NSWindowStyleMaskTexturedBackground that is
also borderless.
*/
- (NSColor *)backgroundColor
{
- return self.styleMask == NSBorderlessWindowMask
+ return self.styleMask == NSWindowStyleMaskBorderless
? [NSColor clearColor] : qt_objcDynamicSuper();
}
- (void)sendEvent:(NSEvent*)theEvent
{
- qCDebug(lcCocoaEvents) << "Sending" << theEvent << "to" << self;
+ qCDebug(lcQpaEvents) << "Sending" << theEvent << "to" << self;
// We might get events for a NSWindow after the corresponding platform
// window has been deleted, as the NSWindow can outlive the QCocoaWindow
@@ -239,7 +238,7 @@ static bool isMouseEvent(NSEvent *ev)
- (void)closeAndRelease
{
- qCDebug(lcQpaCocoaWindow) << "closeAndRelease" << self;
+ qCDebug(lcQpaWindow) << "closeAndRelease" << self;
[self.delegate release];
self.delegate = nil;
@@ -252,7 +251,7 @@ static bool isMouseEvent(NSEvent *ev)
#pragma clang diagnostic ignored "-Wobjc-missing-super-calls"
- (void)dealloc
{
- qCDebug(lcQpaCocoaWindow) << "dealloc" << self;
+ qCDebug(lcQpaWindow) << "dealloc" << self;
qt_objcDynamicSuper();
}
#pragma clang diagnostic pop
@@ -263,29 +262,20 @@ static bool isMouseEvent(NSEvent *ev)
NSEnumerator<NSWindow*> *windowEnumerator = nullptr;
NSApplication *application = [NSApplication sharedApplication];
-#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_12)
- if (__builtin_available(macOS 10.12, *)) {
- // Unfortunately there's no NSWindowListOrderedBackToFront,
- // so we have to manually reverse the order using an array.
- NSMutableArray *windows = [[[NSMutableArray alloc] init] autorelease];
- [application enumerateWindowsWithOptions:NSWindowListOrderedFrontToBack
- usingBlock:^(NSWindow *window, BOOL *) {
- // For some reason AppKit will give us nil-windows, skip those
- if (!window)
- return;
-
- [(NSMutableArray*)windows addObject:window];
- }
- ];
-
- windowEnumerator = windows.reverseObjectEnumerator;
- } else
-#endif
- {
- // No way to get ordered list of windows, so fall back to unordered,
- // list, which typically corresponds to window creation order.
- windowEnumerator = application.windows.objectEnumerator;
- }
+ // Unfortunately there's no NSWindowListOrderedBackToFront,
+ // so we have to manually reverse the order using an array.
+ NSMutableArray<NSWindow *> *windows = [NSMutableArray<NSWindow *> new];
+ [application enumerateWindowsWithOptions:NSWindowListOrderedFrontToBack
+ usingBlock:^(NSWindow *window, BOOL *) {
+ // For some reason AppKit will give us nil-windows, skip those
+ if (!window)
+ return;
+
+ [windows addObject:window];
+ }
+ ];
+
+ windowEnumerator = windows.reverseObjectEnumerator;
for (NSWindow *window in windowEnumerator) {
// We're meddling with normal and floating windows, so leave others alone
diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.h b/src/plugins/platforms/cocoa/qnswindowdelegate.h
index d2078b5786..e71afcbb2a 100644
--- a/src/plugins/platforms/cocoa/qnswindowdelegate.h
+++ b/src/plugins/platforms/cocoa/qnswindowdelegate.h
@@ -41,20 +41,16 @@
#define QNSWINDOWDELEGATE_H
#include <AppKit/AppKit.h>
+#include <QtCore/private/qcore_mac_p.h>
-#include "qcocoawindow.h"
+QT_BEGIN_NAMESPACE
+class QCocoaWindow;
+QT_END_NAMESPACE
@interface QT_MANGLE_NAMESPACE(QNSWindowDelegate) : NSObject <NSWindowDelegate>
-{
- QCocoaWindow *m_cocoaWindow;
-}
-- (id)initWithQCocoaWindow:(QCocoaWindow *)cocoaWindow;
+- (instancetype)initWithQCocoaWindow:(QT_PREPEND_NAMESPACE(QCocoaWindow) *)cocoaWindow;
-- (BOOL)windowShouldClose:(NSNotification *)notification;
-
-- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu;
-- (BOOL)window:(NSWindow *)window shouldDragDocumentWithEvent:(NSEvent *)event from:(NSPoint)dragImageLocation withPasteboard:(NSPasteboard *)pasteboard;
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSWindowDelegate);
diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm
index 057a4c2943..97309ea990 100644
--- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm
+++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm
@@ -39,21 +39,24 @@
#include "qnswindowdelegate.h"
#include "qcocoahelpers.h"
+#include "qcocoawindow.h"
#include "qcocoascreen.h"
#include <QDebug>
+#include <QtCore/private/qcore_mac_p.h>
#include <qpa/qplatformscreen.h>
#include <qpa/qwindowsysteminterface.h>
static QRegExp whitespaceRegex = QRegExp(QStringLiteral("\\s*"));
-@implementation QNSWindowDelegate
+@implementation QNSWindowDelegate {
+ QCocoaWindow *m_cocoaWindow;
+}
-- (id)initWithQCocoaWindow:(QCocoaWindow *)cocoaWindow
+- (instancetype)initWithQCocoaWindow:(QCocoaWindow *)cocoaWindow
{
- if (self = [super init])
+ if ((self = [self init]))
m_cocoaWindow = cocoaWindow;
-
return self;
}
@@ -103,6 +106,36 @@ static QRegExp whitespaceRegex = QRegExp(QStringLiteral("\\s*"));
return QCocoaScreen::mapToNative(maximizedFrame);
}
+#pragma clang diagnostic push
+// NSDisableScreenUpdates and NSEnableScreenUpdates are deprecated, but the
+// NSAnimationContext API that replaces them doesn't handle the use-case of
+// cross-thread screen update synchronization.
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)frameSize
+{
+ qCDebug(lcQpaWindow) << window << "will resize to" << QSizeF::fromCGSize(frameSize)
+ << "- disabling screen updates temporarily";
+
+ // There may be separate threads rendering to CA layers in this window,
+ // and if any of them do a swap while the resize is still in progress,
+ // the visual bounds of that layer will be updated before the visual
+ // bounds of the window frame, resulting in flickering while resizing.
+
+ // To prevent this we disable screen updates for the whole process until
+ // the resize is complete, which makes the whole thing visually atomic.
+ NSDisableScreenUpdates();
+
+ return frameSize;
+}
+
+- (void)windowDidResize:(NSNotification *)notification
+{
+ NSWindow *window = notification.object;
+ qCDebug(lcQpaWindow) << window << "was resized - re-enabling screen updates";
+ NSEnableScreenUpdates();
+}
+#pragma clang diagnostic pop
+
- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu
{
Q_UNUSED(window);
diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm
index 3f363b62d5..96506c67fa 100644
--- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm
+++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm
@@ -98,8 +98,8 @@ CGImageRef qt_mac_create_imagemask(const QPixmap &pixmap, const QRectF &sr)
for (int x = sx; x < sw; ++x)
*(dptr+(offset++)) = (*(srow+x) & mask) ? 255 : 0;
}
- QCFType<CGDataProviderRef> provider = CGDataProviderCreateWithData(0, dptr, nbytes, qt_mac_cgimage_data_free);
- return CGImageMaskCreate(sw, sh, 8, 8, nbytes / sh, provider, 0, 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
@@ -287,16 +287,16 @@ static void qt_mac_draw_pattern(void *info, CGContextRef c)
Q_ASSERT(pat->data.bytes);
w = h = 8;
#if (QMACPATTERN_MASK_MULTIPLIER == 1)
- CGDataProviderRef provider = CGDataProviderCreateWithData(0, pat->data.bytes, w*h, 0);
- pat->image = CGImageMaskCreate(w, h, 1, 1, 1, provider, 0, false);
+ 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(0, xor_bytes, w*h, 0);
- CGImageRef swatch = CGImageMaskCreate(w, h, 1, 1, 1, provider, 0, false);
+ 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);
@@ -399,9 +399,9 @@ QCoreGraphicsPaintEngine::begin(QPaintDevice *pdev)
d->orig_xform = CGContextGetCTM(d->hd);
if (d->shading) {
CGShadingRelease(d->shading);
- d->shading = 0;
+ d->shading = nullptr;
}
- d->setClip(0); //clear the context's clipping
+ d->setClip(nullptr); //clear the context's clipping
}
setActive(true);
@@ -445,12 +445,12 @@ QCoreGraphicsPaintEngine::end()
CGShadingRelease(d->shading);
d->shading = 0;
}
- d->pdev = 0;
+ d->pdev = nullptr;
if (d->hd) {
d->restoreGraphicsState();
CGContextSynchronize(d->hd);
CGContextRelease(d->hd);
- d->hd = 0;
+ d->hd = nullptr;
}
return true;
}
@@ -545,7 +545,7 @@ QCoreGraphicsPaintEngine::updateBrush(const QBrush &brush, const QPointF &brushO
if (d->shading) {
CGShadingRelease(d->shading);
- d->shading = 0;
+ d->shading = nullptr;
}
d->setFillBrush(brushOrigin);
}
@@ -592,7 +592,7 @@ QCoreGraphicsPaintEngine::updateClipPath(const QPainterPath &p, Qt::ClipOperatio
if (d->current.clipEnabled) {
d->current.clipEnabled = false;
d->current.clip = QRegion();
- d->setClip(0);
+ d->setClip(nullptr);
}
} else {
if (!d->current.clipEnabled)
@@ -601,7 +601,7 @@ QCoreGraphicsPaintEngine::updateClipPath(const QPainterPath &p, Qt::ClipOperatio
QRegion clipRegion(p.toFillPolygon().toPolygon(), p.fillRule());
if (op == Qt::ReplaceClip) {
d->current.clip = clipRegion;
- d->setClip(0);
+ d->setClip(nullptr);
if (p.isEmpty()) {
CGRect rect = CGRectMake(0, 0, 0, 0);
CGContextClipToRect(d->hd, rect);
@@ -630,7 +630,7 @@ QCoreGraphicsPaintEngine::updateClipRegion(const QRegion &clipRegion, Qt::ClipOp
if (op == Qt::NoClip) {
d->current.clipEnabled = false;
d->current.clip = QRegion();
- d->setClip(0);
+ d->setClip(nullptr);
} else {
if (!d->current.clipEnabled)
op = Qt::ReplaceClip;
@@ -676,7 +676,7 @@ QCoreGraphicsPaintEngine::drawRects(const QRectF *rects, int rectCount)
QRectF r = rects[i];
CGMutablePathRef path = CGPathCreateMutable();
- CGPathAddRect(path, 0, qt_mac_compose_rect(r));
+ CGPathAddRect(path, nullptr, qt_mac_compose_rect(r));
d->drawPath(QCoreGraphicsPaintEnginePrivate::CGFill|QCoreGraphicsPaintEnginePrivate::CGStroke,
path);
CGPathRelease(path);
@@ -698,8 +698,8 @@ QCoreGraphicsPaintEngine::drawPoints(const QPointF *points, int pointCount)
CGMutablePathRef path = CGPathCreateMutable();
for (int i=0; i < pointCount; i++) {
float x = points[i].x(), y = points[i].y();
- CGPathMoveToPoint(path, 0, x, y);
- CGPathAddLineToPoint(path, 0, x+0.001, y);
+ CGPathMoveToPoint(path, nullptr, x, y);
+ CGPathAddLineToPoint(path, nullptr, x+0.001, y);
}
bool doRestore = false;
@@ -745,11 +745,11 @@ QCoreGraphicsPaintEngine::drawPolygon(const QPointF *points, int pointCount, Pol
return;
CGMutablePathRef path = CGPathCreateMutable();
- CGPathMoveToPoint(path, 0, points[0].x(), points[0].y());
+ CGPathMoveToPoint(path, nullptr, points[0].x(), points[0].y());
for (int x = 1; x < pointCount; ++x)
- CGPathAddLineToPoint(path, 0, points[x].x(), points[x].y());
+ CGPathAddLineToPoint(path, nullptr, points[x].x(), points[x].y());
if (mode != PolylineMode && points[0] != points[pointCount-1])
- CGPathAddLineToPoint(path, 0, points[0].x(), points[0].y());
+ CGPathAddLineToPoint(path, nullptr, points[0].x(), points[0].y());
uint op = QCoreGraphicsPaintEnginePrivate::CGStroke;
if (mode != PolylineMode)
op |= mode == OddEvenMode ? QCoreGraphicsPaintEnginePrivate::CGEOFill
@@ -770,8 +770,8 @@ QCoreGraphicsPaintEngine::drawLines(const QLineF *lines, int lineCount)
CGMutablePathRef path = CGPathCreateMutable();
for (int i = 0; i < lineCount; i++) {
const QPointF start = lines[i].p1(), end = lines[i].p2();
- CGPathMoveToPoint(path, 0, start.x(), start.y());
- CGPathAddLineToPoint(path, 0, end.x(), end.y());
+ CGPathMoveToPoint(path, nullptr, start.x(), start.y());
+ CGPathAddLineToPoint(path, nullptr, end.x(), end.y());
}
d->drawPath(QCoreGraphicsPaintEnginePrivate::CGStroke, path);
CGPathRelease(path);
@@ -870,7 +870,7 @@ QCoreGraphicsPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap
CGPatternRef pat = CGPatternCreate(qpattern, CGRectMake(0, 0, width, height),
trans, width, height,
kCGPatternTilingNoDistortion, true, &callbks);
- CGColorSpaceRef cs = CGColorSpaceCreatePattern(0);
+ CGColorSpaceRef cs = CGColorSpaceCreatePattern(nullptr);
CGContextSetFillColorSpace(d->hd, cs);
CGFloat component = 1.0; //just one
CGContextSetFillPattern(d->hd, pat, &component);
@@ -1198,9 +1198,9 @@ void QCoreGraphicsPaintEnginePrivate::setFillBrush(const QPointF &offset)
Q_ASSERT(grad->spread() == QGradient::PadSpread);
static const CGFloat domain[] = { 0.0f, +1.0f };
- static const CGFunctionCallbacks callbacks = { 0, qt_mac_color_gradient_function, 0 };
+ static const CGFunctionCallbacks callbacks = { 0, qt_mac_color_gradient_function, nullptr };
CGFunctionRef fill_func = CGFunctionCreate(reinterpret_cast<void *>(&current.brush),
- 1, domain, 4, 0, &callbacks);
+ 1, domain, 4, nullptr, &callbacks);
CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB)
if (bs == Qt::LinearGradientPattern) {
@@ -1233,7 +1233,7 @@ void QCoreGraphicsPaintEnginePrivate::setFillBrush(const QPointF &offset)
QMacPattern *qpattern = new QMacPattern;
qpattern->pdev = pdev;
CGFloat components[4] = { 1.0, 1.0, 1.0, 1.0 };
- CGColorSpaceRef base_colorspace = 0;
+ CGColorSpaceRef base_colorspace = nullptr;
if (bs == Qt::TexturePattern) {
qpattern->data.pixmap = current.brush.texture();
if (qpattern->data.pixmap.isQBitmap()) {
@@ -1291,7 +1291,7 @@ QCoreGraphicsPaintEnginePrivate::setClip(const QRegion *rgn)
if (!sysClip.isEmpty())
qt_mac_clip_cg(hd, sysClip, &orig_xform);
if (rgn)
- qt_mac_clip_cg(hd, *rgn, 0);
+ qt_mac_clip_cg(hd, *rgn, nullptr);
}
}
@@ -1404,7 +1404,7 @@ void QCoreGraphicsPaintEnginePrivate::drawPath(uchar ops, CGMutablePathRef path)
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(0); //unset the context transform
+ setTransform(nullptr); //unset the context transform
CGContextSetLineWidth(hd, cosmeticPenSize);
CGContextAddPath(hd, t.path);
CGPathRelease(t.path);
diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac_p.h b/src/plugins/platforms/cocoa/qpaintengine_mac_p.h
index c9519ac827..1416386745 100644
--- a/src/plugins/platforms/cocoa/qpaintengine_mac_p.h
+++ b/src/plugins/platforms/cocoa/qpaintengine_mac_p.h
@@ -135,7 +135,7 @@ class QCoreGraphicsPaintEnginePrivate : public QPaintEnginePrivate
Q_DECLARE_PUBLIC(QCoreGraphicsPaintEngine)
public:
QCoreGraphicsPaintEnginePrivate()
- : hd(0), shading(0), stackCount(0), complexXForm(false), disabledSmoothFonts(false)
+ : hd(nullptr), shading(nullptr), stackCount(0), complexXForm(false), disabledSmoothFonts(false)
{
}
@@ -164,8 +164,8 @@ public:
//internal functions
enum { CGStroke=0x01, CGEOFill=0x02, CGFill=0x04 };
- void drawPath(uchar ops, CGMutablePathRef path = 0);
- void setClip(const QRegion *rgn=0);
+ 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);
@@ -174,7 +174,7 @@ public:
float penOffset();
QPointF devicePixelSize(CGContextRef context);
float adjustPenWidth(float penWidth);
- inline void setTransform(const QTransform *matrix=0)
+ inline void setTransform(const QTransform *matrix = nullptr)
{
CGContextConcatCTM(hd, CGAffineTransformInvert(CGContextGetCTM(hd)));
CGAffineTransform xform = orig_xform;
diff --git a/src/plugins/platforms/cocoa/qprintengine_mac.mm b/src/plugins/platforms/cocoa/qprintengine_mac.mm
index eade407500..f2f29b26ee 100644
--- a/src/plugins/platforms/cocoa/qprintengine_mac.mm
+++ b/src/plugins/platforms/cocoa/qprintengine_mac.mm
@@ -117,7 +117,7 @@ bool QMacPrintEngine::end()
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 = 0;
+ static_cast<QCoreGraphicsPaintEngine*>(d->paintEngine)->d_func()->hd = nullptr;
}
d->paintEngine->end();
if (d->state != QPrinter::Idle)
@@ -271,7 +271,7 @@ void QMacPrintEnginePrivate::releaseSession()
PMSessionEndPageNoDialog(session());
PMSessionEndDocumentNoDialog(session());
[printInfo release];
- printInfo = 0;
+ printInfo = nil;
}
bool QMacPrintEnginePrivate::newPage_helper()
@@ -291,7 +291,7 @@ bool QMacPrintEnginePrivate::newPage_helper()
while (cgEngine->d_func()->stackCount > 0)
cgEngine->d_func()->restoreGraphicsState();
- OSStatus status = PMSessionBeginPageNoDialog(session(), format(), 0);
+ OSStatus status = PMSessionBeginPageNoDialog(session(), format(), nullptr);
if (status != noErr) {
state = QPrinter::Error;
return false;
@@ -318,7 +318,7 @@ bool QMacPrintEnginePrivate::newPage_helper()
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(0);
+ cgEngine->d_func()->setClip(nullptr);
cgEngine->state->dirtyFlags = QPaintEngine::DirtyFlag(QPaintEngine::AllDirty
& ~(QPaintEngine::DirtyClipEnabled
| QPaintEngine::DirtyClipRegion
@@ -340,7 +340,7 @@ void QMacPrintEnginePrivate::setPageSize(const QPageSize &pageSize)
// Get the PMPaper and check it is valid
PMPaper macPaper = m_printDevice->macPaper(usePageSize);
- if (macPaper == 0) {
+ if (!macPaper) {
qWarning() << "QMacPrintEngine: Invalid PMPaper returned for " << pageSize;
return;
}
diff --git a/src/plugins/platforms/cocoa/qprintengine_mac_p.h b/src/plugins/platforms/cocoa/qprintengine_mac_p.h
index 9514f3e691..3d94227ae4 100644
--- a/src/plugins/platforms/cocoa/qprintengine_mac_p.h
+++ b/src/plugins/platforms/cocoa/qprintengine_mac_p.h
@@ -134,7 +134,7 @@ public:
QMacPrintEnginePrivate() : mode(QPrinter::ScreenResolution), state(QPrinter::Idle),
m_pageLayout(QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0, 0, 0, 0))),
- printInfo(0), paintEngine(0), embedFonts(true) {}
+ printInfo(nullptr), paintEngine(nullptr), embedFonts(true) {}
~QMacPrintEnginePrivate();
void initialize();
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp
index 38f2352934..9689d6a89b 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp
@@ -48,9 +48,9 @@
#include "qwindowscontext.h"
-#include <QtGui/QPainter>
-#include <QtGui/QWindow>
-#include <QtCore/QDebug>
+#include <QtGui/qpainter.h>
+#include <QtGui/qwindow.h>
+#include <QtCore/qdebug.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp
index 38425f8fa1..2151f3ae95 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp
@@ -42,8 +42,8 @@
#include "qwindowsdirect2dhelpers.h"
#include "qwindowsdirect2ddevicecontext.h"
-#include <QtGui/QImage>
-#include <QtGui/QColor>
+#include <QtGui/qimage.h>
+#include <QtGui/qcolor.h>
#include <wrl.h>
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h
index ef39b6a661..d8a8a49aec 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h
@@ -41,8 +41,8 @@
#define QWINDOWSDIRECT2DBITMAP_H
#include <QtCore/qnamespace.h>
-#include <QtCore/QRect>
-#include <QtCore/QScopedPointer>
+#include <QtCore/qrect.h>
+#include <QtCore/qscopedpointer.h>
struct ID2D1DeviceContext;
struct ID2D1Bitmap1;
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h
index 0d42c65964..5bce056ad1 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h
@@ -40,7 +40,7 @@
#ifndef QWINDOWSDIRECT2DCONTEXT_H
#define QWINDOWSDIRECT2DCONTEXT_H
-#include <QtCore/QScopedPointer>
+#include <QtCore/qscopedpointer.h>
struct ID3D11Device;
struct ID2D1Device;
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h
index 8544f9448b..aee0eb867d 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h
@@ -40,7 +40,7 @@
#ifndef QWINDOWSDIRECT2DDEVICECONTEXT_H
#define QWINDOWSDIRECT2DDEVICECONTEXT_H
-#include <QtCore/QScopedPointer>
+#include <QtCore/qscopedpointer.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h b/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h
index 34225bba9a..babe646fd8 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h
@@ -40,11 +40,11 @@
#ifndef QWINDOWSDIRECT2DHELPERS_H
#define QWINDOWSDIRECT2DHELPERS_H
-#include <QtCore/QRectF>
-#include <QtCore/QSizeF>
-#include <QtCore/QPointF>
-#include <QtGui/QColor>
-#include <QtGui/QTransform>
+#include <QtCore/qrect.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qpoint.h>
+#include <QtGui/qcolor.h>
+#include <QtGui/qtransform.h>
#ifdef Q_CC_MINGW
# include <qt_windows.h>
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp
index 6d98da5be5..173d79cf2b 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp
@@ -47,8 +47,8 @@
#include "qwindowscontext.h"
#include <qplatformdefs.h>
-#include <QtCore/QCoreApplication>
-#include <QtCore/QVersionNumber>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qversionnumber.h>
#include <QtGui/private/qpixmap_raster_p.h>
#include <QtGui/qpa/qwindowsysteminterface.h>
#include <QtEventDispatcherSupport/private/qwindowsguieventdispatcher_p.h>
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h
index 39ca1d0dbf..19c7521eb7 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h
@@ -42,7 +42,7 @@
#include "qwindowsintegration.h"
-#include <QtCore/QScopedPointer>
+#include <QtCore/qscopedpointer.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.cpp
index 711366a0b5..f763c4f7ab 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.cpp
@@ -39,7 +39,7 @@
#include "qwindowsdirect2dnativeinterface.h"
-#include <QtGui/QBackingStore>
+#include <QtGui/qbackingstore.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.h b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.h
index 1f23d604f5..013d7a9b79 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.h
@@ -40,8 +40,8 @@
#ifndef QWINDOWSDIRECT2DPAINTDEVICE_H
#define QWINDOWSDIRECT2DPAINTDEVICE_H
-#include <QtCore/QScopedPointer>
-#include <QtGui/QPaintDevice>
+#include <QtCore/qscopedpointer.h>
+#include <QtGui/qpaintdevice.h>
#include "qwindowsdirect2dpaintengine.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp
index 95fbd37247..d3e1d4dd12 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp
@@ -49,9 +49,9 @@
#include <QtFontDatabaseSupport/private/qwindowsfontengine_p.h>
#include "qwindowsintegration.h"
-#include <QtCore/QtMath>
-#include <QtCore/QStack>
-#include <QtCore/QSettings>
+#include <QtCore/qmath.h>
+#include <QtCore/qstack.h>
+#include <QtCore/qsettings.h>
#include <QtGui/private/qpaintengine_p.h>
#include <QtGui/private/qtextengine_p.h>
#include <QtGui/private/qfontengine_p.h>
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h
index b9616acd6a..6404c60b13 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h
@@ -40,7 +40,7 @@
#ifndef QWINDOWSDIRECT2DPAINTENGINE_H
#define QWINDOWSDIRECT2DPAINTENGINE_H
-#include <QtCore/QScopedPointer>
+#include <QtCore/qscopedpointer.h>
#include <QtGui/private/qpaintengineex_p.h>
struct ID2D1Geometry;
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp
index 65e056d312..fb50e05b3f 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp
@@ -43,10 +43,10 @@
#include "qwindowsdirect2dbitmap.h"
#include "qwindowsdirect2dhelpers.h"
-#include <QtGui/QPainter>
-#include <QtGui/QImage>
-#include <QtGui/QPaintDevice>
-#include <QtGui/QPaintEngine>
+#include <QtGui/qpainter.h>
+#include <QtGui/qimage.h>
+#include <QtGui/qpaintdevice.h>
+#include <QtGui/qpaintengine.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h
index 0448613a95..6bd7852ae0 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h
@@ -42,7 +42,7 @@
#include "qwindowsdirect2dpaintengine.h"
#include <QtGui/qpa/qplatformpixmap.h>
-#include <QtCore/QScopedPointer>
+#include <QtCore/qscopedpointer.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp
index 7393c11dda..6c56d356b7 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp
@@ -40,7 +40,7 @@
#include "qwindowsdirect2dintegration.h"
#include <QtGui/qpa/qplatformintegrationplugin.h>
-#include <QtCore/QStringList>
+#include <QtCore/qstringlist.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/api/qeglfshooks.cpp b/src/plugins/platforms/eglfs/api/qeglfshooks.cpp
index d8332a94cb..ff5c5deee4 100644
--- a/src/plugins/platforms/eglfs/api/qeglfshooks.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfshooks.cpp
@@ -54,6 +54,7 @@ QEglFSDeviceIntegration *qt_egl_device_integration()
#else
+namespace {
class DeviceIntegration
{
public:
@@ -63,6 +64,7 @@ public:
private:
QEglFSDeviceIntegration *m_integration;
};
+}
Q_GLOBAL_STATIC(DeviceIntegration, deviceIntegration)
diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp
index 33878a5f50..43f2e31a49 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp
@@ -415,8 +415,7 @@ static void *eglContextForContext(QOpenGLContext *context)
QPlatformNativeInterface::NativeResourceForContextFunction QEglFSIntegration::nativeResourceFunctionForContext(const QByteArray &resource)
{
#ifndef QT_NO_OPENGL
- QByteArray lowerCaseResource = resource.toLower();
- if (lowerCaseResource == "get_egl_context")
+ if (resource.compare("get_egl_context", Qt::CaseInsensitive) == 0)
return NativeResourceForContextFunction(eglContextForContext);
#else
Q_UNUSED(resource);
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/eglfs_brcm.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/eglfs_brcm.pro
index fee67da2de..aa487be8c0 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/eglfs_brcm.pro
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/eglfs_brcm.pro
@@ -6,7 +6,6 @@ INCLUDEPATH += $$PWD/../../api
CONFIG += egl
LIBS += -lbcm_host
-QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
# Avoid X11 header collision, use generic EGL native types
DEFINES += QT_EGL_NO_X11
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro
index 43170a3875..f5c2c0ed89 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro
@@ -13,7 +13,6 @@ DEFINES += QT_EGL_NO_X11
QMAKE_USE += gbm drm
CONFIG += egl
-QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
SOURCES += $$PWD/qeglfskmsgbmmain.cpp \
$$PWD/qeglfskmsgbmintegration.cpp \
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
index 1b52bdf3ec..24f82e7843 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
@@ -47,6 +47,7 @@
#include <QtCore/QLoggingCategory>
#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qtguiglobal_p.h>
#include <QtFbSupport/private/qfbvthandler_p.h>
#include <errno.h>
@@ -226,17 +227,29 @@ void QEglFSKmsGbmScreen::ensureModeSet(uint32_t fb)
if (doModeSet) {
qCDebug(qLcEglfsKmsDebug, "Setting mode for screen %s", qPrintable(name()));
- int ret = drmModeSetCrtc(fd,
- op.crtc_id,
- fb,
- 0, 0,
- &op.connector_id, 1,
- &op.modes[op.mode]);
-
- if (ret == 0)
- setPowerState(PowerStateOn);
- else
- qErrnoWarning(errno, "Could not set DRM mode for screen %s", qPrintable(name()));
+
+ if (device()->hasAtomicSupport()) {
+#if QT_CONFIG(drm_atomic)
+ drmModeAtomicReq *request = device()->atomic_request();
+ if (request) {
+ drmModeAtomicAddProperty(request, op.connector_id, op.crtcIdPropertyId, op.crtc_id);
+ drmModeAtomicAddProperty(request, op.crtc_id, op.modeIdPropertyId, op.mode_blob_id);
+ drmModeAtomicAddProperty(request, op.crtc_id, op.activePropertyId, 1);
+ }
+#endif
+ } else {
+ int ret = drmModeSetCrtc(fd,
+ op.crtc_id,
+ fb,
+ 0, 0,
+ &op.connector_id, 1,
+ &op.modes[op.mode]);
+
+ if (ret == 0)
+ setPowerState(PowerStateOn);
+ else
+ qErrnoWarning(errno, "Could not set DRM mode for screen %s", qPrintable(name()));
+ }
}
}
}
@@ -259,6 +272,11 @@ void QEglFSKmsGbmScreen::waitForFlip()
drmEvent.page_flip_handler = pageFlipHandler;
drmHandleEvent(device()->fd(), &drmEvent);
}
+
+#if QT_CONFIG(drm_atomic)
+ if (device()->hasAtomicSupport())
+ device()->atomicReset();
+#endif
}
void QEglFSKmsGbmScreen::flip()
@@ -290,34 +308,79 @@ void QEglFSKmsGbmScreen::flip()
QKmsOutput &op(output());
const int fd = device()->fd();
m_flipPending = true;
- int ret = drmModePageFlip(fd,
+
+ if (device()->hasAtomicSupport()) {
+#if QT_CONFIG(drm_atomic)
+ drmModeAtomicReq *request = device()->atomic_request();
+ 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,
+ output().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,
+ output().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);
+
+ static int zpos = qEnvironmentVariableIntValue("QT_QPA_EGLFS_KMS_ZPOS");
+ if (zpos)
+ drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->zposPropertyId, zpos);
+ }
+#endif
+ } else {
+ int ret = drmModePageFlip(fd,
op.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;
+ 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;
+ }
}
for (CloneDestination &d : m_cloneDests) {
if (d.screen != this) {
d.screen->ensureModeSet(fb->fb);
d.cloneFlipPending = true;
- int ret = drmModePageFlip(fd,
- d.screen->output().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()));
- d.cloneFlipPending = false;
+
+ if (device()->hasAtomicSupport()) {
+#if QT_CONFIG(drm_atomic)
+ drmModeAtomicReq *request = device()->atomic_request();
+ 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);
+ }
+#endif
+ } else {
+ int ret = drmModePageFlip(fd,
+ d.screen->output().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()));
+ d.cloneFlipPending = false;
+ }
}
}
}
+
+#if QT_CONFIG(drm_atomic)
+ if (device()->hasAtomicSupport())
+ device()->atomicCommit(this);
+#endif
}
void QEglFSKmsGbmScreen::pageFlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data)
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
index 36f037ac6c..a6145c07e6 100644
--- 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
@@ -9,7 +9,6 @@ DEFINES += QT_EGL_NO_X11
QMAKE_USE += drm
CONFIG += egl
-QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
SOURCES += $$PWD/qeglfskmsegldevicemain.cpp \
$$PWD/qeglfskmsegldeviceintegration.cpp \
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 531b73d1dc..1626c86239 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp
@@ -112,7 +112,7 @@ void QEglFSKmsEglDeviceScreen::waitForFlip()
qCDebug(qLcEglfsKmsDebug, "Setting plane %u", op.forced_plane_id);
int ret = drmModeSetPlane(fd, op.forced_plane_id, op.crtc_id, uint32_t(-1), 0,
0, 0, w, h,
- 0 << 16, 0 << 16, w << 16, h << 16);
+ 0 << 16, 0 << 16, op.size.width() << 16, op.size.height() << 16);
if (ret == -1)
qErrnoWarning(errno, "drmModeSetPlane failed");
}
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
index 4d1321079c..40806b6a9b 100644
--- 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
@@ -11,7 +11,6 @@ DEFINES += QT_EGL_NO_X11
QMAKE_USE += drm
CONFIG += egl
-QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
SOURCES += $$PWD/qeglfskmsintegration.cpp \
$$PWD/qeglfskmsdevice.cpp \
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 06bc272050..a6aac61506 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp
@@ -138,6 +138,10 @@ void *QEglFSKmsIntegration::nativeResourceForIntegration(const QByteArray &name)
if (name == QByteArrayLiteral("dri_fd") && m_device)
return (void *) (qintptr) m_device->fd();
+#if QT_CONFIG(drm_atomic)
+ if (name == QByteArrayLiteral("dri_atomic_request") && m_device)
+ return (void *) (qintptr) m_device->atomic_request();
+#endif
return nullptr;
}
@@ -147,6 +151,8 @@ void *QEglFSKmsIntegration::nativeResourceForScreen(const QByteArray &resource,
if (s) {
if (resource == QByteArrayLiteral("dri_crtcid"))
return (void *) (qintptr) s->output().crtc_id;
+ if (resource == QByteArrayLiteral("dri_connectorid"))
+ return (void *) (qintptr) s->output().connector_id;
}
return nullptr;
}
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 5e45b42abe..e5354d97bd 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
@@ -113,10 +113,9 @@ QRect QEglFSKmsScreen::rawGeometry() const
if (m_headless)
return QRect(QPoint(0, 0), m_device->screenConfig()->headlessSize());
- const int mode = m_output.mode;
return QRect(m_pos.x(), m_pos.y(),
- m_output.modes[mode].hdisplay,
- m_output.modes[mode].vdisplay);
+ m_output.size.width(),
+ m_output.size.height());
}
int QEglFSKmsScreen::depth() const
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
index 826c2f989f..f63b768a38 100644
--- 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
@@ -13,7 +13,6 @@ DEFINES += QT_EGL_NO_X11
QMAKE_USE += gbm drm v4l2
CONFIG += egl
-QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
SOURCES += $$PWD/qeglfskmsvsp2main.cpp \
$$PWD/qeglfskmsvsp2integration.cpp \
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/eglfs_mali.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/eglfs_mali.pro
index 5e6f636e2b..3261a6dbba 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/eglfs_mali.pro
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/eglfs_mali.pro
@@ -7,7 +7,6 @@ DEFINES += QT_EGL_NO_X11
INCLUDEPATH += $$PWD/../../api
CONFIG += egl
-QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
SOURCES += $$PWD/qeglfsmalimain.cpp \
$$PWD/qeglfsmaliintegration.cpp
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/eglfs_rcar.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/eglfs_rcar.pro
index 04236449a0..62acd51cea 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/eglfs_rcar.pro
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_rcar/eglfs_rcar.pro
@@ -5,7 +5,6 @@ QT += core-private gui-private eglfsdeviceintegration-private
INCLUDEPATH += $$PWD/../../api
CONFIG += egl
DEFINES += LINUX=1 EGL_API_FB=1
-QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
SOURCES += $$PWD/qeglfsrcarmain.cpp \
$$PWD/qeglfsrcarintegration.cpp
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/eglfs_viv.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/eglfs_viv.pro
index f9cce8d48b..8d3be9c2ac 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/eglfs_viv.pro
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/eglfs_viv.pro
@@ -5,7 +5,6 @@ QT += core-private gui-private eglfsdeviceintegration-private
INCLUDEPATH += $$PWD/../../api
CONFIG += egl
DEFINES += LINUX=1 EGL_API_FB=1
-QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
SOURCES += $$PWD/qeglfsvivmain.cpp \
$$PWD/qeglfsvivintegration.cpp
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
index 065a103376..45d73e1eb8 100644
--- 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
@@ -5,7 +5,6 @@ QT += core-private gui-private eglfsdeviceintegration-private
INCLUDEPATH += $$PWD/../../api
CONFIG += egl
DEFINES += LINUX=1 EGL_API_FB=1
-QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
SOURCES += $$PWD/qeglfsvivwlmain.cpp \
$$PWD/qeglfsvivwlintegration.cpp
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro
index 391f63615b..acbd1cc785 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/eglfs_x11.pro
@@ -9,7 +9,6 @@ INCLUDEPATH += $$PWD/../../api
CONFIG += egl
QMAKE_USE += xcb_xlib
-QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
SOURCES += $$PWD/qeglfsx11main.cpp \
$$PWD/qeglfsx11integration.cpp
diff --git a/src/plugins/platforms/eglfs/eglfsdeviceintegration.pro b/src/plugins/platforms/eglfs/eglfsdeviceintegration.pro
index 187cbc025f..8bb7b614f1 100644
--- a/src/plugins/platforms/eglfs/eglfsdeviceintegration.pro
+++ b/src/plugins/platforms/eglfs/eglfsdeviceintegration.pro
@@ -27,8 +27,6 @@ DEFINES += QT_BUILD_EGL_DEVICE_LIB
include($$PWD/api/api.pri)
-QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
-
!isEmpty(EGLFS_PLATFORM_HOOKS_SOURCES) {
HEADERS += $$EGLFS_PLATFORM_HOOKS_HEADERS
SOURCES += $$EGLFS_PLATFORM_HOOKS_SOURCES
diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h
index c52d498cd4..201b277494 100644
--- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h
+++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h
@@ -41,8 +41,6 @@
#include "../../qiosfiledialog.h"
-@interface QIOSImagePickerController : UIImagePickerController <UIImagePickerControllerDelegate, UINavigationControllerDelegate> {
- QIOSFileDialog *m_fileDialog;
-}
-- (id)initWithQIOSFileDialog:(QIOSFileDialog *)fileDialog;
+@interface QIOSImagePickerController : UIImagePickerController <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
+- (instancetype)initWithQIOSFileDialog:(QIOSFileDialog *)fileDialog;
@end
diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm
index 78e0f00ab4..79d4ecf83f 100644
--- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm
+++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm
@@ -41,15 +41,17 @@
#include "qiosimagepickercontroller.h"
-@implementation QIOSImagePickerController
+@implementation QIOSImagePickerController {
+ QIOSFileDialog *m_fileDialog;
+}
-- (id)initWithQIOSFileDialog:(QIOSFileDialog *)fileDialog
+- (instancetype)initWithQIOSFileDialog:(QIOSFileDialog *)fileDialog
{
self = [super init];
if (self) {
m_fileDialog = fileDialog;
- [self setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
- [self setDelegate:self];
+ self.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
+ self.delegate = self;
}
return self;
}
@@ -57,8 +59,8 @@
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
Q_UNUSED(picker);
- NSURL *url = [info objectForKey:UIImagePickerControllerReferenceURL];
- QUrl fileUrl = QUrl::fromLocalFile(QString::fromNSString([url description]));
+ NSURL *url = info[UIImagePickerControllerReferenceURL];
+ QUrl fileUrl = QUrl::fromLocalFile(QString::fromNSString(url.description));
m_fileDialog->selectedFilesChanged(QList<QUrl>() << fileUrl);
emit m_fileDialog->accept();
}
diff --git a/src/plugins/platforms/ios/qiosclipboard.mm b/src/plugins/platforms/ios/qiosclipboard.mm
index 9a975eadc9..6bdbf94d3f 100644
--- a/src/plugins/platforms/ios/qiosclipboard.mm
+++ b/src/plugins/platforms/ios/qiosclipboard.mm
@@ -46,11 +46,11 @@
#include <QtGui/QGuiApplication>
@interface UIPasteboard (QUIPasteboard)
- + (UIPasteboard *)pasteboardWithQClipboardMode:(QClipboard::Mode)mode;
++ (instancetype)pasteboardWithQClipboardMode:(QClipboard::Mode)mode;
@end
@implementation UIPasteboard (QUIPasteboard)
-+ (UIPasteboard *)pasteboardWithQClipboardMode:(QClipboard::Mode)mode
++ (instancetype)pasteboardWithQClipboardMode:(QClipboard::Mode)mode
{
NSString *name = (mode == QClipboard::Clipboard) ? UIPasteboardNameGeneral : UIPasteboardNameFind;
return [UIPasteboard pasteboardWithName:name create:NO];
@@ -60,17 +60,15 @@
// --------------------------------------------------------------------
@interface QUIClipboard : NSObject
-{
-@public
+@end
+
+@implementation QUIClipboard {
QIOSClipboard *m_qiosClipboard;
NSInteger m_changeCountClipboard;
NSInteger m_changeCountFindBuffer;
}
-@end
-
-@implementation QUIClipboard
-- (id)initWithQIOSClipboard:(QIOSClipboard *)qiosClipboard
+- (instancetype)initWithQIOSClipboard:(QIOSClipboard *)qiosClipboard
{
self = [super init];
if (self) {
@@ -149,7 +147,7 @@ QStringList QIOSMimeData::formats() const
{
QStringList foundMimeTypes;
UIPasteboard *pb = [UIPasteboard pasteboardWithQClipboardMode:m_mode];
- NSArray *pasteboardTypes = [pb pasteboardTypes];
+ NSArray<NSString *> *pasteboardTypes = [pb pasteboardTypes];
for (NSUInteger i = 0; i < [pasteboardTypes count]; ++i) {
QString uti = QString::fromNSString([pasteboardTypes objectAtIndex:i]);
@@ -164,7 +162,7 @@ QStringList QIOSMimeData::formats() const
QVariant QIOSMimeData::retrieveData(const QString &mimeType, QVariant::Type) const
{
UIPasteboard *pb = [UIPasteboard pasteboardWithQClipboardMode:m_mode];
- NSArray *pasteboardTypes = [pb pasteboardTypes];
+ NSArray<NSString *> *pasteboardTypes = [pb pasteboardTypes];
foreach (QMacInternalPasteboardMime *converter,
QMacInternalPasteboardMime::all(QMacInternalPasteboardMime::MIME_ALL)) {
@@ -213,12 +211,12 @@ void QIOSClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode)
UIPasteboard *pb = [UIPasteboard pasteboardWithQClipboardMode:mode];
if (!mimeData) {
- pb.items = [NSArray array];
+ pb.items = [NSArray<NSDictionary<NSString *, id> *> array];
return;
}
mimeData->deleteLater();
- NSMutableDictionary *pbItem = [NSMutableDictionary dictionaryWithCapacity:mimeData->formats().size()];
+ NSMutableDictionary<NSString *, id> *pbItem = [NSMutableDictionary<NSString *, id> dictionaryWithCapacity:mimeData->formats().size()];
foreach (const QString &mimeType, mimeData->formats()) {
foreach (QMacInternalPasteboardMime *converter,
@@ -246,7 +244,7 @@ void QIOSClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode)
}
}
- pb.items = [NSArray arrayWithObject:pbItem];
+ pb.items = @[pbItem];
}
bool QIOSClipboard::supportsMode(QClipboard::Mode mode) const
diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm
index 06e5e6cb80..776343c5aa 100644
--- a/src/plugins/platforms/ios/qioseventdispatcher.mm
+++ b/src/plugins/platforms/ios/qioseventdispatcher.mm
@@ -204,6 +204,11 @@ namespace
jmp_buf applicationWillTerminateJumpPoint;
bool debugStackUsage = false;
+
+ struct {
+ QAppleLogActivity UIApplicationMain;
+ QAppleLogActivity applicationDidFinishLaunching;
+ } logActivity;
}
extern "C" int qt_main_wrapper(int argc, char *argv[])
@@ -228,6 +233,9 @@ extern "C" int qt_main_wrapper(int argc, char *argv[])
}
}
+ logActivity.UIApplicationMain = QT_APPLE_LOG_ACTIVITY(
+ lcEventDispatcher().isDebugEnabled(), "UIApplicationMain").enter();
+
qCDebug(lcEventDispatcher) << "Running UIApplicationMain";
return UIApplicationMain(argc, argv, nil, NSStringFromClass([QIOSApplicationDelegate class]));
}
@@ -245,7 +253,7 @@ extern "C" int main(int argc, char *argv[]);
static void __attribute__((noinline, noreturn)) user_main_trampoline()
{
- NSArray *arguments = [[NSProcessInfo processInfo] arguments];
+ NSArray<NSString *> *arguments = [[NSProcessInfo processInfo] arguments];
int argc = arguments.count;
char **argv = new char*[argc];
@@ -263,11 +271,14 @@ static void __attribute__((noinline, noreturn)) user_main_trampoline()
int exitCode = main(argc, argv);
delete[] argv;
+ logActivity.applicationDidFinishLaunching.enter();
qCDebug(lcEventDispatcher) << "Returned from main with exit code " << exitCode;
if (Q_UNLIKELY(debugStackUsage))
userMainStack.printUsage();
+ logActivity.applicationDidFinishLaunching.leave();
+
if (applicationAboutToTerminate)
longjmp(applicationWillTerminateJumpPoint, kJumpedFromUserMainTrampoline);
@@ -322,6 +333,9 @@ static bool rootLevelRunLoopIntegration()
+ (void)applicationDidFinishLaunching:(NSNotification *)notification
{
+ logActivity.applicationDidFinishLaunching = QT_APPLE_LOG_ACTIVITY_WITH_PARENT(
+ lcEventDispatcher().isDebugEnabled(), "applicationDidFinishLaunching", logActivity.UIApplicationMain).enter();
+
qCDebug(lcEventDispatcher) << "Application launched with options" << notification.userInfo;
if (!isQtApplication())
@@ -339,10 +353,11 @@ static bool rootLevelRunLoopIntegration()
return;
}
-
switch (setjmp(processEventEnterJumpPoint)) {
- case kJumpPointSetSuccessfully:
+ case kJumpPointSetSuccessfully: {
qCDebug(lcEventDispatcher) << "Running main() on separate stack";
+ QT_APPLE_SCOPED_LOG_ACTIVITY(lcEventDispatcher().isDebugEnabled(), "main()");
+
// Redirect the stack pointer to the start of the reserved stack. This ensures
// that when we longjmp out of the event dispatcher and continue execution, the
// 'Qt main' call-stack will not be smashed, as it lives in a part of the stack
@@ -357,9 +372,11 @@ static bool rootLevelRunLoopIntegration()
Q_UNREACHABLE();
break;
+ }
case kJumpedFromEventDispatcherProcessEvents:
// We've returned from the longjmp in the event dispatcher,
// and the stack has been restored to its old self.
+ logActivity.UIApplicationMain.enter();
qCDebug(lcEventDispatcher) << "↳ Jumped from processEvents due to exec";
if (Q_UNLIKELY(debugStackUsage))
@@ -378,6 +395,10 @@ static const char kApplicationWillTerminateExitCode = char(SIGTERM | 0x80);
+ (void)applicationWillTerminate
{
+ QAppleLogActivity applicationWillTerminateActivity = QT_APPLE_LOG_ACTIVITY_WITH_PARENT(
+ lcEventDispatcher().isDebugEnabled(), "applicationWillTerminate", logActivity.UIApplicationMain).enter();
+ qCDebug(lcEventDispatcher) << "Application about to be terminated by iOS";
+
if (!isQtApplication())
return;
@@ -403,11 +424,14 @@ static const char kApplicationWillTerminateExitCode = char(SIGTERM | 0x80);
// so we'll never see the exit activity and have a chance to return from
// QEventLoop::exec(). We initiate the return manually as a workaround.
qCDebug(lcEventDispatcher) << "Manually triggering return from event loop exec";
+ applicationWillTerminateActivity.leave();
static_cast<QIOSJumpingEventDispatcher *>(qApp->eventDispatcher())->interruptEventLoopExec();
break;
case kJumpedFromUserMainTrampoline:
+ applicationWillTerminateActivity.enter();
// The user's main has returned, so we're ready to let iOS terminate the application
qCDebug(lcEventDispatcher) << "kJumpedFromUserMainTrampoline, allowing iOS to terminate";
+ applicationWillTerminateActivity.leave();
break;
default:
qFatal("Unexpected jump result in event loop integration");
@@ -446,8 +470,10 @@ bool QIOSEventDispatcher::processPostedEvents()
if (!QEventDispatcherCoreFoundation::processPostedEvents())
return false;
- qCDebug(lcEventDispatcher) << "Sending window system events for" << m_processEvents.flags;
- QWindowSystemInterface::sendWindowSystemEvents(m_processEvents.flags);
+ QT_APPLE_SCOPED_LOG_ACTIVITY(lcEventDispatcher().isDebugEnabled(), "sendWindowSystemEvents");
+ QEventLoop::ProcessEventsFlags flags = QEventLoop::ProcessEventsFlags(m_processEvents.flags.load());
+ qCDebug(lcEventDispatcher) << "Sending window system events for" << flags;
+ QWindowSystemInterface::sendWindowSystemEvents(flags);
return true;
}
@@ -469,6 +495,7 @@ bool __attribute__((returns_twice)) QIOSJumpingEventDispatcher::processEvents(QE
}
if (!m_processEventLevel && (flags & QEventLoop::EventLoopExec)) {
+ QT_APPLE_SCOPED_LOG_ACTIVITY(lcEventDispatcher().isDebugEnabled(), "processEvents");
qCDebug(lcEventDispatcher) << "Processing events with flags" << flags;
++m_processEventLevel;
@@ -526,10 +553,12 @@ void QIOSJumpingEventDispatcher::interruptEventLoopExec()
switch (setjmp(processEventEnterJumpPoint)) {
case kJumpPointSetSuccessfully:
qCDebug(lcEventDispatcher) << "Jumping into processEvents due to system runloop exit ⇢";
+ logActivity.UIApplicationMain.leave();
longjmp(processEventExitJumpPoint, kJumpedFromEventLoopExecInterrupt);
break;
case kJumpedFromEventDispatcherProcessEvents:
// QEventLoop was re-executed
+ logActivity.UIApplicationMain.enter();
qCDebug(lcEventDispatcher) << "↳ Jumped from processEvents due to re-exec";
break;
default:
diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm
index 493c283ec1..d2229df133 100644
--- a/src/plugins/platforms/ios/qiosinputcontext.mm
+++ b/src/plugins/platforms/ios/qiosinputcontext.mm
@@ -69,7 +69,7 @@ static QUIView *focusView()
@implementation QIOSLocaleListener
-- (id)init
+- (instancetype)init
{
if (self = [super init]) {
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
@@ -97,16 +97,15 @@ static QUIView *focusView()
// -------------------------------------------------------------------------
-@interface QIOSKeyboardListener : UIGestureRecognizer <UIGestureRecognizerDelegate> {
- @private
- QT_PREPEND_NAMESPACE(QIOSInputContext) *m_context;
-}
+@interface QIOSKeyboardListener : UIGestureRecognizer <UIGestureRecognizerDelegate>
@property BOOL hasDeferredScrollToCursor;
@end
-@implementation QIOSKeyboardListener
+@implementation QIOSKeyboardListener {
+ QT_PREPEND_NAMESPACE(QIOSInputContext) *m_context;
+}
-- (id)initWithQIOSInputContext:(QT_PREPEND_NAMESPACE(QIOSInputContext) *)context
+- (instancetype)initWithQIOSInputContext:(QT_PREPEND_NAMESPACE(QIOSInputContext) *)context
{
if (self = [super initWithTarget:self action:@selector(gestureStateChanged:)]) {
@@ -581,7 +580,7 @@ void QIOSInputContext::scroll(int y)
// Raise all known windows to above the status-bar if we're scrolling the screen,
// while keeping the relative window level between the windows the same.
- NSArray *applicationWindows = [qt_apple_sharedApplication() windows];
+ NSArray<UIWindow *> *applicationWindows = [qt_apple_sharedApplication() windows];
static QHash<UIWindow *, UIWindowLevel> originalWindowLevels;
for (UIWindow *window in applicationWindows) {
if (keyboardScrollIsActive && !originalWindowLevels.contains(window))
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
index ed2bfbc0d8..bec8354fcc 100644
--- a/src/plugins/platforms/ios/qiosintegration.mm
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -100,7 +100,7 @@ QIOSIntegration::QIOSIntegration()
void QIOSIntegration::initialize()
{
UIScreen *mainScreen = [UIScreen mainScreen];
- NSMutableArray *screens = [[[UIScreen screens] mutableCopy] autorelease];
+ NSMutableArray<UIScreen *> *screens = [[[UIScreen screens] mutableCopy] autorelease];
if (![screens containsObject:mainScreen]) {
// Fallback for iOS 7.1 (QTBUG-42345)
[screens insertObject:mainScreen atIndex:0];
@@ -115,10 +115,8 @@ void QIOSIntegration::initialize()
m_touchDevice = new QTouchDevice;
m_touchDevice->setType(QTouchDevice::TouchScreen);
QTouchDevice::Capabilities touchCapabilities = QTouchDevice::Position | QTouchDevice::NormalizedPosition;
- if (__builtin_available(iOS 9, *)) {
- if (mainScreen.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable)
- touchCapabilities |= QTouchDevice::Pressure;
- }
+ if (mainScreen.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable)
+ touchCapabilities |= QTouchDevice::Pressure;
m_touchDevice->setCapabilities(touchCapabilities);
QWindowSystemInterface::registerTouchDevice(m_touchDevice);
#if QT_CONFIG(tabletevent)
diff --git a/src/plugins/platforms/ios/qiosmenu.mm b/src/plugins/platforms/ios/qiosmenu.mm
index 6c70676a31..74a77de757 100644
--- a/src/plugins/platforms/ios/qiosmenu.mm
+++ b/src/plugins/platforms/ios/qiosmenu.mm
@@ -60,14 +60,14 @@ QIOSMenu *QIOSMenu::m_currentMenu = 0;
static NSString *const kSelectorPrefix = @"_qtMenuItem_";
-@interface QUIMenuController : UIResponder {
- QIOSMenuItemList m_visibleMenuItems;
-}
+@interface QUIMenuController : UIResponder
@end
-@implementation QUIMenuController
+@implementation QUIMenuController {
+ QIOSMenuItemList m_visibleMenuItems;
+}
-- (id)initWithVisibleMenuItems:(const QIOSMenuItemList &)visibleMenuItems
+- (instancetype)initWithVisibleMenuItems:(const QIOSMenuItemList &)visibleMenuItems
{
if (self = [super init]) {
[self setVisibleMenuItems:visibleMenuItems];
@@ -80,7 +80,7 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_";
return self;
}
--(void)dealloc
+- (void)dealloc
{
[[NSNotificationCenter defaultCenter]
removeObserver:self
@@ -91,7 +91,7 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_";
- (void)setVisibleMenuItems:(const QIOSMenuItemList &)visibleMenuItems
{
m_visibleMenuItems = visibleMenuItems;
- NSMutableArray *menuItemArray = [NSMutableArray arrayWithCapacity:m_visibleMenuItems.size()];
+ NSMutableArray<UIMenuItem *> *menuItemArray = [NSMutableArray<UIMenuItem *> arrayWithCapacity:m_visibleMenuItems.size()];
// Create an array of UIMenuItems, one for each visible QIOSMenuItem. Each
// UIMenuItem needs a callback assigned, so we assign one of the placeholder methods
// added to UIWindow (QIOSMenuActionTargets) below. Each method knows its own index, which
@@ -107,7 +107,7 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_";
[[UIMenuController sharedMenuController] setMenuVisible:YES animated:NO];
}
--(void)menuClosed
+- (void)menuClosed
{
QIOSMenu::currentMenu()->dismiss();
}
@@ -141,19 +141,19 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_";
// -------------------------------------------------------------------------
-@interface QUIPickerView : UIPickerView <UIPickerViewDelegate, UIPickerViewDataSource> {
- QIOSMenuItemList m_visibleMenuItems;
- QPointer<QObject> m_focusObjectWithPickerView;
- NSInteger m_selectedRow;
-}
+@interface QUIPickerView : UIPickerView <UIPickerViewDelegate, UIPickerViewDataSource>
@property(retain) UIToolbar *toolbar;
@end
-@implementation QUIPickerView
+@implementation QUIPickerView {
+ QIOSMenuItemList m_visibleMenuItems;
+ QPointer<QObject> m_focusObjectWithPickerView;
+ NSInteger m_selectedRow;
+}
-- (id)initWithVisibleMenuItems:(const QIOSMenuItemList &)visibleMenuItems selectItem:(const QIOSMenuItem *)selectItem
+- (instancetype)initWithVisibleMenuItems:(const QIOSMenuItemList &)visibleMenuItems selectItem:(const QIOSMenuItem *)selectItem
{
if (self = [super init]) {
[self setVisibleMenuItems:visibleMenuItems selectItem:selectItem];
@@ -172,7 +172,7 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_";
UIBarButtonItem *doneButton = [[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self action:@selector(closeMenu)] autorelease];
- [self.toolbar setItems:[NSArray arrayWithObjects:cancelButton, spaceButton, doneButton, nil]];
+ [self.toolbar setItems:@[cancelButton, spaceButton, doneButton]];
[self setDelegate:self];
[self setDataSource:self];
diff --git a/src/plugins/platforms/ios/qiosmessagedialog.h b/src/plugins/platforms/ios/qiosmessagedialog.h
index 92a4db8319..913fe0c2e9 100644
--- a/src/plugins/platforms/ios/qiosmessagedialog.h
+++ b/src/plugins/platforms/ios/qiosmessagedialog.h
@@ -63,6 +63,7 @@ private:
UIAlertController *m_alertController;
QString messageTextPlain();
UIAlertAction *createAction(StandardButton button);
+ UIAlertAction *createAction(const QMessageDialogOptions::CustomButton &customButton);
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosmessagedialog.mm b/src/plugins/platforms/ios/qiosmessagedialog.mm
index a7de9b473a..254922701a 100644
--- a/src/plugins/platforms/ios/qiosmessagedialog.mm
+++ b/src/plugins/platforms/ios/qiosmessagedialog.mm
@@ -79,6 +79,18 @@ inline QString QIOSMessageDialog::messageTextPlain()
return text;
}
+inline UIAlertAction *QIOSMessageDialog::createAction(
+ const QMessageDialogOptions::CustomButton &customButton)
+{
+ const QString label = QPlatformTheme::removeMnemonics(customButton.label);
+ const UIAlertActionStyle style = UIAlertActionStyleDefault;
+
+ return [UIAlertAction actionWithTitle:label.toNSString() style:style handler:^(UIAlertAction *) {
+ hide();
+ emit clicked(static_cast<QPlatformDialogHelper::StandardButton>(customButton.id), customButton.role);
+ }];
+}
+
inline UIAlertAction *QIOSMessageDialog::createAction(StandardButton button)
{
const StandardButton labelButton = button == NoButton ? Ok : button;
@@ -118,12 +130,18 @@ bool QIOSMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality win
message:messageTextPlain().toNSString()
preferredStyle:UIAlertControllerStyleAlert] retain];
+ const QVector<QMessageDialogOptions::CustomButton> customButtons = options()->customButtons();
+ for (const QMessageDialogOptions::CustomButton &button : customButtons) {
+ UIAlertAction *act = createAction(button);
+ [m_alertController addAction:act];
+ }
+
if (StandardButtons buttons = options()->standardButtons()) {
for (int i = FirstButton; i < LastButton; i<<=1) {
if (i & buttons)
[m_alertController addAction:createAction(StandardButton(i))];
}
- } else {
+ } else if (customButtons.isEmpty()) {
// We need at least one button to allow the user close the dialog
[m_alertController addAction:createAction(NoButton)];
}
diff --git a/src/plugins/platforms/ios/qiosoptionalplugininterface.h b/src/plugins/platforms/ios/qiosoptionalplugininterface.h
index 660c74e856..bae9e5a0d8 100644
--- a/src/plugins/platforms/ios/qiosoptionalplugininterface.h
+++ b/src/plugins/platforms/ios/qiosoptionalplugininterface.h
@@ -44,10 +44,10 @@
#include "qiosfiledialog.h"
-QT_BEGIN_NAMESPACE
-
Q_FORWARD_DECLARE_OBJC_CLASS(UIViewController);
+QT_BEGIN_NAMESPACE
+
#define QIosOptionalPluginInterface_iid "org.qt-project.Qt.QPA.ios.optional"
class QIosOptionalPluginInterface
diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm
index f367d1e75e..4f753be21a 100644
--- a/src/plugins/platforms/ios/qiosscreen.mm
+++ b/src/plugins/platforms/ios/qiosscreen.mm
@@ -132,16 +132,14 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen)
// -------------------------------------------------------------------------
-@interface QIOSOrientationListener : NSObject {
- @public
- QIOSScreen *m_screen;
-}
-- (id)initWithQIOSScreen:(QIOSScreen *)screen;
+@interface QIOSOrientationListener : NSObject
@end
-@implementation QIOSOrientationListener
+@implementation QIOSOrientationListener {
+ QIOSScreen *m_screen;
+}
-- (id)initWithQIOSScreen:(QIOSScreen *)screen
+- (instancetype)initWithQIOSScreen:(QIOSScreen *)screen
{
self = [super init];
if (self) {
@@ -195,7 +193,7 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen)
@implementation QUIWindow
-- (id)initWithFrame:(CGRect)frame
+- (instancetype)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame]))
self->_sendingEvent = NO;
@@ -399,17 +397,21 @@ void QIOSScreen::deliverUpdateRequests() const
QList<QWindow*> windows = QGuiApplication::allWindows();
for (int i = 0; i < windows.size(); ++i) {
- if (platformScreenForWindow(windows.at(i)) != this)
+ QWindow *window = windows.at(i);
+ if (platformScreenForWindow(window) != this)
continue;
- QWindowPrivate *wp = static_cast<QWindowPrivate *>(QObjectPrivate::get(windows.at(i)));
- if (!wp->updateRequestPending)
+ QPlatformWindow *platformWindow = window->handle();
+ if (!platformWindow)
continue;
- wp->deliverUpdateRequest();
+ if (!platformWindow->hasPendingUpdateRequest())
+ continue;
+
+ platformWindow->deliverUpdateRequest();
// Another update request was triggered, keep the display link running
- if (wp->updateRequestPending)
+ if (platformWindow->hasPendingUpdateRequest())
pauseUpdates = false;
}
@@ -454,12 +456,7 @@ qreal QIOSScreen::devicePixelRatio() const
qreal QIOSScreen::refreshRate() const
{
-#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_NA, 100300, 110000, __WATCHOS_NA)
- if (__builtin_available(iOS 10.3, tvOS 11, *))
- return m_uiScreen.maximumFramesPerSecond;
-#endif
-
- return 60.0;
+ return m_uiScreen.maximumFramesPerSecond;
}
Qt::ScreenOrientation QIOSScreen::nativeOrientation() const
diff --git a/src/plugins/platforms/ios/qiostextinputoverlay.mm b/src/plugins/platforms/ios/qiostextinputoverlay.mm
index 87c282e24a..e5419b1766 100644
--- a/src/plugins/platforms/ios/qiostextinputoverlay.mm
+++ b/src/plugins/platforms/ios/qiostextinputoverlay.mm
@@ -97,7 +97,7 @@ static void executeBlockWithoutAnimation(Block block)
@implementation QIOSEditMenu
-- (id)init
+- (instancetype)init
{
if (self = [super init]) {
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
@@ -161,7 +161,13 @@ static void executeBlockWithoutAnimation(Block block)
// -------------------------------------------------------------------------
-@interface QIOSLoupeLayer : CALayer {
+@interface QIOSLoupeLayer : CALayer
+@property (nonatomic, retain) UIView *targetView;
+@property (nonatomic, assign) CGPoint focalPoint;
+@property (nonatomic, assign) BOOL visible;
+@end
+
+@implementation QIOSLoupeLayer {
UIView *_snapshotView;
BOOL _pendingSnapshotUpdate;
UIView *_loupeImageView;
@@ -169,14 +175,8 @@ static void executeBlockWithoutAnimation(Block block)
CGFloat _loupeOffset;
QTimer _updateTimer;
}
-@property (nonatomic, retain) UIView *targetView;
-@property (nonatomic, assign) CGPoint focalPoint;
-@property (nonatomic, assign) BOOL visible;
-@end
-@implementation QIOSLoupeLayer
-
-- (id)initWithSize:(CGSize)size cornerRadius:(CGFloat)cornerRadius bottomOffset:(CGFloat)bottomOffset
+- (instancetype)initWithSize:(CGSize)size cornerRadius:(CGFloat)cornerRadius bottomOffset:(CGFloat)bottomOffset
{
if (self = [super init]) {
_loupeOffset = bottomOffset + (size.height / 2);
@@ -302,26 +302,22 @@ static void executeBlockWithoutAnimation(Block block)
// -------------------------------------------------------------------------
-#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_10_0)
-@interface QIOSHandleLayer : CALayer <CAAnimationDelegate> {
-#else
-@interface QIOSHandleLayer : CALayer {
-#endif
- CALayer *_handleCursorLayer;
- CALayer *_handleKnobLayer;
- Qt::Edge _selectionEdge;
-}
+@interface QIOSHandleLayer : CALayer <CAAnimationDelegate>
@property (nonatomic, assign) CGRect cursorRectangle;
@property (nonatomic, assign) CGFloat handleScale;
@property (nonatomic, assign) BOOL visible;
@property (nonatomic, copy) Block onAnimationDidStop;
@end
-@implementation QIOSHandleLayer
+@implementation QIOSHandleLayer {
+ CALayer *_handleCursorLayer;
+ CALayer *_handleKnobLayer;
+ Qt::Edge _selectionEdge;
+}
@dynamic handleScale;
-- (id)initWithKnobAtEdge:(Qt::Edge)selectionEdge
+- (instancetype)initWithKnobAtEdge:(Qt::Edge)selectionEdge
{
if (self = [super init]) {
CGColorRef bgColor = [UIColor colorWithRed:0.1 green:0.4 blue:0.9 alpha:1].CGColor;
@@ -356,16 +352,8 @@ static void executeBlockWithoutAnimation(Block block)
// The handle should "bounce" in when becoming visible
CAKeyframeAnimation * animation = [CAKeyframeAnimation animationWithKeyPath:key];
[animation setDuration:0.5];
- animation.values = [NSArray arrayWithObjects:
- [NSNumber numberWithFloat:0],
- [NSNumber numberWithFloat:1.3],
- [NSNumber numberWithFloat:1.3],
- [NSNumber numberWithFloat:1], nil];
- animation.keyTimes = [NSArray arrayWithObjects:
- [NSNumber numberWithFloat:0],
- [NSNumber numberWithFloat:0.3],
- [NSNumber numberWithFloat:0.9],
- [NSNumber numberWithFloat:1], nil];
+ animation.values = @[@(0.0f), @(1.3f), @(1.3f), @(1.0f)];
+ animation.keyTimes = @[@(0.0f), @(0.3f), @(0.9f), @(1.0f)];
return animation;
} else {
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:key];
@@ -437,8 +425,13 @@ static void executeBlockWithoutAnimation(Block block)
below will inherit. It takes care of creating and showing a magnifier
glass depending on the current gesture state.
*/
-@interface QIOSLoupeRecognizer : UIGestureRecognizer <UIGestureRecognizerDelegate> {
-@public
+@interface QIOSLoupeRecognizer : UIGestureRecognizer <UIGestureRecognizerDelegate>
+@property (nonatomic, assign) QPointF focalPoint;
+@property (nonatomic, assign) BOOL dragTriggersGesture;
+@property (nonatomic, readonly) UIView *focusView;
+@end
+
+@implementation QIOSLoupeRecognizer {
QIOSLoupeLayer *_loupeLayer;
UIView *_desktopView;
CGPoint _firstTouchPoint;
@@ -446,14 +439,8 @@ static void executeBlockWithoutAnimation(Block block)
QTimer _triggerStateBeganTimer;
int _originalCursorFlashTime;
}
-@property (nonatomic, assign) QPointF focalPoint;
-@property (nonatomic, assign) BOOL dragTriggersGesture;
-@property (nonatomic, readonly) UIView *focusView;
-@end
-@implementation QIOSLoupeRecognizer
-
-- (id)init
+- (instancetype)init
{
if (self = [super initWithTarget:self action:@selector(gestureStateChanged)]) {
self.enabled = NO;
@@ -658,7 +645,10 @@ static void executeBlockWithoutAnimation(Block block)
on the sides. If the user starts dragging on a handle (or do a press and
hold), it will show a magnifier glass that follows the handle as it moves.
*/
-@interface QIOSSelectionRecognizer : QIOSLoupeRecognizer {
+@interface QIOSSelectionRecognizer : QIOSLoupeRecognizer
+@end
+
+@implementation QIOSSelectionRecognizer {
CALayer *_clipRectLayer;
QIOSHandleLayer *_cursorLayer;
QIOSHandleLayer *_anchorLayer;
@@ -670,11 +660,8 @@ static void executeBlockWithoutAnimation(Block block)
QMetaObject::Connection _anchorConnection;
QMetaObject::Connection _clipRectConnection;
}
-@end
-
-@implementation QIOSSelectionRecognizer
-- (id)init
+- (instancetype)init
{
if (self = [super init]) {
self.delaysTouchesBegan = YES;
@@ -890,15 +877,15 @@ static void executeBlockWithoutAnimation(Block block)
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.
*/
-@interface QIOSTapRecognizer : UITapGestureRecognizer {
+@interface QIOSTapRecognizer : UITapGestureRecognizer
+@end
+
+@implementation QIOSTapRecognizer {
int _cursorPosOnPress;
UIView *_focusView;
}
-@end
-
-@implementation QIOSTapRecognizer
-- (id)init
+- (instancetype)init
{
if (self = [super initWithTarget:self action:@selector(gestureStateChanged)]) {
self.enabled = NO;
diff --git a/src/plugins/platforms/ios/qiostextresponder.h b/src/plugins/platforms/ios/qiostextresponder.h
index 77be2cf2fe..074598c1c3 100644
--- a/src/plugins/platforms/ios/qiostextresponder.h
+++ b/src/plugins/platforms/ios/qiostextresponder.h
@@ -49,16 +49,8 @@ class QIOSInputContext;
QT_END_NAMESPACE
@interface QIOSTextInputResponder : UIResponder <UITextInputTraits, UIKeyInput, UITextInput>
-{
- @private
- QT_PREPEND_NAMESPACE(QIOSInputContext) *m_inputContext;
- QT_PREPEND_NAMESPACE(QInputMethodQueryEvent) *m_configuredImeState;
- QString m_markedText;
- BOOL m_inSendEventToFocusObject;
- BOOL m_inSelectionChange;
-}
-- (id)initWithInputContext:(QT_PREPEND_NAMESPACE(QIOSInputContext) *)context;
+- (instancetype)initWithInputContext:(QT_PREPEND_NAMESPACE(QIOSInputContext) *)context;
- (BOOL)needsKeyboardReconfigure:(Qt::InputMethodQueries)updatedProperties;
- (void)notifyInputDelegate:(Qt::InputMethodQueries)updatedProperties;
diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm
index b029c49a67..396c769be8 100644
--- a/src/plugins/platforms/ios/qiostextresponder.mm
+++ b/src/plugins/platforms/ios/qiostextresponder.mm
@@ -55,13 +55,13 @@
@interface QUITextPosition : UITextPosition
@property (nonatomic) NSUInteger index;
-+ (QUITextPosition *)positionWithIndex:(NSUInteger)index;
++ (instancetype)positionWithIndex:(NSUInteger)index;
@end
@implementation QUITextPosition
-+ (QUITextPosition *)positionWithIndex:(NSUInteger)index
++ (instancetype)positionWithIndex:(NSUInteger)index
{
QUITextPosition *pos = [[QUITextPosition alloc] init];
pos.index = index;
@@ -75,15 +75,15 @@
@interface QUITextRange : UITextRange
@property (nonatomic) NSRange range;
-+ (QUITextRange *)rangeWithNSRange:(NSRange)range;
++ (instancetype)rangeWithNSRange:(NSRange)range;
@end
@implementation QUITextRange
-+ (QUITextRange *)rangeWithNSRange:(NSRange)nsrange
++ (instancetype)rangeWithNSRange:(NSRange)nsrange
{
- QUITextRange *range = [[QUITextRange alloc] init];
+ QUITextRange *range = [[self alloc] init];
range.range = nsrange;
return [range autorelease];
}
@@ -117,7 +117,7 @@
@implementation WrapperView
-- (id)initWithView:(UIView *)view
+- (instancetype)initWithView:(UIView *)view
{
if (self = [self init]) {
[self addSubview:view];
@@ -132,7 +132,7 @@
- (void)layoutSubviews
{
- UIView* view = [self.subviews firstObject];
+ UIView *view = [self.subviews firstObject];
view.frame = self.bounds;
// FIXME: During orientation changes the size and position
@@ -161,9 +161,15 @@
// -------------------------------------------------------------------------
-@implementation QIOSTextInputResponder
+@implementation QIOSTextInputResponder {
+ QT_PREPEND_NAMESPACE(QIOSInputContext) *m_inputContext;
+ QT_PREPEND_NAMESPACE(QInputMethodQueryEvent) *m_configuredImeState;
+ QString m_markedText;
+ BOOL m_inSendEventToFocusObject;
+ BOOL m_inSelectionChange;
+}
-- (id)initWithInputContext:(QT_PREPEND_NAMESPACE(QIOSInputContext) *)inputContext
+- (instancetype)initWithInputContext:(QT_PREPEND_NAMESPACE(QIOSInputContext) *)inputContext
{
if (!(self = [self init]))
return self;
@@ -238,17 +244,15 @@
self.inputAccessoryView = [[[WrapperView alloc] initWithView:accessoryView] autorelease];
#ifndef Q_OS_TVOS
- if (__builtin_available(iOS 9, *)) {
- 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
- // compiler warnings. Still it is the way to go to really hide the space reserved for that.
+ 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
+ // compiler warnings. Still it is the way to go to really hide the space reserved for that.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnonnull"
- self.inputAssistantItem.leadingBarButtonGroups = nil;
- self.inputAssistantItem.trailingBarButtonGroups = nil;
+ self.inputAssistantItem.leadingBarButtonGroups = nil;
+ self.inputAssistantItem.trailingBarButtonGroups = nil;
#pragma clang diagnostic pop
- }
}
#endif
@@ -548,7 +552,7 @@
[self sendKeyPressRelease:key modifiers:modifiers];
}
-- (void)addKeyCommandsToArray:(NSMutableArray *)array key:(NSString *)key
+- (void)addKeyCommandsToArray:(NSMutableArray<UIKeyCommand *> *)array key:(NSString *)key
{
SEL s = @selector(keyCommandTriggered:);
[array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:0 action:s]];
@@ -559,19 +563,19 @@
[array addObject:[UIKeyCommand keyCommandWithInput:key modifierFlags:UIKeyModifierCommand|UIKeyModifierShift action:s]];
}
-- (NSArray *)keyCommands
+- (NSArray<UIKeyCommand *> *)keyCommands
{
// Since keyCommands is called for every key
// press/release, we cache the result
static dispatch_once_t once;
- static NSMutableArray *array;
+ static NSMutableArray<UIKeyCommand *> *array;
dispatch_once(&once, ^{
// We let Qt move the cursor around when the arrow keys are being used. This
// is normally implemented through UITextInput, but since IM in Qt have poor
// support for moving the cursor vertically, and even less support for selecting
// text across multiple paragraphs, we do this through key events.
- array = [NSMutableArray new];
+ array = [NSMutableArray<UIKeyCommand *> new];
[self addKeyCommandsToArray:array key:UIKeyInputUpArrow];
[self addKeyCommandsToArray:array key:UIKeyInputDownArrow];
[self addKeyCommandsToArray:array key:UIKeyInputLeftArrow];
@@ -825,13 +829,13 @@
return startRect.united(endRect).toCGRect();
}
-- (NSArray *)selectionRectsForRange:(UITextRange *)range
+- (NSArray<UITextSelectionRect *> *)selectionRectsForRange:(UITextRange *)range
{
Q_UNUSED(range);
// This method is supposed to return a rectangle for each line with selection. Since we don't
// expose an API in Qt/IM for getting this information, and since we never seems to be getting
// a call from UIKit for this, we return an empty array until a need arise.
- return [[NSArray new] autorelease];
+ return [[NSArray<UITextSelectionRect *> new] autorelease];
}
- (CGRect)caretRectForPosition:(UITextPosition *)position
@@ -916,7 +920,7 @@
QObject *focusObject = QGuiApplication::focusObject();
if (!focusObject)
- return [NSDictionary dictionary];
+ return @{};
// Assume position is the same as the cursor for now. QInputMethodQueryEvent with Qt::ImFont
// needs to be extended to take an extra position argument before this can be fully correct.
@@ -925,8 +929,8 @@
QFont qfont = qvariant_cast<QFont>(e.value(Qt::ImFont));
UIFont *uifont = [UIFont fontWithName:qfont.family().toNSString() size:qfont.pointSize()];
if (!uifont)
- return [NSDictionary dictionary];
- return [NSDictionary dictionaryWithObject:uifont forKey:NSFontAttributeName];
+ return @{};
+ return @{NSFontAttributeName: uifont};
}
#endif
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.h b/src/plugins/platforms/ios/qiosviewcontroller.h
index 07d5535e1a..7af4c83b48 100644
--- a/src/plugins/platforms/ios/qiosviewcontroller.h
+++ b/src/plugins/platforms/ios/qiosviewcontroller.h
@@ -48,7 +48,7 @@ QT_END_NAMESPACE
@interface QIOSViewController : UIViewController
-- (id)initWithQIOSScreen:(QT_PREPEND_NAMESPACE(QIOSScreen) *)screen;
+- (instancetype)initWithQIOSScreen:(QT_PREPEND_NAMESPACE(QIOSScreen) *)screen;
- (void)updateProperties;
#ifndef Q_OS_TVOS
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm
index aa909d6f63..ce2aa96ca5 100644
--- a/src/plugins/platforms/ios/qiosviewcontroller.mm
+++ b/src/plugins/platforms/ios/qiosviewcontroller.mm
@@ -57,12 +57,8 @@
// -------------------------------------------------------------------------
-@interface QIOSViewController () {
- @public
- QPointer<QT_PREPEND_NAMESPACE(QIOSScreen)> m_screen;
- BOOL m_updatingProperties;
- QMetaObject::Connection m_focusWindowChangeConnection;
-}
+@interface QIOSViewController ()
+@property (nonatomic, assign) QPointer<QT_PREPEND_NAMESPACE(QIOSScreen)> platformScreen;
@property (nonatomic, assign) BOOL changingOrientation;
@end
@@ -73,7 +69,7 @@
@implementation QIOSDesktopManagerView
-- (id)init
+- (instancetype)init
{
if (!(self = [super init]))
return nil;
@@ -126,7 +122,7 @@
{
Q_UNUSED(subview);
- QT_PREPEND_NAMESPACE(QIOSScreen) *screen = self.qtViewController->m_screen;
+ QT_PREPEND_NAMESPACE(QIOSScreen) *screen = self.qtViewController.platformScreen;
// The 'window' property of our view is not valid until the window
// has been shown, so we have to access it through the QIOSScreen.
@@ -171,7 +167,7 @@
// here. iOS will still use the latest rendered frame to create the
// application switcher thumbnail, but it will be based on the last
// active orientation of the application.
- QIOSScreen *screen = self.qtViewController->m_screen;
+ QIOSScreen *screen = self.qtViewController.platformScreen;
qCDebug(lcQpaWindow) << "ignoring layout of subviews while suspended,"
<< "likely system snapshot of" << screen->screen()->primaryOrientation();
return;
@@ -247,7 +243,10 @@
// -------------------------------------------------------------------------
-@implementation QIOSViewController
+@implementation QIOSViewController {
+ BOOL m_updatingProperties;
+ QMetaObject::Connection m_focusWindowChangeConnection;
+}
#ifndef Q_OS_TVOS
@synthesize prefersStatusBarHidden;
@@ -255,11 +254,10 @@
@synthesize preferredStatusBarStyle;
#endif
-- (id)initWithQIOSScreen:(QT_PREPEND_NAMESPACE(QIOSScreen) *)screen
+- (instancetype)initWithQIOSScreen:(QT_PREPEND_NAMESPACE(QIOSScreen) *)screen
{
if (self = [self init]) {
- m_screen = screen;
-
+ self.platformScreen = screen;
self.changingOrientation = NO;
#ifndef Q_OS_TVOS
@@ -333,7 +331,7 @@
- (BOOL)shouldAutorotate
{
#ifndef Q_OS_TVOS
- return m_screen && m_screen->uiScreen() == [UIScreen mainScreen] && !self.lockedOrientation;
+ return self.platformScreen && self.platformScreen->uiScreen() == [UIScreen mainScreen] && !self.lockedOrientation;
#else
return NO;
#endif
@@ -413,8 +411,8 @@
if (!QCoreApplication::instance())
return;
- if (m_screen)
- m_screen->updateProperties();
+ if (self.platformScreen)
+ self.platformScreen->updateProperties();
}
// -------------------------------------------------------------------------
@@ -424,12 +422,12 @@
if (!isQtApplication())
return;
- if (!m_screen || !m_screen->screen())
+ if (!self.platformScreen || !self.platformScreen->screen())
return;
// For now we only care about the main screen, as both the statusbar
// visibility and orientation is only appropriate for the main screen.
- if (m_screen->uiScreen() != [UIScreen mainScreen])
+ if (self.platformScreen->uiScreen() != [UIScreen mainScreen])
return;
// Prevent recursion caused by updating the status bar appearance (position
@@ -451,7 +449,7 @@
return;
// We only care about changes to focusWindow that involves our screen
- if (!focusWindow->screen() || focusWindow->screen()->handle() != m_screen)
+ if (!focusWindow->screen() || focusWindow->screen()->handle() != self.platformScreen)
return;
// All decisions are based on the the top level window
diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm
index 6ee258e363..cdec57de71 100644
--- a/src/plugins/platforms/ios/qioswindow.mm
+++ b/src/plugins/platforms/ios/qioswindow.mm
@@ -96,7 +96,7 @@ QIOSWindow::~QIOSWindow()
[m_view touchesCancelled:[NSSet set] withEvent:0];
clearAccessibleCache();
- m_view->m_qioswindow = 0;
+ m_view.platformWindow = 0;
[m_view removeFromSuperview];
[m_view release];
}
@@ -139,7 +139,7 @@ void QIOSWindow::setVisible(bool visible)
} else if (!visible && [m_view isActiveWindow]) {
// Our window was active/focus window but now hidden, so relinquish
// focus to the next possible window in the stack.
- NSArray *subviews = m_view.viewController.view.subviews;
+ NSArray<UIView *> *subviews = m_view.viewController.view.subviews;
for (int i = int(subviews.count) - 1; i >= 0; --i) {
UIView *view = [subviews objectAtIndex:i];
if (view.hidden)
@@ -301,7 +301,7 @@ void QIOSWindow::raiseOrLower(bool raise)
if (!isQtApplication())
return;
- NSArray *subviews = m_view.superview.subviews;
+ NSArray<UIView *> *subviews = m_view.superview.subviews;
if (subviews.count == 1)
return;
diff --git a/src/plugins/platforms/ios/quiaccessibilityelement.h b/src/plugins/platforms/ios/quiaccessibilityelement.h
index 03abf5407e..6b8efdcede 100644
--- a/src/plugins/platforms/ios/quiaccessibilityelement.h
+++ b/src/plugins/platforms/ios/quiaccessibilityelement.h
@@ -45,13 +45,12 @@
#ifndef QT_NO_ACCESSIBILITY
-@interface QMacAccessibilityElement : UIAccessibilityElement
-{}
+@interface QT_MANGLE_NAMESPACE(QMacAccessibilityElement) : UIAccessibilityElement
@property (readonly) QAccessible::Id axid;
-- (id)initWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view;
-+ (QMacAccessibilityElement *)elementWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view;
+- (instancetype)initWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view;
++ (instancetype)elementWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view;
@end
diff --git a/src/plugins/platforms/ios/quiaccessibilityelement.mm b/src/plugins/platforms/ios/quiaccessibilityelement.mm
index a26ba61b3c..3154536aad 100644
--- a/src/plugins/platforms/ios/quiaccessibilityelement.mm
+++ b/src/plugins/platforms/ios/quiaccessibilityelement.mm
@@ -42,20 +42,23 @@
#ifndef QT_NO_ACCESSIBILITY
#include "private/qaccessiblecache_p.h"
+#include "private/qcore_mac_p.h"
+
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
@implementation QMacAccessibilityElement
-- (id)initWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view
+- (instancetype)initWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view
{
Q_ASSERT((int)anId < 0);
- self = [super initWithAccessibilityContainer: view];
+ self = [super initWithAccessibilityContainer:view];
if (self)
_axid = anId;
return self;
}
-+ (id)elementWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view
++ (instancetype)elementWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view
{
Q_ASSERT(anId);
if (!anId)
@@ -63,10 +66,10 @@
QAccessibleCache *cache = QAccessibleCache::instance();
- QT_MANGLE_NAMESPACE(QMacAccessibilityElement) *element = cache->elementForId(anId);
+ QMacAccessibilityElement *element = cache->elementForId(anId);
if (!element) {
Q_ASSERT(QAccessible::accessibleInterface(anId));
- element = [[self alloc] initWithId:anId withAccessibilityContainer: view];
+ element = [[self alloc] initWithId:anId withAccessibilityContainer:view];
cache->insertElement(anId, element);
}
return element;
diff --git a/src/plugins/platforms/ios/quiview.h b/src/plugins/platforms/ios/quiview.h
index 3e3c579075..e1d5d5af0c 100644
--- a/src/plugins/platforms/ios/quiview.h
+++ b/src/plugins/platforms/ios/quiview.h
@@ -53,21 +53,10 @@ QT_END_NAMESPACE
@class QIOSViewController;
@interface QUIView : UIView
-{
- @public
- QT_PREPEND_NAMESPACE(QIOSWindow) *m_qioswindow;
- @private
- QHash<UITouch *, QWindowSystemInterface::TouchPoint> m_activeTouches;
- UITouch *m_activePencilTouch;
- int m_nextTouchId;
-
- @private
- NSMutableArray *m_accessibleElements;
-};
-
-- (id)initWithQIOSWindow:(QT_PREPEND_NAMESPACE(QIOSWindow) *)window;
+- (instancetype)initWithQIOSWindow:(QT_PREPEND_NAMESPACE(QIOSWindow) *)window;
- (void)sendUpdatedExposeEvent;
- (BOOL)isActiveWindow;
+@property (nonatomic, assign) QT_PREPEND_NAMESPACE(QIOSWindow) *platformWindow;
@end
@interface QUIView (Accessibility)
diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm
index 8db36705c0..e64c05d099 100644
--- a/src/plugins/platforms/ios/quiview.mm
+++ b/src/plugins/platforms/ios/quiview.mm
@@ -55,7 +55,12 @@
Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
-@implementation QUIView
+@implementation QUIView {
+ QHash<UITouch *, QWindowSystemInterface::TouchPoint> m_activeTouches;
+ UITouch *m_activePencilTouch;
+ int m_nextTouchId;
+ NSMutableArray<UIAccessibilityElement *> *m_accessibleElements;
+}
+ (void)load
{
@@ -82,25 +87,26 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
return [CAEAGLLayer class];
}
-- (id)initWithQIOSWindow:(QT_PREPEND_NAMESPACE(QIOSWindow) *)window
+- (instancetype)initWithQIOSWindow:(QT_PREPEND_NAMESPACE(QIOSWindow) *)window
{
if (self = [self initWithFrame:window->geometry().toCGRect()]) {
- m_qioswindow = window;
- m_accessibleElements = [[NSMutableArray alloc] init];
+ self.platformWindow = window;
+ m_accessibleElements = [[NSMutableArray<UIAccessibilityElement *> alloc] init];
}
return self;
}
-- (id)initWithFrame:(CGRect)frame
+- (instancetype)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame])) {
// Set up EAGL layer
CAEAGLLayer *eaglLayer = static_cast<CAEAGLLayer *>(self.layer);
eaglLayer.opaque = TRUE;
- eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithBool:YES], kEAGLDrawablePropertyRetainedBacking,
- kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
+ eaglLayer.drawableProperties = @{
+ kEAGLDrawablePropertyRetainedBacking: @(YES),
+ kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8
+ };
if (isQtApplication())
self.hidden = YES;
@@ -122,21 +128,17 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
self.layer.borderWidth = 1.0;
}
-#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_NA, 110000, 110000, __WATCHOS_NA)
if (qEnvironmentVariableIsSet("QT_IOS_DEBUG_WINDOW_SAFE_AREAS")) {
- if (__builtin_available(iOS 11, tvOS 11, *)) {
- UIView *safeAreaOverlay = [[UIView alloc] initWithFrame:CGRectZero];
- [safeAreaOverlay setBackgroundColor:[UIColor colorWithRed:0.3 green:0.7 blue:0.9 alpha:0.3]];
- [self addSubview:safeAreaOverlay];
-
- safeAreaOverlay.translatesAutoresizingMaskIntoConstraints = NO;
- [safeAreaOverlay.topAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.topAnchor].active = YES;
- [safeAreaOverlay.leftAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.leftAnchor].active = YES;
- [safeAreaOverlay.rightAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.rightAnchor].active = YES;
- [safeAreaOverlay.bottomAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.bottomAnchor].active = YES;
- }
+ UIView *safeAreaOverlay = [[UIView alloc] initWithFrame:CGRectZero];
+ [safeAreaOverlay setBackgroundColor:[UIColor colorWithRed:0.3 green:0.7 blue:0.9 alpha:0.3]];
+ [self addSubview:safeAreaOverlay];
+
+ safeAreaOverlay.translatesAutoresizingMaskIntoConstraints = NO;
+ [safeAreaOverlay.topAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.topAnchor].active = YES;
+ [safeAreaOverlay.leftAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.leftAnchor].active = YES;
+ [safeAreaOverlay.rightAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.rightAnchor].active = YES;
+ [safeAreaOverlay.bottomAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.bottomAnchor].active = YES;
}
-#endif
}
return self;
@@ -156,7 +158,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
#ifndef QT_NO_DEBUG_STREAM
QString platformWindowDescription;
QDebug debug(&platformWindowDescription);
- debug.nospace() << "; " << m_qioswindow << ">";
+ debug.nospace() << "; " << self.platformWindow << ">";
NSRange lastCharacter = [description rangeOfComposedCharacterSequenceAtIndex:description.length - 1];
[description replaceCharactersInRange:lastCharacter withString:platformWindowDescription.toNSString()];
#endif
@@ -210,10 +212,10 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
if (!CGAffineTransformIsIdentity(self.transform))
qWarning() << self << "has a transform set. This is not supported.";
- QWindow *window = m_qioswindow->window();
+ QWindow *window = self.platformWindow->window();
QRect lastReportedGeometry = qt_window_private(window)->geometry;
QRect currentGeometry = QRectF::fromCGRect(self.frame).toRect();
- qCDebug(lcQpaWindow) << m_qioswindow << "new geometry is" << currentGeometry;
+ qCDebug(lcQpaWindow) << self.platformWindow << "new geometry is" << currentGeometry;
QWindowSystemInterface::handleGeometryChange(window, currentGeometry);
if (currentGeometry.size() != lastReportedGeometry.size()) {
@@ -237,29 +239,29 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
{
QRegion region;
- if (m_qioswindow->isExposed()) {
+ if (self.platformWindow->isExposed()) {
QSize bounds = QRectF::fromCGRect(self.layer.bounds).toRect().size();
- Q_ASSERT(m_qioswindow->geometry().size() == bounds);
- Q_ASSERT(self.hidden == !m_qioswindow->window()->isVisible());
+ Q_ASSERT(self.platformWindow->geometry().size() == bounds);
+ Q_ASSERT(self.hidden == !self.platformWindow->window()->isVisible());
region = QRect(QPoint(), bounds);
}
- qCDebug(lcQpaWindow) << m_qioswindow << region << "isExposed" << m_qioswindow->isExposed();
- QWindowSystemInterface::handleExposeEvent(m_qioswindow->window(), region);
+ qCDebug(lcQpaWindow) << self.platformWindow << region << "isExposed" << self.platformWindow->isExposed();
+ QWindowSystemInterface::handleExposeEvent(self.platformWindow->window(), region);
}
- (void)safeAreaInsetsDidChange
{
- QWindowSystemInterface::handleSafeAreaMarginsChanged(m_qioswindow->window());
+ QWindowSystemInterface::handleSafeAreaMarginsChanged(self.platformWindow->window());
}
// -------------------------------------------------------------------------
- (BOOL)canBecomeFirstResponder
{
- return !(m_qioswindow->window()->flags() & Qt::WindowDoesNotAcceptFocus);
+ return !(self.platformWindow->window()->flags() & Qt::WindowDoesNotAcceptFocus);
}
- (BOOL)becomeFirstResponder
@@ -280,10 +282,10 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
qImDebug() << self << "became first responder";
}
- if (qGuiApp->focusWindow() != m_qioswindow->window())
- QWindowSystemInterface::handleWindowActivated(m_qioswindow->window());
+ if (qGuiApp->focusWindow() != self.platformWindow->window())
+ QWindowSystemInterface::handleWindowActivated(self.platformWindow->window());
else
- qImDebug() << m_qioswindow->window() << "already active, not sending window activation";
+ qImDebug() << self.platformWindow->window() << "already active, not sending window activation";
return YES;
}
@@ -349,19 +351,17 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
QTouchDevice *touchDevice = QIOSIntegration::instance()->touchDevice();
QTouchDevice::Capabilities touchCapabilities = touchDevice->capabilities();
- if (__builtin_available(iOS 9, *)) {
- if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable)
- touchCapabilities |= QTouchDevice::Pressure;
- else
- touchCapabilities &= ~QTouchDevice::Pressure;
- }
+ if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable)
+ touchCapabilities |= QTouchDevice::Pressure;
+ else
+ touchCapabilities &= ~QTouchDevice::Pressure;
touchDevice->setCapabilities(touchCapabilities);
}
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
- if (m_qioswindow->window()->flags() & Qt::WindowTransparentForInput)
+ if (self.platformWindow->window()->flags() & Qt::WindowTransparentForInput)
return NO;
return [super pointInside:point withEvent:event];
}
@@ -378,7 +378,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
for (UITouch *cTouch in cTouches) {
QPointF localViewPosition = QPointF::fromCGPoint([cTouch preciseLocationInView:self]);
QPoint localViewPositionI = localViewPosition.toPoint();
- QPointF globalScreenPosition = m_qioswindow->mapToGlobal(localViewPositionI) +
+ QPointF globalScreenPosition = self.platformWindow->mapToGlobal(localViewPositionI) +
(localViewPosition - localViewPositionI);
qreal pressure = cTouch.force / cTouch.maximumPossibleForce;
// azimuth unit vector: +x to the right, +y going downwards
@@ -391,7 +391,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
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(m_qioswindow->window(), timeStamp, localViewPosition, globalScreenPosition,
+ QWindowSystemInterface::handleTabletEvent(self.platformWindow->window(), timeStamp, localViewPosition, globalScreenPosition,
// device, pointerType, buttons
QTabletEvent::RotationStylus, QTabletEvent::Pen, state == Qt::TouchPointReleased ? Qt::NoButton : Qt::LeftButton,
// pressure, xTilt, yTilt
@@ -415,12 +415,12 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
// just map from the local view position to global coordinates.
// tvOS: all touches start at the center of the screen and move from there.
QPoint localViewPosition = QPointF::fromCGPoint([uiTouch locationInView:self]).toPoint();
- QPoint globalScreenPosition = m_qioswindow->mapToGlobal(localViewPosition);
+ QPoint globalScreenPosition = self.platformWindow->mapToGlobal(localViewPosition);
touchPoint.area = QRectF(globalScreenPosition, QSize(0, 0));
// FIXME: Do we really need to support QTouchDevice::NormalizedPosition?
- QSize screenSize = m_qioswindow->screen()->geometry().size();
+ QSize screenSize = self.platformWindow->screen()->geometry().size();
touchPoint.normalPosition = QPointF(globalScreenPosition.x() / screenSize.width(),
globalScreenPosition.y() / screenSize.height());
@@ -451,10 +451,10 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
// alert dialog, will fail to recognize. To be on the safe side, we deliver
// the event asynchronously.
QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::AsynchronousDelivery>(
- m_qioswindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values());
+ self.platformWindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values());
} else {
QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(
- m_qioswindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values());
+ self.platformWindow->window(), timeStamp, iosIntegration->touchDevice(), m_activeTouches.values());
}
}
@@ -482,8 +482,8 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
#endif
}
- if (m_qioswindow->shouldAutoActivateWindow() && m_activeTouches.size() == 1) {
- QPlatformWindow *topLevel = m_qioswindow;
+ if (self.platformWindow->shouldAutoActivateWindow() && m_activeTouches.size() == 1) {
+ QPlatformWindow *topLevel = self.platformWindow;
while (QPlatformWindow *p = topLevel->parent())
topLevel = p;
if (topLevel->window() != QGuiApplication::focusWindow())
@@ -553,7 +553,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
NSTimeInterval timestamp = event ? event.timestamp : [[NSProcessInfo processInfo] systemUptime];
QIOSIntegration *iosIntegration = static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration());
- QWindowSystemInterface::handleTouchCancelEvent(m_qioswindow->window(), ulong(timestamp * 1000), iosIntegration->touchDevice());
+ QWindowSystemInterface::handleTouchCancelEvent(self.platformWindow->window(), ulong(timestamp * 1000), iosIntegration->touchDevice());
}
- (int)mapPressTypeToKey:(UIPress*)press
@@ -581,7 +581,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
int key = [self mapPressTypeToKey:press];
if (key == Qt::Key_unknown)
continue;
- if (QWindowSystemInterface::handleKeyEvent(m_qioswindow->window(), type, key, Qt::NoModifier))
+ if (QWindowSystemInterface::handleKeyEvent(self.platformWindow->window(), type, key, Qt::NoModifier))
handled = true;
}
@@ -635,7 +635,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
- (QWindow *)qwindow
{
if ([self isKindOfClass:[QUIView class]]) {
- if (QT_PREPEND_NAMESPACE(QIOSWindow) *w = static_cast<QUIView *>(self)->m_qioswindow)
+ if (QT_PREPEND_NAMESPACE(QIOSWindow) *w = static_cast<QUIView *>(self).platformWindow)
return w->window();
}
return nil;
@@ -662,18 +662,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
- (UIEdgeInsets)qt_safeAreaInsets
{
-#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_NA, 110000, 110000, __WATCHOS_NA)
- if (__builtin_available(iOS 11, tvOS 11, *))
- return self.safeAreaInsets;
-#endif
-
- // Fallback for iOS < 11
- UIEdgeInsets safeAreaInsets = UIEdgeInsetsZero;
- CGPoint topInset = [self convertPoint:CGPointMake(0, self.viewController.topLayoutGuide.length) fromView:nil];
- CGPoint bottomInset = [self convertPoint:CGPointMake(0, self.viewController.bottomLayoutGuide.length) fromView:nil];
- safeAreaInsets.top = topInset.y;
- safeAreaInsets.bottom = bottomInset.y;
- return safeAreaInsets;
+ return self.safeAreaInsets;
}
@end
diff --git a/src/plugins/platforms/ios/quiview_accessibility.mm b/src/plugins/platforms/ios/quiview_accessibility.mm
index 69a4d375bd..a3f4156a59 100644
--- a/src/plugins/platforms/ios/quiview_accessibility.mm
+++ b/src/plugins/platforms/ios/quiview_accessibility.mm
@@ -49,8 +49,9 @@
if (!iface || iface->state().invisible || (iface->text(QAccessible::Name).isEmpty() && iface->text(QAccessible::Value).isEmpty() && iface->text(QAccessible::Description).isEmpty()))
return;
QAccessible::Id accessibleId = QAccessible::uniqueId(iface);
- UIAccessibilityElement *elem = [[QMacAccessibilityElement alloc] initWithId: accessibleId withAccessibilityContainer: self];
- [m_accessibleElements addObject:[elem autorelease]];
+ UIAccessibilityElement *elem = [[QT_MANGLE_NAMESPACE(QMacAccessibilityElement) alloc] initWithId:accessibleId withAccessibilityContainer:self];
+ [m_accessibleElements addObject:elem];
+ [elem release];
}
- (void)createAccessibleContainer:(QAccessibleInterface *)iface
@@ -73,7 +74,7 @@
if ([m_accessibleElements count])
return;
- QWindow *win = m_qioswindow->window();
+ QWindow *win = self.platformWindow->window();
QAccessibleInterface *iface = win->accessibleRoot();
if (iface)
[self createAccessibleContainer: iface];
diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro
index e61887618f..5bf2b77421 100644
--- a/src/plugins/platforms/platforms.pro
+++ b/src/plugins/platforms/platforms.pro
@@ -46,6 +46,8 @@ haiku {
SUBDIRS += haiku
}
+wasm: SUBDIRS = wasm
+
qtConfig(mirclient): SUBDIRS += mirclient
qtConfig(integrityfb): SUBDIRS += integrity
diff --git a/src/plugins/platforms/qnx/qqnxglcontext.cpp b/src/plugins/platforms/qnx/qqnxglcontext.cpp
index 2031de308c..1d030ba1aa 100644
--- a/src/plugins/platforms/qnx/qqnxglcontext.cpp
+++ b/src/plugins/platforms/qnx/qqnxglcontext.cpp
@@ -64,7 +64,7 @@ static QEGLPlatformContext::Flags makeFlags()
{
QEGLPlatformContext::Flags result = 0;
- if (!QQnxIntegration::options().testFlag(QQnxIntegration::SurfacelessEGLContext))
+ if (!QQnxIntegration::instance()->options().testFlag(QQnxIntegration::SurfacelessEGLContext))
result |= QEGLPlatformContext::NoSurfaceless;
return result;
diff --git a/src/plugins/platforms/qnx/qqnxglobal.cpp b/src/plugins/platforms/qnx/qqnxglobal.cpp
index 6b3cc6bebf..c17f6a7546 100644
--- a/src/plugins/platforms/qnx/qqnxglobal.cpp
+++ b/src/plugins/platforms/qnx/qqnxglobal.cpp
@@ -45,9 +45,9 @@ QT_BEGIN_NAMESPACE
void qScreenCheckError(int rc, const char *funcInfo, const char *message, bool critical)
{
- if (!rc && (QQnxIntegration::options() & QQnxIntegration::AlwaysFlushScreenContext)
- && QQnxIntegration::screenContext() != 0) {
- rc = screen_flush_context(QQnxIntegration::screenContext(), 0);
+ if (!rc && (QQnxIntegration::instance()->options() & QQnxIntegration::AlwaysFlushScreenContext)
+ && QQnxIntegration::instance()->screenContext() != 0) {
+ rc = screen_flush_context(QQnxIntegration::instance()->screenContext(), 0);
}
if (Q_UNLIKELY(rc)) {
diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp
index dc4ebdf699..8c8521325c 100644
--- a/src/plugins/platforms/qnx/qqnxintegration.cpp
+++ b/src/plugins/platforms/qnx/qqnxintegration.cpp
@@ -99,8 +99,7 @@
QT_BEGIN_NAMESPACE
-QQnxWindowMapper QQnxIntegration::ms_windowMapper;
-QMutex QQnxIntegration::ms_windowMapperMutex;
+QQnxIntegration *QQnxIntegration::ms_instance;
static inline QQnxIntegration::Options parseOptions(const QStringList &paramList)
{
@@ -124,6 +123,22 @@ static inline QQnxIntegration::Options parseOptions(const QStringList &paramList
return options;
}
+static inline int getContextCapabilities(const QStringList &paramList)
+{
+ QString contextCapabilitiesPrefix = QStringLiteral("screen-context-capabilities=");
+ int contextCapabilities = SCREEN_APPLICATION_CONTEXT;
+ for (const QString &param : paramList) {
+ if (param.startsWith(contextCapabilitiesPrefix)) {
+ QStringRef value = param.midRef(contextCapabilitiesPrefix.length());
+ bool ok = false;
+ contextCapabilities = value.toInt(&ok, 0);
+ if (!ok)
+ contextCapabilities = SCREEN_APPLICATION_CONTEXT;
+ }
+ }
+ return contextCapabilities;
+}
+
QQnxIntegration::QQnxIntegration(const QStringList &paramList)
: QPlatformIntegration()
, m_screenEventThread(0)
@@ -147,11 +162,15 @@ QQnxIntegration::QQnxIntegration(const QStringList &paramList)
, m_drag(new QSimpleDrag())
#endif
{
- ms_options = parseOptions(paramList);
+ ms_instance = this;
+ m_options = parseOptions(paramList);
qIntegrationDebug();
+
// Open connection to QNX composition manager
- Q_SCREEN_CRITICALERROR(screen_create_context(&ms_screenContext, SCREEN_APPLICATION_CONTEXT),
- "Failed to create screen context");
+ if (screen_create_context(&m_screenContext, getContextCapabilities(paramList))) {
+ qFatal("%s - Screen: Failed to create screen context - Error: %s (%i)",
+ Q_FUNC_INFO, strerror(errno), errno);
+ }
#if QT_CONFIG(qqnx_pps)
// Create/start navigator event notifier
@@ -168,7 +187,8 @@ QQnxIntegration::QQnxIntegration(const QStringList &paramList)
#endif
// Create/start event thread
- m_screenEventThread = new QQnxScreenEventThread(ms_screenContext, m_screenEventHandler);
+ m_screenEventThread = new QQnxScreenEventThread(m_screenContext);
+ m_screenEventHandler->setScreenEventThread(m_screenEventThread);
m_screenEventThread->start();
#if QT_CONFIG(qqnx_pps)
@@ -244,7 +264,7 @@ QQnxIntegration::~QQnxIntegration()
destroyDisplays();
// Close connection to QNX composition manager
- screen_destroy_context(ms_screenContext);
+ screen_destroy_context(m_screenContext);
#if !defined(QT_NO_OPENGL)
// Cleanup global OpenGL resources
@@ -268,6 +288,8 @@ QQnxIntegration::~QQnxIntegration()
// Destroy navigator interface
delete m_navigator;
+ ms_instance = nullptr;
+
qIntegrationDebug("platform plugin shutdown end");
}
@@ -296,10 +318,10 @@ QPlatformWindow *QQnxIntegration::createPlatformWindow(QWindow *window) const
const bool needRootWindow = options() & RootWindow;
switch (surfaceType) {
case QSurface::RasterSurface:
- return new QQnxRasterWindow(window, ms_screenContext, needRootWindow);
+ return new QQnxRasterWindow(window, m_screenContext, needRootWindow);
#if !defined(QT_NO_OPENGL)
case QSurface::OpenGLSurface:
- return new QQnxEglWindow(window, ms_screenContext, needRootWindow);
+ return new QQnxEglWindow(window, m_screenContext, needRootWindow);
#endif
default:
qFatal("QQnxWindow: unsupported window API");
@@ -433,7 +455,7 @@ QPlatformDrag *QQnxIntegration::drag() const
QVariant QQnxIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
{
qIntegrationDebug();
- if ((hint == ShowIsFullScreen) && (ms_options & FullScreenApplication))
+ if ((hint == ShowIsFullScreen) && (m_options & FullScreenApplication))
return true;
return QPlatformIntegration::styleHint(hint);
@@ -447,25 +469,25 @@ QPlatformServices * QQnxIntegration::services() const
QWindow *QQnxIntegration::window(screen_window_t qnxWindow)
{
qIntegrationDebug();
- QMutexLocker locker(&ms_windowMapperMutex);
+ QMutexLocker locker(&m_windowMapperMutex);
Q_UNUSED(locker);
- return ms_windowMapper.value(qnxWindow, 0);
+ return m_windowMapper.value(qnxWindow, 0);
}
void QQnxIntegration::addWindow(screen_window_t qnxWindow, QWindow *window)
{
qIntegrationDebug();
- QMutexLocker locker(&ms_windowMapperMutex);
+ QMutexLocker locker(&m_windowMapperMutex);
Q_UNUSED(locker);
- ms_windowMapper.insert(qnxWindow, window);
+ m_windowMapper.insert(qnxWindow, window);
}
void QQnxIntegration::removeWindow(screen_window_t qnxWindow)
{
qIntegrationDebug();
- QMutexLocker locker(&ms_windowMapperMutex);
+ QMutexLocker locker(&m_windowMapperMutex);
Q_UNUSED(locker);
- ms_windowMapper.remove(qnxWindow);
+ m_windowMapper.remove(qnxWindow);
}
void QQnxIntegration::createDisplays()
@@ -473,7 +495,7 @@ void QQnxIntegration::createDisplays()
qIntegrationDebug();
// Query number of displays
int displayCount = 0;
- int result = screen_get_context_property_iv(ms_screenContext, SCREEN_PROPERTY_DISPLAY_COUNT,
+ int result = screen_get_context_property_iv(m_screenContext, SCREEN_PROPERTY_DISPLAY_COUNT,
&displayCount);
Q_SCREEN_CRITICALERROR(result, "Failed to query display count");
@@ -484,7 +506,7 @@ void QQnxIntegration::createDisplays()
// Get all displays
screen_display_t *displays = (screen_display_t *)alloca(sizeof(screen_display_t) * displayCount);
- result = screen_get_context_property_pv(ms_screenContext, SCREEN_PROPERTY_DISPLAYS,
+ result = screen_get_context_property_pv(m_screenContext, SCREEN_PROPERTY_DISPLAYS,
(void **)displays);
Q_SCREEN_CRITICALERROR(result, "Failed to query displays");
@@ -510,7 +532,7 @@ void QQnxIntegration::createDisplays()
void QQnxIntegration::createDisplay(screen_display_t display, bool isPrimary)
{
- QQnxScreen *screen = new QQnxScreen(ms_screenContext, display, isPrimary);
+ QQnxScreen *screen = new QQnxScreen(m_screenContext, display, isPrimary);
m_screens.append(screen);
screenAdded(screen);
screen->adjustOrientation();
@@ -559,14 +581,14 @@ QQnxScreen *QQnxIntegration::primaryDisplay() const
return m_screens.first();
}
-QQnxIntegration::Options QQnxIntegration::options()
+QQnxIntegration::Options QQnxIntegration::options() const
{
- return ms_options;
+ return m_options;
}
screen_context_t QQnxIntegration::screenContext()
{
- return ms_screenContext;
+ return m_screenContext;
}
QQnxNavigatorEventHandler *QQnxIntegration::navigatorEventHandler()
@@ -574,10 +596,6 @@ QQnxNavigatorEventHandler *QQnxIntegration::navigatorEventHandler()
return m_navigatorEventHandler;
}
-screen_context_t QQnxIntegration::ms_screenContext = 0;
-
-QQnxIntegration::Options QQnxIntegration::ms_options = 0;
-
bool QQnxIntegration::supportsNavigatorEvents() const
{
// If QQNX_PPS is defined then we have navigator
diff --git a/src/plugins/platforms/qnx/qqnxintegration.h b/src/plugins/platforms/qnx/qqnxintegration.h
index f844a7508c..2993607489 100644
--- a/src/plugins/platforms/qnx/qqnxintegration.h
+++ b/src/plugins/platforms/qnx/qqnxintegration.h
@@ -88,6 +88,8 @@ public:
explicit QQnxIntegration(const QStringList &paramList);
~QQnxIntegration();
+ static QQnxIntegration *instance() { return ms_instance; }
+
bool hasCapability(QPlatformIntegration::Capability cap) const override;
QPlatformWindow *createPlatformWindow(QWindow *window) const override;
@@ -121,15 +123,15 @@ public:
QPlatformServices *services() const override;
- static QWindow *window(screen_window_t qnxWindow);
+ QWindow *window(screen_window_t qnxWindow);
QQnxScreen *screenForNative(screen_display_t qnxScreen) const;
void createDisplay(screen_display_t display, bool isPrimary);
void removeDisplay(QQnxScreen *screen);
QQnxScreen *primaryDisplay() const;
- static Options options();
- static screen_context_t screenContext();
+ Options options() const;
+ screen_context_t screenContext();
QQnxNavigatorEventHandler *navigatorEventHandler();
@@ -137,10 +139,10 @@ private:
void createDisplays();
void destroyDisplays();
- static void addWindow(screen_window_t qnxWindow, QWindow *window);
- static void removeWindow(screen_window_t qnxWindow);
+ void addWindow(screen_window_t qnxWindow, QWindow *window);
+ void removeWindow(screen_window_t qnxWindow);
- static screen_context_t ms_screenContext;
+ screen_context_t m_screenContext;
QQnxScreenEventThread *m_screenEventThread;
QQnxNavigatorEventHandler *m_navigatorEventHandler;
QQnxAbstractVirtualKeyboard *m_virtualKeyboard;
@@ -162,10 +164,12 @@ private:
#if QT_CONFIG(draganddrop)
QSimpleDrag *m_drag;
#endif
- static QQnxWindowMapper ms_windowMapper;
- static QMutex ms_windowMapperMutex;
+ QQnxWindowMapper m_windowMapper;
+ QMutex m_windowMapperMutex;
+
+ Options m_options;
- static Options ms_options;
+ static QQnxIntegration *ms_instance;
friend class QQnxWindow;
};
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
index ff1133aaa7..e4843cb438 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
@@ -218,36 +218,39 @@ void QQnxScreenEventHandler::injectKeyboardEvent(int flags, int sym, int modifie
void QQnxScreenEventHandler::setScreenEventThread(QQnxScreenEventThread *eventThread)
{
m_eventThread = eventThread;
+ connect(m_eventThread, &QQnxScreenEventThread::eventsPending,
+ this, &QQnxScreenEventHandler::processEvents);
}
-void QQnxScreenEventHandler::processEventsFromScreenThread()
+void QQnxScreenEventHandler::processEvents()
{
if (!m_eventThread)
return;
- QQnxScreenEventArray *events = m_eventThread->lock();
+ screen_event_t event = nullptr;
+ if (screen_create_event(&event) != 0)
+ return;
- for (int i = 0; i < events->size(); ++i) {
- screen_event_t event = events->at(i);
- if (!event)
- continue;
- (*events)[i] = 0;
+ int count = 0;
+ for (;;) {
+ if (screen_get_event(m_eventThread->context(), event, 0) != 0)
+ break;
- m_eventThread->unlock();
+ int type = SCREEN_EVENT_NONE;
+ screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &type);
+ if (type == SCREEN_EVENT_NONE)
+ break;
+ ++count;
long result = 0;
QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance();
bool handled = dispatcher && dispatcher->filterNativeEvent(QByteArrayLiteral("screen_event_t"), event, &result);
if (!handled)
handleEvent(event);
- screen_destroy_event(event);
-
- m_eventThread->lock();
}
- events->clear();
-
- m_eventThread->unlock();
+ m_eventThread->armEventsPending(count);
+ screen_destroy_event(event);
}
void QQnxScreenEventHandler::handleKeyboardEvent(screen_event_t event)
@@ -323,11 +326,11 @@ void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event)
"Failed to query event wheel delta");
// Map window handle to top-level QWindow
- QWindow *w = QQnxIntegration::window(qnxWindow);
+ QWindow *w = QQnxIntegration::instance()->window(qnxWindow);
// Generate enter and leave events as needed.
if (qnxWindow != m_lastMouseWindow) {
- QWindow *wOld = QQnxIntegration::window(m_lastMouseWindow);
+ QWindow *wOld = QQnxIntegration::instance()->window(m_lastMouseWindow);
if (wOld) {
QWindowSystemInterface::handleLeaveEvent(wOld);
@@ -435,11 +438,11 @@ void QQnxScreenEventHandler::handleTouchEvent(screen_event_t event, int qnxType)
if (touchId < MaximumTouchPoints) {
// Map window handle to top-level QWindow
- QWindow *w = QQnxIntegration::window(qnxWindow);
+ QWindow *w = QQnxIntegration::instance()->window(qnxWindow);
// Generate enter and leave events as needed.
if (qnxWindow != m_lastMouseWindow) {
- QWindow *wOld = QQnxIntegration::window(m_lastMouseWindow);
+ QWindow *wOld = QQnxIntegration::instance()->window(m_lastMouseWindow);
if (wOld) {
QWindowSystemInterface::handleLeaveEvent(wOld);
@@ -529,7 +532,7 @@ void QQnxScreenEventHandler::handleCloseEvent(screen_event_t event)
Q_EMIT windowClosed(window);
// Map window handle to top-level QWindow
- QWindow *w = QQnxIntegration::window(window);
+ QWindow *w = QQnxIntegration::instance()->window(window);
if (w != 0)
QWindowSystemInterface::handleCloseEvent(w);
}
@@ -629,7 +632,7 @@ void QQnxScreenEventHandler::handleKeyboardFocusPropertyEvent(screen_window_t wi
if (Q_UNLIKELY(window && screen_get_window_property_iv(window, SCREEN_PROPERTY_FOCUS, &focus) != 0))
qFatal("QQnx: failed to query keyboard focus property, errno=%d", errno);
- QWindow *focusWindow = QQnxIntegration::window(window);
+ QWindow *focusWindow = QQnxIntegration::instance()->window(window);
if (m_focusLostTimer != -1) {
killTimer(m_focusLostTimer);
@@ -655,7 +658,7 @@ void QQnxScreenEventHandler::handleGeometryPropertyEvent(screen_window_t window)
}
QRect rect(pos[0], pos[1], size[0], size[1]);
- QWindow *qtWindow = QQnxIntegration::window(window);
+ QWindow *qtWindow = QQnxIntegration::instance()->window(window);
if (qtWindow) {
qtWindow->setGeometry(rect);
QWindowSystemInterface::handleGeometryChange(qtWindow, rect);
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.h b/src/plugins/platforms/qnx/qqnxscreeneventhandler.h
index 40697b7a09..b35967610e 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.h
+++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.h
@@ -74,7 +74,7 @@ protected:
void timerEvent(QTimerEvent *event) override;
private Q_SLOTS:
- void processEventsFromScreenThread();
+ void processEvents();
private:
void handleKeyboardEvent(screen_event_t event);
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp b/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp
index c56d9a8da4..1b5f3b4954 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp
@@ -1,5 +1,6 @@
/***************************************************************************
**
+** Copyright (C) 2017 QNX Software Systems. All rights reserved.
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: https://www.qt.io/licensing/
**
@@ -55,116 +56,101 @@
#define qScreenEventThreadDebug QT_NO_QDEBUG_MACRO
#endif
-QQnxScreenEventThread::QQnxScreenEventThread(screen_context_t context, QQnxScreenEventHandler *screenEventHandler)
- : QThread(),
- m_screenContext(context),
- m_screenEventHandler(screenEventHandler),
- m_quit(false)
+static const int c_screenCode = _PULSE_CODE_MINAVAIL + 0;
+static const int c_armCode = _PULSE_CODE_MINAVAIL + 1;
+static const int c_quitCode = _PULSE_CODE_MINAVAIL + 2;
+
+QQnxScreenEventThread::QQnxScreenEventThread(screen_context_t context)
+ : QThread()
+ , m_screenContext(context)
{
- screenEventHandler->setScreenEventThread(this);
- connect(this, SIGNAL(eventPending()), screenEventHandler, SLOT(processEventsFromScreenThread()), Qt::QueuedConnection);
- connect(this, SIGNAL(finished()), screenEventHandler, SLOT(processEventsFromScreenThread()), Qt::QueuedConnection);
+ m_channelId = ChannelCreate(_NTO_CHF_DISCONNECT | _NTO_CHF_UNBLOCK | _NTO_CHF_PRIVATE);
+ if (m_channelId == -1) {
+ qFatal("QQnxScreenEventThread: Can't continue without a channel");
+ }
+
+ m_connectionId = ConnectAttach(0, 0, m_channelId, _NTO_SIDE_CHANNEL, 0);
+ if (m_connectionId == -1) {
+ ChannelDestroy(m_channelId);
+ qFatal("QQnxScreenEventThread: Can't continue without a channel connection");
+ }
+
+ struct sigevent screenEvent;
+ SIGEV_PULSE_INIT(&screenEvent, m_connectionId, SIGEV_PULSE_PRIO_INHERIT, c_screenCode, 0);
+
+ screen_notify(m_screenContext, SCREEN_NOTIFY_EVENT, nullptr, &screenEvent);
}
QQnxScreenEventThread::~QQnxScreenEventThread()
{
// block until thread terminates
shutdown();
-}
-void QQnxScreenEventThread::injectKeyboardEvent(int flags, int sym, int mod, int scan, int cap)
-{
- QQnxScreenEventHandler::injectKeyboardEvent(flags, sym, mod, scan, cap);
-}
-
-QQnxScreenEventArray *QQnxScreenEventThread::lock()
-{
- m_mutex.lock();
- return &m_events;
-}
-
-void QQnxScreenEventThread::unlock()
-{
- m_mutex.unlock();
+ ConnectDetach(m_connectionId);
+ ChannelDestroy(m_channelId);
}
void QQnxScreenEventThread::run()
{
qScreenEventThreadDebug("screen event thread started");
- int errorCounter = 0;
- // loop indefinitely
- while (!m_quit) {
- screen_event_t event;
-
- // create screen event
- Q_SCREEN_CHECKERROR(screen_create_event(&event), "Failed to create screen event");
-
- // block until screen event is available
- const int error = screen_get_event(m_screenContext, event, -1);
- Q_SCREEN_CRITICALERROR(error, "Failed to get screen event");
- // Only allow 50 consecutive errors before we exit the thread
- if (error) {
- errorCounter++;
- if (errorCounter > 50)
- m_quit = true;
-
- screen_destroy_event(event);
- continue;
- } else {
- errorCounter = 0;
- }
-
- // process received event
- // get the event type
- int qnxType;
- Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &qnxType),
- "Failed to query screen event type");
-
- if (qnxType == SCREEN_EVENT_USER) {
- // treat all user events as shutdown requests
- qScreenEventThreadDebug("QNX user screen event");
- m_quit = true;
- } else {
- m_mutex.lock();
- m_events << event;
- m_mutex.unlock();
- emit eventPending();
- }
+ while (1) {
+ struct _pulse msg;
+ memset(&msg, 0, sizeof(msg));
+ int receiveId = MsgReceive(m_channelId, &msg, sizeof(msg), nullptr);
+ if (receiveId == 0 && msg.code == c_quitCode)
+ break;
+ else if (receiveId == 0)
+ handlePulse(msg);
+ else if (receiveId > 0)
+ qWarning() << "Unexpected message" << msg.code;
+ else
+ qWarning() << "MsgReceive error" << strerror(errno);
}
qScreenEventThreadDebug("screen event thread stopped");
-
- // cleanup
- m_mutex.lock();
- Q_FOREACH (screen_event_t event, m_events) {
- screen_destroy_event(event);
- }
- m_events.clear();
- m_mutex.unlock();
}
-void QQnxScreenEventThread::shutdown()
+void QQnxScreenEventThread::armEventsPending(int count)
{
- screen_event_t event;
+ MsgSendPulse(m_connectionId, SIGEV_PULSE_PRIO_INHERIT, c_armCode, count);
+}
- // create screen event
- Q_SCREEN_CHECKERROR(screen_create_event(&event),
- "Failed to create screen event");
+void QQnxScreenEventThread::handleScreenPulse(const struct _pulse &msg)
+{
+ Q_UNUSED(msg);
- // set the event type as user
- int type = SCREEN_EVENT_USER;
- Q_SCREEN_CHECKERROR(screen_set_event_property_iv(event, SCREEN_PROPERTY_TYPE, &type),
- "Failed to set screen type");
+ ++m_screenPulsesSinceLastArmPulse;
+ if (m_emitNeededOnNextScreenPulse) {
+ m_emitNeededOnNextScreenPulse = false;
+ Q_EMIT eventsPending();
+ }
+}
- // NOTE: ignore SCREEN_PROPERTY_USER_DATA; treat all user events as shutdown events
+void QQnxScreenEventThread::handleArmPulse(const struct _pulse &msg)
+{
+ if (msg.value.sival_int == 0 && m_screenPulsesSinceLastArmPulse == 0) {
+ m_emitNeededOnNextScreenPulse = true;
+ } else {
+ m_screenPulsesSinceLastArmPulse = 0;
+ m_emitNeededOnNextScreenPulse = false;
+ Q_EMIT eventsPending();
+ }
+}
- // post event to event loop so it will wake up and die
- Q_SCREEN_CHECKERROR(screen_send_event(m_screenContext, event, getpid()),
- "Failed to set screen event type");
+void QQnxScreenEventThread::handlePulse(const struct _pulse &msg)
+{
+ if (msg.code == c_screenCode)
+ handleScreenPulse(msg);
+ else if (msg.code == c_armCode)
+ handleArmPulse(msg);
+ else
+ qWarning() << "Unexpected pulse" << msg.code;
+}
- // cleanup
- screen_destroy_event(event);
+void QQnxScreenEventThread::shutdown()
+{
+ MsgSendPulse(m_connectionId, SIGEV_PULSE_PRIO_INHERIT, c_quitCode, 0);
qScreenEventThreadDebug("screen event thread shutdown begin");
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventthread.h b/src/plugins/platforms/qnx/qqnxscreeneventthread.h
index 140f53aa50..3c8d197545 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventthread.h
+++ b/src/plugins/platforms/qnx/qqnxscreeneventthread.h
@@ -1,5 +1,6 @@
/***************************************************************************
**
+** Copyright (C) 2017 QNX Software Systems. All rights reserved.
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: https://www.qt.io/licensing/
**
@@ -47,37 +48,34 @@
QT_BEGIN_NAMESPACE
-class QQnxScreenEventHandler;
-
-typedef QVarLengthArray<screen_event_t, 64> QQnxScreenEventArray;
-
class QQnxScreenEventThread : public QThread
{
Q_OBJECT
public:
- QQnxScreenEventThread(screen_context_t context, QQnxScreenEventHandler *screenEventHandler);
+ QQnxScreenEventThread(screen_context_t context);
~QQnxScreenEventThread();
- static void injectKeyboardEvent(int flags, int sym, int mod, int scan, int cap);
-
- QQnxScreenEventArray *lock();
- void unlock();
+ screen_context_t context() const { return m_screenContext; }
+ void armEventsPending(int count);
protected:
void run() override;
Q_SIGNALS:
- void eventPending();
+ void eventsPending();
private:
+ void handleScreenPulse(const struct _pulse &msg);
+ void handleArmPulse(const struct _pulse &msg);
+ void handlePulse(const struct _pulse &msg);
void shutdown();
+ int m_channelId;
+ int m_connectionId;
screen_context_t m_screenContext;
- QMutex m_mutex;
- QQnxScreenEventArray m_events;
- QQnxScreenEventHandler *m_screenEventHandler;
- bool m_quit;
+ bool m_emitNeededOnNextScreenPulse = true;
+ int m_screenPulsesSinceLastArmPulse = 0;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp
index 4a547aa158..2096bc789e 100644
--- a/src/plugins/platforms/qnx/qqnxwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxwindow.cpp
@@ -132,22 +132,12 @@ DECLARE_DEBUG_VAR(statistics)
setWindowProperty function of the native interface to set the \e qnxWindowGroup property
to the desired value, for example:
- \code
- QQuickView *view = new QQuickView(parent);
- view->create();
- QGuiApplication::platformNativeInterface()->setWindowProperty(view->handle(), "qnxWindowGroup",
- group);
- \endcode
+ \snippet code/src_plugins_platforms_qnx_qqnxwindow.cpp 0
To leave the current window group, one passes a null value for the property value,
for example:
- \code
- QQuickView *view = new QQuickView(parent);
- view->create();
- QGuiApplication::platformNativeInterface()->setWindowProperty(view->handle(), "qnxWindowGroup",
- QVariant());
- \endcode
+ \snippet code/src_plugins_platforms_qnx_qqnxwindow.cpp 1
\section1 Window Id
@@ -174,7 +164,9 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootW
// If a qnxInitialWindowGroup property is set on the window we'll take this as an
// indication that we want to create a child window and join that window group.
- const QVariant windowGroup = window->property("qnxInitialWindowGroup");
+ QVariant windowGroup = window->property("qnxInitialWindowGroup");
+ if (!windowGroup.isValid())
+ windowGroup = window->property("_q_platform_qnxParentGroup");
if (window->type() == Qt::CoverWindow) {
// Cover windows have to be top level to be accessible to window delegate (i.e. navigator)
@@ -194,7 +186,12 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootW
if (window->type() == Qt::Desktop) // A desktop widget does not need a libscreen window
return;
- if (m_isTopLevel) {
+ QVariant type = window->property("_q_platform_qnxWindowType");
+ if (type.isValid() && type.canConvert<int>()) {
+ Q_SCREEN_CHECKERROR(
+ screen_create_window_type(&m_window, m_screenContext, type.value<int>()),
+ "Could not create window");
+ } else if (m_isTopLevel) {
Q_SCREEN_CRITICALERROR(screen_create_window(&m_window, m_screenContext),
"Could not create top level window"); // Creates an application window
if (window->type() != Qt::CoverWindow) {
@@ -212,7 +209,9 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootW
// If the window has a qnxWindowId property, set this as the string id property. This generally
// needs to be done prior to joining any group as it might be used by the owner of the
// group to identify the window.
- const QVariant windowId = window->property("qnxWindowId");
+ QVariant windowId = window->property("qnxWindowId");
+ if (!windowId.isValid())
+ windowId = window->property("_q_platform_qnxWindowId");
if (windowId.isValid() && windowId.canConvert<QByteArray>()) {
QByteArray id = windowId.toByteArray();
Q_SCREEN_CHECKERROR(screen_set_window_property_cv(m_window, SCREEN_PROPERTY_ID_STRING,
@@ -262,7 +261,7 @@ QQnxWindow::~QQnxWindow()
Q_ASSERT(m_childWindows.size() == 0);
// Remove from plugin's window mapper
- QQnxIntegration::removeWindow(m_window);
+ QQnxIntegration::instance()->removeWindow(m_window);
// Remove from parent's Hierarchy.
removeFromParent();
@@ -471,7 +470,7 @@ void QQnxWindow::setScreen(QQnxScreen *platformScreen)
qWindowDebug("Moving window to different screen");
m_screen->removeWindow(this);
- if ((QQnxIntegration::options() & QQnxIntegration::RootWindow)) {
+ if ((QQnxIntegration::instance()->options() & QQnxIntegration::RootWindow)) {
screen_leave_window_group(m_window);
}
}
@@ -726,7 +725,7 @@ void QQnxWindow::initWindow()
m_exposed = false;
// Add window to plugin's window mapper
- QQnxIntegration::addWindow(m_window, window());
+ QQnxIntegration::instance()->addWindow(m_window, window());
// Qt never calls these setters after creating the window, so we need to do that ourselves here
setWindowState(window()->windowState());
@@ -823,7 +822,7 @@ void QQnxWindow::windowPosted()
bool QQnxWindow::shouldMakeFullScreen() const
{
return ((static_cast<QQnxScreen *>(screen())->rootWindow() == this)
- && (QQnxIntegration::options() & QQnxIntegration::FullScreenApplication));
+ && (QQnxIntegration::instance()->options() & QQnxIntegration::FullScreenApplication));
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/main.cpp b/src/plugins/platforms/wasm/main.cpp
new file mode 100644
index 0000000000..a4d23b4e0d
--- /dev/null
+++ b/src/plugins/platforms/wasm/main.cpp
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** 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 <qpa/qplatformintegrationplugin.h>
+#include "qwasmintegration.h"
+
+QT_BEGIN_NAMESPACE
+
+class QWasmIntegrationPlugin : public QPlatformIntegrationPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "wasm.json")
+public:
+ QPlatformIntegration *create(const QString &, const QStringList &) override;
+};
+
+QPlatformIntegration *QWasmIntegrationPlugin::create(const QString& system, const QStringList& paramList)
+{
+ Q_UNUSED(paramList);
+ if (!system.compare(QStringLiteral("wasm"), Qt::CaseInsensitive))
+ return new QWasmIntegration;
+
+ return nullptr;
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/plugins/platforms/wasm/qtloader.js b/src/plugins/platforms/wasm/qtloader.js
new file mode 100644
index 0000000000..37a5308034
--- /dev/null
+++ b/src/plugins/platforms/wasm/qtloader.js
@@ -0,0 +1,516 @@
+/****************************************************************************
+**
+** 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 = {
+// 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.
+// 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.
+
+
+var Module = {}
+
+function QtLoader(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;
+ }
+ }
+
+ 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);
+ }
+
+ // Set default state handler functions if needed
+ if (config.containerElements !== undefined) {
+ config.showError = config.showError || function(errorText, container) {
+ removeChildren(container);
+ var errorTextElement = document.createElement("text");
+ errorTextElement.className = "QtError"
+ errorTextElement.innerHTML = errorText;
+ return errorTextElement;
+ }
+
+ 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(container) {
+ removeChildren(container);
+ var canvas = document.createElement("canvas");
+ canvas.className = "QtCanvas"
+ canvas.style = "height: 100%; width: 100%;"
+ return canvas;
+ }
+
+ 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;
+ }
+ }
+
+ 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;
+
+ 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");
+ });
+ }
+
+ function completeLoadEmscriptenModule(applicationName, emscriptenModuleSource, wasmModule) {
+
+ // 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) {
+ return WebAssembly.instantiate(wasmModule, imports).then(function(instance) {
+ successCallback(instance);
+ return instance;
+ }, function(error) {
+ self.error = error;
+ setStatus("Error");
+ });
+ };
+
+ 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)) {
+ Module.ENV[key.toUpperCase()] = value;
+ }
+ });
+
+ 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);
+ }
+ }
+
+ function setCanvasContent() {
+ var firstCanvas;
+ if (config.containerElements === undefined) {
+ firstCanvas = config.showCanvas();
+ } else {
+ for (container of config.containerElements) {
+ var canvasElement = config.showCanvas(container);
+ container.appendChild(canvasElement);
+ }
+ firstCanvas = config.containerElements[0].firstChild;
+ }
+
+ if (Module.canvas === undefined) {
+ Module.canvas = firstCanvas;
+ }
+ }
+
+ 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;
+
+ for (container of config.containerElements) {
+ var loaderElement = config.showExit(publicAPI.crashed, publicAPI.exitCode, container);
+ if (loaderElement !== undefined)
+ container.appendChild(loaderElement);
+ }
+ }
+
+ 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();
+ }
+ }
+
+ // 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);
+ }
+
+ setStatus("Created");
+
+ return publicAPI;
+}
diff --git a/src/plugins/platforms/wasm/qtlogo.svg b/src/plugins/platforms/wasm/qtlogo.svg
new file mode 100644
index 0000000000..cb8989bb79
--- /dev/null
+++ b/src/plugins/platforms/wasm/qtlogo.svg
@@ -0,0 +1,67 @@
+<?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"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="462pt"
+ height="339pt"
+ viewBox="0 0 462 339"
+ version="1.1"
+ id="svg2"
+ inkscape:version="0.91 r13725"
+ sodipodi:docname="TheQtCompany_logo_2.svg">
+ <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>
+ <defs
+ id="defs18" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1536"
+ inkscape:window-height="801"
+ id="namedview16"
+ showgrid="false"
+ inkscape:zoom="1.1138643"
+ inkscape:cx="270.58047"
+ inkscape:cy="174.65092"
+ inkscape:window-x="-8"
+ inkscape:window-y="-8"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg2" />
+ <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/qwasmbackingstore.cpp b/src/plugins/platforms/wasm/qwasmbackingstore.cpp
new file mode 100644
index 0000000000..5b40c44807
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmbackingstore.cpp
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** 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 "qwasmbackingstore.h"
+#include "qwasmwindow.h"
+#include "qwasmcompositor.h"
+
+#include <QtGui/qopengltexture.h>
+#include <QtGui/qmatrix4x4.h>
+#include <QtGui/qpainter.h>
+#include <private/qguiapplication_p.h>
+#include <qpa/qplatformscreen.h>
+
+#include <QtGui/qbackingstore.h>
+
+QT_BEGIN_NAMESPACE
+
+QWasmBackingStore::QWasmBackingStore(QWasmCompositor *compositor, QWindow *window)
+ : QPlatformBackingStore(window)
+ , m_compositor(compositor)
+ , m_texture(new QOpenGLTexture(QOpenGLTexture::Target2D))
+{
+ QWasmWindow *wasmWindow = static_cast<QWasmWindow *>(window->handle());
+ if (wasmWindow)
+ wasmWindow->setBackingStore(this);
+}
+
+QWasmBackingStore::~QWasmBackingStore()
+{
+}
+
+QPaintDevice *QWasmBackingStore::paintDevice()
+{
+ return &m_image;
+}
+
+void QWasmBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
+{
+ Q_UNUSED(window);
+ Q_UNUSED(region);
+ Q_UNUSED(offset);
+
+ m_dirty |= region;
+ m_compositor->requestRedraw();
+}
+
+void QWasmBackingStore::updateTexture()
+{
+ if (m_dirty.isNull())
+ return;
+
+ 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;
+ 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);
+
+ // intersect with image rect to be sure
+ QRect r = imageRect & deviceRect;
+ // if the rect is wide enough it is cheaper to just extend it instead of doing an image copy
+ if (r.width() >= imageRect.width() / 2) {
+ r.setX(0);
+ r.setWidth(imageRect.width());
+ }
+
+ fixed |= 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 */
+
+ m_dirty = QRegion();
+}
+
+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())
+ 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);
+}
+
+void QWasmBackingStore::resize(const QSize &size, const QRegion &staticContents)
+{
+ Q_UNUSED(staticContents)
+
+ m_image = QImage(size * window()->devicePixelRatio(), QImage::Format_RGB32);
+ m_image.setDevicePixelRatio(window()->devicePixelRatio());
+
+ if (m_texture->isCreated())
+ m_texture->destroy();
+}
+
+QImage QWasmBackingStore::toImage() const
+{
+ // used by QPlatformBackingStore::composeAndFlush
+ return m_image;
+}
+
+const QImage &QWasmBackingStore::getImageRef() const
+{
+ return m_image;
+}
+
+const QOpenGLTexture *QWasmBackingStore::getUpdatedTexture()
+{
+ updateTexture();
+ return m_texture.data();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmbackingstore.h b/src/plugins/platforms/wasm/qwasmbackingstore.h
new file mode 100644
index 0000000000..6ffa262e3d
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmbackingstore.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** 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 QWASMBACKINGSTORE_H
+#define QWASMBACKINGSTORE_H
+
+#include <qpa/qplatformbackingstore.h>
+#include <QtGui/qimage.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLTexture;
+class QRegion;
+class QWasmCompositor;
+
+class QWasmBackingStore : public QPlatformBackingStore
+{
+public:
+ QWasmBackingStore(QWasmCompositor *compositor, QWindow *window);
+ ~QWasmBackingStore();
+
+ QPaintDevice *paintDevice() override;
+
+ void beginPaint(const QRegion &) 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;
+ const QImage &getImageRef() const;
+
+ const QOpenGLTexture *getUpdatedTexture();
+
+protected:
+ void updateTexture();
+
+private:
+ QWasmCompositor *m_compositor;
+ QImage m_image;
+ QScopedPointer<QOpenGLTexture> m_texture;
+ QRegion m_dirty;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWASMBACKINGSTORE_H
diff --git a/src/plugins/platforms/wasm/qwasmcompositor.cpp b/src/plugins/platforms/wasm/qwasmcompositor.cpp
new file mode 100644
index 0000000000..3dc6b7d2f3
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmcompositor.cpp
@@ -0,0 +1,721 @@
+/****************************************************************************
+**
+** 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 "qwasmcompositor.h"
+#include "qwasmwindow.h"
+#include "qwasmstylepixmaps_p.h"
+
+#include <QtGui/qopengltexture.h>
+
+#include <QtGui/private/qwindow_p.h>
+#include <QtGui/qopenglcontext.h>
+#include <QtGui/qopenglfunctions.h>
+#include <QtGui/qopengltextureblitter.h>
+#include <QtGui/qpainter.h>
+#include <private/qpixmapcache_p.h>
+
+#include <private/qguiapplication_p.h>
+
+#include <qpa/qwindowsysteminterface.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtGui/qguiapplication.h>
+
+Q_GUI_EXPORT int qt_defaultDpiX();
+
+QWasmCompositedWindow::QWasmCompositedWindow()
+ : window(nullptr)
+ , parentWindow(nullptr)
+ , flushPending(false)
+ , visible(false)
+{
+}
+
+QWasmCompositor::QWasmCompositor()
+ : m_frameBuffer(nullptr)
+ , m_blitter(new QOpenGLTextureBlitter)
+ , m_needComposit(false)
+ , m_inFlush(false)
+ , m_inResize(false)
+ , m_isEnabled(true)
+ , m_targetDevicePixelRatio(1)
+{
+}
+
+QWasmCompositor::~QWasmCompositor()
+{
+ delete m_frameBuffer;
+}
+
+void QWasmCompositor::setEnabled(bool enabled)
+{
+ m_isEnabled = enabled;
+}
+
+void QWasmCompositor::addWindow(QWasmWindow *window, QWasmWindow *parentWindow)
+{
+ 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);
+}
+
+void QWasmCompositor::removeWindow(QWasmWindow *window)
+{
+ QWasmWindow *platformWindow = m_compositedWindows[window].parentWindow;
+
+ if (platformWindow) {
+ QWasmWindow *parentWindow = window;
+ m_compositedWindows[parentWindow].childWindows.removeAll(window);
+ }
+
+ m_windowStack.removeAll(window);
+ m_compositedWindows.remove(window);
+
+ notifyTopWindowChanged(window);
+}
+
+void QWasmCompositor::setScreen(QWasmScreen *screen)
+{
+ m_screen = screen;
+}
+
+void QWasmCompositor::setVisible(QWasmWindow *window, bool visible)
+{
+ QWasmCompositedWindow &compositedWindow = m_compositedWindows[window];
+ if (compositedWindow.visible == visible)
+ 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)
+ 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;
+
+ m_windowStack.removeAll(window);
+ m_windowStack.prepend(window);
+ QWasmCompositedWindow &compositedWindow = m_compositedWindows[window];
+ m_globalDamage = compositedWindow.window->geometry(); // repaint previosly covered area.
+
+ 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));
+}
+
+QWindow *QWasmCompositor::windowAt(QPoint p, 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(p))
+ 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();
+
+ QOpenGLTexture const *texture = backingStore->getUpdatedTexture();
+
+ blit(blitter, screen, texture, window->geometry());
+}
+
+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;
+ };
+
+ 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);
+}
+
+QWasmCompositor::QWasmTitleBarOptions QWasmCompositor::makeTitleBarOptions(const QWasmWindow *window)
+{
+ int width = window->windowFrameGeometry().width();
+ int border = window->borderWidth();
+
+ 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;
+ }
+ 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;
+}
+
+void QWasmCompositor::drawWindowDecorations(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window)
+{
+ 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);
+
+ QWasmFrameOptions frameOptions;
+ frameOptions.rect = QRect(0, 0, width, height);
+ frameOptions.lineWidth = dpiScaled(4.);
+
+ 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);
+ }
+
+ 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)
+{
+ 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;
+}
+
+void QWasmCompositor::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment,
+ const QPixmap &pixmap) const
+{
+ 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_windowStack.empty() || !m_screen)
+ return;
+
+ QWasmWindow *someWindow = nullptr;
+
+ foreach (QWasmWindow *window, 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());
+ //mContext->setFormat(mScreen->format());
+ m_context->setScreen(m_screen->screen());
+ m_context->create();
+ }
+
+ m_context->makeCurrent(someWindow->window());
+
+ if (!m_blitter->isCreated())
+ m_blitter->create();
+
+ qreal dpr = m_screen->devicePixelRatio();
+ glViewport(0, 0, m_screen->geometry().width() * dpr, m_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);
+
+ foreach (QWasmWindow *window, m_windowStack) {
+ QWasmCompositedWindow &compositedWindow = m_compositedWindows[window];
+
+ if (!compositedWindow.visible)
+ continue;
+
+ drawWindow(m_blitter.data(), m_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()));
+ return;
+ }
+
+ requestRedraw();
+ QWindowSystemInterface::handleWindowActivated(window->window());
+}
diff --git a/src/plugins/platforms/wasm/qwasmcompositor.h b/src/plugins/platforms/wasm/qwasmcompositor.h
new file mode 100644
index 0000000000..4e5ed46cec
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmcompositor.h
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** 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 QWASMCOMPOSITOR_H
+#define QWASMCOMPOSITOR_H
+
+#include <QtGui/qregion.h>
+#include <qpa/qplatformwindow.h>
+
+#include <QtGui/qopengltextureblitter.h>
+#include <QtGui/qopengltexture.h>
+#include <QtGui/qpalette.h>
+#include <QtGui/qpainter.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWasmWindow;
+class QWasmScreen;
+class QOpenGLContext;
+class QOpenGLTextureBlitter;
+
+class QWasmCompositedWindow
+{
+public:
+ QWasmCompositedWindow();
+
+ QWasmWindow *window;
+ QWasmWindow *parentWindow;
+ QRegion damage;
+ bool flushPending;
+ bool visible;
+ QList<QWasmWindow *> childWindows;
+};
+
+class QWasmCompositor : public QObject
+{
+ Q_OBJECT
+public:
+ QWasmCompositor();
+ ~QWasmCompositor();
+
+ 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);
+ void setScreen(QWasmScreen *screen);
+
+ 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);
+
+ int windowCount() const;
+
+ void redrawWindowContent();
+ void requestRedraw();
+
+ QWindow *windowAt(QPoint p, int padding = 0) const;
+ QWindow *keyWindow() const;
+
+ bool event(QEvent *event);
+
+ static QWasmTitleBarOptions makeTitleBarOptions(const QWasmWindow *window);
+ static QRect titlebarRect(QWasmTitleBarOptions tb, QWasmCompositor::SubControls subcontrol);
+
+private slots:
+ void frame();
+
+private:
+ void createFrameBuffer();
+ void flushCompletedCallback(int32_t);
+ 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;
+ QWasmScreen *m_screen;
+
+ 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;
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QWasmCompositor::SubControls)
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/wasm/qwasmcursor.cpp b/src/plugins/platforms/wasm/qwasmcursor.cpp
new file mode 100644
index 0000000000..54804a55b3
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmcursor.cpp
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** 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 "qwasmcursor.h"
+
+#include <QtCore/qdebug.h>
+
+#include <emscripten/emscripten.h>
+
+void QWasmCursor::changeCursor(QCursor *windowCursor, QWindow *window)
+{
+ if (windowCursor == nullptr)
+ return;
+
+ // FIXME: The HTML5 plugin sets the cursor on the native canvas; when using multiple windows
+ // multiple cursors need to be managed taking mouse postion and stacking into account.
+ Q_UNUSED(window);
+
+ // 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 main canvas
+ EM_ASM_ARGS({
+ if (Module['canvas']) {
+ Module['canvas'].style['cursor'] = Pointer_stringify($0);
+ }
+ }, htmlCursorName.constData());
+}
+
+QByteArray QWasmCursor::cursorShapeToHtml(Qt::CursorShape shape)
+{
+ QByteArray cursorName;
+
+ switch (shape) {
+ case Qt::ArrowCursor:
+ cursorName = "default";
+ break;
+ case Qt::UpArrowCursor:
+ break;
+ case Qt::CrossCursor:
+ cursorName = "crosshair";
+ break;
+ case Qt::WaitCursor:
+ cursorName = "wait";
+ break;
+ case Qt::IBeamCursor:
+ cursorName = "text";
+ break;
+ case Qt::SizeVerCursor:
+ cursorName = "ns-resize";
+ break;
+ case Qt::SizeHorCursor:
+ cursorName = "ew-resize";
+ break;
+ case Qt::SizeBDiagCursor:
+ cursorName = "nesw-resize";
+ break;
+ case Qt::SizeFDiagCursor:
+ cursorName = "nwse-resize";
+ break;
+ case Qt::SizeAllCursor:
+ break; // no equivalent?
+ case Qt::BlankCursor:
+ cursorName = "none";
+ break;
+ case Qt::SplitVCursor:
+ cursorName = "row-resize";
+ break;
+ case Qt::SplitHCursor:
+ cursorName = "col-resize";
+ break;
+ case Qt::PointingHandCursor:
+ cursorName = "pointer";
+ break;
+ case Qt::ForbiddenCursor:
+ cursorName = "not-allowed";
+ break;
+ case Qt::WhatsThisCursor:
+ cursorName = "help";
+ break;
+ case Qt::BusyCursor:
+ cursorName = "wait";
+ break;
+ case Qt::OpenHandCursor:
+ break; // no equivalent?
+ case Qt::ClosedHandCursor:
+ break; // no equivalent?
+ case Qt::DragCopyCursor:
+ break; // no equivalent?
+ case Qt::DragMoveCursor:
+ break; // no equivalent?
+ case Qt::DragLinkCursor:
+ break; // no equivalent?
+ default:
+ break;
+ }
+
+ return cursorName;
+}
diff --git a/src/plugins/platforms/wasm/qwasmcursor.h b/src/plugins/platforms/wasm/qwasmcursor.h
new file mode 100644
index 0000000000..516e07aa31
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmcursor.h
@@ -0,0 +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$
+**
+****************************************************************************/
+
+#ifndef QWASMCURSOR_H
+#define QWASMCURSOR_H
+
+#include <qpa/qplatformcursor.h>
+
+class QWasmCursor : public QPlatformCursor
+{
+public:
+ void changeCursor(QCursor *windowCursor, QWindow *window) override;
+
+ QByteArray cursorShapeToHtml(Qt::CursorShape shape);
+};
+
+#endif
diff --git a/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp b/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp
new file mode 100644
index 0000000000..41355d72ae
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** 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 "qwasmeventdispatcher.h"
+
+#include <QtCore/qcoreapplication.h>
+
+#include <emscripten.h>
+
+class QWasmEventDispatcherPrivate : public QEventDispatcherUNIXPrivate
+{
+
+};
+
+QWasmEventDispatcher *g_htmlEventDispatcher;
+
+QWasmEventDispatcher::QWasmEventDispatcher(QObject *parent)
+ : QUnixEventDispatcherQPA(parent)
+{
+
+ g_htmlEventDispatcher = this;
+}
+
+QWasmEventDispatcher::~QWasmEventDispatcher()
+{
+ 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;
+}
+
+void QWasmEventDispatcher::maintainTimers()
+{
+ if (!g_htmlEventDispatcher || !g_htmlEventDispatcher->m_hasMainLoop)
+ return;
+
+ g_htmlEventDispatcher->doMaintainTimers();
+}
+
+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;
+}
diff --git a/src/plugins/platforms/wasm/qwasmeventdispatcher.h b/src/plugins/platforms/wasm/qwasmeventdispatcher.h
new file mode 100644
index 0000000000..5300b3de73
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmeventdispatcher.h
@@ -0,0 +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: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 QWASMEVENTDISPATCHER_H
+#define QWASMEVENTDISPATCHER_H
+
+#include <QtCore/qhash.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtEventDispatcherSupport/private/qunixeventdispatcher_qpa_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWasmEventDispatcherPrivate;
+
+class QWasmEventDispatcher : public QUnixEventDispatcherQPA
+{
+ 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();
+
+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;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp
new file mode 100644
index 0000000000..cc48c15b64
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp
@@ -0,0 +1,555 @@
+/****************************************************************************
+**
+** 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 <QtGui/qevent.h>
+#include <qpa/qwindowsysteminterface.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qobject.h>
+
+#include <QtCore/qdeadlinetimer.h>
+#include <emscripten/bind.h>
+
+#include <iostream>
+
+QT_BEGIN_NAMESPACE
+using namespace emscripten;
+
+// 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 = false;
+
+void setNaturalScrolling(bool use) {
+ g_useNaturalScrolling = use;
+}
+
+EMSCRIPTEN_BINDINGS(mouse_module) {
+ function("setNaturalScrolling", &setNaturalScrolling);
+}
+
+QWasmEventTranslator::QWasmEventTranslator(QObject *parent)
+ : QObject(parent)
+ , draggedWindow(nullptr)
+ , pressedButtons(Qt::NoButton)
+ , resizeMode(QWasmWindow::ResizeNone)
+{
+ emscripten_set_keydown_callback(0, (void *)this, 1, &keyboard_cb);
+ emscripten_set_keyup_callback(0, (void *)this, 1, &keyboard_cb);
+
+ emscripten_set_mousedown_callback(0, (void *)this, 1, &mouse_cb);
+ emscripten_set_mouseup_callback(0, (void *)this, 1, &mouse_cb);
+ emscripten_set_mousemove_callback(0, (void *)this, 1, &mouse_cb);
+
+ emscripten_set_focus_callback(0, (void *)this, 1, &focus_cb);
+
+ emscripten_set_wheel_callback(0, (void *)this, 1, &wheel_cb);
+
+ touchDevice = new QTouchDevice;
+ touchDevice->setType(QTouchDevice::TouchScreen);
+ touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::NormalizedPosition);
+ QWindowSystemInterface::registerTouchDevice(touchDevice);
+
+ emscripten_set_touchstart_callback("#canvas", (void *)this, 1, &touchCallback);
+ emscripten_set_touchend_callback("#canvas", (void *)this, 1, &touchCallback);
+ emscripten_set_touchmove_callback("#canvas", (void *)this, 1, &touchCallback);
+ emscripten_set_touchcancel_callback("#canvas", (void *)this, 1, &touchCallback);
+
+ // The Platform Detect: expand coverage and move as needed
+ enum Platform {
+ GenericPlatform,
+ MacOSPlatform
+ };
+ Platform platform =
+ Platform(EM_ASM_INT("if (navigator.platform.includes(\"Mac\")) return 1; return 0;"));
+
+ g_usePlatformMacCtrlMetaSwitching = (platform == MacOSPlatform);
+
+ if (platform == MacOSPlatform) {
+ g_useNaturalScrolling = true; //make this default on macOS
+ EM_ASM(
+ if (window.safari !== undefined) {//this only works on safari
+ Module["canvas"].addEventListener('wheel', mouseWheelEvent);
+ function mouseWheelEvent(e) {
+ if (event.webkitDirectionInvertedFromDevice) {
+ Module.setNaturalScrolling(event.webkitDirectionInvertedFromDevice);
+ }
+ }
+ }
+ );
+ }
+}
+
+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)
+{
+ Q_UNUSED(userData)
+
+ bool alphanumeric;
+ Qt::Key qtKey = translateEmscriptKey(keyEvent, &alphanumeric);
+
+ QEvent::Type keyType = QEvent::None;
+ switch (eventType) {
+ case EMSCRIPTEN_EVENT_KEYPRESS:
+ case EMSCRIPTEN_EVENT_KEYDOWN: //down
+ keyType = QEvent::KeyPress;
+ break;
+ case EMSCRIPTEN_EVENT_KEYUP: //up
+ keyType = QEvent::KeyRelease;
+ break;
+ default:
+ break;
+ };
+
+ if (keyType == QEvent::None)
+ return 0;
+
+ QString keyText = alphanumeric ? QString(keyEvent->key) : QString();
+ bool accepted = QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(
+ 0, keyType, qtKey, translateKeyboardEventModifier(keyEvent), keyText);
+ QWasmEventDispatcher::maintainTimers();
+ return accepted ? 1 : 0;
+}
+
+Qt::Key QWasmEventTranslator::translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey, bool *outAlphanumeric)
+{
+ Qt::Key qtKey;
+ if (outAlphanumeric)
+ *outAlphanumeric = false;
+
+ switch (emscriptKey->keyCode) {
+ case KeyMultiply: qtKey = Qt::Key_Asterisk; *outAlphanumeric = true; break;
+ case KeyAdd: qtKey = Qt::Key_Plus; *outAlphanumeric = true; break;
+ case KeyMinus: qtKey = Qt::Key_Minus; *outAlphanumeric = true; break;
+ case KeySubtract: qtKey = Qt::Key_Minus; *outAlphanumeric = true; break;
+ case KeyDecimal: qtKey = Qt::Key_Period; *outAlphanumeric = true; break;
+ case KeyDivide: qtKey = Qt::Key_Slash; *outAlphanumeric = true; break;
+ case KeyNumPad0: qtKey = Qt::Key_0; *outAlphanumeric = true; break;
+ case KeyNumPad1: qtKey = Qt::Key_1; *outAlphanumeric = true; break;
+ case KeyNumPad2: qtKey = Qt::Key_2; *outAlphanumeric = true; break;
+ case KeyNumPad3: qtKey = Qt::Key_3; *outAlphanumeric = true; break;
+ case KeyNumPad4: qtKey = Qt::Key_4; *outAlphanumeric = true; break;
+ case KeyNumPad5: qtKey = Qt::Key_5; *outAlphanumeric = true; break;
+ case KeyNumPad6: qtKey = Qt::Key_6; *outAlphanumeric = true; break;
+ case KeyNumPad7: qtKey = Qt::Key_7; *outAlphanumeric = true; break;
+ case KeyNumPad8: qtKey = Qt::Key_8; *outAlphanumeric = true; break;
+ case KeyNumPad9: qtKey = Qt::Key_9; *outAlphanumeric = true; break;
+ case KeyComma: qtKey = Qt::Key_Comma; *outAlphanumeric = true; break;
+ case KeyPeriod: qtKey = Qt::Key_Period; *outAlphanumeric = true; break;
+ case KeySlash: qtKey = Qt::Key_Slash; *outAlphanumeric = true; break;
+ case KeySemiColon: qtKey = Qt::Key_Semicolon; *outAlphanumeric = true; break;
+ case KeyEquals: qtKey = Qt::Key_Equal; *outAlphanumeric = true; break;
+ case KeyOpenBracket: qtKey = Qt::Key_BracketLeft; *outAlphanumeric = true; break;
+ case KeyCloseBracket: qtKey = Qt::Key_BracketRight; *outAlphanumeric = true; break;
+ case KeyBackSlash: qtKey = Qt::Key_Backslash; *outAlphanumeric = true; break;
+ case KeyMeta:
+ Q_FALLTHROUGH();
+ case KeyMetaRight:
+ qtKey = Qt::Key_Meta;
+ break;
+ case KeyTab: qtKey = Qt::Key_Tab; break;
+ case KeyClear: qtKey = Qt::Key_Clear; break;
+ case KeyBackSpace: qtKey = Qt::Key_Backspace; break;
+ case KeyEnter: qtKey = Qt::Key_Return; break;
+ case KeyShift: qtKey = Qt::Key_Shift; break;
+ case KeyControl: qtKey = Qt::Key_Control; break;
+ case KeyAlt: qtKey = Qt::Key_Alt; break;
+ case KeyCapsLock: qtKey = Qt::Key_CapsLock; break;
+ case KeyEscape: qtKey = Qt::Key_Escape; break;
+ case KeyPageUp: qtKey = Qt::Key_PageUp; break;
+ case KeyPageDown: qtKey = Qt::Key_PageDown; break;
+ case KeyEnd: qtKey = Qt::Key_End; break;
+ case KeyHome: qtKey = Qt::Key_Home; break;
+ case KeyLeft: qtKey = Qt::Key_Left; break;
+ case KeyUp: qtKey = Qt::Key_Up; break;
+ case KeyRight: qtKey = Qt::Key_Right; break;
+ case KeyDown: qtKey = Qt::Key_Down; break;
+ case KeyBrightnessDown: qtKey = Qt::Key_MonBrightnessDown; break;
+ case KeyBrightnessUp: qtKey = Qt::Key_MonBrightnessUp; break;
+ case KeyMediaTrackPrevious: qtKey = Qt::Key_MediaPrevious; break;
+ case KeyMediaPlayPause: qtKey = Qt::Key_MediaTogglePlayPause; break;
+ case KeyMediaTrackNext: qtKey = Qt::Key_MediaNext; break;
+ case KeyAudioVolumeMute: qtKey = Qt::Key_VolumeMute; break;
+ case KeyAudioVolumeDown: qtKey = Qt::Key_VolumeDown; break;
+ case KeyAudioVolumeUp: qtKey = Qt::Key_VolumeUp; break;
+ case KeyDelete: qtKey = Qt::Key_Delete; break;
+
+ case KeyF1: qtKey = Qt::Key_F1; break;
+ case KeyF2: qtKey = Qt::Key_F2; break;
+ case KeyF3: qtKey = Qt::Key_F3; break;
+ case KeyF4: qtKey = Qt::Key_F4; break;
+ case KeyF5: qtKey = Qt::Key_F5; break;
+ case KeyF6: qtKey = Qt::Key_F6; break;
+ case KeyF7: qtKey = Qt::Key_F7; break;
+ case KeyF8: qtKey = Qt::Key_F8; break;
+ case KeyF9: qtKey = Qt::Key_F9; break;
+ case KeyF10: qtKey = Qt::Key_F10; break;
+ case KeyF11: qtKey = Qt::Key_F11; break;
+ case KeyF12: qtKey = Qt::Key_F12; break;
+ case 124: qtKey = Qt::Key_F13; break;
+ case 125: qtKey = Qt::Key_F14; break;
+
+ case KeySpace:
+ default:
+ if (outAlphanumeric)
+ *outAlphanumeric = true;
+ qtKey = static_cast<Qt::Key>(emscriptKey->keyCode);
+ break;
+ }
+
+ // Handle Mac command key. Using event->keyCode as above is
+ // no reliable since the codes differ between browsers.
+ if (qstrncmp(emscriptKey->key, "Meta", 4) == 0) {
+ qtKey = Qt::Key_Meta;
+ *outAlphanumeric = false;
+ }
+
+ if (g_usePlatformMacCtrlMetaSwitching) {
+ if (qtKey == Qt::Key_Meta)
+ qtKey = Qt::Key_Control;
+ else if (qtKey == Qt::Key_Control)
+ qtKey = Qt::Key_Meta;
+ }
+
+ 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 = mouseEvent->timestamp;
+ QPoint point(mouseEvent->canvasX, mouseEvent->canvasY);
+
+ QEvent::Type buttonEventType = QEvent::None;
+
+ Qt::MouseButton button = translateMouseButton(mouseEvent->button);
+ Qt::KeyboardModifiers modifiers = translateMouseEventModifier(mouseEvent);
+
+ QWindow *window2 = QWasmIntegration::get()->compositor()->windowAt(point, 5);
+ QWasmWindow *htmlWindow = static_cast<QWasmWindow*>(window2->handle());
+ bool onFrame = false;
+ if (window2 && !window2->geometry().contains(point))
+ onFrame = true;
+
+ QPoint localPoint(point.x() - window2->geometry().x(), point.y() - window2->geometry().y());
+
+ switch (eventType) {
+ case 5: //down
+ {
+ if (window2)
+ window2->raise();
+
+ 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(point))
+ draggedWindow = window2;
+ else if (htmlWindow && htmlWindow->isPointOnResizeRegion(point)) {
+ draggedWindow = window2;
+ resizeMode = htmlWindow->resizeModeAtPoint(point);
+ resizePoint = point;
+ resizeStartRect = window2->geometry();
+ }
+ }
+ }
+
+ htmlWindow->injectMousePressed(localPoint, point, button, modifiers);
+ break;
+ }
+ case 6: //up
+ {
+ 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, point, button, modifiers);
+ break;
+ }
+ case 8://move //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->canvasX, mouseEvent->canvasY) - resizePoint;
+ resizeWindow(draggedWindow, resizeMode, resizeStartRect, delta);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ };
+
+ if (window2 && !onFrame) {
+ QWindowSystemInterface::handleMouseEvent<QWindowSystemInterface::SynchronousDelivery>(
+ window2, timestamp, localPoint, point, 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)
+ Q_UNUSED(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;
+
+ Qt::KeyboardModifiers modifiers = translateMouseEventModifier(&mouseEvent);
+ auto timestamp = mouseEvent.timestamp;
+ QPoint globalPoint(mouseEvent.canvasX, mouseEvent.canvasY);
+
+ QWindow *window2 = QWasmIntegration::get()->compositor()->windowAt(globalPoint, 5);
+
+ QPoint localPoint(globalPoint.x() - window2->geometry().x(), globalPoint.y() - window2->geometry().y());
+
+ 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);
+ return 1;
+}
+
+int QWasmEventTranslator::touchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
+{
+ 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 point(touches->canvasX, touches->canvasY);
+ window2 = QWasmIntegration::get()->compositor()->windowAt(point, 5);
+
+ QWindowSystemInterface::TouchPoint touchPoint;
+
+ auto cX = point.x();
+ auto cY = point.y();
+ touchPoint.area = QRect(0, 0, 8, 8);
+ touchPoint.area.moveCenter(QPointF(cX,cY)); // simulate area
+
+ touchPoint.id = touches->identifier;
+ touchPoint.normalPosition = QPointF(cX / window2->width(), cY / window2->height());
+
+ switch (eventType) {
+ case EMSCRIPTEN_EVENT_TOUCHSTART:
+ touchPoint.state = Qt::TouchPointPressed;
+ break;
+ case EMSCRIPTEN_EVENT_TOUCHEND:
+ touchPoint.state = Qt::TouchPointReleased;
+ break;
+ case EMSCRIPTEN_EVENT_TOUCHMOVE:
+ touchPoint.state = Qt::TouchPointMoved;
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+
+ touchPointList.append(touchPoint);
+ }
+
+ QWasmEventTranslator *wasmEventTranslator = (QWasmEventTranslator*)userData;
+ QFlags<Qt::KeyboardModifier> keyModifier = translatKeyModifier(touchEvent);
+
+ if (eventType != EMSCRIPTEN_EVENT_TOUCHCANCEL)
+ QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(window2, wasmEventTranslator->getTimestamp(), wasmEventTranslator->touchDevice, touchPointList, keyModifier);
+ else
+ QWindowSystemInterface::handleTouchCancelEvent(window2, wasmEventTranslator->getTimestamp(), wasmEventTranslator->touchDevice, keyModifier);
+
+ QCoreApplication::processEvents();
+ return 1;
+}
+
+quint64 QWasmEventTranslator::getTimestamp()
+{
+ return QDeadlineTimer::current().deadlineNSecs() / 1000;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.h b/src/plugins/platforms/wasm/qwasmeventtranslator.h
new file mode 100644
index 0000000000..11430a57a2
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmeventtranslator.h
@@ -0,0 +1,210 @@
+/****************************************************************************
+**
+** 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>
+
+QT_BEGIN_NAMESPACE
+
+class QWindow;
+
+class QWasmEventTranslator : public QObject
+{
+ Q_OBJECT
+
+ enum KeyCode {
+ // numpad
+ KeyNumPad0 = 0x60,
+ KeyNumPad1 = 0x61,
+ KeyNumPad2 = 0x62,
+ KeyNumPad3 = 0x63,
+ KeyNumPad4 = 0x64,
+ KeyNumPad5 = 0x65,
+ KeyNumPad6 = 0x66,
+ KeyNumPad7 = 0x67,
+ KeyNumPad8 = 0x68,
+ KeyNumPad9 = 0x69,
+ KeyMultiply = 0x6A,
+ KeyAdd = 0x6B,
+ KeySeparator = 0x6C,
+ KeySubtract = 0x6D,
+ KeyDecimal = 0x6E,
+ KeyDivide = 0x6F,
+ KeyMeta = 0x5B,
+ KeyMetaRight = 0x5C,
+ ////////
+ KeyClear = 0x90,
+ KeyEnter = 0xD,
+ KeyBackSpace = 0x08,
+ KeyCancel = 0x03,
+ KeyTab = 0x09,
+ KeyShift = 0x10,
+ KeyControl = 0x11,
+ KeyAlt = 0x12,
+ KeyPause = 0x13,
+ KeyCapsLock = 0x14,
+ KeyEscape = 0x1B,
+ KeySpace = 0x20,
+ KeyPageUp = 0x21,
+ KeyPageDown = 0x22,
+ KeyEnd = 0x23,
+ KeyHome = 0x24,
+ KeyLeft = 0x25,
+ KeyUp = 0x26,
+ KeyRight = 0x27,
+ KeyDown = 0x28,
+ KeyComma = 0xBC,
+ KeyPeriod = 0xBE,
+ KeySlash = 0xBF,
+ KeyZero = 0x30,
+ KeyOne = 0x31,
+ KeyTwo = 0x32,
+ KeyThree = 0x33,
+ KeyFour = 0x34,
+ KeyFive = 0x35,
+ KeySix = 0x36,
+ KeySeven = 0x37,
+ KeyEight = 0x38,
+ KeyNine = 0x39,
+ KeyBrightnessDown = 0xD8,
+ KeyBrightnessUp = 0xD9,
+ KeyMediaTrackPrevious = 0xB1,
+ KeyMediaPlayPause = 0xB3,
+ KeyMediaTrackNext = 0xB0,
+ KeyAudioVolumeMute = 0xAD,
+ KeyAudioVolumeDown = 0xAE,
+ KeyAudioVolumeUp = 0xAF,
+ KeySemiColon = 0xBA,
+ KeyEquals = 0xBB,
+ KeyMinus = 0xBD,
+ KeyA = 0x41,
+ KeyB = 0x42,
+ KeyC = 0x43,
+ KeyD = 0x44,
+ KeyE = 0x45,
+ KeyF = 0x46,
+ KeyG = 0x47,
+ KeyH = 0x48,
+ KeyI = 0x49,
+ KeyJ = 0x4A,
+ KeyK = 0x4B,
+ KeyL = 0x4C,
+ KeyM = 0x4D,
+ KeyN = 0x4E,
+ KeyO = 0x4F,
+ KeyP = 0x50,
+ KeyQ = 0x51,
+ KeyR = 0x52,
+ KeyS = 0x53,
+ KeyT = 0x54,
+ KeyU = 0x55,
+ KeyV = 0x56,
+ KeyW = 0x57,
+ KeyX = 0x58,
+ KeyY = 0x59,
+ KeyZ = 0x5A,
+ KeyOpenBracket = 0xDB,
+ KeyBackSlash = 0xDC,
+ KeyCloseBracket = 0xDD,
+ KeyF1 = 0x70,
+ KeyF2 = 0x71,
+ KeyF3 = 0x72,
+ KeyF4 = 0x73,
+ KeyF5 = 0x74,
+ KeyF6 = 0x75,
+ KeyF7 = 0x76,
+ KeyF8 = 0x77,
+ KeyF9 = 0x78,
+ KeyF10 = 0x79,
+ KeyF11 = 0x7A,
+ KeyF12 = 0x7B,
+ KeyDelete = 0x2E,
+ KeyNumLock = 0x90,
+ KeyScrollLock = 0x91,
+ KeyPrintScreen = 0x9A,
+ KeyInsert = 0x9B,
+ KeyHelp = 0x9C,
+ KeyBackQuote = 0xC0,
+ KeyQuote = 0xDE,
+ KeyFinal = 0x18,
+ KeyConvert = 0x1C,
+ KeyNonConvert = 0x1D,
+ KeyAccept = 0x1E,
+ KeyModeChange = 0x1F,
+ KeyKana = 0x15,
+ KeyKanji = 0x19,
+ KeyUndefined = 0x0
+ };
+
+public:
+
+ explicit QWasmEventTranslator(QObject *parent = 0);
+
+ 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();
+
+Q_SIGNALS:
+ void getWindowAt(const QPoint &point, QWindow **window);
+private:
+ static Qt::Key translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey, bool *outAlphanumretic);
+ template <typename Event>
+ static QFlags<Qt::KeyboardModifier> translatKeyModifier(const Event *event);
+ static QFlags<Qt::KeyboardModifier> translateKeyboardEventModifier(const EmscriptenKeyboardEvent *keyEvent);
+ static QFlags<Qt::KeyboardModifier> translateMouseEventModifier(const EmscriptenMouseEvent *mouseEvent);
+ static Qt::MouseButton translateMouseButton(unsigned short button);
+
+ void processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent);
+
+private:
+ QWindow *draggedWindow;
+ QWindow *pressedWindow;
+ Qt::MouseButtons pressedButtons;
+
+ QWasmWindow::ResizeMode resizeMode;
+ QPoint resizePoint;
+ QRect resizeStartRect;
+ QTouchDevice *touchDevice;
+ quint64 getTimestamp();
+};
+
+QT_END_NAMESPACE
+#endif // QWASMEVENTTRANSLATOR_H
diff --git a/src/plugins/platforms/wasm/qwasmfontdatabase.cpp b/src/plugins/platforms/wasm/qwasmfontdatabase.cpp
new file mode 100644
index 0000000000..0c72dfddc4
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmfontdatabase.cpp
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** 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 "qwasmfontdatabase.h"
+
+#include <QtCore/qfile.h>
+
+QT_BEGIN_NAMESPACE
+
+void QWasmFontDatabase::populateFontDatabase()
+{
+ // Load font file from resources. Currently
+ // all fonts needs to be bundled with the nexe
+ // as Qt resources.
+ QStringList fontFileNames = QStringList() << QStringLiteral(":/fonts/Vera.ttf")
+ << QStringLiteral(":/fonts/DejaVuSans.ttf");
+
+ foreach (const QString &fontFileName, fontFileNames) {
+ QFile theFont(fontFileName);
+ if (!theFont.open(QIODevice::ReadOnly))
+ break;
+
+ QFreeTypeFontDatabase::addTTFile(theFont.readAll(), fontFileName.toLatin1());
+ }
+}
+
+QFontEngine *QWasmFontDatabase::fontEngine(const QFontDef &fontDef, void *handle)
+{
+ return QFreeTypeFontDatabase::fontEngine(fontDef, handle);
+}
+
+QStringList QWasmFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style,
+ QFont::StyleHint styleHint,
+ QChar::Script script) const
+{
+ QStringList fallbacks
+ = QFreeTypeFontDatabase::fallbacksForFamily(family, style, styleHint, script);
+
+ // Add the vera.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);
+
+ return fallbacks;
+}
+
+QStringList QWasmFontDatabase::addApplicationFont(const QByteArray &fontData,
+ const QString &fileName)
+{
+ return QFreeTypeFontDatabase::addApplicationFont(fontData, fileName);
+}
+
+void QWasmFontDatabase::releaseHandle(void *handle)
+{
+ QFreeTypeFontDatabase::releaseHandle(handle);
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmfontdatabase.h b/src/plugins/platforms/wasm/qwasmfontdatabase.h
new file mode 100644
index 0000000000..891f12859e
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmfontdatabase.h
@@ -0,0 +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$
+**
+****************************************************************************/
+
+#ifndef QWASMFONTDATABASE_H
+#define QWASMFONTDATABASE_H
+
+#include <QtFontDatabaseSupport/private/qfreetypefontdatabase_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWasmFontDatabase : public QFreeTypeFontDatabase
+{
+public:
+ 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;
+};
+QT_END_NAMESPACE
+#endif
diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp
new file mode 100644
index 0000000000..1be909f0a0
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmintegration.cpp
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** 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 "qwasmintegration.h"
+#include "qwasmeventtranslator.h"
+#include "qwasmeventdispatcher.h"
+#include "qwasmcompositor.h"
+#include "qwasmopenglcontext.h"
+#include "qwasmtheme.h"
+
+#include "qwasmwindow.h"
+#ifndef QT_NO_OPENGL
+# include "qwasmbackingstore.h"
+#endif
+#include "qwasmfontdatabase.h"
+#if defined(Q_OS_UNIX)
+#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
+#endif
+#include <qpa/qplatformwindow.h>
+#include <QtGui/qscreen.h>
+#include <qpa/qwindowsysteminterface.h>
+#include <QtCore/qcoreapplication.h>
+
+#include <emscripten/bind.h>
+
+// this is where EGL headers are pulled in, make sure it is last
+#include "qwasmscreen.h"
+
+using namespace emscripten;
+QT_BEGIN_NAMESPACE
+
+void browserBeforeUnload()
+{
+ QWasmIntegration::QWasmBrowserExit();
+}
+
+EMSCRIPTEN_BINDINGS(my_module)
+{
+ function("browserBeforeUnload", &browserBeforeUnload);
+}
+
+static QWasmIntegration *globalHtml5Integration;
+QWasmIntegration *QWasmIntegration::get() { return globalHtml5Integration; }
+
+QWasmIntegration::QWasmIntegration()
+ : m_fontDb(nullptr),
+ m_compositor(new QWasmCompositor),
+ m_screen(new QWasmScreen(m_compositor)),
+ m_eventDispatcher(nullptr)
+{
+
+ globalHtml5Integration = this;
+
+ updateQScreenAndCanvasRenderSize();
+ screenAdded(m_screen);
+ emscripten_set_resize_callback(0, (void *)this, 1, uiEvent_cb);
+
+ m_eventTranslator = new QWasmEventTranslator;
+
+ EM_ASM(// exit app if browser closes
+ window.onbeforeunload = function () {
+ Module.browserBeforeUnload();
+ };
+ );
+}
+
+QWasmIntegration::~QWasmIntegration()
+{
+ delete m_compositor;
+ destroyScreen(m_screen);
+ delete m_fontDb;
+ delete m_eventTranslator;
+}
+
+void QWasmIntegration::QWasmBrowserExit()
+{
+ QCoreApplication *app = QCoreApplication::instance();
+ app->quit();
+}
+
+bool QWasmIntegration::hasCapability(QPlatformIntegration::Capability cap) const
+{
+ switch (cap) {
+ case ThreadedPixmaps: return true;
+ case OpenGL: return true;
+ case ThreadedOpenGL: return true;
+ case RasterGLSurface: return false; // to enable this you need to fix qopenglwidget and quickwidget for wasm
+ case MultipleWindows: return true;
+ case WindowManagement: return true;
+ default: return QPlatformIntegration::hasCapability(cap);
+ }
+}
+
+QPlatformWindow *QWasmIntegration::createPlatformWindow(QWindow *window) const
+{
+ return new QWasmWindow(window, m_compositor, m_backingStores.value(window));
+}
+
+QPlatformBackingStore *QWasmIntegration::createPlatformBackingStore(QWindow *window) const
+{
+#ifndef QT_NO_OPENGL
+ QWasmBackingStore *backingStore = new QWasmBackingStore(m_compositor, window);
+ m_backingStores.insert(window, backingStore);
+ return backingStore;
+#else
+ return nullptr;
+#endif
+}
+
+#ifndef QT_NO_OPENGL
+QPlatformOpenGLContext *QWasmIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
+{
+ return new QWasmOpenGLContext(context->format());
+}
+#endif
+
+QPlatformFontDatabase *QWasmIntegration::fontDatabase() const
+{
+ if (m_fontDb == nullptr)
+ m_fontDb = new QWasmFontDatabase;
+
+ return m_fontDb;
+}
+
+QAbstractEventDispatcher *QWasmIntegration::createEventDispatcher() const
+{
+ return new QWasmEventDispatcher;
+}
+
+QVariant QWasmIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
+{
+ return QPlatformIntegration::styleHint(hint);
+}
+
+QStringList QWasmIntegration::themeNames() const
+{
+ return QStringList() << QLatin1String("webassembly");
+}
+
+QPlatformTheme *QWasmIntegration::createPlatformTheme(const QString &name) const
+{
+ if (name == QLatin1String("webassembly"))
+ return new QWasmTheme;
+ return QPlatformIntegration::createPlatformTheme(name);
+}
+
+int QWasmIntegration::uiEvent_cb(int eventType, const EmscriptenUiEvent *e, void *userData)
+{
+ Q_UNUSED(e)
+ Q_UNUSED(userData)
+
+ if (eventType == EMSCRIPTEN_EVENT_RESIZE) {
+ // This resize event is called when the HTML window is resized. Depending
+ // on the page layout the the canvas might also have been resized, so we
+ // update the Qt screen size (and canvas render size).
+ updateQScreenAndCanvasRenderSize();
+ }
+
+ return 0;
+}
+
+static void set_canvas_size(double width, double height)
+{
+ EM_ASM_({
+ var canvas = Module.canvas;
+ canvas.width = $0;
+ canvas.height = $1;
+ }, width, height);
+}
+
+void QWasmIntegration::updateQScreenAndCanvasRenderSize()
+{
+ // The HTML canvas has two sizes: the CSS size and the canvas render size.
+ // The CSS size is determined according to standard CSS rules, while the
+ // render size is set using the "width" and "height" attributes. The render
+ // 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.
+
+ double css_width;
+ double css_height;
+ emscripten_get_element_css_size(0, &css_width, &css_height);
+ QSizeF cssSize(css_width, css_height);
+
+ QWasmScreen *screen = QWasmIntegration::get()->m_screen;
+ QSizeF canvasSize = cssSize * screen->devicePixelRatio();
+
+ set_canvas_size(canvasSize.width(), canvasSize.height());
+ screen->setGeometry(QRect(QPoint(0, 0), cssSize.toSize()));
+ QWasmIntegration::get()->m_compositor->redrawWindowContent();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmintegration.h b/src/plugins/platforms/wasm/qwasmintegration.h
new file mode 100644
index 0000000000..ebc3d9d431
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmintegration.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** 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 QWASMINTEGRATION_H
+#define QWASMINTEGRATION_H
+
+#include "qwasmwindow.h"
+
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformscreen.h>
+
+#include <QtCore/qhash.h>
+
+#include <emscripten.h>
+#include <emscripten/html5.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWasmEventTranslator;
+class QWasmFontDatabase;
+class QWasmWindow;
+class QWasmEventDispatcher;
+class QWasmScreen;
+class QWasmCompositor;
+class QWasmBackingStore;
+
+class QWasmIntegration : public QObject, public QPlatformIntegration
+{
+ Q_OBJECT
+public:
+ QWasmIntegration();
+ ~QWasmIntegration();
+
+ bool hasCapability(QPlatformIntegration::Capability cap) const override;
+ QPlatformWindow *createPlatformWindow(QWindow *window) const override;
+ QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
+#ifndef QT_NO_OPENGL
+ QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
+#endif
+ QPlatformFontDatabase *fontDatabase() const override;
+ QAbstractEventDispatcher *createEventDispatcher() const override;
+ QVariant styleHint(QPlatformIntegration::StyleHint hint) const override;
+ QStringList themeNames() const override;
+ QPlatformTheme *createPlatformTheme(const QString &name) const override;
+
+ static QWasmIntegration *get();
+ QWasmScreen *screen() { return m_screen; }
+ QWasmCompositor *compositor() { return m_compositor; }
+ QWasmEventTranslator *eventTranslator() { return m_eventTranslator; }
+
+ static void QWasmBrowserExit();
+ static void updateQScreenAndCanvasRenderSize();
+
+private:
+ mutable QWasmFontDatabase *m_fontDb;
+ QWasmCompositor *m_compositor;
+ mutable QWasmScreen *m_screen;
+ mutable QWasmEventTranslator *m_eventTranslator;
+ mutable QWasmEventDispatcher *m_eventDispatcher;
+ static int uiEvent_cb(int eventType, const EmscriptenUiEvent *e, void *userData);
+ mutable QHash<QWindow *, QWasmBackingStore *> m_backingStores;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWASMINTEGRATION_H
diff --git a/src/plugins/platforms/wasm/qwasmopenglcontext.cpp b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp
new file mode 100644
index 0000000000..73af3d1878
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** 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 "qwasmopenglcontext.h"
+
+#include <EGL/egl.h>
+
+QT_BEGIN_NAMESPACE
+
+QWasmOpenGLContext::QWasmOpenGLContext(const QSurfaceFormat &format)
+ : m_requestedFormat(format)
+{
+ m_requestedFormat.setRenderableType(QSurfaceFormat::OpenGLES);
+}
+
+QWasmOpenGLContext::~QWasmOpenGLContext()
+{
+ if (m_context)
+ emscripten_webgl_destroy_context(m_context);
+}
+
+void QWasmOpenGLContext::maybeRecreateEmscriptenContext(QPlatformSurface *surface)
+{
+ // Native emscripten contexts are tied to a single surface. Recreate
+ // the context if the surface is changed.
+ if (surface != m_surface) {
+ m_surface = surface;
+
+ // Destroy existing context
+ if (m_context)
+ emscripten_webgl_destroy_context(m_context);
+
+ // Create new context
+ const char *canvasId = 0; // (use default canvas) FIXME: get the actual canvas from the surface.
+ m_context = createEmscriptenContext(canvasId, m_requestedFormat);
+
+ // Register context-lost callback.
+ auto callback = [](int eventType, const void *reserved, void *userData) -> EM_BOOL
+ {
+ Q_UNUSED(eventType);
+ Q_UNUSED(reserved);
+ // The application may get contex-lost if e.g. moved to the background. Set
+ // m_contextLost which will make isValid() return false. Application code will
+ // then detect this and recrate the the context, resulting in a new QWasmOpenGLContext
+ // instance.
+ reinterpret_cast<QWasmOpenGLContext *>(userData)->m_contextLost = true;
+ return true;
+ };
+ bool capture = true;
+ emscripten_set_webglcontextlost_callback(canvasId, this, capture, callback);
+ }
+}
+
+EMSCRIPTEN_WEBGL_CONTEXT_HANDLE QWasmOpenGLContext::createEmscriptenContext(const char *canvasId, QSurfaceFormat format)
+{
+ EmscriptenWebGLContextAttributes attributes;
+ emscripten_webgl_init_context_attributes(&attributes); // Populate with default attributes
+
+ attributes.preferLowPowerToHighPerformance = false;
+ attributes.failIfMajorPerformanceCaveat = false;
+ attributes.antialias = true;
+ attributes.enableExtensionsByDefault = true;
+
+ if (format.majorVersion() == 3) {
+ attributes.majorVersion = 2;
+ }
+
+ // WebGL offers enable/disable control but not size control for these
+ attributes.alpha = format.alphaBufferSize() > 0;
+ attributes.depth = format.depthBufferSize() > 0;
+ attributes.stencil = format.stencilBufferSize() > 0;
+
+ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context(canvasId, &attributes);
+
+ return context;
+}
+
+QSurfaceFormat QWasmOpenGLContext::format() const
+{
+ return m_requestedFormat;
+}
+
+GLuint QWasmOpenGLContext::defaultFramebufferObject(QPlatformSurface *surface) const
+{
+ return QPlatformOpenGLContext::defaultFramebufferObject(surface);
+}
+
+bool QWasmOpenGLContext::makeCurrent(QPlatformSurface *surface)
+{
+ maybeRecreateEmscriptenContext(surface);
+
+ return emscripten_webgl_make_context_current(m_context) == EMSCRIPTEN_RESULT_SUCCESS;
+}
+
+void QWasmOpenGLContext::swapBuffers(QPlatformSurface *surface)
+{
+ Q_UNUSED(surface);
+ // No swapbuffers on WebGl
+}
+
+void QWasmOpenGLContext::doneCurrent()
+{
+ // No doneCurrent on WebGl
+}
+
+bool QWasmOpenGLContext::isSharing() const
+{
+ return false;
+}
+
+bool QWasmOpenGLContext::isValid() const
+{
+ return (m_contextLost == false);
+}
+
+QFunctionPointer QWasmOpenGLContext::getProcAddress(const char *procName)
+{
+ return reinterpret_cast<QFunctionPointer>(eglGetProcAddress(procName));
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmopenglcontext.h b/src/plugins/platforms/wasm/qwasmopenglcontext.h
new file mode 100644
index 0000000000..9123100479
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmopenglcontext.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** 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 <qpa/qplatformopenglcontext.h>
+
+#include <emscripten.h>
+#include <emscripten/html5.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWasmOpenGLContext : public QPlatformOpenGLContext
+{
+public:
+ QWasmOpenGLContext(const QSurfaceFormat &format);
+ ~QWasmOpenGLContext();
+
+ QSurfaceFormat format() const override;
+ void swapBuffers(QPlatformSurface *surface) override;
+ GLuint defaultFramebufferObject(QPlatformSurface *surface) const override;
+ bool makeCurrent(QPlatformSurface *surface) override;
+ void doneCurrent() override;
+ bool isSharing() const override;
+ bool isValid() const override;
+ QFunctionPointer getProcAddress(const char *procName) override;
+
+private:
+ void maybeRecreateEmscriptenContext(QPlatformSurface *surface);
+ static EMSCRIPTEN_WEBGL_CONTEXT_HANDLE createEmscriptenContext(const char *canvasId, QSurfaceFormat format);
+
+ bool m_contextLost = false;
+ QSurfaceFormat m_requestedFormat;
+ QPlatformSurface *m_surface = nullptr;
+ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE m_context = 0;
+};
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/platforms/wasm/qwasmscreen.cpp b/src/plugins/platforms/wasm/qwasmscreen.cpp
new file mode 100644
index 0000000000..93e9906ffc
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmscreen.cpp
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** 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 "qwasmscreen.h"
+#include "qwasmwindow.h"
+#include "qwasmcompositor.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>
+
+
+QT_BEGIN_NAMESPACE
+
+QWasmScreen::QWasmScreen(QWasmCompositor *compositor)
+ : m_compositor(compositor)
+ , m_depth(32)
+ , m_format(QImage::Format_RGB32)
+{
+ m_compositor->setScreen(this);
+}
+
+QWasmScreen::~QWasmScreen()
+{
+
+}
+
+QRect QWasmScreen::geometry() const
+{
+ return m_geometry;
+}
+
+int QWasmScreen::depth() const
+{
+ return m_depth;
+}
+
+QImage::Format QWasmScreen::format() const
+{
+ return m_format;
+}
+
+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 = EM_ASM_DOUBLE({
+ return window.devicePixelRatio;
+ });
+ return qreal(htmlWindowDpr);
+}
+
+QPlatformCursor *QWasmScreen::cursor() const
+{
+ return const_cast<QWasmCursor *>(&m_cursor);
+}
+
+void QWasmScreen::resizeMaximizedWindows()
+{
+ QPlatformScreen::resizeMaximizedWindows();
+}
+
+QWindow *QWasmScreen::topWindow() const
+{
+ return m_compositor->keyWindow();
+}
+
+QWindow *QWasmScreen::topLevelAt(const QPoint &p) const
+{
+ return m_compositor->windowAt(p);
+}
+
+void QWasmScreen::invalidateSize()
+{
+ m_geometry = QRect();
+}
+
+void QWasmScreen::setGeometry(const QRect &rect)
+{
+ m_geometry = rect;
+ QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry(), availableGeometry());
+ resizeMaximizedWindows();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmscreen.h b/src/plugins/platforms/wasm/qwasmscreen.h
new file mode 100644
index 0000000000..3891db77bb
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmscreen.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** 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 QWASMSCREEN_H
+#define QWASMSCREEN_H
+
+#include "qwasmcursor.h"
+
+#include <qpa/qplatformscreen.h>
+
+#include <QtCore/qscopedpointer.h>
+#include <QtCore/qtextstream.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPlatformOpenGLContext;
+class QWasmWindow;
+class QWasmBackingStore;
+class QWasmCompositor;
+class QOpenGLContext;
+
+class QWasmScreen : public QObject, public QPlatformScreen
+{
+ Q_OBJECT
+public:
+
+ QWasmScreen(QWasmCompositor *compositor);
+ ~QWasmScreen();
+
+ QRect geometry() const override;
+ int depth() const override;
+ QImage::Format format() const override;
+ qreal devicePixelRatio() const override;
+ QPlatformCursor *cursor() const override;
+
+ void resizeMaximizedWindows();
+ QWindow *topWindow() const;
+ QWindow *topLevelAt(const QPoint &p) const override;
+
+ void invalidateSize();
+
+public slots:
+ void setGeometry(const QRect &rect);
+protected:
+
+private:
+ QWasmCompositor *m_compositor;
+
+ QRect m_geometry = QRect(0, 0, 100, 100);
+ int m_depth;
+ QImage::Format m_format;
+ QWasmCursor m_cursor;
+};
+
+QT_END_NAMESPACE
+#endif // QWASMSCREEN_H
diff --git a/src/plugins/platforms/wasm/qwasmstylepixmaps_p.h b/src/plugins/platforms/wasm/qwasmstylepixmaps_p.h
new file mode 100644
index 0000000000..2b5860f42f
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmstylepixmaps_p.h
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..a7f2db3bd3
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmtheme.cpp
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** 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 "qwasmtheme.h"
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+QWasmTheme::QWasmTheme()
+{
+}
+
+QWasmTheme::~QWasmTheme()
+{
+}
+
+QVariant QWasmTheme::themeHint(ThemeHint hint) const
+{
+ if (hint == QPlatformTheme::StyleNames)
+ return QVariant(QStringList() << QLatin1String("fusion"));
+ return QPlatformTheme::themeHint(hint);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmtheme.h b/src/plugins/platforms/wasm/qwasmtheme.h
new file mode 100644
index 0000000000..e4cc06e049
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmtheme.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** 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 QWASMTHEME_H
+#define QWASMTHEME_H
+
+#include <qpa/qplatformtheme.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWasmEventTranslator;
+class QWasmFontDatabase;
+class QWasmWindow;
+class QWasmEventDispatcher;
+class QWasmScreen;
+class QWasmCompositor;
+class QWasmBackingStore;
+
+class QWasmTheme : public QPlatformTheme
+{
+public:
+ QWasmTheme();
+ ~QWasmTheme();
+
+ QVariant themeHint(ThemeHint hint) const override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWASMTHEME_H
diff --git a/src/plugins/platforms/wasm/qwasmwindow.cpp b/src/plugins/platforms/wasm/qwasmwindow.cpp
new file mode 100644
index 0000000000..c4167be71e
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmwindow.cpp
@@ -0,0 +1,401 @@
+/****************************************************************************
+**
+** 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 <qpa/qwindowsysteminterface.h>
+#include <private/qguiapplication_p.h>
+#include <QtGui/private/qopenglcontext_p.h>
+#include <QtGui/private/qwindow_p.h>
+#include <QtGui/qopenglcontext.h>
+
+#include "qwasmwindow.h"
+#include "qwasmscreen.h"
+#include "qwasmcompositor.h"
+#include "qwasmeventdispatcher.h"
+
+#include <iostream>
+
+Q_GUI_EXPORT int qt_defaultDpiX();
+
+QT_BEGIN_NAMESPACE
+
+QWasmWindow::QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingStore *backingStore)
+ : QPlatformWindow(w),
+ m_window(w),
+ m_compositor(compositor),
+ m_backingStore(backingStore)
+{
+ m_needsCompositor = w->surfaceType() != QSurface::OpenGLSurface;
+ static int serialNo = 0;
+ m_winid = ++serialNo;
+ qWarning("QWasmWindow %p: %p 0x%x\n", this, w, uint(m_winid));
+
+ m_compositor->addWindow(this);
+
+ // Pure OpenGL windows draw directly using egl, disable the compositor.
+ m_compositor->setEnabled(w->surfaceType() != QSurface::OpenGLSurface);
+}
+
+QWasmWindow::~QWasmWindow()
+{
+ m_compositor->removeWindow(this);
+}
+
+void QWasmWindow::initialize()
+{
+ QRect rect = windowGeometry();
+
+ QPlatformWindow::setGeometry(rect);
+
+ 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);
+ }
+
+ setWindowState(window()->windowStates());
+ setWindowFlags(window()->flags());
+ setWindowTitle(window()->title());
+ if (window()->isTopLevel())
+ setWindowIcon(window()->icon());
+ m_normalGeometry = rect;
+}
+
+QWasmScreen *QWasmWindow::platformScreen() const
+{
+ return static_cast<QWasmScreen *>(window()->screen()->handle());
+}
+
+void QWasmWindow::setGeometry(const QRect &rect)
+{
+ 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);
+
+ QWindowSystemInterface::flushWindowSystemEvents();
+ invalidate();
+}
+
+void QWasmWindow::setVisible(bool visible)
+{
+ QRect newGeom;
+
+ if (visible) {
+ const bool forceFullScreen = !m_needsCompositor;//make gl apps fullscreen for now
+
+ if (forceFullScreen || (m_windowState & Qt::WindowFullScreen))
+ newGeom = platformScreen()->geometry();
+ else if (m_windowState & Qt::WindowMaximized)
+ newGeom = platformScreen()->availableGeometry();
+ }
+ QPlatformWindow::setVisible(visible);
+
+ m_compositor->setVisible(this, visible);
+
+ if (!newGeom.isEmpty())
+ setGeometry(newGeom); // may or may not generate an expose
+
+ invalidate();
+}
+
+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;
+}
+
+void QWasmWindow::raise()
+{
+ m_compositor->raise(this);
+ QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size()));
+ invalidate();
+}
+
+void QWasmWindow::lower()
+{
+ m_compositor->lower(this);
+ QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size()));
+ invalidate();
+}
+
+WId QWasmWindow::winId() const
+{
+ return m_winid;
+}
+
+void QWasmWindow::propagateSizeHints()
+{
+// get rid of base class warning
+}
+
+void QWasmWindow::injectMousePressed(const QPoint &local, const QPoint &global,
+ Qt::MouseButton button, Qt::KeyboardModifiers mods)
+{
+ Q_UNUSED(local);
+ Q_UNUSED(mods);
+
+ if (!hasTitleBar() || button != Qt::LeftButton)
+ return;
+
+ 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;
+
+ invalidate();
+}
+
+void QWasmWindow::injectMouseReleased(const QPoint &local, const QPoint &global,
+ Qt::MouseButton button, Qt::KeyboardModifiers mods)
+{
+ Q_UNUSED(local);
+ Q_UNUSED(mods);
+
+ if (!hasTitleBar() || button != Qt::LeftButton)
+ return;
+
+ if (closeButtonRect().contains(global) && m_activeControl == QWasmCompositor::SC_TitleBarCloseButton)
+ window()->close();
+
+ 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());
+ }
+
+ m_activeControl = QWasmCompositor::SC_None;
+
+ invalidate();
+}
+
+int QWasmWindow::titleHeight() const
+{
+ return 18. * (qreal(qt_defaultDpiX()) / 96.0);//dpiScaled(18.);
+}
+
+int QWasmWindow::borderWidth() const
+{
+ return 4. * (qreal(qt_defaultDpiX()) / 96.0);// dpiScaled(4.);
+}
+
+QRegion QWasmWindow::titleGeometry() const
+{
+ int border = borderWidth();
+
+ QRegion result(window()->frameGeometry().x() + border,
+ window()->frameGeometry().y() + border,
+ window()->frameGeometry().width() - 2*border,
+ titleHeight());
+
+ result -= titleControlRegion();
+
+ return result;
+}
+
+QRegion QWasmWindow::resizeRegion() const
+{
+ int border = borderWidth();
+ QRegion result(window()->frameGeometry().adjusted(-border, -border, border, border));
+ result -= window()->frameGeometry().adjusted(border, border, -border, -border);
+
+ return result;
+}
+
+bool QWasmWindow::isPointOnTitle(QPoint point) const
+{
+ bool ok = titleGeometry().contains(point);
+ return ok;
+}
+
+bool QWasmWindow::isPointOnResizeRegion(QPoint point) const
+{
+ return resizeRegion().contains(point);
+}
+
+QWasmWindow::ResizeMode QWasmWindow::resizeModeAtPoint(QPoint point) const
+{
+ QPoint p1 = window()->frameGeometry().topLeft() - QPoint(5, 5);
+ QPoint p2 = window()->frameGeometry().bottomRight() + QPoint(5, 5);
+ int corner = 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);
+
+ 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 ResizeNone;
+}
+
+QRect getSubControlRect(const QWasmWindow *window, QWasmCompositor::SubControls subControl)
+{
+ QWasmCompositor::QWasmTitleBarOptions options = QWasmCompositor::makeTitleBarOptions(window);
+
+ QRect r = QWasmCompositor::titlebarRect(options, subControl);
+ r.translate(window->window()->frameGeometry().x(), window->window()->frameGeometry().y());
+
+ return r;
+}
+
+QRect QWasmWindow::maxButtonRect() const
+{
+ return getSubControlRect(this, QWasmCompositor::SC_TitleBarMaxButton);
+}
+
+QRect QWasmWindow::minButtonRect() const
+{
+ return getSubControlRect(this, QWasmCompositor::SC_TitleBarMinButton);
+}
+
+QRect QWasmWindow::closeButtonRect() const
+{
+ return getSubControlRect(this, QWasmCompositor::SC_TitleBarCloseButton);
+}
+
+QRect QWasmWindow::normButtonRect() const
+{
+ return getSubControlRect(this, QWasmCompositor::SC_TitleBarNormalButton);
+}
+
+QRect QWasmWindow::sysMenuRect() const
+{
+ return getSubControlRect(this, QWasmCompositor::SC_TitleBarSysMenu);
+}
+
+QRegion QWasmWindow::titleControlRegion() const
+{
+ QRegion result;
+ result += closeButtonRect();
+ result += minButtonRect();
+ result += maxButtonRect();
+ result += sysMenuRect();
+
+ return result;
+}
+
+void QWasmWindow::invalidate()
+{
+ m_compositor->requestRedraw();
+}
+
+QWasmCompositor::SubControls QWasmWindow::activeSubControl() const
+{
+ return m_activeControl;
+}
+
+void QWasmWindow::setWindowState(Qt::WindowStates states)
+{
+ 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;
+}
+
+QRect QWasmWindow::normalGeometry() const
+{
+ return m_normalGeometry;
+}
+
+qreal QWasmWindow::devicePixelRatio() const
+{
+ return screen()->devicePixelRatio();
+}
+
+void QWasmWindow::requestUpdate()
+{
+ QPointer<QWindow> windowPointer(window());
+ bool registered = QWasmEventDispatcher::registerRequestUpdateCallback([=](){
+ if (windowPointer.isNull())
+ return;
+
+ deliverUpdateRequest();
+ });
+
+ if (!registered)
+ QPlatformWindow::requestUpdate();
+}
+
+bool QWasmWindow::hasTitleBar() const
+{
+ return !(m_windowState & Qt::WindowFullScreen) && (window()->flags().testFlag(Qt::WindowTitleHint) && m_needsCompositor);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmwindow.h b/src/plugins/platforms/wasm/qwasmwindow.h
new file mode 100644
index 0000000000..cbbce99aeb
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmwindow.h
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** 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 QWASMWINDOW_H
+#define QWASMWINDOW_H
+
+#include "qwasmintegration.h"
+#include <qpa/qplatformwindow.h>
+#include <emscripten/html5.h>
+#include "qwasmbackingstore.h"
+#include "qwasmscreen.h"
+#include "qwasmcompositor.h"
+
+QT_BEGIN_NAMESPACE
+
+class QWasmCompositor;
+
+class QWasmWindow : public QPlatformWindow
+{
+public:
+ enum ResizeMode {
+ ResizeNone,
+ ResizeTopLeft,
+ ResizeTop,
+ ResizeTopRight,
+ ResizeRight,
+ ResizeBottomRight,
+ ResizeBottom,
+ ResizeBottomLeft,
+ ResizeLeft
+ };
+
+ QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingStore *backingStore);
+ ~QWasmWindow();
+
+ 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 raise() override;
+ void lower() override;
+ QRect normalGeometry() const override;
+ qreal devicePixelRatio() const override;
+ void requestUpdate() override;
+
+ 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;
+
+ void setWindowState(Qt::WindowStates state) override;
+ bool setKeyboardGrabEnabled(bool) override { return false; }
+ bool setMouseGrabEnabled(bool) override { return false; }
+
+protected:
+ void invalidate();
+ bool hasTitleBar() const;
+
+protected:
+ friend class QWasmScreen;
+
+ QWindow* m_window = nullptr;
+ QWasmCompositor *m_compositor = nullptr;
+ QWasmBackingStore *m_backingStore = nullptr;
+ QRect m_normalGeometry {0, 0, 0 ,0};
+
+ Qt::WindowState m_windowState = Qt::WindowNoState;
+ QWasmCompositor::SubControls m_activeControl = QWasmCompositor::SC_None;
+ WId m_winid = 0;
+ bool m_hasTitle = false;
+ bool m_needsCompositor = false;
+ friend class QWasmCompositor;
+ friend class QWasmEventTranslator;
+};
+QT_END_NAMESPACE
+#endif // QWASMWINDOW_H
diff --git a/src/plugins/platforms/wasm/wasm.json b/src/plugins/platforms/wasm/wasm.json
new file mode 100644
index 0000000000..6e700e06b9
--- /dev/null
+++ b/src/plugins/platforms/wasm/wasm.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "wasm" ]
+}
diff --git a/src/plugins/platforms/wasm/wasm.pro b/src/plugins/platforms/wasm/wasm.pro
new file mode 100644
index 0000000000..f1205702ef
--- /dev/null
+++ b/src/plugins/platforms/wasm/wasm.pro
@@ -0,0 +1,65 @@
+TARGET = wasm
+CONFIG += static plugin
+QT += \
+ core-private gui-private \
+ eventdispatcher_support-private fontdatabase_support-private egl_support-private
+
+# Avoid X11 header collision, use generic EGL native types
+DEFINES += QT_EGL_NO_X11
+
+SOURCES = \
+ main.cpp \
+ qwasmintegration.cpp \
+ qwasmwindow.cpp \
+ qwasmscreen.cpp \
+ qwasmfontdatabase.cpp \
+ qwasmeventtranslator.cpp \
+ qwasmeventdispatcher.cpp \
+ qwasmcompositor.cpp \
+ qwasmcursor.cpp \
+ qwasmopenglcontext.cpp \
+ qwasmtheme.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
+
+wasmfonts.files = \
+ ../../../3rdparty/wasm/Vera.ttf \
+ ../../../3rdparty/wasm/DejaVuSans.ttf
+wasmfonts.prefix = /fonts
+wasmfonts.base = ../../../3rdparty/wasm
+RESOURCES += wasmfonts
+
+qtConfig(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
new file mode 100644
index 0000000000..67bfcdfbdc
--- /dev/null
+++ b/src/plugins/platforms/wasm/wasm_shell.html
@@ -0,0 +1,61 @@
+<!doctype html>
+<html lang="en-us">
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <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%; }
+ </style>
+ </head>
+ <body onload="init()">
+ <figure style="overflow:visible;" id="spinner">
+ <center style="margin-top:1.5em; line-height:150%">
+ <img src="qtlogo.svg"; width=320; height=200; style="display:block"> </img>
+ <strong>Qt for WebAssembly: APPNAME</strong>
+ <div id="status"></div>
+ <noscript>JavaScript is disabled. Please enable JavaScript to use this application.</noscript>
+ </center>
+ </figure>
+ <canvas id="canvas" oncontextmenu="event.preventDefault()"></canvas>
+
+ <script type='text/javascript'>
+ function init() {
+ var spinner = document.getElementById('spinner');
+ var canvas = document.getElementById('canvas');
+ var status = document.getElementById('status')
+
+ var qtLoader = QtLoader({
+ 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';
+ return canvas;
+ },
+ });
+ qtLoader.loadEmscriptenModule("APPNAME");
+ }
+ </script>
+ <script type="text/javascript" src="qtloader.js"></script>
+ </body>
+</html>
diff --git a/src/plugins/platforms/windows/main.cpp b/src/plugins/platforms/windows/main.cpp
index 980de88e72..8bde87c975 100644
--- a/src/plugins/platforms/windows/main.cpp
+++ b/src/plugins/platforms/windows/main.cpp
@@ -39,7 +39,7 @@
#include <qpa/qplatformintegrationplugin.h>
-#include <QtCore/QStringList>
+#include <QtCore/qstringlist.h>
#include "qwindowsgdiintegration.h"
diff --git a/src/plugins/platforms/windows/openglblacklists/default.json b/src/plugins/platforms/windows/openglblacklists/default.json
index d1e9f85247..3cfa7e3856 100644
--- a/src/plugins/platforms/windows/openglblacklists/default.json
+++ b/src/plugins/platforms/windows/openglblacklists/default.json
@@ -141,6 +141,17 @@
"features": [
"disable_desktopgl", "disable_d3d11", "disable_d3d9"
]
+ },
+ {
+ "id": 12,
+ "description": "Intel HD Graphics crash in conjunction with shader caches (QTBUG-64697) - disable for all Intel GPUs",
+ "vendor_id": "0x8086",
+ "os": {
+ "type": "win"
+ },
+ "features": [
+ "disable_program_cache"
+ ]
}
]
}
diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h
index 6c44541314..985f13bdc5 100644
--- a/src/plugins/platforms/windows/qtwindowsglobal.h
+++ b/src/plugins/platforms/windows/qtwindowsglobal.h
@@ -60,6 +60,22 @@
# define WM_DPICHANGED 0x02E0
#endif
+// WM_POINTER support from Windows 8 onwards (WINVER >= 0x0602)
+#ifndef WM_POINTERUPDATE
+# define WM_NCPOINTERUPDATE 0x0241
+# define WM_NCPOINTERDOWN 0x0242
+# define WM_NCPOINTERUP 0x0243
+# define WM_POINTERUPDATE 0x0245
+# define WM_POINTERDOWN 0x0246
+# define WM_POINTERUP 0x0247
+# define WM_POINTERENTER 0x0249
+# define WM_POINTERLEAVE 0x024A
+# define WM_POINTERACTIVATE 0x024B
+# define WM_POINTERCAPTURECHANGED 0x024C
+# define WM_POINTERWHEEL 0x024E
+# define WM_POINTERHWHEEL 0x024F
+#endif // WM_POINTERUPDATE
+
QT_BEGIN_NAMESPACE
namespace QtWindows
@@ -78,6 +94,7 @@ enum
ApplicationEventFlag = 0x1000000,
ThemingEventFlag = 0x2000000,
GenericEventFlag = 0x4000000, // Misc
+ PointerEventFlag = 0x8000000,
};
enum WindowsEventType // Simplify event types
@@ -103,13 +120,16 @@ enum WindowsEventType // Simplify event types
DpiChangedEvent = WindowEventFlag + 21,
EnterSizeMoveEvent = WindowEventFlag + 22,
ExitSizeMoveEvent = WindowEventFlag + 23,
+ PointerActivateWindowEvent = WindowEventFlag + 24,
MouseEvent = MouseEventFlag + 1,
MouseWheelEvent = MouseEventFlag + 2,
CursorEvent = MouseEventFlag + 3,
TouchEvent = TouchEventFlag + 1,
+ PointerEvent = PointerEventFlag + 1,
NonClientMouseEvent = NonClientEventFlag + MouseEventFlag + 1,
NonClientHitTest = NonClientEventFlag + 2,
NonClientCreate = NonClientEventFlag + 3,
+ NonClientPointerEvent = NonClientEventFlag + PointerEventFlag + 4,
KeyEvent = KeyEventFlag + 1,
KeyDownEvent = KeyEventFlag + KeyDownEventFlag + 1,
KeyboardLayoutChangeEvent = KeyEventFlag + 2,
@@ -167,6 +187,8 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
QtWindows::ActivateApplicationEvent : QtWindows::DeactivateApplicationEvent;
case WM_MOUSEACTIVATE:
return QtWindows::MouseActivateWindowEvent;
+ case WM_POINTERACTIVATE:
+ return QtWindows::PointerActivateWindowEvent;
case WM_ACTIVATE:
return LOWORD(wParamIn) == WA_INACTIVE ?
QtWindows::DeactivateWindowEvent : QtWindows::ActivateWindowEvent;
@@ -297,6 +319,10 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
if ((message >= WM_MOUSEFIRST && message <= WM_MOUSELAST)
|| (message >= WM_XBUTTONDOWN && message <= WM_XBUTTONDBLCLK))
return QtWindows::MouseEvent;
+ if (message >= WM_NCPOINTERUPDATE && message <= WM_NCPOINTERUP)
+ return QtWindows::NonClientPointerEvent;
+ if (message >= WM_POINTERUPDATE && message <= WM_POINTERHWHEEL)
+ return QtWindows::PointerEvent;
return QtWindows::UnknownEvent;
}
diff --git a/src/plugins/platforms/windows/qwin10helpers.cpp b/src/plugins/platforms/windows/qwin10helpers.cpp
index 5976fd23c0..cc17d8798f 100644
--- a/src/plugins/platforms/windows/qwin10helpers.cpp
+++ b/src/plugins/platforms/windows/qwin10helpers.cpp
@@ -39,8 +39,8 @@
#include "qwin10helpers.h"
-#include <QtCore/QDebug>
-#include <QtCore/QOperatingSystemVersion>
+#include <QtCore/qdebug.h>
+#include <QtCore/qoperatingsystemversion.h>
#include <QtCore/private/qsystemlibrary_p.h>
#if defined(Q_CC_MINGW) || defined(Q_CC_CLANG)
diff --git a/src/plugins/platforms/windows/qwin10helpers.h b/src/plugins/platforms/windows/qwin10helpers.h
index e1485003dd..4f364dfc59 100644
--- a/src/plugins/platforms/windows/qwin10helpers.h
+++ b/src/plugins/platforms/windows/qwin10helpers.h
@@ -40,7 +40,7 @@
#ifndef QWIN10HELPERS_H
#define QWIN10HELPERS_H
-#include <QtCore/QtGlobal>
+#include <QtCore/qglobal.h>
#include <QtCore/qt_windows.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp
index 80872c3ea3..03b44458ac 100644
--- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp
+++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp
@@ -41,13 +41,13 @@
#include "qwindowswindow.h"
#include "qwindowscontext.h"
-#include <QtGui/QWindow>
-#include <QtGui/QPainter>
+#include <QtGui/qwindow.h>
+#include <QtGui/qpainter.h>
#include <QtFontDatabaseSupport/private/qwindowsnativeimage_p.h>
#include <private/qhighdpiscaling_p.h>
#include <private/qimage_p.h>
-#include <QtCore/QDebug>
+#include <QtCore/qdebug.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.h b/src/plugins/platforms/windows/qwindowsbackingstore.h
index 9e62266697..088ab3b257 100644
--- a/src/plugins/platforms/windows/qwindowsbackingstore.h
+++ b/src/plugins/platforms/windows/qwindowsbackingstore.h
@@ -43,7 +43,7 @@
#include <QtCore/qt_windows.h>
#include <qpa/qplatformbackingstore.h>
-#include <QtCore/QScopedPointer>
+#include <QtCore/qscopedpointer.h>
QT_BEGIN_NAMESPACE
@@ -55,7 +55,7 @@ class QWindowsBackingStore : public QPlatformBackingStore
Q_DISABLE_COPY(QWindowsBackingStore)
public:
QWindowsBackingStore(QWindow *window);
- ~QWindowsBackingStore();
+ ~QWindowsBackingStore() override;
QPaintDevice *paintDevice() override;
void flush(QWindow *window, const QRegion &region, const QPoint &offset) override;
diff --git a/src/plugins/platforms/windows/qwindowsclipboard.cpp b/src/plugins/platforms/windows/qwindowsclipboard.cpp
index 01191a7dc1..8b386da9f7 100644
--- a/src/plugins/platforms/windows/qwindowsclipboard.cpp
+++ b/src/plugins/platforms/windows/qwindowsclipboard.cpp
@@ -42,16 +42,17 @@
#include "qwindowsole.h"
#include "qwindowsmime.h"
-#include <QtGui/QGuiApplication>
-#include <QtGui/QClipboard>
-#include <QtGui/QColor>
-#include <QtGui/QImage>
-
-#include <QtCore/QDebug>
-#include <QtCore/QMimeData>
-#include <QtCore/QStringList>
-#include <QtCore/QVariant>
-#include <QtCore/QUrl>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qclipboard.h>
+#include <QtGui/qcolor.h>
+#include <QtGui/qimage.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qmimedata.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qurl.h>
#include <QtEventDispatcherSupport/private/qwindowsguieventdispatcher_p.h>
@@ -318,7 +319,15 @@ void QWindowsClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode)
m_data = new QWindowsOleDataObject(mimeData);
}
- const HRESULT src = OleSetClipboard(m_data);
+ HRESULT src = S_FALSE;
+ int attempts = 0;
+ for (; attempts < 3; ++attempts) {
+ src = OleSetClipboard(m_data);
+ if (src != CLIPBRD_E_CANT_OPEN || QWindowsContext::isSessionLocked())
+ break;
+ QThread::msleep(100);
+ }
+
if (src != S_OK) {
QString mimeDataFormats = mimeData ?
mimeData->formats().join(QLatin1String(", ")) : QString(QStringLiteral("NULL"));
diff --git a/src/plugins/platforms/windows/qwindowsclipboard.h b/src/plugins/platforms/windows/qwindowsclipboard.h
index 4f3e7437f6..469d638b89 100644
--- a/src/plugins/platforms/windows/qwindowsclipboard.h
+++ b/src/plugins/platforms/windows/qwindowsclipboard.h
@@ -58,9 +58,10 @@ protected:
class QWindowsClipboard : public QPlatformClipboard
{
+ Q_DISABLE_COPY(QWindowsClipboard)
public:
QWindowsClipboard();
- ~QWindowsClipboard();
+ ~QWindowsClipboard() override;
void registerViewer(); // Call in initialization, when context is up.
void cleanup();
diff --git a/src/plugins/platforms/windows/qwindowscombase.h b/src/plugins/platforms/windows/qwindowscombase.h
index 5e51b6b7b7..6b25d665dc 100644
--- a/src/plugins/platforms/windows/qwindowscombase.h
+++ b/src/plugins/platforms/windows/qwindowscombase.h
@@ -40,7 +40,7 @@
#ifndef QWINDOWSCOMBASE_H
#define QWINDOWSCOMBASE_H
-#include <QtCore/QtGlobal>
+#include <QtCore/qglobal.h>
#include <unknwn.h>
@@ -83,7 +83,7 @@ template <class ComInterface> class QWindowsComBase : public ComInterface
Q_DISABLE_COPY(QWindowsComBase)
public:
explicit QWindowsComBase(ULONG initialRefCount = 1) : m_ref(initialRefCount) {}
- virtual ~QWindowsComBase() {}
+ virtual ~QWindowsComBase() = default;
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, LPVOID *iface)
{
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index b0c9349da5..4959ed952d 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -43,6 +43,7 @@
#include "qwindowswindow.h"
#include "qwindowskeymapper.h"
#include "qwindowsmousehandler.h"
+#include "qwindowspointerhandler.h"
#include "qtwindowsglobal.h"
#include "qwindowsmenu.h"
#include "qwindowsmime.h"
@@ -52,7 +53,7 @@
#endif
#include "qwindowstheme.h"
#include <private/qguiapplication_p.h>
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
# include "uiautomation/qwindowsuiaaccessibility.h"
#endif
#if QT_CONFIG(sessionmanager)
@@ -62,20 +63,20 @@
#include "qwindowsscreen.h"
#include "qwindowstheme.h"
-#include <QtGui/qtguiglobal.h>
-#include <QtGui/QWindow>
+#include <QtGui/qwindow.h>
#include <qpa/qwindowsysteminterface.h>
+#include <qpa/qwindowsysteminterface_p.h>
#include <qpa/qplatformnativeinterface.h>
-#include <QtGui/QGuiApplication>
-#include <QtGui/QOpenGLContext>
-
-#include <QtCore/QSet>
-#include <QtCore/QHash>
-#include <QtCore/QStringList>
-#include <QtCore/QDebug>
-#include <QtCore/QOperatingSystemVersion>
-#include <QtCore/QSysInfo>
-#include <QtCore/QScopedArrayPointer>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qopenglcontext.h>
+
+#include <QtCore/qset.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qoperatingsystemversion.h>
+#include <QtCore/qsysinfo.h>
+#include <QtCore/qscopedpointer.h>
#include <QtCore/private/qsystemlibrary_p.h>
#include <QtEventDispatcherSupport/private/qwindowsguieventdispatcher_p.h>
@@ -85,11 +86,11 @@
#include <windowsx.h>
#include <comdef.h>
#include <dbt.h>
+#include <wtsapi32.h>
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcQpaWindows, "qt.qpa.windows")
-Q_LOGGING_CATEGORY(lcQpaBackingStore, "qt.qpa.backingstore")
Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events")
Q_LOGGING_CATEGORY(lcQpaGl, "qt.qpa.gl")
Q_LOGGING_CATEGORY(lcQpaMime, "qt.qpa.mime")
@@ -147,7 +148,7 @@ static inline bool sessionManagerInteractionBlocked() { return false; }
static inline int windowDpiAwareness(HWND hwnd)
{
- return QWindowsContext::user32dll.getWindowDpiAwarenessContext && QWindowsContext::user32dll.getWindowDpiAwarenessContext
+ return QWindowsContext::user32dll.getWindowDpiAwarenessContext && QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext
? QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext(QWindowsContext::user32dll.getWindowDpiAwarenessContext(hwnd))
: -1;
}
@@ -194,6 +195,19 @@ void QWindowsUser32DLL::init()
getDisplayAutoRotationPreferences = (GetDisplayAutoRotationPreferences)library.resolve("GetDisplayAutoRotationPreferences");
setDisplayAutoRotationPreferences = (SetDisplayAutoRotationPreferences)library.resolve("SetDisplayAutoRotationPreferences");
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8) {
+ enableMouseInPointer = (EnableMouseInPointer)library.resolve("EnableMouseInPointer");
+ getPointerType = (GetPointerType)library.resolve("GetPointerType");
+ getPointerInfo = (GetPointerInfo)library.resolve("GetPointerInfo");
+ getPointerDeviceRects = (GetPointerDeviceRects)library.resolve("GetPointerDeviceRects");
+ getPointerTouchInfo = (GetPointerTouchInfo)library.resolve("GetPointerTouchInfo");
+ getPointerFrameTouchInfo = (GetPointerFrameTouchInfo)library.resolve("GetPointerFrameTouchInfo");
+ getPointerFrameTouchInfoHistory = (GetPointerFrameTouchInfoHistory)library.resolve("GetPointerFrameTouchInfoHistory");
+ getPointerPenInfo = (GetPointerPenInfo)library.resolve("GetPointerPenInfo");
+ getPointerPenInfoHistory = (GetPointerPenInfoHistory)library.resolve("GetPointerPenInfoHistory");
+ skipPointerFrameMessages = (SkipPointerFrameMessages)library.resolve("SkipPointerFrameMessages");
+ }
+
if (QOperatingSystemVersion::current()
>= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 14393)) {
enableNonClientDpiScaling = (EnableNonClientDpiScaling)library.resolve("EnableNonClientDpiScaling");
@@ -202,6 +216,13 @@ void QWindowsUser32DLL::init()
}
}
+bool QWindowsUser32DLL::supportsPointerApi()
+{
+ return enableMouseInPointer && getPointerType && getPointerInfo && getPointerDeviceRects
+ && getPointerTouchInfo && getPointerFrameTouchInfo && getPointerFrameTouchInfoHistory
+ && getPointerPenInfo && getPointerPenInfoHistory && skipPointerFrameMessages;
+}
+
void QWindowsShcoreDLL::init()
{
if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8_1)
@@ -239,6 +260,7 @@ struct QWindowsContextPrivate {
int m_defaultDPI = 96;
QWindowsKeyMapper m_keyMapper;
QWindowsMouseHandler m_mouseHandler;
+ QWindowsPointerHandler m_pointerHandler;
QWindowsMimeConverter m_mimeConverter;
QWindowsScreenManager m_screenManager;
QSharedPointer<QWindowCreationContext> m_creationContext;
@@ -256,7 +278,7 @@ QWindowsContextPrivate::QWindowsContextPrivate()
QWindowsContext::user32dll.init();
QWindowsContext::shcoredll.init();
- if (m_mouseHandler.touchDevice())
+ if (m_pointerHandler.touchDevice() || m_mouseHandler.touchDevice())
m_systemInfo |= QWindowsContext::SI_SupportsTouch;
m_displayContext = GetDC(0);
m_defaultDPI = GetDeviceCaps(m_displayContext, LOGPIXELSY);
@@ -281,10 +303,6 @@ QWindowsContext::QWindowsContext() :
const QByteArray bv = qgetenv("QT_QPA_VERBOSE");
if (!bv.isEmpty())
QLoggingCategory::setFilterRules(QString::fromLocal8Bit(bv));
-#if QT_CONFIG(tabletevent)
- d->m_tabletSupport.reset(QWindowsTabletSupport::create());
- qCDebug(lcQpaTablet) << "Tablet support: " << (d->m_tabletSupport.isNull() ? QStringLiteral("None") : d->m_tabletSupport->description());
-#endif
}
QWindowsContext::~QWindowsContext()
@@ -310,12 +328,17 @@ bool QWindowsContext::initTouch(unsigned integrationOptions)
if (d->m_systemInfo & QWindowsContext::SI_SupportsTouch)
return true;
- QTouchDevice *touchDevice = d->m_mouseHandler.ensureTouchDevice();
+ QTouchDevice *touchDevice = (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) ?
+ d->m_pointerHandler.ensureTouchDevice() : d->m_mouseHandler.ensureTouchDevice();
if (!touchDevice)
return false;
- if (!(integrationOptions & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch))
- touchDevice->setCapabilities(touchDevice->capabilities() | QTouchDevice::MouseEmulation);
+ if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) {
+ QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
+ } else {
+ if (!(integrationOptions & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch))
+ touchDevice->setCapabilities(touchDevice->capabilities() | QTouchDevice::MouseEmulation);
+ }
QWindowSystemInterface::registerTouchDevice(touchDevice);
@@ -330,6 +353,33 @@ bool QWindowsContext::initTouch(unsigned integrationOptions)
return true;
}
+bool QWindowsContext::initTablet(unsigned integrationOptions)
+{
+ Q_UNUSED(integrationOptions);
+#if QT_CONFIG(tabletevent)
+ d->m_tabletSupport.reset(QWindowsTabletSupport::create());
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool QWindowsContext::initPointer(unsigned integrationOptions)
+{
+ if (integrationOptions & QWindowsIntegration::DontUseWMPointer)
+ return false;
+
+ if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8)
+ return false;
+
+ if (!QWindowsContext::user32dll.supportsPointerApi())
+ return false;
+
+ QWindowsContext::user32dll.enableMouseInPointer(TRUE);
+ d->m_systemInfo |= QWindowsContext::SI_SupportsPointer;
+ return true;
+}
+
void QWindowsContext::setTabletAbsoluteRange(int a)
{
#if QT_CONFIG(tabletevent)
@@ -340,6 +390,11 @@ void QWindowsContext::setTabletAbsoluteRange(int a)
#endif
}
+void QWindowsContext::setDetectAltGrModifier(bool a)
+{
+ d->m_keyMapper.setDetectAltGrModifier(a);
+}
+
int QWindowsContext::processDpiAwareness()
{
int result;
@@ -548,7 +603,7 @@ void QWindowsContext::unregisterWindowClasses()
{
const HINSTANCE appInstance = static_cast<HINSTANCE>(GetModuleHandle(0));
- foreach (const QString &name, d->m_registeredWindowClassNames) {
+ for (const QString &name : qAsConst(d->m_registeredWindowClassNames)) {
if (!UnregisterClass(reinterpret_cast<LPCWSTR>(name.utf16()), appInstance) && QWindowsContext::verbose)
qErrnoWarning("UnregisterClass failed for '%s'", qPrintable(name));
}
@@ -632,12 +687,16 @@ QWindow *QWindowsContext::findWindow(HWND hwnd) const
QWindow *QWindowsContext::windowUnderMouse() const
{
- return d->m_mouseHandler.windowUnderMouse();
+ return (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) ?
+ d->m_pointerHandler.windowUnderMouse() : d->m_mouseHandler.windowUnderMouse();
}
void QWindowsContext::clearWindowUnderMouse()
{
- d->m_mouseHandler.clearWindowUnderMouse();
+ if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer)
+ d->m_pointerHandler.clearWindowUnderMouse();
+ else
+ d->m_mouseHandler.clearWindowUnderMouse();
}
/*!
@@ -696,6 +755,37 @@ QWindowsWindow *QWindowsContext::findPlatformWindowAt(HWND parent,
return result;
}
+bool QWindowsContext::isSessionLocked()
+{
+ bool result = false;
+ const DWORD sessionId = WTSGetActiveConsoleSessionId();
+ if (sessionId != 0xFFFFFFFF) {
+ LPTSTR buffer = nullptr;
+ DWORD size = 0;
+#if !defined(Q_CC_MINGW)
+ if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, sessionId,
+ WTSSessionInfoEx, &buffer, &size) == TRUE
+ && size > 0) {
+ const WTSINFOEXW *info = reinterpret_cast<WTSINFOEXW *>(buffer);
+ result = info->Level == 1 && info->Data.WTSInfoExLevel1.SessionFlags == WTS_SESSIONSTATE_LOCK;
+ WTSFreeMemory(buffer);
+ }
+#else // MinGW as of 7.3 does not have WTSINFOEXW in wtsapi32.h
+ // Retrieve the flags which are at offset 16 due to padding for 32/64bit alike.
+ if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, sessionId,
+ WTS_INFO_CLASS(25), &buffer, &size) == TRUE
+ && size >= 20) {
+ const DWORD *p = reinterpret_cast<DWORD *>(buffer);
+ const DWORD level = *p;
+ const DWORD sessionFlags = *(p + 4);
+ result = level == 1 && sessionFlags == 1;
+ WTSFreeMemory(buffer);
+ }
+#endif // Q_CC_MINGW
+ }
+ return result;
+}
+
QWindowsMimeConverter &QWindowsContext::mimeConverter() const
{
return d->m_mimeConverter;
@@ -870,6 +960,7 @@ static inline bool isInputMessage(UINT m)
case WM_IME_STARTCOMPOSITION:
case WM_IME_ENDCOMPOSITION:
case WM_IME_COMPOSITION:
+ case WM_INPUT:
case WM_TOUCH:
case WM_MOUSEHOVER:
case WM_MOUSELEAVE:
@@ -957,7 +1048,9 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
switch (et) {
case QtWindows::GestureEvent:
- return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateGestureEvent(platformWindow->window(), hwnd, et, msg, result);
+ if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
+ return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateGestureEvent(platformWindow->window(), hwnd, et, msg, result);
+ break;
case QtWindows::InputMethodOpenCandidateWindowEvent:
case QtWindows::InputMethodCloseCandidateWindowEvent:
// TODO: Release/regrab mouse if a popup has mouse grab.
@@ -974,7 +1067,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::UnknownEvent:
return false;
case QtWindows::AccessibleObjectFromWindowRequest:
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
return QWindowsUiaAccessibility::handleWmGetObject(hwnd, wParam, lParam, result);
#else
return false;
@@ -1083,18 +1176,25 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::ExposeEvent:
return platformWindow->handleWmPaint(hwnd, message, wParam, lParam);
case QtWindows::NonClientMouseEvent:
- if (platformWindow->frameStrutEventsEnabled())
+ if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer) && platformWindow->frameStrutEventsEnabled())
return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
break;
+ case QtWindows::NonClientPointerEvent:
+ if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer) && platformWindow->frameStrutEventsEnabled())
+ return sessionManagerInteractionBlocked() || d->m_pointerHandler.translatePointerEvent(platformWindow->window(), hwnd, et, msg, result);
+ break;
case QtWindows::EnterSizeMoveEvent:
platformWindow->setFlag(QWindowsWindow::ResizeMoveActive);
return true;
case QtWindows::ExitSizeMoveEvent:
platformWindow->clearFlag(QWindowsWindow::ResizeMoveActive);
platformWindow->checkForScreenChanged();
+ handleExitSizeMove(platformWindow->window());
return true;
case QtWindows::ScrollEvent:
- return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateScrollEvent(platformWindow->window(), hwnd, msg, result);
+ if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
+ return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateScrollEvent(platformWindow->window(), hwnd, msg, result);
+ break;
case QtWindows::MouseWheelEvent:
case QtWindows::MouseEvent:
case QtWindows::LeaveEvent:
@@ -1104,10 +1204,20 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
window = window->parent();
if (!window)
return false;
- return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(window, hwnd, et, msg, result);
+ if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
+ return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(window, hwnd, et, msg, result);
+ else
+ return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(window, hwnd, et, msg, result);
}
+ break;
case QtWindows::TouchEvent:
- return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateTouchEvent(platformWindow->window(), hwnd, et, msg, result);
+ if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
+ return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateTouchEvent(platformWindow->window(), hwnd, et, msg, result);
+ break;
+ case QtWindows::PointerEvent:
+ if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer)
+ return sessionManagerInteractionBlocked() || d->m_pointerHandler.translatePointerEvent(platformWindow->window(), hwnd, et, msg, result);
+ break;
case QtWindows::FocusInEvent: // see QWindowsWindow::requestActivateWindow().
case QtWindows::FocusOutEvent:
handleFocusEvent(et, platformWindow);
@@ -1150,6 +1260,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
}
break;
case QtWindows::MouseActivateWindowEvent:
+ case QtWindows::PointerActivateWindowEvent:
if (platformWindow->window()->flags() & Qt::WindowDoesNotAcceptFocus) {
*result = LRESULT(MA_NOACTIVATE);
return true;
@@ -1294,6 +1405,37 @@ bool QWindowsContext::handleContextMenuEvent(QWindow *window, const MSG &msg)
}
#endif
+void QWindowsContext::handleExitSizeMove(QWindow *window)
+{
+ // Windows can be moved/resized by:
+ // 1) User moving a window by dragging the title bar: Causes a sequence
+ // of WM_NCLBUTTONDOWN, WM_NCMOUSEMOVE but no WM_NCLBUTTONUP,
+ // leaving the left mouse button 'pressed'
+ // 2) User choosing Resize/Move from System menu and using mouse/cursor keys:
+ // No mouse events are received
+ // 3) Programmatically via QSizeGrip calling QPlatformWindow::startSystemResize/Move():
+ // Mouse is left in pressed state after press on size grip (inside window),
+ // no further mouse events are received
+ // For cases 1,3, intercept WM_EXITSIZEMOVE to sync the buttons.
+ const Qt::MouseButtons currentButtons = QWindowsMouseHandler::queryMouseButtons();
+ const Qt::MouseButtons appButtons = QGuiApplication::mouseButtons();
+ if (currentButtons == appButtons)
+ return;
+ const Qt::KeyboardModifiers keyboardModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
+ const QPoint globalPos = QWindowsCursor::mousePosition();
+ const QPlatformWindow *platWin = window->handle();
+ const QPoint localPos = platWin->mapFromGlobal(globalPos);
+ const QEvent::Type type = platWin->geometry().contains(globalPos)
+ ? QEvent::MouseButtonRelease : QEvent::NonClientAreaMouseButtonRelease;
+ 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);
+ }
+ }
+}
+
bool QWindowsContext::asyncExpose() const
{
return d->m_asyncExpose;
@@ -1306,7 +1448,8 @@ void QWindowsContext::setAsyncExpose(bool value)
QTouchDevice *QWindowsContext::touchDevice() const
{
- return d->m_mouseHandler.touchDevice();
+ return (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) ?
+ d->m_pointerHandler.touchDevice() : d->m_mouseHandler.touchDevice();
}
static DWORD readDwordRegistrySetting(const wchar_t *regKey, const wchar_t *subKey, DWORD defaultValue)
@@ -1399,7 +1542,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) {
- platformWindow->setFrameMargins(margins);
+ platformWindow->setFullFrameMargins(margins);
} else {
const QSharedPointer<QWindowCreationContext> ctx = QWindowsContext::instance()->windowCreationContext();
if (!ctx.isNull())
diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h
index 0a7f20ca83..19e9c26130 100644
--- a/src/plugins/platforms/windows/qwindowscontext.h
+++ b/src/plugins/platforms/windows/qwindowscontext.h
@@ -43,9 +43,9 @@
#include "qtwindowsglobal.h"
#include <QtCore/qt_windows.h>
-#include <QtCore/QScopedPointer>
-#include <QtCore/QSharedPointer>
-#include <QtCore/QLoggingCategory>
+#include <QtCore/qscopedpointer.h>
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/qloggingcategory.h>
#define STRICT_TYPED_ITEMIDS
#include <shlobj.h>
@@ -57,7 +57,6 @@ struct _SHSTOCKICONINFO;
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcQpaWindows)
-Q_DECLARE_LOGGING_CATEGORY(lcQpaBackingStore)
Q_DECLARE_LOGGING_CATEGORY(lcQpaEvents)
Q_DECLARE_LOGGING_CATEGORY(lcQpaGl)
Q_DECLARE_LOGGING_CATEGORY(lcQpaMime)
@@ -85,7 +84,18 @@ 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);
@@ -95,6 +105,18 @@ struct QWindowsUser32DLL
typedef int (WINAPI *GetWindowDpiAwarenessContext)(HWND);
typedef int (WINAPI *GetAwarenessFromDpiAwarenessContext)(int);
+ // 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;
@@ -134,7 +156,8 @@ public:
enum SystemInfoFlags
{
SI_RTL_Extensions = 0x1,
- SI_SupportsTouch = 0x2
+ SI_SupportsTouch = 0x2,
+ SI_SupportsPointer = 0x4,
};
// Verbose flag set by environment variable QT_QPA_VERBOSE
@@ -145,6 +168,8 @@ public:
bool initTouch();
bool initTouch(unsigned integrationOptions); // For calls from QWindowsIntegration::QWindowsIntegration() only.
+ bool initTablet(unsigned integrationOptions);
+ bool initPointer(unsigned integrationOptions);
int defaultDPI() const;
@@ -191,12 +216,16 @@ public:
void setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness);
static int processDpiAwareness();
+ void setDetectAltGrModifier(bool a);
+
// Returns a combination of SystemInfoFlags
unsigned systemInfo() const;
bool useRTLExtensions() const;
QList<int> possibleKeys(const QKeyEvent *e) const;
+ static bool isSessionLocked();
+
QWindowsMimeConverter &mimeConverter() const;
QWindowsScreenManager &screenManager();
QWindowsTabletSupport *tabletSupport() const;
@@ -220,6 +249,7 @@ private:
#ifndef QT_NO_CONTEXTMENU
bool handleContextMenuEvent(QWindow *window, const MSG &msg);
#endif
+ void handleExitSizeMove(QWindow *window);
void unregisterWindowClasses();
QScopedPointer<QWindowsContextPrivate> d;
diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp
index 72155a1d1b..4f669a5509 100644
--- a/src/plugins/platforms/windows/qwindowscursor.cpp
+++ b/src/plugins/platforms/windows/qwindowscursor.cpp
@@ -43,16 +43,16 @@
#include "qwindowswindow.h"
#include "qwindowsscreen.h"
-#include <QtGui/QBitmap>
-#include <QtGui/QImage>
-#include <QtGui/QBitmap>
-#include <QtGui/QGuiApplication>
-#include <QtGui/QScreen>
+#include <QtGui/qbitmap.h>
+#include <QtGui/qimage.h>
+#include <QtGui/qbitmap.h>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qscreen.h>
#include <QtGui/private/qguiapplication_p.h> // getPixmapCursor()
#include <QtGui/private/qhighdpiscaling_p.h>
-#include <QtCore/QDebug>
-#include <QtCore/QScopedArrayPointer>
+#include <QtCore/qdebug.h>
+#include <QtCore/qscopedpointer.h>
static bool initResources()
{
@@ -524,10 +524,11 @@ HCURSOR QWindowsCursor::createCursorFromShape(Qt::CursorShape cursorShape, const
}
// Load available standard cursors from resources
- const QWindowsStandardCursorMapping *sEnd = standardCursors + sizeof(standardCursors) / sizeof(standardCursors[0]);
- for (const QWindowsStandardCursorMapping *s = standardCursors; s < sEnd; ++s) {
- if (s->shape == cursorShape)
- return static_cast<HCURSOR>(LoadImage(0, s->resource, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED));
+ for (const QWindowsStandardCursorMapping &s : standardCursors) {
+ if (s.shape == cursorShape) {
+ return static_cast<HCURSOR>(LoadImage(nullptr, s.resource, IMAGE_CURSOR,
+ 0, 0, LR_DEFAULTSIZE | LR_SHARED));
+ }
}
qWarning("%s: Invalid cursor shape %d", __FUNCTION__, cursorShape);
@@ -659,18 +660,18 @@ QPoint QWindowsCursor::mousePosition()
return QPoint(p.x, p.y);
}
-QWindowsCursor::CursorState QWindowsCursor::cursorState()
+QWindowsCursor::State QWindowsCursor::cursorState()
{
enum { cursorShowing = 0x1, cursorSuppressed = 0x2 }; // Windows 8: CURSOR_SUPPRESSED
CURSORINFO cursorInfo;
cursorInfo.cbSize = sizeof(CURSORINFO);
if (GetCursorInfo(&cursorInfo)) {
- if (cursorInfo.flags & CursorShowing)
- return CursorShowing;
+ if (cursorInfo.flags & cursorShowing)
+ return State::Showing;
if (cursorInfo.flags & cursorSuppressed)
- return CursorSuppressed;
+ return State::Suppressed;
}
- return CursorHidden;
+ return State::Hidden;
}
QPoint QWindowsCursor::pos() const
diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h
index 345f47597e..8495b51a5a 100644
--- a/src/plugins/platforms/windows/qwindowscursor.h
+++ b/src/plugins/platforms/windows/qwindowscursor.h
@@ -43,8 +43,8 @@
#include <QtCore/qt_windows.h>
#include <qpa/qplatformcursor.h>
-#include <QtCore/QSharedPointer>
-#include <QtCore/QHash>
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/qhash.h>
QT_BEGIN_NAMESPACE
@@ -89,10 +89,10 @@ typedef QSharedPointer<CursorHandle> CursorHandlePtr;
class QWindowsCursor : public QPlatformCursor
{
public:
- enum CursorState {
- CursorShowing,
- CursorHidden,
- CursorSuppressed // Cursor suppressed by touch interaction (Windows 8).
+ enum class State {
+ Showing,
+ Hidden,
+ Suppressed // Cursor suppressed by touch interaction (Windows 8).
};
struct PixmapCursor {
@@ -119,7 +119,7 @@ public:
static HCURSOR createCursorFromShape(Qt::CursorShape cursorShape, const QPlatformScreen *screen = nullptr);
static QPoint mousePosition();
- static CursorState cursorState();
+ static State cursorState();
CursorHandlePtr standardWindowCursor(Qt::CursorShape s = Qt::ArrowCursor);
CursorHandlePtr pixmapWindowCursor(const QCursor &c);
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
index 80ee7b2287..681b35eb7c 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
@@ -51,24 +51,23 @@
#include "qwindowsintegration.h"
#include "qwindowstheme.h" // Color conversion helpers
-#include <QtGui/QGuiApplication>
-#include <QtGui/QColor>
-
-#include <QtCore/QDebug>
-#include <QtCore/QRegularExpression>
-#include <QtCore/QTimer>
-#include <QtCore/QDir>
-#include <QtCore/QScopedArrayPointer>
-#include <QtCore/QSharedPointer>
-#include <QtCore/QObject>
-#include <QtCore/QThread>
-#include <QtCore/QSysInfo>
-#include <QtCore/QSharedData>
-#include <QtCore/QExplicitlySharedDataPointer>
-#include <QtCore/QMutex>
-#include <QtCore/QMutexLocker>
-#include <QtCore/QUuid>
-#include <QtCore/QTemporaryFile>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qcolor.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qregularexpression.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qscopedpointer.h>
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qsysinfo.h>
+#include <QtCore/qshareddata.h>
+#include <QtCore/qshareddata.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/quuid.h>
+#include <QtCore/qtemporaryfile.h>
#include <QtCore/private/qsystemlibrary_p.h>
#include <algorithm>
@@ -365,7 +364,7 @@ static BOOL QT_WIN_CALLBACK findDialogEnumWindowsProc(HWND hwnd, LPARAM lParam)
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()))
+ if (!GetWindowTextW(hwnd, buf, sizeof(buf)/sizeof(wchar_t)) || wcscmp(buf, context->title.data()) != 0)
return TRUE;
context->hwnd = hwnd;
return FALSE;
@@ -508,6 +507,7 @@ class QWindowsNativeFileDialogBase;
class QWindowsNativeFileDialogEventHandler : public QWindowsComBase<IFileDialogEvents>
{
+ Q_DISABLE_COPY(QWindowsNativeFileDialogEventHandler)
public:
static IFileDialogEvents *create(QWindowsNativeFileDialogBase *nativeFileDialog);
@@ -523,7 +523,6 @@ public:
QWindowsNativeFileDialogEventHandler(QWindowsNativeFileDialogBase *nativeFileDialog) :
m_nativeFileDialog(nativeFileDialog) {}
- virtual ~QWindowsNativeFileDialogEventHandler() {}
private:
QWindowsNativeFileDialogBase *m_nativeFileDialog;
@@ -787,7 +786,7 @@ class QWindowsNativeFileDialogBase : public QWindowsNativeDialogBase
Q_OBJECT
Q_PROPERTY(bool hideFiltersDetails READ hideFiltersDetails WRITE setHideFiltersDetails)
public:
- ~QWindowsNativeFileDialogBase();
+ ~QWindowsNativeFileDialogBase() override;
inline static QWindowsNativeFileDialogBase *create(QFileDialogOptions::AcceptMode am, const QWindowsFileDialogSharedData &data);
@@ -1027,7 +1026,7 @@ static QList<FilterSpec> filterSpecs(const QStringList &filters,
Q_ASSERT(filterSeparatorRE.isValid());
// Split filter specification as 'Texts (*.txt[;] *.doc)', '*.txt[;] *.doc'
// into description and filters specification as '*.txt;*.doc'
- foreach (const QString &filterString, filters) {
+ for (const QString &filterString : filters) {
const int openingParenPos = filterString.lastIndexOf(QLatin1Char('('));
const int closingParenPos = openingParenPos != -1 ?
filterString.indexOf(QLatin1Char(')'), openingParenPos + 1) : -1;
@@ -1322,7 +1321,7 @@ void QWindowsNativeSaveFileDialog::setNameFilters(const QStringList &f)
// filter only if a default suffix is set (see docs). Set the first available
// suffix unless we have a defaultSuffix.
if (!hasDefaultSuffix()) {
- foreach (const QString &filter, f) {
+ for (const QString &filter : f) {
const QString suffix = suffixFromFilter(filter);
if (!suffix.isEmpty()) {
setDefaultSuffixSys(suffix);
@@ -1546,8 +1545,8 @@ QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog()
result->updateDirectory();
result->updateSelectedNameFilter();
const QList<QUrl> initialSelection = opts->initiallySelectedFiles();
- if (initialSelection.size() > 0) {
- const QUrl url = initialSelection.front();
+ if (!initialSelection.empty()) {
+ const QUrl &url = initialSelection.constFirst();
if (url.isLocalFile()) {
QFileInfo info(url.toLocalFile());
if (!info.isDir())
@@ -1699,7 +1698,7 @@ void QWindowsXpNativeFileDialog::doExec(HWND owner)
const QStringList nameFilters = m_options->nameFilters();
if (selectedFilterIndex >= 0 && selectedFilterIndex < nameFilters.size())
m_data.setSelectedNameFilter(nameFilters.at(selectedFilterIndex));
- QUrl firstFile = selectedFiles.front();
+ const QUrl &firstFile = selectedFiles.constFirst();
m_data.setDirectory(firstFile.adjusted(QUrl::RemoveFilename));
m_result = QPlatformDialogHelper::Accepted;
emit accepted();
@@ -1728,7 +1727,7 @@ int QWindowsXpNativeFileDialog::existingDirCallback(HWND hwnd, UINT uMsg, LPARAM
switch (uMsg) {
case BFFM_INITIALIZED: {
if (!m_title.isEmpty())
- SetWindowText(hwnd, (wchar_t *)m_title.utf16());
+ SetWindowText(hwnd, reinterpret_cast<const wchar_t *>(m_title.utf16()));
const QString initialFile = QDir::toNativeSeparators(m_data.directory().toLocalFile());
if (!initialFile.isEmpty())
SendMessage(hwnd, BFFM_SETSELECTION, TRUE, LPARAM(initialFile.utf16()));
@@ -1781,12 +1780,12 @@ void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND ow
// Create a buffer with the filter strings.
int totalStringLength = 0;
- QList<FilterSpec> specs =
+ const QList<FilterSpec> specs =
filterSpecs(m_options->nameFilters(), m_options->options() & QFileDialogOptions::HideNameFilterDetails, &totalStringLength);
const int size = specs.size();
wchar_t *ptr = new wchar_t[totalStringLength + 2 * size + 1];
ofn->lpstrFilter = ptr;
- foreach (const FilterSpec &spec, specs) {
+ for (const FilterSpec &spec : specs) {
ptr += spec.description.toWCharArray(ptr);
*ptr++ = 0;
ptr += spec.filter.toWCharArray(ptr);
@@ -1874,7 +1873,7 @@ QList<QUrl> QWindowsXpNativeFileDialog::execFileNames(HWND owner, int *selectedF
class QWindowsXpFileDialogHelper : public QWindowsDialogHelperBase<QPlatformFileDialogHelper>
{
public:
- QWindowsXpFileDialogHelper() {}
+ QWindowsXpFileDialogHelper() = default;
bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const override { return false; }
bool defaultNameFilterDisables() const override
{ return true; }
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.h b/src/plugins/platforms/windows/qwindowsdialoghelpers.h
index 55f112c57a..6099ea9ac6 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.h
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.h
@@ -43,8 +43,8 @@
#include <QtCore/qt_windows.h>
#include <qpa/qplatformdialoghelper.h>
#include <qpa/qplatformtheme.h>
-#include <QtCore/QStringList>
-#include <QtCore/QSharedPointer>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qsharedpointer.h>
QT_BEGIN_NAMESPACE
@@ -78,7 +78,7 @@ public:
virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return true; }
protected:
- QWindowsDialogHelperBase() {}
+ QWindowsDialogHelperBase() = default;
QWindowsNativeDialogBase *nativeDialog() const;
inline bool hasNativeDialog() const { return m_nativeDialog; }
void timerEvent(QTimerEvent *) override;
diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp
index e427ee162a..b7d225cb00 100644
--- a/src/plugins/platforms/windows/qwindowsdrag.cpp
+++ b/src/plugins/platforms/windows/qwindowsdrag.cpp
@@ -50,19 +50,19 @@
#include "qwindowsmousehandler.h"
#include "qwindowscursor.h"
-#include <QtGui/QMouseEvent>
-#include <QtGui/QPixmap>
-#include <QtGui/QPainter>
-#include <QtGui/QRasterWindow>
-#include <QtGui/QGuiApplication>
+#include <QtGui/qevent.h>
+#include <QtGui/qpixmap.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qrasterwindow.h>
+#include <QtGui/qguiapplication.h>
#include <qpa/qwindowsysteminterface_p.h>
#include <QtGui/private/qdnd_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qhighdpiscaling_p.h>
-#include <QtCore/QDebug>
-#include <QtCore/QBuffer>
-#include <QtCore/QPoint>
+#include <QtCore/qdebug.h>
+#include <QtCore/qbuffer.h>
+#include <QtCore/qpoint.h>
#include <shlobj.h>
@@ -225,7 +225,7 @@ public:
};
explicit QWindowsOleDropSource(QWindowsDrag *drag);
- virtual ~QWindowsOleDropSource();
+ ~QWindowsOleDropSource() override;
void createCursors();
@@ -260,7 +260,7 @@ private:
};
QWindowsOleDropSource::QWindowsOleDropSource(QWindowsDrag *drag)
- : m_mode(QWindowsCursor::cursorState() != QWindowsCursor::CursorSuppressed ? MouseDrag : TouchDrag)
+ : m_mode(QWindowsCursor::cursorState() != QWindowsCursor::State::Suppressed ? MouseDrag : TouchDrag)
, m_drag(drag)
, m_windowUnderMouse(QWindowsContext::instance()->windowUnderMouse())
, m_currentButtons(Qt::NoButton)
@@ -402,20 +402,16 @@ QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
switch (result) {
case DRAGDROP_S_DROP:
case DRAGDROP_S_CANCEL:
- QGuiApplicationPrivate::modifier_buttons = toQtKeyboardModifiers(grfKeyState);
- if (buttons != QGuiApplicationPrivate::mouse_buttons) {
- if (m_windowUnderMouse.isNull() || m_mode == TouchDrag || fEscapePressed == TRUE) {
- QGuiApplicationPrivate::mouse_buttons = buttons;
- } else {
- // QTBUG 66447: Synthesize a mouse release to the window under mouse at
- // start of the DnD operation as Windows does not send any.
- const QPoint globalPos = QWindowsCursor::mousePosition();
- const QPoint localPos = m_windowUnderMouse->handle()->mapFromGlobal(globalPos);
- QWindowSystemInterface::handleMouseEvent(m_windowUnderMouse.data(),
- QPointF(localPos), QPointF(globalPos),
- QWindowsMouseHandler::queryMouseButtons(),
- Qt::LeftButton, QEvent::MouseButtonRelease);
- }
+ if (!m_windowUnderMouse.isNull() && m_mode != TouchDrag && fEscapePressed == FALSE
+ && buttons != QGuiApplicationPrivate::mouse_buttons) {
+ // QTBUG 66447: Synthesize a mouse release to the window under mouse at
+ // start of the DnD operation as Windows does not send any.
+ const QPoint globalPos = QWindowsCursor::mousePosition();
+ const QPoint localPos = m_windowUnderMouse->handle()->mapFromGlobal(globalPos);
+ QWindowSystemInterface::handleMouseEvent(m_windowUnderMouse.data(),
+ QPointF(localPos), QPointF(globalPos),
+ QWindowsMouseHandler::queryMouseButtons(),
+ Qt::LeftButton, QEvent::MouseButtonRelease);
}
m_currentButtons = Qt::NoButton;
break;
@@ -459,7 +455,7 @@ QWindowsOleDropSource::GiveFeedback(DWORD dwEffect)
break;
case TouchDrag:
// "Touch drag" with an unsuppressed cursor may happen with RDP (see createCursors())
- if (QWindowsCursor::cursorState() != QWindowsCursor::CursorSuppressed)
+ if (QWindowsCursor::cursorState() != QWindowsCursor::State::Suppressed)
SetCursor(nullptr);
if (!m_touchDragWindow)
m_touchDragWindow = new QWindowsDragCursorWindow;
@@ -507,11 +503,13 @@ void QWindowsOleDropTarget::handleDrag(QWindow *window, DWORD grfKeyState,
QWindowsDrag *windowsDrag = QWindowsDrag::instance();
const Qt::DropActions actions = translateToQDragDropActions(*pdwEffect);
- QGuiApplicationPrivate::modifier_buttons = toQtKeyboardModifiers(grfKeyState);
- QGuiApplicationPrivate::mouse_buttons = toQtMouseButtons(grfKeyState);
+ const Qt::KeyboardModifiers keyboardModifiers = toQtKeyboardModifiers(grfKeyState);
+ const Qt::MouseButtons mouseButtons = toQtMouseButtons(grfKeyState);
const QPlatformDragQtResponse response =
- QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(), m_lastPoint, actions);
+ QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(),
+ m_lastPoint, actions,
+ mouseButtons, keyboardModifiers);
m_answerRect = response.answerRect();
const Qt::DropAction action = response.acceptedAction();
@@ -523,8 +521,7 @@ void QWindowsOleDropTarget::handleDrag(QWindow *window, DWORD grfKeyState,
*pdwEffect = m_chosenEffect;
qCDebug(lcQpaMime) << __FUNCTION__ << m_window
<< windowsDrag->dropData() << " supported actions=" << actions
- << " mods=" << QGuiApplicationPrivate::modifier_buttons
- << " mouse=" << QGuiApplicationPrivate::mouse_buttons
+ << " mods=" << keyboardModifiers << " mouse=" << mouseButtons
<< " accepted: " << response.isAccepted() << action
<< m_answerRect << " effect" << *pdwEffect;
}
@@ -575,13 +572,11 @@ QWindowsOleDropTarget::DragLeave()
qCDebug(lcQpaMime) << __FUNCTION__ << ' ' << m_window;
- QWindowSystemInterface::handleDrag(m_window, 0, QPoint(), Qt::IgnoreAction);
+ QWindowSystemInterface::handleDrag(m_window, 0, QPoint(), Qt::IgnoreAction,
+ Qt::NoButton, Qt::NoModifier);
- if (!QDragManager::self()->source()) {
- QGuiApplicationPrivate::modifier_buttons = Qt::NoModifier;
- QGuiApplicationPrivate::mouse_buttons = Qt::NoButton;
+ if (!QDragManager::self()->source())
m_lastKeyState = 0;
- }
QWindowsDrag::instance()->releaseDropDataObject();
return NOERROR;
@@ -600,18 +595,16 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState,
<< "keys=" << grfKeyState << "pt=" << pt.x << ',' << pt.y;
m_lastPoint = QWindowsGeometryHint::mapFromGlobal(m_window, QPoint(pt.x,pt.y));
- // grfKeyState does not all ways contain button state in the drop
- QGuiApplicationPrivate::mouse_buttons = toQtMouseButtons(m_lastKeyState);
- QGuiApplicationPrivate::modifier_buttons = toQtKeyboardModifiers(grfKeyState);
QWindowsDrag *windowsDrag = QWindowsDrag::instance();
const QPlatformDropQtResponse response =
QWindowSystemInterface::handleDrop(m_window, windowsDrag->dropData(),
m_lastPoint,
- translateToQDragDropActions(*pdwEffect));
+ translateToQDragDropActions(*pdwEffect),
+ toQtMouseButtons(grfKeyState),
+ toQtKeyboardModifiers(grfKeyState));
- QGuiApplicationPrivate::mouse_buttons = toQtMouseButtons(grfKeyState);
m_lastKeyState = grfKeyState;
if (response.isAccepted()) {
diff --git a/src/plugins/platforms/windows/qwindowsdrag.h b/src/plugins/platforms/windows/qwindowsdrag.h
index d934679488..f116e50cbf 100644
--- a/src/plugins/platforms/windows/qwindowsdrag.h
+++ b/src/plugins/platforms/windows/qwindowsdrag.h
@@ -44,8 +44,8 @@
#include "qwindowsinternalmimedata.h"
#include <qpa/qplatformdrag.h>
+#include <QtGui/qpixmap.h>
#include <QtGui/qdrag.h>
-#include <QtGui/QPixmap>
struct IDropTargetHelper;
@@ -55,7 +55,7 @@ class QPlatformScreen;
class QWindowsDropMimeData : public QWindowsInternalMimeData {
public:
- QWindowsDropMimeData() {}
+ QWindowsDropMimeData() = default;
IDataObject *retrieveDataObject() const override;
};
@@ -63,7 +63,7 @@ class QWindowsOleDropTarget : public QWindowsComBase<IDropTarget>
{
public:
explicit QWindowsOleDropTarget(QWindow *w);
- virtual ~QWindowsOleDropTarget();
+ ~QWindowsOleDropTarget() override;
// IDropTarget methods
STDMETHOD(DragEnter)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);
diff --git a/src/plugins/platforms/windows/qwindowsdropdataobject.cpp b/src/plugins/platforms/windows/qwindowsdropdataobject.cpp
index bd532ab70e..229ff92894 100644
--- a/src/plugins/platforms/windows/qwindowsdropdataobject.cpp
+++ b/src/plugins/platforms/windows/qwindowsdropdataobject.cpp
@@ -39,8 +39,8 @@
#include "qwindowsdropdataobject.h"
-#include <QtCore/QUrl>
-#include <QtCore/QMimeData>
+#include <QtCore/qurl.h>
+#include <QtCore/qmimedata.h>
QT_BEGIN_NAMESPACE
@@ -60,9 +60,7 @@ QWindowsDropDataObject::QWindowsDropDataObject(QMimeData *mimeData) :
{
}
-QWindowsDropDataObject::~QWindowsDropDataObject()
-{
-}
+QWindowsDropDataObject::~QWindowsDropDataObject() = default;
STDMETHODIMP
QWindowsDropDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium)
diff --git a/src/plugins/platforms/windows/qwindowsdropdataobject.h b/src/plugins/platforms/windows/qwindowsdropdataobject.h
index 5ef72c9336..16ba7b036a 100644
--- a/src/plugins/platforms/windows/qwindowsdropdataobject.h
+++ b/src/plugins/platforms/windows/qwindowsdropdataobject.h
@@ -48,7 +48,7 @@ class QWindowsDropDataObject : public QWindowsOleDataObject
{
public:
explicit QWindowsDropDataObject(QMimeData *mimeData);
- virtual ~QWindowsDropDataObject();
+ ~QWindowsDropDataObject() override;
// overridden IDataObject methods
STDMETHOD(GetData)(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium);
diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp
index 4632c9c157..52f3c56beb 100644
--- a/src/plugins/platforms/windows/qwindowseglcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp
@@ -41,8 +41,8 @@
#include "qwindowscontext.h"
#include "qwindowswindow.h"
-#include <QtCore/QDebug>
-#include <QtGui/QOpenGLContext>
+#include <QtCore/qdebug.h>
+#include <QtGui/qopenglcontext.h>
#if defined(QT_OPENGL_ES_2_ANGLE) || defined(QT_OPENGL_DYNAMIC)
# include <EGL/eglext.h>
@@ -889,19 +889,19 @@ EGLConfig QWindowsEGLContext::chooseConfig(const QSurfaceFormat &format)
EGLint green = 0;
EGLint blue = 0;
EGLint alpha = 0;
- for (int i = 0; i < configs.size(); ++i) {
+ for (const EGLConfig &config : configs) {
if (confAttrRed)
- QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, configs[i], EGL_RED_SIZE, &red);
+ QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, config, EGL_RED_SIZE, &red);
if (confAttrGreen)
- QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, configs[i], EGL_GREEN_SIZE, &green);
+ QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &green);
if (confAttrBlue)
- QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, configs[i], EGL_BLUE_SIZE, &blue);
+ QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blue);
if (confAttrAlpha)
- QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, configs[i], EGL_ALPHA_SIZE, &alpha);
+ QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &alpha);
if (red == confAttrRed && green == confAttrGreen
&& blue == confAttrBlue && alpha == confAttrAlpha)
- return configs[i];
+ return config;
}
} while (reduceConfigAttributes(&configureAttributes));
diff --git a/src/plugins/platforms/windows/qwindowseglcontext.h b/src/plugins/platforms/windows/qwindowseglcontext.h
index 3e5f2c81d5..8a1e1ddae8 100644
--- a/src/plugins/platforms/windows/qwindowseglcontext.h
+++ b/src/plugins/platforms/windows/qwindowseglcontext.h
@@ -113,7 +113,7 @@ class QWindowsEGLStaticContext : public QWindowsStaticOpenGLContext
public:
static QWindowsEGLStaticContext *create(QWindowsOpenGLTester::Renderers preferredType);
- ~QWindowsEGLStaticContext();
+ ~QWindowsEGLStaticContext() override;
EGLDisplay display() const { return m_display; }
@@ -143,7 +143,7 @@ public:
QWindowsEGLContext(QWindowsEGLStaticContext *staticContext,
const QSurfaceFormat &format,
QPlatformOpenGLContext *share);
- ~QWindowsEGLContext();
+ ~QWindowsEGLContext() override;
bool makeCurrent(QPlatformSurface *surface) override;
void doneCurrent() override;
diff --git a/src/plugins/platforms/windows/qwindowsgdiintegration.cpp b/src/plugins/platforms/windows/qwindowsgdiintegration.cpp
index 51f74518f7..c88f669eb5 100644
--- a/src/plugins/platforms/windows/qwindowsgdiintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsgdiintegration.cpp
@@ -42,7 +42,7 @@
#include "qwindowsbackingstore.h"
#include "qwindowsgdinativeinterface.h"
-#include <QtCore/QDebug>
+#include <QtCore/qdebug.h>
#include <QtGui/private/qpixmap_raster_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsgdiintegration.h b/src/plugins/platforms/windows/qwindowsgdiintegration.h
index ec67a99bc9..74ce3ffd49 100644
--- a/src/plugins/platforms/windows/qwindowsgdiintegration.h
+++ b/src/plugins/platforms/windows/qwindowsgdiintegration.h
@@ -49,7 +49,7 @@ class QWindowsGdiIntegration : public QWindowsIntegration
{
public:
explicit QWindowsGdiIntegration(const QStringList &paramList);
- virtual ~QWindowsGdiIntegration();
+ ~QWindowsGdiIntegration() override;
QPlatformNativeInterface *nativeInterface() const override;
QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const override;
diff --git a/src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp b/src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp
index c7796d959e..4ba7108f45 100644
--- a/src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp
+++ b/src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp
@@ -40,7 +40,7 @@
#include "qwindowsgdinativeinterface.h"
#include "qwindowsbackingstore.h"
-#include <QtGui/QBackingStore>
+#include <QtGui/qbackingstore.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp
index cc8174051a..851a6c961e 100644
--- a/src/plugins/platforms/windows/qwindowsglcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp
@@ -42,11 +42,11 @@
#include "qwindowswindow.h"
#include "qwindowsintegration.h"
-#include <QtCore/QDebug>
-#include <QtCore/QSysInfo>
-#include <QtGui/QGuiApplication>
+#include <QtCore/qdebug.h>
+#include <QtCore/qsysinfo.h>
+#include <QtGui/qguiapplication.h>
#include <qpa/qplatformnativeinterface.h>
-#include <QtPlatformHeaders/QWGLNativeContext>
+#include <QtPlatformHeaders/qwglnativecontext.h>
#include <algorithm>
@@ -206,18 +206,12 @@ bool QWindowsOpengl32DLL::init(bool softwareRendering)
BOOL QWindowsOpengl32DLL::swapBuffers(HDC dc)
{
- if (moduleIsNotOpengl32())
- return wglSwapBuffers(dc);
- else
- return SwapBuffers(dc);
+ return moduleIsNotOpengl32() ? wglSwapBuffers(dc) : SwapBuffers(dc);
}
BOOL QWindowsOpengl32DLL::setPixelFormat(HDC dc, int pf, const PIXELFORMATDESCRIPTOR *pfd)
{
- if (moduleIsNotOpengl32())
- return wglSetPixelFormat(dc, pf, pfd);
- else
- return SetPixelFormat(dc, pf, pfd);
+ return moduleIsNotOpengl32() ? wglSetPixelFormat(dc, pf, pfd) : SetPixelFormat(dc, pf, pfd);
}
QWindowsOpenGLContext *QOpenGLStaticContext::createContext(QOpenGLContext *context)
diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h
index 87c3723c26..199f8112e3 100644
--- a/src/plugins/platforms/windows/qwindowsglcontext.h
+++ b/src/plugins/platforms/windows/qwindowsglcontext.h
@@ -43,7 +43,7 @@
#include <QtCore/qt_windows.h>
#include "qwindowsopenglcontext.h"
-#include <QtGui/QOpenGLContext>
+#include <QtGui/qopenglcontext.h>
#include <vector>
@@ -170,13 +170,15 @@ public:
static QOpenGLStaticContext *create(bool softwareRendering = false);
static QByteArray getGlString(unsigned int which);
- QWindowsOpenGLContext *createContext(QOpenGLContext *context);
- void *moduleHandle() const { return opengl32.moduleHandle(); }
- QOpenGLContext::OpenGLModuleType moduleType() const { return QOpenGLContext::LibGL; }
+ QWindowsOpenGLContext *createContext(QOpenGLContext *context) override;
+ void *moduleHandle() const override { return opengl32.moduleHandle(); }
+ QOpenGLContext::OpenGLModuleType moduleType() const override
+ { return QOpenGLContext::LibGL; }
// For a regular opengl32.dll report the ThreadedOpenGL capability.
// For others, which are likely to be software-only, don't.
- bool supportsThreadedOpenGL() const { return !opengl32.moduleIsNotOpengl32(); }
+ bool supportsThreadedOpenGL() const override
+ { return !opengl32.moduleIsNotOpengl32(); }
const QByteArray vendor;
const QByteArray renderer;
@@ -198,7 +200,7 @@ class QWindowsGLContext : public QWindowsOpenGLContext
{
public:
explicit QWindowsGLContext(QOpenGLStaticContext *staticContext, QOpenGLContext *context);
- ~QWindowsGLContext();
+ ~QWindowsGLContext() override;
bool isSharing() const override { return m_context->shareHandle(); }
bool isValid() const override { return m_renderingContext && !m_lost; }
QSurfaceFormat format() const override { return m_obtainedFormat; }
diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
index 261c931f2b..30da0da1de 100644
--- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
@@ -43,16 +43,15 @@
#include "qwindowsintegration.h"
#include "qwindowsmousehandler.h"
-#include <QtCore/QDebug>
-#include <QtCore/QObject>
-#include <QtCore/QRect>
-#include <QtCore/QRectF>
-#include <QtCore/QTextBoundaryFinder>
-
-#include <QtGui/QInputMethodEvent>
-#include <QtGui/QTextCharFormat>
-#include <QtGui/QPalette>
-#include <QtGui/QGuiApplication>
+#include <QtCore/qdebug.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qtextboundaryfinder.h>
+
+#include <QtGui/qevent.h>
+#include <QtGui/qtextformat.h>
+#include <QtGui/qpalette.h>
+#include <QtGui/qguiapplication.h>
#include <private/qhighdpiscaling_p.h>
diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.h b/src/plugins/platforms/windows/qwindowsinputcontext.h
index d647628ff1..a47585c29e 100644
--- a/src/plugins/platforms/windows/qwindowsinputcontext.h
+++ b/src/plugins/platforms/windows/qwindowsinputcontext.h
@@ -42,8 +42,8 @@
#include <QtCore/qt_windows.h>
-#include <QtCore/QLocale>
-#include <QtCore/QPointer>
+#include <QtCore/qlocale.h>
+#include <QtCore/qpointer.h>
#include <qpa/qplatforminputcontext.h>
QT_BEGIN_NAMESPACE
@@ -53,6 +53,7 @@ class QWindowsWindow;
class QWindowsInputContext : public QPlatformInputContext
{
+ Q_DISABLE_COPY(QWindowsInputContext)
Q_OBJECT
struct CompositionContext
@@ -65,7 +66,7 @@ class QWindowsInputContext : public QPlatformInputContext
};
public:
explicit QWindowsInputContext();
- ~QWindowsInputContext();
+ ~QWindowsInputContext() override;
static void setWindowsImeEnabled(QWindowsWindow *platformWindow, bool enabled);
diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp
index 0a9e8b9d91..9e03d09607 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -59,7 +59,7 @@
#endif
#include "qwindowsinputcontext.h"
#include "qwindowskeymapper.h"
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
# include "uiautomation/qwindowsuiaaccessibility.h"
#endif
@@ -76,8 +76,8 @@
#include <QtEventDispatcherSupport/private/qwindowsguieventdispatcher_p.h>
-#include <QtCore/QDebug>
-#include <QtCore/QVariant>
+#include <QtCore/qdebug.h>
+#include <QtCore/qvariant.h>
#include <limits.h>
@@ -133,6 +133,7 @@ QT_BEGIN_NAMESPACE
struct QWindowsIntegrationPrivate
{
+ Q_DISABLE_COPY(QWindowsIntegrationPrivate)
explicit QWindowsIntegrationPrivate(const QStringList &paramList);
~QWindowsIntegrationPrivate();
@@ -150,7 +151,7 @@ struct QWindowsIntegrationPrivate
QScopedPointer<QWindowsStaticOpenGLContext> m_staticOpenGLContext;
#endif // QT_NO_OPENGL
QScopedPointer<QPlatformInputContext> m_inputContext;
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
QWindowsUiaAccessibility m_accessibility;
#endif
QWindowsServices m_services;
@@ -184,7 +185,7 @@ static inline unsigned parseOptions(const QStringList &paramList,
QtWindows::ProcessDpiAwareness *dpiAwareness)
{
unsigned options = 0;
- foreach (const QString &param, paramList) {
+ for (const QString &param : paramList) {
if (param.startsWith(QLatin1String("fontengine="))) {
if (param.endsWith(QLatin1String("freetype"))) {
options |= QWindowsIntegration::FontDatabaseFreeType;
@@ -197,6 +198,8 @@ static inline unsigned parseOptions(const QStringList &paramList,
} else if (param.endsWith(QLatin1String("none"))) {
options |= QWindowsIntegration::NoNativeDialogs;
}
+ } else if (param == QLatin1String("altgr")) {
+ options |= QWindowsIntegration::DetectAltGrModifier;
} else if (param == QLatin1String("gl=gdi")) {
options |= QWindowsIntegration::DisableArb;
} else if (param == QLatin1String("nodirectwrite")) {
@@ -212,6 +215,8 @@ static inline unsigned parseOptions(const QStringList &paramList,
options |= QWindowsIntegration::AlwaysUseNativeMenus;
} else if (param == QLatin1String("menus=none")) {
options |= QWindowsIntegration::NoNativeMenus;
+ } else if (param == QLatin1String("nowmpointer")) {
+ options |= QWindowsIntegration::DontUseWMPointer;
} else {
qWarning() << "Unknown option" << param;
}
@@ -230,8 +235,15 @@ QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList &paramL
QtWindows::ProcessDpiAwareness dpiAwareness = QtWindows::ProcessPerMonitorDpiAware;
m_options = parseOptions(paramList, &tabletAbsoluteRange, &dpiAwareness);
QWindowsFontDatabase::setFontOptions(m_options);
- if (tabletAbsoluteRange >= 0)
- m_context.setTabletAbsoluteRange(tabletAbsoluteRange);
+
+ if (m_context.initPointer(m_options)) {
+ QCoreApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents);
+ } else {
+ m_context.initTablet(m_options);
+ if (tabletAbsoluteRange >= 0)
+ m_context.setTabletAbsoluteRange(tabletAbsoluteRange);
+ }
+
if (!dpiAwarenessSet) { // Set only once in case of repeated instantiations of QGuiApplication.
if (!QCoreApplication::testAttribute(Qt::AA_PluginApplication)) {
m_context.setProcessDpiAwareness(dpiAwareness);
@@ -248,8 +260,7 @@ QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList &paramL
QWindowsIntegrationPrivate::~QWindowsIntegrationPrivate()
{
- if (m_fontDatabase)
- delete m_fontDatabase;
+ delete m_fontDatabase;
}
QWindowsIntegration *QWindowsIntegration::m_instance = nullptr;
@@ -262,6 +273,7 @@ QWindowsIntegration::QWindowsIntegration(const QStringList &paramList) :
d->m_clipboard.registerViewer();
#endif
d->m_context.screenManager().handleScreenChanges();
+ d->m_context.setDetectAltGrModifier((d->m_options & DetectAltGrModifier) != 0);
}
QWindowsIntegration::~QWindowsIntegration()
@@ -332,7 +344,7 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons
<< "\n Requested: " << requested.geometry << " frame incl.="
<< QWindowsGeometryHint::positionIncludesFrame(window)
<< ' ' << requested.flags
- << "\n Obtained : " << obtained.geometry << " margins=" << obtained.frame
+ << "\n Obtained : " << obtained.geometry << " margins=" << obtained.fullFrameMargins
<< " handle=" << obtained.hwnd << ' ' << obtained.flags << '\n';
if (Q_UNLIKELY(!obtained.hwnd))
@@ -381,7 +393,7 @@ QWindowsStaticOpenGLContext *QWindowsStaticOpenGLContext::doCreate()
switch (requestedRenderer) {
case QWindowsOpenGLTester::DesktopGl:
if (QWindowsStaticOpenGLContext *glCtx = QOpenGLStaticContext::create()) {
- if ((QWindowsOpenGLTester::supportedRenderers() & QWindowsOpenGLTester::DisableRotationFlag)
+ if ((QWindowsOpenGLTester::supportedRenderers(requestedRenderer) & QWindowsOpenGLTester::DisableRotationFlag)
&& !QWindowsScreen::setOrientationPreference(Qt::LandscapeOrientation)) {
qCWarning(lcQpaGl, "Unable to disable rotation.");
}
@@ -395,19 +407,23 @@ QWindowsStaticOpenGLContext *QWindowsStaticOpenGLContext::doCreate()
case QWindowsOpenGLTester::AngleRendererD3d11Warp:
return QWindowsEGLStaticContext::create(requestedRenderer);
case QWindowsOpenGLTester::Gles:
- return QWindowsEGLStaticContext::create(QWindowsOpenGLTester::supportedGlesRenderers());
+ return QWindowsEGLStaticContext::create(requestedRenderer);
case QWindowsOpenGLTester::SoftwareRasterizer:
if (QWindowsStaticOpenGLContext *swCtx = QOpenGLStaticContext::create(true))
return swCtx;
qCWarning(lcQpaGl, "Software OpenGL failed. Falling back to system OpenGL.");
- if (QWindowsOpenGLTester::supportedRenderers() & QWindowsOpenGLTester::DesktopGl)
+ if (QWindowsOpenGLTester::supportedRenderers(requestedRenderer) & QWindowsOpenGLTester::DesktopGl)
return QOpenGLStaticContext::create();
return nullptr;
default:
break;
}
- const QWindowsOpenGLTester::Renderers supportedRenderers = QWindowsOpenGLTester::supportedRenderers();
+ const QWindowsOpenGLTester::Renderers supportedRenderers = QWindowsOpenGLTester::supportedRenderers(requestedRenderer);
+ if (supportedRenderers.testFlag(QWindowsOpenGLTester::DisableProgramCacheFlag)
+ && !QCoreApplication::testAttribute(Qt::AA_DisableShaderDiskCache)) {
+ QCoreApplication::setAttribute(Qt::AA_DisableShaderDiskCache);
+ }
if (supportedRenderers & QWindowsOpenGLTester::DesktopGl) {
if (QWindowsStaticOpenGLContext *glCtx = QOpenGLStaticContext::create()) {
if ((supportedRenderers & QWindowsOpenGLTester::DisableRotationFlag)
@@ -425,7 +441,7 @@ QWindowsStaticOpenGLContext *QWindowsStaticOpenGLContext::doCreate()
#elif defined(QT_OPENGL_ES_2)
QWindowsOpenGLTester::Renderers glesRenderers = QWindowsOpenGLTester::requestedGlesRenderer();
if (glesRenderers == QWindowsOpenGLTester::InvalidRenderer)
- glesRenderers = QWindowsOpenGLTester::supportedGlesRenderers();
+ glesRenderers = QWindowsOpenGLTester::supportedRenderers(QWindowsOpenGLTester::AngleRendererD3d11);
return QWindowsEGLStaticContext::create(glesRenderers);
#elif !defined(QT_NO_OPENGL)
return QOpenGLStaticContext::create();
@@ -560,7 +576,7 @@ QPlatformInputContext * QWindowsIntegration::inputContext() const
return d->m_inputContext.data();
}
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
QPlatformAccessibility *QWindowsIntegration::accessibility() const
{
return &d->m_accessibility;
diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h
index 23f3d9ef4e..da86852766 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.h
+++ b/src/plugins/platforms/windows/qwindowsintegration.h
@@ -42,7 +42,7 @@
#define QWINDOWSINTEGRATION_H
#include <qpa/qplatformintegration.h>
-#include <QtCore/QScopedPointer>
+#include <QtCore/qscopedpointer.h>
#include <QtFontDatabaseSupport/private/qwindowsfontdatabase_p.h>
QT_BEGIN_NAMESPACE
@@ -54,6 +54,7 @@ class QWindowsStaticOpenGLContext;
class QWindowsIntegration : public QPlatformIntegration
{
+ Q_DISABLE_COPY(QWindowsIntegration)
public:
enum Options { // Options to be passed on command line.
FontDatabaseFreeType = 0x1,
@@ -66,11 +67,13 @@ public:
DontUseDirectWriteFonts = QWindowsFontDatabase::DontUseDirectWriteFonts,
DontUseColorFonts = QWindowsFontDatabase::DontUseColorFonts,
AlwaysUseNativeMenus = 0x100,
- NoNativeMenus = 0x200
+ NoNativeMenus = 0x200,
+ DontUseWMPointer = 0x400,
+ DetectAltGrModifier = 0x800
};
explicit QWindowsIntegration(const QStringList &paramList);
- virtual ~QWindowsIntegration();
+ ~QWindowsIntegration() override;
bool hasCapability(QPlatformIntegration::Capability cap) const override;
@@ -90,7 +93,7 @@ public:
# endif
#endif // !QT_NO_CLIPBOARD
QPlatformInputContext *inputContext() const override;
-#ifndef QT_NO_ACCESSIBILITY
+#if QT_CONFIG(accessibility)
QPlatformAccessibility *accessibility() const override;
#endif
QPlatformFontDatabase *fontDatabase() const override;
diff --git a/src/plugins/platforms/windows/qwindowsinternalmimedata.cpp b/src/plugins/platforms/windows/qwindowsinternalmimedata.cpp
index 21ebee6262..8f1d8f73d9 100644
--- a/src/plugins/platforms/windows/qwindowsinternalmimedata.cpp
+++ b/src/plugins/platforms/windows/qwindowsinternalmimedata.cpp
@@ -40,7 +40,7 @@
#include "qwindowsinternalmimedata.h"
#include "qwindowscontext.h"
#include "qwindowsmime.h"
-#include <QDebug>
+#include <QtCore/qdebug.h>
/*!
\class QWindowsInternalMimeDataBase
\brief Base for implementations of QInternalMimeData using a IDataObject COM object.
diff --git a/src/plugins/platforms/windows/qwindowsinternalmimedata.h b/src/plugins/platforms/windows/qwindowsinternalmimedata.h
index a44f5b509c..dbc1ea3922 100644
--- a/src/plugins/platforms/windows/qwindowsinternalmimedata.h
+++ b/src/plugins/platforms/windows/qwindowsinternalmimedata.h
@@ -43,7 +43,7 @@
#include <QtCore/qt_windows.h>
#include <QtGui/private/qinternalmimedata_p.h>
-#include <QtCore/QVariant>
+#include <QtCore/qvariant.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp
index 950d8ecd36..9e6101b758 100644
--- a/src/plugins/platforms/windows/qwindowskeymapper.cpp
+++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp
@@ -43,13 +43,14 @@
#include "qwindowswindow.h"
#include "qwindowsinputcontext.h"
-#include <QtGui/QGuiApplication>
-#include <QtGui/QWindow>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qwindow.h>
#include <qpa/qwindowsysteminterface.h>
#include <private/qguiapplication_p.h>
#include <private/qhighdpiscaling_p.h>
-#include <QtGui/QKeyEvent>
+#include <QtGui/qevent.h>
#include <QtEventDispatcherSupport/private/qwindowsguieventdispatcher_p.h>
+#include <QtCore/private/qdebug_p.h>
#if defined(WM_APPCOMMAND)
# ifndef FAPPCOMMAND_MOUSE
@@ -105,9 +106,7 @@ QWindowsKeyMapper::QWindowsKeyMapper()
changeKeyboard();
}
-QWindowsKeyMapper::~QWindowsKeyMapper()
-{
-}
+QWindowsKeyMapper::~QWindowsKeyMapper()= default;
#ifndef LANG_PASHTO
#define LANG_PASHTO 0x63
@@ -544,6 +543,59 @@ static const Qt::KeyboardModifiers ModsTbl[] = {
static const size_t NumMods = sizeof ModsTbl / sizeof *ModsTbl;
Q_STATIC_ASSERT((NumMods == KeyboardLayoutItem::NumQtKeys));
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const KeyboardLayoutItem &k)
+{
+ QDebugStateSaver saver(d);
+ d.nospace();
+ d << "KeyboardLayoutItem(";
+ if (k.exists) {
+ for (size_t i = 0; i < NumMods; ++i) {
+ if (const quint32 qtKey = k.qtKey[i]) {
+ d << '[' << i << ' ';
+ QtDebugUtils::formatQFlags(d, ModsTbl[i]);
+ d << ' ' << hex << showbase << qtKey << dec << noshowbase << ' ';
+ QtDebugUtils::formatQEnum(d, Qt::Key(qtKey));
+ if (qtKey >= 32 && qtKey < 128)
+ d << " '" << char(qtKey) << '\'';
+ if (k.deadkeys & (1<<i))
+ d << " deadkey";
+ d << "] ";
+ }
+ }
+ }
+ 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
+
/**
Remap return or action key to select key for windows mobile.
*/
@@ -599,8 +651,8 @@ static inline int asciiToKeycode(char a, int state)
void QWindowsKeyMapper::deleteLayouts()
{
- for (size_t i = 0; i < NumKeyboardLayoutItems; ++i)
- keyLayout[i].exists = false;
+ for (KeyboardLayoutItem &k : keyLayout)
+ k.exists = false;
}
void QWindowsKeyMapper::changeKeyboard()
@@ -620,6 +672,7 @@ void QWindowsKeyMapper::changeKeyboard()
bidi = true;
keyboardInputDirection = bidi ? Qt::RightToLeft : Qt::LeftToRight;
+ m_seenAltGr = false;
}
// Helper function that is used when obtaining the list of characters that can be produced by one key and
@@ -722,21 +775,8 @@ void QWindowsKeyMapper::updatePossibleKeyCodes(unsigned char *kbdBuffer, quint32
::ToAscii(VK_SPACE, 0, emptyBuffer, reinterpret_cast<LPWORD>(&buffer), 0);
::ToAscii(vk_key, scancode, kbdBuffer, reinterpret_cast<LPWORD>(&buffer), 0);
}
- if (QWindowsContext::verbose > 1 && lcQpaEvents().isDebugEnabled()) {
- QString message;
- QDebug debug(&message);
- debug <<__FUNCTION__ << " for virtual key = 0x" << hex << vk_key << dec<< '\n';
- for (size_t i = 0; i < NumMods; ++i) {
- const quint32 qtKey = keyLayout[vk_key].qtKey[i];
- debug << " [" << i << "] (" << qtKey << ','
- << hex << showbase << qtKey << noshowbase << dec
- << ",'" << char(qtKey ? qtKey : 0x03) << "')";
- if (keyLayout[vk_key].deadkeys & (1<<i))
- debug << " deadkey";
- debug << '\n';
- }
- qCDebug(lcQpaEvents) << message;
- }
+ qCDebug(lcQpaEvents) << __FUNCTION__ << "for virtual key="
+ << hex << showbase << vk_key << dec << noshowbase << keyLayout[vk_key];
}
static inline QString messageKeyText(const MSG &msg)
@@ -837,10 +877,26 @@ bool QWindowsKeyMapper::translateKeyEvent(QWindow *widget, HWND hwnd,
bool QWindowsKeyMapper::translateMultimediaKeyEventInternal(QWindow *window, const MSG &msg)
{
#if defined(WM_APPCOMMAND)
+ const int cmd = GET_APPCOMMAND_LPARAM(msg.lParam);
// QTBUG-57198, do not send mouse-synthesized commands as key events in addition
- if (GET_DEVICE_LPARAM(msg.lParam) == FAPPCOMMAND_MOUSE)
+ switch (GET_DEVICE_LPARAM(msg.lParam)) {
+ case FAPPCOMMAND_MOUSE:
return false;
- const int cmd = GET_APPCOMMAND_LPARAM(msg.lParam);
+ case FAPPCOMMAND_KEY:
+ // QTBUG-62838, swallow WM_KEYDOWN, WM_KEYUP for commands that are
+ // reflected in VK(s) like VK_MEDIA_NEXT_TRACK. Don't do that for
+ // APPCOMMAND_BROWSER_HOME as that one does not trigger two events
+ if (cmd != APPCOMMAND_BROWSER_HOME) {
+ MSG peekedMsg;
+ if (PeekMessage(&peekedMsg, msg.hwnd, 0, 0, PM_NOREMOVE)
+ && peekedMsg.message == WM_KEYDOWN) {
+ PeekMessage(&peekedMsg, msg.hwnd, 0, 0, PM_REMOVE);
+ PeekMessage(&peekedMsg, msg.hwnd, 0, 0, PM_REMOVE);
+ }
+ }
+ break;
+ }
+
const int dwKeys = GET_KEYSTATE_LPARAM(msg.lParam);
int state = 0;
state |= (dwKeys & MK_SHIFT ? int(Qt::ShiftModifier) : 0);
@@ -867,8 +923,34 @@ bool QWindowsKeyMapper::translateMultimediaKeyEventInternal(QWindow *window, con
#endif
}
-bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &msg, bool /* grab */, LRESULT *lResult)
+// QTBUG-69317: Check for AltGr found on some keyboards
+// which is a sequence of left Ctrl (SYSKEY) + right Menu (Alt).
+static bool isAltGr(MSG *msg)
+{
+ enum : LONG_PTR { RightFlag = 0x1000000 };
+ if (msg->wParam != VK_CONTROL || (msg->lParam & RightFlag) != 0
+ || (msg->message != WM_KEYDOWN && msg->message != WM_SYSKEYUP)) {
+ return false;
+ }
+ const UINT expectedMessage = msg->message == WM_SYSKEYUP
+ ? WM_KEYUP : msg->message;
+ MSG peekedMsg;
+ if (PeekMessage(&peekedMsg, msg->hwnd, 0, 0, PM_NOREMOVE) == FALSE
+ || peekedMsg.message != expectedMessage || peekedMsg.wParam != VK_MENU
+ || (peekedMsg.lParam & RightFlag) == 0) {
+ return false;
+ }
+ *msg = peekedMsg;
+ PeekMessage(&peekedMsg, msg->hwnd, 0, 0, PM_REMOVE);
+ return true;
+}
+
+bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
+ bool /* grab */, LRESULT *lResult)
{
+ const bool altGr = m_detectAltGrModifier && isAltGr(&msg);
+ if (altGr)
+ m_seenAltGr = true;
const UINT msgType = msg.message;
const quint32 scancode = (msg.lParam >> 16) & scancodeBitmask;
@@ -897,10 +979,12 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms
// Get the modifier states (may be altered later, depending on key code)
int state = 0;
state |= (nModifiers & ShiftAny ? int(Qt::ShiftModifier) : 0);
- state |= (nModifiers & ControlAny ? int(Qt::ControlModifier) : 0);
- state |= (nModifiers & AltAny ? int(Qt::AltModifier) : 0);
+ state |= (nModifiers & AltLeft ? int(Qt::AltModifier) : 0);
+ if ((nModifiers & AltRight) != 0)
+ state |= m_seenAltGr ? Qt::GroupSwitchModifier : Qt::AltModifier;
+ if ((nModifiers & ControlAny) != 0 && (state & Qt::GroupSwitchModifier) == 0)
+ state |= Qt::ControlModifier;
state |= (nModifiers & MetaAny ? int(Qt::MetaModifier) : 0);
-
// A multi-character key or a Input method character
// not found by our look-ahead
if (msgType == WM_CHAR || msgType == WM_IME_CHAR) {
@@ -971,8 +1055,17 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms
modifiersIndex |= (nModifiers & ControlAny ? 0x2 : 0);
modifiersIndex |= (nModifiers & AltAny ? 0x4 : 0);
+ // Note: For the resulting key, AltGr is equivalent to Alt + Ctrl (as
+ // opposed to Linux); hence no entry in KeyboardLayoutItem is required
int code = keyLayout[vk_key].qtKey[modifiersIndex];
+ // If the bit 24 of lParm is set you received a enter,
+ // otherwise a Return. (This is the extended key bit)
+ if ((code == Qt::Key_Return) && (msg.lParam & 0x1000000))
+ code = Qt::Key_Enter;
+ else if (altGr)
+ code = Qt::Key_AltGr;
+
// Invert state logic:
// 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
@@ -982,11 +1075,8 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms
state = state ^ Qt::ShiftModifier;
else if (code == Qt::Key_Alt)
state = state ^ Qt::AltModifier;
-
- // If the bit 24 of lParm is set you received a enter,
- // otherwise a Return. (This is the extended key bit)
- if ((code == Qt::Key_Return) && (msg.lParam & 0x1000000))
- code = Qt::Key_Enter;
+ else if (code == Qt::Key_AltGr)
+ state = state ^ Qt::GroupSwitchModifier;
// All cursor keys without extended bit
if (!(msg.lParam & 0x1000000)) {
@@ -1070,7 +1160,8 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms
if (uch.isHighSurrogate()) {
m_lastHighSurrogate = uch;
return true;
- } else if (uch.isLowSurrogate() && !m_lastHighSurrogate.isNull()) {
+ }
+ if (uch.isLowSurrogate() && !m_lastHighSurrogate.isNull()) {
if (QObject *focusObject = QGuiApplication::focusObject()) {
const QChar chars[2] = {m_lastHighSurrogate, uch};
QInputMethodEvent event;
@@ -1287,7 +1378,9 @@ QList<int> QWindowsKeyMapper::possibleKeys(const QKeyEvent *e) const
*it = matchedKey;
}
}
-
+ qCDebug(lcQpaEvents) << __FUNCTION__ << e << "nativeVirtualKey="
+ << showbase << hex << e->nativeVirtualKey() << dec << noshowbase
+ << e->modifiers() << kbItem << "\n returns" << formatKeys(result);
return result;
}
diff --git a/src/plugins/platforms/windows/qwindowskeymapper.h b/src/plugins/platforms/windows/qwindowskeymapper.h
index c6b46b0c30..a454f0f973 100644
--- a/src/plugins/platforms/windows/qwindowskeymapper.h
+++ b/src/plugins/platforms/windows/qwindowskeymapper.h
@@ -42,7 +42,7 @@
#include <QtCore/qt_windows.h>
-#include <QtCore/QLocale>
+#include <QtCore/qlocale.h>
QT_BEGIN_NAMESPACE
@@ -81,6 +81,9 @@ public:
void setUseRTLExtensions(bool e) { m_useRTLExtensions = e; }
bool useRTLExtensions() const { return m_useRTLExtensions; }
+ void setDetectAltGrModifier(bool a) { m_detectAltGrModifier = a; }
+ bool detectAltGrModifier() const { return m_detectAltGrModifier; }
+
bool translateKeyEvent(QWindow *widget, HWND hwnd, const MSG &msg, LRESULT *result);
QWindow *keyGrabber() const { return m_keyGrabber; }
@@ -90,7 +93,7 @@ public:
QList<int> possibleKeys(const QKeyEvent *e) const;
private:
- bool translateKeyEventInternal(QWindow *receiver, const MSG &msg, bool grab, LRESULT *lResult);
+ bool translateKeyEventInternal(QWindow *receiver, MSG msg, bool grab, LRESULT *lResult);
bool translateMultimediaKeyEventInternal(QWindow *receiver, const MSG &msg);
void updateKeyMap(const MSG &msg);
@@ -106,6 +109,9 @@ private:
QChar m_lastHighSurrogate;
static const size_t NumKeyboardLayoutItems = 256;
KeyboardLayoutItem keyLayout[NumKeyboardLayoutItems];
+ bool m_detectAltGrModifier = false;
+ bool m_seenAltGr = false;
+
};
enum WindowsNativeModifiers {
diff --git a/src/plugins/platforms/windows/qwindowsmenu.h b/src/plugins/platforms/windows/qwindowsmenu.h
index d51a29676e..6de1553f35 100644
--- a/src/plugins/platforms/windows/qwindowsmenu.h
+++ b/src/plugins/platforms/windows/qwindowsmenu.h
@@ -44,8 +44,8 @@
#include <qpa/qplatformmenu.h>
-#include <QtCore/QVector>
-#include <QtCore/QPair>
+#include <QtCore/qvector.h>
+#include <QtCore/qpair.h>
QT_BEGIN_NAMESPACE
@@ -60,7 +60,7 @@ class QWindowsMenuItem : public QPlatformMenuItem
Q_OBJECT
public:
explicit QWindowsMenuItem(QWindowsMenu *parentMenu = nullptr);
- ~QWindowsMenuItem();
+ ~QWindowsMenuItem() override;
void setText(const QString &text) override;
void setIcon(const QIcon &icon) override;
@@ -199,7 +199,7 @@ public:
typedef QVector<QWindowsMenu *> Menus;
QWindowsMenuBar();
- ~QWindowsMenuBar();
+ ~QWindowsMenuBar() override;
void insertMenu(QPlatformMenu *menu, QPlatformMenu *before) override;
void removeMenu(QPlatformMenu *menu) override;
diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp
index 0439797a7d..ff0dccb0d9 100644
--- a/src/plugins/platforms/windows/qwindowsmime.cpp
+++ b/src/plugins/platforms/windows/qwindowsmime.cpp
@@ -41,15 +41,15 @@
#include "qwindowscontext.h"
#include <QtGui/private/qinternalmimedata_p.h>
-#include <QtCore/QByteArrayMatcher>
-#include <QtCore/QTextCodec>
-#include <QtCore/QMap>
-#include <QtCore/QUrl>
-#include <QtCore/QDir>
-#include <QtCore/QDebug>
-#include <QtCore/QBuffer>
-#include <QtGui/QImageReader>
-#include <QtGui/QImageWriter>
+#include <QtCore/qbytearraymatcher.h>
+#include <QtCore/qtextcodec.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qbuffer.h>
+#include <QtGui/qimagereader.h>
+#include <QtGui/qimagewriter.h>
#include <shlobj.h>
#include <algorithm>
@@ -107,7 +107,8 @@ static inline QByteArray msgConversionError(const char *func, const char *format
msg += ": Unable to convert DIB image. The image converter plugin for '";
msg += format;
msg += "' is not available. Available formats: ";
- foreach (const QByteArray &af, QImageReader::supportedImageFormats()) {
+ const QList<QByteArray> &formats = QImageReader::supportedImageFormats();
+ for (const QByteArray &af : formats) {
msg += af;
msg += ' ';
}
@@ -487,17 +488,13 @@ QDebug operator<<(QDebug d, IDataObject *dataObj)
Constructs a new conversion object, adding it to the globally accessed
list of available converters.
*/
-QWindowsMime::QWindowsMime()
-{
-}
+QWindowsMime::QWindowsMime() = default;
/*!
Destroys a conversion object, removing it from the global
list of available converters.
*/
-QWindowsMime::~QWindowsMime()
-{
-}
+QWindowsMime::~QWindowsMime() = default;
/*!
Registers the MIME type \a mime, and returns an ID number
@@ -573,12 +570,12 @@ int QWindowsMime::registerMimeType(const QString &mime)
class QWindowsMimeText : public QWindowsMime
{
public:
- bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const;
- QVariant convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const;
- QString mimeForFormat(const FORMATETC &formatetc) const;
- bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
- bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const;
- QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const;
+ bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override;
+ QVariant convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QVariant::Type 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;
};
bool QWindowsMimeText::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
@@ -627,7 +624,8 @@ bool QWindowsMimeText::convertFromMime(const FORMATETC &formatetc, const QMimeDa
}
o[j]=0;
return setData(r, pmedium);
- } else if (cf == CF_UNICODETEXT) {
+ }
+ if (cf == CF_UNICODETEXT) {
QString str = mimeData->text();
const QChar *u = str.unicode();
QString res;
@@ -729,12 +727,12 @@ class QWindowsMimeURI : public QWindowsMime
{
public:
QWindowsMimeURI();
- bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const;
- QVariant convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QVariant::Type preferredType) const;
- QString mimeForFormat(const FORMATETC &formatetc) const;
- bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const;
- bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const;
- QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const;
+ bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override;
+ QVariant convertToMime(const QString &mime, LPDATAOBJECT pDataObj, QVariant::Type 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;
private:
int CF_INETURL_W; // wide char version
int CF_INETURL;
@@ -749,9 +747,9 @@ QWindowsMimeURI::QWindowsMimeURI()
bool QWindowsMimeURI::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
{
if (mimeData->hasUrls() && getCf(formatetc) == CF_HDROP) {
- QList<QUrl> urls = mimeData->urls();
- for (int i=0; i<urls.size(); i++) {
- if (!urls.at(i).toLocalFile().isEmpty())
+ const QList<QUrl> urls = mimeData->urls();
+ for (const QUrl &url : urls) {
+ if (url.isLocalFile())
return true;
}
}
@@ -762,11 +760,11 @@ bool QWindowsMimeURI::convertFromMime(const FORMATETC &formatetc, const QMimeDat
{
if (canConvertFromMime(formatetc, mimeData)) {
if (getCf(formatetc) == CF_HDROP) {
- QList<QUrl> urls = mimeData->urls();
+ const QList<QUrl> &urls = mimeData->urls();
QStringList fileNames;
int size = sizeof(DROPFILES)+2;
- for (int i=0; i<urls.size(); i++) {
- QString fn = QDir::toNativeSeparators(urls.at(i).toLocalFile());
+ for (const QUrl &url : urls) {
+ const QString fn = QDir::toNativeSeparators(url.toLocalFile());
if (!fn.isEmpty()) {
size += sizeof(ushort) * size_t(fn.length() + 1);
fileNames.append(fn);
@@ -791,7 +789,8 @@ bool QWindowsMimeURI::convertFromMime(const FORMATETC &formatetc, const QMimeDat
*f = 0;
return setData(result, pmedium);
- } else if (getCf(formatetc) == CF_INETURL_W) {
+ }
+ if (getCf(formatetc) == CF_INETURL_W) {
QList<QUrl> urls = mimeData->urls();
QByteArray result;
if (!urls.isEmpty()) {
@@ -802,7 +801,8 @@ bool QWindowsMimeURI::convertFromMime(const FORMATETC &formatetc, const QMimeDat
result.append('\0');
result.append('\0');
return setData(result, pmedium);
- } else if (getCf(formatetc) == CF_INETURL) {
+ }
+ if (getCf(formatetc) == CF_INETURL) {
QList<QUrl> urls = mimeData->urls();
QByteArray result;
if (!urls.isEmpty())
@@ -872,7 +872,7 @@ QVariant QWindowsMimeURI::convertToMime(const QString &mimeType, LPDATAOBJECT pD
if (preferredType == QVariant::Url && urls.size() == 1)
return urls.at(0);
- else if (!urls.isEmpty())
+ if (!urls.isEmpty())
return urls;
} else if (canGetData(CF_INETURL_W, pDataObj)) {
QByteArray data = getData(CF_INETURL_W, pDataObj);
@@ -1075,10 +1075,8 @@ QString QWindowsMimeImage::mimeForFormat(const FORMATETC &formatetc) const
bool QWindowsMimeImage::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
{
- if (mimeType == QLatin1String("application/x-qt-image") &&
- (canGetData(CF_DIB, pDataObj) || canGetData(CF_PNG, pDataObj)))
- return true;
- return false;
+ return mimeType == QLatin1String("application/x-qt-image")
+ && (canGetData(CF_DIB, pDataObj) || canGetData(CF_PNG, pDataObj));
}
bool QWindowsMimeImage::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
@@ -1134,7 +1132,7 @@ bool QWindowsMimeImage::hasOriginalDIBV5(IDataObject *pDataObj) const
CoTaskMemFree(fc.ptd);
if (fc.cfFormat == CF_DIB)
break;
- else if (fc.cfFormat == CF_DIBV5) {
+ if (fc.cfFormat == CF_DIBV5) {
isSynthesized = false;
break;
}
@@ -1328,7 +1326,7 @@ QStringList QLastResortMimes::excludeList;
QLastResortMimes::QLastResortMimes()
{
//MIME Media-Types
- if (!ianaTypes.size()) {
+ if (ianaTypes.isEmpty()) {
ianaTypes.append(QStringLiteral("application/"));
ianaTypes.append(QStringLiteral("audio/"));
ianaTypes.append(QStringLiteral("example/"));
@@ -1340,7 +1338,7 @@ QLastResortMimes::QLastResortMimes()
ianaTypes.append(QStringLiteral("video/"));
}
//Types handled by other classes
- if (!excludeList.size()) {
+ if (excludeList.isEmpty()) {
excludeList.append(QStringLiteral("HTML Format"));
excludeList.append(QStringLiteral("UniformResourceLocator"));
excludeList.append(QStringLiteral("text/html"));
@@ -1598,7 +1596,7 @@ QVariant QWindowsMimeConverter::convertToMime(const QStringList &mimeTypes,
QVariant::Type preferredType,
QString *formatIn /* = 0 */) const
{
- foreach (const QString &format, mimeTypes) {
+ for (const QString &format : mimeTypes) {
if (const QWindowsMime *converter = converterToMime(format, pDataObj)) {
if (converter->canConvertToMime(format, pDataObj)) {
const QVariant dataV = converter->convertToMime(format, pDataObj, preferredType);
diff --git a/src/plugins/platforms/windows/qwindowsmime.h b/src/plugins/platforms/windows/qwindowsmime.h
index 1ed2aa933f..6bbbae1a0e 100644
--- a/src/plugins/platforms/windows/qwindowsmime.h
+++ b/src/plugins/platforms/windows/qwindowsmime.h
@@ -42,9 +42,9 @@
#include <QtCore/qt_windows.h>
-#include <QtCore/QVector>
-#include <QtCore/QList>
-#include <QtCore/QVariant>
+#include <QtCore/qvector.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qvariant.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
index 17851618b4..c1c275144f 100644
--- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp
+++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
@@ -45,14 +45,14 @@
#include "qwindowsscreen.h"
#include <qpa/qwindowsysteminterface.h>
-#include <QtGui/QGuiApplication>
-#include <QtGui/QScreen>
-#include <QtGui/QTouchDevice>
-#include <QtGui/QWindow>
-#include <QtGui/QCursor>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qscreen.h>
+#include <QtGui/qtouchdevice.h>
+#include <QtGui/qwindow.h>
+#include <QtGui/qcursor.h>
-#include <QtCore/QDebug>
-#include <QtCore/QScopedArrayPointer>
+#include <QtCore/qdebug.h>
+#include <QtCore/qscopedpointer.h>
#include <windowsx.h>
@@ -119,20 +119,16 @@ static inline void compressMouseMove(MSG *msg)
static inline QTouchDevice *createTouchDevice()
{
- enum { QT_SM_TABLETPC = 86, QT_SM_DIGITIZER = 94, QT_SM_MAXIMUMTOUCHES = 95,
- QT_NID_INTEGRATED_TOUCH = 0x1, QT_NID_EXTERNAL_TOUCH = 0x02,
- QT_NID_MULTI_INPUT = 0x40, QT_NID_READY = 0x80 };
-
- const int digitizers = GetSystemMetrics(QT_SM_DIGITIZER);
- if (!(digitizers & (QT_NID_INTEGRATED_TOUCH | QT_NID_EXTERNAL_TOUCH)))
+ const int digitizers = GetSystemMetrics(SM_DIGITIZER);
+ if (!(digitizers & (NID_INTEGRATED_TOUCH | NID_EXTERNAL_TOUCH)))
return 0;
- const int tabletPc = GetSystemMetrics(QT_SM_TABLETPC);
- const int maxTouchPoints = GetSystemMetrics(QT_SM_MAXIMUMTOUCHES);
- qCDebug(lcQpaEvents) << "Digitizers:" << hex << showbase << (digitizers & ~QT_NID_READY)
- << "Ready:" << (digitizers & QT_NID_READY) << dec << noshowbase
+ const int tabletPc = GetSystemMetrics(SM_TABLETPC);
+ const int maxTouchPoints = GetSystemMetrics(SM_MAXIMUMTOUCHES);
+ qCDebug(lcQpaEvents) << "Digitizers:" << hex << showbase << (digitizers & ~NID_READY)
+ << "Ready:" << (digitizers & NID_READY) << dec << noshowbase
<< "Tablet PC:" << tabletPc << "Max touch points:" << maxTouchPoints;
QTouchDevice *result = new QTouchDevice;
- result->setType(digitizers & QT_NID_INTEGRATED_TOUCH
+ result->setType(digitizers & NID_INTEGRATED_TOUCH
? QTouchDevice::TouchScreen : QTouchDevice::TouchPad);
QTouchDevice::Capabilities capabilities = QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::NormalizedPosition;
if (result->type() == QTouchDevice::TouchPad)
@@ -178,22 +174,121 @@ Qt::MouseButtons QWindowsMouseHandler::queryMouseButtons()
return result;
}
+static QPoint lastMouseMovePos;
+
+namespace {
+struct MouseEvent {
+ QEvent::Type type;
+ Qt::MouseButton button;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const MouseEvent &e)
+{
+ QDebugStateSaver saver(d);
+ d.nospace();
+ d << "MouseEvent(" << e.type << ", " << e.button << ')';
+ return d;
+}
+#endif // QT_NO_DEBUG_STREAM
+} // namespace
+
+static inline Qt::MouseButton extraButton(WPARAM wParam) // for WM_XBUTTON...
+{
+ return GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? Qt::BackButton : Qt::ForwardButton;
+}
+
+static inline MouseEvent eventFromMsg(const MSG &msg)
+{
+ switch (msg.message) {
+ case WM_MOUSEMOVE:
+ return {QEvent::MouseMove, Qt::NoButton};
+ case WM_LBUTTONDOWN:
+ return {QEvent::MouseButtonPress, Qt::LeftButton};
+ case WM_LBUTTONUP:
+ return {QEvent::MouseButtonRelease, Qt::LeftButton};
+ case WM_LBUTTONDBLCLK:
+ return {QEvent::MouseButtonDblClick, Qt::LeftButton};
+ case WM_MBUTTONDOWN:
+ return {QEvent::MouseButtonPress, Qt::MidButton};
+ case WM_MBUTTONUP:
+ return {QEvent::MouseButtonRelease, Qt::MidButton};
+ case WM_MBUTTONDBLCLK:
+ return {QEvent::MouseButtonDblClick, Qt::MidButton};
+ case WM_RBUTTONDOWN:
+ return {QEvent::MouseButtonPress, Qt::RightButton};
+ case WM_RBUTTONUP:
+ return {QEvent::MouseButtonRelease, Qt::RightButton};
+ case WM_RBUTTONDBLCLK:
+ return {QEvent::MouseButtonDblClick, Qt::RightButton};
+ case WM_XBUTTONDOWN:
+ return {QEvent::MouseButtonPress, extraButton(msg.wParam)};
+ case WM_XBUTTONUP:
+ return {QEvent::MouseButtonRelease, extraButton(msg.wParam)};
+ case WM_XBUTTONDBLCLK:
+ return {QEvent::MouseButtonDblClick, extraButton(msg.wParam)};
+ case WM_NCMOUSEMOVE:
+ return {QEvent::NonClientAreaMouseMove, Qt::NoButton};
+ case WM_NCLBUTTONDOWN:
+ return {QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton};
+ case WM_NCLBUTTONUP:
+ return {QEvent::NonClientAreaMouseButtonRelease, Qt::LeftButton};
+ case WM_NCLBUTTONDBLCLK:
+ return {QEvent::NonClientAreaMouseButtonDblClick, Qt::LeftButton};
+ case WM_NCMBUTTONDOWN:
+ return {QEvent::NonClientAreaMouseButtonPress, Qt::MidButton};
+ case WM_NCMBUTTONUP:
+ return {QEvent::NonClientAreaMouseButtonRelease, Qt::MidButton};
+ case WM_NCMBUTTONDBLCLK:
+ return {QEvent::NonClientAreaMouseButtonDblClick, Qt::MidButton};
+ case WM_NCRBUTTONDOWN:
+ return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton};
+ case WM_NCRBUTTONUP:
+ return {QEvent::NonClientAreaMouseButtonRelease, Qt::RightButton};
+ case WM_NCRBUTTONDBLCLK:
+ return {QEvent::NonClientAreaMouseButtonDblClick, Qt::RightButton};
+ default: // WM_MOUSELEAVE
+ break;
+ }
+ return {QEvent::None, Qt::NoButton};
+}
+
bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
QtWindows::WindowsEventType et,
MSG msg, LRESULT *result)
{
-#ifdef Q_COMPILER_CLASS_ENUM
enum : quint64 { signatureMask = 0xffffff00, miWpSignature = 0xff515700 };
-#else
- static const quint64 signatureMask = 0xffffff00;
- static const quint64 miWpSignature = 0xff515700;
-#endif // !Q_COMPILER_CLASS_ENUM
if (et == QtWindows::MouseWheelEvent)
return translateMouseWheelEvent(window, hwnd, msg, result);
+ const QPoint winEventPosition(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
+ QPoint clientPosition;
+ QPoint globalPosition;
+ if (et & QtWindows::NonClientEventFlag) {
+ globalPosition = winEventPosition;
+ clientPosition = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPosition);
+ } else {
+ clientPosition = winEventPosition;
+ globalPosition = QWindowsGeometryHint::mapToGlobal(hwnd, winEventPosition);
+ }
+
+ // Windows sends a mouse move with no buttons pressed to signal "Enter"
+ // when a window is shown over the cursor. Discard the event and only use
+ // it for generating QEvent::Enter to be consistent with other platforms -
+ // X11 and macOS.
+ bool discardEvent = false;
+ if (msg.message == WM_MOUSEMOVE) {
+ const bool samePosition = globalPosition == lastMouseMovePos;
+ lastMouseMovePos = globalPosition;
+ if (msg.wParam == 0 && (m_windowUnderMouse.isNull() || samePosition))
+ discardEvent = true;
+ }
+
Qt::MouseEventSource source = Qt::MouseEventNotSynthesized;
+ const MouseEvent mouseEvent = eventFromMsg(msg);
+
// Check for events synthesized from touch. Lower byte is touch index, 0 means pen.
static const bool passSynthesizedMouseEvents =
!(QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch);
@@ -210,13 +305,11 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
}
}
- const QPoint winEventPosition(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
- if (et & QtWindows::NonClientEventFlag) {
- const QPoint globalPosition = winEventPosition;
- const QPoint clientPosition = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPosition);
+ if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) {
const Qt::MouseButtons buttons = QWindowsMouseHandler::queryMouseButtons();
QWindowSystemInterface::handleFrameStrutMouseEvent(window, clientPosition,
globalPosition, buttons,
+ mouseEvent.button, mouseEvent.type,
QWindowsKeyMapper::queryKeyboardModifiers(),
source);
return false; // Allow further event processing (dragging of windows).
@@ -224,7 +317,8 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
*result = 0;
if (msg.message == WM_MOUSELEAVE) {
- qCDebug(lcQpaEvents) << "WM_MOUSELEAVE for " << window << " previous window under mouse = " << m_windowUnderMouse << " tracked window =" << m_trackedWindow;
+ qCDebug(lcQpaEvents) << mouseEvent << "for" << window << "previous window under mouse="
+ << m_windowUnderMouse << "tracked window=" << m_trackedWindow;
// When moving out of a window, WM_MOUSEMOVE within the moved-to window is received first,
// so if m_trackedWindow is not the window here, it means the cursor has left the
@@ -264,12 +358,11 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
}
m_previousCaptureWindow = window;
return true;
- } else if (m_leftButtonDown && !actualLeftDown) {
- m_leftButtonDown = false;
}
+ if (m_leftButtonDown && !actualLeftDown)
+ m_leftButtonDown = false;
}
- const QPoint globalPosition = QWindowsGeometryHint::mapToGlobal(hwnd, winEventPosition);
// In this context, neither an invisible nor a transparent window (transparent regarding mouse
// events, "click-through") can be considered as the window under mouse.
QWindow *currentWindowUnderMouse = platformWindow->hasMouseCapture() ?
@@ -290,10 +383,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
// Qt expects the platform plugin to capture the mouse on
// any button press until release.
if (!platformWindow->hasMouseCapture()
- && (msg.message == WM_LBUTTONDOWN || msg.message == WM_MBUTTONDOWN
- || msg.message == WM_RBUTTONDOWN || msg.message == WM_XBUTTONDOWN
- || msg.message == WM_LBUTTONDBLCLK || msg.message == WM_MBUTTONDBLCLK
- || msg.message == WM_RBUTTONDBLCLK || msg.message == WM_XBUTTONDBLCLK)) {
+ && (mouseEvent.type == QEvent::MouseButtonPress || mouseEvent.type == QEvent::MouseButtonDblClick)) {
platformWindow->setMouseGrabEnabled(true);
platformWindow->setFlag(QWindowsWindow::AutoMouseCapture);
qCDebug(lcQpaEvents) << "Automatic mouse capture " << window;
@@ -302,8 +392,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
window->requestActivate();
} else if (platformWindow->hasMouseCapture()
&& platformWindow->testFlag(QWindowsWindow::AutoMouseCapture)
- && (msg.message == WM_LBUTTONUP || msg.message == WM_MBUTTONUP
- || msg.message == WM_RBUTTONUP || msg.message == WM_XBUTTONUP)
+ && mouseEvent.type == QEvent::MouseButtonRelease
&& !buttons) {
platformWindow->setMouseGrabEnabled(false);
qCDebug(lcQpaEvents) << "Releasing automatic mouse capture " << window;
@@ -369,9 +458,12 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
m_windowUnderMouse = currentWindowUnderMouse;
}
- QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition, buttons,
- QWindowsKeyMapper::queryKeyboardModifiers(),
- source);
+ if (!discardEvent && mouseEvent.type != QEvent::None) {
+ QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition, buttons,
+ mouseEvent.button, mouseEvent.type,
+ QWindowsKeyMapper::queryKeyboardModifiers(),
+ source);
+ }
m_previousCaptureWindow = hasCapture ? window : 0;
// QTBUG-48117, force synchronous handling for the extra buttons so that WM_APPCOMMAND
// is sent for unhandled WM_XBUTTONDOWN.
@@ -411,9 +503,10 @@ 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,
QWindowsGeometryHint::mapFromGlobal(receiver, globalPos),
- globalPos, delta, orientation, mods);
+ globalPos, QPoint(), point, mods);
}
}
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.h b/src/plugins/platforms/windows/qwindowsmousehandler.h
index 86f18a0482..480662c9bf 100644
--- a/src/plugins/platforms/windows/qwindowsmousehandler.h
+++ b/src/plugins/platforms/windows/qwindowsmousehandler.h
@@ -43,8 +43,8 @@
#include "qtwindowsglobal.h"
#include <QtCore/qt_windows.h>
-#include <QtCore/QPointer>
-#include <QtCore/QHash>
+#include <QtCore/qpointer.h>
+#include <QtCore/qhash.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp
index ffa100f824..de11356fd4 100644
--- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp
+++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp
@@ -48,9 +48,9 @@
#include "qwindowsmime.h"
#include "qwin10helpers.h"
-#include <QtGui/QWindow>
-#include <QtGui/QOpenGLContext>
-#include <QtGui/QScreen>
+#include <QtGui/qwindow.h>
+#include <QtGui/qopenglcontext.h>
+#include <QtGui/qscreen.h>
#include <qpa/qplatformscreen.h>
#include <QtFontDatabaseSupport/private/qwindowsfontdatabase_p.h>
@@ -111,15 +111,14 @@ void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resourc
return 0;
}
break;
- case QWindow::OpenGLSurface:
- case QWindow::OpenVGSurface:
- break;
case QWindow::VulkanSurface:
#if QT_CONFIG(vulkan)
if (type == VkSurface)
return bw->surface(nullptr, nullptr); // returns the address of the VkSurfaceKHR, not the value, as expected
#endif
break;
+ default:
+ break;
}
qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData());
return 0;
@@ -276,11 +275,11 @@ QFunctionPointer QWindowsNativeInterface::platformFunction(const QByteArray &fun
{
if (function == QWindowsWindowFunctions::setTouchWindowTouchTypeIdentifier())
return QFunctionPointer(QWindowsWindow::setTouchWindowTouchTypeStatic);
- else if (function == QWindowsWindowFunctions::setHasBorderInFullScreenIdentifier())
+ if (function == QWindowsWindowFunctions::setHasBorderInFullScreenIdentifier())
return QFunctionPointer(QWindowsWindow::setHasBorderInFullScreenStatic);
- else if (function == QWindowsWindowFunctions::setWindowActivationBehaviorIdentifier())
+ if (function == QWindowsWindowFunctions::setWindowActivationBehaviorIdentifier())
return QFunctionPointer(QWindowsNativeInterface::setWindowActivationBehavior);
- else if (function == QWindowsWindowFunctions::isTabletModeIdentifier())
+ if (function == QWindowsWindowFunctions::isTabletModeIdentifier())
return QFunctionPointer(QWindowsNativeInterface::isTabletMode);
return nullptr;
}
diff --git a/src/plugins/platforms/windows/qwindowsole.cpp b/src/plugins/platforms/windows/qwindowsole.cpp
index 0ceb0d82fa..ad0442c8bd 100644
--- a/src/plugins/platforms/windows/qwindowsole.cpp
+++ b/src/plugins/platforms/windows/qwindowsole.cpp
@@ -41,14 +41,14 @@
#include "qwindowsmime.h"
#include "qwindowscontext.h"
\
-#include <QtGui/QMouseEvent>
-#include <QtGui/QWindow>
-#include <QtGui/QPainter>
-#include <QtGui/QCursor>
-#include <QtGui/QGuiApplication>
+#include <QtGui/qevent.h>
+#include <QtGui/qwindow.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qcursor.h>
+#include <QtGui/qguiapplication.h>
-#include <QtCore/QMimeData>
-#include <QtCore/QDebug>
+#include <QtCore/qmimedata.h>
+#include <QtCore/qdebug.h>
#include <shlobj.h>
@@ -80,9 +80,7 @@ QWindowsOleDataObject::QWindowsOleDataObject(QMimeData *mimeData) :
qCDebug(lcQpaMime) << __FUNCTION__ << mimeData->formats();
}
-QWindowsOleDataObject::~QWindowsOleDataObject()
-{
-}
+QWindowsOleDataObject::~QWindowsOleDataObject() = default;
void QWindowsOleDataObject::releaseQt()
{
@@ -365,10 +363,9 @@ QWindowsOleEnumFmtEtc::Clone(LPENUMFORMATETC FAR* newEnum)
if (result->isNull()) {
delete result;
return ResultFromScode(E_OUTOFMEMORY);
- } else {
- *newEnum = result;
}
+ *newEnum = result;
return NOERROR;
}
diff --git a/src/plugins/platforms/windows/qwindowsole.h b/src/plugins/platforms/windows/qwindowsole.h
index fc58858f2c..6940657e88 100644
--- a/src/plugins/platforms/windows/qwindowsole.h
+++ b/src/plugins/platforms/windows/qwindowsole.h
@@ -43,9 +43,9 @@
#include "qwindowscombase.h"
#include <QtCore/qt_windows.h>
-#include <QtCore/QMap>
-#include <QtCore/QPointer>
-#include <QtCore/QVector>
+#include <QtCore/qmap.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qvector.h>
#include <objidl.h>
@@ -58,7 +58,7 @@ class QWindowsOleDataObject : public QWindowsComBase<IDataObject>
{
public:
explicit QWindowsOleDataObject(QMimeData *mimeData);
- virtual ~QWindowsOleDataObject();
+ ~QWindowsOleDataObject() override;
void releaseQt();
QMimeData *mimeData() const;
@@ -88,7 +88,7 @@ class QWindowsOleEnumFmtEtc : public QWindowsComBase<IEnumFORMATETC>
public:
explicit QWindowsOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs);
explicit QWindowsOleEnumFmtEtc(const QVector<LPFORMATETC> &lpfmtetcs);
- virtual ~QWindowsOleEnumFmtEtc();
+ ~QWindowsOleEnumFmtEtc() override;
bool isNull() const;
diff --git a/src/plugins/platforms/windows/qwindowsopenglcontext.h b/src/plugins/platforms/windows/qwindowsopenglcontext.h
index 85f4f717f5..cc6d93d35e 100644
--- a/src/plugins/platforms/windows/qwindowsopenglcontext.h
+++ b/src/plugins/platforms/windows/qwindowsopenglcontext.h
@@ -40,7 +40,7 @@
#ifndef QWINDOWSOPENGLCONTEXT_H
#define QWINDOWSOPENGLCONTEXT_H
-#include <QtGui/QOpenGLContext>
+#include <QtGui/qopenglcontext.h>
#include <qpa/qplatformopenglcontext.h>
QT_BEGIN_NAMESPACE
@@ -51,9 +51,10 @@ class QWindowsOpenGLContext;
class QWindowsStaticOpenGLContext
{
+ Q_DISABLE_COPY(QWindowsStaticOpenGLContext)
public:
static QWindowsStaticOpenGLContext *create();
- virtual ~QWindowsStaticOpenGLContext() { }
+ virtual ~QWindowsStaticOpenGLContext() = default;
virtual QWindowsOpenGLContext *createContext(QOpenGLContext *context) = 0;
virtual void *moduleHandle() const = 0;
@@ -65,15 +66,17 @@ public:
virtual void *createWindowSurface(void * /*nativeWindow*/, void * /*nativeConfig*/, int * /*err*/) { return 0; }
virtual void destroyWindowSurface(void * /*nativeSurface*/) { }
+protected:
+ QWindowsStaticOpenGLContext() = default;
+
private:
static QWindowsStaticOpenGLContext *doCreate();
};
class QWindowsOpenGLContext : public QPlatformOpenGLContext
{
+ Q_DISABLE_COPY(QWindowsOpenGLContext)
public:
- virtual ~QWindowsOpenGLContext() { }
-
// Returns the native context handle (e.g. HGLRC for WGL, EGLContext for EGL).
virtual void *nativeContext() const = 0;
@@ -81,6 +84,9 @@ public:
// For others, like WGL, they are not relevant.
virtual void *nativeDisplay() const { return 0; }
virtual void *nativeConfig() const { return 0; }
+
+protected:
+ QWindowsOpenGLContext() = default;
};
#endif // QT_NO_OPENGL
diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp
index c52e4e612e..3efccf0f32 100644
--- a/src/plugins/platforms/windows/qwindowsopengltester.cpp
+++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp
@@ -40,15 +40,15 @@
#include "qwindowsopengltester.h"
#include "qwindowscontext.h"
-#include <QtCore/QVariantMap>
-#include <QtCore/QDebug>
-#include <QtCore/QTextStream>
-#include <QtCore/QCoreApplication>
-#include <QtCore/QFile>
-#include <QtCore/QFileInfo>
-#include <QtCore/QStandardPaths>
-#include <QtCore/QLibraryInfo>
-#include <QtCore/QHash>
+#include <QtCore/qvariant.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qtextstream.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qstandardpaths.h>
+#include <QtCore/qlibraryinfo.h>
+#include <QtCore/qhash.h>
#ifndef QT_NO_OPENGL
#include <private/qopengl_p.h>
@@ -60,6 +60,8 @@
QT_BEGIN_NAMESPACE
+static const DWORD VENDOR_ID_AMD = 0x1002;
+
GpuDescription GpuDescription::detect()
{
typedef IDirect3D9 * (WINAPI *PtrDirect3DCreate9)(UINT);
@@ -74,9 +76,16 @@ GpuDescription GpuDescription::detect()
IDirect3D9 *direct3D9 = direct3DCreate9(D3D_SDK_VERSION);
if (!direct3D9)
return result;
+
D3DADAPTER_IDENTIFIER9 adapterIdentifier;
- const HRESULT hr = direct3D9->GetAdapterIdentifier(0, 0, &adapterIdentifier);
- direct3D9->Release();
+ bool isAMD = false;
+ // Adapter "0" is D3DADAPTER_DEFAULT which returns the default adapter. In
+ // multi-GPU, multi-screen setups this is the GPU that is associated with
+ // the "main display" in the Display Settings, and this is the GPU OpenGL
+ // and D3D uses by default. Therefore querying any additional adapters is
+ // futile and not useful for our purposes in general, except for
+ // identifying a few special cases later on.
+ HRESULT hr = direct3D9->GetAdapterIdentifier(0, 0, &adapterIdentifier);
if (SUCCEEDED(hr)) {
result.vendorId = adapterIdentifier.VendorId;
result.deviceId = adapterIdentifier.DeviceId;
@@ -90,7 +99,37 @@ GpuDescription GpuDescription::detect()
result.driverVersion = QVersionNumber(version);
result.driverName = adapterIdentifier.Driver;
result.description = adapterIdentifier.Description;
+ isAMD = result.vendorId == VENDOR_ID_AMD;
+ }
+
+ // Detect QTBUG-50371 (having AMD as the default adapter results in a crash
+ // when starting apps on a screen connected to the Intel card) by looking
+ // for a default AMD adapter and an additional non-AMD one.
+ if (isAMD) {
+ const UINT adapterCount = direct3D9->GetAdapterCount();
+ for (UINT adp = 1; adp < adapterCount; ++adp) {
+ hr = direct3D9->GetAdapterIdentifier(adp, 0, &adapterIdentifier);
+ if (SUCCEEDED(hr)) {
+ if (adapterIdentifier.VendorId != VENDOR_ID_AMD) {
+ // Bingo. Now figure out the display for the AMD card.
+ DISPLAY_DEVICE dd;
+ memset(&dd, 0, sizeof(dd));
+ dd.cb = sizeof(dd);
+ for (int dev = 0; EnumDisplayDevices(nullptr, dev, &dd, 0); ++dev) {
+ if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
+ // DeviceName is something like \\.\DISPLAY1 which can be used to
+ // match with the MONITORINFOEX::szDevice queried by QWindowsScreen.
+ result.gpuSuitableScreen = QString::fromWCharArray(dd.DeviceName);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
}
+
+ direct3D9->Release();
return result;
}
@@ -103,7 +142,8 @@ QDebug operator<<(QDebug d, const GpuDescription &gd)
<< ", deviceId=" << gd.deviceId << ", subSysId=" << gd.subSysId
<< dec << noshowbase << ", revision=" << gd.revision
<< ", driver: " << gd.driverName
- << ", version=" << gd.driverVersion << ", " << gd.description << ')';
+ << ", version=" << gd.driverVersion << ", " << gd.description
+ << gd.gpuSuitableScreen << ')';
return d;
}
#endif // !QT_NO_DEBUG_STREAM
@@ -113,15 +153,17 @@ QString GpuDescription::toString() const
{
QString result;
QTextStream str(&result);
- str << " Card name: " << description
- << "\n Driver Name: " << driverName
- << "\n Driver Version: " << driverVersion.toString()
- << "\n Vendor ID: 0x" << qSetPadChar(QLatin1Char('0'))
+ str << " Card name : " << description
+ << "\n Driver Name : " << driverName
+ << "\n Driver Version : " << driverVersion.toString()
+ << "\n Vendor ID : 0x" << qSetPadChar(QLatin1Char('0'))
<< uppercasedigits << hex << qSetFieldWidth(4) << vendorId
- << "\n Device ID: 0x" << qSetFieldWidth(4) << deviceId
- << "\n SubSys ID: 0x" << qSetFieldWidth(8) << subSysId
- << "\n Revision ID: 0x" << qSetFieldWidth(4) << revision
+ << "\n Device ID : 0x" << qSetFieldWidth(4) << deviceId
+ << "\n SubSys ID : 0x" << qSetFieldWidth(8) << subSysId
+ << "\n Revision ID : 0x" << qSetFieldWidth(4) << revision
<< dec;
+ if (!gpuSuitableScreen.isEmpty())
+ str << "\nGL windows forced to screen: " << gpuSuitableScreen;
return result;
}
@@ -205,11 +247,12 @@ typedef QHash<QOpenGLConfig::Gpu, QWindowsOpenGLTester::Renderers> SupportedRend
Q_GLOBAL_STATIC(SupportedRenderersCache, supportedRenderersCache)
#endif
-QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::detectSupportedRenderers(const GpuDescription &gpu, bool glesOnly)
+QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::detectSupportedRenderers(const GpuDescription &gpu,
+ Renderer requested)
{
- Q_UNUSED(gpu)
- Q_UNUSED(glesOnly)
#if defined(QT_NO_OPENGL)
+ Q_UNUSED(gpu)
+ Q_UNUSED(requested)
return 0;
#else
QOpenGLConfig::Gpu qgpu = QOpenGLConfig::Gpu::fromDevice(gpu.vendorId, gpu.deviceId, gpu.driverVersion, gpu.description);
@@ -223,8 +266,11 @@ QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::detectSupportedRenderers(c
| QWindowsOpenGLTester::AngleRendererD3d11Warp
| QWindowsOpenGLTester::SoftwareRasterizer);
- if (!glesOnly && testDesktopGL())
- result |= QWindowsOpenGLTester::DesktopGl;
+ // 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");
@@ -259,24 +305,20 @@ QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::detectSupportedRenderers(c
qCDebug(lcQpaGl) << "Disabling rotation: " << gpu;
result |= DisableRotationFlag;
}
+ if (features.contains(QStringLiteral("disable_program_cache"))) {
+ qCDebug(lcQpaGl) << "Disabling program cache: " << gpu;
+ result |= DisableProgramCacheFlag;
+ }
srCache->insert(qgpu, result);
return result;
#endif // !QT_NO_OPENGL
}
-QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::supportedGlesRenderers()
-{
- const GpuDescription gpu = GpuDescription::detect();
- const QWindowsOpenGLTester::Renderers result = detectSupportedRenderers(gpu, true);
- qCDebug(lcQpaGl) << __FUNCTION__ << gpu << "renderer: " << result;
- return result;
-}
-
-QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::supportedRenderers()
+QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::supportedRenderers(Renderer requested)
{
const GpuDescription gpu = GpuDescription::detect();
- const QWindowsOpenGLTester::Renderers result = detectSupportedRenderers(gpu, false);
- qCDebug(lcQpaGl) << __FUNCTION__ << gpu << "renderer: " << result;
+ const QWindowsOpenGLTester::Renderers result = detectSupportedRenderers(gpu, requested);
+ qCDebug(lcQpaGl) << __FUNCTION__ << gpu << requested << "renderer: " << result;
return result;
}
diff --git a/src/plugins/platforms/windows/qwindowsopengltester.h b/src/plugins/platforms/windows/qwindowsopengltester.h
index e3fec59dd5..08628c2586 100644
--- a/src/plugins/platforms/windows/qwindowsopengltester.h
+++ b/src/plugins/platforms/windows/qwindowsopengltester.h
@@ -40,8 +40,8 @@
#ifndef QWINDOWSOPENGLTESTER_H
#define QWINDOWSOPENGLTESTER_H
-#include <QtCore/QByteArray>
-#include <QtCore/QFlags>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qflags.h>
#include <QtCore/qversionnumber.h>
QT_BEGIN_NAMESPACE
@@ -62,6 +62,7 @@ struct GpuDescription
QVersionNumber driverVersion;
QByteArray driverName;
QByteArray description;
+ QString gpuSuitableScreen;
};
#ifndef QT_NO_DEBUG_STREAM
@@ -82,18 +83,18 @@ public:
GlesMask = Gles | AngleBackendMask,
SoftwareRasterizer = 0x0020,
RendererMask = 0x00FF,
- DisableRotationFlag = 0x0100
+ DisableRotationFlag = 0x0100,
+ DisableProgramCacheFlag = 0x0200
};
Q_DECLARE_FLAGS(Renderers, Renderer)
static Renderer requestedGlesRenderer();
static Renderer requestedRenderer();
- static Renderers supportedGlesRenderers();
- static Renderers supportedRenderers();
+ static QWindowsOpenGLTester::Renderers supportedRenderers(Renderer requested);
private:
- static QWindowsOpenGLTester::Renderers detectSupportedRenderers(const GpuDescription &gpu, bool glesOnly);
+ static Renderers detectSupportedRenderers(const GpuDescription &gpu, Renderer requested);
static bool testDesktopGL();
};
diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp
new file mode 100644
index 0000000000..c5acc38e7c
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp
@@ -0,0 +1,667 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#if defined(WINVER) && WINVER < 0x0603
+# undef WINVER
+#endif
+#if !defined(WINVER)
+# define WINVER 0x0603 // Enable pointer functions for MinGW
+#endif
+
+#include "qwindowspointerhandler.h"
+#include "qwindowskeymapper.h"
+#include "qwindowscontext.h"
+#include "qwindowswindow.h"
+#include "qwindowsintegration.h"
+#include "qwindowsscreen.h"
+
+#include <qpa/qwindowsysteminterface.h>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qscreen.h>
+#include <QtGui/qtouchdevice.h>
+#include <QtGui/qwindow.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qoperatingsystemversion.h>
+
+#include <algorithm>
+
+#include <windowsx.h>
+
+QT_BEGIN_NAMESPACE
+
+enum {
+ QT_PT_POINTER = 1,
+ QT_PT_TOUCH = 2,
+ QT_PT_PEN = 3,
+ QT_PT_MOUSE = 4,
+ QT_PT_TOUCHPAD = 5, // MinGW is missing PT_TOUCHPAD
+};
+
+bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result)
+{
+ *result = 0;
+ const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam);
+
+ POINTER_INPUT_TYPE pointerType;
+ if (!QWindowsContext::user32dll.getPointerType(pointerId, &pointerType)) {
+ qWarning() << "GetPointerType() failed:" << qt_error_string();
+ return false;
+ }
+
+ switch (pointerType) {
+ case QT_PT_POINTER:
+ case QT_PT_MOUSE:
+ case QT_PT_TOUCHPAD: {
+ POINTER_INFO pointerInfo;
+ if (!QWindowsContext::user32dll.getPointerInfo(pointerId, &pointerInfo)) {
+ qWarning() << "GetPointerInfo() failed:" << qt_error_string();
+ return false;
+ }
+ return translateMouseTouchPadEvent(window, hwnd, et, msg, &pointerInfo);
+ }
+ case QT_PT_TOUCH: {
+ quint32 pointerCount = 0;
+ if (!QWindowsContext::user32dll.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())) {
+ qWarning() << "GetPointerFrameTouchInfo() failed:" << qt_error_string();
+ return false;
+ }
+
+ if (!pointerCount)
+ return false;
+
+ // The history count is the same for all the touchpoints in touchInfo
+ quint32 historyCount = touchInfo[0].pointerInfo.historyCount;
+ // 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())) {
+ qWarning() << "GetPointerFrameTouchInfoHistory() failed:" << qt_error_string();
+ return false;
+ }
+
+ // history frames are returned with the most recent frame first so we iterate backwards
+ bool result = true;
+ for (auto it = touchInfo.rbegin(), end = touchInfo.rend(); it != end; it += pointerCount) {
+ result &= translateTouchEvent(window, hwnd, et, msg,
+ &(*(it + (pointerCount - 1))), pointerCount);
+ }
+ return result;
+ }
+
+ return translateTouchEvent(window, hwnd, et, msg, touchInfo.data(), pointerCount);
+ }
+ case QT_PT_PEN: {
+ POINTER_PEN_INFO penInfo;
+ if (!QWindowsContext::user32dll.getPointerPenInfo(pointerId, &penInfo)) {
+ qWarning() << "GetPointerPenInfo() failed:" << qt_error_string();
+ return false;
+ }
+
+ quint32 historyCount = penInfo.pointerInfo.historyCount;
+ // dispatch any skipped frames if generic or tablet event compression is disabled by the app
+ if (historyCount > 1
+ && (!QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents)
+ || !QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents))) {
+ QVarLengthArray<POINTER_PEN_INFO, 10> penInfoHistory(historyCount);
+
+ if (!QWindowsContext::user32dll.getPointerPenInfoHistory(pointerId,
+ &historyCount,
+ penInfoHistory.data())) {
+ qWarning() << "GetPointerPenInfoHistory() failed:" << qt_error_string();
+ return false;
+ }
+
+ // history frames are returned with the most recent frame first so we iterate backwards
+ bool result = true;
+ for (auto it = penInfoHistory.rbegin(), end = penInfoHistory.rend(); it != end; ++it) {
+ result &= translatePenEvent(window, hwnd, et, msg, &(*(it)));
+ }
+ return result;
+ }
+
+ return translatePenEvent(window, hwnd, et, msg, &penInfo);
+ }
+ }
+ return false;
+}
+
+static void getMouseEventInfo(UINT message, POINTER_BUTTON_CHANGE_TYPE changeType, QPoint globalPos, QEvent::Type *eventType, Qt::MouseButton *mouseButton)
+{
+ static const QHash<POINTER_BUTTON_CHANGE_TYPE, Qt::MouseButton> buttonMapping {
+ {POINTER_CHANGE_FIRSTBUTTON_DOWN, Qt::LeftButton},
+ {POINTER_CHANGE_FIRSTBUTTON_UP, Qt::LeftButton},
+ {POINTER_CHANGE_SECONDBUTTON_DOWN, Qt::RightButton},
+ {POINTER_CHANGE_SECONDBUTTON_UP, Qt::RightButton},
+ {POINTER_CHANGE_THIRDBUTTON_DOWN, Qt::MiddleButton},
+ {POINTER_CHANGE_THIRDBUTTON_UP, Qt::MiddleButton},
+ {POINTER_CHANGE_FOURTHBUTTON_DOWN, Qt::XButton1},
+ {POINTER_CHANGE_FOURTHBUTTON_UP, Qt::XButton1},
+ {POINTER_CHANGE_FIFTHBUTTON_DOWN, Qt::XButton2},
+ {POINTER_CHANGE_FIFTHBUTTON_UP, Qt::XButton2},
+ };
+
+ static const POINTER_BUTTON_CHANGE_TYPE downChanges[] = {
+ POINTER_CHANGE_FIRSTBUTTON_DOWN,
+ POINTER_CHANGE_SECONDBUTTON_DOWN,
+ POINTER_CHANGE_THIRDBUTTON_DOWN,
+ POINTER_CHANGE_FOURTHBUTTON_DOWN,
+ POINTER_CHANGE_FIFTHBUTTON_DOWN,
+ };
+
+ static const POINTER_BUTTON_CHANGE_TYPE upChanges[] = {
+ POINTER_CHANGE_FIRSTBUTTON_UP,
+ POINTER_CHANGE_SECONDBUTTON_UP,
+ POINTER_CHANGE_THIRDBUTTON_UP,
+ POINTER_CHANGE_FOURTHBUTTON_UP,
+ POINTER_CHANGE_FIFTHBUTTON_UP,
+ };
+
+ if (!eventType || !mouseButton)
+ return;
+
+ const bool nonClient = message == WM_NCPOINTERUPDATE ||
+ message == WM_NCPOINTERDOWN ||
+ message == WM_NCPOINTERUP;
+
+ if (std::find(std::begin(downChanges),
+ std::end(downChanges), changeType) < std::end(downChanges)) {
+ *eventType = nonClient ? QEvent::NonClientAreaMouseButtonPress :
+ QEvent::MouseButtonPress;
+ } else if (std::find(std::begin(upChanges),
+ std::end(upChanges), changeType) < std::end(upChanges)) {
+ *eventType = nonClient ? QEvent::NonClientAreaMouseButtonRelease :
+ QEvent::MouseButtonRelease;
+ } else if (message == WM_POINTERWHEEL || message == WM_POINTERHWHEEL) {
+ *eventType = QEvent::Wheel;
+ } else {
+ *eventType = nonClient ? QEvent::NonClientAreaMouseMove :
+ QEvent::MouseMove;
+ }
+
+ *mouseButton = buttonMapping.value(changeType, Qt::NoButton);
+
+ // Pointer messages lack a double click indicator. Check if this is the case here.
+ if (*eventType == QEvent::MouseButtonPress ||
+ *eventType == QEvent::NonClientAreaMouseButtonPress) {
+ static LONG lastTime = 0;
+ static Qt::MouseButton lastButton = Qt::NoButton;
+ static QEvent::Type lastEvent = QEvent::None;
+ static QPoint lastPos;
+ LONG messageTime = GetMessageTime();
+ if (*mouseButton == lastButton
+ && *eventType == lastEvent
+ && messageTime - lastTime < (LONG)GetDoubleClickTime()
+ && qAbs(globalPos.x() - lastPos.x()) < GetSystemMetrics(SM_CXDOUBLECLK)
+ && qAbs(globalPos.y() - lastPos.y()) < GetSystemMetrics(SM_CYDOUBLECLK)) {
+ *eventType = nonClient ? QEvent::NonClientAreaMouseButtonDblClick :
+ QEvent::MouseButtonDblClick;
+ }
+ lastTime = messageTime;
+ lastButton = *mouseButton;
+ lastEvent = *eventType;
+ lastPos = globalPos;
+ }
+}
+
+static QWindow *getWindowUnderPointer(QWindow *window, QPoint globalPos)
+{
+ QWindow *currentWindowUnderPointer = QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT);
+
+ while (currentWindowUnderPointer && currentWindowUnderPointer->flags() & Qt::WindowTransparentForInput)
+ currentWindowUnderPointer = currentWindowUnderPointer->parent();
+
+ // QTBUG-44332: When Qt is running at low integrity level and
+ // a Qt Window is parented on a Window of a higher integrity process
+ // using QWindow::fromWinId() (for example, Qt running in a browser plugin)
+ // ChildWindowFromPointEx() may not find the Qt window (failing with ERROR_ACCESS_DENIED)
+ if (!currentWindowUnderPointer) {
+ const QRect clientRect(QPoint(0, 0), window->size());
+ if (clientRect.contains(globalPos))
+ currentWindowUnderPointer = window;
+ }
+ return currentWindowUnderPointer;
+}
+
+static bool trackLeave(HWND hwnd)
+{
+ TRACKMOUSEEVENT tme;
+ tme.cbSize = sizeof(TRACKMOUSEEVENT);
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = hwnd;
+ tme.dwHoverTime = HOVER_DEFAULT;
+ return TrackMouseEvent(&tme);
+}
+
+static bool isValidWheelReceiver(QWindow *candidate)
+{
+ if (candidate) {
+ const QWindow *toplevel = QWindowsWindow::topLevelOf(candidate);
+ if (toplevel->handle() && toplevel->handle()->isForeignWindow())
+ return true;
+ if (const QWindowsWindow *ww = QWindowsWindow::windowsWindowOf(toplevel))
+ return !ww->testFlag(QWindowsWindow::BlockedByModal);
+ }
+ 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:" << hex << showbase << (digitizers & ~NID_READY)
+ << "Ready:" << (digitizers & NID_READY) << dec << noshowbase
+ << "Tablet PC:" << tabletPc << "Max touch points:" << maxTouchPoints;
+ QTouchDevice *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()
+{
+ if (!m_touchDevice)
+ m_touchDevice = createTouchDevice();
+ return m_touchDevice;
+}
+
+Qt::MouseButtons QWindowsPointerHandler::queryMouseButtons()
+{
+ Qt::MouseButtons result = 0;
+ const bool mouseSwapped = GetSystemMetrics(SM_SWAPBUTTON);
+ if (GetAsyncKeyState(VK_LBUTTON) < 0)
+ result |= mouseSwapped ? Qt::RightButton: Qt::LeftButton;
+ if (GetAsyncKeyState(VK_RBUTTON) < 0)
+ result |= mouseSwapped ? Qt::LeftButton : Qt::RightButton;
+ if (GetAsyncKeyState(VK_MBUTTON) < 0)
+ result |= Qt::MidButton;
+ if (GetAsyncKeyState(VK_XBUTTON1) < 0)
+ result |= Qt::XButton1;
+ if (GetAsyncKeyState(VK_XBUTTON2) < 0)
+ result |= Qt::XButton2;
+ return result;
+}
+
+bool QWindowsPointerHandler::translateMouseTouchPadEvent(QWindow *window, HWND hwnd,
+ QtWindows::WindowsEventType et,
+ MSG msg, PVOID vPointerInfo)
+{
+ POINTER_INFO *pointerInfo = static_cast<POINTER_INFO *>(vPointerInfo);
+ const QPoint globalPos = QPoint(pointerInfo->ptPixelLocation.x, pointerInfo->ptPixelLocation.y);
+ const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos);
+ const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
+ const Qt::MouseButtons mouseButtons = queryMouseButtons();
+
+ QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos);
+ QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window->handle());
+
+ switch (msg.message) {
+ case WM_NCPOINTERDOWN:
+ case WM_NCPOINTERUP:
+ case WM_NCPOINTERUPDATE:
+ case WM_POINTERDOWN:
+ case WM_POINTERUP:
+ case WM_POINTERUPDATE: {
+
+ QEvent::Type eventType;
+ Qt::MouseButton button;
+ getMouseEventInfo(msg.message, pointerInfo->ButtonChangeType, globalPos, &eventType, &button);
+
+ if (et & QtWindows::NonClientEventFlag) {
+ QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, mouseButtons, button, eventType,
+ keyModifiers, Qt::MouseEventNotSynthesized);
+ return false; // To allow window dragging, etc.
+ } else {
+ if (currentWindowUnderPointer != m_windowUnderPointer) {
+ if (m_windowUnderPointer && m_windowUnderPointer == m_currentWindow) {
+ QWindowSystemInterface::handleLeaveEvent(m_windowUnderPointer);
+ m_currentWindow = nullptr;
+ }
+
+ if (currentWindowUnderPointer) {
+ if (currentWindowUnderPointer != m_currentWindow) {
+ QWindowSystemInterface::handleEnterEvent(currentWindowUnderPointer, localPos, globalPos);
+ m_currentWindow = currentWindowUnderPointer;
+ if (QWindowsWindow *wumPlatformWindow = QWindowsWindow::windowsWindowOf(currentWindowUnderPointer))
+ wumPlatformWindow->applyCursor();
+ trackLeave(hwnd);
+ }
+ } else {
+ platformWindow->applyCursor();
+ }
+ m_windowUnderPointer = currentWindowUnderPointer;
+ }
+
+ QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, button, eventType,
+ keyModifiers, Qt::MouseEventNotSynthesized);
+
+ // The initial down click over the QSizeGrip area, which posts a resize WM_SYSCOMMAND
+ // has go to through DefWindowProc() for resizing to work, so we return false here,
+ // unless the mouse is captured, as it would mess with menu processing.
+ return msg.message != WM_POINTERDOWN || GetCapture();
+ }
+ }
+ case WM_POINTERHWHEEL:
+ case WM_POINTERWHEEL: {
+
+ int delta = GET_WHEEL_DELTA_WPARAM(msg.wParam);
+
+ // Qt horizontal wheel rotation orientation is opposite to the one in WM_POINTERHWHEEL
+ if (msg.message == WM_POINTERHWHEEL)
+ delta = -delta;
+
+ const QPoint angleDelta = (msg.message == WM_POINTERHWHEEL || (keyModifiers & Qt::AltModifier)) ?
+ QPoint(delta, 0) : QPoint(0, delta);
+
+ if (isValidWheelReceiver(window))
+ QWindowSystemInterface::handleWheelEvent(window, localPos, globalPos, QPoint(), angleDelta, keyModifiers);
+ return true;
+ }
+ case WM_POINTERLEAVE:
+ return true;
+ }
+ return false;
+}
+
+bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
+ QtWindows::WindowsEventType et,
+ MSG msg, PVOID vTouchInfo, quint32 count)
+{
+ Q_UNUSED(hwnd);
+ Q_UNUSED(et);
+
+ if (et & QtWindows::NonClientEventFlag)
+ return false; // Let DefWindowProc() handle Non Client messages.
+
+ if (count < 1)
+ return false;
+
+ if (msg.message == WM_POINTERCAPTURECHANGED) {
+ QWindowSystemInterface::handleTouchCancelEvent(window, m_touchDevice,
+ QWindowsKeyMapper::queryKeyboardModifiers());
+ m_lastTouchPositions.clear();
+ return true;
+ }
+
+ // Only handle down/up/update, ignore others like WM_POINTERENTER, WM_POINTERLEAVE, etc.
+ if (msg.message > WM_POINTERUP)
+ return false;
+
+ const QScreen *screen = window->screen();
+ if (!screen)
+ screen = QGuiApplication::primaryScreen();
+ if (!screen)
+ return false;
+
+ POINTER_TOUCH_INFO *touchInfo = static_cast<POINTER_TOUCH_INFO *>(vTouchInfo);
+
+ const QRect screenGeometry = screen->geometry();
+
+ QList<QWindowSystemInterface::TouchPoint> touchPoints;
+
+ if (QWindowsContext::verbose > 1)
+ qCDebug(lcQpaEvents).noquote().nospace() << showbase
+ << __FUNCTION__
+ << " message=" << hex << msg.message
+ << " count=" << dec << count;
+
+ for (quint32 i = 0; i < count; ++i) {
+ if (QWindowsContext::verbose > 1)
+ qCDebug(lcQpaEvents).noquote().nospace() << showbase
+ << " TouchPoint id=" << touchInfo[i].pointerInfo.pointerId
+ << " frame=" << touchInfo[i].pointerInfo.frameId
+ << " flags=" << hex << touchInfo[i].pointerInfo.pointerFlags;
+
+ QWindowSystemInterface::TouchPoint touchPoint;
+ touchPoint.id = touchInfo[i].pointerInfo.pointerId;
+ 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);
+
+ const QPointF screenPos = QPointF(touchInfo[i].pointerInfo.ptPixelLocation.x,
+ touchInfo[i].pointerInfo.ptPixelLocation.y);
+
+ if (touchInfo[i].touchMask & TOUCH_MASK_CONTACTAREA)
+ touchPoint.area.setSize(QSizeF(touchInfo[i].rcContact.right - touchInfo[i].rcContact.left,
+ touchInfo[i].rcContact.bottom - touchInfo[i].rcContact.top));
+ touchPoint.area.moveCenter(screenPos);
+ QPointF normalPosition = QPointF(screenPos.x() / screenGeometry.width(),
+ screenPos.y() / screenGeometry.height());
+ const bool stationaryTouchPoint = (normalPosition == touchPoint.normalPosition);
+ touchPoint.normalPosition = normalPosition;
+
+ if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_DOWN) {
+ touchPoint.state = Qt::TouchPointPressed;
+ m_lastTouchPositions.insert(touchPoint.id, touchPoint.normalPosition);
+ } else if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_UP) {
+ touchPoint.state = Qt::TouchPointReleased;
+ m_lastTouchPositions.remove(touchPoint.id);
+ } else {
+ touchPoint.state = stationaryTouchPoint ? Qt::TouchPointStationary : Qt::TouchPointMoved;
+ m_lastTouchPositions.insert(touchPoint.id, touchPoint.normalPosition);
+ }
+ touchPoints.append(touchPoint);
+
+ // Avoid getting repeated messages for this frame if there are multiple pointerIds
+ QWindowsContext::user32dll.skipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId);
+ }
+
+ QWindowSystemInterface::handleTouchEvent(window, m_touchDevice, touchPoints,
+ QWindowsKeyMapper::queryKeyboardModifiers());
+
+ return true;
+}
+
+bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et,
+ MSG msg, PVOID vPenInfo)
+{
+ if (et & QtWindows::NonClientEventFlag)
+ return false; // Let DefWindowProc() handle Non Client messages.
+
+ POINTER_PEN_INFO *penInfo = static_cast<POINTER_PEN_INFO *>(vPenInfo);
+
+ RECT pRect, dRect;
+ if (!QWindowsContext::user32dll.getPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect))
+ return false;
+
+ const quint32 pointerId = penInfo->pointerInfo.pointerId;
+ 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 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 int z = 0;
+
+ if (QWindowsContext::verbose > 1)
+ qCDebug(lcQpaEvents).noquote().nospace() << showbase
+ << __FUNCTION__ << " pointerId=" << pointerId
+ << " globalPos=" << globalPos << " localPos=" << localPos << " hiResGlobalPos=" << hiResGlobalPos
+ << " message=" << hex << msg.message
+ << " flags=" << hex << penInfo->pointerInfo.pointerFlags;
+
+ const QTabletEvent::TabletDevice device = QTabletEvent::Stylus;
+ QTabletEvent::PointerType type;
+ Qt::MouseButtons mouseButtons;
+
+ const bool pointerInContact = IS_POINTER_INCONTACT_WPARAM(msg.wParam);
+ if (pointerInContact)
+ mouseButtons = Qt::LeftButton;
+
+ if (penInfo->penFlags & (PEN_FLAG_ERASER | PEN_FLAG_INVERTED)) {
+ type = QTabletEvent::Eraser;
+ } else {
+ type = QTabletEvent::Pen;
+ if (pointerInContact && penInfo->penFlags & PEN_FLAG_BARREL)
+ mouseButtons = Qt::RightButton; // Either left or right, not both
+ }
+
+ switch (msg.message) {
+ case WM_POINTERENTER: {
+ QWindowSystemInterface::handleTabletEnterProximityEvent(device, type, pointerId);
+ m_windowUnderPointer = window;
+ // The local coordinates may fall outside the window.
+ // Wait until the next update to send the enter event.
+ m_needsEnterOnPointerUpdate = true;
+ break;
+ }
+ case WM_POINTERLEAVE:
+ if (m_windowUnderPointer && m_windowUnderPointer == m_currentWindow) {
+ QWindowSystemInterface::handleLeaveEvent(m_windowUnderPointer);
+ m_windowUnderPointer = nullptr;
+ m_currentWindow = nullptr;
+ }
+ QWindowSystemInterface::handleTabletLeaveProximityEvent(device, type, pointerId);
+ break;
+ case WM_POINTERDOWN:
+ case WM_POINTERUP:
+ case WM_POINTERUPDATE: {
+ QWindow *target = QGuiApplicationPrivate::tabletDevicePoint(pointerId).target; // Pass to window that grabbed it.
+ if (!target && m_windowUnderPointer)
+ target = m_windowUnderPointer;
+ if (!target)
+ target = window;
+
+ if (m_needsEnterOnPointerUpdate) {
+ m_needsEnterOnPointerUpdate = false;
+ if (window != m_currentWindow) {
+ QWindowSystemInterface::handleEnterEvent(window, localPos, globalPos);
+ m_currentWindow = window;
+ if (QWindowsWindow *wumPlatformWindow = QWindowsWindow::windowsWindowOf(target))
+ wumPlatformWindow->applyCursor();
+ }
+ }
+ const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
+
+ QWindowSystemInterface::handleTabletEvent(target, localPos, hiResGlobalPos, device, type, mouseButtons,
+ pressure, xTilt, yTilt, tangentialPressure, rotation, z,
+ pointerId, keyModifiers);
+ break;
+ }
+ }
+ return true;
+}
+
+// SetCursorPos()/TrackMouseEvent() will generate old-style WM_MOUSE messages. Handle them here.
+bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result)
+{
+ Q_UNUSED(et);
+
+ *result = 0;
+ if (msg.message != WM_MOUSELEAVE && msg.message != WM_MOUSEMOVE)
+ return false;
+
+ const QPoint localPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
+ const QPoint globalPos = QWindowsGeometryHint::mapToGlobal(hwnd, localPos);
+
+ QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window->handle());
+
+ if (msg.message == WM_MOUSELEAVE) {
+ if (window == m_currentWindow) {
+ QWindowSystemInterface::handleLeaveEvent(window);
+ m_windowUnderPointer = nullptr;
+ m_currentWindow = nullptr;
+ platformWindow->applyCursor();
+ }
+ return false;
+ }
+
+ // Windows sends a mouse move with no buttons pressed to signal "Enter"
+ // when a window is shown over the cursor. Discard the event and only use
+ // it for generating QEvent::Enter to be consistent with other platforms -
+ // X11 and macOS.
+ static QPoint lastMouseMovePos;
+ const bool discardEvent = msg.wParam == 0 && (m_windowUnderPointer.isNull() || globalPos == lastMouseMovePos);
+ lastMouseMovePos = globalPos;
+
+ QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos);
+
+ if (currentWindowUnderPointer != m_windowUnderPointer) {
+ if (m_windowUnderPointer && m_windowUnderPointer == m_currentWindow) {
+ QWindowSystemInterface::handleLeaveEvent(m_windowUnderPointer);
+ m_currentWindow = nullptr;
+ }
+
+ if (currentWindowUnderPointer) {
+ if (currentWindowUnderPointer != m_currentWindow) {
+ QWindowSystemInterface::handleEnterEvent(currentWindowUnderPointer, localPos, globalPos);
+ m_currentWindow = currentWindowUnderPointer;
+ if (QWindowsWindow *wumPlatformWindow = QWindowsWindow::windowsWindowOf(currentWindowUnderPointer))
+ wumPlatformWindow->applyCursor();
+ trackLeave(hwnd);
+ }
+ } else {
+ platformWindow->applyCursor();
+ }
+ m_windowUnderPointer = currentWindowUnderPointer;
+ }
+
+ const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
+ const Qt::MouseButtons mouseButtons = queryMouseButtons();
+
+ if (!discardEvent)
+ QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, Qt::NoButton, QEvent::MouseMove,
+ keyModifiers, Qt::MouseEventNotSynthesized);
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.h b/src/plugins/platforms/windows/qwindowspointerhandler.h
new file mode 100644
index 0000000000..c4d0e0ce4a
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowspointerhandler.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** 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 QWINDOWSPOINTERHANDLER_H
+#define QWINDOWSPOINTERHANDLER_H
+
+#include "qtwindowsglobal.h"
+#include <QtCore/qt_windows.h>
+
+#include <QtCore/qpointer.h>
+#include <QtCore/qscopedpointer.h>
+#include <QtCore/qhash.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWindow;
+class QTouchDevice;
+
+class QWindowsPointerHandler
+{
+ Q_DISABLE_COPY(QWindowsPointerHandler)
+public:
+ QWindowsPointerHandler() = default;
+ 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();
+ Qt::MouseButtons queryMouseButtons();
+ QWindow *windowUnderMouse() const { return m_windowUnderPointer.data(); }
+ void clearWindowUnderMouse() { m_windowUnderPointer = nullptr; }
+
+private:
+ bool translateMouseTouchPadEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vPointerInfo);
+ bool translateTouchEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vTouchInfo, unsigned int count);
+ bool translatePenEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vPenInfo);
+
+ QTouchDevice *m_touchDevice = nullptr;
+ QHash<int, QPointF> m_lastTouchPositions;
+ QPointer<QWindow> m_windowUnderPointer;
+ QPointer<QWindow> m_currentWindow;
+ bool m_needsEnterOnPointerUpdate = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSPOINTERHANDLER_H
diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp
index d56dc870ea..2eaf386d42 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.cpp
+++ b/src/plugins/platforms/windows/qwindowsscreen.cpp
@@ -45,14 +45,14 @@
#include <QtCore/qt_windows.h>
-#include <QtCore/QSettings>
-#include <QtGui/QPixmap>
-#include <QtGui/QGuiApplication>
+#include <QtCore/qsettings.h>
+#include <QtGui/qpixmap.h>
+#include <QtGui/qguiapplication.h>
#include <qpa/qwindowsysteminterface.h>
#include <private/qhighdpiscaling_p.h>
-#include <QtGui/QScreen>
+#include <QtGui/qscreen.h>
-#include <QtCore/QDebug>
+#include <QtCore/qdebug.h>
QT_BEGIN_NAMESPACE
@@ -69,7 +69,7 @@ static inline QDpi monitorDPI(HMONITOR hMonitor)
if (SUCCEEDED(QWindowsContext::shcoredll.getDpiForMonitor(hMonitor, 0, &dpiX, &dpiY)))
return QDpi(dpiX, dpiY);
}
- return QDpi(0, 0);
+ return {0, 0};
}
typedef QList<QWindowsScreenData> WindowsScreenDataList;
@@ -274,9 +274,12 @@ QList<QPlatformScreen *> QWindowsScreen::virtualSiblings() const
{
QList<QPlatformScreen *> result;
if (m_data.flags & QWindowsScreenData::VirtualDesktop) {
- foreach (QWindowsScreen *screen, QWindowsContext::instance()->screenManager().screens())
+ const QWindowsScreenManager::WindowsScreenList screens
+ = QWindowsContext::instance()->screenManager().screens();
+ for (QWindowsScreen *screen : screens) {
if (screen->data().flags & QWindowsScreenData::VirtualDesktop)
result.push_back(screen);
+ }
} else {
result.push_back(const_cast<QWindowsScreen *>(this));
}
@@ -327,10 +330,7 @@ QRect QWindowsScreen::virtualGeometry(const QPlatformScreen *screen) // cf QScre
return result;
}
-enum OrientationPreference // matching Win32 API ORIENTATION_PREFERENCE
-#if defined(Q_COMPILER_CLASS_ENUM) || defined(Q_CC_MSVC)
- : DWORD
-#endif
+enum OrientationPreference : DWORD // matching Win32 API ORIENTATION_PREFERENCE
{
orientationPreferenceNone = 0,
orientationPreferenceLandscape = 0x1,
@@ -398,7 +398,8 @@ QPlatformScreen::SubpixelAntialiasingType QWindowsScreen::subpixelAntialiasingTy
{
QPlatformScreen::SubpixelAntialiasingType type = QPlatformScreen::subpixelAntialiasingTypeHint();
if (type == QPlatformScreen::Subpixel_None) {
- QSettings settings(QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Avalon.Graphics\\DISPLAY1"), QSettings::NativeFormat);
+ QSettings settings(QLatin1String(R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Avalon.Graphics\DISPLAY1)"),
+ QSettings::NativeFormat);
int registryValue = settings.value(QLatin1String("PixelStructure"), -1).toInt();
switch (registryValue) {
case 0:
@@ -505,7 +506,8 @@ void QWindowsScreenManager::removeScreen(int index)
// move those manually.
if (screen != primaryScreen) {
unsigned movedWindowCount = 0;
- foreach (QWindow *w, QGuiApplication::topLevelWindows()) {
+ const QWindowList tlws = QGuiApplication::topLevelWindows();
+ for (QWindow *w : tlws) {
if (w->screen() == screen && w->handle() && w->type() != Qt::Desktop) {
if (w->isVisible() && w->windowState() != Qt::WindowMinimized
&& (QWindowsWindow::baseWindowOf(w)->exStyle() & WS_EX_TOOLWINDOW)) {
@@ -530,9 +532,9 @@ void QWindowsScreenManager::removeScreen(int index)
bool QWindowsScreenManager::handleScreenChanges()
{
// Look for changed monitors, add new ones
- WindowsScreenDataList newDataList = monitorData();
+ const WindowsScreenDataList newDataList = monitorData();
const bool lockScreen = newDataList.size() == 1 && (newDataList.front().flags & QWindowsScreenData::LockScreen);
- foreach (const QWindowsScreenData &newData, newDataList) {
+ for (const QWindowsScreenData &newData : newDataList) {
const int existingIndex = indexOfMonitor(m_screens, newData.name);
if (existingIndex != -1) {
m_screens.at(existingIndex)->handleChanges(newData);
@@ -564,7 +566,7 @@ void QWindowsScreenManager::clearScreens()
const QWindowsScreen *QWindowsScreenManager::screenAtDp(const QPoint &p) const
{
- foreach (QWindowsScreen *scr, m_screens) {
+ for (QWindowsScreen *scr : m_screens) {
if (scr->geometry().contains(p))
return scr;
}
diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h
index 5753e605da..824bcb1ad6 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.h
+++ b/src/plugins/platforms/windows/qwindowsscreen.h
@@ -42,10 +42,10 @@
#include "qtwindowsglobal.h"
-#include <QtCore/QList>
-#include <QtCore/QVector>
-#include <QtCore/QPair>
-#include <QtCore/QScopedPointer>
+#include <QtCore/qlist.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qscopedpointer.h>
#include <qpa/qplatformscreen.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsservices.cpp b/src/plugins/platforms/windows/qwindowsservices.cpp
index 48332b35f8..b6ed27464e 100644
--- a/src/plugins/platforms/windows/qwindowsservices.cpp
+++ b/src/plugins/platforms/windows/qwindowsservices.cpp
@@ -41,9 +41,9 @@
#include "qwindowsservices.h"
#include <QtCore/qt_windows.h>
-#include <QtCore/QUrl>
-#include <QtCore/QDebug>
-#include <QtCore/QDir>
+#include <QtCore/qurl.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qdir.h>
#include <shlobj.h>
#include <intshcut.h>
diff --git a/src/plugins/platforms/windows/qwindowsservices.h b/src/plugins/platforms/windows/qwindowsservices.h
index 7518a52755..5feb7c8490 100644
--- a/src/plugins/platforms/windows/qwindowsservices.h
+++ b/src/plugins/platforms/windows/qwindowsservices.h
@@ -47,8 +47,8 @@ QT_BEGIN_NAMESPACE
class QWindowsServices : public QPlatformServices
{
public:
- bool openUrl(const QUrl &url);
- bool openDocument(const QUrl &url);
+ bool openUrl(const QUrl &url) override;
+ bool openDocument(const QUrl &url) override;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.h b/src/plugins/platforms/windows/qwindowssystemtrayicon.h
index 1f696180cd..a8adb9641f 100644
--- a/src/plugins/platforms/windows/qwindowssystemtrayicon.h
+++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.h
@@ -57,7 +57,7 @@ class QWindowsSystemTrayIcon : public QPlatformSystemTrayIcon
{
public:
QWindowsSystemTrayIcon();
- ~QWindowsSystemTrayIcon();
+ ~QWindowsSystemTrayIcon() override;
void init() override;
void cleanup() override;
diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp
index 6acb62ad8f..fa209f09c4 100644
--- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp
+++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp
@@ -46,13 +46,13 @@
#include <qpa/qwindowsysteminterface.h>
-#include <QtGui/QTabletEvent>
-#include <QtGui/QScreen>
-#include <QtGui/QGuiApplication>
-#include <QtGui/QWindow>
-#include <QtCore/QDebug>
-#include <QtCore/QVarLengthArray>
-#include <QtCore/QtMath>
+#include <QtGui/qevent.h>
+#include <QtGui/qscreen.h>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qwindow.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qmath.h>
#include <private/qguiapplication_p.h>
#include <QtCore/private/qsystemlibrary_p.h>
@@ -108,7 +108,7 @@ inline QPointF QWindowsTabletDeviceData::scaleCoordinates(int coordX, int coordY
((coordY - minY) * qAbs(targetHeight) / qAbs(qreal(maxY - minY))) + targetY :
((qAbs(maxY) - (coordY - minY)) * qAbs(targetHeight) / qAbs(qreal(maxY - minY))) + targetY;
- return QPointF(x, y);
+ return {x, y};
}
template <class Stream>
@@ -135,9 +135,9 @@ QDebug operator<<(QDebug d, const QWindowsTabletDeviceData &t)
d.nospace();
d << "TabletDevice id:" << t.uniqueId << " 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.maxTanPressure << " area: (" << t.minX << ',' << t.minY << ',' << t.minZ
+ << ")..(" << t.maxX << ',' << t.maxY << ',' << t.maxZ << ") device "
+ << t.currentDevice << " pointer " << t.currentPointerType;
return d;
}
@@ -211,9 +211,6 @@ bool QWindowsWinTab32DLL::init()
QWindowsTabletSupport::QWindowsTabletSupport(HWND window, HCTX context)
: m_window(window)
, m_context(context)
- , m_absoluteRange(20)
- , m_tiltSupport(false)
- , m_currentDevice(-1)
{
AXIS orientation[3];
// Some tablets don't support tilt, check if it is possible,
@@ -230,13 +227,13 @@ QWindowsTabletSupport::~QWindowsTabletSupport()
QWindowsTabletSupport *QWindowsTabletSupport::create()
{
if (!m_winTab32DLL.init())
- return 0;
+ return nullptr;
const HWND window = QWindowsContext::instance()->createDummyWindow(QStringLiteral("TabletDummyWindow"),
L"TabletDummyWindow",
qWindowsTabletSupportWndProc);
if (!window) {
qCWarning(lcQpaTablet) << __FUNCTION__ << "Unable to create window for tablet.";
- return 0;
+ return nullptr;
}
LOGCONTEXT lcMine;
// build our context from the default context
@@ -255,7 +252,7 @@ QWindowsTabletSupport *QWindowsTabletSupport::create()
if (!context) {
qCDebug(lcQpaTablet) << __FUNCTION__ << "Unable to open tablet.";
DestroyWindow(window);
- return 0;
+ return nullptr;
}
// Set the size of the Packet Queue to the correct size
@@ -266,7 +263,7 @@ QWindowsTabletSupport *QWindowsTabletSupport::create()
qWarning("Unable to set queue size on tablet. The tablet will not work.");
QWindowsTabletSupport::m_winTab32DLL.wTClose(context);
DestroyWindow(window);
- return 0;
+ return nullptr;
} // cannot restore old size
} // cannot set
} // mismatch
@@ -285,7 +282,7 @@ unsigned QWindowsTabletSupport::options() const
QString QWindowsTabletSupport::description() const
{
- const unsigned size = m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_WINTABID, 0);
+ const unsigned size = m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_WINTABID, nullptr);
if (!size)
return QString();
QVarLengthArray<TCHAR> winTabId(size + 1);
diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.h b/src/plugins/platforms/windows/qwindowstabletsupport.h
index 9379dd72d6..d91701d6a5 100644
--- a/src/plugins/platforms/windows/qwindowstabletsupport.h
+++ b/src/plugins/platforms/windows/qwindowstabletsupport.h
@@ -43,8 +43,8 @@
#include "qtwindowsglobal.h"
#include <QtGui/qtguiglobal.h>
-#include <QtCore/QVector>
-#include <QtCore/QPointF>
+#include <QtCore/qvector.h>
+#include <QtCore/qpoint.h>
#include <wintab.h>
@@ -83,22 +83,23 @@ struct QWindowsWinTab32DLL
struct QWindowsTabletDeviceData
{
- QWindowsTabletDeviceData() : minPressure(0), maxPressure(0), minTanPressure(0),
- maxTanPressure(0), minX(0), maxX(0), minY(0), maxY(0), minZ(0), maxZ(0),
- uniqueId(0), currentDevice(0), currentPointerType(0) {}
-
QPointF scaleCoordinates(int coordX, int coordY,const QRect &targetArea) const;
qreal scalePressure(qreal p) const { return p / qreal(maxPressure - minPressure); }
qreal scaleTangentialPressure(qreal p) const { return p / qreal(maxTanPressure - minTanPressure); }
- int minPressure;
- int maxPressure;
- int minTanPressure;
- int maxTanPressure;
- int minX, maxX, minY, maxY, minZ, maxZ;
- qint64 uniqueId;
- int currentDevice;
- int currentPointerType;
+ int minPressure = 0;
+ int maxPressure = 0;
+ int minTanPressure = 0;
+ int maxTanPressure = 0;
+ int minX = 0;
+ int maxX = 0;
+ int minY = 0;
+ int maxY = 0;
+ int minZ = 0;
+ int maxZ = 0;
+ qint64 uniqueId = 0;
+ int currentDevice = 0;
+ int currentPointerType = 0;
};
#ifndef QT_NO_DEBUG_STREAM
@@ -145,10 +146,10 @@ private:
static QWindowsWinTab32DLL m_winTab32DLL;
const HWND m_window;
const HCTX m_context;
- int m_absoluteRange;
- bool m_tiltSupport;
+ int m_absoluteRange = 20;
+ bool m_tiltSupport = false;
QVector<QWindowsTabletDeviceData> m_devices;
- int m_currentDevice;
+ int m_currentDevice = -1;
Mode m_mode = PenMode;
State m_state = PenUp;
};
diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp
index 651c661d6b..d01a7b0a8a 100644
--- a/src/plugins/platforms/windows/qwindowstheme.cpp
+++ b/src/plugins/platforms/windows/qwindowstheme.cpp
@@ -59,20 +59,20 @@
#endif
#include <shellapi.h>
-#include <QtCore/QVariant>
-#include <QtCore/QCoreApplication>
-#include <QtCore/QDebug>
-#include <QtCore/QTextStream>
-#include <QtCore/QSysInfo>
-#include <QtCore/QCache>
-#include <QtCore/QThread>
-#include <QtCore/QMutex>
-#include <QtCore/QWaitCondition>
-#include <QtGui/QColor>
-#include <QtGui/QPalette>
-#include <QtGui/QGuiApplication>
-#include <QtGui/QPainter>
-#include <QtGui/QPixmapCache>
+#include <QtCore/qvariant.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qtextstream.h>
+#include <QtCore/qsysinfo.h>
+#include <QtCore/qcache.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qwaitcondition.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>
@@ -107,7 +107,7 @@ static inline bool booleanSystemParametersInfo(UINT what, bool defaultValue)
{
BOOL result;
if (SystemParametersInfo(what, 0, &result, 0))
- return result ? true : false;
+ return result != FALSE;
return defaultValue;
}
@@ -121,9 +121,9 @@ static inline DWORD dWordSystemParametersInfo(UINT what, DWORD defaultValue)
static inline QColor mixColors(const QColor &c1, const QColor &c2)
{
- return QColor ((c1.red() + c2.red()) / 2,
- (c1.green() + c2.green()) / 2,
- (c1.blue() + c2.blue()) / 2);
+ return {(c1.red() + c2.red()) / 2,
+ (c1.green() + c2.green()) / 2,
+ (c1.blue() + c2.blue()) / 2};
}
static inline QColor getSysColor(int index)
diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h
index 237e8158fa..c132f20167 100644
--- a/src/plugins/platforms/windows/qwindowstheme.h
+++ b/src/plugins/platforms/windows/qwindowstheme.h
@@ -42,8 +42,8 @@
#include <qpa/qplatformtheme.h>
-#include <QtCore/QSharedPointer>
-#include <QtCore/QVariant>
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/qvariant.h>
QT_BEGIN_NAMESPACE
@@ -51,9 +51,10 @@ class QWindow;
class QWindowsTheme : public QPlatformTheme
{
+ Q_DISABLE_COPY(QWindowsTheme)
public:
QWindowsTheme();
- ~QWindowsTheme();
+ ~QWindowsTheme() override;
static QWindowsTheme *instance() { return m_instance; }
diff --git a/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h b/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h
index 5601cc9305..731e4b5432 100644
--- a/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h
+++ b/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h
@@ -40,10 +40,10 @@
#ifndef QWINDOWSTHREADPOOLRUNNER_H
#define QWINDOWSTHREADPOOLRUNNER_H
-#include <QtCore/QMutex>
-#include <QtCore/QRunnable>
-#include <QtCore/QThreadPool>
-#include <QtCore/QWaitCondition>
+#include <QtCore/qmutex.h>
+#include <QtCore/qrunnable.h>
+#include <QtCore/qthreadpool.h>
+#include <QtCore/qwaitcondition.h>
QT_BEGIN_NAMESPACE
@@ -61,7 +61,7 @@ class QWindowsThreadPoolRunner
{
Q_DISABLE_COPY(QWindowsThreadPoolRunner)
-#ifndef QT_NO_THREAD
+#if QT_CONFIG(thread)
template <class RunnableFunction> // nested class implementing QRunnable to execute a function.
class Runnable : public QRunnable
{
@@ -104,7 +104,7 @@ public:
private:
QMutex m_mutex;
QWaitCondition m_condition;
-#else // !QT_NO_THREAD
+#else // QT_CONFIG(thread)
public:
QWindowsThreadPoolRunner() {}
@@ -114,7 +114,7 @@ public:
f();
return true;
}
-#endif // QT_NO_THREAD
+#endif // QT_CONFIG(thread)
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsvulkaninstance.cpp b/src/plugins/platforms/windows/qwindowsvulkaninstance.cpp
index d81ee8ba29..7a01483abd 100644
--- a/src/plugins/platforms/windows/qwindowsvulkaninstance.cpp
+++ b/src/plugins/platforms/windows/qwindowsvulkaninstance.cpp
@@ -44,20 +44,9 @@ QT_BEGIN_NAMESPACE
QWindowsVulkanInstance::QWindowsVulkanInstance(QVulkanInstance *instance)
: m_instance(instance),
m_getPhysDevPresSupport(nullptr),
- m_createSurface(nullptr),
- m_destroySurface(nullptr)
+ m_createSurface(nullptr)
{
- if (qEnvironmentVariableIsSet("QT_VULKAN_LIB"))
- m_lib.setFileName(QString::fromUtf8(qgetenv("QT_VULKAN_LIB")));
- else
- m_lib.setFileName(QStringLiteral("vulkan-1"));
-
- if (!m_lib.load()) {
- qWarning("Failed to load %s: %s", qPrintable(m_lib.fileName()), qPrintable(m_lib.errorString()));
- return;
- }
-
- init(&m_lib);
+ loadVulkanLibrary(QStringLiteral("vulkan-1"));
}
void QWindowsVulkanInstance::createOrAdoptInstance()
@@ -73,10 +62,6 @@ void QWindowsVulkanInstance::createOrAdoptInstance()
qWarning("Failed to find vkGetPhysicalDeviceWin32PresentationSupportKHR");
}
-QWindowsVulkanInstance::~QWindowsVulkanInstance()
-{
-}
-
bool QWindowsVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice,
uint32_t queueFamilyIndex,
QWindow *window)
@@ -106,14 +91,6 @@ VkSurfaceKHR QWindowsVulkanInstance::createSurface(HWND win)
qWarning("Failed to find vkCreateWin32SurfaceKHR");
return surface;
}
- if (!m_destroySurface) {
- m_destroySurface = reinterpret_cast<PFN_vkDestroySurfaceKHR>(
- m_vkGetInstanceProcAddr(m_vkInst, "vkDestroySurfaceKHR"));
- }
- if (!m_destroySurface) {
- qWarning("Failed to find vkDestroySurfaceKHR");
- return surface;
- }
VkWin32SurfaceCreateInfoKHR surfaceInfo;
memset(&surfaceInfo, 0, sizeof(surfaceInfo));
@@ -127,10 +104,4 @@ VkSurfaceKHR QWindowsVulkanInstance::createSurface(HWND win)
return surface;
}
-void QWindowsVulkanInstance::destroySurface(VkSurfaceKHR surface)
-{
- if (m_destroySurface && surface)
- m_destroySurface(m_vkInst, surface, nullptr);
-}
-
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsvulkaninstance.h b/src/plugins/platforms/windows/qwindowsvulkaninstance.h
index ca60ab7627..3292137c39 100644
--- a/src/plugins/platforms/windows/qwindowsvulkaninstance.h
+++ b/src/plugins/platforms/windows/qwindowsvulkaninstance.h
@@ -47,28 +47,25 @@
#define VK_USE_PLATFORM_WIN32_KHR
#include <QtVulkanSupport/private/qbasicvulkanplatforminstance_p.h>
-#include <QLibrary>
+#include <QtCore/qlibrary.h>
QT_BEGIN_NAMESPACE
class QWindowsVulkanInstance : public QBasicPlatformVulkanInstance
{
+ Q_DISABLE_COPY(QWindowsVulkanInstance)
public:
QWindowsVulkanInstance(QVulkanInstance *instance);
- ~QWindowsVulkanInstance();
void createOrAdoptInstance() override;
bool supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window) override;
VkSurfaceKHR createSurface(HWND win);
- void destroySurface(VkSurfaceKHR surface);
private:
QVulkanInstance *m_instance;
- QLibrary m_lib;
PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR m_getPhysDevPresSupport;
PFN_vkCreateWin32SurfaceKHR m_createSurface;
- PFN_vkDestroySurfaceKHR m_destroySurface;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index ca87f1b6a4..9c31409644 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -58,23 +58,25 @@
#else
# include "qwindowsopenglcontext.h"
#endif
+#include "qwindowsopengltester.h"
#ifdef QT_NO_CURSOR
# include "qwindowscursor.h"
#endif
-#include <QtGui/QGuiApplication>
-#include <QtGui/QScreen>
-#include <QtGui/QWindow>
-#include <QtGui/QRegion>
-#include <QtGui/QOpenGLContext>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qscreen.h>
+#include <QtGui/qwindow.h>
+#include <QtGui/qregion.h>
+#include <QtGui/qopenglcontext.h>
#include <private/qsystemlibrary_p.h>
#include <private/qwindow_p.h> // QWINDOWSIZE_MAX
#include <private/qguiapplication_p.h>
#include <private/qhighdpiscaling_p.h>
#include <qpa/qwindowsysteminterface.h>
-#include <QtCore/QDebug>
-#include <QtCore/QLibraryInfo>
+#include <QtCore/qdebug.h>
+#include <QtCore/qlibraryinfo.h>
+#include <QtCore/qoperatingsystemversion.h>
#include <dwmapi.h>
@@ -422,6 +424,31 @@ static inline void updateGLWindowSettings(const QWindow *w, HWND hwnd, Qt::Windo
}
/*!
+ 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.
+*/
+
+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);
+ }
+ }
+ }
+ }
+ return QMargins();
+}
+
+/*!
\class WindowCreationData
\brief Window creation code.
@@ -515,6 +542,84 @@ static inline void fixTopLevelWindowFlags(Qt::WindowFlags &flags)
flags |= Qt::FramelessWindowHint;
}
+static QScreen *screenForName(const QWindow *w, const QString &name)
+{
+ QScreen *winScreen = w ? w->screen() : QGuiApplication::primaryScreen();
+ if (winScreen && winScreen->name() != name) {
+ const auto screens = winScreen->virtualSiblings();
+ for (QScreen *screen : screens) {
+ if (screen->name() == name)
+ return screen;
+ }
+ }
+ return winScreen;
+}
+
+static QScreen *forcedScreenForGLWindow(const QWindow *w)
+{
+ const QString forceToScreen = GpuDescription::detect().gpuSuitableScreen;
+ return forceToScreen.isEmpty() ? nullptr : screenForName(w, forceToScreen);
+}
+
+static QPoint calcPosition(const QWindow *w, const QWindowCreationContextPtr &context, const QMargins &invMargins)
+{
+ const QPoint orgPos(context->frameX - invMargins.left(), context->frameY - invMargins.top());
+
+ if (!w || (!w->isTopLevel() && w->surfaceType() != QWindow::OpenGLSurface))
+ return orgPos;
+
+ // Workaround for QTBUG-50371
+ const QScreen *screenForGL = forcedScreenForGLWindow(w);
+ if (!screenForGL)
+ return orgPos;
+
+ const QPoint posFrame(context->frameX, context->frameY);
+ const QMargins margins = context->margins;
+ const QRect scrGeo = screenForGL->handle()->availableGeometry();
+
+ // Point is already in the required screen.
+ if (scrGeo.contains(orgPos))
+ return orgPos;
+
+ // If the visible part of the window is already in the
+ // required screen, just ignore the invisible offset.
+ if (scrGeo.contains(posFrame))
+ return posFrame;
+
+ // Find the original screen containing the coordinates.
+ const QList<QScreen *> screens = screenForGL->virtualSiblings();
+ const QScreen *orgScreen = nullptr;
+ for (QScreen *screen : screens) {
+ if (screen->handle()->availableGeometry().contains(posFrame)) {
+ orgScreen = screen;
+ break;
+ }
+ }
+ const QPoint ctPos = QPoint(qMax(scrGeo.left(), scrGeo.center().x()
+ + (margins.right() - margins.left() - context->frameWidth)/2),
+ qMax(scrGeo.top(), scrGeo.center().y()
+ + (margins.bottom() - margins.top() - context->frameHeight)/2));
+
+ // If initial coordinates were outside all screens, center the window on the required screen.
+ if (!orgScreen)
+ return ctPos;
+
+ const QRect orgGeo = orgScreen->handle()->availableGeometry();
+ const QRect orgFrame(QPoint(context->frameX, context->frameY),
+ QSize(context->frameWidth, context->frameHeight));
+
+ // Window would be centered on orgScreen. Center it on the required screen.
+ if (orgGeo.center() == (orgFrame - margins).center())
+ return ctPos;
+
+ // Transform the coordinates to map them into the required screen.
+ const QPoint newPos(scrGeo.left() + ((posFrame.x() - orgGeo.left()) * scrGeo.width()) / orgGeo.width(),
+ scrGeo.top() + ((posFrame.y() - orgGeo.top()) * scrGeo.height()) / orgGeo.height());
+ const QPoint newPosNoMargin(newPos.x() - invMargins.left(), newPos.y() - invMargins.top());
+
+ return scrGeo.contains(newPosNoMargin) ? newPosNoMargin : newPos;
+}
+
void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flagsIn,
unsigned creationFlags)
{
@@ -634,7 +739,7 @@ QWindowsWindowData
WindowData result;
result.flags = flags;
- const HINSTANCE appinst = (HINSTANCE)GetModuleHandle(0);
+ const auto appinst = reinterpret_cast<HINSTANCE>(GetModuleHandle(nullptr));
const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w);
@@ -651,16 +756,23 @@ QWindowsWindowData
const QWindowCreationContextPtr context(new QWindowCreationContext(w, data.geometry, rect, data.customMargins, style, exStyle));
QWindowsContext::instance()->setWindowCreationContext(context);
+ QMargins invMargins = topLevel && !(result.flags & Qt::FramelessWindowHint) && QWindowsGeometryHint::positionIncludesFrame(w)
+ ? invisibleMargins(QPoint(context->frameX, context->frameY)) : QMargins();
+
qCDebug(lcQpaWindows).nospace()
<< "CreateWindowEx: " << w << " class=" << windowClassName << " title=" << title
<< '\n' << *this << "\nrequested: " << rect << ": "
<< context->frameWidth << 'x' << context->frameHeight
<< '+' << context->frameX << '+' << context->frameY
- << " custom margins: " << context->customMargins;
+ << " custom margins: " << context->customMargins
+ << " invisible margins: " << invMargins;
+
+
+ QPoint pos = calcPosition(w, context, invMargins);
result.hwnd = CreateWindowEx(exStyle, classNameUtf16, titleUtf16,
style,
- context->frameX, context->frameY,
+ pos.x(), pos.y(),
context->frameWidth, context->frameHeight,
parentHandle, NULL, appinst, NULL);
qCDebug(lcQpaWindows).nospace()
@@ -673,7 +785,7 @@ QWindowsWindowData
}
result.geometry = context->obtainedGeometry;
- result.frame = context->margins;
+ result.fullFrameMargins = context->margins;
result.embedded = embedded;
result.customMargins = context->customMargins;
@@ -887,7 +999,7 @@ QRect QWindowsBaseWindow::frameGeometry_sys() const
QRect QWindowsBaseWindow::geometry_sys() const
{
- return frameGeometry_sys().marginsRemoved(frameMargins());
+ return frameGeometry_sys().marginsRemoved(fullFrameMargins());
}
QMargins QWindowsBaseWindow::frameMargins_sys() const
@@ -1344,28 +1456,12 @@ bool QWindowsWindow::isEmbedded() const
QPoint QWindowsWindow::mapToGlobal(const QPoint &pos) const
{
- if (m_data.hwnd)
- return QWindowsGeometryHint::mapToGlobal(m_data.hwnd, pos);
- else
- return pos;
+ return m_data.hwnd ? QWindowsGeometryHint::mapToGlobal(m_data.hwnd, pos) : pos;
}
QPoint QWindowsWindow::mapFromGlobal(const QPoint &pos) const
{
- if (m_data.hwnd)
- return QWindowsGeometryHint::mapFromGlobal(m_data.hwnd, pos);
- else
- return pos;
-}
-
-static inline HWND transientParentHwnd(HWND hwnd)
-{
- if (GetAncestor(hwnd, GA_PARENT) == GetDesktopWindow()) {
- const HWND rootOwnerHwnd = GetAncestor(hwnd, GA_ROOTOWNER);
- if (rootOwnerHwnd != hwnd) // May return itself for toplevels.
- return rootOwnerHwnd;
- }
- return 0;
+ return m_data.hwnd ? QWindowsGeometryHint::mapFromGlobal(m_data.hwnd, pos) : pos;
}
// Update the transient parent for a toplevel window. The concept does not
@@ -1382,7 +1478,7 @@ void QWindowsWindow::updateTransientParent() const
if (window()->type() == Qt::Popup)
return; // QTBUG-34503, // a popup stays on top, no parent, see also WindowCreationData::fromWindow().
// Update transient parent.
- const HWND oldTransientParent = transientParentHwnd(m_data.hwnd);
+ const HWND oldTransientParent = GetWindow(m_data.hwnd, GW_OWNER);
HWND newTransientParent = 0;
if (const QWindow *tp = window()->transientParent())
if (const QWindowsWindow *tw = QWindowsWindow::windowsWindowOf(tp))
@@ -1560,7 +1656,7 @@ QRect QWindowsWindow::normalGeometry() const
const bool fakeFullScreen =
m_savedFrameGeometry.isValid() && (window()->windowStates() & Qt::WindowFullScreen);
const QRect frame = fakeFullScreen ? m_savedFrameGeometry : normalFrameGeometry(m_data.hwnd);
- const QMargins margins = fakeFullScreen ? QWindowsGeometryHint::frame(m_savedStyle, 0) : frameMargins();
+ const QMargins margins = fakeFullScreen ? QWindowsGeometryHint::frame(m_savedStyle, 0) : fullFrameMargins();
return frame.isValid() ? frame.marginsRemoved(margins) : frame;
}
@@ -1592,8 +1688,8 @@ void QWindowsWindow::setGeometry(const QRect &rectIn)
window()->metaObject()->className(), qPrintable(window()->objectName()),
m_data.geometry.width(), m_data.geometry.height(),
m_data.geometry.x(), m_data.geometry.y(),
- m_data.frame.left(), m_data.frame.top(),
- m_data.frame.right(), m_data.frame.bottom(),
+ m_data.fullFrameMargins.left(), m_data.fullFrameMargins.top(),
+ m_data.fullFrameMargins.right(), m_data.fullFrameMargins.bottom(),
m_data.customMargins.left(), m_data.customMargins.top(),
m_data.customMargins.right(), m_data.customMargins.bottom(),
window()->minimumWidth(), window()->minimumHeight(),
@@ -1685,7 +1781,7 @@ void QWindowsWindow::handleGeometryChange()
void QWindowsBaseWindow::setGeometry_sys(const QRect &rect) const
{
- const QMargins margins = frameMargins();
+ const QMargins margins = fullFrameMargins();
const QRect frameGeometry = rect + margins;
qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << window()
@@ -1856,7 +1952,8 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowStates state)
fireExpose(QRegion(0, 0, w->width(), w->height()));
exposeEventsSent = true;
}
- foreach (QWindow *child, QGuiApplication::allWindows()) {
+ const QWindowList allWindows = QGuiApplication::allWindows();
+ for (QWindow *child : allWindows) {
if (child != w && child->isVisible() && child->transientParent() == w) {
QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(child);
if (platformWindow && platformWindow->isLayered()) {
@@ -2048,7 +2145,7 @@ void QWindowsWindow::setExStyle(unsigned s) const
SetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE, s);
}
-void QWindowsWindow::windowEvent(QEvent *event)
+bool QWindowsWindow::windowEvent(QEvent *event)
{
switch (event->type()) {
case QEvent::WindowBlocked: // Blocked by another modal window.
@@ -2064,6 +2161,8 @@ void QWindowsWindow::windowEvent(QEvent *event)
default:
break;
}
+
+ return QPlatformWindow::windowEvent(event);
}
void QWindowsWindow::propagateSizeHints()
@@ -2106,21 +2205,29 @@ bool QWindowsWindow::handleGeometryChangingMessage(MSG *message, const QWindow *
bool QWindowsWindow::handleGeometryChanging(MSG *message) const
{
- const QMargins margins = window()->isTopLevel() ? frameMargins() : QMargins();
+ const QMargins margins = window()->isTopLevel() ? fullFrameMargins() : QMargins();
return QWindowsWindow::handleGeometryChangingMessage(message, window(), margins);
}
-void QWindowsWindow::setFrameMargins(const QMargins &newMargins)
+void QWindowsWindow::setFullFrameMargins(const QMargins &newMargins)
{
- if (m_data.frame != newMargins) {
- qCDebug(lcQpaWindows) << __FUNCTION__ << window() << m_data.frame << "->" << newMargins;
- m_data.frame = newMargins;
+ if (m_data.fullFrameMargins != newMargins) {
+ qCDebug(lcQpaWindows) << __FUNCTION__ << window() << m_data.fullFrameMargins << "->" << newMargins;
+ m_data.fullFrameMargins = newMargins;
}
}
QMargins QWindowsWindow::frameMargins() const
{
- return m_data.frame;
+ QMargins result = fullFrameMargins();
+ if (isTopLevel() && !(m_data.flags & Qt::FramelessWindowHint))
+ result -= invisibleMargins(geometry().topLeft());
+ return result;
+}
+
+QMargins QWindowsWindow::fullFrameMargins() const
+{
+ return m_data.fullFrameMargins;
}
void QWindowsWindow::setOpacity(qreal level)
@@ -2174,7 +2281,7 @@ void QWindowsWindow::setMask(const QRegion &region)
// Mask is in client area coordinates, so offset it in case we have a frame
if (window()->isTopLevel()) {
- const QMargins margins = frameMargins();
+ const QMargins margins = fullFrameMargins();
OffsetRgn(winRegion, margins.left(), margins.top());
}
diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h
index 6d439bce1a..e8c30bd44b 100644
--- a/src/plugins/platforms/windows/qwindowswindow.h
+++ b/src/plugins/platforms/windows/qwindowswindow.h
@@ -41,7 +41,7 @@
#define QWINDOWSWINDOW_H
#include <QtCore/qt_windows.h>
-#include <QtCore/QPointer>
+#include <QtCore/qpointer.h>
#include "qwindowscursor.h"
#include <qpa/qplatformwindow.h>
@@ -59,7 +59,7 @@ class QDebug;
struct QWindowsGeometryHint
{
- QWindowsGeometryHint() {}
+ QWindowsGeometryHint() = default;
explicit QWindowsGeometryHint(const QWindow *w, const QMargins &customMargins);
static QMargins frame(DWORD style, DWORD exStyle);
static bool handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result);
@@ -108,8 +108,8 @@ struct QWindowsWindowData
{
Qt::WindowFlags flags;
QRect geometry;
- QMargins frame; // Do not use directly for windows, see FrameDirty.
- QMargins customMargins; // User-defined, additional frame for NCCALCSIZE
+ QMargins fullFrameMargins; // Do not use directly for windows, see FrameDirty.
+ QMargins customMargins; // User-defined, additional frame for NCCALCSIZE
HWND hwnd = 0;
bool embedded = false;
@@ -120,14 +120,16 @@ struct QWindowsWindowData
class QWindowsBaseWindow : public QPlatformWindow
{
+ Q_DISABLE_COPY(QWindowsBaseWindow)
public:
explicit QWindowsBaseWindow(QWindow *window) : QPlatformWindow(window) {}
WId winId() const override { return WId(handle()); }
QRect geometry() const override { return geometry_sys(); }
- QMargins frameMargins() const override { return frameMargins_sys(); }
+ QMargins frameMargins() const override { return fullFrameMargins(); }
QPoint mapToGlobal(const QPoint &pos) const override;
QPoint mapFromGlobal(const QPoint &pos) const override;
+ virtual QMargins fullFrameMargins() const { return frameMargins_sys(); }
using QPlatformWindow::screenForGeometry;
@@ -222,7 +224,7 @@ public:
};
QWindowsWindow(QWindow *window, const QWindowsWindowData &data);
- ~QWindowsWindow();
+ ~QWindowsWindow() override;
void initialize() override;
@@ -251,13 +253,14 @@ public:
void raise() override { raise_sys(); }
void lower() override { lower_sys(); }
- void windowEvent(QEvent *event) override;
+ bool windowEvent(QEvent *event) override;
void propagateSizeHints() override;
static bool handleGeometryChangingMessage(MSG *message, const QWindow *qWindow, const QMargins &marginsDp);
bool handleGeometryChanging(MSG *message) const;
QMargins frameMargins() const override;
- void setFrameMargins(const QMargins &newMargins);
+ QMargins fullFrameMargins() const override;
+ void setFullFrameMargins(const QMargins &newMargins);
void setOpacity(qreal level) override;
void setMask(const QRegion &region) override;
@@ -428,7 +431,7 @@ inline QWindowsWindow *QWindowsWindow::windowsWindowOf(const QWindow *w)
void *QWindowsWindow::userDataOf(HWND hwnd)
{
- return (void *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ return reinterpret_cast<void *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
}
void QWindowsWindow::setUserDataOf(HWND hwnd, void *ud)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp
index 0f0f42fafe..85a931e015 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp
@@ -37,16 +37,16 @@
**
****************************************************************************/
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiaaccessibility.h"
#include "qwindowsuiamainprovider.h"
#include "qwindowsuiautils.h"
-#include <QtGui/QAccessible>
-#include <QtGui/QWindow>
-#include <QtGui/QGuiApplication>
+#include <QtGui/qaccessible.h>
+#include <QtGui/qwindow.h>
+#include <QtGui/qguiapplication.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtCore/qt_windows.h>
#include <qpa/qplatformintegration.h>
@@ -104,19 +104,15 @@ void QWindowsUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event
return;
switch (event->type()) {
-
case QAccessible::Focus:
QWindowsUiaMainProvider::notifyFocusChange(event);
break;
-
case QAccessible::StateChanged:
QWindowsUiaMainProvider::notifyStateChange(static_cast<QAccessibleStateChangeEvent *>(event));
break;
-
case QAccessible::ValueChanged:
QWindowsUiaMainProvider::notifyValueChange(static_cast<QAccessibleValueChangeEvent *>(event));
break;
-
case QAccessible::TextAttributeChanged:
case QAccessible::TextColumnChanged:
case QAccessible::TextInserted:
@@ -126,7 +122,6 @@ void QWindowsUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event
case QAccessible::TextCaretMoved:
QWindowsUiaMainProvider::notifyTextChange(event);
break;
-
default:
break;
}
@@ -134,4 +129,4 @@ void QWindowsUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h
index bbb81d596b..48b4f9fa6a 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h
@@ -40,15 +40,15 @@
#ifndef QWINDOWSUIAACCESSIBILITY_H
#define QWINDOWSUIAACCESSIBILITY_H
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowscontext.h"
#include <qpa/qplatformaccessibility.h>
QT_BEGIN_NAMESPACE
-// Windows plataform accessibility implemented over UI Automation.
+// Windows platform accessibility implemented over UI Automation.
class QWindowsUiaAccessibility : public QPlatformAccessibility
{
public:
@@ -60,6 +60,6 @@ public:
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
#endif // QWINDOWSUIAACCESSIBILITY_H
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.cpp
index 1e1fc49c0f..53c647512a 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.cpp
@@ -37,17 +37,15 @@
**
****************************************************************************/
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiabaseprovider.h"
#include "qwindowsuiautils.h"
#include "qwindowscontext.h"
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QDebug>
-#include <QtCore/QString>
+#include <QtGui/qaccessible.h>
+#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
@@ -78,4 +76,4 @@ QAccessible::Id QWindowsUiaBaseProvider::id() const
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h
index 3ae403e8c5..9caa7d6898 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h
@@ -40,12 +40,11 @@
#ifndef QWINDOWSUIABASEPROVIDER_H
#define QWINDOWSUIABASEPROVIDER_H
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QPointer>
+#include <QtGui/qaccessible.h>
+#include <QtCore/qpointer.h>
#include <qwindowscombase.h>
#include <QtWindowsUIAutomationSupport/private/qwindowsuiawrapper_p.h>
@@ -53,7 +52,6 @@
QT_BEGIN_NAMESPACE
class QAccessibleInterface;
-class QDebug;
// Base class for UI Automation providers.
class QWindowsUiaBaseProvider : public QObject
@@ -73,6 +71,6 @@ private:
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
#endif // QWINDOWSUIABASEPROVIDER_H
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.cpp
index e0502c00f3..93d360c40b 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.cpp
@@ -37,18 +37,17 @@
**
****************************************************************************/
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiagriditemprovider.h"
#include "qwindowsuiamainprovider.h"
#include "qwindowsuiautils.h"
#include "qwindowscontext.h"
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QDebug>
-#include <QtCore/QString>
+#include <QtGui/qaccessible.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
@@ -148,7 +147,7 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaGridItemProvider::get_ColumnSpan(int *pRetV
return S_OK;
}
-// Returns the provider for the cointaining table/tree.
+// Returns the provider for the containing table/tree.
HRESULT STDMETHODCALLTYPE QWindowsUiaGridItemProvider::get_ContainingGrid(IRawElementProviderSimple **pRetVal)
{
qCDebug(lcQpaUiAutomation) << __FUNCTION__;
@@ -173,4 +172,4 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaGridItemProvider::get_ContainingGrid(IRawEl
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h
index a93b50ef97..3d17056d38 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h
@@ -40,8 +40,8 @@
#ifndef QWINDOWSUIAGRIDITEMPROVIDER_H
#define QWINDOWSUIAGRIDITEMPROVIDER_H
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiabaseprovider.h"
@@ -57,15 +57,15 @@ public:
virtual ~QWindowsUiaGridItemProvider();
// IGridItemProvider
- HRESULT STDMETHODCALLTYPE get_Row(int *pRetVal);
- HRESULT STDMETHODCALLTYPE get_Column(int *pRetVal);
- HRESULT STDMETHODCALLTYPE get_RowSpan(int *pRetVal);
- HRESULT STDMETHODCALLTYPE get_ColumnSpan(int *pRetVal);
- HRESULT STDMETHODCALLTYPE get_ContainingGrid(IRawElementProviderSimple **pRetVal);
+ HRESULT STDMETHODCALLTYPE get_Row(int *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_Column(int *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_RowSpan(int *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_ColumnSpan(int *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_ContainingGrid(IRawElementProviderSimple **pRetVal) override;
};
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
#endif // QWINDOWSUIAGRIDITEMPROVIDER_H
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.cpp
index 65c2df703b..cce9d8143c 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.cpp
@@ -37,18 +37,17 @@
**
****************************************************************************/
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiagridprovider.h"
#include "qwindowsuiamainprovider.h"
#include "qwindowsuiautils.h"
#include "qwindowscontext.h"
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QDebug>
-#include <QtCore/QString>
+#include <QtGui/qaccessible.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
@@ -133,4 +132,4 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaGridProvider::get_ColumnCount(int *pRetVal)
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h
index 15521f98b3..b96fc1a93c 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h
@@ -40,8 +40,8 @@
#ifndef QWINDOWSUIAGRIDPROVIDER_H
#define QWINDOWSUIAGRIDPROVIDER_H
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiabaseprovider.h"
@@ -57,13 +57,13 @@ public:
virtual ~QWindowsUiaGridProvider();
// IGridProvider
- HRESULT STDMETHODCALLTYPE GetItem(int row, int column, IRawElementProviderSimple **pRetVal);
- HRESULT STDMETHODCALLTYPE get_RowCount(int *pRetVal);
- HRESULT STDMETHODCALLTYPE get_ColumnCount(int *pRetVal);
+ HRESULT STDMETHODCALLTYPE GetItem(int row, int column, IRawElementProviderSimple **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_RowCount(int *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_ColumnCount(int *pRetVal) override;
};
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
#endif // QWINDOWSUIAGRIDPROVIDER_H
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.cpp
index 2af883c4f6..d09770bc81 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.cpp
@@ -37,17 +37,16 @@
**
****************************************************************************/
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiainvokeprovider.h"
#include "qwindowsuiautils.h"
#include "qwindowscontext.h"
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QDebug>
-#include <QtCore/QString>
+#include <QtGui/qaccessible.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
@@ -81,4 +80,4 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaInvokeProvider::Invoke()
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h
index 2b8a646983..5fb509c5f3 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h
@@ -40,8 +40,8 @@
#ifndef QWINDOWSUIAINVOKEPROVIDER_H
#define QWINDOWSUIAINVOKEPROVIDER_H
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiabaseprovider.h"
@@ -57,11 +57,11 @@ public:
virtual ~QWindowsUiaInvokeProvider();
// IInvokeProvider
- HRESULT STDMETHODCALLTYPE Invoke();
+ HRESULT STDMETHODCALLTYPE Invoke() override;
};
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
#endif // QWINDOWSUIAINVOKEPROVIDER_H
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
index e36006c103..fad83fb165 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiamainprovider.h"
#include "qwindowsuiavalueprovider.h"
@@ -57,10 +57,10 @@
#include "qwindowsuiautils.h"
#include "qwindowsuiaprovidercache.h"
-#include <QtCore/QDebug>
-#include <QtGui/QAccessible>
-#include <QtGui/QGuiApplication>
-#include <QtGui/QWindow>
+#include <QtCore/qloggingcategory.h>
+#include <QtGui/qaccessible.h>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qwindow.h>
#if !defined(Q_CC_BOR) && !defined (Q_CC_GNU)
#include <comdef.h>
@@ -391,9 +391,8 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR
break;
case UIA_NamePropertyId: {
QString name = accessible->text(QAccessible::Name);
- if (name.isEmpty() && clientTopLevel) {
+ if (name.isEmpty() && clientTopLevel)
name = QCoreApplication::applicationName();
- }
setVariantString(name, pRetVal);
break;
}
@@ -658,4 +657,4 @@ HRESULT QWindowsUiaMainProvider::GetFocus(IRawElementProviderFragment **pRetVal)
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h
index 893cbf7f8a..325d5b3de4 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h
@@ -40,15 +40,15 @@
#ifndef QWINDOWSUIAMAINPROVIDER_H
#define QWINDOWSUIAMAINPROVIDER_H
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiabaseprovider.h"
-#include <QtCore/QPointer>
-#include <QtCore/QSharedPointer>
+#include <QtCore/qpointer.h>
+#include <QtCore/qsharedpointer.h>
#include <QtCore/qt_windows.h>
-#include <QtGui/QAccessible>
+#include <QtGui/qaccessible.h>
QT_BEGIN_NAMESPACE
@@ -71,27 +71,27 @@ public:
static void notifyTextChange(QAccessibleEvent *event);
// IUnknown
- HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, LPVOID *iface);
- ULONG STDMETHODCALLTYPE AddRef();
- ULONG STDMETHODCALLTYPE Release();
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, LPVOID *iface) override;
+ ULONG STDMETHODCALLTYPE AddRef() override;
+ ULONG STDMETHODCALLTYPE Release() override;
// IRawElementProviderSimple methods
- HRESULT STDMETHODCALLTYPE get_ProviderOptions(ProviderOptions *pRetVal);
- HRESULT STDMETHODCALLTYPE GetPatternProvider(PATTERNID idPattern, IUnknown **pRetVal);
- HRESULT STDMETHODCALLTYPE GetPropertyValue(PROPERTYID idProp, VARIANT *pRetVal);
- HRESULT STDMETHODCALLTYPE get_HostRawElementProvider(IRawElementProviderSimple **pRetVal);
+ HRESULT STDMETHODCALLTYPE get_ProviderOptions(ProviderOptions *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE GetPatternProvider(PATTERNID idPattern, IUnknown **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE GetPropertyValue(PROPERTYID idProp, VARIANT *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_HostRawElementProvider(IRawElementProviderSimple **pRetVal) override;
// IRawElementProviderFragment methods
- HRESULT STDMETHODCALLTYPE Navigate(NavigateDirection direction, IRawElementProviderFragment **pRetVal);
- HRESULT STDMETHODCALLTYPE GetRuntimeId(SAFEARRAY **pRetVal);
- HRESULT STDMETHODCALLTYPE get_BoundingRectangle(UiaRect *pRetVal);
- HRESULT STDMETHODCALLTYPE GetEmbeddedFragmentRoots(SAFEARRAY **pRetVal);
- HRESULT STDMETHODCALLTYPE SetFocus();
- HRESULT STDMETHODCALLTYPE get_FragmentRoot(IRawElementProviderFragmentRoot **pRetVal);
+ HRESULT STDMETHODCALLTYPE Navigate(NavigateDirection direction, IRawElementProviderFragment **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE GetRuntimeId(SAFEARRAY **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_BoundingRectangle(UiaRect *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE GetEmbeddedFragmentRoots(SAFEARRAY **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE SetFocus() override;
+ HRESULT STDMETHODCALLTYPE get_FragmentRoot(IRawElementProviderFragmentRoot **pRetVal) override;
// IRawElementProviderFragmentRoot methods
- HRESULT STDMETHODCALLTYPE ElementProviderFromPoint(double x, double y, IRawElementProviderFragment **pRetVal);
- HRESULT STDMETHODCALLTYPE GetFocus(IRawElementProviderFragment **pRetVal);
+ HRESULT STDMETHODCALLTYPE ElementProviderFromPoint(double x, double y, IRawElementProviderFragment **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE GetFocus(IRawElementProviderFragment **pRetVal) override;
private:
QString automationIdForAccessible(const QAccessibleInterface *accessible);
@@ -100,6 +100,6 @@ private:
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
#endif // QWINDOWSUIAMAINPROVIDER_H
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.cpp
index 9f0a1e126f..c55e827a46 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.cpp
@@ -37,15 +37,13 @@
**
****************************************************************************/
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiaprovidercache.h"
#include "qwindowsuiautils.h"
#include "qwindowscontext.h"
-#include <QtCore/QDebug>
-
QT_BEGIN_NAMESPACE
using namespace QWindowsUiAutomation;
@@ -66,7 +64,7 @@ QWindowsUiaProviderCache *QWindowsUiaProviderCache::instance()
// Returns the provider instance associated with the ID, or nullptr.
QWindowsUiaBaseProvider *QWindowsUiaProviderCache::providerForId(QAccessible::Id id) const
{
- return providerTable.value(id);
+ return m_providerTable.value(id);
}
// Inserts a provider in the cache and associates it with an accessibility ID.
@@ -74,8 +72,8 @@ void QWindowsUiaProviderCache::insert(QAccessible::Id id, QWindowsUiaBaseProvide
{
remove(id);
if (provider) {
- providerTable[id] = provider;
- inverseTable[provider] = id;
+ 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);
}
@@ -87,20 +85,20 @@ void QWindowsUiaProviderCache::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 = inverseTable.find(obj);
- if (it != inverseTable.end()) {
- providerTable.remove(*it);
- inverseTable.remove(obj);
+ 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 QWindowsUiaProviderCache::remove(QAccessible::Id id)
{
- inverseTable.remove(providerTable.value(id));
- providerTable.remove(id);
+ m_inverseTable.remove(m_providerTable.value(id));
+ m_providerTable.remove(id);
}
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.h
index 7ad30ac39c..f66dc2c170 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.h
@@ -40,14 +40,13 @@
#ifndef QWINDOWSUIAPROVIDERCACHE_H
#define QWINDOWSUIAPROVIDERCACHE_H
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiabaseprovider.h"
-#include <QtCore/QHash>
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
+#include <QtCore/qhash.h>
+#include <QtGui/qaccessible.h>
QT_BEGIN_NAMESPACE
@@ -66,12 +65,12 @@ private Q_SLOTS:
void objectDestroyed(QObject *obj);
private:
- QHash<QAccessible::Id, QWindowsUiaBaseProvider *> providerTable;
- QHash<QObject *, QAccessible::Id> inverseTable;
+ QHash<QAccessible::Id, QWindowsUiaBaseProvider *> m_providerTable;
+ QHash<QObject *, QAccessible::Id> m_inverseTable;
};
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
#endif // QWINDOWSUIAPROVIDERCACHE_H
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.cpp
index 0cd09c3f0a..7c1827387a 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.cpp
@@ -37,17 +37,16 @@
**
****************************************************************************/
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiarangevalueprovider.h"
#include "qwindowsuiautils.h"
#include "qwindowscontext.h"
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QDebug>
-#include <QtCore/QString>
+#include <QtGui/qaccessible.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
@@ -187,4 +186,4 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaRangeValueProvider::get_SmallChange(double
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h
index f742ef99c2..c5e0a03ee5 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h
@@ -40,8 +40,8 @@
#ifndef QWINDOWSUIARANGEVALUEPROVIDER_H
#define QWINDOWSUIARANGEVALUEPROVIDER_H
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiabaseprovider.h"
@@ -57,17 +57,17 @@ public:
virtual ~QWindowsUiaRangeValueProvider();
// IRangeValueProvider
- HRESULT STDMETHODCALLTYPE SetValue(double val);
- HRESULT STDMETHODCALLTYPE get_Value(double *pRetVal);
- HRESULT STDMETHODCALLTYPE get_IsReadOnly(BOOL *pRetVal);
- HRESULT STDMETHODCALLTYPE get_Maximum(double *pRetVal);
- HRESULT STDMETHODCALLTYPE get_Minimum(double *pRetVal);
- HRESULT STDMETHODCALLTYPE get_LargeChange(double *pRetVal);
- HRESULT STDMETHODCALLTYPE get_SmallChange(double *pRetVal);
+ HRESULT STDMETHODCALLTYPE SetValue(double val) override;
+ HRESULT STDMETHODCALLTYPE get_Value(double *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_IsReadOnly(BOOL *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_Maximum(double *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_Minimum(double *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_LargeChange(double *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_SmallChange(double *pRetVal) override;
};
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
#endif // QWINDOWSUIARANGEVALUEPROVIDER_H
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp
index 45216a6d1c..a93a05c7bc 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp
@@ -37,18 +37,17 @@
**
****************************************************************************/
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiaselectionitemprovider.h"
#include "qwindowsuiamainprovider.h"
#include "qwindowsuiautils.h"
#include "qwindowscontext.h"
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QDebug>
-#include <QtCore/QString>
+#include <QtGui/qaccessible.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
@@ -198,4 +197,4 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::get_SelectionContain
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h
index 6a9b5b1e4b..1f2605188b 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h
@@ -40,8 +40,8 @@
#ifndef QWINDOWSUIASELECTIONITEMPROVIDER_H
#define QWINDOWSUIASELECTIONITEMPROVIDER_H
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiabaseprovider.h"
@@ -57,15 +57,15 @@ public:
virtual ~QWindowsUiaSelectionItemProvider();
// ISelectionItemProvider
- HRESULT STDMETHODCALLTYPE Select();
- HRESULT STDMETHODCALLTYPE AddToSelection();
- HRESULT STDMETHODCALLTYPE RemoveFromSelection();
- HRESULT STDMETHODCALLTYPE get_IsSelected(BOOL *pRetVal);
- HRESULT STDMETHODCALLTYPE get_SelectionContainer(IRawElementProviderSimple **pRetVal);
+ HRESULT STDMETHODCALLTYPE Select() override;
+ HRESULT STDMETHODCALLTYPE AddToSelection() override;
+ HRESULT STDMETHODCALLTYPE RemoveFromSelection() override;
+ HRESULT STDMETHODCALLTYPE get_IsSelected(BOOL *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_SelectionContainer(IRawElementProviderSimple **pRetVal) override;
};
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
#endif // QWINDOWSUIASELECTIONITEMPROVIDER_H
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp
index 1c06503bfc..3305e9c5c4 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp
@@ -37,19 +37,18 @@
**
****************************************************************************/
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiaselectionprovider.h"
#include "qwindowsuiamainprovider.h"
#include "qwindowsuiautils.h"
#include "qwindowscontext.h"
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QDebug>
-#include <QtCore/QString>
-#include <QList>
+#include <QtGui/qaccessible.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qlist.h>
QT_BEGIN_NAMESPACE
@@ -144,4 +143,4 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionProvider::get_IsSelectionRequired(
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h
index 5a07a82ac8..0376d25804 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h
@@ -40,8 +40,8 @@
#ifndef QWINDOWSUIASELECTIONPROVIDER_H
#define QWINDOWSUIASELECTIONPROVIDER_H
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiabaseprovider.h"
@@ -57,13 +57,13 @@ public:
virtual ~QWindowsUiaSelectionProvider();
// ISelectionProvider
- HRESULT STDMETHODCALLTYPE GetSelection(SAFEARRAY **pRetVal);
- HRESULT STDMETHODCALLTYPE get_CanSelectMultiple(BOOL *pRetVal);
- HRESULT STDMETHODCALLTYPE get_IsSelectionRequired(BOOL *pRetVal);
+ HRESULT STDMETHODCALLTYPE GetSelection(SAFEARRAY **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_CanSelectMultiple(BOOL *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_IsSelectionRequired(BOOL *pRetVal) override;
};
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
#endif // QWINDOWSUIASELECTIONPROVIDER_H
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.cpp
index 3ea29fc86c..2a94012590 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.cpp
@@ -37,18 +37,17 @@
**
****************************************************************************/
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiatableitemprovider.h"
#include "qwindowsuiamainprovider.h"
#include "qwindowsuiautils.h"
#include "qwindowscontext.h"
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QDebug>
-#include <QtCore/QString>
+#include <QtGui/qaccessible.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
@@ -126,4 +125,4 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaTableItemProvider::GetColumnHeaderItems(SAF
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h
index 277884c980..bf4b52ee0b 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h
@@ -40,8 +40,8 @@
#ifndef QWINDOWSUIATABLEITEMPROVIDER_H
#define QWINDOWSUIATABLEITEMPROVIDER_H
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiabaseprovider.h"
@@ -57,12 +57,12 @@ public:
virtual ~QWindowsUiaTableItemProvider();
// ITableItemProvider
- HRESULT STDMETHODCALLTYPE GetRowHeaderItems(SAFEARRAY **pRetVal);
- HRESULT STDMETHODCALLTYPE GetColumnHeaderItems(SAFEARRAY **pRetVal);
+ HRESULT STDMETHODCALLTYPE GetRowHeaderItems(SAFEARRAY **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE GetColumnHeaderItems(SAFEARRAY **pRetVal) override;
};
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
#endif // QWINDOWSUIATABLEITEMPROVIDER_H
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.cpp
index f79a24536b..80086f1d4f 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.cpp
@@ -37,18 +37,17 @@
**
****************************************************************************/
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiatableprovider.h"
#include "qwindowsuiamainprovider.h"
#include "qwindowsuiautils.h"
#include "qwindowscontext.h"
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QDebug>
-#include <QtCore/QString>
+#include <QtGui/qaccessible.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
@@ -151,4 +150,4 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaTableProvider::get_RowOrColumnMajor(enum Ro
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h
index 8cd0acda03..94c8ab93a7 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h
@@ -40,8 +40,8 @@
#ifndef QWINDOWSUIATABLEPROVIDER_H
#define QWINDOWSUIATABLEPROVIDER_H
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiabaseprovider.h"
@@ -57,13 +57,13 @@ public:
virtual ~QWindowsUiaTableProvider();
// ITableProvider
- HRESULT STDMETHODCALLTYPE GetRowHeaders(SAFEARRAY **pRetVal);
- HRESULT STDMETHODCALLTYPE GetColumnHeaders(SAFEARRAY **pRetVal);
- HRESULT STDMETHODCALLTYPE get_RowOrColumnMajor(enum RowOrColumnMajor *pRetVal);
+ HRESULT STDMETHODCALLTYPE GetRowHeaders(SAFEARRAY **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE GetColumnHeaders(SAFEARRAY **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_RowOrColumnMajor(enum RowOrColumnMajor *pRetVal) override;
};
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
#endif // QWINDOWSUIATABLEPROVIDER_H
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp
index e1622933af..9d1e72fb78 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp
@@ -37,17 +37,16 @@
**
****************************************************************************/
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiatextprovider.h"
#include "qwindowsuiautils.h"
#include "qwindowscontext.h"
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QDebug>
-#include <QtCore/QString>
+#include <QtGui/qaccessible.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
@@ -258,4 +257,4 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaTextProvider::GetCaretRange(BOOL *isActive,
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h
index a6d10027fa..a9be70fa16 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h
@@ -40,8 +40,8 @@
#ifndef QWINDOWSUIATEXTPROVIDER_H
#define QWINDOWSUIATEXTPROVIDER_H
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiabaseprovider.h"
#include "qwindowsuiatextrangeprovider.h"
@@ -58,23 +58,23 @@ public:
~QWindowsUiaTextProvider();
// IUnknown overrides
- HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, LPVOID *iface);
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, LPVOID *iface) override;
// ITextProvider
- HRESULT STDMETHODCALLTYPE GetSelection(SAFEARRAY **pRetVal);
- HRESULT STDMETHODCALLTYPE GetVisibleRanges(SAFEARRAY **pRetVal);
- HRESULT STDMETHODCALLTYPE RangeFromChild(IRawElementProviderSimple *childElement, ITextRangeProvider **pRetVal);
- HRESULT STDMETHODCALLTYPE RangeFromPoint(UiaPoint point, ITextRangeProvider **pRetVal);
- HRESULT STDMETHODCALLTYPE get_DocumentRange(ITextRangeProvider **pRetVal);
- HRESULT STDMETHODCALLTYPE get_SupportedTextSelection(SupportedTextSelection *pRetVal);
+ HRESULT STDMETHODCALLTYPE GetSelection(SAFEARRAY **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE GetVisibleRanges(SAFEARRAY **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE RangeFromChild(IRawElementProviderSimple *childElement, ITextRangeProvider **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE RangeFromPoint(UiaPoint point, ITextRangeProvider **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_DocumentRange(ITextRangeProvider **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_SupportedTextSelection(SupportedTextSelection *pRetVal) override;
// ITextProvider2
- HRESULT STDMETHODCALLTYPE RangeFromAnnotation(IRawElementProviderSimple *annotationElement, ITextRangeProvider **pRetVal);
- HRESULT STDMETHODCALLTYPE GetCaretRange(BOOL *isActive, ITextRangeProvider **pRetVal);
+ HRESULT STDMETHODCALLTYPE RangeFromAnnotation(IRawElementProviderSimple *annotationElement, ITextRangeProvider **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE GetCaretRange(BOOL *isActive, ITextRangeProvider **pRetVal) override;
};
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
#endif // QWINDOWSUIATEXTPROVIDER_H
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp
index dae7cbdd5f..1be186f6b3 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp
@@ -37,18 +37,17 @@
**
****************************************************************************/
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiatextrangeprovider.h"
#include "qwindowsuiamainprovider.h"
#include "qwindowsuiautils.h"
#include "qwindowscontext.h"
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QDebug>
-#include <QtCore/QString>
+#include <QtGui/qaccessible.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
@@ -238,12 +237,12 @@ HRESULT QWindowsUiaTextRangeProvider::GetBoundingRectangles(SAFEARRAY **pRetVal)
int endRange = qMin(end, m_endOffset);
if (startRange < endRange) {
// Calculates a bounding rectangle for the line and adds it to the list.
- QRect startRect = textInterface->characterRect(startRange);
- QRect endRect = textInterface->characterRect(endRange - 1);
- 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()));
+ 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()));
rectList.append(lineRect);
}
if (end >= len) break;
@@ -519,9 +518,9 @@ HRESULT QWindowsUiaTextRangeProvider::Select()
}
// Not supported.
-HRESULT QWindowsUiaTextRangeProvider::FindTextW(BSTR /* text */, BOOL /* backward */,
- BOOL /* ignoreCase */,
- ITextRangeProvider **pRetVal)
+HRESULT QWindowsUiaTextRangeProvider::FindText(BSTR /* text */, BOOL /* backward */,
+ BOOL /* ignoreCase */,
+ ITextRangeProvider **pRetVal)
{
if (!pRetVal)
return E_INVALIDARG;
@@ -551,4 +550,4 @@ HRESULT QWindowsUiaTextRangeProvider::unselect()
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h
index 6fe6502c41..39b9069fc0 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h
@@ -40,8 +40,8 @@
#ifndef QWINDOWSUIATEXTRANGEPROVIDER_H
#define QWINDOWSUIATEXTRANGEPROVIDER_H
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiabaseprovider.h"
@@ -56,24 +56,25 @@ public:
explicit QWindowsUiaTextRangeProvider(QAccessible::Id id, int startOffset, int endOffset);
virtual ~QWindowsUiaTextRangeProvider();
- HRESULT STDMETHODCALLTYPE AddToSelection();
- HRESULT STDMETHODCALLTYPE Clone(ITextRangeProvider **pRetVal);
- HRESULT STDMETHODCALLTYPE Compare(ITextRangeProvider *range, BOOL *pRetVal);
- HRESULT STDMETHODCALLTYPE CompareEndpoints(TextPatternRangeEndpoint endpoint, ITextRangeProvider *targetRange, TextPatternRangeEndpoint targetEndpoint, int *pRetVal);
- HRESULT STDMETHODCALLTYPE ExpandToEnclosingUnit(TextUnit unit);
- HRESULT STDMETHODCALLTYPE FindAttribute(TEXTATTRIBUTEID attributeId, VARIANT val, BOOL backward, ITextRangeProvider **pRetVal);
- HRESULT STDMETHODCALLTYPE FindText(BSTR text, BOOL backward, BOOL ignoreCase, ITextRangeProvider **pRetVal);
- HRESULT STDMETHODCALLTYPE GetAttributeValue(TEXTATTRIBUTEID attributeId, VARIANT *pRetVal);
- HRESULT STDMETHODCALLTYPE GetBoundingRectangles(SAFEARRAY **pRetVal);
- HRESULT STDMETHODCALLTYPE GetChildren(SAFEARRAY **pRetVal);
- HRESULT STDMETHODCALLTYPE GetEnclosingElement(IRawElementProviderSimple **pRetVal);
- HRESULT STDMETHODCALLTYPE GetText(int maxLength, BSTR *pRetVal);
- HRESULT STDMETHODCALLTYPE Move(TextUnit unit, int count, int *pRetVal);
- HRESULT STDMETHODCALLTYPE MoveEndpointByRange(TextPatternRangeEndpoint endpoint, ITextRangeProvider *targetRange, TextPatternRangeEndpoint targetEndpoint);
- HRESULT STDMETHODCALLTYPE MoveEndpointByUnit(TextPatternRangeEndpoint endpoint, TextUnit unit, int count, int *pRetVal);
- HRESULT STDMETHODCALLTYPE RemoveFromSelection();
- HRESULT STDMETHODCALLTYPE ScrollIntoView(BOOL alignToTop);
- HRESULT STDMETHODCALLTYPE Select();
+ // ITextRangeProvider
+ HRESULT STDMETHODCALLTYPE AddToSelection() override;
+ HRESULT STDMETHODCALLTYPE Clone(ITextRangeProvider **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE Compare(ITextRangeProvider *range, BOOL *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE CompareEndpoints(TextPatternRangeEndpoint endpoint, ITextRangeProvider *targetRange, TextPatternRangeEndpoint targetEndpoint, int *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE ExpandToEnclosingUnit(TextUnit unit) override;
+ HRESULT STDMETHODCALLTYPE FindAttribute(TEXTATTRIBUTEID attributeId, VARIANT val, BOOL backward, ITextRangeProvider **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE FindText(BSTR text, BOOL backward, BOOL ignoreCase, ITextRangeProvider **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE GetAttributeValue(TEXTATTRIBUTEID attributeId, VARIANT *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE GetBoundingRectangles(SAFEARRAY **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE GetChildren(SAFEARRAY **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE GetEnclosingElement(IRawElementProviderSimple **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE GetText(int maxLength, BSTR *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE Move(TextUnit unit, int count, int *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE MoveEndpointByRange(TextPatternRangeEndpoint endpoint, ITextRangeProvider *targetRange, TextPatternRangeEndpoint targetEndpoint) override;
+ HRESULT STDMETHODCALLTYPE MoveEndpointByUnit(TextPatternRangeEndpoint endpoint, TextUnit unit, int count, int *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE RemoveFromSelection() override;
+ HRESULT STDMETHODCALLTYPE ScrollIntoView(BOOL alignToTop) override;
+ HRESULT STDMETHODCALLTYPE Select() override;
private:
HRESULT unselect();
@@ -83,6 +84,6 @@ private:
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
#endif // QWINDOWSUIATEXTRANGEPROVIDER_H
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.cpp
index 01cdfd7e91..32445e4ffb 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.cpp
@@ -37,17 +37,16 @@
**
****************************************************************************/
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiatoggleprovider.h"
#include "qwindowsuiautils.h"
#include "qwindowscontext.h"
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QDebug>
-#include <QtCore/QString>
+#include <QtGui/qaccessible.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
@@ -102,4 +101,4 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaToggleProvider::get_ToggleState(ToggleState
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h
index a0df983e40..2bed6f7e36 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h
@@ -40,8 +40,8 @@
#ifndef QWINDOWSUIATOGGLEPROVIDER_H
#define QWINDOWSUIATOGGLEPROVIDER_H
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiabaseprovider.h"
@@ -57,12 +57,12 @@ public:
virtual ~QWindowsUiaToggleProvider();
// IToggleProvider
- HRESULT STDMETHODCALLTYPE Toggle();
- HRESULT STDMETHODCALLTYPE get_ToggleState(ToggleState *pRetVal);
+ HRESULT STDMETHODCALLTYPE Toggle() override;
+ HRESULT STDMETHODCALLTYPE get_ToggleState(ToggleState *pRetVal) override;
};
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
#endif // QWINDOWSUIATOGGLEPROVIDER_H
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp
index 89e5aad6a6..fbb5c3b9ec 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp
@@ -37,14 +37,14 @@
**
****************************************************************************/
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiautils.h"
#include "qwindowscontext.h"
#include "qwindowswindow.h"
-#include <QtGui/QWindow>
+#include <QtGui/qwindow.h>
#include <QtGui/private/qhighdpiscaling_p.h>
#include <cmath>
@@ -232,4 +232,4 @@ bool isTextUnitSeparator(TextUnit unit, const QChar &ch)
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.h
index 15f4d6e8ba..6a482f6c1c 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.h
@@ -40,16 +40,14 @@
#ifndef QWINDOWSUIAUTILS_H
#define QWINDOWSUIAUTILS_H
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
-#include <QtCore/QString>
+#include <QtCore/qstring.h>
#include <QtCore/qt_windows.h>
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtGui/QWindow>
-#include <QtCore/QDebug>
-#include <QtCore/QRect>
+#include <QtGui/qaccessible.h>
+#include <QtGui/qwindow.h>
+#include <QtCore/qrect.h>
#include <QtWindowsUIAutomationSupport/private/qwindowsuiawrapper_p.h>
QT_BEGIN_NAMESPACE
@@ -84,6 +82,6 @@ void setVariantString(const QString &value, VARIANT *variant);
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
#endif // QWINDOWSUIAUTILS_H
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.cpp
index ef7d564e22..8651bcff60 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.cpp
@@ -37,17 +37,16 @@
**
****************************************************************************/
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiavalueprovider.h"
#include "qwindowsuiautils.h"
#include "qwindowscontext.h"
-#include <QtGui/QAccessible>
-#include <QtGui/QAccessibleInterface>
-#include <QtCore/QDebug>
-#include <QtCore/QString>
+#include <QtGui/qaccessible.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
@@ -129,4 +128,4 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaValueProvider::get_Value(BSTR *pRetVal)
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h
index db54fc0a46..334a17e51d 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h
@@ -40,8 +40,8 @@
#ifndef QWINDOWSUIAVALUEPROVIDER_H
#define QWINDOWSUIAVALUEPROVIDER_H
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
#include "qwindowsuiabaseprovider.h"
@@ -58,13 +58,13 @@ public:
virtual ~QWindowsUiaValueProvider();
// IValueProvider
- HRESULT STDMETHODCALLTYPE SetValue(LPCWSTR val);
- HRESULT STDMETHODCALLTYPE get_IsReadOnly(BOOL *pRetVal);
- HRESULT STDMETHODCALLTYPE get_Value(BSTR *pRetVal);
+ HRESULT STDMETHODCALLTYPE SetValue(LPCWSTR val) override;
+ HRESULT STDMETHODCALLTYPE get_IsReadOnly(BOOL *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_Value(BSTR *pRetVal) override;
};
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
#endif // QWINDOWSUIAVALUEPROVIDER_H
diff --git a/src/plugins/platforms/windows/windows.pri b/src/plugins/platforms/windows/windows.pri
index f4c396f7c5..db06a6a2a3 100644
--- a/src/plugins/platforms/windows/windows.pri
+++ b/src/plugins/platforms/windows/windows.pri
@@ -7,9 +7,9 @@ qtConfig(opengl):!qtConfig(opengles2):!qtConfig(dynamicgl): LIBS *= -lopengl32
mingw: LIBS *= -luuid
# For the dialog helpers:
-LIBS += -lshlwapi -lshell32 -ladvapi32
+LIBS += -lshlwapi -lshell32 -ladvapi32 -lwtsapi32
-DEFINES *= QT_NO_CAST_FROM_ASCII
+DEFINES *= QT_NO_CAST_FROM_ASCII QT_NO_FOREACH
SOURCES += \
$$PWD/qwindowswindow.cpp \
@@ -18,6 +18,7 @@ SOURCES += \
$$PWD/qwindowsscreen.cpp \
$$PWD/qwindowskeymapper.cpp \
$$PWD/qwindowsmousehandler.cpp \
+ $$PWD/qwindowspointerhandler.cpp \
$$PWD/qwindowsole.cpp \
$$PWD/qwindowsdropdataobject.cpp \
$$PWD/qwindowsmime.cpp \
@@ -40,6 +41,7 @@ HEADERS += \
$$PWD/qwindowsscreen.h \
$$PWD/qwindowskeymapper.h \
$$PWD/qwindowsmousehandler.h \
+ $$PWD/qwindowspointerhandler.h \
$$PWD/qtwindowsglobal.h \
$$PWD/qwindowsole.h \
$$PWD/qwindowsdropdataobject.h \
diff --git a/src/plugins/platforms/winrt/main.cpp b/src/plugins/platforms/winrt/main.cpp
index 222287b3ef..a37bd1e3d8 100644
--- a/src/plugins/platforms/winrt/main.cpp
+++ b/src/plugins/platforms/winrt/main.cpp
@@ -58,7 +58,7 @@ QPlatformIntegration *QWinRTIntegrationPlugin::create(const QString& system, con
if (!system.compare(QLatin1String("winrt"), Qt::CaseInsensitive))
return QWinRTIntegration::create();
- return 0;
+ return nullptr;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrtbackingstore.cpp b/src/plugins/platforms/winrt/qwinrtbackingstore.cpp
index 113886f9b4..c23d48b2dd 100644
--- a/src/plugins/platforms/winrt/qwinrtbackingstore.cpp
+++ b/src/plugins/platforms/winrt/qwinrtbackingstore.cpp
@@ -50,9 +50,6 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcQpaBackingStore, "qt.qpa.backingstore")
-Q_LOGGING_CATEGORY(lcQpaBackingStoreVerbose, "qt.qpa.backingstore.verbose")
-
class QWinRTBackingStorePrivate
{
public:
@@ -68,7 +65,7 @@ QWinRTBackingStore::QWinRTBackingStore(QWindow *window)
: QPlatformBackingStore(window), d_ptr(new QWinRTBackingStorePrivate)
{
Q_D(QWinRTBackingStore);
- qCDebug(lcQpaBackingStore) << __FUNCTION__ << this << window;
+ qCInfo(lcQpaBackingStore) << __FUNCTION__ << this << window;
d->initialized = false;
d->screen = static_cast<QWinRTScreen*>(window->screen()->handle());
@@ -80,7 +77,7 @@ QWinRTBackingStore::QWinRTBackingStore(QWindow *window)
bool QWinRTBackingStore::initialize()
{
Q_D(QWinRTBackingStore);
- qCDebug(lcQpaBackingStoreVerbose) << __FUNCTION__ << d->initialized;
+ qCDebug(lcQpaBackingStore) << __FUNCTION__ << d->initialized;
if (d->initialized)
return true;
@@ -102,7 +99,7 @@ bool QWinRTBackingStore::initialize()
QWinRTBackingStore::~QWinRTBackingStore()
{
- qCDebug(lcQpaBackingStore) << __FUNCTION__ << this;
+ qCInfo(lcQpaBackingStore) << __FUNCTION__ << this;
}
QPaintDevice *QWinRTBackingStore::paintDevice()
@@ -116,16 +113,19 @@ void QWinRTBackingStore::flush(QWindow *window, const QRegion &region, const QPo
Q_D(QWinRTBackingStore);
Q_UNUSED(offset)
- qCDebug(lcQpaBackingStoreVerbose) << __FUNCTION__ << this << window << region;
+ 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");
- const QRect bounds = region.boundingRect();
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(),
@@ -151,7 +151,7 @@ void QWinRTBackingStore::resize(const QSize &size, const QRegion &staticContents
Q_D(QWinRTBackingStore);
Q_UNUSED(staticContents)
- qCDebug(lcQpaBackingStoreVerbose) << __FUNCTION__ << this << size;
+ qCDebug(lcQpaBackingStore) << __FUNCTION__ << this << size;
if (!initialize())
return;
@@ -182,14 +182,14 @@ QImage QWinRTBackingStore::toImage() const
void QWinRTBackingStore::beginPaint(const QRegion &region)
{
- qCDebug(lcQpaBackingStoreVerbose) << __FUNCTION__ << this << region;
+ qCDebug(lcQpaBackingStore) << __FUNCTION__ << this << region;
resize(window()->size(), region);
}
void QWinRTBackingStore::endPaint()
{
- qCDebug(lcQpaBackingStoreVerbose) << __FUNCTION__ << this;
+ qCDebug(lcQpaBackingStore) << __FUNCTION__ << this;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrtbackingstore.h b/src/plugins/platforms/winrt/qwinrtbackingstore.h
index cd05faa63e..b62d340b82 100644
--- a/src/plugins/platforms/winrt/qwinrtbackingstore.h
+++ b/src/plugins/platforms/winrt/qwinrtbackingstore.h
@@ -47,9 +47,6 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcQpaBackingStore)
-Q_DECLARE_LOGGING_CATEGORY(lcQpaBackingStoreVerbose)
-
class QWinRTScreen;
class QWinRTBackingStorePrivate;
@@ -57,7 +54,7 @@ class QWinRTBackingStore : public QPlatformBackingStore
{
public:
explicit QWinRTBackingStore(QWindow *window);
- ~QWinRTBackingStore();
+ ~QWinRTBackingStore() override;
QPaintDevice *paintDevice() override;
void beginPaint(const QRegion &) override;
void endPaint() override;
diff --git a/src/plugins/platforms/winrt/qwinrtcanvas.cpp b/src/plugins/platforms/winrt/qwinrtcanvas.cpp
new file mode 100644
index 0000000000..dd6b52d9cd
--- /dev/null
+++ b/src/plugins/platforms/winrt/qwinrtcanvas.cpp
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..bc3b708ac2
--- /dev/null
+++ b/src/plugins/platforms/winrt/qwinrtcanvas.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** 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
index 05c34b82f8..fd0ed8aed2 100644
--- a/src/plugins/platforms/winrt/qwinrtclipboard.cpp
+++ b/src/plugins/platforms/winrt/qwinrtclipboard.cpp
@@ -99,7 +99,7 @@ QMimeData *QWinRTClipboard::mimeData(QClipboard::Mode mode)
quint32 size;
const wchar_t *textStr = result.GetRawBuffer(&size);
- QString text = QString::fromWCharArray(textStr, size);
+ QString text = QString::fromWCharArray(textStr, int(size));
text.replace(QLatin1String("\r\n"), QLatin1String("\n"));
if (m_mimeData) {
@@ -161,7 +161,8 @@ void QWinRTClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
&package);
const QString nativeString = convertToWindowsLineEnding(text);
- HStringReference textRef(reinterpret_cast<LPCWSTR>(nativeString.utf16()), nativeString.length());
+ 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.");
diff --git a/src/plugins/platforms/winrt/qwinrtcursor.cpp b/src/plugins/platforms/winrt/qwinrtcursor.cpp
index 3c918df935..180905945b 100644
--- a/src/plugins/platforms/winrt/qwinrtcursor.cpp
+++ b/src/plugins/platforms/winrt/qwinrtcursor.cpp
@@ -56,6 +56,11 @@ 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:
@@ -73,10 +78,6 @@ QWinRTCursor::QWinRTCursor()
Q_ASSERT_SUCCEEDED(hr);
}
-QWinRTCursor::~QWinRTCursor()
-{
-}
-
#ifndef QT_NO_CURSOR
void QWinRTCursor::changeCursor(QCursor *windowCursor, QWindow *window)
{
@@ -169,14 +170,60 @@ QPoint QWinRTCursor::pos() const
ICoreWindow *coreWindow = screen->coreWindow();
Q_ASSERT(coreWindow);
Point point;
- HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([coreWindow, &point]() {
- return coreWindow->get_PointerPosition(&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);
- const QPoint position = QPoint(point.X, point.Y) * screen->scaleFactor();
+ QPointF position(qreal(point.X), qreal(point.Y));
// If no cursor get_PointerPosition returns SHRT_MIN for x and y
- return position.x() == SHRT_MIN && position.y() == SHRT_MIN || FAILED(hr) ? QPointF(Q_INFINITY, Q_INFINITY).toPoint()
- : position;
+ 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
index 7f579f1531..eca3d8c7ca 100644
--- a/src/plugins/platforms/winrt/qwinrtcursor.h
+++ b/src/plugins/platforms/winrt/qwinrtcursor.h
@@ -49,11 +49,12 @@ class QWinRTCursor : public QPlatformCursor
{
public:
explicit QWinRTCursor();
- ~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;
diff --git a/src/plugins/platforms/winrt/qwinrtdrag.cpp b/src/plugins/platforms/winrt/qwinrtdrag.cpp
index 0c918230b3..3ed4cd692d 100644
--- a/src/plugins/platforms/winrt/qwinrtdrag.cpp
+++ b/src/plugins/platforms/winrt/qwinrtdrag.cpp
@@ -81,7 +81,7 @@ ComPtr<IBuffer> createIBufferFromData(const char *data, qint32 size)
}
ComPtr<IBuffer> buffer;
- const UINT32 length = size;
+ const UINT32 length = UINT32(size);
hr = bufferFactory->Create(length, &buffer);
Q_ASSERT_SUCCEEDED(hr);
hr = buffer->put_Length(length);
@@ -118,13 +118,13 @@ inline QString hStringToQString(const HString &hString)
{
quint32 l;
const wchar_t *raw = hString.GetRawBuffer(&l);
- return (QString::fromWCharArray(raw, l));
+ return (QString::fromWCharArray(raw, int(l)));
}
inline HString qStringToHString(const QString &qString)
{
HString h;
- h.Set(reinterpret_cast<const wchar_t*>(qString.utf16()), qString.size());
+ h.Set(reinterpret_cast<const wchar_t*>(qString.utf16()), uint(qString.size()));
return h;
}
@@ -184,10 +184,6 @@ QWinRTInternalMimeData::QWinRTInternalMimeData()
}
}
-QWinRTInternalMimeData::~QWinRTInternalMimeData()
-{
-}
-
bool QWinRTInternalMimeData::hasFormat_sys(const QString &mimetype) const
{
qCDebug(lcQpaMime) << __FUNCTION__ << mimetype;
@@ -311,7 +307,7 @@ QVariant QWinRTInternalMimeData::retrieveData_sys(const QString &mimetype, QVari
ComPtr<IAsyncOperation<IInspectable*>> op;
ComPtr<IInspectable> res;
HString type;
- type.Set(reinterpret_cast<const wchar_t*>(mimetype.utf16()), mimetype.size());
+ 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());
@@ -434,7 +430,7 @@ QVariant QWinRTInternalMimeData::retrieveData_sys(const QString &mimetype, QVari
IID_PPV_ARGS(&bufferFactory));
Q_ASSERT_SUCCEEDED(hr);
- UINT32 length = qBound(quint64(0), quint64(size), quint64(UINT_MAX));
+ UINT32 length = UINT32(qBound(quint64(0), quint64(size), quint64(UINT_MAX)));
ComPtr<IBuffer> buffer;
hr = bufferFactory->Create(length, &buffer);
Q_ASSERT_SUCCEEDED(hr);
@@ -452,7 +448,7 @@ QVariant QWinRTInternalMimeData::retrieveData_sys(const QString &mimetype, QVari
byte *bytes;
hr = byteArrayAccess->Buffer(&bytes);
- QByteArray array((char *)bytes, length);
+ QByteArray array((char *)bytes, int(length));
result.setValue(array);
return S_OK;
}
@@ -559,7 +555,7 @@ extern ComPtr<ABI::Windows::UI::Input::IPointerPoint> qt_winrt_lastPointerPoint;
QWinRTDrag::QWinRTDrag()
: QPlatformDrag()
- , m_dragTarget(0)
+ , m_dragTarget(nullptr)
{
qCDebug(lcQpaMime) << __FUNCTION__;
m_enter = new Q_INST_DRAGHANDLER(Enter);
@@ -612,7 +608,7 @@ Qt::DropAction QWinRTDrag::drag(QDrag *drag)
ComPtr<IAsyncOperation<ABI::Windows::ApplicationModel::DataTransfer::DataPackageOperation>> op;
EventRegistrationToken startingToken;
- hr = QEventDispatcherWinRT::runOnXamlThread([drag, &op, &hr, elem3, &startingToken, this]() {
+ hr = QEventDispatcherWinRT::runOnXamlThread([drag, &op, &hr, elem3, &startingToken]() {
hr = elem3->put_CanDrag(true);
Q_ASSERT_SUCCEEDED(hr);
@@ -660,7 +656,8 @@ Qt::DropAction QWinRTDrag::drag(QDrag *drag)
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()), image.byteCount());
+ 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(),
@@ -697,7 +694,7 @@ Qt::DropAction QWinRTDrag::drag(QDrag *drag)
hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_InMemoryRandomAccessStream).Get(), &ras);
Q_ASSERT_SUCCEEDED(hr);
- hr = ras->put_Size(data.size());
+ hr = ras->put_Size(UINT64(data.size()));
ComPtr<IOutputStream> outputStream;
hr = ras->GetOutputStreamAt(0, &outputStream);
Q_ASSERT_SUCCEEDED(hr);
@@ -802,7 +799,7 @@ void QWinRTDrag::handleNativeDragEvent(IInspectable *sender, ABI::Windows::UI::X
Point relativePoint;
hr = e->GetPosition(m_ui.Get(), &relativePoint);
RETURN_VOID_IF_FAILED("Could not query drag position.");
- const QPoint p(relativePoint.X, relativePoint.Y);
+ const QPoint p(int(relativePoint.X), int(relativePoint.Y));
ComPtr<IDragEventArgs2> e2;
hr = e->QueryInterface(IID_PPV_ARGS(&e2));
diff --git a/src/plugins/platforms/winrt/qwinrtdrag.h b/src/plugins/platforms/winrt/qwinrtdrag.h
index 3868c9f015..ab57999bba 100644
--- a/src/plugins/platforms/winrt/qwinrtdrag.h
+++ b/src/plugins/platforms/winrt/qwinrtdrag.h
@@ -77,7 +77,7 @@ class QWinRTInternalMimeData;
class QWinRTInternalMimeData : public QInternalMimeData {
public:
QWinRTInternalMimeData();
- virtual ~QWinRTInternalMimeData();
+ ~QWinRTInternalMimeData() override = default;
bool hasFormat_sys(const QString &mimetype) const override;
QStringList formats_sys() const override;
@@ -92,7 +92,7 @@ private:
class QWinRTDrag : public QPlatformDrag {
public:
QWinRTDrag();
- virtual ~QWinRTDrag();
+ ~QWinRTDrag() override;
static QWinRTDrag *instance();
Qt::DropAction drag(QDrag *) override;
diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.h b/src/plugins/platforms/winrt/qwinrteglcontext.h
index 325dc82c40..8dbd0fc7d0 100644
--- a/src/plugins/platforms/winrt/qwinrteglcontext.h
+++ b/src/plugins/platforms/winrt/qwinrteglcontext.h
@@ -50,7 +50,7 @@ class QWinRTEGLContext : public QPlatformOpenGLContext
{
public:
explicit QWinRTEGLContext(QOpenGLContext *context);
- ~QWinRTEGLContext();
+ ~QWinRTEGLContext() override;
void initialize() override;
diff --git a/src/plugins/platforms/winrt/qwinrteventdispatcher.h b/src/plugins/platforms/winrt/qwinrteventdispatcher.h
index 4c5c19c6b0..61c824f0a9 100644
--- a/src/plugins/platforms/winrt/qwinrteventdispatcher.h
+++ b/src/plugins/platforms/winrt/qwinrteventdispatcher.h
@@ -48,7 +48,7 @@ class QWinRTEventDispatcher : public QEventDispatcherWinRT
{
Q_OBJECT
public:
- explicit QWinRTEventDispatcher(QObject *parent = 0);
+ explicit QWinRTEventDispatcher(QObject *parent = nullptr);
protected:
bool hasPendingEvents() override;
diff --git a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp
index 3c90334c8c..114d6dacd8 100644
--- a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp
+++ b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp
@@ -51,7 +51,7 @@
#include <wrl.h>
#include <windows.foundation.h>
#include <windows.storage.pickers.h>
-#include <Windows.ApplicationModel.activation.h>
+#include <Windows.Applicationmodel.Activation.h>
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
@@ -73,12 +73,12 @@ class WindowsStringVector : public RuntimeClass<IVector<HSTRING>>
public:
HRESULT __stdcall GetAt(quint32 index, HSTRING *item)
{
- *item = impl.at(index);
+ *item = impl.at(int(index));
return S_OK;
}
HRESULT __stdcall get_Size(quint32 *size)
{
- *size = impl.size();
+ *size = quint32(impl.size());
return S_OK;
}
HRESULT __stdcall GetView(IVectorView<HSTRING> **view)
@@ -108,7 +108,7 @@ public:
HRESULT hr = WindowsDuplicateString(item, &newItem);
if (FAILED(hr))
return hr;
- impl[index] = newItem;
+ impl[int(index)] = newItem;
return S_OK;
}
HRESULT __stdcall InsertAt(quint32 index, HSTRING item)
@@ -117,12 +117,12 @@ public:
HRESULT hr = WindowsDuplicateString(item, &newItem);
if (FAILED(hr))
return hr;
- impl.insert(index, newItem);
+ impl.insert(int(index), newItem);
return S_OK;
}
HRESULT __stdcall RemoveAt(quint32 index)
{
- WindowsDeleteString(impl.takeAt(index));
+ WindowsDeleteString(impl.takeAt(int(index)));
return S_OK;
}
HRESULT __stdcall Append(HSTRING item)
@@ -164,7 +164,7 @@ static bool initializePicker(HSTRING runtimeId, T **picker, const QSharedPointer
if (options->isLabelExplicitlySet(QFileDialogOptions::Accept)) {
const QString labelText = options->labelText(QFileDialogOptions::Accept);
HStringReference labelTextRef(reinterpret_cast<const wchar_t *>(labelText.utf16()),
- labelText.length());
+ uint(labelText.length()));
hr = (*picker)->put_CommitButtonText(labelTextRef.Get());
RETURN_FALSE_IF_FAILED("Failed to set commit button text");
}
@@ -188,7 +188,7 @@ static bool initializeOpenPickerOptions(T *picker, const QSharedPointer<QFileDia
// Remove leading star
const int offset = (filter.length() > 1 && filter.startsWith(QLatin1Char('*'))) ? 1 : 0;
HStringReference filterRef(reinterpret_cast<const wchar_t *>(filter.utf16() + offset),
- filter.length() - offset);
+ uint(filter.length() - offset));
hr = filters->Append(filterRef.Get());
if (FAILED(hr)) {
qWarning("Failed to add named file filter \"%s\": %s",
@@ -290,16 +290,12 @@ QWinRTFileDialogHelper::QWinRTFileDialogHelper()
d->shown = false;
}
-QWinRTFileDialogHelper::~QWinRTFileDialogHelper()
-{
-}
-
void QWinRTFileDialogHelper::exec()
{
Q_D(QWinRTFileDialogHelper);
if (!d->shown)
- show(Qt::Dialog, Qt::ApplicationModal, 0);
+ show(Qt::Dialog, Qt::ApplicationModal, nullptr);
d->loop.exec();
}
@@ -369,7 +365,7 @@ bool QWinRTFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModalit
// Remove leading star
const int starOffset = (filter.length() > 1 && filter.startsWith(QLatin1Char('*'))) ? 1 : 0;
HStringReference filterRef(reinterpret_cast<const wchar_t *>(filter.utf16() + starOffset),
- filter.length() - starOffset);
+ uint(filter.length() - starOffset));
hr = entry->Append(filterRef.Get());
if (FAILED(hr)) {
qWarning("Failed to add named file filter \"%s\": %s",
@@ -379,7 +375,7 @@ bool QWinRTFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModalit
const int offset = namedFilter.indexOf(QLatin1String(" ("));
const QString filterTitle = namedFilter.mid(0, offset);
HStringReference namedFilterRef(reinterpret_cast<const wchar_t *>(filterTitle.utf16()),
- filterTitle.length());
+ 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
@@ -396,7 +392,7 @@ bool QWinRTFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModalit
if (!suffix.startsWith(QLatin1Char('.')))
suffix.prepend(QLatin1Char('.'));
HStringReference nativeSuffix(reinterpret_cast<const wchar_t *>(suffix.utf16()),
- suffix.length());
+ uint(suffix.length()));
hr = picker->put_DefaultFileExtension(nativeSuffix.Get());
RETURN_FALSE_IF_FAILED_WITH_ARGS("Failed to set default file extension \"%s\"", qPrintable(suffix));
}
@@ -404,7 +400,7 @@ bool QWinRTFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModalit
const QString suggestedName = QFileInfo(d->saveFileName.toLocalFile()).fileName();
if (!suggestedName.isEmpty()) {
HStringReference nativeSuggestedName(reinterpret_cast<const wchar_t *>(suggestedName.utf16()),
- suggestedName.length());
+ uint(suggestedName.length()));
hr = picker->put_SuggestedFileName(nativeSuggestedName.Get());
RETURN_FALSE_IF_FAILED("Failed to set suggested file name");
}
diff --git a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h
index 99239aad3a..994d099dcf 100644
--- a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h
+++ b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h
@@ -70,7 +70,7 @@ class QWinRTFileDialogHelper : public QPlatformFileDialogHelper
Q_OBJECT
public:
explicit QWinRTFileDialogHelper();
- ~QWinRTFileDialogHelper();
+ ~QWinRTFileDialogHelper() override = default;
void exec() override;
bool show(Qt::WindowFlags, Qt::WindowModality, QWindow *) override;
diff --git a/src/plugins/platforms/winrt/qwinrtfileengine.cpp b/src/plugins/platforms/winrt/qwinrtfileengine.cpp
index 76efdf6cc8..3014b30c38 100644
--- a/src/plugins/platforms/winrt/qwinrtfileengine.cpp
+++ b/src/plugins/platforms/winrt/qwinrtfileengine.cpp
@@ -122,10 +122,6 @@ QWinRTFileEngineHandler::QWinRTFileEngineHandler()
{
}
-QWinRTFileEngineHandler::~QWinRTFileEngineHandler()
-{
-}
-
void QWinRTFileEngineHandler::registerFile(const QString &fileName, IStorageItem *file)
{
handlerInstance->d_func()->files.insert(QDir::cleanPath(fileName), file);
@@ -168,7 +164,7 @@ static HRESULT getDestinationFolder(const QString &fileName, const QString &newF
const QString newFilePath = QDir::toNativeSeparators(newFileInfo.absolutePath());
HStringReference nativeNewFilePath(reinterpret_cast<LPCWSTR>(newFilePath.utf16()),
- newFilePath.length());
+ uint(newFilePath.length()));
hr = folderFactory->GetFolderFromPathAsync(nativeNewFilePath.Get(), &op);
}
if (FAILED(hr))
@@ -181,10 +177,6 @@ QWinRTFileEngine::QWinRTFileEngine(const QString &fileName, IStorageItem *file)
{
}
-QWinRTFileEngine::~QWinRTFileEngine()
-{
-}
-
bool QWinRTFileEngine::open(QIODevice::OpenMode openMode)
{
Q_D(QWinRTFileEngine);
@@ -278,7 +270,7 @@ bool QWinRTFileEngine::seek(qint64 pos)
if (!d->stream)
return false;
- HRESULT hr = d->stream->Seek(pos);
+ HRESULT hr = d->stream->Seek(UINT64(pos));
RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::PositionError, false);
d->pos = pos;
return SUCCEEDED(hr);
@@ -311,7 +303,8 @@ bool QWinRTFileEngine::copy(const QString &newName)
RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::CopyError, false);
const QString destinationName = QFileInfo(newName).fileName();
- HStringReference nativeDestinationName(reinterpret_cast<LPCWSTR>(destinationName.utf16()), destinationName.length());
+ 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);
@@ -332,7 +325,8 @@ bool QWinRTFileEngine::rename(const QString &newName)
RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RenameError, false);
const QString destinationName = QFileInfo(newName).fileName();
- HStringReference nativeDestinationName(reinterpret_cast<LPCWSTR>(destinationName.utf16()), destinationName.length());
+ 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);
@@ -349,7 +343,8 @@ bool QWinRTFileEngine::renameOverwrite(const QString &newName)
RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::RenameError, false);
const QString destinationName = QFileInfo(newName).fileName();
- HStringReference nativeDestinationName(reinterpret_cast<LPCWSTR>(destinationName.utf16()), destinationName.length());
+ 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);
@@ -451,7 +446,7 @@ qint64 QWinRTFileEngine::read(char *data, qint64 maxlen)
HRESULT hr = d->stream.As(&stream);
RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1);
- UINT32 length = qBound(quint64(0), quint64(maxlen), quint64(UINT_MAX));
+ 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);
@@ -494,7 +489,7 @@ qint64 QWinRTFileEngine::write(const char *data, qint64 maxlen)
HRESULT hr = d->stream.As(&stream);
RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::WriteError, -1);
- UINT32 length = qBound(quint64(0), quint64(maxlen), quint64(UINT_MAX));
+ 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);
diff --git a/src/plugins/platforms/winrt/qwinrtfileengine.h b/src/plugins/platforms/winrt/qwinrtfileengine.h
index 73ff54b0c8..4485917c9e 100644
--- a/src/plugins/platforms/winrt/qwinrtfileengine.h
+++ b/src/plugins/platforms/winrt/qwinrtfileengine.h
@@ -57,7 +57,7 @@ class QWinRTFileEngineHandler : public QAbstractFileEngineHandler
{
public:
QWinRTFileEngineHandler();
- ~QWinRTFileEngineHandler();
+ ~QWinRTFileEngineHandler() override = default;
QAbstractFileEngine *create(const QString &fileName) const override;
static void registerFile(const QString &fileName, ABI::Windows::Storage::IStorageItem *file);
@@ -73,7 +73,7 @@ class QWinRTFileEngine : public QAbstractFileEngine
{
public:
QWinRTFileEngine(const QString &fileName, ABI::Windows::Storage::IStorageItem *file);
- ~QWinRTFileEngine();
+ ~QWinRTFileEngine() override = default;
bool open(QIODevice::OpenMode openMode) override;
bool close() override;
diff --git a/src/plugins/platforms/winrt/qwinrtinputcontext.cpp b/src/plugins/platforms/winrt/qwinrtinputcontext.cpp
index 63e5b0cf27..f7e91bb047 100644
--- a/src/plugins/platforms/winrt/qwinrtinputcontext.cpp
+++ b/src/plugins/platforms/winrt/qwinrtinputcontext.cpp
@@ -64,8 +64,8 @@ inline QRectF getInputPaneRect(ComPtr<IInputPane> pane, qreal scaleFactor)
{
Rect rect;
pane->get_OccludedRect(&rect);
- return QRectF(qRound(rect.X * scaleFactor), qRound(rect.Y * scaleFactor),
- qRound(rect.Width * scaleFactor), qRound(rect.Height * scaleFactor));
+ return QRectF(qRound(qreal(rect.X) * scaleFactor), qRound(qreal(rect.Y) * scaleFactor),
+ qRound(qreal(rect.Width) * scaleFactor), qRound(qreal(rect.Height) * scaleFactor));
}
/*!
@@ -205,6 +205,8 @@ void QWinRTInputContext::showInputPanel()
void QWinRTInputContext::hideInputPanel()
{
qCDebug(lcQpaInputMethods) << __FUNCTION__;
+ if (!m_isInputPanelVisible)
+ return;
QEventDispatcherWinRT::runOnXamlThread([&]() {
ComPtr<IInputPane2> inputPane;
diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp
index c52207d23b..4f37583bed 100644
--- a/src/plugins/platforms/winrt/qwinrtintegration.cpp
+++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp
@@ -50,6 +50,9 @@
#if QT_CONFIG(draganddrop)
#include "qwinrtdrag.h"
#endif
+#if QT_CONFIG(accessibility)
+# include "uiautomation/qwinrtuiaaccessibility.h"
+#endif
#include <QtGui/QOffscreenSurface>
#include <QtGui/QOpenGLContext>
@@ -119,6 +122,9 @@ public:
QPlatformClipboard *clipboard;
QWinRTScreen *mainScreen;
QScopedPointer<QWinRTInputContext> inputContext;
+#if QT_CONFIG(accessibility)
+ QWinRTUiaAccessibility *accessibility;
+#endif
ComPtr<ICoreApplication> application;
QHash<CoreApplicationCallbackRemover, EventRegistrationToken> applicationTokens;
@@ -198,6 +204,9 @@ QWinRTIntegration::QWinRTIntegration() : d_ptr(new QWinRTIntegrationPrivate)
screenAdded(d->mainScreen);
d->platformServices = new QWinRTServices;
d->clipboard = new QWinRTClipboard;
+#if QT_CONFIG(accessibility)
+ d->accessibility = new QWinRTUiaAccessibility;
+#endif
}
QWinRTIntegration::~QWinRTIntegration()
@@ -315,6 +324,14 @@ QPlatformDrag *QWinRTIntegration::drag() const
}
#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);
diff --git a/src/plugins/platforms/winrt/qwinrtintegration.h b/src/plugins/platforms/winrt/qwinrtintegration.h
index d1a9b7edbd..636e594b4b 100644
--- a/src/plugins/platforms/winrt/qwinrtintegration.h
+++ b/src/plugins/platforms/winrt/qwinrtintegration.h
@@ -75,7 +75,7 @@ class QWinRTIntegration : public QPlatformIntegration
private:
explicit QWinRTIntegration();
public:
- ~QWinRTIntegration();
+ ~QWinRTIntegration() override;
static QWinRTIntegration *create()
{
@@ -100,6 +100,9 @@ public:
#if QT_CONFIG(draganddrop)
QPlatformDrag *drag() const override;
#endif
+#if QT_CONFIG(accessibility)
+ QPlatformAccessibility *accessibility() const override;
+#endif
Qt::KeyboardModifiers queryKeyboardModifiers() const override;
diff --git a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp
index d69c63e9a4..7016b47f7e 100644
--- a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp
+++ b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp
@@ -99,7 +99,7 @@ void QWinRTMessageDialogHelper::exec()
Q_D(QWinRTMessageDialogHelper);
if (!d->shown)
- show(Qt::Dialog, Qt::ApplicationModal, 0);
+ show(Qt::Dialog, Qt::ApplicationModal, nullptr);
d->loop.exec();
}
@@ -134,9 +134,11 @@ bool QWinRTMessageDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModa
RETURN_FALSE_IF_FAILED("Failed to create command factory");
ComPtr<IMessageDialog> dialog;
- HStringReference nativeText(reinterpret_cast<LPCWSTR>(text.utf16()), text.size());
+ HStringReference nativeText(reinterpret_cast<LPCWSTR>(text.utf16()),
+ uint(text.size()));
if (!title.isEmpty()) {
- HStringReference nativeTitle(reinterpret_cast<LPCWSTR>(title.utf16()), title.size());
+ 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 {
@@ -162,7 +164,8 @@ bool QWinRTMessageDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModa
continue;
// Add native command
const QString label = d->theme->standardButtonText(i);
- HStringReference nativeLabel(reinterpret_cast<LPCWSTR>(label.utf16()), label.size());
+ 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");
diff --git a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h
index 14b6d4b715..ab704b1c7d 100644
--- a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h
+++ b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h
@@ -67,7 +67,7 @@ class QWinRTMessageDialogHelper : public QPlatformMessageDialogHelper
Q_OBJECT
public:
explicit QWinRTMessageDialogHelper(const QWinRTTheme *theme);
- ~QWinRTMessageDialogHelper();
+ ~QWinRTMessageDialogHelper() override;
void exec() override;
bool show(Qt::WindowFlags windowFlags,
diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp
index e39a87148a..bd2bbcb81c 100644
--- a/src/plugins/platforms/winrt/qwinrtscreen.cpp
+++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp
@@ -46,9 +46,11 @@
#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>
@@ -99,6 +101,31 @@ typedef ITypedEventHandler<ApplicationView*, IInspectable*> VisibleBoundsChanged
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()
{
@@ -463,7 +490,7 @@ public:
QTouchDevice *touchDevice;
ComPtr<ICoreWindow> coreWindow;
ComPtr<ICorePointerRedirector> redirect;
- ComPtr<Xaml::IDependencyObject> canvas;
+ ComPtr<QWinRTCanvas> canvas;
ComPtr<IApplicationView> view;
ComPtr<IDisplayInformation> displayInformation;
@@ -490,6 +517,7 @@ public:
QAtomicPointer<QWinRTWindow> keyboardGrabWindow;
QWindow *currentPressWindow = nullptr;
QWindow *currentTargetWindow = nullptr;
+ bool firstMouseMove = true;
};
// To be called from the XAML thread
@@ -553,27 +581,25 @@ QWinRTScreen::QWinRTScreen()
hr = applicationViewStatics->GetForCurrentView(&d->view);
RETURN_VOID_IF_FAILED("Could not access currentView");
- // Create a canvas and set it as the window content. Eventually, this should have its own method so multiple "screens" can be added
- ComPtr<Xaml::Controls::ICanvas> canvas;
- hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_Canvas).Get(), &canvas);
- Q_ASSERT_SUCCEEDED(hr);
+ d->canvas = Make<QWinRTCanvas>([this]() { return topWindow(); });
+
ComPtr<Xaml::IFrameworkElement> frameworkElement;
- hr = canvas.As(&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 = canvas.As(&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);
- hr = canvas.As(&d->canvas);
- Q_ASSERT_SUCCEEDED(hr);
d->cursor.reset(new QWinRTCursor);
@@ -723,7 +749,10 @@ ICoreWindow *QWinRTScreen::coreWindow() const
Xaml::IDependencyObject *QWinRTScreen::canvas() const
{
Q_D(const QWinRTScreen);
- return d->canvas.Get();
+ Xaml::IDependencyObject *depCanvas;
+ if (SUCCEEDED(d->canvas.CopyTo(&depCanvas)))
+ return depCanvas;
+ return nullptr;
}
void QWinRTScreen::initialize()
@@ -848,6 +877,7 @@ void QWinRTScreen::addWindow(QWindow *window)
}
handleExpose();
+ d->firstMouseMove = true;
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
#if QT_CONFIG(draganddrop)
@@ -860,6 +890,8 @@ void QWinRTScreen::removeWindow(QWindow *window)
Q_D(QWinRTScreen);
qCDebug(lcQpaWindows) << __FUNCTION__ << window;
+ handleExpose();
+
const bool wasTopWindow = window == topWindow();
if (!d->visibleWindows.removeAll(window))
return;
@@ -867,7 +899,6 @@ void QWinRTScreen::removeWindow(QWindow *window)
const Qt::WindowType type = window->type();
if (wasTopWindow && type != Qt::Popup && type != Qt::ToolTip && type != Qt::Tool)
QWindowSystemInterface::handleWindowActivated(nullptr, Qt::OtherFocusReason);
- handleExpose();
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
#if QT_CONFIG(draganddrop)
if (wasTopWindow)
@@ -1075,6 +1106,7 @@ HRESULT QWinRTScreen::onCharacterReceived(ICoreWindow *, ICharacterReceivedEvent
HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *, IPointerEventArgs *args)
{
Q_D(QWinRTScreen);
+ qCDebug(lcQpaEvents) << __FUNCTION__;
ComPtr<IPointerPoint> pointerPoint;
if (SUCCEEDED(args->get_CurrentPoint(&pointerPoint))) {
@@ -1087,7 +1119,9 @@ HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *, IPointerEventArgs *args)
if (d->mouseGrabWindow)
d->currentTargetWindow = d->mouseGrabWindow.load()->window();
+ qCDebug(lcQpaEvents) << __FUNCTION__ << "handleEnterEvent" << d->currentTargetWindow << pos;
QWindowSystemInterface::handleEnterEvent(d->currentTargetWindow, pos, pos);
+ d->firstMouseMove = false;
}
return S_OK;
}
@@ -1095,7 +1129,7 @@ HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *, IPointerEventArgs *args)
HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *args)
{
Q_D(QWinRTScreen);
-
+ qCDebug(lcQpaEvents) << __FUNCTION__;
ComPtr<IPointerPoint> pointerPoint;
if (FAILED(args->get_CurrentPoint(&pointerPoint)))
return E_INVALIDARG;
@@ -1109,6 +1143,7 @@ HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *args)
if (d->mouseGrabWindow)
d->currentTargetWindow = d->mouseGrabWindow.load()->window();
+ qCDebug(lcQpaEvents) << __FUNCTION__ << "handleLeaveEvent" << d->currentTargetWindow;
QWindowSystemInterface::handleLeaveEvent(d->currentTargetWindow);
d->currentTargetWindow = nullptr;
return S_OK;
@@ -1120,6 +1155,7 @@ 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;
@@ -1175,6 +1211,8 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args)
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;
}
@@ -1213,6 +1251,8 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args)
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;
}
@@ -1224,6 +1264,8 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args)
d->currentPressWindow = nullptr;
}
+ qCDebug(lcQpaEvents) << __FUNCTION__ << "handleMouseEvent" << d->currentTargetWindow
+ << localPos << pos << buttons << mods;
QWindowSystemInterface::handleMouseEvent(d->currentTargetWindow, localPos, pos, buttons, mods);
break;
@@ -1280,6 +1322,8 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args)
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;
@@ -1301,6 +1345,9 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args)
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);
@@ -1312,6 +1359,70 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args)
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.load()->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);
+}
+
HRESULT QWinRTScreen::onActivated(ICoreWindow *, IWindowActivatedEventArgs *args)
{
Q_D(QWinRTScreen);
@@ -1413,6 +1524,7 @@ HRESULT QWinRTScreen::onRedirectReleased(ICorePointerRedirector *, IPointerEvent
{
// When dragging ends with a non-mouse input device then onRedirectRelease is invoked.
// QTBUG-58781
+ qCDebug(lcQpaEvents) << __FUNCTION__;
return onPointerUpdated(nullptr, args);
}
diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h
index fd6499c2b9..cde148a638 100644
--- a/src/plugins/platforms/winrt/qwinrtscreen.h
+++ b/src/plugins/platforms/winrt/qwinrtscreen.h
@@ -89,7 +89,7 @@ class QWinRTScreen : public QPlatformScreen
{
public:
explicit QWinRTScreen();
- ~QWinRTScreen();
+ ~QWinRTScreen() override;
QRect geometry() const override;
QRect availableGeometry() const override;
@@ -128,6 +128,15 @@ public:
void setCursorRect(const QRectF &cursorRect);
void setKeyboardRect(const QRectF &keyboardRect);
+ enum class MousePositionTransition {
+ MovedOut,
+ MovedIn,
+ StayedIn,
+ StayedOut
+ };
+
+ void emulateMouseMove(const QPointF &point, MousePositionTransition transition);
+
private:
void handleExpose();
diff --git a/src/plugins/platforms/winrt/qwinrtservices.cpp b/src/plugins/platforms/winrt/qwinrtservices.cpp
index 05620ca4c8..b27c408f40 100644
--- a/src/plugins/platforms/winrt/qwinrtservices.cpp
+++ b/src/plugins/platforms/winrt/qwinrtservices.cpp
@@ -83,17 +83,14 @@ QWinRTServices::QWinRTServices()
Q_ASSERT_X(SUCCEEDED(hr), Q_FUNC_INFO, qPrintable(qt_error_string(hr)));
}
-QWinRTServices::~QWinRTServices()
-{
-}
-
bool QWinRTServices::openUrl(const QUrl &url)
{
Q_D(QWinRTServices);
ComPtr<IUriRuntimeClass> uri;
QString urlString = url.toString();
- HStringReference uriString(reinterpret_cast<LPCWSTR>(urlString.utf16()), urlString.length());
+ 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.");
@@ -122,7 +119,8 @@ bool QWinRTServices::openDocument(const QUrl &url)
}
if (!file) {
const QString pathString = QDir::toNativeSeparators(url.toLocalFile());
- HStringReference path(reinterpret_cast<LPCWSTR>(pathString.utf16()), pathString.length());
+ 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.");
diff --git a/src/plugins/platforms/winrt/qwinrtservices.h b/src/plugins/platforms/winrt/qwinrtservices.h
index 80b9a6c92a..202ce722cf 100644
--- a/src/plugins/platforms/winrt/qwinrtservices.h
+++ b/src/plugins/platforms/winrt/qwinrtservices.h
@@ -50,7 +50,7 @@ class QWinRTServices : public QPlatformServices
{
public:
explicit QWinRTServices();
- ~QWinRTServices();
+ ~QWinRTServices() override = default;
bool openUrl(const QUrl &url) override;
bool openDocument(const QUrl &url) override;
diff --git a/src/plugins/platforms/winrt/qwinrtwindow.cpp b/src/plugins/platforms/winrt/qwinrtwindow.cpp
index cbf0ba36c9..29d234d276 100644
--- a/src/plugins/platforms/winrt/qwinrtwindow.cpp
+++ b/src/plugins/platforms/winrt/qwinrtwindow.cpp
@@ -126,7 +126,7 @@ QWinRTWindow::QWinRTWindow(QWindow *window)
hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_Canvas).Get(),
IID_PPV_ARGS(&d->canvas));
Q_ASSERT_SUCCEEDED(hr);
- hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() {
+ 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(),
diff --git a/src/plugins/platforms/winrt/qwinrtwindow.h b/src/plugins/platforms/winrt/qwinrtwindow.h
index 9604b4bbaa..0445e6bf54 100644
--- a/src/plugins/platforms/winrt/qwinrtwindow.h
+++ b/src/plugins/platforms/winrt/qwinrtwindow.h
@@ -54,7 +54,7 @@ class QWinRTWindow : public QPlatformWindow
{
public:
QWinRTWindow(QWindow *window);
- ~QWinRTWindow();
+ ~QWinRTWindow() override;
QSurfaceFormat format() const override;
bool isActive() const override;
diff --git a/src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.cpp b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.cpp
new file mode 100644
index 0000000000..40274fb967
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.cpp
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..b966271e21
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaaccessibility.h
@@ -0,0 +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$
+**
+****************************************************************************/
+
+#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
new file mode 100644
index 0000000000..ee53714caa
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..d8837354dc
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiabaseprovider.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..4e406a3545
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.cpp
@@ -0,0 +1,182 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..769f073a1b
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiacontrolmetadata.h
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..35e4df75fc
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaemptypropertyvalue.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..524000b618
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.cpp
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** 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>
+
+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 = QSharedPointer<QAccessible::Id>(new QAccessible::Id(0));
+ auto ptrElementId = new QSharedPointer<QAccessible::Id>(elementId);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementId]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid)) {
+ if (QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface()) {
+ if (QAccessibleInterface *table = tableCellInterface->table()) {
+ **ptrElementId = idForAccessible(table);
+ QWinRTUiaMetadataCache::instance()->load(**ptrElementId);
+ }
+ }
+ }
+ delete ptrElementId;
+ 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
new file mode 100644
index 0000000000..70504fc555
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagriditemprovider.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..e469991de2
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.cpp
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** 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>
+
+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 = QSharedPointer<QAccessible::Id>(new QAccessible::Id(0));
+ auto ptrElementId = new QSharedPointer<QAccessible::Id>(elementId);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, row, column, ptrElementId]() {
+ 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)) {
+ **ptrElementId = idForAccessible(cell);
+ QWinRTUiaMetadataCache::instance()->load(**ptrElementId);
+ }
+ }
+ }
+ }
+ delete ptrElementId;
+ 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
new file mode 100644
index 0000000000..d6dfaed315
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiagridprovider.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..e2cf7bc107
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.cpp
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..dfe7917a16
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiainvokeprovider.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..6f3ad6dcd2
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.cpp
@@ -0,0 +1,789 @@
+/****************************************************************************
+**
+** 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>
+
+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 QList<QAccessible::Id> &elementIds,
+ UINT32 *returnValueSize,
+ IIRawElementProviderSimple ***returnValue)
+{
+ if (!returnValueSize || !returnValue)
+ return E_INVALIDARG;
+ *returnValueSize = 0;
+ *returnValue = nullptr;
+
+ QList<IIRawElementProviderSimple *> rawProviderList;
+
+ for (auto elementId : qAsConst(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 = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>);
+ auto ptrChildren = new QSharedPointer<QList<QAccessible::Id>>(children);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrChildren]() {
+ 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)
+ (*ptrChildren)->append(childId);
+ }
+ }
+ }
+ delete ptrChildren;
+ return S_OK;
+ }))) {
+ return E_FAIL;
+ }
+
+ ComPtr<IVector<AutomationPeer *>> peerVector = Make<QWinRTUiaPeerVector>();
+
+ for (auto childId : qAsConst(*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 = QSharedPointer<QAccessible::Id>(new QAccessible::Id(0));
+ auto ptrElementId = new QSharedPointer<QAccessible::Id>(elementId);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementId, 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;
+ }
+ **ptrElementId = idForAccessible(target);
+ QWinRTUiaMetadataCache::instance()->load(**ptrElementId);
+ delete ptrElementId;
+ 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
new file mode 100644
index 0000000000..384a166cf7
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiamainprovider.h
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** 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 QList<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
new file mode 100644
index 0000000000..442ff184a8
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.cpp
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..2d68d1b654
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiametadatacache.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..e3d6bcae4b
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.cpp
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..265526de09
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiapeervector.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..06ff094c45
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.cpp
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..393ef7d562
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaprovidercache.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..4ac59c890a
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.cpp
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..4e98959526
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiarangevalueprovider.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..9bc88272ba
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.cpp
@@ -0,0 +1,214 @@
+/****************************************************************************
+**
+** 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>
+
+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 = QSharedPointer<QAccessible::Id>(new QAccessible::Id(0));
+ auto ptrElementId = new QSharedPointer<QAccessible::Id>(elementId);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementId]() {
+ 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) {
+ **ptrElementId = idForAccessible(parent);
+ }
+ }
+ }
+ }
+ delete ptrElementId;
+ 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
new file mode 100644
index 0000000000..1b3cce7495
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionitemprovider.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..9e61a8df61
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.cpp
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** 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>
+
+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 = QSharedPointer<bool>(new bool(false));
+ auto ptrSelectionRequired = new QSharedPointer<bool>(selectionRequired);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrSelectionRequired]() {
+ // 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;
+ }
+ }
+ }
+ **ptrSelectionRequired = anySelected && !accessible->state().multiSelectable && !accessible->state().extSelectable;
+ }
+ delete ptrSelectionRequired;
+ 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 = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>);
+ auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() {
+ 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);
+ (*ptrElementIds)->append(childId);
+ }
+ }
+ }
+ }
+ delete ptrElementIds;
+ 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
new file mode 100644
index 0000000000..dcd286800f
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiaselectionprovider.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..1af74a8b72
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.cpp
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** 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>
+
+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 = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>);
+ auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() {
+ 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);
+ (*ptrElementIds)->append(headerId);
+ }
+ }
+ }
+ delete ptrElementIds;
+ 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 = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>);
+ auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() {
+ 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);
+ (*ptrElementIds)->append(headerId);
+ }
+ }
+ }
+ delete ptrElementIds;
+ 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
new file mode 100644
index 0000000000..cb759864ae
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableitemprovider.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..e71ade3c1f
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.cpp
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** 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>
+
+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 = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>);
+ auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() {
+ 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);
+ (*ptrElementIds)->append(headerId);
+ }
+ }
+ }
+ }
+ }
+ }
+ delete ptrElementIds;
+ 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 = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>);
+ auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() {
+ 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);
+ (*ptrElementIds)->append(headerId);
+ }
+ }
+ }
+ }
+ }
+ }
+ delete ptrElementIds;
+ 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
new file mode 100644
index 0000000000..0cd174e401
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatableprovider.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..aa120377df
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.cpp
@@ -0,0 +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:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** 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>
+
+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;
+
+ auto accid = id();
+ auto selections = QSharedPointer<QList<QPair<int,int>>>(new QList<QPair<int,int>>);
+ auto ptrSelections = new QSharedPointer<QList<QPair<int,int>>>(selections);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrSelections]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid)) {
+ if (QAccessibleTextInterface *textInterface = accessible->textInterface()) {
+ for (int i = 0; i < textInterface->selectionCount(); ++i) {
+ QPair<int,int> sel;
+ textInterface->selection(i, &sel.first, &sel.second);
+ (*ptrSelections)->append(sel);
+ }
+ if ((*ptrSelections)->size() == 0) {
+ // If there is no selection, we return an array with a single degenerate (empty) text range at the cursor position.
+ QPair<int,int> sel(textInterface->cursorPosition(), textInterface->cursorPosition());
+ (*ptrSelections)->append(sel);
+ }
+ }
+ }
+ delete ptrSelections;
+ 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;
+
+ for (int i = 0; i < selCount; ++i) {
+ ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider = Make<QWinRTUiaTextRangeProvider>(id(), (*selections)[i].first, (*selections)[i].second);
+ textRangeProvider.CopyTo(&providerArray[i]);
+ }
+ *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 = QSharedPointer<int>(new int);
+ auto ptrOffset = new QSharedPointer<int>(offset);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, pt, ptrOffset]() {
+ if (QAccessibleInterface *accessible = accessibleForId(accid))
+ if (QAccessibleTextInterface *textInterface = accessible->textInterface())
+ **ptrOffset = qBound(0, textInterface->offsetAtPoint(pt), textInterface->characterCount() - 1);
+ delete ptrOffset;
+ 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
new file mode 100644
index 0000000000..80d88e4115
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextprovider.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..fc3778d652
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.cpp
@@ -0,0 +1,497 @@
+/****************************************************************************
+**
+** 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>
+
+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 = QSharedPointer<QList<QRect>>(new QList<QRect>);
+ auto ptrRects = new QSharedPointer<QList<QRect>>(rects);
+
+ if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, startOffset, endOffset, ptrRects]() {
+ 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()));
+ (*ptrRects)->append(lineRect);
+ }
+ if (end >= len) break;
+ textInterface->textAfterOffset(end + 1, QAccessible::LineBoundary, &start, &end);
+ }
+ }
+ }
+ }
+ delete ptrRects;
+ return S_OK;
+ }))) {
+ return E_FAIL;
+ }
+
+ DOUBLE *doubleArray = static_cast<DOUBLE *>(CoTaskMemAlloc(4 * rects->size() * sizeof(DOUBLE)));
+ if (!doubleArray)
+ return E_OUTOFMEMORY;
+
+ for (int i = 0; i < rects->size(); ++i) {
+ doubleArray[i*4] = (*rects)[i].left();
+ doubleArray[i*4+1] = (*rects)[i].top();
+ doubleArray[i*4+2] = (*rects)[i].width();
+ doubleArray[i*4+3] = (*rects)[i].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
new file mode 100644
index 0000000000..81b5f0d400
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatextrangeprovider.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..59f55eb422
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.cpp
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..3d1740c0a1
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiatoggleprovider.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..16197c99b9
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.cpp
@@ -0,0 +1,182 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..9519cb4eb5
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiautils.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..21389b74d2
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.cpp
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** 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();
+ auto tmpValue = QSharedPointer<QString>(new QString);
+ auto ptrValue = new QSharedPointer<QString>(tmpValue);
+
+ *tmpValue = hStrToQStr(value);
+
+ QEventDispatcherWinRT::runOnMainThread([accid, ptrValue]() {
+
+ if (QAccessibleInterface *accessible = accessibleForId(accid)) {
+
+ // First sets the value as a text.
+ accessible->setText(QAccessible::Value, **ptrValue);
+
+ // 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 = (*ptrValue)->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);
+ delete ptrValue;
+ 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
new file mode 100644
index 0000000000..d9cd5d200d
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/qwinrtuiavalueprovider.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..ca0dfae53f
--- /dev/null
+++ b/src/plugins/platforms/winrt/uiautomation/uiautomation.pri
@@ -0,0 +1,45 @@
+
+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.pro b/src/plugins/platforms/winrt/winrt.pro
index 46371b4880..6a847465e4 100644
--- a/src/plugins/platforms/winrt/winrt.pro
+++ b/src/plugins/platforms/winrt/winrt.pro
@@ -13,6 +13,7 @@ LIBS += -lws2_32 -ld3d11
SOURCES = \
main.cpp \
qwinrtbackingstore.cpp \
+ qwinrtcanvas.cpp \
qwinrtclipboard.cpp \
qwinrtcursor.cpp \
qwinrteglcontext.cpp \
@@ -30,6 +31,7 @@ SOURCES = \
HEADERS = \
qwinrtbackingstore.h \
+ qwinrtcanvas.h \
qwinrtclipboard.h \
qwinrtcursor.h \
qwinrteglcontext.h \
@@ -56,6 +58,8 @@ qtConfig(draganddrop) {
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 = -
diff --git a/src/plugins/platforms/xcb/README b/src/plugins/platforms/xcb/README
index 8308db46dc..5f238ab261 100644
--- a/src/plugins/platforms/xcb/README
+++ b/src/plugins/platforms/xcb/README
@@ -1,32 +1,7 @@
-Requires libxcb >= 1.5.
-
-PACKAGE DEPENDENCIES
-
-Required packages:
-libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm1 libxcb-icccm1-dev libxcb-sync0 libxcb-sync0-dev libxcb-render-util0 libxcb-render-util0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-glx0-dev libxcb-xinerama0-dev
-
-On Ubuntu 11.10 icccm1 is replaced by icccm4 and xcb-render-util is not available:
-libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm4 libxcb-icccm4-dev libxcb-sync0 libxcb-sync0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-glx0-dev libxcb-xinerama0-dev
-The packages for xcb-render-util can be installed manually from http://packages.ubuntu.com/natty/libxcb-render-util0 and http://packages.ubuntu.com/natty/libxcb-render-util0-dev
-
-On Ubuntu 12.04 icccm1 is replaced by icccm4 and xcb-render-util can be installed automatically:
-libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm4 libxcb-icccm4-dev libxcb-sync0 libxcb-sync0-dev libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-render-util0 libxcb-render-util0-dev libxcb-glx0-dev libxcb-xinerama0-dev
-
-
-On Fedora, the following packages are required:
-libxcb libxcb-devel libXrender libXrender-devel xcb-util-wm xcb-util-wm-devel xcb-util xcb-util-devel xcb-util-image xcb-util-image-devel xcb-util-keysyms xcb-util-keysyms-devel
+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.
-
-PACKAGE VERSION REQUIREMENTS
-
-When using touch input via XInput 2.2 or higher, there is a potential issue on systems that ship with
-a libXi older than 1.7.5. This is because XIAllowTouchEvents can deadlock with libXi 1.7.4 and earlier.
-When touch events are never received, this is not an issue, so plain mouse/keyboard systems are not affected.
-Qt versions before 5.8 attempted to recognize this scenario based on the pkg-config package version and skip
-the call. This has been removed starting from 5.8 since relying on pkg-config package versions is unsafe given
-that Qt must also support systems with limited or incomplete pkg-config setups.
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 a7641baea1..b751aaf8a3 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp
@@ -163,9 +163,9 @@ bool QXcbGlxIntegration::handleXcbEvent(xcb_generic_event_t *event, uint respons
// Unlock the display before calling the native event filter
XUnlockDisplay(xdisplay);
locked = false;
- QByteArray genericEventFilterType = m_connection->nativeInterface()->genericEventFilterType();
+ auto eventType = m_connection->nativeInterface()->nativeEventType();
long result = 0;
- handled = dispatcher->filterNativeEvent(genericEventFilterType, &ev, &result);
+ handled = dispatcher->filterNativeEvent(eventType, &ev, &result);
}
#endif
}
diff --git a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp b/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp
index 8b63e5431d..a3e6cedecd 100644
--- a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp
+++ b/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp
@@ -226,7 +226,9 @@ public:
QXRenderGlyphCache(QXcbX11Info x, QFontEngine::GlyphFormat format, const QTransform &matrix);
~QXRenderGlyphCache();
- bool addGlyphs(const QTextItemInt &ti, QVarLengthArray<glyph_t> glyphs, QVarLengthArray<QFixedPoint> positions);
+ bool addGlyphs(const QTextItemInt &ti,
+ const QVarLengthArray<glyph_t> &glyphs,
+ const QVarLengthArray<QFixedPoint> &positions);
bool draw(Drawable src, Drawable dst, const QTransform &matrix, const QTextItemInt &ti);
inline GlyphSet glyphSet();
@@ -2608,7 +2610,9 @@ QXRenderGlyphCache::~QXRenderGlyphCache()
XRenderFreeGlyphSet(xinfo.display(), gset);
}
-bool QXRenderGlyphCache::addGlyphs(const QTextItemInt &ti, QVarLengthArray<glyph_t> glyphs, QVarLengthArray<QFixedPoint> positions)
+bool QXRenderGlyphCache::addGlyphs(const QTextItemInt &ti,
+ const QVarLengthArray<glyph_t> &glyphs,
+ const QVarLengthArray<QFixedPoint> &positions)
{
Q_ASSERT(ti.fontEngine->type() == QFontEngine::Freetype);
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
index 8ae9d9899e..c29eb29b7e 100644
--- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
@@ -45,6 +45,16 @@
#include <xcb/shm.h>
#include <xcb/xcb_image.h>
+#if QT_CONFIG(xcb_render)
+#include <xcb/render.h>
+// 'template' is used as a function argument name in xcb_renderutil.h
+#define template template_param
+// extern "C" is missing too
+extern "C" {
+#include <xcb/xcb_renderutil.h>
+}
+#undef template
+#endif
#include <sys/ipc.h>
#include <sys/shm.h>
@@ -76,6 +86,7 @@ class QXcbBackingStoreImage : public QXcbObject
{
public:
QXcbBackingStoreImage(QXcbBackingStore *backingStore, const QSize &size);
+ QXcbBackingStoreImage(QXcbBackingStore *backingStore, const QSize &size, uint depth, QImage::Format format);
~QXcbBackingStoreImage() { destroy(true); }
void resize(const QSize &size);
@@ -99,6 +110,8 @@ public:
xcb_shm_segment_info_t *shm_info = nullptr);
private:
+ void init(const QSize &size, uint depth, QImage::Format format);
+
void createShmSegment(size_t segmentSize);
void destroyShmSegment();
void destroy(bool destroyShm);
@@ -109,8 +122,8 @@ private:
void setClip(const QRegion &region);
xcb_shm_segment_info_t m_shm_info;
- QXcbBackingStore *m_backingStore = nullptr;
size_t m_segmentSize = 0;
+ QXcbBackingStore *m_backingStore = nullptr;
xcb_image_t *m_xcb_image = nullptr;
@@ -185,10 +198,23 @@ QXcbBackingStoreImage::QXcbBackingStoreImage(QXcbBackingStore *backingStore, con
, m_backingStore(backingStore)
{
auto window = static_cast<QXcbWindow *>(m_backingStore->window()->handle());
- m_xcb_format = connection()->formatForDepth(window->depth());
+ init(size, window->depth(), window->imageFormat());
+}
+
+QXcbBackingStoreImage::QXcbBackingStoreImage(QXcbBackingStore *backingStore, const QSize &size,
+ uint depth, QImage::Format format)
+ : QXcbObject(backingStore->connection())
+ , m_backingStore(backingStore)
+{
+ init(size, depth, format);
+}
+
+void QXcbBackingStoreImage::init(const QSize &size, uint depth, QImage::Format format)
+{
+ m_xcb_format = connection()->formatForDepth(depth);
Q_ASSERT(m_xcb_format);
- m_qimage_format = window->imageFormat();
+ 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);
@@ -843,7 +869,7 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion &region, const QPoin
return;
}
- m_image->put(platformWindow->xcb_window(), clipped, offset);
+ render(platformWindow->xcb_window(), clipped, offset);
if (platformWindow->needsSync())
platformWindow->updateSyncRequestCounter();
@@ -851,6 +877,11 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion &region, const QPoin
xcb_flush(xcb_connection());
}
+void QXcbBackingStore::render(xcb_window_t window, const QRegion &region, const QPoint &offset)
+{
+ m_image->put(window, region, offset);
+}
+
#ifndef QT_NO_OPENGL
void QXcbBackingStore::composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset,
QPlatformTextureList *textures,
@@ -884,6 +915,11 @@ void QXcbBackingStore::resize(const QSize &size, const QRegion &)
}
QXcbWindow* win = static_cast<QXcbWindow *>(pw);
+ recreateImage(win, size);
+}
+
+void QXcbBackingStore::recreateImage(QXcbWindow *win, const QSize &size)
+{
if (m_image)
m_image->resize(size);
else
@@ -904,4 +940,167 @@ bool QXcbBackingStore::scroll(const QRegion &area, int dx, int dy)
return false;
}
+QXcbSystemTrayBackingStore::QXcbSystemTrayBackingStore(QWindow *window)
+ : QXcbBackingStore(window)
+{
+ // We need three different behaviors depending on whether the X11 visual
+ // for the system tray supports an alpha channel, i.e. is 32 bits, and
+ // whether XRender can be used:
+ // 1) if the visual has an alpha channel, then render the window's buffer
+ // directly to the X11 window as usual
+ // 2) else if XRender can be used, then render the window's buffer to Pixmap,
+ // then render Pixmap's contents to the cleared X11 window with
+ // xcb_render_composite()
+ // 3) else grab the X11 window's content and paint it first each time as a
+ // background before rendering the window's buffer to the X11 window
+
+ auto *platformWindow = static_cast<QXcbWindow *>(window->handle());
+ quint8 depth = connection()->primaryScreen()->depthOfVisual(platformWindow->visualId());
+
+ if (depth != 32) {
+ platformWindow->setParentRelativeBackPixmap();
+#if QT_CONFIG(xcb_render)
+ initXRenderMode();
+#endif
+ m_useGrabbedBackgound = !m_usingXRenderMode;
+ }
+}
+
+QXcbSystemTrayBackingStore::~QXcbSystemTrayBackingStore()
+{
+#if QT_CONFIG(xcb_render)
+ if (m_xrenderPicture) {
+ xcb_render_free_picture(xcb_connection(), m_xrenderPicture);
+ m_xrenderPicture = XCB_NONE;
+ }
+ if (m_xrenderPixmap) {
+ xcb_free_pixmap(xcb_connection(), m_xrenderPixmap);
+ m_xrenderPixmap = XCB_NONE;
+ }
+ if (m_windowPicture) {
+ xcb_render_free_picture(xcb_connection(), m_windowPicture);
+ m_windowPicture = XCB_NONE;
+ }
+#endif // QT_CONFIG(xcb_render)
+}
+
+void QXcbSystemTrayBackingStore::beginPaint(const QRegion &region)
+{
+ QXcbBackingStore::beginPaint(region);
+
+ if (m_useGrabbedBackgound) {
+ QPainter p(paintDevice());
+ p.setCompositionMode(QPainter::CompositionMode_Source);
+ for (const QRect &rect: region)
+ p.drawPixmap(rect, m_grabbedBackground, rect);
+ }
+}
+
+void QXcbSystemTrayBackingStore::render(xcb_window_t window, const QRegion &region, const QPoint &offset)
+{
+ if (!m_usingXRenderMode) {
+ QXcbBackingStore::render(window, region, offset);
+ return;
+ }
+
+#if QT_CONFIG(xcb_render)
+ m_image->put(m_xrenderPixmap, region, offset);
+ const QRect bounds = region.boundingRect();
+ const QPoint target = bounds.topLeft();
+ const QRect source = bounds.translated(offset);
+ xcb_clear_area(xcb_connection(), false, window,
+ target.x(), target.y(), source.width(), source.height());
+ xcb_render_composite(xcb_connection(), XCB_RENDER_PICT_OP_OVER,
+ m_xrenderPicture, 0, m_windowPicture,
+ target.x(), target.y(), 0, 0, target.x(), target.y(),
+ source.width(), source.height());
+#endif // QT_CONFIG(xcb_render)
+}
+
+void QXcbSystemTrayBackingStore::recreateImage(QXcbWindow *win, const QSize &size)
+{
+ if (!m_usingXRenderMode) {
+ QXcbBackingStore::recreateImage(win, size);
+
+ if (m_useGrabbedBackgound) {
+ xcb_clear_area(xcb_connection(), false, win->xcb_window(),
+ 0, 0, size.width(), size.height());
+ m_grabbedBackground = win->xcbScreen()->grabWindow(win->winId(), 0, 0,
+ size.width(), size.height());
+ }
+ return;
+ }
+
+#if QT_CONFIG(xcb_render)
+ if (m_xrenderPicture) {
+ xcb_render_free_picture(xcb_connection(), m_xrenderPicture);
+ m_xrenderPicture = XCB_NONE;
+ }
+ if (m_xrenderPixmap) {
+ xcb_free_pixmap(xcb_connection(), m_xrenderPixmap);
+ m_xrenderPixmap = XCB_NONE;
+ }
+
+ QXcbScreen *screen = win->xcbScreen();
+
+ m_xrenderPixmap = xcb_generate_id(xcb_connection());
+ xcb_create_pixmap(xcb_connection(), 32, m_xrenderPixmap, screen->root(), size.width(), size.height());
+
+ m_xrenderPicture = xcb_generate_id(xcb_connection());
+ xcb_render_create_picture(xcb_connection(), m_xrenderPicture, m_xrenderPixmap, m_xrenderPictFormat, 0, 0);
+
+ // XRender expects premultiplied alpha
+ if (m_image)
+ m_image->resize(size);
+ else
+ m_image = new QXcbBackingStoreImage(this, size, 32, QImage::Format_ARGB32_Premultiplied);
+#endif // QT_CONFIG(xcb_render)
+}
+
+#if QT_CONFIG(xcb_render)
+void QXcbSystemTrayBackingStore::initXRenderMode()
+{
+ if (!connection()->hasXRender())
+ return;
+
+ xcb_connection_t *conn = xcb_connection();
+ auto formatsReply = Q_XCB_REPLY(xcb_render_query_pict_formats, conn);
+
+ if (!formatsReply) {
+ qWarning("QXcbSystemTrayBackingStore: xcb_render_query_pict_formats() failed");
+ return;
+ }
+
+ xcb_render_pictforminfo_t *fmt = xcb_render_util_find_standard_format(formatsReply.get(),
+ XCB_PICT_STANDARD_ARGB_32);
+ if (!fmt) {
+ qWarning("QXcbSystemTrayBackingStore: Failed to find format PICT_STANDARD_ARGB_32");
+ return;
+ }
+
+ m_xrenderPictFormat = fmt->id;
+
+ auto *platformWindow = static_cast<QXcbWindow *>(window()->handle());
+ xcb_render_pictvisual_t *vfmt = xcb_render_util_find_visual_format(formatsReply.get(), platformWindow->visualId());
+
+ if (!vfmt) {
+ qWarning("QXcbSystemTrayBackingStore: Failed to find format for visual %x", platformWindow->visualId());
+ return;
+ }
+
+ m_windowPicture = xcb_generate_id(conn);
+ xcb_void_cookie_t cookie =
+ xcb_render_create_picture_checked(conn, m_windowPicture, platformWindow->xcb_window(), vfmt->format, 0, 0);
+ xcb_generic_error_t *error = xcb_request_check(conn, cookie);
+ if (error) {
+ qWarning("QXcbSystemTrayBackingStore: Failed to create Picture with format %x for window %x, error code %d",
+ vfmt->format, platformWindow->xcb_window(), error->error_code);
+ free(error);
+ return;
+ }
+
+ m_usingXRenderMode = true;
+}
+#endif // QT_CONFIG(xcb_render)
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.h b/src/plugins/platforms/xcb/qxcbbackingstore.h
index 734de1f7d7..39d023cb9d 100644
--- a/src/plugins/platforms/xcb/qxcbbackingstore.h
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.h
@@ -77,12 +77,41 @@ public:
static bool createSystemVShmSegment(QXcbConnection *c, size_t segmentSize = 1,
void *shmInfo = nullptr);
-private:
+protected:
+ virtual void render(xcb_window_t window, const QRegion &region, const QPoint &offset);
+ virtual void recreateImage(QXcbWindow *win, const QSize &size);
+
QXcbBackingStoreImage *m_image = nullptr;
QStack<QRegion> m_paintRegions;
QImage m_rgbImage;
};
+class QXcbSystemTrayBackingStore : public QXcbBackingStore
+{
+public:
+ QXcbSystemTrayBackingStore(QWindow *window);
+ ~QXcbSystemTrayBackingStore();
+
+ void beginPaint(const QRegion &) override;
+
+protected:
+ void render(xcb_window_t window, const QRegion &region, const QPoint &offset) override;
+ void recreateImage(QXcbWindow *win, const QSize &size) override;
+
+private:
+#if QT_CONFIG(xcb_render)
+ void initXRenderMode();
+
+ xcb_pixmap_t m_xrenderPixmap = XCB_NONE;
+ xcb_render_picture_t m_xrenderPicture = XCB_NONE;
+ xcb_render_pictformat_t m_xrenderPictFormat = XCB_NONE;
+ xcb_render_picture_t m_windowPicture = XCB_NONE;
+#endif
+ bool m_usingXRenderMode = false;
+ bool m_useGrabbedBackgound = false;
+ QPixmap m_grabbedBackground;
+};
+
QT_END_NAMESPACE
#endif
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp
index b091928e8c..3fd14a659e 100644
--- a/src/plugins/platforms/xcb/qxcbclipboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp
@@ -42,16 +42,13 @@
#include "qxcbconnection.h"
#include "qxcbscreen.h"
#include "qxcbmime.h"
+#include "qxcbwindow.h"
#include <private/qguiapplication_p.h>
#include <QElapsedTimer>
#include <QtCore/QDebug>
-#define class class_name // Workaround XCB-ICCCM 3.8 breakage
-#include <xcb/xcb_icccm.h>
-#undef class
-
QT_BEGIN_NAMESPACE
#ifndef QT_NO_CLIPBOARD
@@ -156,6 +153,7 @@ private:
QByteArray format_atoms;
};
+namespace {
class INCRTransaction;
typedef QMap<xcb_window_t,INCRTransaction*> TransactionMap;
static TransactionMap *transactions = 0;
@@ -262,6 +260,7 @@ private:
uint offset;
int abort_timer;
};
+} // unnamed namespace
const int QXcbClipboard::clipboard_timeout = 5000;
@@ -276,18 +275,6 @@ QXcbClipboard::QXcbClipboard(QXcbConnection *c)
m_timestamp[QClipboard::Selection] = XCB_CURRENT_TIME;
m_owner = connection()->getQtSelectionOwner();
-#ifndef QT_NO_DEBUG
- QByteArray ba("Qt clipboard window");
- xcb_change_property(xcb_connection(),
- XCB_PROP_MODE_REPLACE,
- m_owner,
- atom(QXcbAtom::_NET_WM_NAME),
- atom(QXcbAtom::UTF8_STRING),
- 8,
- ba.length(),
- ba.constData());
-#endif
-
if (connection()->hasXFixes()) {
const uint32_t mask = XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
@@ -314,7 +301,7 @@ QXcbClipboard::~QXcbClipboard()
connection()->sync();
// waiting until the clipboard manager fetches the content.
- if (!waitForClipboardEvent(m_owner, XCB_SELECTION_NOTIFY, clipboard_timeout, true)) {
+ if (!waitForClipboardEvent(m_owner, XCB_SELECTION_NOTIFY, true)) {
qWarning("QXcbClipboard: Unable to receive an event from the "
"clipboard manager in a reasonable time");
}
@@ -467,17 +454,9 @@ xcb_window_t QXcbClipboard::requestor() const
platformScreen->screen()->root_visual, // visual
0, // value mask
0); // value list
-#ifndef QT_NO_DEBUG
- QByteArray ba("Qt clipboard requestor window");
- xcb_change_property(xcb_connection(),
- XCB_PROP_MODE_REPLACE,
- window,
- atom(QXcbAtom::_NET_WM_NAME),
- atom(QXcbAtom::UTF8_STRING),
- 8,
- ba.length(),
- ba.constData());
-#endif
+
+ QXcbWindow::setWindowTitle(connection(), window,
+ QStringLiteral("Qt Clipboard Requestor Window"));
uint32_t mask = XCB_EVENT_MASK_PROPERTY_CHANGE;
xcb_change_window_attributes(xcb_connection(), window, XCB_CW_EVENT_MASK, &mask);
@@ -600,7 +579,7 @@ void QXcbClipboard::handleSelectionRequest(xcb_selection_request_event_t *req)
return;
}
- Q_DECLARE_XCB_EVENT(event, xcb_selection_notify_event_t);
+ q_padded_xcb_event<xcb_selection_notify_event_t> event = {};
event.response_type = XCB_SELECTION_NOTIFY;
event.requestor = req->requestor;
event.selection = req->selection;
@@ -824,73 +803,44 @@ bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property,
return ok;
}
-
-namespace
+xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t window, int type, bool checkManager)
{
- class Notify {
- public:
- Notify(xcb_window_t win, int t)
- : window(win), type(t) {}
- xcb_window_t window;
- int type;
- bool checkEvent(xcb_generic_event_t *event) const {
- if (!event)
- return false;
- int t = event->response_type & 0x7f;
- if (t != type)
+ QElapsedTimer timer;
+ timer.start();
+ QXcbEventQueue *queue = connection()->eventQueue();
+ do {
+ auto e = queue->peek([window, type](xcb_generic_event_t *event, int eventType) {
+ if (eventType != type)
return false;
- if (t == XCB_PROPERTY_NOTIFY) {
- xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event;
- if (pn->window == window)
- return true;
- } else if (t == XCB_SELECTION_NOTIFY) {
- xcb_selection_notify_event_t *sn = (xcb_selection_notify_event_t *)event;
- if (sn->requestor == window)
- return true;
+ if (eventType == XCB_PROPERTY_NOTIFY) {
+ auto propertyNotify = reinterpret_cast<xcb_property_notify_event_t *>(event);
+ return propertyNotify->window == window;
}
- return false;
- }
- };
- class ClipboardEvent {
- public:
- ClipboardEvent(QXcbConnection *c)
- { clipboard = c->internAtom("CLIPBOARD"); }
- xcb_atom_t clipboard;
- bool checkEvent(xcb_generic_event_t *e) const {
- if (!e)
- return false;
- int type = e->response_type & 0x7f;
- if (type == XCB_SELECTION_REQUEST) {
- xcb_selection_request_event_t *sr = (xcb_selection_request_event_t *)e;
- return sr->selection == XCB_ATOM_PRIMARY || sr->selection == clipboard;
- } else if (type == XCB_SELECTION_CLEAR) {
- xcb_selection_clear_event_t *sc = (xcb_selection_clear_event_t *)e;
- return sc->selection == XCB_ATOM_PRIMARY || sc->selection == clipboard;
+ if (eventType == XCB_SELECTION_NOTIFY) {
+ auto selectionNotify = reinterpret_cast<xcb_selection_notify_event_t *>(event);
+ return selectionNotify->requestor == window;
}
return false;
- }
- };
-}
-
-xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t win, int type, int timeout, bool checkManager)
-{
- QElapsedTimer timer;
- timer.start();
- do {
- Notify notify(win, type);
- xcb_generic_event_t *e = connection()->checkEvent(notify);
- if (e)
+ });
+ if (e) // found the waited for event
return e;
if (checkManager) {
auto reply = Q_XCB_REPLY(xcb_get_selection_owner, xcb_connection(), atom(QXcbAtom::CLIPBOARD_MANAGER));
if (!reply || reply->owner == XCB_NONE)
- return 0;
+ return nullptr;
}
// process other clipboard events, since someone is probably requesting data from us
- ClipboardEvent clipboard(connection());
- e = connection()->checkEvent(clipboard);
+ auto clipboardAtom = atom(QXcbAtom::CLIPBOARD);
+ e = queue->peek([clipboardAtom](xcb_generic_event_t *event, int type) {
+ xcb_atom_t selection = XCB_ATOM_NONE;
+ if (type == XCB_SELECTION_REQUEST)
+ selection = reinterpret_cast<xcb_selection_request_event_t *>(event)->selection;
+ else if (type == XCB_SELECTION_CLEAR)
+ selection = reinterpret_cast<xcb_selection_clear_event_t *>(event)->selection;
+ return selection == XCB_ATOM_PRIMARY || selection == clipboardAtom;
+ });
if (e) {
connection()->handleXcbEvent(e);
free(e);
@@ -900,9 +850,9 @@ xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t win, int
// sleep 50 ms, so we don't use up CPU cycles all the time.
QThread::msleep(50);
- } while (timer.elapsed() < timeout);
+ } while (timer.elapsed() < clipboard_timeout);
- return 0;
+ return nullptr;
}
QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb_atom_t property, int nbytes, bool nullterm)
@@ -924,7 +874,7 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb
for (;;) {
connection()->flush();
- xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_PROPERTY_NOTIFY, clipboard_timeout);
+ xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_PROPERTY_NOTIFY);
if (!ge)
break;
xcb_property_notify_event_t *event = (xcb_property_notify_event_t *)ge;
@@ -987,7 +937,7 @@ QByteArray QXcbClipboard::getSelection(xcb_atom_t selection, xcb_atom_t target,
connection()->sync();
- xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_SELECTION_NOTIFY, clipboard_timeout);
+ xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_SELECTION_NOTIFY);
bool no_selection = !ge || ((xcb_selection_notify_event_t *)ge)->property == XCB_NONE;
free(ge);
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.h b/src/plugins/platforms/xcb/qxcbclipboard.h
index bfeae13e10..abab42a613 100644
--- a/src/plugins/platforms/xcb/qxcbclipboard.h
+++ b/src/plugins/platforms/xcb/qxcbclipboard.h
@@ -89,7 +89,7 @@ public:
QByteArray getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property, xcb_timestamp_t t = 0);
private:
- xcb_generic_event_t *waitForClipboardEvent(xcb_window_t win, int type, int timeout, bool checkManager = false);
+ xcb_generic_event_t *waitForClipboardEvent(xcb_window_t window, int type, bool checkManager = false);
xcb_atom_t sendTargetsSelection(QMimeData *d, xcb_window_t window, xcb_atom_t property);
xcb_atom_t sendSelection(QMimeData *d, xcb_atom_t target, xcb_window_t window, xcb_atom_t property);
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index aca2c347ea..a4294956c1 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -55,7 +55,9 @@
#include "qxcbsystemtraytracker.h"
#include "qxcbglintegrationfactory.h"
#include "qxcbglintegration.h"
+#include "qxcbcursor.h"
#include "qxcbbackingstore.h"
+#include "qxcbeventqueue.h"
#include <QSocketNotifier>
#include <QAbstractEventDispatcher>
@@ -81,33 +83,14 @@
#undef register
#endif
-#if QT_CONFIG(xinput2)
-#include <X11/extensions/XI2proto.h>
+#if QT_CONFIG(xcb_xinput)
+#include <xcb/xinput.h>
#endif
#if QT_CONFIG(xcb_render)
#include <xcb/render.h>
#endif
-#if defined(Q_CC_GNU) && defined(Q_OF_ELF)
-static xcb_generic_event_t *local_xcb_poll_for_queued_event(xcb_connection_t *c)
- __attribute__((weakref("xcb_poll_for_queued_event")));
-
-static inline void checkXcbPollForQueuedEvent()
-{ }
-#else
-#include <dlfcn.h>
-typedef xcb_generic_event_t * (*XcbPollForQueuedEventFunctionPointer)(xcb_connection_t *c);
-static XcbPollForQueuedEventFunctionPointer local_xcb_poll_for_queued_event;
-
-static inline void checkXcbPollForQueuedEvent()
-{
-#ifdef RTLD_DEFAULT
- local_xcb_poll_for_queued_event = (XcbPollForQueuedEventFunctionPointer)dlsym(RTLD_DEFAULT, "xcb_poll_for_queued_event");
-#endif
-}
-#endif
-
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcQpaXInput, "qt.qpa.input")
@@ -115,9 +98,11 @@ Q_LOGGING_CATEGORY(lcQpaXInputDevices, "qt.qpa.input.devices")
Q_LOGGING_CATEGORY(lcQpaXInputEvents, "qt.qpa.input.events")
Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.screen")
Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events")
+Q_LOGGING_CATEGORY(lcQpaEventReader, "qt.qpa.events.reader")
Q_LOGGING_CATEGORY(lcQpaXcb, "qt.qpa.xcb") // for general (uncategorized) XCB logging
Q_LOGGING_CATEGORY(lcQpaPeeker, "qt.qpa.peeker")
Q_LOGGING_CATEGORY(lcQpaKeyboard, "qt.qpa.xkeyboard")
+Q_LOGGING_CATEGORY(lcQpaXDnd, "qt.qpa.xdnd")
// this event type was added in libxcb 1.10,
// but we support also older version
@@ -125,7 +110,7 @@ Q_LOGGING_CATEGORY(lcQpaKeyboard, "qt.qpa.xkeyboard")
#define XCB_GE_GENERIC 35
#endif
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
// Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed:
// - "pad0" became "extension"
// - "pad1" and "pad" became "pad0"
@@ -143,7 +128,7 @@ static inline bool isXIEvent(xcb_generic_event_t *event, int opCode)
qt_xcb_ge_event_t *e = reinterpret_cast<qt_xcb_ge_event_t *>(event);
return e->extension == opCode;
}
-#endif // QT_CONFIG(xinput2)
+#endif // QT_CONFIG(xcb_xinput)
#if QT_CONFIG(xcb_xlib)
static const char * const xcbConnectionErrors[] = {
@@ -567,8 +552,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
return;
}
- m_reader = new QXcbEventReader(this);
- m_reader->start();
+ m_eventQueue = new QXcbEventQueue(this);
xcb_extension_t *extensions[] = {
&xcb_shm_id, &xcb_xfixes_id, &xcb_randr_id, &xcb_shape_id, &xcb_sync_id,
@@ -578,6 +562,9 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
#if QT_CONFIG(xcb_render)
&xcb_render_id,
#endif
+#if QT_CONFIG(xcb_xinput)
+ &xcb_input_id,
+#endif
0
};
@@ -590,6 +577,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
initializeAllAtoms();
+ initializeXSync();
if (!qEnvironmentVariableIsSet("QT_XCB_NO_MITSHM"))
initializeShm();
if (!qEnvironmentVariableIsSet("QT_XCB_NO_XRANDR"))
@@ -600,7 +588,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
initializeScreens();
initializeXRender();
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
if (!qEnvironmentVariableIsSet("QT_XCB_NO_XI2"))
initializeXInput2();
#endif
@@ -620,34 +608,6 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
if (!m_startupId.isNull())
qunsetenv("DESKTOP_STARTUP_ID");
-
- QStringList glIntegrationNames;
- glIntegrationNames << QStringLiteral("xcb_glx") << QStringLiteral("xcb_egl");
- 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")) {
- glIntegrationNames.removeAll(glIntegrationName);
- glIntegrationNames.prepend(glIntegrationName);
- } else {
- glIntegrationNames.clear();
- }
- }
-
- if (!glIntegrationNames.isEmpty()) {
- qCDebug(lcQpaGl) << "Choosing xcb gl-integration based on following priority\n" << glIntegrationNames;
- for (int i = 0; i < glIntegrationNames.size() && !m_glIntegration; i++) {
- m_glIntegration = QXcbGlIntegrationFactory::create(glIntegrationNames.at(i));
- if (m_glIntegration && !m_glIntegration->initialize(this)) {
- qCDebug(lcQpaGl) << "Failed to initialize xcb gl-integration" << glIntegrationNames.at(i);
- delete m_glIntegration;
- m_glIntegration = nullptr;
- }
- }
- if (!m_glIntegration)
- qCDebug(lcQpaGl) << "Failed to create xcb gl-integration";
- }
-
sync();
}
@@ -659,12 +619,8 @@ QXcbConnection::~QXcbConnection()
#if QT_CONFIG(draganddrop)
delete m_drag;
#endif
- if (m_reader && m_reader->isRunning()) {
- sendConnectionEvent(QXcbAtom::_QT_CLOSE_CONNECTION);
- m_reader->wait();
- }
-
- delete m_reader;
+ if (m_eventQueue)
+ delete m_eventQueue;
QXcbIntegration *integration = QXcbIntegration::instance();
// Delete screens in reverse order to avoid crash in case of multiple screens
@@ -727,22 +683,22 @@ QXcbWindow *QXcbConnection::platformWindowFromId(xcb_window_t id)
#define HANDLE_PLATFORM_WINDOW_EVENT(event_t, windowMember, handler) \
{ \
- event_t *e = reinterpret_cast<event_t *>(event); \
+ auto e = reinterpret_cast<event_t *>(event); \
if (QXcbWindowEventListener *eventListener = windowEventListenerFromId(e->windowMember)) { \
- handled = eventListener->handleGenericEvent(event, &result); \
- if (!handled) \
- eventListener->handler(e); \
+ if (eventListener->handleNativeEvent(event)) \
+ return; \
+ eventListener->handler(e); \
} \
} \
break;
#define HANDLE_KEYBOARD_EVENT(event_t, handler) \
{ \
- event_t *e = reinterpret_cast<event_t *>(event); \
+ auto e = reinterpret_cast<event_t *>(event); \
if (QXcbWindowEventListener *eventListener = windowEventListenerFromId(e->event)) { \
- handled = eventListener->handleGenericEvent(event, &result); \
- if (!handled) \
- m_keyboard->handler(e); \
+ if (eventListener->handleNativeEvent(event)) \
+ return; \
+ m_keyboard->handler(e); \
} \
} \
break;
@@ -968,7 +924,7 @@ void QXcbConnection::handleXcbError(xcb_generic_error_t *error)
{
long result = 0;
QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance();
- if (dispatcher && dispatcher->filterNativeEvent(m_nativeInterface->genericEventFilterType(), error, &result))
+ if (dispatcher && dispatcher->filterNativeEvent(m_nativeInterface->nativeEventType(), error, &result))
return;
printXcbError("QXcbConnection: XCB error", error);
@@ -1060,371 +1016,210 @@ namespace {
void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
{
- long result = 0;
- QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance();
- bool handled = dispatcher && dispatcher->filterNativeEvent(m_nativeInterface->genericEventFilterType(), event, &result);
+ if (Q_UNLIKELY(lcQpaEvents().isDebugEnabled()))
+ printXcbEvent(lcQpaEvents(), "Event", event);
- uint response_type = event->response_type & ~0x80;
+ long result = 0; // Used only by MS Windows
+ if (QAbstractEventDispatcher *dispatcher = QAbstractEventDispatcher::instance()) {
+ if (dispatcher->filterNativeEvent(m_nativeInterface->nativeEventType(), event, &result))
+ return;
+ }
- if (!handled) {
- switch (response_type) {
- case XCB_EXPOSE:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent);
-
- case XCB_BUTTON_PRESS: {
- xcb_button_press_event_t *ev = (xcb_button_press_event_t *)event;
- m_keyboard->updateXKBStateFromCore(ev->state);
- // the event explicitly contains the state of the three first buttons,
- // the rest we need to manage ourselves
- m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state);
- setButtonState(translateMouseButton(ev->detail), true);
- if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
- qCDebug(lcQpaXInputEvents, "legacy mouse press, button %d state %X", ev->detail, static_cast<unsigned int>(m_buttonState));
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent);
- }
- case XCB_BUTTON_RELEASE: {
- xcb_button_release_event_t *ev = (xcb_button_release_event_t *)event;
- m_keyboard->updateXKBStateFromCore(ev->state);
- m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state);
- setButtonState(translateMouseButton(ev->detail), false);
- if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
- qCDebug(lcQpaXInputEvents, "legacy mouse release, button %d state %X", ev->detail, static_cast<unsigned int>(m_buttonState));
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent);
- }
- case XCB_MOTION_NOTIFY: {
- xcb_motion_notify_event_t *ev = (xcb_motion_notify_event_t *)event;
- m_keyboard->updateXKBStateFromCore(ev->state);
- m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state);
- if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
- qCDebug(lcQpaXInputEvents, "legacy mouse move %d,%d button %d state %X", 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);
- }
+ uint response_type = event->response_type & ~0x80;
- case XCB_CONFIGURE_NOTIFY:
- 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:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_unmap_notify_event_t, event, handleUnmapNotifyEvent);
- case XCB_DESTROY_NOTIFY:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_destroy_notify_event_t, event, handleDestroyNotifyEvent);
- case XCB_CLIENT_MESSAGE:
- handleClientMessageEvent((xcb_client_message_event_t *)event);
- break;
- case XCB_ENTER_NOTIFY:
-#if QT_CONFIG(xinput2)
- if (hasXInput2() && !xi2MouseEventsDisabled())
- break;
+ bool handled = true;
+ switch (response_type) {
+ case XCB_EXPOSE:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent);
+ case XCB_BUTTON_PRESS: {
+ auto ev = reinterpret_cast<xcb_button_press_event_t *>(event);
+ m_keyboard->updateXKBStateFromCore(ev->state);
+ // the event explicitly contains the state of the three first buttons,
+ // the rest we need to manage ourselves
+ m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state);
+ setButtonState(translateMouseButton(ev->detail), true);
+ if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
+ qCDebug(lcQpaXInputEvents, "legacy mouse press, button %d state %X",
+ ev->detail, static_cast<unsigned int>(m_buttonState));
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent);
+ }
+ case XCB_BUTTON_RELEASE: {
+ auto ev = reinterpret_cast<xcb_button_release_event_t *>(event);
+ m_keyboard->updateXKBStateFromCore(ev->state);
+ m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state);
+ setButtonState(translateMouseButton(ev->detail), false);
+ if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
+ qCDebug(lcQpaXInputEvents, "legacy mouse release, button %d state %X",
+ ev->detail, static_cast<unsigned int>(m_buttonState));
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent);
+ }
+ case XCB_MOTION_NOTIFY: {
+ auto ev = reinterpret_cast<xcb_motion_notify_event_t *>(event);
+ m_keyboard->updateXKBStateFromCore(ev->state);
+ m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state);
+ if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
+ qCDebug(lcQpaXInputEvents, "legacy mouse move %d,%d button %d state %X",
+ 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:
+ 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:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_unmap_notify_event_t, event, handleUnmapNotifyEvent);
+ case XCB_DESTROY_NOTIFY:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_destroy_notify_event_t, event, handleDestroyNotifyEvent);
+ case XCB_CLIENT_MESSAGE: {
+ auto clientMessage = reinterpret_cast<xcb_client_message_event_t *>(event);
+ if (clientMessage->format != 32)
+ return;
+#if QT_CONFIG(draganddrop)
+ if (clientMessage->type == atom(QXcbAtom::XdndStatus))
+ drag()->handleStatus(clientMessage);
+ else if (clientMessage->type == atom(QXcbAtom::XdndFinished))
+ drag()->handleFinished(clientMessage);
#endif
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent);
- case XCB_LEAVE_NOTIFY:
-#if QT_CONFIG(xinput2)
- if (hasXInput2() && !xi2MouseEventsDisabled())
- break;
+ if (m_systemTrayTracker && clientMessage->type == atom(QXcbAtom::MANAGER))
+ m_systemTrayTracker->notifyManagerClientMessageEvent(clientMessage);
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_client_message_event_t, window, handleClientMessageEvent);
+ }
+ case XCB_ENTER_NOTIFY:
+#if QT_CONFIG(xcb_xinput)
+ if (hasXInput2() && !xi2MouseEventsDisabled())
+ break;
#endif
- m_keyboard->updateXKBStateFromCore(((xcb_leave_notify_event_t *)event)->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:
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_out_event_t, event, handleFocusOutEvent);
- case XCB_KEY_PRESS:
- {
- xcb_key_press_event_t *kp = (xcb_key_press_event_t *)event;
- m_keyboard->updateXKBStateFromCore(kp->state);
- setTime(kp->time);
- HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent);
- }
- case XCB_KEY_RELEASE:
- m_keyboard->updateXKBStateFromCore(((xcb_key_release_event_t *)event)->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));
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent);
+ case XCB_LEAVE_NOTIFY:
+#if QT_CONFIG(xcb_xinput)
+ if (hasXInput2() && !xi2MouseEventsDisabled())
break;
- case XCB_SELECTION_REQUEST:
- {
+#endif
+ m_keyboard->updateXKBStateFromCore(reinterpret_cast<xcb_leave_notify_event_t *>(event)->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:
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_out_event_t, event, handleFocusOutEvent);
+ case XCB_KEY_PRESS:
+ {
+ auto keyPress = reinterpret_cast<xcb_key_press_event_t *>(event);
+ 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);
+ 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;
+ case XCB_SELECTION_REQUEST:
+ {
#if QT_CONFIG(draganddrop) || QT_CONFIG(clipboard)
- xcb_selection_request_event_t *sr = reinterpret_cast<xcb_selection_request_event_t *>(event);
+ auto selectionRequest = reinterpret_cast<xcb_selection_request_event_t *>(event);
#endif
#if QT_CONFIG(draganddrop)
- if (sr->selection == atom(QXcbAtom::XdndSelection))
- m_drag->handleSelectionRequest(sr);
- else
+ if (selectionRequest->selection == atom(QXcbAtom::XdndSelection))
+ m_drag->handleSelectionRequest(selectionRequest);
+ else
#endif
- {
+ {
#ifndef QT_NO_CLIPBOARD
- m_clipboard->handleSelectionRequest(sr);
+ m_clipboard->handleSelectionRequest(selectionRequest);
#endif
- }
- break;
}
- case XCB_SELECTION_CLEAR:
- setTime((reinterpret_cast<xcb_selection_clear_event_t *>(event))->time);
+ break;
+ }
+ case XCB_SELECTION_CLEAR:
+ setTime((reinterpret_cast<xcb_selection_clear_event_t *>(event))->time);
#ifndef QT_NO_CLIPBOARD
- m_clipboard->handleSelectionClearRequest(reinterpret_cast<xcb_selection_clear_event_t *>(event));
+ m_clipboard->handleSelectionClearRequest(reinterpret_cast<xcb_selection_clear_event_t *>(event));
#endif
- handled = true;
- break;
- case XCB_SELECTION_NOTIFY:
- setTime((reinterpret_cast<xcb_selection_notify_event_t *>(event))->time);
- handled = false;
- break;
- case XCB_PROPERTY_NOTIFY:
- {
- xcb_property_notify_event_t *pn = reinterpret_cast<xcb_property_notify_event_t *>(event);
- if (pn->atom == atom(QXcbAtom::_NET_WORKAREA)) {
- QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(pn->window);
- if (virtualDesktop)
- virtualDesktop->updateWorkArea();
- } else {
- HANDLE_PLATFORM_WINDOW_EVENT(xcb_property_notify_event_t, window, handlePropertyNotifyEvent);
- }
- break;
+ break;
+ case XCB_SELECTION_NOTIFY:
+ setTime((reinterpret_cast<xcb_selection_notify_event_t *>(event))->time);
+ break;
+ case XCB_PROPERTY_NOTIFY:
+ {
+ auto propertyNotify = reinterpret_cast<xcb_property_notify_event_t *>(event);
+ if (propertyNotify->atom == atom(QXcbAtom::_NET_WORKAREA)) {
+ QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(propertyNotify->window);
+ if (virtualDesktop)
+ virtualDesktop->updateWorkArea();
+ } else {
+ HANDLE_PLATFORM_WINDOW_EVENT(xcb_property_notify_event_t, window, handlePropertyNotifyEvent);
}
-#if QT_CONFIG(xinput2)
- case XCB_GE_GENERIC:
- // Here the windowEventListener is invoked from xi2HandleEvent()
- if (hasXInput2() && isXIEvent(event, m_xiOpCode))
- xi2HandleEvent(reinterpret_cast<xcb_ge_event_t *>(event));
- break;
+ break;
+ }
+#if QT_CONFIG(xcb_xinput)
+ case XCB_GE_GENERIC:
+ // Here the windowEventListener is invoked from xi2HandleEvent()
+ if (hasXInput2() && isXIEvent(event, m_xiOpCode))
+ xi2HandleEvent(reinterpret_cast<xcb_ge_event_t *>(event));
+ break;
#endif
- default:
- handled = false;
- break;
- }
+ default:
+ handled = false; // event type not recognized
+ break;
}
- if (!handled) {
- if (has_xfixes && response_type == xfixes_first_event + XCB_XFIXES_SELECTION_NOTIFY) {
- xcb_xfixes_selection_notify_event_t *notify_event = reinterpret_cast<xcb_xfixes_selection_notify_event_t *>(event);
- setTime(notify_event->timestamp);
+ if (handled)
+ return;
+
+ handled = true;
+ if (has_xfixes && response_type == xfixes_first_event + XCB_XFIXES_SELECTION_NOTIFY) {
+ auto notify_event = reinterpret_cast<xcb_xfixes_selection_notify_event_t *>(event);
+ setTime(notify_event->timestamp);
#ifndef QT_NO_CLIPBOARD
- m_clipboard->handleXFixesSelectionRequest(notify_event);
+ m_clipboard->handleXFixesSelectionRequest(notify_event);
#endif
- for (QXcbVirtualDesktop *virtualDesktop : qAsConst(m_virtualDesktops))
- virtualDesktop->handleXFixesSelectionNotify(notify_event);
-
- handled = true;
- } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_NOTIFY) {
- updateScreens(reinterpret_cast<xcb_randr_notify_event_t *>(event));
- handled = true;
- } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY) {
- xcb_randr_screen_change_notify_event_t *change_event = reinterpret_cast<xcb_randr_screen_change_notify_event_t *>(event);
- if (auto *virtualDesktop = virtualDesktopForRootWindow(change_event->root))
- virtualDesktop->handleScreenChange(change_event);
-
- handled = true;
+ for (QXcbVirtualDesktop *virtualDesktop : qAsConst(m_virtualDesktops))
+ virtualDesktop->handleXFixesSelectionNotify(notify_event);
+ } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_NOTIFY) {
+ updateScreens(reinterpret_cast<xcb_randr_notify_event_t *>(event));
+ } else if (has_randr_extension && response_type == xrandr_first_event + 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 QT_CONFIG(xkb)
- } else if (response_type == xkb_first_event) { // https://bugs.freedesktop.org/show_bug.cgi?id=51295
- _xkb_event *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.
- case XCB_XKB_STATE_NOTIFY:
- m_keyboard->updateXKBState(&xkb_event->state_notify);
- handled = true;
- break;
- case XCB_XKB_MAP_NOTIFY:
+ } else if (response_type == xkb_first_event) { // https://bugs.freedesktop.org/show_bug.cgi?id=51295
+ 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.
+ case XCB_XKB_STATE_NOTIFY:
+ m_keyboard->updateXKBState(&xkb_event->state_notify);
+ break;
+ case XCB_XKB_MAP_NOTIFY:
+ m_keyboard->updateKeymap();
+ break;
+ case XCB_XKB_NEW_KEYBOARD_NOTIFY: {
+ xcb_xkb_new_keyboard_notify_event_t *ev = &xkb_event->new_keyboard_notify;
+ if (ev->changed & XCB_XKB_NKN_DETAIL_KEYCODES)
m_keyboard->updateKeymap();
- handled = true;
- break;
- case XCB_XKB_NEW_KEYBOARD_NOTIFY: {
- xcb_xkb_new_keyboard_notify_event_t *ev = &xkb_event->new_keyboard_notify;
- if (ev->changed & XCB_XKB_NKN_DETAIL_KEYCODES)
- m_keyboard->updateKeymap();
- break;
- }
- default:
- break;
+ break;
}
+ default:
+ break;
}
-#endif
}
- }
-
- if (!handled && m_glIntegration)
- handled = m_glIntegration->handleXcbEvent(event, response_type);
-
-#if 0
- if (Q_UNLIKELY(lcQpaEvents().isDebugEnabled()))
- printXcbEvent(lcQpaEvents(), handled ? "Handled" : "Unhandled", event);
#endif
-}
-
-void QXcbConnection::addPeekFunc(PeekFunc f)
-{
- m_peekFuncs.append(f);
-}
-
-qint32 QXcbConnection::generatePeekerId()
-{
- qint32 peekerId = m_peekerIdSource++;
- m_peekerToCachedIndex.insert(peekerId, 0);
- return peekerId;
-}
-
-bool QXcbConnection::removePeekerId(qint32 peekerId)
-{
- if (!m_peekerToCachedIndex.contains(peekerId)) {
- qCWarning(lcQpaXcb, "failed to remove unknown peeker id: %d", peekerId);
- return false;
- }
- m_peekerToCachedIndex.remove(peekerId);
- if (m_peekerToCachedIndex.isEmpty()) {
- m_peekerIdSource = 0; // Once the hash becomes empty, we can start reusing IDs
- m_peekerIndexCacheDirty = false;
- }
- return true;
-}
-
-bool QXcbConnection::peekEventQueue(PeekerCallback peeker, void *peekerData,
- PeekOptions option, qint32 peekerId)
-{
- bool peekerIdProvided = peekerId != -1;
- if (peekerIdProvided && !m_peekerToCachedIndex.contains(peekerId)) {
- qCWarning(lcQpaXcb, "failed to find index for unknown peeker id: %d", peekerId);
- return false;
- }
-
- bool peekFromCachedIndex = option.testFlag(PeekOption::PeekFromCachedIndex);
- if (peekFromCachedIndex && !peekerIdProvided) {
- qCWarning(lcQpaXcb, "PeekOption::PeekFromCachedIndex requires peeker id");
- return false;
- }
-
- if (peekerIdProvided && m_peekerIndexCacheDirty) {
- // When the main event loop has flushed the buffered XCB events into the window
- // system event queue, the cached indices are not valid anymore and need reset.
- auto it = m_peekerToCachedIndex.begin();
- while (it != m_peekerToCachedIndex.constEnd()) {
- (*it) = 0;
- ++it;
- }
- m_peekerIndexCacheDirty = false;
- }
-
- qint32 peekerIndex = peekFromCachedIndex ? m_peekerToCachedIndex.value(peekerId) : 0;
- qint32 startingIndex = peekerIndex;
- bool result = false;
- m_mainEventLoopFlushedQueue = false;
-
- QXcbEventArray *eventqueue = m_reader->lock();
-
- if (Q_UNLIKELY(lcQpaPeeker().isDebugEnabled())) {
- qCDebug(lcQpaPeeker, "[%d] peeker index: %d | mode: %s | queue size: %d", peekerId,
- peekerIndex, peekFromCachedIndex ? "cache" : "start", eventqueue->size());
- }
- while (peekerIndex < eventqueue->size() && !result && !m_mainEventLoopFlushedQueue) {
- xcb_generic_event_t *event = eventqueue->at(peekerIndex++);
- if (!event)
- continue;
- if (Q_UNLIKELY(lcQpaPeeker().isDebugEnabled())) {
- QString debug = QString((QLatin1String("[%1] peeking at index: %2")))
- .arg(peekerId).arg(peekerIndex - 1);
- printXcbEvent(lcQpaPeeker(), debug.toLatin1(), event);
- }
- // A peeker may call QCoreApplication::processEvents(), which has two implications:
- // 1) We need to make the lock available for QXcbConnection::processXcbEvents(),
- // otherwise we will deadlock;
- // 2) QXcbConnection::processXcbEvents() will flush the queue we are currently
- // looping through;
- m_reader->unlock();
- result = peeker(event, peekerData);
- m_reader->lock();
- }
-
- m_reader->unlock();
-
- if (peekerIdProvided && peekerIndex != startingIndex && !m_mainEventLoopFlushedQueue) {
- auto it = m_peekerToCachedIndex.find(peekerId);
- // Make sure that a peeker callback did not remove the peeker id
- if (it != m_peekerToCachedIndex.constEnd())
- (*it) = peekerIndex;
- }
-
- return result;
-}
-
-QXcbEventReader::QXcbEventReader(QXcbConnection *connection)
- : m_connection(connection)
-{
- checkXcbPollForQueuedEvent();
-}
-
-void QXcbEventReader::start()
-{
- if (local_xcb_poll_for_queued_event) {
- connect(this, SIGNAL(eventPending()), m_connection, SLOT(processXcbEvents()), Qt::QueuedConnection);
- connect(this, SIGNAL(finished()), m_connection, SLOT(processXcbEvents()));
- QThread::start();
} else {
- // Must be done after we have an event-dispatcher. By posting a method invocation
- // we are sure that by the time the method is called we have an event-dispatcher.
- QMetaObject::invokeMethod(this, "registerForEvents", Qt::QueuedConnection);
- }
-}
-
-void QXcbEventReader::registerForEvents()
-{
- QSocketNotifier *notifier = new QSocketNotifier(xcb_get_file_descriptor(m_connection->xcb_connection()), QSocketNotifier::Read, this);
- connect(notifier, SIGNAL(activated(int)), m_connection, SLOT(processXcbEvents()));
-
- QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher;
- connect(dispatcher, SIGNAL(aboutToBlock()), m_connection, SLOT(processXcbEvents()));
- connect(dispatcher, SIGNAL(awake()), m_connection, SLOT(processXcbEvents()));
-}
-
-void QXcbEventReader::registerEventDispatcher(QAbstractEventDispatcher *dispatcher)
-{
- // flush the xcb connection before the EventDispatcher is going to block
- // In the non-threaded case processXcbEvents is called before going to block,
- // which flushes the connection.
- if (local_xcb_poll_for_queued_event)
- connect(dispatcher, SIGNAL(aboutToBlock()), m_connection, SLOT(flush()));
-}
-
-void QXcbEventReader::run()
-{
- xcb_generic_event_t *event;
- while (m_connection && (event = xcb_wait_for_event(m_connection->xcb_connection()))) {
- m_mutex.lock();
- addEvent(event);
- while (m_connection && (event = local_xcb_poll_for_queued_event(m_connection->xcb_connection())))
- addEvent(event);
- m_mutex.unlock();
- emit eventPending();
+ handled = false; // event type still not recognized
}
- m_mutex.lock();
- for (int i = 0; i < m_events.size(); ++i)
- free(m_events.at(i));
- m_events.clear();
- m_mutex.unlock();
-}
-
-void QXcbEventReader::addEvent(xcb_generic_event_t *event)
-{
- if ((event->response_type & ~0x80) == XCB_CLIENT_MESSAGE
- && (reinterpret_cast<xcb_client_message_event_t *>(event))->type == m_connection->atom(QXcbAtom::_QT_CLOSE_CONNECTION))
- m_connection = 0;
- m_events << event;
-}
+ if (handled)
+ return;
-QXcbEventArray *QXcbEventReader::lock()
-{
- m_mutex.lock();
- if (!local_xcb_poll_for_queued_event) {
- while (xcb_generic_event_t *event = xcb_poll_for_event(m_connection->xcb_connection()))
- m_events << event;
- }
- return &m_events;
+ if (m_glIntegration)
+ m_glIntegration->handleXcbEvent(event, response_type);
}
-void QXcbEventReader::unlock()
+void QXcbConnection::addPeekFunc(PeekFunc f)
{
- m_mutex.unlock();
+ m_peekFuncs.append(f);
}
void QXcbConnection::setFocusWindow(QWindow *w)
@@ -1453,79 +1248,33 @@ void QXcbConnection::ungrabServer()
xcb_ungrab_server(m_connection);
}
-void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom a, uint id)
-{
- xcb_client_message_event_t event;
- memset(&event, 0, sizeof(event));
-
- const xcb_window_t eventListener = xcb_generate_id(m_connection);
- xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup);
- xcb_screen_t *screen = it.data;
- xcb_create_window(m_connection, XCB_COPY_FROM_PARENT,
- eventListener, screen->root,
- 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY,
- screen->root_visual, 0, 0);
-
- event.response_type = XCB_CLIENT_MESSAGE;
- event.format = 32;
- event.sequence = 0;
- event.window = eventListener;
- event.type = atom(a);
- event.data.data32[0] = id;
-
- xcb_send_event(xcb_connection(), false, eventListener, XCB_EVENT_MASK_NO_EVENT, reinterpret_cast<const char *>(&event));
- xcb_destroy_window(m_connection, eventListener);
- xcb_flush(xcb_connection());
-}
-
-namespace
-{
- class PropertyNotifyEvent {
- public:
- PropertyNotifyEvent(xcb_window_t win, xcb_atom_t property)
- : window(win), type(XCB_PROPERTY_NOTIFY), atom(property) {}
- xcb_window_t window;
- int type;
- xcb_atom_t atom;
- bool checkEvent(xcb_generic_event_t *event) const {
- if (!event)
- return false;
- if ((event->response_type & ~0x80) != type) {
- return false;
- } else {
- xcb_property_notify_event_t *pn = reinterpret_cast<xcb_property_notify_event_t *>(event);
- if ((pn->window == window) && (pn->atom == atom))
- return true;
- }
- return false;
- }
- };
-}
-
xcb_timestamp_t QXcbConnection::getTimestamp()
{
// send a dummy event to myself to get the timestamp from X server.
- xcb_window_t root_win = rootWindow();
- xcb_change_property(xcb_connection(), XCB_PROP_MODE_APPEND, root_win, atom(QXcbAtom::CLIP_TEMPORARY),
- XCB_ATOM_INTEGER, 32, 0, NULL);
+ 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_INTEGER, 32, 0, nullptr);
connection()->flush();
- PropertyNotifyEvent checker(root_win, atom(QXcbAtom::CLIP_TEMPORARY));
- xcb_generic_event_t *event = 0;
- // lets keep this inside a loop to avoid a possible race condition, where
- // reader thread has not yet had the time to acquire the mutex in order
- // to add the new set of events to its event queue
+ xcb_generic_event_t *event = nullptr;
+
while (!event) {
connection()->sync();
- event = checkEvent(checker);
+ event = eventQueue()->peek([window, dummyAtom](xcb_generic_event_t *event, int type) {
+ if (type != XCB_PROPERTY_NOTIFY)
+ return false;
+ auto propertyNotify = reinterpret_cast<xcb_property_notify_event_t *>(event);
+ return propertyNotify->window == window && propertyNotify->atom == dummyAtom;
+ });
}
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(), root_win, atom(QXcbAtom::CLIP_TEMPORARY));
+ xcb_delete_property(xcb_connection(), window, dummyAtom);
return timestamp;
}
@@ -1552,6 +1301,9 @@ xcb_window_t QXcbConnection::getQtSelectionOwner()
xcbScreen->root_visual, // visual
0, // value mask
0); // value list
+
+ QXcbWindow::setWindowTitle(connection(), m_qtSelectionOwner,
+ QStringLiteral("Qt Selection Window"));
}
return m_qtSelectionOwner;
}
@@ -1576,17 +1328,11 @@ xcb_window_t QXcbConnection::clientLeader()
XCB_WINDOW_CLASS_INPUT_OUTPUT,
screen->screen()->root_visual,
0, 0);
-#ifndef QT_NO_DEBUG
- QByteArray ba("Qt client leader window");
- xcb_change_property(xcb_connection(),
- XCB_PROP_MODE_REPLACE,
- m_clientLeader,
- atom(QXcbAtom::_NET_WM_NAME),
- atom(QXcbAtom::UTF8_STRING),
- 8,
- ba.length(),
- ba.constData());
-#endif
+
+
+ QXcbWindow::setWindowTitle(connection(), m_clientLeader,
+ QStringLiteral("Qt Client Leader Window"));
+
xcb_change_property(xcb_connection(),
XCB_PROP_MODE_REPLACE,
m_clientLeader,
@@ -1614,45 +1360,16 @@ xcb_window_t QXcbConnection::clientLeader()
return m_clientLeader;
}
-#if QT_CONFIG(xcb_xlib)
-void *QXcbConnection::xlib_display() const
-{
- return m_xlib_display;
-}
-
-void *QXcbConnection::createVisualInfoForDefaultVisualId() const
-{
- if (m_defaultVisualId == UINT_MAX)
- return 0;
- XVisualInfo info;
- memset(&info, 0, sizeof info);
- info.visualid = m_defaultVisualId;
-
- int count = 0;
- Display *dpy = static_cast<Display *>(connection()->xlib_display());
- XVisualInfo *retVisual = XGetVisualInfo(dpy, VisualIDMask, &info, &count);
- Q_ASSERT(count < 2);
- return retVisual;
-}
-
-#endif
-
-#if QT_CONFIG(xinput2)
-// it is safe to cast XI_* events here as long as we are only touching the first 32 bytes,
-// after that position event needs memmove, see xi2PrepareXIGenericDeviceEvent
+#if QT_CONFIG(xcb_xinput)
static inline bool isXIType(xcb_generic_event_t *event, int opCode, uint16_t type)
{
if (!isXIEvent(event, opCode))
return false;
- xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event);
- return xiEvent->evtype == type;
+ auto *e = reinterpret_cast<qt_xcb_ge_event_t *>(event);
+ return e->event_type == type;
}
#endif
-static inline bool isValid(xcb_generic_event_t *event)
-{
- return event && (event->response_type & ~0x80);
-}
/*! \internal
@@ -1666,85 +1383,114 @@ static inline bool isValid(xcb_generic_event_t *event)
3) Or add public API to Qt for disabling event compression QTBUG-44964
*/
-bool QXcbConnection::compressEvent(xcb_generic_event_t *event, int currentIndex, QXcbEventArray *eventqueue) const
+bool QXcbConnection::compressEvent(xcb_generic_event_t *event) const
{
+ if (!QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents))
+ return false;
+
uint responseType = event->response_type & ~0x80;
- int nextIndex = currentIndex + 1;
if (responseType == XCB_MOTION_NOTIFY) {
// compress XCB_MOTION_NOTIFY notify events
- for (int j = nextIndex; j < eventqueue->size(); ++j) {
- xcb_generic_event_t *next = eventqueue->at(j);
- if (!isValid(next))
- continue;
- if (next->response_type == XCB_MOTION_NOTIFY)
- return true;
- }
- return false;
+ return m_eventQueue->peek(QXcbEventQueue::PeekRetainMatch,
+ [](xcb_generic_event_t *, int type) {
+ return type == XCB_MOTION_NOTIFY;
+ });
}
-#if QT_CONFIG(xinput2)
+
+#if QT_CONFIG(xcb_xinput)
// compress XI_* events
if (responseType == XCB_GE_GENERIC) {
if (!hasXInput2())
return false;
// compress XI_Motion
- if (isXIType(event, m_xiOpCode, XI_Motion)) {
+ if (isXIType(event, m_xiOpCode, XCB_INPUT_MOTION)) {
#if QT_CONFIG(tabletevent)
- xXIDeviceEvent *xdev = reinterpret_cast<xXIDeviceEvent *>(event);
- // Xlib's XI2 events need memmove, see xi2PrepareXIGenericDeviceEvent()
- auto sourceId = *reinterpret_cast<uint16_t *>(reinterpret_cast<char *>(&xdev->sourceid) + 4);
+ auto xdev = reinterpret_cast<xcb_input_motion_event_t *>(event);
if (!QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents) &&
- const_cast<QXcbConnection *>(this)->tabletDataForDevice(sourceId))
+ const_cast<QXcbConnection *>(this)->tabletDataForDevice(xdev->sourceid))
return false;
#endif // QT_CONFIG(tabletevent)
- for (int j = nextIndex; j < eventqueue->size(); ++j) {
- xcb_generic_event_t *next = eventqueue->at(j);
- if (!isValid(next))
- continue;
- if (isXIType(next, m_xiOpCode, XI_Motion))
- return true;
- }
- return false;
+ return m_eventQueue->peek(QXcbEventQueue::PeekRetainMatch,
+ [this](xcb_generic_event_t *next, int) {
+ return isXIType(next, m_xiOpCode, XCB_INPUT_MOTION);
+ });
}
-#ifdef XCB_USE_XINPUT22
+
// compress XI_TouchUpdate for the same touch point id
- if (isXIType(event, m_xiOpCode, XI_TouchUpdate)) {
- xXIDeviceEvent *xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event);
- uint32_t id = xiDeviceEvent->detail % INT_MAX;
- for (int j = nextIndex; j < eventqueue->size(); ++j) {
- xcb_generic_event_t *next = eventqueue->at(j);
- if (!isValid(next))
- continue;
- if (isXIType(next, m_xiOpCode, XI_TouchUpdate)) {
- xXIDeviceEvent *xiDeviceNextEvent = reinterpret_cast<xXIDeviceEvent *>(next);
- if (id == xiDeviceNextEvent->detail % INT_MAX)
- return true;
- }
- }
- return false;
+ if (isXIType(event, m_xiOpCode, XCB_INPUT_TOUCH_UPDATE)) {
+ auto touchUpdateEvent = reinterpret_cast<xcb_input_touch_update_event_t *>(event);
+ uint32_t id = touchUpdateEvent->detail % INT_MAX;
+ return m_eventQueue->peek(QXcbEventQueue::PeekRetainMatch,
+ [this, &id](xcb_generic_event_t *next, int) {
+ if (!isXIType(next, m_xiOpCode, XCB_INPUT_TOUCH_UPDATE))
+ return false;
+ auto touchUpdateNextEvent = reinterpret_cast<xcb_input_touch_update_event_t *>(next);
+ return id == touchUpdateNextEvent->detail % INT_MAX;
+ });
}
-#endif
+
return false;
}
#endif
+
if (responseType == XCB_CONFIGURE_NOTIFY) {
// compress multiple configure notify events for the same window
- for (int j = nextIndex; j < eventqueue->size(); ++j) {
- xcb_generic_event_t *next = eventqueue->at(j);
- if (isValid(next) && next->response_type == XCB_CONFIGURE_NOTIFY
- && reinterpret_cast<xcb_configure_notify_event_t *>(next)->event == reinterpret_cast<xcb_configure_notify_event_t *>(event)->event)
- {
- return true;
- }
- }
- return false;
+ return m_eventQueue->peek(QXcbEventQueue::PeekRetainMatch,
+ [event](xcb_generic_event_t *next, int type) {
+ if (type != XCB_CONFIGURE_NOTIFY)
+ return false;
+ auto currentEvent = reinterpret_cast<xcb_configure_notify_event_t *>(event);
+ auto nextEvent = reinterpret_cast<xcb_configure_notify_event_t *>(next);
+ return currentEvent->event == nextEvent->event;
+ });
}
return false;
}
-void QXcbConnection::processXcbEvents()
+bool QXcbConnection::isUserInputEvent(xcb_generic_event_t *event) const
+{
+ auto eventType = event->response_type & ~0x80;
+ bool isInputEvent = eventType == XCB_BUTTON_PRESS ||
+ eventType == XCB_BUTTON_RELEASE ||
+ eventType == XCB_KEY_PRESS ||
+ eventType == XCB_KEY_RELEASE ||
+ eventType == XCB_MOTION_NOTIFY ||
+ eventType == XCB_ENTER_NOTIFY ||
+ eventType == XCB_LEAVE_NOTIFY;
+ if (isInputEvent)
+ return true;
+
+#if QT_CONFIG(xcb_xinput)
+ if (connection()->hasXInput2()) {
+ isInputEvent = isXIType(event, m_xiOpCode, XCB_INPUT_BUTTON_PRESS) ||
+ isXIType(event, m_xiOpCode, XCB_INPUT_BUTTON_RELEASE) ||
+ isXIType(event, m_xiOpCode, XCB_INPUT_MOTION) ||
+ isXIType(event, m_xiOpCode, XCB_INPUT_TOUCH_BEGIN) ||
+ isXIType(event, m_xiOpCode, XCB_INPUT_TOUCH_UPDATE) ||
+ isXIType(event, m_xiOpCode, XCB_INPUT_TOUCH_END) ||
+ isXIType(event, m_xiOpCode, XCB_INPUT_ENTER) ||
+ isXIType(event, m_xiOpCode, XCB_INPUT_LEAVE) ||
+ // wacom driver's way of reporting tool proximity
+ isXIType(event, m_xiOpCode, XCB_INPUT_PROPERTY);
+ }
+ if (isInputEvent)
+ return true;
+#endif
+
+ 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))
+ isInputEvent = true;
+ }
+
+ return isInputEvent;
+}
+
+void QXcbConnection::processXcbEvents(QEventLoop::ProcessEventsFlags flags)
{
int connection_error = xcb_connection_has_error(xcb_connection());
if (connection_error) {
@@ -1752,22 +1498,17 @@ void QXcbConnection::processXcbEvents()
exit(1);
}
- QXcbEventArray *eventqueue = m_reader->lock();
+ m_eventQueue->flushBufferedEvents();
- for (int i = 0; i < eventqueue->size(); ++i) {
- xcb_generic_event_t *event = eventqueue->at(i);
- if (!event)
- continue;
+ while (xcb_generic_event_t *event = m_eventQueue->takeFirst(flags)) {
QScopedPointer<xcb_generic_event_t, QScopedPointerPodDeleter> eventGuard(event);
- (*eventqueue)[i] = 0;
if (!(event->response_type & ~0x80)) {
handleXcbError(reinterpret_cast<xcb_generic_error_t *>(event));
continue;
}
- if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents)) &&
- compressEvent(event, i, eventqueue))
+ if (compressEvent(event))
continue;
#ifndef QT_NO_CLIPBOARD
@@ -1786,48 +1527,24 @@ void QXcbConnection::processXcbEvents()
m_peekFuncs.erase(std::remove_if(m_peekFuncs.begin(), m_peekFuncs.end(),
isWaitingFor),
m_peekFuncs.end());
- m_reader->unlock();
- handleXcbEvent(event);
- m_reader->lock();
- }
-
- eventqueue->clear();
- m_reader->unlock();
+ handleXcbEvent(event);
- m_peekerIndexCacheDirty = m_mainEventLoopFlushedQueue = true;
+ // The lock-based solution used to free the lock inside this loop,
+ // hence allowing for more events to arrive. ### Check if we want
+ // this flush here after QTBUG-70095
+ m_eventQueue->flushBufferedEvents();
+ }
// Indicate with a null event that the event the callbacks are waiting for
// is not in the queue currently.
for (PeekFunc f : qAsConst(m_peekFuncs))
- f(this, 0);
+ f(this, nullptr);
m_peekFuncs.clear();
xcb_flush(xcb_connection());
}
-void QXcbConnection::handleClientMessageEvent(const xcb_client_message_event_t *event)
-{
- if (event->format != 32)
- return;
-
-#if QT_CONFIG(draganddrop)
- if (event->type == atom(QXcbAtom::XdndStatus)) {
- drag()->handleStatus(event);
- } else if (event->type == atom(QXcbAtom::XdndFinished)) {
- drag()->handleFinished(event);
- }
-#endif
- if (m_systemTrayTracker && event->type == atom(QXcbAtom::MANAGER))
- m_systemTrayTracker->notifyManagerClientMessageEvent(event);
-
- QXcbWindow *window = platformWindowFromId(event->window);
- if (!window)
- return;
-
- window->handleClientMessageEvent(event);
-}
-
static const char * xcb_atomnames = {
// window-manager <-> client protocols
"WM_PROTOCOLS\0"
@@ -1850,6 +1567,7 @@ static const char * xcb_atomnames = {
"WM_CLIENT_LEADER\0"
"WM_WINDOW_ROLE\0"
"SM_CLIENT_ID\0"
+ "WM_CLIENT_MACHINE\0"
// Clipboard
"CLIPBOARD\0"
@@ -2021,6 +1739,10 @@ static const char * xcb_atomnames = {
"_COMPIZ_DECOR_DELETE_PIXMAP\0"
"_COMPIZ_TOOLKIT_ACTION\0"
"_GTK_LOAD_ICONTHEMES\0"
+ "AT_SPI_BUS\0"
+ "EDID\0"
+ "EDID_DATA\0"
+ "XFree86_DDC_EDID1_RAWDATA\0"
// \0\0 terminates loop.
};
@@ -2041,10 +1763,7 @@ void QXcbConnection::initializeAllAtoms() {
++ptr;
}
- Q_ASSERT(i == QXcbAtom::NPredefinedAtoms);
-
- const QByteArray settings_atom_name = "_QT_SETTINGS_TIMESTAMP_" + m_displayName;
- names[i++] = settings_atom_name;
+ Q_ASSERT(i == QXcbAtom::NAtoms);
xcb_intern_atom_cookie_t cookies[QXcbAtom::NAtoms];
@@ -2297,6 +2016,15 @@ void QXcbConnection::initializeXKB()
#endif
}
+void QXcbConnection::initializeXSync()
+{
+ const xcb_query_extension_reply_t *reply = xcb_get_extension_data(xcb_connection(), &xcb_sync_id);
+ if (!reply || !reply->present)
+ return;
+
+ has_sync_extension = true;
+}
+
QXcbSystemTrayTracker *QXcbConnection::systemTrayTracker() const
{
if (!m_systemTrayTracker) {
@@ -2309,20 +2037,54 @@ QXcbSystemTrayTracker *QXcbConnection::systemTrayTracker() const
return m_systemTrayTracker;
}
-bool QXcbConnection::xEmbedSystemTrayAvailable()
+Qt::MouseButtons QXcbConnection::queryMouseButtons() const
{
- if (!QGuiApplicationPrivate::platformIntegration())
- return false;
- QXcbConnection *connection = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration())->defaultConnection();
- return connection->systemTrayTracker();
+ int stateMask = 0;
+ QXcbCursor::queryPointer(connection(), 0, 0, &stateMask);
+ return translateMouseButtons(stateMask);
}
-bool QXcbConnection::xEmbedSystemTrayVisualHasAlphaChannel()
+Qt::KeyboardModifiers QXcbConnection::queryKeyboardModifiers() const
{
- if (!QGuiApplicationPrivate::platformIntegration())
- return false;
- QXcbConnection *connection = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration())->defaultConnection();
- return connection->systemTrayTracker() && connection->systemTrayTracker()->visualHasAlphaChannel();
+ int stateMask = 0;
+ QXcbCursor::queryPointer(connection(), 0, 0, &stateMask);
+ return keyboard()->translateModifiers(stateMask);
+}
+
+QXcbGlIntegration *QXcbConnection::glIntegration() const
+{
+ if (m_glIntegrationInitialized)
+ return m_glIntegration;
+
+ QStringList glIntegrationNames;
+ glIntegrationNames << QStringLiteral("xcb_glx") << QStringLiteral("xcb_egl");
+ 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")) {
+ glIntegrationNames.removeAll(glIntegrationName);
+ glIntegrationNames.prepend(glIntegrationName);
+ } else {
+ glIntegrationNames.clear();
+ }
+ }
+
+ if (!glIntegrationNames.isEmpty()) {
+ qCDebug(lcQpaGl) << "Choosing xcb gl-integration based on following priority\n" << glIntegrationNames;
+ for (int i = 0; i < glIntegrationNames.size() && !m_glIntegration; i++) {
+ m_glIntegration = QXcbGlIntegrationFactory::create(glIntegrationNames.at(i));
+ if (m_glIntegration && !m_glIntegration->initialize(const_cast<QXcbConnection *>(this))) {
+ qCDebug(lcQpaGl) << "Failed to initialize xcb gl-integration" << glIntegrationNames.at(i);
+ delete m_glIntegration;
+ m_glIntegration = nullptr;
+ }
+ }
+ if (!m_glIntegration)
+ qCDebug(lcQpaGl) << "Failed to create xcb gl-integration";
+ }
+
+ m_glIntegrationInitialized = true;
+ return m_glIntegration;
}
bool QXcbConnection::event(QEvent *e)
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index c9dde35558..96591c7994 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -47,15 +47,14 @@
#include "qxcbexport.h"
#include <QHash>
#include <QList>
-#include <QMutex>
#include <QObject>
-#include <QThread>
#include <QVector>
-#include <QVarLengthArray>
#include <qpa/qwindowsysteminterface.h>
#include <QtCore/QLoggingCategory>
#include <QtCore/private/qglobal_p.h>
+#include "qxcbeventqueue.h"
+
#include <cstdlib>
#include <memory>
@@ -71,16 +70,6 @@
#include <QTabletEvent>
#endif
-#if QT_CONFIG(xinput2)
-#include <X11/extensions/XI2.h>
-#ifdef XIScrollClass
-#define XCB_USE_XINPUT21 // XI 2.1 adds smooth scrolling support
-#ifdef XI_TouchBeginMask
-#define XCB_USE_XINPUT22 // XI 2.2 adds multi-point touch support
-#endif
-#endif
-#endif // QT_CONFIG(xinput2)
-
struct xcb_randr_get_output_info_reply_t;
QT_BEGIN_NAMESPACE
@@ -93,6 +82,8 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaEvents)
Q_DECLARE_LOGGING_CATEGORY(lcQpaXcb)
Q_DECLARE_LOGGING_CATEGORY(lcQpaPeeker)
Q_DECLARE_LOGGING_CATEGORY(lcQpaKeyboard)
+Q_DECLARE_LOGGING_CATEGORY(lcQpaXDnd)
+Q_DECLARE_LOGGING_CATEGORY(lcQpaEventReader)
class QXcbVirtualDesktop;
class QXcbScreen;
@@ -128,6 +119,7 @@ namespace QXcbAtom {
WM_CLIENT_LEADER,
WM_WINDOW_ROLE,
SM_CLIENT_ID,
+ WM_CLIENT_MACHINE,
// Clipboard
CLIPBOARD,
@@ -303,50 +295,21 @@ namespace QXcbAtom {
_COMPIZ_TOOLKIT_ACTION,
_GTK_LOAD_ICONTHEMES,
- NPredefinedAtoms,
+ AT_SPI_BUS,
+
+ EDID,
+ EDID_DATA,
+ XFree86_DDC_EDID1_RAWDATA,
- _QT_SETTINGS_TIMESTAMP = NPredefinedAtoms,
NAtoms
};
}
-typedef QVarLengthArray<xcb_generic_event_t *, 64> QXcbEventArray;
-
-class QXcbConnection;
-class QXcbEventReader : public QThread
-{
- Q_OBJECT
-public:
- QXcbEventReader(QXcbConnection *connection);
-
- void run() override;
-
- QXcbEventArray *lock();
- void unlock();
-
- void start();
-
- void registerEventDispatcher(QAbstractEventDispatcher *dispatcher);
-
-signals:
- void eventPending();
-
-private slots:
- void registerForEvents();
-
-private:
- void addEvent(xcb_generic_event_t *event);
-
- QMutex m_mutex;
- QXcbEventArray m_events;
- QXcbConnection *m_connection;
-};
-
class QXcbWindowEventListener
{
public:
virtual ~QXcbWindowEventListener() {}
- virtual bool handleGenericEvent(xcb_generic_event_t *, long *) { return false; }
+ virtual bool handleNativeEvent(xcb_generic_event_t *) { return false; }
virtual void handleExposeEvent(const xcb_expose_event_t *) {}
virtual void handleClientMessageEvent(const xcb_client_message_event_t *) {}
@@ -362,7 +325,7 @@ public:
virtual void handleFocusInEvent(const xcb_focus_in_event_t *) {}
virtual void handleFocusOutEvent(const xcb_focus_out_event_t *) {}
virtual void handlePropertyNotifyEvent(const xcb_property_notify_event_t *) {}
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
virtual void handleXIMouseEvent(xcb_ge_event_t *, Qt::MouseEventSource = Qt::MouseEventNotSynthesized) {}
virtual void handleXIEnterLeave(xcb_ge_event_t *) {}
#endif
@@ -383,7 +346,6 @@ private:
QXcbWindow *m_window;
};
-class QAbstractEventDispatcher;
class Q_XCB_EXPORT QXcbConnection : public QObject
{
Q_OBJECT
@@ -393,6 +355,7 @@ public:
QXcbConnection *connection() const { return const_cast<QXcbConnection *>(this); }
bool isConnected() const;
+ QXcbEventQueue *eventQueue() const { return m_eventQueue; }
const QList<QXcbVirtualDesktop *> &virtualDesktops() const { return m_virtualDesktops; }
const QList<QXcbScreen *> &screens() const { return m_screens; }
@@ -438,8 +401,7 @@ public:
xcb_visualid_t defaultVisualId() const { return m_defaultVisualId; }
#if QT_CONFIG(xcb_xlib)
- void *xlib_display() const;
- void *createVisualInfoForDefaultVisualId() const;
+ void *xlib_display() const { return m_xlib_display; }
#endif
void sync();
@@ -454,21 +416,9 @@ public:
QXcbWindowEventListener *windowEventListenerFromId(xcb_window_t id);
QXcbWindow *platformWindowFromId(xcb_window_t id);
- template<typename T>
- inline xcb_generic_event_t *checkEvent(T &checker);
-
typedef bool (*PeekFunc)(QXcbConnection *, xcb_generic_event_t *);
void addPeekFunc(PeekFunc f);
- // Peek at all queued events
- qint32 generatePeekerId();
- bool removePeekerId(qint32 peekerId);
- enum PeekOption { PeekDefault = 0, PeekFromCachedIndex = 1 }; // see qx11info_x11.h
- Q_DECLARE_FLAGS(PeekOptions, PeekOption)
- typedef bool (*PeekerCallback)(xcb_generic_event_t *event, void *peekerData);
- bool peekEventQueue(PeekerCallback peeker, void *peekerData = nullptr,
- PeekOptions option = PeekDefault, qint32 peekerId = -1);
-
inline xcb_timestamp_t time() const { return m_time; }
inline void setTime(xcb_timestamp_t t) { if (t > m_time) m_time = t; }
@@ -490,8 +440,7 @@ public:
bool hasXInput2() const { return m_xi2Enabled; }
bool hasShm() const { return has_shm; }
bool hasShmFd() const { return has_shm_fd; }
-
- bool threadedEventHandling() const { return m_reader->isRunning(); }
+ bool hasXSync() const { return has_sync_extension; }
xcb_timestamp_t getTimestamp();
xcb_window_t getSelectionOwner(xcb_atom_t atom) const;
@@ -522,10 +471,13 @@ public:
QXcbNativeInterface *nativeInterface() const { return m_nativeInterface; }
QXcbSystemTrayTracker *systemTrayTracker() const;
- static bool xEmbedSystemTrayAvailable();
- static bool xEmbedSystemTrayVisualHasAlphaChannel();
-#if QT_CONFIG(xinput2)
+ Qt::MouseButtons queryMouseButtons() const;
+ Qt::KeyboardModifiers queryKeyboardModifiers() const;
+
+ bool isUserInputEvent(xcb_generic_event_t *event) const;
+
+#if QT_CONFIG(xcb_xinput)
void xi2SelectStateEvents();
void xi2SelectDeviceEvents(xcb_window_t window);
void xi2SelectDeviceEventsCompatibility(xcb_window_t window);
@@ -534,33 +486,24 @@ public:
bool isAtLeastXI21() const { return m_xi2Enabled && m_xi2Minor >= 1; }
bool isAtLeastXI22() const { return m_xi2Enabled && m_xi2Minor >= 2; }
Qt::MouseButton xiToQtMouseButton(uint32_t b);
-#ifdef XCB_USE_XINPUT21
void xi2UpdateScrollingDevices();
-#endif
-#ifdef XCB_USE_XINPUT22
bool startSystemMoveResizeForTouchBegin(xcb_window_t window, const QPoint &point, int corner);
void abortSystemMoveResizeForTouch();
bool isTouchScreen(int id);
#endif
-#endif
- QXcbEventReader *eventReader() const { return m_reader; }
bool canGrab() const { return m_canGrabServer; }
- QXcbGlIntegration *glIntegration() const { return m_glIntegration; }
+ QXcbGlIntegration *glIntegration() const;
-protected:
- bool event(QEvent *e) override;
-
-public slots:
void flush() { xcb_flush(m_connection); }
+ void processXcbEvents(QEventLoop::ProcessEventsFlags flags);
-private slots:
- void processXcbEvents();
+protected:
+ bool event(QEvent *e) override;
private:
void initializeAllAtoms();
- void sendConnectionEvent(QXcbAtom::Atom atom, uint id = 0);
void initializeShm();
void initializeXFixes();
void initializeXRender();
@@ -568,7 +511,7 @@ private:
void initializeXinerama();
void initializeXShape();
void initializeXKB();
- void handleClientMessageEvent(const xcb_client_message_event_t *event);
+ void initializeXSync();
QXcbScreen* findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc) const;
QXcbScreen* findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t output) const;
QXcbVirtualDesktop* virtualDesktopForRootWindow(xcb_window_t rootWindow) const;
@@ -580,10 +523,10 @@ private:
xcb_randr_get_output_info_reply_t *outputInfo);
void destroyScreen(QXcbScreen *screen);
void initializeScreens();
- bool compressEvent(xcb_generic_event_t *event, int currentIndex, QXcbEventArray *eventqueue) const;
+ bool compressEvent(xcb_generic_event_t *event) const;
bool m_xi2Enabled = false;
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
int m_xi2Minor = -1;
void initializeXInput2();
void xi2SetupDevice(void *info, bool removeExisting = true);
@@ -611,10 +554,8 @@ private:
void xi2HandleEvent(xcb_ge_event_t *event);
void xi2HandleHierarchyEvent(void *event);
void xi2HandleDeviceChangedEvent(void *event);
- int m_xiOpCode, m_xiEventBase, m_xiErrorBase;
-#ifdef XCB_USE_XINPUT22
+ int m_xiOpCode;
void xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindow);
-#endif // XCB_USE_XINPUT22
#if QT_CONFIG(tabletevent)
struct TabletData {
int deviceId = 0;
@@ -649,14 +590,11 @@ private:
QPointF lastScrollPosition;
};
QHash<int, ScrollingDevice> m_scrollingDevices;
-#ifdef XCB_USE_XINPUT21
void xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice);
void xi2UpdateScrollingDevice(ScrollingDevice &scrollingDevice);
ScrollingDevice *scrollingDeviceForId(int id);
-#endif
static bool xi2GetValuatorValueIfSet(const void *event, int valuatorNum, double *value);
- static void xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event);
#endif
xcb_connection_t *m_connection = nullptr;
@@ -688,11 +626,10 @@ private:
#if QT_CONFIG(xcb_xlib)
void *m_xlib_display = nullptr;
#endif
- QXcbEventReader *m_reader = nullptr;
+ QXcbEventQueue *m_eventQueue = nullptr;
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
QHash<int, TouchDeviceData> m_touchDevices;
-#ifdef XCB_USE_XINPUT22
struct StartSystemMoveResizeInfo {
xcb_window_t window = XCB_NONE;
uint16_t deviceid;
@@ -700,7 +637,6 @@ private:
int corner;
} m_startSystemMoveResizeInfo;
#endif
-#endif
WindowMapper m_mapper;
QVector<PeekFunc> m_peekFuncs;
@@ -708,6 +644,9 @@ private:
uint32_t xfixes_first_event = 0;
uint32_t xrandr_first_event = 0;
uint32_t xkb_first_event = 0;
+#if QT_CONFIG(xcb_xinput)
+ uint32_t xinput_first_event = 0;
+#endif
bool has_xfixes = false;
bool has_xinerama_extension = false;
@@ -718,6 +657,7 @@ private:
bool has_render_extension = false;
bool has_shm = false;
bool has_shm_fd = false;
+ bool has_sync_extension = false;
QPair<int, int> m_xrenderVersion;
@@ -731,44 +671,24 @@ private:
xcb_window_t m_clientLeader = 0;
QByteArray m_startupId;
QXcbSystemTrayTracker *m_systemTrayTracker = nullptr;
- QXcbGlIntegration *m_glIntegration = nullptr;
+ mutable QXcbGlIntegration *m_glIntegration = nullptr;
+ mutable bool m_glIntegrationInitialized = false;
bool m_xiGrab = false;
QVector<int> m_xiMasterPointerIds;
xcb_window_t m_qtSelectionOwner = 0;
- bool m_mainEventLoopFlushedQueue = false;
- qint32 m_peekerIdSource = 0;
- bool m_peekerIndexCacheDirty = false;
- QHash<qint32, qint32> m_peekerToCachedIndex;
- friend class QXcbEventReader;
+ friend class QXcbEventQueue;
QByteArray m_xdgCurrentDesktop;
};
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
#if QT_CONFIG(tabletevent)
Q_DECLARE_TYPEINFO(QXcbConnection::TabletData::ValuatorClassInfo, Q_PRIMITIVE_TYPE);
Q_DECLARE_TYPEINFO(QXcbConnection::TabletData, Q_MOVABLE_TYPE);
#endif
#endif
-template<typename T>
-xcb_generic_event_t *QXcbConnection::checkEvent(T &checker)
-{
- QXcbEventArray *eventqueue = m_reader->lock();
-
- for (int i = 0; i < eventqueue->size(); ++i) {
- xcb_generic_event_t *event = eventqueue->at(i);
- if (checker.checkEvent(event)) {
- (*eventqueue)[i] = 0;
- m_reader->unlock();
- return event;
- }
- }
- m_reader->unlock();
- return 0;
-}
-
class QXcbConnectionGrabber
{
public:
@@ -795,18 +715,11 @@ struct QStdFreeDeleter {
call##_reply(Q_XCB_REPLY_CONNECTION_ARG(__VA_ARGS__), call##_unchecked(__VA_ARGS__), nullptr) \
)
-template <typename T>
-union q_padded_xcb_event {
- T event;
- char padding[32];
-};
-
// The xcb_send_event() requires all events to have 32 bytes. It calls memcpy() on the
// passed in event. If the passed in event is less than 32 bytes, memcpy() reaches into
// unrelated memory.
-#define Q_DECLARE_XCB_EVENT(event_var, event_type) \
- q_padded_xcb_event<event_type> store = {}; \
- auto &event_var = store.event;
+template <typename T>
+struct alignas(32) q_padded_xcb_event : T { };
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index 6a5248b8f1..a3befc7384 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -47,59 +47,51 @@
#include <QDebug>
#include <cmath>
-#include <X11/extensions/XInput2.h>
-#include <X11/extensions/XI2proto.h>
+#include <xcb/xinput.h>
+
+using qt_xcb_input_device_event_t = xcb_input_button_press_event_t;
void QXcbConnection::initializeXInput2()
{
- Display *xDisplay = static_cast<Display *>(m_xlib_display);
- if (XQueryExtension(xDisplay, "XInputExtension", &m_xiOpCode, &m_xiEventBase, &m_xiErrorBase)) {
- int xiMajor = 2;
-#if defined(XCB_USE_XINPUT22)
- m_xi2Minor = 2; // for touch support 2.2 is enough
-#elif defined(XCB_USE_XINPUT21)
- m_xi2Minor = 1; // for smooth scrolling 2.1 is enough
-#else
- m_xi2Minor = 0; // for tablet support 2.0 is enough
-#endif
- qCDebug(lcQpaXInput, "Plugin build with support for XInput 2 version up "
- "to %d.%d", xiMajor, m_xi2Minor);
-
- switch (XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor)) {
- case Success:
- // Server's supported version can be lower than the version we have
- // announced to support. In this case Qt client will be limited by
- // X server's supported version.
- qCDebug(lcQpaXInput, "Using XInput version %d.%d", xiMajor, m_xi2Minor);
- m_xi2Enabled = true;
- xi2SetupDevices();
- xi2SelectStateEvents();
- break;
- case BadRequest: // Must be an X server with XInput 1
- qCDebug(lcQpaXInput, "X server does not support XInput 2");
- break;
- default: // BadValue
- qCDebug(lcQpaXInput, "Internal error");
- break;
- }
+ const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_input_id);
+ if (!reply || !reply->present) {
+ qCDebug(lcQpaXInput, "XInput extension is not present on the X server");
+ return;
+ }
+
+ m_xiOpCode = reply->major_opcode;
+ xinput_first_event = reply->first_event;
+
+ auto xinput_query = Q_XCB_REPLY(xcb_input_xi_query_version, m_connection, 2, 2);
+
+ if (!xinput_query || xinput_query->major_version != 2) {
+ qCWarning(lcQpaXInput, "X server does not support XInput 2");
+ } else {
+ qCDebug(lcQpaXInput, "Using XInput version %d.%d",
+ xinput_query->major_version, xinput_query->minor_version);
+ m_xi2Minor = xinput_query->minor_version;
+ m_xi2Enabled = true;
+ xi2SetupDevices();
+ xi2SelectStateEvents();
}
}
+struct qt_xcb_input_event_mask_t {
+ xcb_input_event_mask_t header;
+ uint32_t mask;
+};
+
void QXcbConnection::xi2SelectStateEvents()
{
// These state events do not depend on a specific X window, but are global
// for the X client's (application's) state.
- unsigned int bitMask = 0;
- unsigned char *xiBitMask = reinterpret_cast<unsigned char *>(&bitMask);
- XIEventMask xiEventMask;
- bitMask = XI_HierarchyChangedMask;
- bitMask |= XI_DeviceChangedMask;
- bitMask |= XI_PropertyEventMask;
- xiEventMask.deviceid = XIAllDevices;
- xiEventMask.mask_len = sizeof(bitMask);
- xiEventMask.mask = xiBitMask;
- Display *dpy = static_cast<Display *>(m_xlib_display);
- XISelectEvents(dpy, DefaultRootWindow(dpy), &xiEventMask, 1);
+ 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;
+ xcb_input_xi_select_events(m_connection, rootWindow(), 1, &xiEventMask.header);
}
void QXcbConnection::xi2SelectDeviceEvents(xcb_window_t window)
@@ -107,38 +99,42 @@ void QXcbConnection::xi2SelectDeviceEvents(xcb_window_t window)
if (window == rootWindow())
return;
- unsigned int bitMask = 0;
- unsigned char *xiBitMask = reinterpret_cast<unsigned char *>(&bitMask);
- bitMask |= XI_ButtonPressMask;
- bitMask |= XI_ButtonReleaseMask;
- bitMask |= XI_MotionMask;
+ 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;
// 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 |= XI_EnterMask;
- bitMask |= XI_LeaveMask;
-#ifdef XCB_USE_XINPUT22
+ bitMask |= XCB_INPUT_XI_EVENT_MASK_ENTER;
+ bitMask |= XCB_INPUT_XI_EVENT_MASK_LEAVE;
if (isAtLeastXI22()) {
- bitMask |= XI_TouchBeginMask;
- bitMask |= XI_TouchUpdateMask;
- bitMask |= XI_TouchEndMask;
+ bitMask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_BEGIN;
+ bitMask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_UPDATE;
+ bitMask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_END;
}
-#endif
- XIEventMask mask;
- mask.mask_len = sizeof(bitMask);
- mask.mask = xiBitMask;
- mask.deviceid = XIAllMasterDevices;
- Display *dpy = static_cast<Display *>(m_xlib_display);
- Status result = XISelectEvents(dpy, window, &mask, 1);
- if (result == Success)
+ qt_xcb_input_event_mask_t mask;
+ mask.header.deviceid = XCB_INPUT_DEVICE_ALL_MASTER;
+ mask.header.mask_len = 1;
+ mask.mask = bitMask;
+ xcb_void_cookie_t cookie =
+ xcb_input_xi_select_events_checked(m_connection, window, 1, &mask.header);
+ xcb_generic_error_t *error = xcb_request_check(m_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);
- else
- qCDebug(lcQpaXInput, "failed to select events, window %x, result %d", window, result);
+ }
+}
+
+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)
{
- XIDeviceInfo *deviceInfo = reinterpret_cast<XIDeviceInfo *>(info);
+ 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) {
@@ -152,53 +148,54 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting)
m_touchDevices.remove(deviceInfo->deviceid);
}
- qCDebug(lcQpaXInputDevices) << "input device " << deviceInfo->name << "ID" << deviceInfo->deviceid;
+ qCDebug(lcQpaXInputDevices) << "input device " << xcb_input_xi_device_info_name(deviceInfo) << "ID" << deviceInfo->deviceid;
#if QT_CONFIG(tabletevent)
TabletData tabletData;
#endif
ScrollingDevice scrollingDevice;
- for (int c = 0; c < deviceInfo->num_classes; ++c) {
- XIAnyClassInfo *classinfo = deviceInfo->classes[c];
+ 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) {
- case XIValuatorClass: {
- XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(classinfo);
+ case XCB_INPUT_DEVICE_CLASS_TYPE_VALUATOR: {
+ auto *vci = reinterpret_cast<xcb_input_valuator_class_t *>(classinfo);
const int valuatorAtom = qatom(vci->label);
qCDebug(lcQpaXInputDevices) << " has valuator" << atomName(vci->label) << "recognized?" << (valuatorAtom < QXcbAtom::NAtoms);
#if QT_CONFIG(tabletevent)
if (valuatorAtom < QXcbAtom::NAtoms) {
TabletData::ValuatorClassInfo info;
- info.minVal = vci->min;
- info.maxVal = vci->max;
+ info.minVal = fixed3232ToReal(vci->min);
+ info.maxVal = fixed3232ToReal(vci->max);
info.number = vci->number;
tabletData.valuatorInfo[valuatorAtom] = info;
}
#endif // QT_CONFIG(tabletevent)
if (valuatorAtom == QXcbAtom::RelHorizScroll || valuatorAtom == QXcbAtom::RelHorizWheel)
- scrollingDevice.lastScrollPosition.setX(vci->value);
+ scrollingDevice.lastScrollPosition.setX(fixed3232ToReal(vci->value));
else if (valuatorAtom == QXcbAtom::RelVertScroll || valuatorAtom == QXcbAtom::RelVertWheel)
- scrollingDevice.lastScrollPosition.setY(vci->value);
+ scrollingDevice.lastScrollPosition.setY(fixed3232ToReal(vci->value));
break;
}
-#ifdef XCB_USE_XINPUT21
- case XIScrollClass: {
- XIScrollClassInfo *sci = reinterpret_cast<XIScrollClassInfo *>(classinfo);
- if (sci->scroll_type == XIScrollTypeVertical) {
+ 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 = sci->increment;
- }
- else if (sci->scroll_type == XIScrollTypeHorizontal) {
+ scrollingDevice.verticalIncrement = fixed3232ToReal(sci->increment);
+ } else if (sci->scroll_type == XCB_INPUT_SCROLL_TYPE_HORIZONTAL) {
scrollingDevice.orientations |= Qt::Horizontal;
scrollingDevice.horizontalIndex = sci->number;
- scrollingDevice.horizontalIncrement = sci->increment;
+ scrollingDevice.horizontalIncrement = fixed3232ToReal(sci->increment);
}
break;
}
- case XIButtonClass: {
- XIButtonClassInfo *bci = reinterpret_cast<XIButtonClassInfo *>(classinfo);
+ case XCB_INPUT_DEVICE_CLASS_TYPE_BUTTON: {
+ auto *bci = reinterpret_cast<xcb_input_button_class_t *>(classinfo);
+ xcb_atom_t *labels = 0;
if (bci->num_buttons >= 5) {
- Atom label4 = bci->labels[3];
- Atom label5 = bci->labels[4];
+ labels = xcb_input_button_class_labels(bci);
+ xcb_atom_t label4 = labels[3];
+ 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) &&
@@ -206,23 +203,20 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting)
scrollingDevice.legacyOrientations |= Qt::Vertical;
}
if (bci->num_buttons >= 7) {
- Atom label6 = bci->labels[5];
- Atom label7 = bci->labels[6];
+ 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;
}
qCDebug(lcQpaXInputDevices, " has %d buttons", bci->num_buttons);
break;
}
-#endif
- case XIKeyClass:
+ case XCB_INPUT_DEVICE_CLASS_TYPE_KEY:
qCDebug(lcQpaXInputDevices) << " it's a keyboard";
break;
-#ifdef XCB_USE_XINPUT22
- case XITouchClass:
+ case XCB_INPUT_DEVICE_CLASS_TYPE_TOUCH:
// will be handled in populateTouchDevices()
break;
-#endif
default:
qCDebug(lcQpaXInputDevices) << " has class" << classinfo->type;
break;
@@ -237,7 +231,8 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting)
isTablet = true;
// But we need to be careful not to take the touch and tablet-button devices as tablets.
- QByteArray name = QByteArray(deviceInfo->name).toLower();
+ 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")) {
isTablet = true;
@@ -281,7 +276,6 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting)
}
#endif // QT_CONFIG(tabletevent)
-#ifdef XCB_USE_XINPUT21
if (scrollingDevice.orientations || scrollingDevice.legacyOrientations) {
scrollingDevice.deviceId = deviceInfo->deviceid;
// Only use legacy wheel button events when we don't have real scroll valuators.
@@ -289,7 +283,6 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting)
m_scrollingDevices.insert(scrollingDevice.deviceId, scrollingDevice);
qCDebug(lcQpaXInputDevices) << " it's a scrolling device";
}
-#endif
if (!isTablet) {
TouchDeviceData *dev = populateTouchDevices(deviceInfo);
@@ -315,23 +308,28 @@ void QXcbConnection::xi2SetupDevices()
#endif
m_scrollingDevices.clear();
m_touchDevices.clear();
-
- Display *xDisplay = static_cast<Display *>(m_xlib_display);
- int deviceCount = 0;
- XIDeviceInfo *devices = XIQueryDevice(xDisplay, XIAllDevices, &deviceCount);
m_xiMasterPointerIds.clear();
- for (int i = 0; i < deviceCount; ++i) {
- XIDeviceInfo deviceInfo = devices[i];
- if (deviceInfo.use == XIMasterPointer) {
- m_xiMasterPointerIds.append(deviceInfo.deviceid);
+
+ auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, m_connection, XCB_INPUT_DEVICE_ALL);
+ if (!reply) {
+ qCDebug(lcQpaXInputDevices) << "failed to query devices";
+ return;
+ }
+
+ 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) {
+ m_xiMasterPointerIds.append(deviceInfo->deviceid);
continue;
}
- if (deviceInfo.use == XISlavePointer) // only slave pointer devices are relevant here
- xi2SetupDevice(&deviceInfo, false);
+ // 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";
- XIFreeDeviceInfo(devices);
}
/*! \internal
@@ -376,70 +374,64 @@ void QXcbConnection::xi2SelectDeviceEventsCompatibility(xcb_window_t window)
if (window == rootWindow())
return;
- unsigned int mask = 0;
- unsigned char *bitMask = reinterpret_cast<unsigned char *>(&mask);
- Display *dpy = static_cast<Display *>(m_xlib_display);
+ uint32_t mask = 0;
-#ifdef XCB_USE_XINPUT22
if (isAtLeastXI22()) {
- mask |= XI_TouchBeginMask;
- mask |= XI_TouchUpdateMask;
- mask |= XI_TouchEndMask;
-
- XIEventMask xiMask;
- xiMask.mask_len = sizeof(mask);
- xiMask.mask = bitMask;
- xiMask.deviceid = XIAllMasterDevices;
- Status result = XISelectEvents(dpy, window, &xiMask, 1);
- if (result == Success)
+ 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(m_connection, window, 1, &xiMask.header);
+ xcb_generic_error_t *error = xcb_request_check(m_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);
- else
- qCDebug(lcQpaXInput, "failed to select events, window %x, result %d", window, result);
+ }
}
-#endif
- mask = XI_ButtonPressMask;
- mask |= XI_ButtonReleaseMask;
- mask |= XI_MotionMask;
+ 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<XIEventMask> xiEventMask(nrTablets);
+ 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].deviceid = deviceId;
- xiEventMask[i].mask_len = sizeof(mask);
- xiEventMask[i].mask = bitMask;
+ xiEventMask[i].header.deviceid = deviceId;
+ xiEventMask[i].header.mask_len = 1;
+ xiEventMask[i].mask = mask;
}
- XISelectEvents(dpy, window, xiEventMask.data(), nrTablets);
+ xcb_input_xi_select_events(m_connection, window, nrTablets, &(xiEventMask.data()->header));
}
#endif
-#ifdef XCB_USE_XINPUT21
if (!m_scrollingDevices.isEmpty()) {
- QVector<XIEventMask> xiEventMask(m_scrollingDevices.size());
+ 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].deviceid = scrollingDevice.deviceId;
- xiEventMask[i].mask_len = sizeof(mask);
- xiEventMask[i].mask = bitMask;
+ xiEventMask[i].header.deviceid = scrollingDevice.deviceId;
+ xiEventMask[i].header.mask_len = 1;
+ xiEventMask[i].mask = mask;
i++;
}
- XISelectEvents(dpy, window, xiEventMask.data(), i);
+ xcb_input_xi_select_events(m_connection, window, i, &(xiEventMask.data()->header));
}
-#endif
-
-#if !QT_CONFIG(tabletevent) && !defined(XCB_USE_XINPUT21)
- Q_UNUSED(bitMask);
- Q_UNUSED(dpy);
-#endif
}
QXcbConnection::TouchDeviceData *QXcbConnection::touchDeviceForId(int id)
@@ -452,39 +444,38 @@ QXcbConnection::TouchDeviceData *QXcbConnection::touchDeviceForId(int id)
QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info)
{
- XIDeviceInfo *deviceinfo = reinterpret_cast<XIDeviceInfo *>(info);
+ auto *deviceinfo = reinterpret_cast<xcb_input_xi_device_info_t *>(info);
QTouchDevice::Capabilities caps = 0;
int type = -1;
int maxTouchPoints = 1;
bool isTouchDevice = false;
bool hasRelativeCoords = false;
TouchDeviceData dev;
- for (int i = 0; i < deviceinfo->num_classes; ++i) {
- XIAnyClassInfo *classinfo = deviceinfo->classes[i];
+ 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) {
-#ifdef XCB_USE_XINPUT22
- case XITouchClass: {
- XITouchClassInfo *tci = reinterpret_cast<XITouchClassInfo *>(classinfo);
+ case XCB_INPUT_DEVICE_CLASS_TYPE_TOUCH: {
+ auto *tci = reinterpret_cast<xcb_input_touch_class_t *>(classinfo);
maxTouchPoints = tci->num_touches;
qCDebug(lcQpaXInputDevices, " has touch class with mode %d", tci->mode);
switch (tci->mode) {
- case XIDependentTouch:
+ case XCB_INPUT_TOUCH_MODE_DEPENDENT:
type = QTouchDevice::TouchPad;
break;
- case XIDirectTouch:
+ case XCB_INPUT_TOUCH_MODE_DIRECT:
type = QTouchDevice::TouchScreen;
break;
}
break;
}
-#endif // XCB_USE_XINPUT22
- case XIValuatorClass: {
- XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(classinfo);
+ case XCB_INPUT_DEVICE_CLASS_TYPE_VALUATOR: {
+ auto *vci = reinterpret_cast<xcb_input_valuator_class_t *>(classinfo);
const QXcbAtom::Atom valuatorAtom = qatom(vci->label);
if (valuatorAtom < QXcbAtom::NAtoms) {
TouchDeviceData::ValuatorClassInfo info;
- info.min = vci->min;
- info.max = vci->max;
+ info.min = fixed3232ToReal(vci->min);
+ info.max = fixed3232ToReal(vci->max);
info.number = vci->number;
info.label = valuatorAtom;
dev.valuatorInfo.append(info);
@@ -502,16 +493,16 @@ QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info
caps |= QTouchDevice::Pressure;
else if (valuatorAtom == QXcbAtom::RelX) {
hasRelativeCoords = true;
- dev.size.setWidth((vci->max - vci->min) * 1000.0 / vciResolution);
+ dev.size.setWidth((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
} else if (valuatorAtom == QXcbAtom::RelY) {
hasRelativeCoords = true;
- dev.size.setHeight((vci->max - vci->min) * 1000.0 / vciResolution);
+ dev.size.setHeight((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
} else if (valuatorAtom == QXcbAtom::AbsX) {
caps |= QTouchDevice::Position;
- dev.size.setWidth((vci->max - vci->min) * 1000.0 / vciResolution);
+ dev.size.setWidth((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
} else if (valuatorAtom == QXcbAtom::AbsY) {
caps |= QTouchDevice::Position;
- dev.size.setHeight((vci->max - vci->min) * 1000.0 / vciResolution);
+ dev.size.setHeight((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
}
break;
}
@@ -530,7 +521,8 @@ QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info
if (type >= QTouchDevice::TouchScreen && type <= QTouchDevice::TouchPad) {
dev.qtTouchDevice = new QTouchDevice;
- dev.qtTouchDevice->setName(QString::fromUtf8(deviceinfo->name));
+ 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);
@@ -543,89 +535,83 @@ QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info
return isTouchDevice ? &m_touchDevices[deviceinfo->deviceid] : nullptr;
}
-#if defined(XCB_USE_XINPUT21) || QT_CONFIG(tabletevent)
-static inline qreal fixed1616ToReal(FP1616 val)
+#if QT_CONFIG(tabletevent)
+static inline qreal fixed1616ToReal(xcb_input_fp1616_t val)
{
return qreal(val) / 0x10000;
}
-#endif // defined(XCB_USE_XINPUT21) || QT_CONFIG(tabletevent)
+#endif // QT_CONFIG(tabletevent)
void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
{
- xi2PrepareXIGenericDeviceEvent(event);
- xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event);
+ auto *xiEvent = reinterpret_cast<qt_xcb_input_device_event_t *>(event);
int sourceDeviceId = xiEvent->deviceid; // may be the master id
- xXIDeviceEvent *xiDeviceEvent = 0;
- xXIEnterEvent *xiEnterEvent = 0;
+ qt_xcb_input_device_event_t *xiDeviceEvent = nullptr;
+ xcb_input_enter_event_t *xiEnterEvent = nullptr;
QXcbWindowEventListener *eventListener = 0;
- switch (xiEvent->evtype) {
- case XI_ButtonPress:
- case XI_ButtonRelease:
- case XI_Motion:
-#ifdef XCB_USE_XINPUT22
- case XI_TouchBegin:
- case XI_TouchUpdate:
- case XI_TouchEnd:
-#endif
+ switch (xiEvent->event_type) {
+ case XCB_INPUT_BUTTON_PRESS:
+ case XCB_INPUT_BUTTON_RELEASE:
+ case XCB_INPUT_MOTION:
+ case XCB_INPUT_TOUCH_BEGIN:
+ case XCB_INPUT_TOUCH_UPDATE:
+ case XCB_INPUT_TOUCH_END:
{
- xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event);
+ xiDeviceEvent = xiEvent;
eventListener = windowEventListenerFromId(xiDeviceEvent->event);
sourceDeviceId = xiDeviceEvent->sourceid; // use the actual device id instead of the master
break;
}
- case XI_Enter:
- case XI_Leave: {
- xiEnterEvent = reinterpret_cast<xXIEnterEvent *>(event);
+ case XCB_INPUT_ENTER:
+ case XCB_INPUT_LEAVE: {
+ xiEnterEvent = reinterpret_cast<xcb_input_enter_event_t *>(event);
eventListener = windowEventListenerFromId(xiEnterEvent->event);
sourceDeviceId = xiEnterEvent->sourceid; // use the actual device id instead of the master
break;
}
- case XI_HierarchyChanged:
- xi2HandleHierarchyEvent(xiEvent);
+ case XCB_INPUT_HIERARCHY:
+ xi2HandleHierarchyEvent(event);
return;
- case XI_DeviceChanged:
- xi2HandleDeviceChangedEvent(xiEvent);
+ case XCB_INPUT_DEVICE_CHANGED:
+ xi2HandleDeviceChangedEvent(event);
return;
default:
break;
}
if (eventListener) {
- long result = 0;
- if (eventListener->handleGenericEvent(reinterpret_cast<xcb_generic_event_t *>(event), &result))
+ if (eventListener->handleNativeEvent(reinterpret_cast<xcb_generic_event_t *>(event)))
return;
}
#if QT_CONFIG(tabletevent)
if (!xiEnterEvent) {
QXcbConnection::TabletData *tablet = tabletDataForDevice(sourceDeviceId);
- if (tablet && xi2HandleTabletEvent(xiEvent, tablet))
+ if (tablet && xi2HandleTabletEvent(event, tablet))
return;
}
#endif // QT_CONFIG(tabletevent)
-#ifdef XCB_USE_XINPUT21
if (ScrollingDevice *device = scrollingDeviceForId(sourceDeviceId))
- xi2HandleScrollEvent(xiEvent, *device);
-#endif // XCB_USE_XINPUT21
+ xi2HandleScrollEvent(event, *device);
-#ifdef XCB_USE_XINPUT22
if (xiDeviceEvent) {
- switch (xiDeviceEvent->evtype) {
- case XI_ButtonPress:
- case XI_ButtonRelease:
- case XI_Motion:
- if (!xi2MouseEventsDisabled() && eventListener && !(xiDeviceEvent->flags & XIPointerEmulated))
+ 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))
eventListener->handleXIMouseEvent(event);
break;
- case XI_TouchBegin:
- case XI_TouchUpdate:
- case XI_TouchEnd:
+ case XCB_INPUT_TOUCH_BEGIN:
+ case XCB_INPUT_TOUCH_UPDATE:
+ case XCB_INPUT_TOUCH_END:
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInputEvents, "XI2 touch event type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f on window %x",
- event->event_type, xiDeviceEvent->sequenceNumber, xiDeviceEvent->detail,
+ 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))
@@ -633,14 +619,13 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
break;
}
} else if (xiEnterEvent && !xi2MouseEventsDisabled() && eventListener) {
- switch (xiEnterEvent->evtype) {
- case XI_Enter:
- case XI_Leave:
+ switch (xiEnterEvent->event_type) {
+ case XCB_INPUT_ENTER:
+ case XCB_INPUT_LEAVE:
eventListener->handleXIEnterLeave(event);
break;
}
}
-#endif // XCB_USE_XINPUT22
}
bool QXcbConnection::xi2MouseEventsDisabled() const
@@ -651,7 +636,6 @@ bool QXcbConnection::xi2MouseEventsDisabled() const
return xi2MouseDisabled || has_xinerama_extension;
}
-#ifdef XCB_USE_XINPUT22
bool QXcbConnection::isTouchScreen(int id)
{
auto device = touchDeviceForId(id);
@@ -660,11 +644,11 @@ bool QXcbConnection::isTouchScreen(int id)
void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindow)
{
- xXIDeviceEvent *xiDeviceEvent = static_cast<xXIDeviceEvent *>(xiDevEvent);
+ auto *xiDeviceEvent = reinterpret_cast<xcb_input_touch_begin_event_t *>(xiDevEvent);
TouchDeviceData *dev = touchDeviceForId(xiDeviceEvent->sourceid);
Q_ASSERT(dev);
const bool firstTouch = dev->touchPoints.isEmpty();
- if (xiDeviceEvent->evtype == XI_TouchBegin) {
+ if (xiDeviceEvent->event_type == XCB_INPUT_TOUCH_BEGIN) {
QWindowSystemInterface::TouchPoint tp;
tp.id = xiDeviceEvent->detail % INT_MAX;
tp.state = Qt::TouchPointPressed;
@@ -735,7 +719,7 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
y = touchPoint.area.center().y();
ny = y / screen->geometry().height();
}
- if (xiDeviceEvent->evtype != XI_TouchEnd) {
+ if (xiDeviceEvent->event_type != XCB_INPUT_TOUCH_END) {
if (!dev->providesTouchOrientation) {
if (w == 0.0)
w = touchPoint.area.width();
@@ -750,8 +734,8 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
}
}
- switch (xiDeviceEvent->evtype) {
- case XI_TouchBegin:
+ switch (xiDeviceEvent->event_type) {
+ case XCB_INPUT_TOUCH_BEGIN:
if (firstTouch) {
dev->firstPressedPosition = QPointF(x, y);
dev->firstPressedNormalPosition = QPointF(nx, ny);
@@ -761,14 +745,12 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
// Touches must be accepted when we are grabbing touch events. Otherwise the entire sequence
// will get replayed when the grab ends.
if (m_xiGrab) {
- // Note that XIAllowTouchEvents is known to deadlock with older libXi versions,
- // for details see qtbase/src/plugins/platforms/xcb/README. This has nothing to
- // do with the XInput protocol version, but is a bug in libXi implementation instead.
- XIAllowTouchEvents(static_cast<Display *>(m_xlib_display), xiDeviceEvent->deviceid,
- xiDeviceEvent->detail, xiDeviceEvent->event, XIAcceptTouch);
+ xcb_input_xi_allow_events(m_connection, XCB_CURRENT_TIME, xiDeviceEvent->deviceid,
+ XCB_INPUT_EVENT_MODE_ACCEPT_TOUCH,
+ xiDeviceEvent->detail, xiDeviceEvent->event);
}
break;
- case XI_TouchUpdate:
+ case XCB_INPUT_TOUCH_UPDATE:
if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) {
qreal dx = (nx - dev->firstPressedNormalPosition.x()) *
dev->size.width() * screen->geometry().width() / screen->physicalSize().width();
@@ -789,14 +771,15 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
xiDeviceEvent->detail == m_startSystemMoveResizeInfo.pointid) {
QXcbWindow *window = platformWindowFromId(m_startSystemMoveResizeInfo.window);
if (window) {
- XIAllowTouchEvents(static_cast<Display *>(m_xlib_display), xiDeviceEvent->deviceid,
- xiDeviceEvent->detail, xiDeviceEvent->event, XIRejectTouch);
+ xcb_input_xi_allow_events(m_connection, XCB_CURRENT_TIME, xiDeviceEvent->deviceid,
+ XCB_INPUT_EVENT_MODE_REJECT_TOUCH,
+ xiDeviceEvent->detail, xiDeviceEvent->event);
window->doStartSystemMoveResize(QPoint(x, y), m_startSystemMoveResizeInfo.corner);
m_startSystemMoveResizeInfo.window = XCB_NONE;
}
}
break;
- case XI_TouchEnd:
+ case XCB_INPUT_TOUCH_END:
touchPoint.state = Qt::TouchPointReleased;
if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) {
qreal dx = (nx - dev->firstPressedNormalPosition.x()) *
@@ -814,7 +797,7 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInputEvents) << " touchpoint " << touchPoint.id << " state " << touchPoint.state << " pos norm " << touchPoint.normalPosition <<
" area " << touchPoint.area << " pressure " << touchPoint.pressure;
- Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods);
+ 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 a touchpoint was released, we can forget it, because the ID won't be reused.
@@ -850,46 +833,46 @@ void QXcbConnection::abortSystemMoveResizeForTouch()
{
m_startSystemMoveResizeInfo.window = XCB_NONE;
}
-#endif // XCB_USE_XINPUT22
bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab)
{
- Display *xDisplay = static_cast<Display *>(xlib_display());
bool ok = false;
if (grab) { // grab
- XIEventMask evmask;
- unsigned char mask[XIMaskLen(XI_LASTEVENT)];
- evmask.mask = mask;
- evmask.mask_len = sizeof(mask);
- memset(mask, 0, sizeof(mask));
- XISetMask(mask, XI_ButtonPress);
- XISetMask(mask, XI_ButtonRelease);
- XISetMask(mask, XI_Motion);
- XISetMask(mask, XI_Enter);
- XISetMask(mask, XI_Leave);
- XISetMask(mask, XI_TouchBegin);
- XISetMask(mask, XI_TouchUpdate);
- XISetMask(mask, XI_TouchEnd);
+ 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 : m_xiMasterPointerIds) {
- evmask.deviceid = id;
- Status result = XIGrabDevice(xDisplay, id, w, CurrentTime, None,
- XIGrabModeAsync, XIGrabModeAsync, False, &evmask);
- if (result != Success) {
+ xcb_generic_error_t *error = nullptr;
+ auto cookie = xcb_input_xi_grab_device(m_connection, w, XCB_CURRENT_TIME, XCB_CURSOR_NONE, id,
+ XCB_INPUT_GRAB_MODE_22_ASYNC, XCB_INPUT_GRAB_MODE_22_ASYNC,
+ false, 1, &mask);
+ auto *reply = xcb_input_xi_grab_device_reply(m_connection, cookie, &error);
+ if (error) {
qCDebug(lcQpaXInput, "failed to grab events for device %d on window %x"
- "(result %d)", id, w, result);
+ "(error code %d)", id, w, error->error_code);
+ free(error);
} else {
// Managed to grab at least one of master pointers, that should be enough
// to properly dismiss windows that rely on mouse grabbing.
ok = true;
}
+ free(reply);
}
} else { // ungrab
for (int id : m_xiMasterPointerIds) {
- Status result = XIUngrabDevice(xDisplay, id, CurrentTime);
- if (result != Success)
- qCDebug(lcQpaXInput, "XIUngrabDevice failed - id: %d (result %d)", id, result);
+ auto cookie = xcb_input_xi_ungrab_device_checked(m_connection, XCB_CURRENT_TIME, id);
+ xcb_generic_error_t *error = xcb_request_check(m_connection, cookie);
+ if (error) {
+ qCDebug(lcQpaXInput, "XIUngrabDevice failed - id: %d (error code %d)", id, error->error_code);
+ free(error);
+ }
}
// XIUngrabDevice does not seem to wait for a reply from X server (similar to
// xcb_ungrab_pointer). Ungrabbing won't fail, unless NoSuchExtension error
@@ -906,9 +889,9 @@ bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab)
void QXcbConnection::xi2HandleHierarchyEvent(void *event)
{
- xXIHierarchyEvent *xiEvent = reinterpret_cast<xXIHierarchyEvent *>(event);
+ auto *xiEvent = reinterpret_cast<xcb_input_hierarchy_event_t *>(event);
// We only care about hotplugged devices
- if (!(xiEvent->flags & (XISlaveRemoved | XISlaveAdded)))
+ if (!(xiEvent->flags & (XCB_INPUT_HIERARCHY_MASK_SLAVE_REMOVED | XCB_INPUT_HIERARCHY_MASK_SLAVE_ADDED)))
return;
xi2SetupDevices();
@@ -925,23 +908,19 @@ void QXcbConnection::xi2HandleHierarchyEvent(void *event)
void QXcbConnection::xi2HandleDeviceChangedEvent(void *event)
{
- xXIDeviceChangedEvent *xiEvent = reinterpret_cast<xXIDeviceChangedEvent *>(event);
+ auto *xiEvent = reinterpret_cast<xcb_input_device_changed_event_t *>(event);
switch (xiEvent->reason) {
- case XIDeviceChange: {
- int nrDevices = 0;
- Display *dpy = static_cast<Display *>(m_xlib_display);
- XIDeviceInfo* deviceInfo = XIQueryDevice(dpy, xiEvent->sourceid, &nrDevices);
- if (nrDevices <= 0)
+ case XCB_INPUT_CHANGE_REASON_DEVICE_CHANGE: {
+ auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, m_connection, xiEvent->sourceid);
+ if (!reply || reply->num_infos <= 0)
return;
- xi2SetupDevice(deviceInfo);
- XIFreeDeviceInfo(deviceInfo);
+ auto it = xcb_input_xi_query_device_infos_iterator(reply.get());
+ xi2SetupDevice(it.data);
break;
}
- case XISlaveSwitch: {
-#ifdef XCB_USE_XINPUT21
+ case XCB_INPUT_CHANGE_REASON_SLAVE_SWITCH: {
if (ScrollingDevice *scrollingDevice = scrollingDeviceForId(xiEvent->sourceid))
xi2UpdateScrollingDevice(*scrollingDevice);
-#endif
break;
}
default:
@@ -950,28 +929,28 @@ void QXcbConnection::xi2HandleDeviceChangedEvent(void *event)
}
}
-#ifdef XCB_USE_XINPUT21
void QXcbConnection::xi2UpdateScrollingDevice(ScrollingDevice &scrollingDevice)
{
- int nrDevices = 0;
- Display *dpy = static_cast<Display *>(m_xlib_display);
- XIDeviceInfo* deviceInfo = XIQueryDevice(dpy, scrollingDevice.deviceId, &nrDevices);
- if (nrDevices <= 0) {
+ auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, m_connection, scrollingDevice.deviceId);
+ if (!reply || reply->num_infos <= 0) {
qCDebug(lcQpaXInputDevices, "scrolling device %d no longer present", scrollingDevice.deviceId);
return;
}
QPointF lastScrollPosition;
if (lcQpaXInputEvents().isDebugEnabled())
lastScrollPosition = scrollingDevice.lastScrollPosition;
- for (int c = 0; c < deviceInfo->num_classes; ++c) {
- XIAnyClassInfo *classInfo = deviceInfo->classes[c];
- if (classInfo->type == XIValuatorClass) {
- XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(classInfo);
+
+ 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);
+ for (; classes_it.rem; xcb_input_device_class_next(&classes_it)) {
+ xcb_input_device_class_t *classInfo = classes_it.data;
+ 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(vci->value);
+ scrollingDevice.lastScrollPosition.setX(fixed3232ToReal(vci->value));
else if (valuatorAtom == QXcbAtom::RelVertScroll || valuatorAtom == QXcbAtom::RelVertWheel)
- scrollingDevice.lastScrollPosition.setY(vci->value);
+ scrollingDevice.lastScrollPosition.setY(fixed3232ToReal(vci->value));
}
}
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled() && lastScrollPosition != scrollingDevice.lastScrollPosition))
@@ -979,8 +958,6 @@ void QXcbConnection::xi2UpdateScrollingDevice(ScrollingDevice &scrollingDevice)
lastScrollPosition.x(), lastScrollPosition.y(),
scrollingDevice.lastScrollPosition.x(),
scrollingDevice.lastScrollPosition.y());
-
- XIFreeDeviceInfo(deviceInfo);
}
void QXcbConnection::xi2UpdateScrollingDevices()
@@ -1003,10 +980,9 @@ QXcbConnection::ScrollingDevice *QXcbConnection::scrollingDeviceForId(int id)
void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice)
{
- xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event);
+ auto *xiDeviceEvent = reinterpret_cast<qt_xcb_input_device_event_t *>(event);
- if (xiEvent->evtype == XI_Motion && scrollingDevice.orientations) {
- xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event);
+ if (xiDeviceEvent->event_type == XCB_INPUT_MOTION && scrollingDevice.orientations) {
if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
QPoint rawDelta;
QPoint angleDelta;
@@ -1040,17 +1016,16 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin
if (!angleDelta.isNull()) {
QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y));
QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y));
- Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods);
+ Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective);
if (modifiers & Qt::AltModifier) {
std::swap(angleDelta.rx(), angleDelta.ry());
std::swap(rawDelta.rx(), rawDelta.ry());
}
qCDebug(lcQpaXInputEvents) << "scroll wheel @ window pos" << local << "delta px" << rawDelta << "angle" << angleDelta;
- QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiEvent->time, local, global, rawDelta, angleDelta, modifiers);
+ QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, local, global, rawDelta, angleDelta, modifiers);
}
}
- } else if (xiEvent->evtype == XI_ButtonRelease && scrollingDevice.legacyOrientations) {
- xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event);
+ } else if (xiDeviceEvent->event_type == XCB_INPUT_BUTTON_RELEASE && scrollingDevice.legacyOrientations) {
if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
QPoint angleDelta;
if (scrollingDevice.legacyOrientations & Qt::Vertical) {
@@ -1068,16 +1043,15 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin
if (!angleDelta.isNull()) {
QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y));
QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y));
- Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods);
+ Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective);
if (modifiers & Qt::AltModifier)
std::swap(angleDelta.rx(), angleDelta.ry());
qCDebug(lcQpaXInputEvents) << "scroll wheel (button" << xiDeviceEvent->detail << ") @ window pos" << local << "delta angle" << angleDelta;
- QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiEvent->time, local, global, QPoint(), angleDelta, modifiers);
+ QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, local, global, QPoint(), angleDelta, modifiers);
}
}
}
}
-#endif // XCB_USE_XINPUT21
static int xi2ValuatorOffset(const unsigned char *maskPtr, int maskLen, int number)
{
@@ -1100,10 +1074,10 @@ static int xi2ValuatorOffset(const unsigned char *maskPtr, int maskLen, int numb
bool QXcbConnection::xi2GetValuatorValueIfSet(const void *event, int valuatorNum, double *value)
{
- const xXIDeviceEvent *xideviceevent = static_cast<const xXIDeviceEvent *>(event);
- const unsigned char *buttonsMaskAddr = (const unsigned char*)&xideviceevent[1];
- const unsigned char *valuatorsMaskAddr = buttonsMaskAddr + xideviceevent->buttons_len * 4;
- FP3232 *valuatorsValuesAddr = (FP3232*)(valuatorsMaskAddr + xideviceevent->valuators_len * 4);
+ auto *xideviceevent = static_cast<const qt_xcb_input_device_event_t *>(event);
+ auto *buttonsMaskAddr = reinterpret_cast<const unsigned char *>(&xideviceevent[1]);
+ auto *valuatorsMaskAddr = buttonsMaskAddr + xideviceevent->buttons_len * 4;
+ auto *valuatorsValuesAddr = reinterpret_cast<const xcb_input_fp3232_t *>(valuatorsMaskAddr + xideviceevent->valuators_len * 4);
int valuatorOffset = xi2ValuatorOffset(valuatorsMaskAddr, xideviceevent->valuators_len, valuatorNum);
if (valuatorOffset < 0)
@@ -1114,15 +1088,6 @@ bool QXcbConnection::xi2GetValuatorValueIfSet(const void *event, int valuatorNum
return true;
}
-void QXcbConnection::xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event)
-{
- // xcb event structs contain stuff that wasn't on the wire, the full_sequence field
- // adds an extra 4 bytes and generic events cookie data is on the wire right after the standard 32 bytes.
- // Move this data back to have the same layout in memory as it was on the wire
- // and allow casting, overwriting the full_sequence field.
- memmove((char*) event + 32, (char*) event + 36, event->length * 4);
-}
-
Qt::MouseButton QXcbConnection::xiToQtMouseButton(uint32_t b)
{
switch (b) {
@@ -1186,31 +1151,29 @@ static const char *pointerTypeName(QTabletEvent::PointerType ptype) {
bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletData)
{
bool handled = true;
- Display *xDisplay = static_cast<Display *>(m_xlib_display);
- const xXIGenericDeviceEvent *xiEvent = static_cast<const xXIGenericDeviceEvent *>(event);
- const xXIDeviceEvent *xiDeviceEvent = reinterpret_cast<const xXIDeviceEvent *>(xiEvent);
+ const auto *xiDeviceEvent = reinterpret_cast<const qt_xcb_input_device_event_t *>(event);
- switch (xiEvent->evtype) {
- case XI_ButtonPress: {
+ switch (xiDeviceEvent->event_type) {
+ case XCB_INPUT_BUTTON_PRESS: {
Qt::MouseButton b = xiToQtMouseButton(xiDeviceEvent->detail);
tabletData->buttons |= b;
- xi2ReportTabletEvent(xiEvent, tabletData);
+ xi2ReportTabletEvent(event, tabletData);
break;
}
- case XI_ButtonRelease: {
+ case XCB_INPUT_BUTTON_RELEASE: {
Qt::MouseButton b = xiToQtMouseButton(xiDeviceEvent->detail);
tabletData->buttons ^= b;
- xi2ReportTabletEvent(xiEvent, tabletData);
+ xi2ReportTabletEvent(event, tabletData);
break;
}
- case XI_Motion:
- xi2ReportTabletEvent(xiEvent, tabletData);
+ case XCB_INPUT_MOTION:
+ xi2ReportTabletEvent(event, tabletData);
break;
- case XI_PropertyEvent: {
+ case XCB_INPUT_PROPERTY: {
// This is the wacom driver's way of reporting tool proximity.
// The evdev driver doesn't do it this way.
- const xXIPropertyEvent *ev = reinterpret_cast<const xXIPropertyEvent *>(event);
- if (ev->what == XIPropertyModified) {
+ 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)) {
enum WacomSerialIndex {
_WACSER_USB_ID = 0,
@@ -1220,15 +1183,12 @@ bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletD
_WACSER_TOOL_ID,
_WACSER_COUNT
};
- Atom propType;
- int propFormat;
- unsigned long numItems, bytesAfter;
- unsigned char *data;
- if (XIGetProperty(xDisplay, tabletData->deviceId, ev->property, 0, 100,
- 0, AnyPropertyType, &propType, &propFormat,
- &numItems, &bytesAfter, &data) == Success) {
- if (propType == atom(QXcbAtom::INTEGER) && propFormat == 32 && numItems == _WACSER_COUNT) {
- quint32 *ptr = reinterpret_cast<quint32 *>(data);
+
+ auto reply = Q_XCB_REPLY(xcb_input_xi_get_property, m_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) {
+ 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/
// e.g. on Thinkpad Helix, tool ID will be 0 and serial will be 1
@@ -1260,7 +1220,6 @@ bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletD
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));
}
- XFree(data);
}
}
}
@@ -1276,12 +1235,12 @@ bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletD
void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletData)
{
- const xXIDeviceEvent *ev = reinterpret_cast<const xXIDeviceEvent *>(event);
+ auto *ev = reinterpret_cast<const qt_xcb_input_device_event_t *>(event);
QXcbWindow *xcbWindow = platformWindowFromId(ev->event);
if (!xcbWindow)
return;
QWindow *window = xcbWindow->window();
- const Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(ev->mods.effective_mods);
+ const Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(ev->mods.effective);
QPointF local(fixed1616ToReal(ev->event_x), fixed1616ToReal(ev->event_y));
QPointF global(fixed1616ToReal(ev->root_x), fixed1616ToReal(ev->root_y));
double pressure = 0, rotation = 0, tangentialPressure = 0;
@@ -1324,7 +1283,7 @@ void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletD
qCDebug(lcQpaXInputEvents, "XI2 event on tablet %d with tool %s 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),
- ev->sequenceNumber, ev->detail, ev->time,
+ ev->sequence, ev->detail, ev->time,
local.x(), local.y(), global.x(), global.y(),
(int)tabletData->buttons, pressure, xTilt, yTilt, rotation, (int)modifiers);
diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp
index b401100dd4..57629ac03a 100644
--- a/src/plugins/platforms/xcb/qxcbcursor.cpp
+++ b/src/plugins/platforms/xcb/qxcbcursor.cpp
@@ -628,6 +628,12 @@ xcb_cursor_t QXcbCursor::createBitmapCursor(QCursor *cursor)
}
#endif
+/*! \internal
+
+ Note that the logical state of a device (as seen by means of the protocol) may
+ lag the physical state if device event processing is frozen. See QueryPointer
+ in X11 protocol specification.
+*/
void QXcbCursor::queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDesktop, QPoint *pos, int *keybMask)
{
if (pos)
diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp
index c8ba33edf5..aa329d8cb7 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.cpp
+++ b/src/plugins/platforms/xcb/qxcbdrag.cpp
@@ -63,19 +63,6 @@
QT_BEGIN_NAMESPACE
-//#define DND_DEBUG
-#ifdef DND_DEBUG
-#define DEBUG qDebug
-#else
-#define DEBUG if(0) qDebug
-#endif
-
-#ifdef DND_DEBUG
-#define DNDDEBUG qDebug()
-#else
-#define DNDDEBUG if(0) qDebug()
-#endif
-
const int xdnd_version = 5;
static inline xcb_window_t xcb_window(QPlatformWindow *w)
@@ -164,8 +151,12 @@ void QXcbDrag::init()
QXcbCursor::queryPointer(connection(), &current_virtual_desktop, 0);
drag_types.clear();
+ //current_embedding_widget = 0;
+
dropped = false;
canceled = false;
+
+ source_sameanswer = QRect();
}
bool QXcbDrag::eventFilter(QObject *o, QEvent *e)
@@ -181,11 +172,10 @@ bool QXcbDrag::eventFilter(QObject *o, QEvent *e)
void QXcbDrag::startDrag()
{
- // #fixme enableEventFilter();
-
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
@@ -211,6 +201,9 @@ void QXcbDrag::startDrag()
QBasicDrag::startDrag();
if (connection()->mouseGrabber() == nullptr)
shapedPixmapWindow()->setMouseGrabEnabled(true);
+
+ auto nativePixelPos = QHighDpi::toNativePixels(QCursor::pos(), initiatorWindow);
+ move(nativePixelPos, QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
}
void QXcbDrag::endDrag()
@@ -307,34 +300,13 @@ xcb_window_t QXcbDrag::findRealWindow(const QPoint & pos, xcb_window_t w, int md
return 0;
}
-void QXcbDrag::move(const QPoint &globalPos)
+bool QXcbDrag::findXdndAwareTarget(const QPoint &globalPos, xcb_window_t *target_out)
{
-
- if (source_sameanswer.contains(globalPos) && source_sameanswer.isValid())
- return;
-
- QXcbVirtualDesktop *virtualDesktop = nullptr;
- QPoint cursorPos;
- QXcbCursor::queryPointer(connection(), &virtualDesktop, &cursorPos);
- QXcbScreen *screen = virtualDesktop->screenAt(cursorPos);
- QPoint deviceIndependentPos = QHighDpiScaling::mapPositionFromNative(globalPos, screen);
-
- if (virtualDesktop != current_virtual_desktop) {
- setUseCompositing(virtualDesktop->compositingActive());
- recreateShapedPixmapWindow(static_cast<QPlatformScreen*>(screen)->screen(), deviceIndependentPos);
- if (connection()->mouseGrabber() == nullptr)
- shapedPixmapWindow()->setMouseGrabEnabled(true);
-
- current_virtual_desktop = virtualDesktop;
- } else {
- QBasicDrag::moveShapedPixmapWindow(deviceIndependentPos);
- }
-
xcb_window_t rootwin = current_virtual_desktop->root();
- auto translate = Q_XCB_REPLY(xcb_translate_coordinates, connection()->xcb_connection(),
+ auto translate = Q_XCB_REPLY(xcb_translate_coordinates, xcb_connection(),
rootwin, rootwin, globalPos.x(), globalPos.y());
if (!translate)
- return;
+ return false;
xcb_window_t target = translate->child;
int lx = translate->dst_x;
@@ -343,10 +315,9 @@ void QXcbDrag::move(const QPoint &globalPos)
if (target && target != rootwin) {
xcb_window_t src = rootwin;
while (target != 0) {
- DNDDEBUG << "checking target for XdndAware" << target << lx << ly;
+ qCDebug(lcQpaXDnd) << "checking target for XdndAware" << target;
- // translate coordinates
- auto translate = Q_XCB_REPLY(xcb_translate_coordinates, connection()->xcb_connection(),
+ auto translate = Q_XCB_REPLY(xcb_translate_coordinates, xcb_connection(),
src, target, lx, ly);
if (!translate) {
target = 0;
@@ -357,12 +328,11 @@ void QXcbDrag::move(const QPoint &globalPos)
src = target;
xcb_window_t child = translate->child;
- // check if it has XdndAware
auto reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(), false, target,
atom(QXcbAtom::XdndAware), XCB_GET_PROPERTY_TYPE_ANY, 0, 0);
bool aware = reply && reply->type != XCB_NONE;
if (aware) {
- DNDDEBUG << "Found XdndAware on " << target;
+ qCDebug(lcQpaXDnd) << "found XdndAware on" << target;
break;
}
@@ -370,14 +340,45 @@ void QXcbDrag::move(const QPoint &globalPos)
}
if (!target || target == shapedPixmapWindow()->handle()->winId()) {
- DNDDEBUG << "need to find real window";
+ qCDebug(lcQpaXDnd) << "need to find real window";
target = findRealWindow(globalPos, rootwin, 6, true);
if (target == 0)
target = findRealWindow(globalPos, rootwin, 6, false);
- DNDDEBUG << "real window found" << target;
+ qCDebug(lcQpaXDnd) << "real window found" << target;
}
}
+ *target_out = target;
+ return true;
+}
+
+void QXcbDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
+{
+ // The source sends XdndEnter and XdndPosition to the target.
+ if (source_sameanswer.contains(globalPos) && source_sameanswer.isValid())
+ return;
+
+ QXcbVirtualDesktop *virtualDesktop = nullptr;
+ QPoint cursorPos;
+ QXcbCursor::queryPointer(connection(), &virtualDesktop, &cursorPos);
+ QXcbScreen *screen = virtualDesktop->screenAt(cursorPos);
+ QPoint deviceIndependentPos = QHighDpiScaling::mapPositionFromNative(globalPos, screen);
+
+ if (virtualDesktop != current_virtual_desktop) {
+ setUseCompositing(virtualDesktop->compositingActive());
+ recreateShapedPixmapWindow(static_cast<QPlatformScreen*>(screen)->screen(), deviceIndependentPos);
+ if (connection()->mouseGrabber() == nullptr)
+ shapedPixmapWindow()->setMouseGrabEnabled(true);
+
+ current_virtual_desktop = virtualDesktop;
+ } else {
+ QBasicDrag::moveShapedPixmapWindow(deviceIndependentPos);
+ }
+
+ xcb_window_t target;
+ if (!findXdndAwareTarget(globalPos, &target))
+ return;
+
QXcbWindow *w = 0;
if (target) {
w = connection()->platformWindowFromId(target);
@@ -385,7 +386,7 @@ void QXcbDrag::move(const QPoint &globalPos)
w = 0;
} else {
w = 0;
- target = rootwin;
+ target = current_virtual_desktop->root();
}
xcb_window_t proxy_target = xdndProxy(connection(), target);
@@ -427,13 +428,14 @@ void QXcbDrag::move(const QPoint &globalPos)
enter.data.data32[0] = 0;
#endif
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;
- enter.data.data32[4] = drag_types.size()>2 ? drag_types.at(2) : 0;
+ 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;
+ enter.data.data32[4] = drag_types.size() > 2 ? drag_types.at(2) : 0;
// provisionally set the rectangle to 5x5 pixels...
- source_sameanswer = QRect(globalPos.x() - 2, globalPos.y() -2 , 5, 5);
+ source_sameanswer = QRect(globalPos.x() - 2, globalPos.y() - 2 , 5, 5);
+
+ qCDebug(lcQpaXDnd) << "sending XdndEnter to target:" << target;
- DEBUG() << "sending Xdnd enter source=" << enter.data.data32[0];
if (w)
handleEnter(w, &enter, current_proxy_target);
else if (target)
@@ -447,7 +449,8 @@ void QXcbDrag::move(const QPoint &globalPos)
if (target) {
waiting_for_status = true;
-
+ // The source sends a ClientMessage of type XdndPosition. This tells the target the
+ // position of the mouse and the action that the user requested.
xcb_client_message_event_t move;
move.response_type = XCB_CLIENT_MESSAGE;
move.sequence = 0;
@@ -462,21 +465,34 @@ void QXcbDrag::move(const QPoint &globalPos)
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(), QGuiApplication::keyboardModifiers()));
- DEBUG() << "sending Xdnd position source=" << move.data.data32[0] << "target=" << move.window;
+ move.data.data32[4] = toXdndAction(defaultAction(currentDrag()->supportedActions(), mods));
+
+ qCDebug(lcQpaXDnd) << "sending XdndPosition to target:" << target;
source_time = connection()->time();
if (w)
- handle_xdnd_position(w, &move);
+ handle_xdnd_position(w, &move, b, mods);
else
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"))
+ xdndCollectionWindow = target;
+ }
+ if (target == xdndCollectionWindow) {
+ setCanDrop(false);
+ updateCursor(Qt::IgnoreAction);
+ }
}
-void QXcbDrag::drop(const QPoint &globalPos)
+void QXcbDrag::drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
{
- QBasicDrag::drop(globalPos);
+ // XdndDrop is sent from source to target to complete the drop.
+ QBasicDrag::drop(globalPos, b, mods);
if (!current_target)
return;
@@ -500,7 +516,7 @@ void QXcbDrag::drop(const QPoint &globalPos)
QXcbWindow *w = connection()->platformWindowFromId(current_proxy_target);
- if (w && (w->window()->type() == Qt::Desktop) /*&& !w->acceptDrops()*/)
+ if (w && w->window()->type() == Qt::Desktop) // && !w->acceptDrops()
w = 0;
Transaction t = {
@@ -519,16 +535,13 @@ void QXcbDrag::drop(const QPoint &globalPos)
cleanup_timer = startTimer(XdndDropTransactionTimeout);
}
+ qCDebug(lcQpaXDnd) << "sending drop to target:" << current_target;
+
if (w) {
- handleDrop(w, &drop);
+ handleDrop(w, &drop, b, mods);
} else {
xcb_send_event(xcb_connection(), false, current_proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&drop);
}
-
- current_target = 0;
- current_proxy_target = 0;
- source_time = 0;
-// current_embedding_widget = 0;
}
Qt::DropAction QXcbDrag::toDropAction(xcb_atom_t a) const
@@ -586,44 +599,6 @@ int QXcbDrag::findTransactionByTime(xcb_timestamp_t timestamp)
}
#if 0
-
-// find an ancestor with XdndAware on it
-static Window findXdndAwareParent(Window window)
-{
- Window target = 0;
- forever {
- // check if window has XdndAware
- Atom type = 0;
- int f;
- unsigned long n, a;
- unsigned char *data = 0;
- if (XGetWindowProperty(X11->display, window, ATOM(XdndAware), 0, 0, False,
- AnyPropertyType, &type, &f,&n,&a,&data) == Success) {
- if (data)
- XFree(data);
- if (type) {
- target = window;
- break;
- }
- }
-
- // try window's parent
- Window root;
- Window parent;
- Window *children;
- uint unused;
- if (!XQueryTree(X11->display, window, &root, &parent, &children, &unused))
- break;
- if (children)
- XFree(children);
- if (window == root)
- break;
- window = parent;
- }
- return target;
-}
-
-
// for embedding only
static QWidget* current_embedding_widget = 0;
static xcb_client_message_event_t last_enter_event;
@@ -665,11 +640,10 @@ static bool checkEmbedded(QWidget* w, const XEvent* xe)
}
#endif
-
-void QXcbDrag::handleEnter(QPlatformWindow *window, const xcb_client_message_event_t *event, xcb_window_t proxy)
+void QXcbDrag::handleEnter(QPlatformWindow *, const xcb_client_message_event_t *event, xcb_window_t proxy)
{
- Q_UNUSED(window);
- DEBUG() << "handleEnter" << window;
+ // The target receives XdndEnter.
+ qCDebug(lcQpaXDnd) << "target:" << event->window << "received XdndEnter";
xdnd_types.clear();
@@ -705,11 +679,16 @@ void QXcbDrag::handleEnter(QPlatformWindow *window, const xcb_client_message_eve
}
}
for(int i = 0; i < xdnd_types.length(); ++i)
- DEBUG() << " " << connection()->atomName(xdnd_types.at(i));
+ qCDebug(lcQpaXDnd) << " " << connection()->atomName(xdnd_types.at(i));
}
-void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message_event_t *e)
+void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message_event_t *e,
+ Qt::MouseButtons b, Qt::KeyboardModifiers mods)
{
+ // The target receives XdndPosition. The target window must determine which widget the mouse
+ // is in and ask it whether or not it will accept the drop.
+ qCDebug(lcQpaXDnd) << "target:" << e->window << "received XdndPosition";
+
QPoint p((e->data.data32[2] & 0xffff0000) >> 16, e->data.data32[2] & 0x0000ffff);
Q_ASSERT(w);
QRect geometry = w->geometry();
@@ -718,8 +697,9 @@ void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message
if (!w || !w->window() || (w->window()->type() == Qt::Desktop))
return;
- if (e->data.data32[0] != xdnd_dragsource) {
- DEBUG("xdnd drag position from unexpected source (%x not %x)", e->data.data32[0], xdnd_dragsource);
+ if (Q_UNLIKELY(e->data.data32[0] != xdnd_dragsource)) {
+ qCDebug(lcQpaXDnd, "xdnd drag position from unexpected source (%x not %x)",
+ e->data.data32[0], xdnd_dragsource);
return;
}
@@ -741,10 +721,19 @@ void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message
supported_actions = Qt::DropActions(toDropAction(e->data.data32[4]));
}
- QPlatformDragQtResponse qt_response = QWindowSystemInterface::handleDrag(w->window(),dropData,p,supported_actions);
+ auto buttons = currentDrag() ? b : connection()->queryMouseButtons();
+ auto modifiers = currentDrag() ? mods : connection()->queryKeyboardModifiers();
+
+ QPlatformDragQtResponse qt_response = QWindowSystemInterface::handleDrag(
+ w->window(), dropData, p, supported_actions, buttons, modifiers);
+
+ // ### FIXME ? - answerRect appears to be unused.
QRect answerRect(p + geometry.topLeft(), QSize(1,1));
answerRect = qt_response.answerRect().translated(geometry.topLeft()).intersected(geometry);
+ // The target sends a ClientMessage of type XdndStatus. This tells the source whether or not
+ // it will accept the drop, and, if so, what action will be taken. It also includes a rectangle
+ // that means "don't send another XdndPosition message until the mouse moves out of here".
xcb_client_message_event_t response;
response.response_type = XCB_CLIENT_MESSAGE;
response.sequence = 0;
@@ -775,13 +764,15 @@ void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message
// reset
target_time = XCB_CURRENT_TIME;
+ qCDebug(lcQpaXDnd) << "sending XdndStatus to source:" << xdnd_dragsource;
+
#ifndef QT_NO_CLIPBOARD
if (xdnd_dragsource == connection()->clipboard()->owner())
handle_xdnd_status(&response);
else
#endif
- xcb_send_event(xcb_connection(), false, current_proxy_target,
- XCB_EVENT_MASK_NO_EVENT, (const char *)&response);
+ xcb_send_event(xcb_connection(), false, current_proxy_target,
+ XCB_EVENT_MASK_NO_EVENT, (const char *)&response);
}
namespace
@@ -790,12 +781,11 @@ namespace
public:
ClientMessageScanner(xcb_atom_t a) : atom(a) {}
xcb_atom_t atom;
- bool checkEvent(xcb_generic_event_t *event) const {
- if (!event)
+ bool operator() (xcb_generic_event_t *event, int type) const {
+ if (type != XCB_CLIENT_MESSAGE)
return false;
- if ((event->response_type & 0x7f) != XCB_CLIENT_MESSAGE)
- return false;
- return ((xcb_client_message_event_t *)event)->type == atom;
+ auto clientMessage = reinterpret_cast<xcb_client_message_event_t *>(event);
+ return clientMessage->type == atom;
}
};
}
@@ -803,12 +793,11 @@ 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);
- xcb_generic_event_t *nextEvent;
ClientMessageScanner scanner(atom(QXcbAtom::XdndPosition));
- while ((nextEvent = connection()->checkEvent(scanner))) {
+ while (auto nextEvent = connection()->eventQueue()->peek(scanner)) {
if (lastEvent != event)
free(lastEvent);
- lastEvent = (xcb_client_message_event_t *)nextEvent;
+ lastEvent = reinterpret_cast<xcb_client_message_event_t *>(nextEvent);
}
handle_xdnd_position(w, lastEvent);
@@ -818,7 +807,9 @@ void QXcbDrag::handlePosition(QPlatformWindow * w, const xcb_client_message_even
void QXcbDrag::handle_xdnd_status(const xcb_client_message_event_t *event)
{
- DEBUG("xdndHandleStatus");
+ // The source receives XdndStatus. It can use the action to change the cursor to indicate
+ // whether or not the user's requested action will be performed.
+ qCDebug(lcQpaXDnd) << "source:" << event->window << "received XdndStatus";
waiting_for_status = false;
// ignore late status messages
if (event->data.data32[0] && event->data.data32[0] != current_target)
@@ -855,7 +846,7 @@ void QXcbDrag::handleStatus(const xcb_client_message_event_t *event)
xcb_client_message_event_t *lastEvent = const_cast<xcb_client_message_event_t *>(event);
xcb_generic_event_t *nextEvent;
ClientMessageScanner scanner(atom(QXcbAtom::XdndStatus));
- while ((nextEvent = connection()->checkEvent(scanner))) {
+ while ((nextEvent = connection()->eventQueue()->peek(scanner))) {
if (lastEvent != event)
free(lastEvent);
lastEvent = (xcb_client_message_event_t *)nextEvent;
@@ -864,12 +855,13 @@ void QXcbDrag::handleStatus(const xcb_client_message_event_t *event)
handle_xdnd_status(lastEvent);
if (lastEvent != event)
free(lastEvent);
- DEBUG("xdndHandleStatus end");
}
void QXcbDrag::handleLeave(QPlatformWindow *w, const xcb_client_message_event_t *event)
{
- DEBUG("xdnd leave");
+ // 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())
return; // sanity
@@ -882,22 +874,19 @@ void QXcbDrag::handleLeave(QPlatformWindow *w, const xcb_client_message_event_t
if (event->data.data32[0] != xdnd_dragsource) {
// This often happens - leave other-process window quickly
- DEBUG("xdnd drag leave from unexpected source (%x not %x", event->data.data32[0], xdnd_dragsource);
+ qCDebug(lcQpaXDnd, "xdnd drag leave from unexpected source (%x not %x",
+ event->data.data32[0], xdnd_dragsource);
}
- QWindowSystemInterface::handleDrag(w->window(),0,QPoint(),Qt::IgnoreAction);
-
- xdnd_dragsource = 0;
- xdnd_types.clear();
- currentWindow.clear();
+ QWindowSystemInterface::handleDrag(w->window(), nullptr, QPoint(), Qt::IgnoreAction, 0, 0);
}
void QXcbDrag::send_leave()
{
+ // XdndLeave is sent from the source to the target to cancel the drop.
if (!current_target)
return;
-
xcb_client_message_event_t leave;
leave.response_type = XCB_CLIENT_MESSAGE;
leave.sequence = 0;
@@ -919,21 +908,21 @@ void QXcbDrag::send_leave()
if (w && (w->window()->type() == Qt::Desktop) /*&& !w->acceptDrops()*/)
w = 0;
+ qCDebug(lcQpaXDnd) << "sending XdndLeave to target:" << current_target;
+
if (w)
handleLeave(w, (const xcb_client_message_event_t *)&leave);
else
xcb_send_event(xcb_connection(), false,current_proxy_target,
XCB_EVENT_MASK_NO_EVENT, (const char *)&leave);
-
- current_target = 0;
- current_proxy_target = 0;
- source_time = XCB_CURRENT_TIME;
- waiting_for_status = false;
}
-void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *event)
+void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *event,
+ Qt::MouseButtons b, Qt::KeyboardModifiers mods)
{
- DEBUG("xdndHandleDrop");
+ // Target receives XdndDrop. Once it is finished processing the drop, it sends XdndFinished.
+ qCDebug(lcQpaXDnd) << "target:" << event->window << "received XdndDrop";
+
if (!currentWindow) {
xdnd_dragsource = 0;
return; // sanity
@@ -941,16 +930,14 @@ void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *e
const uint32_t *l = event->data.data32;
- DEBUG("xdnd drop");
-
if (l[0] != xdnd_dragsource) {
- DEBUG("xdnd drop from unexpected source (%x not %x", l[0], xdnd_dragsource);
+ qCDebug(lcQpaXDnd, "xdnd drop from unexpected source (%x not %x", l[0], xdnd_dragsource);
return;
}
// update the "user time" from the timestamp in the event.
if (l[2] != 0)
- target_time = /*X11->userTime =*/ l[2];
+ target_time = l[2];
Qt::DropActions supported_drop_actions;
QMimeData *dropData = 0;
@@ -960,9 +947,6 @@ void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *e
} else {
dropData = m_dropData;
supported_drop_actions = accepted_drop_action;
-
- // Drop coming from another app? Update keyboard modifiers.
- QGuiApplicationPrivate::modifier_buttons = QGuiApplication::queryKeyboardModifiers();
}
if (!dropData)
@@ -973,7 +957,13 @@ void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *e
// dropData = QDragManager::dragPrivate(X11->dndDropTransactions.at(at).object)->data;
// if we can't find it, then use the data in the drag manager
- QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(currentWindow.data(),dropData,currentPosition,supported_drop_actions);
+ auto buttons = currentDrag() ? b : connection()->queryMouseButtons();
+ auto modifiers = currentDrag() ? mods : connection()->queryKeyboardModifiers();
+
+ QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(
+ currentWindow.data(), dropData, currentPosition, supported_drop_actions,
+ buttons, modifiers);
+
setExecutedDropAction(response.acceptedAction());
xcb_client_message_event_t finished;
@@ -985,34 +975,26 @@ void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *e
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());
- xcb_send_event(xcb_connection(), false, current_proxy_target,
- XCB_EVENT_MASK_NO_EVENT, (char *)&finished);
- xdnd_dragsource = 0;
- currentWindow.clear();
- waiting_for_status = false;
+ qCDebug(lcQpaXDnd) << "sending XdndFinished to source:" << xdnd_dragsource;
- // reset
- target_time = XCB_CURRENT_TIME;
+ xcb_send_event(xcb_connection(), false, current_proxy_target,
+ XCB_EVENT_MASK_NO_EVENT, (char *)&finished);
dropped = true;
}
-
void QXcbDrag::handleFinished(const xcb_client_message_event_t *event)
{
- DEBUG("xdndHandleFinished");
+ // 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())
return;
#endif
const unsigned long *l = (const unsigned long *)event->data.data32;
-
- DNDDEBUG << "xdndHandleFinished, l[0]" << l[0]
- << "current_target" << current_target
- << "qt_xdnd_current_proxy_targe" << current_proxy_target;
-
if (l[0]) {
int at = findTransactionByWindow(l[0]);
if (at != -1) {
@@ -1087,7 +1069,8 @@ void QXcbDrag::timerEvent(QTimerEvent* e)
void QXcbDrag::cancel()
{
- DEBUG("QXcbDrag::cancel");
+ qCDebug(lcQpaXDnd) << "dnd was canceled";
+
QBasicDrag::cancel();
if (current_target)
send_leave();
@@ -1098,7 +1081,6 @@ void QXcbDrag::cancel()
canceled = true;
}
-// find an ancestor with XdndAware on it
static xcb_window_t findXdndAwareParent(QXcbConnection *c, xcb_window_t window)
{
xcb_window_t target = 0;
@@ -1127,7 +1109,8 @@ static xcb_window_t findXdndAwareParent(QXcbConnection *c, xcb_window_t window)
void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event)
{
- Q_DECLARE_XCB_EVENT(notify, xcb_selection_notify_event_t);
+ qCDebug(lcQpaXDnd) << "handle selection request from target:" << event->requestor;
+ q_padded_xcb_event<xcb_selection_notify_event_t> notify = {};
notify.response_type = XCB_SELECTION_NOTIFY;
notify.requestor = event->requestor;
notify.selection = event->selection;
@@ -1194,10 +1177,10 @@ void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event
bool QXcbDrag::dndEnable(QXcbWindow *w, bool on)
{
- DNDDEBUG << "xdndEnable" << w << on;
+ // Windows announce that they support the XDND protocol by creating a window property XdndAware.
if (on) {
- QXcbWindow *xdnd_widget = 0;
- if ((w->window()->type() == Qt::Desktop)) {
+ QXcbWindow *window = nullptr;
+ if (w->window()->type() == Qt::Desktop) {
if (desktop_proxy) // *WE* already have one.
return false;
@@ -1208,8 +1191,8 @@ bool QXcbDrag::dndEnable(QXcbWindow *w, bool on)
if (!proxy_id) {
desktop_proxy = new QWindow;
- xdnd_widget = static_cast<QXcbWindow *>(desktop_proxy->handle());
- proxy_id = xdnd_widget->xcb_window();
+ window = static_cast<QXcbWindow *>(desktop_proxy->handle());
+ proxy_id = window->xcb_window();
xcb_atom_t xdnd_proxy = atom(QXcbAtom::XdndProxy);
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, w->xcb_window(), xdnd_proxy,
XCB_ATOM_WINDOW, 32, 1, &proxy_id);
@@ -1218,24 +1201,24 @@ bool QXcbDrag::dndEnable(QXcbWindow *w, bool on)
}
} else {
- xdnd_widget = w;
+ window = w;
}
- if (xdnd_widget) {
- DNDDEBUG << "setting XdndAware for" << xdnd_widget << xdnd_widget->xcb_window();
+ if (window) {
+ qCDebug(lcQpaXDnd) << "setting XdndAware for" << window->xcb_window();
xcb_atom_t atm = xdnd_version;
- xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, xdnd_widget->xcb_window(),
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window->xcb_window(),
atom(QXcbAtom::XdndAware), XCB_ATOM_ATOM, 32, 1, &atm);
return true;
} else {
return false;
}
} else {
- if ((w->window()->type() == Qt::Desktop)) {
+ if (w->window()->type() == Qt::Desktop) {
xcb_delete_property(xcb_connection(), w->xcb_window(), atom(QXcbAtom::XdndProxy));
delete desktop_proxy;
desktop_proxy = 0;
} else {
- DNDDEBUG << "not deleting XDndAware";
+ qCDebug(lcQpaXDnd) << "not deleting XDndAware";
}
return true;
}
@@ -1293,7 +1276,6 @@ QVariant QXcbDropData::xdndObtainData(const QByteArray &format, QVariant::Type r
return mimeConvertToFormat(c, a, result, QLatin1String(format), requestedType, encoding);
}
-
bool QXcbDropData::hasFormat_sys(const QString &format) const
{
return formats().contains(format);
diff --git a/src/plugins/platforms/xcb/qxcbdrag.h b/src/plugins/platforms/xcb/qxcbdrag.h
index 60287b717b..c19008c04b 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.h
+++ b/src/plugins/platforms/xcb/qxcbdrag.h
@@ -78,14 +78,15 @@ public:
void startDrag() override;
void cancel() override;
- void move(const QPoint &globalPos) override;
- void drop(const QPoint &globalPos) override;
+ void move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override;
+ void drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override;
void endDrag() 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);
- void handleDrop(QPlatformWindow *, const xcb_client_message_event_t *event);
+ void handleDrop(QPlatformWindow *, const xcb_client_message_event_t *event,
+ Qt::MouseButtons b = 0, Qt::KeyboardModifiers mods = 0);
void handleStatus(const xcb_client_message_event_t *event);
void handleSelectionRequest(const xcb_selection_request_event_t *event);
@@ -100,12 +101,15 @@ public:
protected:
void timerEvent(QTimerEvent* e) override;
+ bool findXdndAwareTarget(const QPoint &globalPos, xcb_window_t *target_out);
+
private:
friend class QXcbDropData;
void init();
- void handle_xdnd_position(QPlatformWindow *w, const xcb_client_message_event_t *event);
+ void handle_xdnd_position(QPlatformWindow *w, const xcb_client_message_event_t *event,
+ Qt::MouseButtons b = 0, Qt::KeyboardModifiers mods = 0);
void handle_xdnd_status(const xcb_client_message_event_t *event);
void send_leave();
@@ -139,6 +143,9 @@ private:
bool dropped;
bool canceled;
+ // A window from Unity DnD Manager, which does not respect the XDnD spec
+ xcb_window_t xdndCollectionWindow = XCB_NONE;
+
// top-level window we sent position to last.
xcb_window_t current_target;
// window to send events to (always valid if current_target)
diff --git a/src/plugins/platforms/xcb/qxcbeventdispatcher.cpp b/src/plugins/platforms/xcb/qxcbeventdispatcher.cpp
new file mode 100644
index 0000000000..3cb2a5b5ef
--- /dev/null
+++ b/src/plugins/platforms/xcb/qxcbeventdispatcher.cpp
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+#include "qxcbeventdispatcher.h"
+#include "qxcbconnection.h"
+
+#include <QtCore/QCoreApplication>
+
+#include <qpa/qwindowsysteminterface.h>
+
+QT_BEGIN_NAMESPACE
+
+QXcbUnixEventDispatcher::QXcbUnixEventDispatcher(QXcbConnection *connection, QObject *parent)
+ : QEventDispatcherUNIX(parent)
+ , m_connection(connection)
+{
+}
+
+QXcbUnixEventDispatcher::~QXcbUnixEventDispatcher()
+{
+}
+
+bool QXcbUnixEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
+{
+ const bool didSendEvents = QEventDispatcherUNIX::processEvents(flags);
+ m_connection->processXcbEvents(flags);
+ // The following line should not be necessary after QTBUG-70095
+ 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
+{
+ GSource source;
+ QXcbGlibEventDispatcher *dispatcher;
+ QXcbGlibEventDispatcherPrivate *dispatcher_p;
+ QXcbConnection *connection = nullptr;
+};
+
+static gboolean xcbSourcePrepare(GSource *source, gint *timeout)
+{
+ Q_UNUSED(timeout)
+ auto xcbEventSource = reinterpret_cast<XcbEventSource *>(source);
+ return xcbEventSource->dispatcher_p->wakeUpCalled;
+}
+
+static gboolean xcbSourceCheck(GSource *source)
+{
+ return xcbSourcePrepare(source, nullptr);
+}
+
+static gboolean xcbSourceDispatch(GSource *source, GSourceFunc, gpointer)
+{
+ auto xcbEventSource = reinterpret_cast<XcbEventSource *>(source);
+ QEventLoop::ProcessEventsFlags flags = xcbEventSource->dispatcher->flags();
+ xcbEventSource->connection->processXcbEvents(flags);
+ // The following line should not be necessary after QTBUG-70095
+ QWindowSystemInterface::sendWindowSystemEvents(flags);
+ return true;
+}
+
+QXcbGlibEventDispatcher::QXcbGlibEventDispatcher(QXcbConnection *connection, QObject *parent)
+ : QEventDispatcherGlib(*new QXcbGlibEventDispatcherPrivate(), parent)
+{
+ Q_D(QXcbGlibEventDispatcher);
+
+ m_xcbEventSourceFuncs.prepare = xcbSourcePrepare;
+ m_xcbEventSourceFuncs.check = xcbSourceCheck;
+ m_xcbEventSourceFuncs.dispatch = xcbSourceDispatch;
+ m_xcbEventSourceFuncs.finalize = nullptr;
+
+ m_xcbEventSource = reinterpret_cast<XcbEventSource *>(
+ g_source_new(&m_xcbEventSourceFuncs, sizeof(XcbEventSource)));
+
+ m_xcbEventSource->dispatcher = this;
+ m_xcbEventSource->dispatcher_p = d_func();
+ m_xcbEventSource->connection = connection;
+
+ g_source_set_can_recurse(&m_xcbEventSource->source, true);
+ g_source_attach(&m_xcbEventSource->source, d->mainContext);
+}
+
+QXcbGlibEventDispatcherPrivate::QXcbGlibEventDispatcherPrivate()
+{
+}
+
+QXcbGlibEventDispatcher::~QXcbGlibEventDispatcher()
+{
+ g_source_destroy(&m_xcbEventSource->source);
+ g_source_unref(&m_xcbEventSource->source);
+}
+
+bool QXcbGlibEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
+{
+ m_flags = flags;
+ return QEventDispatcherGlib::processEvents(m_flags);
+}
+
+#endif // QT_CONFIG(glib)
+
+QAbstractEventDispatcher *QXcbEventDispatcher::createEventDispatcher(QXcbConnection *connection)
+{
+#if QT_CONFIG(glib)
+ if (qEnvironmentVariableIsEmpty("QT_NO_GLIB") && QEventDispatcherGlib::versionSupported()) {
+ qCDebug(lcQpaXcb, "using glib dispatcher");
+ return new QXcbGlibEventDispatcher(connection);
+ } else
+#endif
+ {
+ qCDebug(lcQpaXcb, "using unix dispatcher");
+ return new QXcbUnixEventDispatcher(connection);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbeventdispatcher.h b/src/plugins/platforms/xcb/qxcbeventdispatcher.h
new file mode 100644
index 0000000000..6aadd63a70
--- /dev/null
+++ b/src/plugins/platforms/xcb/qxcbeventdispatcher.h
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+#ifndef QXCBEVENTDISPATCHER_H
+#define QXCBEVENTDISPATCHER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QEventLoop>
+
+#include <QtCore/private/qeventdispatcher_unix_p.h>
+#if QT_CONFIG(glib)
+#include <QtCore/private/qeventdispatcher_glib_p.h>
+#include <glib.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QXcbConnection;
+
+class QXcbUnixEventDispatcher : public QEventDispatcherUNIX
+{
+ Q_OBJECT
+public:
+ explicit QXcbUnixEventDispatcher(QXcbConnection *connection, QObject *parent = nullptr);
+ ~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;
+};
+
+#if QT_CONFIG(glib)
+
+struct XcbEventSource;
+class QXcbGlibEventDispatcherPrivate;
+
+class QXcbGlibEventDispatcher : public QEventDispatcherGlib
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QXcbGlibEventDispatcher)
+
+public:
+ explicit QXcbGlibEventDispatcher(QXcbConnection *connection, QObject *parent = nullptr);
+ ~QXcbGlibEventDispatcher();
+
+ bool processEvents(QEventLoop::ProcessEventsFlags flags) override;
+ QEventLoop::ProcessEventsFlags flags() const { return m_flags; }
+
+private:
+ XcbEventSource *m_xcbEventSource;
+ GSourceFuncs m_xcbEventSourceFuncs;
+ QEventLoop::ProcessEventsFlags m_flags;
+};
+
+class QXcbGlibEventDispatcherPrivate : public QEventDispatcherGlibPrivate
+{
+ Q_DECLARE_PUBLIC(QXcbGlibEventDispatcher)
+
+public:
+ QXcbGlibEventDispatcherPrivate();
+};
+
+#endif // QT_CONFIG(glib)
+
+class QXcbEventDispatcher
+{
+public:
+ static QAbstractEventDispatcher *createEventDispatcher(QXcbConnection *connection);
+
+private:
+ QXcbConnection *m_connection;
+};
+
+QT_END_NAMESPACE
+
+#endif // QXCBEVENTDISPATCHER_H
diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.cpp b/src/plugins/platforms/xcb/qxcbeventqueue.cpp
new file mode 100644
index 0000000000..20589fc550
--- /dev/null
+++ b/src/plugins/platforms/xcb/qxcbeventqueue.cpp
@@ -0,0 +1,383 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+#include "qxcbeventqueue.h"
+#include "qxcbconnection.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QAbstractEventDispatcher>
+#include <QtCore/QMutex>
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+
+static QBasicMutex qAppExiting;
+static bool dispatcherOwnerDestructing = false;
+
+/*!
+ \class QXcbEventQueue
+ \internal
+
+ Lock-free event passing:
+
+ The lock-free solution uses a singly-linked list to pass events from the
+ reader thread to the main thread. An atomic operation is used to sync the
+ tail node of the list between threads. The reader thread takes special care
+ 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
+ lightweight - no reference counting, back links, etc.
+
+ Memory management:
+
+ In a normally functioning application, XCB plugin won't buffer more than few
+ batches of events, couple events per batch. Instead of constantly calling
+ new / delete, we can create a pool of nodes that we reuse. The main thread
+ uses an atomic operation to sync how many nodes have been restored (available
+ for reuse). If at some point a user application will block the main thread
+ for a long time, we might run out of nodes in the pool. Then we create nodes
+ on a heap. These will be automatically "garbage collected" out of the linked
+ list, once the main thread stops blocking.
+*/
+
+QXcbEventQueue::QXcbEventQueue(QXcbConnection *connection)
+ : m_connection(connection)
+{
+ // When running test cases in auto tests, static variables are preserved
+ // between test function runs, even if Q*Application object is destroyed.
+ // Reset to default value to account for this.
+ dispatcherOwnerDestructing = false;
+ qAddPostRoutine([]() {
+ QMutexLocker locker(&qAppExiting);
+ dispatcherOwnerDestructing = true;
+ });
+
+ // Lets init the list with one node, so we don't have to check for
+ // this special case in various places.
+ m_head = m_flushedTail = qXcbEventNodeFactory(nullptr);
+ m_tail.store(m_head, std::memory_order_release);
+
+ start();
+}
+
+QXcbEventQueue::~QXcbEventQueue()
+{
+ if (isRunning()) {
+ sendCloseConnectionEvent();
+ wait();
+ }
+
+ while (xcb_generic_event_t *event = takeFirst())
+ free(event);
+
+ if (m_head && m_head->fromHeap)
+ delete m_head; // the deferred node
+
+ qCDebug(lcQpaEventReader) << "nodes on heap:" << m_nodesOnHeap;
+}
+
+xcb_generic_event_t *QXcbEventQueue::takeFirst(QEventLoop::ProcessEventsFlags flags)
+{
+ // This is the level at which we were moving excluded user input events into
+ // separate queue in Qt 4 (see qeventdispatcher_x11.cpp). In this case
+ // QXcbEventQueue represents Xlib's internal event queue. In Qt 4, Xlib's
+ // event queue peeking APIs would not see these events anymore, the same way
+ // our peeking functions do not consider m_inputEvents. This design is
+ // intentional to keep the same behavior. We could do filtering directly on
+ // QXcbEventQueue, without the m_inputEvents, but it is not clear if it is
+ // needed by anyone who peeks at the native event queue.
+
+ bool excludeUserInputEvents = flags.testFlag(QEventLoop::ExcludeUserInputEvents);
+ if (excludeUserInputEvents) {
+ xcb_generic_event_t *event = nullptr;
+ while ((event = takeFirst())) {
+ if (m_connection->isUserInputEvent(event)) {
+ m_inputEvents << event;
+ continue;
+ }
+ break;
+ }
+ return event;
+ }
+
+ if (!m_inputEvents.isEmpty())
+ return m_inputEvents.takeFirst();
+ return takeFirst();
+}
+
+xcb_generic_event_t *QXcbEventQueue::takeFirst()
+{
+ if (isEmpty())
+ return nullptr;
+
+ xcb_generic_event_t *event = nullptr;
+ do {
+ event = m_head->event;
+ if (m_head == m_flushedTail) {
+ // defer dequeuing until next successful flush of events
+ if (event) // check if not cleared already by some filter
+ m_head->event = nullptr; // if not, clear it
+ } else {
+ dequeueNode();
+ if (!event)
+ continue; // consumed by filter or deferred node
+ }
+ } while (!isEmpty() && !event);
+
+ m_queueModified = m_peekerIndexCacheDirty = true;
+
+ return event;
+}
+
+void QXcbEventQueue::dequeueNode()
+{
+ QXcbEventNode *node = m_head;
+ m_head = m_head->next;
+ if (node->fromHeap)
+ delete node;
+ else
+ m_nodesRestored.fetch_add(1, std::memory_order_release);
+}
+
+void QXcbEventQueue::flushBufferedEvents()
+{
+ m_flushedTail = m_tail.load(std::memory_order_acquire);
+}
+
+QXcbEventNode *QXcbEventQueue::qXcbEventNodeFactory(xcb_generic_event_t *event)
+{
+ static QXcbEventNode qXcbNodePool[PoolSize];
+
+ if (m_freeNodes == 0) // out of nodes, check if the main thread has released any
+ m_freeNodes = m_nodesRestored.exchange(0, std::memory_order_acquire);
+
+ if (m_freeNodes) {
+ m_freeNodes--;
+ if (m_poolIndex == PoolSize) {
+ // wrap back to the beginning, we always take and restore nodes in-order
+ m_poolIndex = 0;
+ }
+ QXcbEventNode *node = &qXcbNodePool[m_poolIndex++];
+ node->event = event;
+ node->next = nullptr;
+ return node;
+ }
+
+ // the main thread is not flushing events and thus the pool has become empty
+ auto node = new QXcbEventNode(event);
+ node->fromHeap = true;
+ qCDebug(lcQpaEventReader) << "[heap] " << m_nodesOnHeap++;
+ return node;
+}
+
+void QXcbEventQueue::run()
+{
+ xcb_generic_event_t *event = nullptr;
+ xcb_connection_t *connection = m_connection->xcb_connection();
+ QXcbEventNode *tail = m_head;
+
+ auto enqueueEvent = [&tail, this](xcb_generic_event_t *event) {
+ if (!isCloseConnectionEvent(event)) {
+ tail->next = qXcbEventNodeFactory(event);
+ tail = tail->next;
+ m_tail.store(tail, std::memory_order_release);
+ }
+ };
+
+ while (!m_closeConnectionDetected && (event = xcb_wait_for_event(connection))) {
+ enqueueEvent(event);
+ while (!m_closeConnectionDetected && (event = xcb_poll_for_queued_event(connection)))
+ enqueueEvent(event);
+ wakeUpDispatcher();
+ }
+
+ if (!m_closeConnectionDetected) {
+ // Connection was terminated not by us. Wake up dispatcher, which will
+ // call processXcbEvents(), where we handle the connection errors via
+ // xcb_connection_has_error().
+ wakeUpDispatcher();
+ }
+}
+
+void QXcbEventQueue::wakeUpDispatcher()
+{
+ QMutexLocker locker(&qAppExiting);
+ if (!dispatcherOwnerDestructing) {
+ // This thread can run before a dispatcher has been created,
+ // so check if it is ready.
+ if (QCoreApplication::eventDispatcher())
+ QCoreApplication::eventDispatcher()->wakeUp();
+ }
+}
+
+qint32 QXcbEventQueue::generatePeekerId()
+{
+ const qint32 peekerId = m_peekerIdSource++;
+ m_peekerToNode.insert(peekerId, nullptr);
+ return peekerId;
+}
+
+bool QXcbEventQueue::removePeekerId(qint32 peekerId)
+{
+ const auto it = m_peekerToNode.find(peekerId);
+ if (it == m_peekerToNode.constEnd()) {
+ qCWarning(lcQpaXcb, "failed to remove unknown peeker id: %d", peekerId);
+ return false;
+ }
+ m_peekerToNode.erase(it);
+ if (m_peekerToNode.isEmpty()) {
+ m_peekerIdSource = 0; // Once the hash becomes empty, we can start reusing IDs
+ m_peekerIndexCacheDirty = false;
+ }
+ return true;
+}
+
+bool QXcbEventQueue::peekEventQueue(PeekerCallback peeker, void *peekerData,
+ PeekOptions option, qint32 peekerId)
+{
+ const bool peekerIdProvided = peekerId != -1;
+ auto peekerToNodeIt = m_peekerToNode.find(peekerId);
+
+ if (peekerIdProvided && peekerToNodeIt == m_peekerToNode.constEnd()) {
+ qCWarning(lcQpaXcb, "failed to find index for unknown peeker id: %d", peekerId);
+ return false;
+ }
+
+ const bool useCache = option.testFlag(PeekOption::PeekFromCachedIndex);
+ if (useCache && !peekerIdProvided) {
+ qCWarning(lcQpaXcb, "PeekOption::PeekFromCachedIndex requires peeker id");
+ return false;
+ }
+
+ if (peekerIdProvided && m_peekerIndexCacheDirty) {
+ for (auto &node : m_peekerToNode) // reset cache
+ node = nullptr;
+ m_peekerIndexCacheDirty = false;
+ }
+
+ flushBufferedEvents();
+ if (isEmpty())
+ return false;
+
+ const auto startNode = [this, useCache, peekerToNodeIt]() -> QXcbEventNode * {
+ if (useCache) {
+ const QXcbEventNode *cachedNode = peekerToNodeIt.value();
+ if (!cachedNode)
+ return m_head; // cache was reset
+ if (cachedNode == m_flushedTail)
+ return nullptr; // no new events since the last call
+ return cachedNode->next;
+ }
+ return m_head;
+ }();
+
+ if (!startNode)
+ return false;
+
+ // A peeker may call QCoreApplication::processEvents(), which will cause
+ // QXcbConnection::processXcbEvents() to modify the queue we are currently
+ // looping through;
+ m_queueModified = false;
+ bool result = false;
+
+ QXcbEventNode *node = startNode;
+ do {
+ xcb_generic_event_t *event = node->event;
+ if (event && peeker(event, peekerData)) {
+ result = true;
+ break;
+ }
+ if (node == m_flushedTail)
+ break;
+ node = node->next;
+ } while (!m_queueModified);
+
+ // Update the cached index if the queue was not modified, and hence the
+ // cache is still valid.
+ if (peekerIdProvided && node != startNode && !m_queueModified) {
+ // Before updating, make sure that a peeker callback did not remove
+ // the peeker id.
+ peekerToNodeIt = m_peekerToNode.find(peekerId);
+ if (peekerToNodeIt != m_peekerToNode.constEnd())
+ *peekerToNodeIt = node; // id still in the cache, update node
+ }
+
+ return result;
+}
+
+void QXcbEventQueue::sendCloseConnectionEvent() const
+{
+ // A hack to close XCB connection. Apparently XCB does not have any APIs for this?
+ xcb_client_message_event_t event;
+ memset(&event, 0, sizeof(event));
+
+ xcb_connection_t *c = m_connection->xcb_connection();
+ const xcb_window_t window = xcb_generate_id(c);
+ xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_connection->m_setup);
+ xcb_screen_t *screen = it.data;
+ xcb_create_window(c, XCB_COPY_FROM_PARENT,
+ window, screen->root,
+ 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY,
+ screen->root_visual, 0, nullptr);
+
+ event.response_type = XCB_CLIENT_MESSAGE;
+ event.format = 32;
+ event.sequence = 0;
+ event.window = window;
+ event.type = m_connection->atom(QXcbAtom::_QT_CLOSE_CONNECTION);
+ event.data.data32[0] = 0;
+
+ xcb_send_event(c, false, window, XCB_EVENT_MASK_NO_EVENT, reinterpret_cast<const char *>(&event));
+ xcb_destroy_window(c, window);
+ xcb_flush(c);
+}
+
+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))
+ m_closeConnectionDetected = true;
+ }
+ return m_closeConnectionDetected;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbeventqueue.h b/src/plugins/platforms/xcb/qxcbeventqueue.h
new file mode 100644
index 0000000000..235f2824be
--- /dev/null
+++ b/src/plugins/platforms/xcb/qxcbeventqueue.h
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+#ifndef QXCBEVENTQUEUE_H
+#define QXCBEVENTQUEUE_H
+
+#include <QtCore/QThread>
+#include <QtCore/QHash>
+#include <QtCore/QEventLoop>
+#include <QtCore/QVector>
+
+#include <xcb/xcb.h>
+
+#include <atomic>
+
+QT_BEGIN_NAMESPACE
+
+struct QXcbEventNode {
+ QXcbEventNode(xcb_generic_event_t *e = nullptr)
+ : event(e) { }
+
+ xcb_generic_event_t *event;
+ QXcbEventNode *next = nullptr;
+ bool fromHeap = false;
+};
+
+class QXcbConnection;
+class QAbstractEventDispatcher;
+
+class QXcbEventQueue : public QThread
+{
+ Q_OBJECT
+public:
+ QXcbEventQueue(QXcbConnection *connection);
+ ~QXcbEventQueue();
+
+ enum { PoolSize = 100 }; // 2.4 kB with 100 nodes
+
+ enum PeekOption {
+ PeekDefault = 0, // see qx11info_x11.h for docs
+ PeekFromCachedIndex = 1,
+ PeekRetainMatch = 2,
+ PeekRemoveMatch = 3,
+ PeekRemoveMatchContinue = 4
+ };
+ Q_DECLARE_FLAGS(PeekOptions, PeekOption)
+
+ void run() override;
+
+ bool isEmpty() const { return m_head == m_flushedTail && !m_head->event; }
+ xcb_generic_event_t *takeFirst(QEventLoop::ProcessEventsFlags flags);
+ xcb_generic_event_t *takeFirst();
+ void flushBufferedEvents();
+ void wakeUpDispatcher();
+
+ // ### peek() and peekEventQueue() could be unified. Note that peekEventQueue()
+ // is public API exposed via QX11Extras/QX11Info.
+ template<typename Peeker>
+ xcb_generic_event_t *peek(Peeker &&peeker) {
+ return peek(PeekRemoveMatch, std::forward<Peeker>(peeker));
+ }
+ template<typename Peeker>
+ inline xcb_generic_event_t *peek(PeekOption config, Peeker &&peeker);
+
+ qint32 generatePeekerId();
+ bool removePeekerId(qint32 peekerId);
+
+ using PeekerCallback = bool (*)(xcb_generic_event_t *event, void *peekerData);
+ bool peekEventQueue(PeekerCallback peeker, void *peekerData = nullptr,
+ PeekOptions option = PeekDefault, qint32 peekerId = -1);
+
+private:
+ QXcbEventNode *qXcbEventNodeFactory(xcb_generic_event_t *event);
+ void dequeueNode();
+
+ void sendCloseConnectionEvent() const;
+ bool isCloseConnectionEvent(const xcb_generic_event_t *event);
+
+ QXcbEventNode *m_head = nullptr;
+ QXcbEventNode *m_flushedTail = nullptr;
+ std::atomic<QXcbEventNode *> m_tail { nullptr };
+ std::atomic_uint m_nodesRestored { 0 };
+
+ QXcbConnection *m_connection = nullptr;
+ bool m_closeConnectionDetected = false;
+
+ uint m_freeNodes = PoolSize;
+ uint m_poolIndex = 0;
+
+ qint32 m_peekerIdSource = 0;
+ bool m_queueModified = false;
+ bool m_peekerIndexCacheDirty = false;
+ QHash<qint32, QXcbEventNode *> m_peekerToNode;
+
+ QVector<xcb_generic_event_t *> m_inputEvents;
+
+ // debug stats
+ quint64 m_nodesOnHeap = 0;
+};
+
+template<typename Peeker>
+xcb_generic_event_t *QXcbEventQueue::peek(PeekOption option, Peeker &&peeker)
+{
+ flushBufferedEvents();
+ if (isEmpty())
+ return nullptr;
+
+ QXcbEventNode *node = m_head;
+ do {
+ xcb_generic_event_t *event = node->event;
+ if (event && peeker(event, event->response_type & ~0x80)) {
+ if (option == PeekRemoveMatch || option == PeekRemoveMatchContinue)
+ node->event = nullptr;
+ if (option != PeekRemoveMatchContinue)
+ return event;
+ }
+ if (node == m_flushedTail)
+ break;
+ node = node->next;
+ } while (true);
+
+ return nullptr;
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index bf9eaacbb8..9a7d193767 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -46,6 +46,8 @@
#include "qxcbbackingstore.h"
#include "qxcbnativeinterface.h"
#include "qxcbclipboard.h"
+#include "qxcbeventqueue.h"
+#include "qxcbeventdispatcher.h"
#if QT_CONFIG(draganddrop)
#include "qxcbdrag.h"
#endif
@@ -57,7 +59,6 @@
#include <xcb/xcb.h>
-#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
#include <QtServiceSupport/private/qgenericunixservices_p.h>
@@ -69,12 +70,12 @@
#define register /* C++17 deprecated register */
#include <X11/Xlib.h>
#undef register
+#endif
#if QT_CONFIG(xcb_native_painting)
#include "qxcbnativepainting.h"
#include "qpixmap_x11_p.h"
#include "qbackingstore_x11_p.h"
#endif
-#endif
#include <qpa/qplatforminputcontextfactory_p.h>
#include <private/qgenericunixthemes_p.h>
@@ -136,6 +137,8 @@ QXcbIntegration::QXcbIntegration(const QStringList &parameters, int &argc, char
m_instance = this;
qApp->setAttribute(Qt::AA_CompressHighFrequencyEvents, true);
+ QWindowSystemInterface::setPlatformFiltersEvents(true);
+
qRegisterMetaType<QXcbWindow*>();
#if QT_CONFIG(xcb_xlib)
XInitThreads();
@@ -241,10 +244,11 @@ QPlatformPixmap *QXcbIntegration::createPlatformPixmap(QPlatformPixmap::PixelTyp
QPlatformWindow *QXcbIntegration::createPlatformWindow(QWindow *window) const
{
- QXcbScreen *screen = static_cast<QXcbScreen *>(window->screen()->handle());
- QXcbGlIntegration *glIntegration = screen->connection()->glIntegration();
- if (window->type() != Qt::Desktop) {
+ QXcbGlIntegration *glIntegration = nullptr;
+ const bool isTrayIconWindow = QXcbWindow::isTrayIconWindow(window);;
+ if (window->type() != Qt::Desktop && !isTrayIconWindow) {
if (window->supportsOpenGL()) {
+ glIntegration = defaultConnection()->glIntegration();
if (glIntegration) {
QXcbWindow *xcbWindow = glIntegration->createWindow(window);
xcbWindow->create();
@@ -259,7 +263,7 @@ QPlatformWindow *QXcbIntegration::createPlatformWindow(QWindow *window) const
}
}
- Q_ASSERT(window->type() == Qt::Desktop || !window->supportsOpenGL()
+ Q_ASSERT(window->type() == Qt::Desktop || isTrayIconWindow || !window->supportsOpenGL()
|| (!glIntegration && window->surfaceType() == QSurface::RasterGLSurface)); // for VNC
QXcbWindow *xcbWindow = new QXcbWindow(window);
xcbWindow->create();
@@ -286,6 +290,10 @@ QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLCont
QPlatformBackingStore *QXcbIntegration::createPlatformBackingStore(QWindow *window) const
{
+ const bool isTrayIconWindow = QXcbWindow::isTrayIconWindow(window);
+ if (isTrayIconWindow)
+ return new QXcbSystemTrayBackingStore(window);
+
#if QT_CONFIG(xcb_native_painting)
if (nativePaintingEnabled())
return new QXcbNativeBackingStore(window);
@@ -313,8 +321,7 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
const auto *connection = qAsConst(m_connections).first();
if (const auto *integration = connection->glIntegration())
- return cap != ThreadedOpenGL
- || (connection->threadedEventHandling() && integration->supportsThreadedOpenGL());
+ return cap != ThreadedOpenGL || integration->supportsThreadedOpenGL();
return false;
}
@@ -338,10 +345,7 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
QAbstractEventDispatcher *QXcbIntegration::createEventDispatcher() const
{
- QAbstractEventDispatcher *dispatcher = createUnixEventDispatcher();
- for (int i = 0; i < m_connections.size(); i++)
- m_connections[i]->eventReader()->registerEventDispatcher(dispatcher);
- return dispatcher;
+ return QXcbEventDispatcher::createEventDispatcher(defaultConnection());
}
void QXcbIntegration::initialize()
@@ -381,8 +385,17 @@ QPlatformClipboard *QXcbIntegration::clipboard() const
#endif
#if QT_CONFIG(draganddrop)
+#include <private/qsimpledrag_p.h>
QPlatformDrag *QXcbIntegration::drag() const
{
+ static const bool useSimpleDrag = qEnvironmentVariableIsSet("QT_XCB_USE_SIMPLE_DRAG");
+ if (Q_UNLIKELY(useSimpleDrag)) { // This is useful for testing purposes
+ static QSimpleDrag *simpleDrag = nullptr;
+ if (!simpleDrag)
+ simpleDrag = new QSimpleDrag();
+ return simpleDrag;
+ }
+
return m_connections.at(0)->drag();
}
#endif
@@ -414,10 +427,7 @@ QPlatformServices *QXcbIntegration::services() const
Qt::KeyboardModifiers QXcbIntegration::queryKeyboardModifiers() const
{
- int keybMask = 0;
- QXcbConnection *conn = m_connections.at(0);
- QXcbCursor::queryPointer(conn, 0, 0, &keybMask);
- return conn->keyboard()->translateModifiers(keybMask);
+ return m_connections.at(0)->queryKeyboardModifiers();
}
QList<int> QXcbIntegration::possibleKeys(const QKeyEvent *e) const
diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h
index 69e49cb7f6..a8dd6402f6 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.h
+++ b/src/plugins/platforms/xcb/qxcbintegration.h
@@ -53,7 +53,6 @@ QT_BEGIN_NAMESPACE
class QXcbConnection;
class QAbstractEventDispatcher;
class QXcbNativeInterface;
-class QXcbScreen;
class Q_XCB_EXPORT QXcbIntegration : public QPlatformIntegration
{
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index 3733995a0d..ad06f24c14 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -49,366 +49,388 @@
#include <QtCore/QMetaEnum>
#include <private/qguiapplication_p.h>
+#include <private/qmakearray_p.h>
#include <xkbcommon/xkbcommon-keysyms.h>
-#if QT_CONFIG(xinput2)
-#include <X11/extensions/XI2proto.h>
-#undef KeyPress
-#undef KeyRelease
+#if QT_CONFIG(xcb_xinput)
+#include <xcb/xinput.h>
#endif
QT_BEGIN_NAMESPACE
-static const unsigned int KeyTbl[] = {
- // misc keys
-
- XKB_KEY_Escape, Qt::Key_Escape,
- XKB_KEY_Tab, Qt::Key_Tab,
- XKB_KEY_ISO_Left_Tab, Qt::Key_Backtab,
- XKB_KEY_BackSpace, Qt::Key_Backspace,
- XKB_KEY_Return, Qt::Key_Return,
- XKB_KEY_Insert, Qt::Key_Insert,
- XKB_KEY_Delete, Qt::Key_Delete,
- XKB_KEY_Clear, Qt::Key_Delete,
- XKB_KEY_Pause, Qt::Key_Pause,
- XKB_KEY_Print, Qt::Key_Print,
- 0x1005FF60, Qt::Key_SysReq, // hardcoded Sun SysReq
- 0x1007ff00, Qt::Key_SysReq, // hardcoded X386 SysReq
-
- // cursor movement
-
- XKB_KEY_Home, Qt::Key_Home,
- XKB_KEY_End, Qt::Key_End,
- XKB_KEY_Left, Qt::Key_Left,
- XKB_KEY_Up, Qt::Key_Up,
- XKB_KEY_Right, Qt::Key_Right,
- XKB_KEY_Down, Qt::Key_Down,
- XKB_KEY_Prior, Qt::Key_PageUp,
- XKB_KEY_Next, Qt::Key_PageDown,
-
- // modifiers
-
- XKB_KEY_Shift_L, Qt::Key_Shift,
- XKB_KEY_Shift_R, Qt::Key_Shift,
- XKB_KEY_Shift_Lock, Qt::Key_Shift,
- XKB_KEY_Control_L, Qt::Key_Control,
- XKB_KEY_Control_R, Qt::Key_Control,
- XKB_KEY_Meta_L, Qt::Key_Meta,
- XKB_KEY_Meta_R, Qt::Key_Meta,
- XKB_KEY_Alt_L, Qt::Key_Alt,
- XKB_KEY_Alt_R, Qt::Key_Alt,
- XKB_KEY_Caps_Lock, Qt::Key_CapsLock,
- XKB_KEY_Num_Lock, Qt::Key_NumLock,
- XKB_KEY_Scroll_Lock, Qt::Key_ScrollLock,
- XKB_KEY_Super_L, Qt::Key_Super_L,
- XKB_KEY_Super_R, Qt::Key_Super_R,
- XKB_KEY_Menu, Qt::Key_Menu,
- XKB_KEY_Hyper_L, Qt::Key_Hyper_L,
- XKB_KEY_Hyper_R, Qt::Key_Hyper_R,
- XKB_KEY_Help, Qt::Key_Help,
- 0x1000FF74, Qt::Key_Backtab, // hardcoded HP backtab
- 0x1005FF10, Qt::Key_F11, // hardcoded Sun F36 (labeled F11)
- 0x1005FF11, Qt::Key_F12, // hardcoded Sun F37 (labeled F12)
-
- // numeric and function keypad keys
-
- XKB_KEY_KP_Space, Qt::Key_Space,
- XKB_KEY_KP_Tab, Qt::Key_Tab,
- XKB_KEY_KP_Enter, Qt::Key_Enter,
- //XKB_KEY_KP_F1, Qt::Key_F1,
- //XKB_KEY_KP_F2, Qt::Key_F2,
- //XKB_KEY_KP_F3, Qt::Key_F3,
- //XKB_KEY_KP_F4, Qt::Key_F4,
- XKB_KEY_KP_Home, Qt::Key_Home,
- XKB_KEY_KP_Left, Qt::Key_Left,
- XKB_KEY_KP_Up, Qt::Key_Up,
- XKB_KEY_KP_Right, Qt::Key_Right,
- XKB_KEY_KP_Down, Qt::Key_Down,
- XKB_KEY_KP_Prior, Qt::Key_PageUp,
- XKB_KEY_KP_Next, Qt::Key_PageDown,
- XKB_KEY_KP_End, Qt::Key_End,
- XKB_KEY_KP_Begin, Qt::Key_Clear,
- XKB_KEY_KP_Insert, Qt::Key_Insert,
- XKB_KEY_KP_Delete, Qt::Key_Delete,
- XKB_KEY_KP_Equal, Qt::Key_Equal,
- XKB_KEY_KP_Multiply, Qt::Key_Asterisk,
- XKB_KEY_KP_Add, Qt::Key_Plus,
- XKB_KEY_KP_Separator, Qt::Key_Comma,
- XKB_KEY_KP_Subtract, Qt::Key_Minus,
- XKB_KEY_KP_Decimal, Qt::Key_Period,
- XKB_KEY_KP_Divide, Qt::Key_Slash,
-
- // special non-XF86 function keys
-
- XKB_KEY_Undo, Qt::Key_Undo,
- XKB_KEY_Redo, Qt::Key_Redo,
- XKB_KEY_Find, Qt::Key_Find,
- XKB_KEY_Cancel, Qt::Key_Cancel,
-
- // International input method support keys
-
- // International & multi-key character composition
- XKB_KEY_ISO_Level3_Shift, Qt::Key_AltGr,
- XKB_KEY_Multi_key, Qt::Key_Multi_key,
- XKB_KEY_Codeinput, Qt::Key_Codeinput,
- XKB_KEY_SingleCandidate, Qt::Key_SingleCandidate,
- XKB_KEY_MultipleCandidate, Qt::Key_MultipleCandidate,
- XKB_KEY_PreviousCandidate, Qt::Key_PreviousCandidate,
-
- // Misc Functions
- XKB_KEY_Mode_switch, Qt::Key_Mode_switch,
- XKB_KEY_script_switch, Qt::Key_Mode_switch,
-
- // Japanese keyboard support
- XKB_KEY_Kanji, Qt::Key_Kanji,
- XKB_KEY_Muhenkan, Qt::Key_Muhenkan,
- //XKB_KEY_Henkan_Mode, Qt::Key_Henkan_Mode,
- XKB_KEY_Henkan_Mode, Qt::Key_Henkan,
- XKB_KEY_Henkan, Qt::Key_Henkan,
- XKB_KEY_Romaji, Qt::Key_Romaji,
- XKB_KEY_Hiragana, Qt::Key_Hiragana,
- XKB_KEY_Katakana, Qt::Key_Katakana,
- XKB_KEY_Hiragana_Katakana, Qt::Key_Hiragana_Katakana,
- XKB_KEY_Zenkaku, Qt::Key_Zenkaku,
- XKB_KEY_Hankaku, Qt::Key_Hankaku,
- XKB_KEY_Zenkaku_Hankaku, Qt::Key_Zenkaku_Hankaku,
- XKB_KEY_Touroku, Qt::Key_Touroku,
- XKB_KEY_Massyo, Qt::Key_Massyo,
- XKB_KEY_Kana_Lock, Qt::Key_Kana_Lock,
- XKB_KEY_Kana_Shift, Qt::Key_Kana_Shift,
- XKB_KEY_Eisu_Shift, Qt::Key_Eisu_Shift,
- XKB_KEY_Eisu_toggle, Qt::Key_Eisu_toggle,
- //XKB_KEY_Kanji_Bangou, Qt::Key_Kanji_Bangou,
- //XKB_KEY_Zen_Koho, Qt::Key_Zen_Koho,
- //XKB_KEY_Mae_Koho, Qt::Key_Mae_Koho,
- XKB_KEY_Kanji_Bangou, Qt::Key_Codeinput,
- XKB_KEY_Zen_Koho, Qt::Key_MultipleCandidate,
- XKB_KEY_Mae_Koho, Qt::Key_PreviousCandidate,
-
- // Korean keyboard support
- XKB_KEY_Hangul, Qt::Key_Hangul,
- XKB_KEY_Hangul_Start, Qt::Key_Hangul_Start,
- XKB_KEY_Hangul_End, Qt::Key_Hangul_End,
- XKB_KEY_Hangul_Hanja, Qt::Key_Hangul_Hanja,
- XKB_KEY_Hangul_Jamo, Qt::Key_Hangul_Jamo,
- XKB_KEY_Hangul_Romaja, Qt::Key_Hangul_Romaja,
- //XKB_KEY_Hangul_Codeinput, Qt::Key_Hangul_Codeinput,
- XKB_KEY_Hangul_Codeinput, Qt::Key_Codeinput,
- XKB_KEY_Hangul_Jeonja, Qt::Key_Hangul_Jeonja,
- XKB_KEY_Hangul_Banja, Qt::Key_Hangul_Banja,
- XKB_KEY_Hangul_PreHanja, Qt::Key_Hangul_PreHanja,
- XKB_KEY_Hangul_PostHanja, Qt::Key_Hangul_PostHanja,
- //XKB_KEY_Hangul_SingleCandidate,Qt::Key_Hangul_SingleCandidate,
- //XKB_KEY_Hangul_MultipleCandidate,Qt::Key_Hangul_MultipleCandidate,
- //XKB_KEY_Hangul_PreviousCandidate,Qt::Key_Hangul_PreviousCandidate,
- XKB_KEY_Hangul_SingleCandidate, Qt::Key_SingleCandidate,
- XKB_KEY_Hangul_MultipleCandidate,Qt::Key_MultipleCandidate,
- XKB_KEY_Hangul_PreviousCandidate,Qt::Key_PreviousCandidate,
- XKB_KEY_Hangul_Special, Qt::Key_Hangul_Special,
- //XKB_KEY_Hangul_switch, Qt::Key_Hangul_switch,
- XKB_KEY_Hangul_switch, Qt::Key_Mode_switch,
-
- // dead keys
- XKB_KEY_dead_grave, Qt::Key_Dead_Grave,
- XKB_KEY_dead_acute, Qt::Key_Dead_Acute,
- XKB_KEY_dead_circumflex, Qt::Key_Dead_Circumflex,
- XKB_KEY_dead_tilde, Qt::Key_Dead_Tilde,
- XKB_KEY_dead_macron, Qt::Key_Dead_Macron,
- XKB_KEY_dead_breve, Qt::Key_Dead_Breve,
- XKB_KEY_dead_abovedot, Qt::Key_Dead_Abovedot,
- XKB_KEY_dead_diaeresis, Qt::Key_Dead_Diaeresis,
- XKB_KEY_dead_abovering, Qt::Key_Dead_Abovering,
- XKB_KEY_dead_doubleacute, Qt::Key_Dead_Doubleacute,
- XKB_KEY_dead_caron, Qt::Key_Dead_Caron,
- XKB_KEY_dead_cedilla, Qt::Key_Dead_Cedilla,
- XKB_KEY_dead_ogonek, Qt::Key_Dead_Ogonek,
- XKB_KEY_dead_iota, Qt::Key_Dead_Iota,
- XKB_KEY_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound,
- XKB_KEY_dead_semivoiced_sound, Qt::Key_Dead_Semivoiced_Sound,
- XKB_KEY_dead_belowdot, Qt::Key_Dead_Belowdot,
- XKB_KEY_dead_hook, Qt::Key_Dead_Hook,
- XKB_KEY_dead_horn, Qt::Key_Dead_Horn,
- XKB_KEY_dead_stroke, Qt::Key_Dead_Stroke,
- XKB_KEY_dead_abovecomma, Qt::Key_Dead_Abovecomma,
- XKB_KEY_dead_abovereversedcomma, Qt::Key_Dead_Abovereversedcomma,
- XKB_KEY_dead_doublegrave, Qt::Key_Dead_Doublegrave,
- XKB_KEY_dead_belowring, Qt::Key_Dead_Belowring,
- XKB_KEY_dead_belowmacron, Qt::Key_Dead_Belowmacron,
- XKB_KEY_dead_belowcircumflex, Qt::Key_Dead_Belowcircumflex,
- XKB_KEY_dead_belowtilde, Qt::Key_Dead_Belowtilde,
- XKB_KEY_dead_belowbreve, Qt::Key_Dead_Belowbreve,
- XKB_KEY_dead_belowdiaeresis, Qt::Key_Dead_Belowdiaeresis,
- XKB_KEY_dead_invertedbreve, Qt::Key_Dead_Invertedbreve,
- XKB_KEY_dead_belowcomma, Qt::Key_Dead_Belowcomma,
- XKB_KEY_dead_currency, Qt::Key_Dead_Currency,
- XKB_KEY_dead_a, Qt::Key_Dead_a,
- XKB_KEY_dead_A, Qt::Key_Dead_A,
- XKB_KEY_dead_e, Qt::Key_Dead_e,
- XKB_KEY_dead_E, Qt::Key_Dead_E,
- XKB_KEY_dead_i, Qt::Key_Dead_i,
- XKB_KEY_dead_I, Qt::Key_Dead_I,
- XKB_KEY_dead_o, Qt::Key_Dead_o,
- XKB_KEY_dead_O, Qt::Key_Dead_O,
- XKB_KEY_dead_u, Qt::Key_Dead_u,
- XKB_KEY_dead_U, Qt::Key_Dead_U,
- XKB_KEY_dead_small_schwa, Qt::Key_Dead_Small_Schwa,
- XKB_KEY_dead_capital_schwa, Qt::Key_Dead_Capital_Schwa,
- XKB_KEY_dead_greek, Qt::Key_Dead_Greek,
- XKB_KEY_dead_lowline, Qt::Key_Dead_Lowline,
- XKB_KEY_dead_aboveverticalline, Qt::Key_Dead_Aboveverticalline,
- XKB_KEY_dead_belowverticalline, Qt::Key_Dead_Belowverticalline,
- XKB_KEY_dead_longsolidusoverlay, Qt::Key_Dead_Longsolidusoverlay,
-
- // Special keys from X.org - This include multimedia keys,
- // wireless/bluetooth/uwb keys, special launcher keys, etc.
- XKB_KEY_XF86Back, Qt::Key_Back,
- XKB_KEY_XF86Forward, Qt::Key_Forward,
- XKB_KEY_XF86Stop, Qt::Key_Stop,
- XKB_KEY_XF86Refresh, Qt::Key_Refresh,
- XKB_KEY_XF86Favorites, Qt::Key_Favorites,
- XKB_KEY_XF86AudioMedia, Qt::Key_LaunchMedia,
- XKB_KEY_XF86OpenURL, Qt::Key_OpenUrl,
- XKB_KEY_XF86HomePage, Qt::Key_HomePage,
- XKB_KEY_XF86Search, Qt::Key_Search,
- XKB_KEY_XF86AudioLowerVolume, Qt::Key_VolumeDown,
- XKB_KEY_XF86AudioMute, Qt::Key_VolumeMute,
- XKB_KEY_XF86AudioRaiseVolume, Qt::Key_VolumeUp,
- XKB_KEY_XF86AudioPlay, Qt::Key_MediaPlay,
- XKB_KEY_XF86AudioStop, Qt::Key_MediaStop,
- XKB_KEY_XF86AudioPrev, Qt::Key_MediaPrevious,
- XKB_KEY_XF86AudioNext, Qt::Key_MediaNext,
- XKB_KEY_XF86AudioRecord, Qt::Key_MediaRecord,
- XKB_KEY_XF86AudioPause, Qt::Key_MediaPause,
- XKB_KEY_XF86Mail, Qt::Key_LaunchMail,
- XKB_KEY_XF86MyComputer, Qt::Key_Launch0, // ### Qt 6: remap properly
- XKB_KEY_XF86Calculator, Qt::Key_Launch1,
- XKB_KEY_XF86Memo, Qt::Key_Memo,
- XKB_KEY_XF86ToDoList, Qt::Key_ToDoList,
- XKB_KEY_XF86Calendar, Qt::Key_Calendar,
- XKB_KEY_XF86PowerDown, Qt::Key_PowerDown,
- XKB_KEY_XF86ContrastAdjust, Qt::Key_ContrastAdjust,
- XKB_KEY_XF86Standby, Qt::Key_Standby,
- XKB_KEY_XF86MonBrightnessUp, Qt::Key_MonBrightnessUp,
- XKB_KEY_XF86MonBrightnessDown, Qt::Key_MonBrightnessDown,
- XKB_KEY_XF86KbdLightOnOff, Qt::Key_KeyboardLightOnOff,
- XKB_KEY_XF86KbdBrightnessUp, Qt::Key_KeyboardBrightnessUp,
- XKB_KEY_XF86KbdBrightnessDown, Qt::Key_KeyboardBrightnessDown,
- XKB_KEY_XF86PowerOff, Qt::Key_PowerOff,
- XKB_KEY_XF86WakeUp, Qt::Key_WakeUp,
- XKB_KEY_XF86Eject, Qt::Key_Eject,
- XKB_KEY_XF86ScreenSaver, Qt::Key_ScreenSaver,
- XKB_KEY_XF86WWW, Qt::Key_WWW,
- XKB_KEY_XF86Sleep, Qt::Key_Sleep,
- XKB_KEY_XF86LightBulb, Qt::Key_LightBulb,
- XKB_KEY_XF86Shop, Qt::Key_Shop,
- XKB_KEY_XF86History, Qt::Key_History,
- XKB_KEY_XF86AddFavorite, Qt::Key_AddFavorite,
- XKB_KEY_XF86HotLinks, Qt::Key_HotLinks,
- XKB_KEY_XF86BrightnessAdjust, Qt::Key_BrightnessAdjust,
- XKB_KEY_XF86Finance, Qt::Key_Finance,
- XKB_KEY_XF86Community, Qt::Key_Community,
- XKB_KEY_XF86AudioRewind, Qt::Key_AudioRewind,
- XKB_KEY_XF86BackForward, Qt::Key_BackForward,
- XKB_KEY_XF86ApplicationLeft, Qt::Key_ApplicationLeft,
- XKB_KEY_XF86ApplicationRight, Qt::Key_ApplicationRight,
- XKB_KEY_XF86Book, Qt::Key_Book,
- XKB_KEY_XF86CD, Qt::Key_CD,
- XKB_KEY_XF86Calculater, Qt::Key_Calculator,
- XKB_KEY_XF86Clear, Qt::Key_Clear,
- XKB_KEY_XF86ClearGrab, Qt::Key_ClearGrab,
- XKB_KEY_XF86Close, Qt::Key_Close,
- XKB_KEY_XF86Copy, Qt::Key_Copy,
- XKB_KEY_XF86Cut, Qt::Key_Cut,
- XKB_KEY_XF86Display, Qt::Key_Display,
- XKB_KEY_XF86DOS, Qt::Key_DOS,
- XKB_KEY_XF86Documents, Qt::Key_Documents,
- XKB_KEY_XF86Excel, Qt::Key_Excel,
- XKB_KEY_XF86Explorer, Qt::Key_Explorer,
- XKB_KEY_XF86Game, Qt::Key_Game,
- XKB_KEY_XF86Go, Qt::Key_Go,
- XKB_KEY_XF86iTouch, Qt::Key_iTouch,
- XKB_KEY_XF86LogOff, Qt::Key_LogOff,
- XKB_KEY_XF86Market, Qt::Key_Market,
- XKB_KEY_XF86Meeting, Qt::Key_Meeting,
- XKB_KEY_XF86MenuKB, Qt::Key_MenuKB,
- XKB_KEY_XF86MenuPB, Qt::Key_MenuPB,
- XKB_KEY_XF86MySites, Qt::Key_MySites,
- XKB_KEY_XF86New, Qt::Key_New,
- XKB_KEY_XF86News, Qt::Key_News,
- XKB_KEY_XF86OfficeHome, Qt::Key_OfficeHome,
- XKB_KEY_XF86Open, Qt::Key_Open,
- XKB_KEY_XF86Option, Qt::Key_Option,
- XKB_KEY_XF86Paste, Qt::Key_Paste,
- XKB_KEY_XF86Phone, Qt::Key_Phone,
- XKB_KEY_XF86Reply, Qt::Key_Reply,
- XKB_KEY_XF86Reload, Qt::Key_Reload,
- XKB_KEY_XF86RotateWindows, Qt::Key_RotateWindows,
- XKB_KEY_XF86RotationPB, Qt::Key_RotationPB,
- XKB_KEY_XF86RotationKB, Qt::Key_RotationKB,
- XKB_KEY_XF86Save, Qt::Key_Save,
- XKB_KEY_XF86Send, Qt::Key_Send,
- XKB_KEY_XF86Spell, Qt::Key_Spell,
- XKB_KEY_XF86SplitScreen, Qt::Key_SplitScreen,
- XKB_KEY_XF86Support, Qt::Key_Support,
- XKB_KEY_XF86TaskPane, Qt::Key_TaskPane,
- XKB_KEY_XF86Terminal, Qt::Key_Terminal,
- XKB_KEY_XF86Tools, Qt::Key_Tools,
- XKB_KEY_XF86Travel, Qt::Key_Travel,
- XKB_KEY_XF86Video, Qt::Key_Video,
- XKB_KEY_XF86Word, Qt::Key_Word,
- XKB_KEY_XF86Xfer, Qt::Key_Xfer,
- XKB_KEY_XF86ZoomIn, Qt::Key_ZoomIn,
- XKB_KEY_XF86ZoomOut, Qt::Key_ZoomOut,
- XKB_KEY_XF86Away, Qt::Key_Away,
- XKB_KEY_XF86Messenger, Qt::Key_Messenger,
- XKB_KEY_XF86WebCam, Qt::Key_WebCam,
- XKB_KEY_XF86MailForward, Qt::Key_MailForward,
- XKB_KEY_XF86Pictures, Qt::Key_Pictures,
- XKB_KEY_XF86Music, Qt::Key_Music,
- XKB_KEY_XF86Battery, Qt::Key_Battery,
- XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth,
- XKB_KEY_XF86WLAN, Qt::Key_WLAN,
- XKB_KEY_XF86UWB, Qt::Key_UWB,
- XKB_KEY_XF86AudioForward, Qt::Key_AudioForward,
- XKB_KEY_XF86AudioRepeat, Qt::Key_AudioRepeat,
- XKB_KEY_XF86AudioRandomPlay, Qt::Key_AudioRandomPlay,
- XKB_KEY_XF86Subtitle, Qt::Key_Subtitle,
- XKB_KEY_XF86AudioCycleTrack, Qt::Key_AudioCycleTrack,
- XKB_KEY_XF86Time, Qt::Key_Time,
- XKB_KEY_XF86Select, Qt::Key_Select,
- XKB_KEY_XF86View, Qt::Key_View,
- XKB_KEY_XF86TopMenu, Qt::Key_TopMenu,
- XKB_KEY_XF86Red, Qt::Key_Red,
- XKB_KEY_XF86Green, Qt::Key_Green,
- XKB_KEY_XF86Yellow, Qt::Key_Yellow,
- XKB_KEY_XF86Blue, Qt::Key_Blue,
- XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth,
- XKB_KEY_XF86Suspend, Qt::Key_Suspend,
- XKB_KEY_XF86Hibernate, Qt::Key_Hibernate,
- XKB_KEY_XF86TouchpadToggle, Qt::Key_TouchpadToggle,
- XKB_KEY_XF86TouchpadOn, Qt::Key_TouchpadOn,
- XKB_KEY_XF86TouchpadOff, Qt::Key_TouchpadOff,
- XKB_KEY_XF86AudioMicMute, Qt::Key_MicMute,
- XKB_KEY_XF86Launch0, Qt::Key_Launch2, // ### Qt 6: remap properly
- XKB_KEY_XF86Launch1, Qt::Key_Launch3,
- XKB_KEY_XF86Launch2, Qt::Key_Launch4,
- XKB_KEY_XF86Launch3, Qt::Key_Launch5,
- XKB_KEY_XF86Launch4, Qt::Key_Launch6,
- XKB_KEY_XF86Launch5, Qt::Key_Launch7,
- XKB_KEY_XF86Launch6, Qt::Key_Launch8,
- XKB_KEY_XF86Launch7, Qt::Key_Launch9,
- XKB_KEY_XF86Launch8, Qt::Key_LaunchA,
- XKB_KEY_XF86Launch9, Qt::Key_LaunchB,
- XKB_KEY_XF86LaunchA, Qt::Key_LaunchC,
- XKB_KEY_XF86LaunchB, Qt::Key_LaunchD,
- XKB_KEY_XF86LaunchC, Qt::Key_LaunchE,
- XKB_KEY_XF86LaunchD, Qt::Key_LaunchF,
- XKB_KEY_XF86LaunchE, Qt::Key_LaunchG,
- XKB_KEY_XF86LaunchF, Qt::Key_LaunchH,
-
- 0, 0
+typedef struct xkb2qt
+{
+ unsigned int xkb;
+ unsigned int qt;
+
+ constexpr bool operator <=(const xkb2qt &that) const noexcept
+ {
+ return xkb <= that.xkb;
+ }
+
+ constexpr bool operator <(const xkb2qt &that) const noexcept
+ {
+ return xkb < that.xkb;
+ }
+} xkb2qt_t;
+
+template<std::size_t Xkb, std::size_t Qt>
+struct Xkb2Qt
+{
+ using Type = xkb2qt_t;
+ static constexpr Type data() noexcept { return Type{Xkb, Qt}; }
};
+static constexpr const auto KeyTbl = qMakeArray(
+ QSortedData<
+ // misc keys
+
+ Xkb2Qt<XKB_KEY_Escape, Qt::Key_Escape>,
+ Xkb2Qt<XKB_KEY_Tab, Qt::Key_Tab>,
+ Xkb2Qt<XKB_KEY_ISO_Left_Tab, Qt::Key_Backtab>,
+ Xkb2Qt<XKB_KEY_BackSpace, Qt::Key_Backspace>,
+ Xkb2Qt<XKB_KEY_Return, Qt::Key_Return>,
+ Xkb2Qt<XKB_KEY_Insert, Qt::Key_Insert>,
+ Xkb2Qt<XKB_KEY_Delete, Qt::Key_Delete>,
+ Xkb2Qt<XKB_KEY_Clear, Qt::Key_Delete>,
+ Xkb2Qt<XKB_KEY_Pause, Qt::Key_Pause>,
+ Xkb2Qt<XKB_KEY_Print, Qt::Key_Print>,
+ Xkb2Qt<0x1005FF60, Qt::Key_SysReq>, // hardcoded Sun SysReq
+ Xkb2Qt<0x1007ff00, Qt::Key_SysReq>, // hardcoded X386 SysReq
+
+ // cursor movement
+
+ Xkb2Qt<XKB_KEY_Home, Qt::Key_Home>,
+ Xkb2Qt<XKB_KEY_End, Qt::Key_End>,
+ Xkb2Qt<XKB_KEY_Left, Qt::Key_Left>,
+ Xkb2Qt<XKB_KEY_Up, Qt::Key_Up>,
+ Xkb2Qt<XKB_KEY_Right, Qt::Key_Right>,
+ Xkb2Qt<XKB_KEY_Down, Qt::Key_Down>,
+ Xkb2Qt<XKB_KEY_Prior, Qt::Key_PageUp>,
+ Xkb2Qt<XKB_KEY_Next, Qt::Key_PageDown>,
+
+ // modifiers
+
+ Xkb2Qt<XKB_KEY_Shift_L, Qt::Key_Shift>,
+ Xkb2Qt<XKB_KEY_Shift_R, Qt::Key_Shift>,
+ Xkb2Qt<XKB_KEY_Shift_Lock, Qt::Key_Shift>,
+ Xkb2Qt<XKB_KEY_Control_L, Qt::Key_Control>,
+ Xkb2Qt<XKB_KEY_Control_R, Qt::Key_Control>,
+ Xkb2Qt<XKB_KEY_Meta_L, Qt::Key_Meta>,
+ Xkb2Qt<XKB_KEY_Meta_R, Qt::Key_Meta>,
+ Xkb2Qt<XKB_KEY_Alt_L, Qt::Key_Alt>,
+ Xkb2Qt<XKB_KEY_Alt_R, Qt::Key_Alt>,
+ Xkb2Qt<XKB_KEY_Caps_Lock, Qt::Key_CapsLock>,
+ Xkb2Qt<XKB_KEY_Num_Lock, Qt::Key_NumLock>,
+ Xkb2Qt<XKB_KEY_Scroll_Lock, Qt::Key_ScrollLock>,
+ Xkb2Qt<XKB_KEY_Super_L, Qt::Key_Super_L>,
+ Xkb2Qt<XKB_KEY_Super_R, Qt::Key_Super_R>,
+ Xkb2Qt<XKB_KEY_Menu, Qt::Key_Menu>,
+ Xkb2Qt<XKB_KEY_Hyper_L, Qt::Key_Hyper_L>,
+ Xkb2Qt<XKB_KEY_Hyper_R, Qt::Key_Hyper_R>,
+ Xkb2Qt<XKB_KEY_Help, Qt::Key_Help>,
+ Xkb2Qt<0x1000FF74, Qt::Key_Backtab>, // hardcoded HP backtab
+ Xkb2Qt<0x1005FF10, Qt::Key_F11>, // hardcoded Sun F36 (labeled F11)
+ Xkb2Qt<0x1005FF11, Qt::Key_F12>, // hardcoded Sun F37 (labeled F12)
+
+ // numeric and function keypad keys
+
+ Xkb2Qt<XKB_KEY_KP_Space, Qt::Key_Space>,
+ Xkb2Qt<XKB_KEY_KP_Tab, Qt::Key_Tab>,
+ Xkb2Qt<XKB_KEY_KP_Enter, Qt::Key_Enter>,
+ //Xkb2Qt<XKB_KEY_KP_F1, Qt::Key_F1>,
+ //Xkb2Qt<XKB_KEY_KP_F2, Qt::Key_F2>,
+ //Xkb2Qt<XKB_KEY_KP_F3, Qt::Key_F3>,
+ //Xkb2Qt<XKB_KEY_KP_F4, Qt::Key_F4>,
+ Xkb2Qt<XKB_KEY_KP_Home, Qt::Key_Home>,
+ Xkb2Qt<XKB_KEY_KP_Left, Qt::Key_Left>,
+ Xkb2Qt<XKB_KEY_KP_Up, Qt::Key_Up>,
+ Xkb2Qt<XKB_KEY_KP_Right, Qt::Key_Right>,
+ Xkb2Qt<XKB_KEY_KP_Down, Qt::Key_Down>,
+ Xkb2Qt<XKB_KEY_KP_Prior, Qt::Key_PageUp>,
+ Xkb2Qt<XKB_KEY_KP_Next, Qt::Key_PageDown>,
+ Xkb2Qt<XKB_KEY_KP_End, Qt::Key_End>,
+ Xkb2Qt<XKB_KEY_KP_Begin, Qt::Key_Clear>,
+ Xkb2Qt<XKB_KEY_KP_Insert, Qt::Key_Insert>,
+ Xkb2Qt<XKB_KEY_KP_Delete, Qt::Key_Delete>,
+ Xkb2Qt<XKB_KEY_KP_Equal, Qt::Key_Equal>,
+ Xkb2Qt<XKB_KEY_KP_Multiply, Qt::Key_Asterisk>,
+ Xkb2Qt<XKB_KEY_KP_Add, Qt::Key_Plus>,
+ Xkb2Qt<XKB_KEY_KP_Separator, Qt::Key_Comma>,
+ Xkb2Qt<XKB_KEY_KP_Subtract, Qt::Key_Minus>,
+ Xkb2Qt<XKB_KEY_KP_Decimal, Qt::Key_Period>,
+ Xkb2Qt<XKB_KEY_KP_Divide, Qt::Key_Slash>,
+
+ // special non-XF86 function keys
+
+ Xkb2Qt<XKB_KEY_Undo, Qt::Key_Undo>,
+ Xkb2Qt<XKB_KEY_Redo, Qt::Key_Redo>,
+ Xkb2Qt<XKB_KEY_Find, Qt::Key_Find>,
+ Xkb2Qt<XKB_KEY_Cancel, Qt::Key_Cancel>,
+
+ // International input method support keys
+
+ // International & multi-key character composition
+ Xkb2Qt<XKB_KEY_ISO_Level3_Shift, Qt::Key_AltGr>,
+ Xkb2Qt<XKB_KEY_Multi_key, Qt::Key_Multi_key>,
+ Xkb2Qt<XKB_KEY_Codeinput, Qt::Key_Codeinput>,
+ Xkb2Qt<XKB_KEY_SingleCandidate, Qt::Key_SingleCandidate>,
+ Xkb2Qt<XKB_KEY_MultipleCandidate, Qt::Key_MultipleCandidate>,
+ Xkb2Qt<XKB_KEY_PreviousCandidate, Qt::Key_PreviousCandidate>,
+
+ // Misc Functions
+ Xkb2Qt<XKB_KEY_Mode_switch, Qt::Key_Mode_switch>,
+ Xkb2Qt<XKB_KEY_script_switch, Qt::Key_Mode_switch>,
+
+ // Japanese keyboard support
+ Xkb2Qt<XKB_KEY_Kanji, Qt::Key_Kanji>,
+ Xkb2Qt<XKB_KEY_Muhenkan, Qt::Key_Muhenkan>,
+ //Xkb2Qt<XKB_KEY_Henkan_Mode, Qt::Key_Henkan_Mode>,
+ Xkb2Qt<XKB_KEY_Henkan_Mode, Qt::Key_Henkan>,
+ Xkb2Qt<XKB_KEY_Henkan, Qt::Key_Henkan>,
+ Xkb2Qt<XKB_KEY_Romaji, Qt::Key_Romaji>,
+ Xkb2Qt<XKB_KEY_Hiragana, Qt::Key_Hiragana>,
+ Xkb2Qt<XKB_KEY_Katakana, Qt::Key_Katakana>,
+ Xkb2Qt<XKB_KEY_Hiragana_Katakana, Qt::Key_Hiragana_Katakana>,
+ Xkb2Qt<XKB_KEY_Zenkaku, Qt::Key_Zenkaku>,
+ Xkb2Qt<XKB_KEY_Hankaku, Qt::Key_Hankaku>,
+ Xkb2Qt<XKB_KEY_Zenkaku_Hankaku, Qt::Key_Zenkaku_Hankaku>,
+ Xkb2Qt<XKB_KEY_Touroku, Qt::Key_Touroku>,
+ Xkb2Qt<XKB_KEY_Massyo, Qt::Key_Massyo>,
+ Xkb2Qt<XKB_KEY_Kana_Lock, Qt::Key_Kana_Lock>,
+ Xkb2Qt<XKB_KEY_Kana_Shift, Qt::Key_Kana_Shift>,
+ Xkb2Qt<XKB_KEY_Eisu_Shift, Qt::Key_Eisu_Shift>,
+ Xkb2Qt<XKB_KEY_Eisu_toggle, Qt::Key_Eisu_toggle>,
+ //Xkb2Qt<XKB_KEY_Kanji_Bangou, Qt::Key_Kanji_Bangou>,
+ //Xkb2Qt<XKB_KEY_Zen_Koho, Qt::Key_Zen_Koho>,
+ //Xkb2Qt<XKB_KEY_Mae_Koho, Qt::Key_Mae_Koho>,
+ Xkb2Qt<XKB_KEY_Kanji_Bangou, Qt::Key_Codeinput>,
+ Xkb2Qt<XKB_KEY_Zen_Koho, Qt::Key_MultipleCandidate>,
+ Xkb2Qt<XKB_KEY_Mae_Koho, Qt::Key_PreviousCandidate>,
+
+ // Korean keyboard support
+ Xkb2Qt<XKB_KEY_Hangul, Qt::Key_Hangul>,
+ Xkb2Qt<XKB_KEY_Hangul_Start, Qt::Key_Hangul_Start>,
+ Xkb2Qt<XKB_KEY_Hangul_End, Qt::Key_Hangul_End>,
+ Xkb2Qt<XKB_KEY_Hangul_Hanja, Qt::Key_Hangul_Hanja>,
+ Xkb2Qt<XKB_KEY_Hangul_Jamo, Qt::Key_Hangul_Jamo>,
+ Xkb2Qt<XKB_KEY_Hangul_Romaja, Qt::Key_Hangul_Romaja>,
+ //Xkb2Qt<XKB_KEY_Hangul_Codeinput, Qt::Key_Hangul_Codeinput>,
+ Xkb2Qt<XKB_KEY_Hangul_Codeinput, Qt::Key_Codeinput>,
+ Xkb2Qt<XKB_KEY_Hangul_Jeonja, Qt::Key_Hangul_Jeonja>,
+ Xkb2Qt<XKB_KEY_Hangul_Banja, Qt::Key_Hangul_Banja>,
+ Xkb2Qt<XKB_KEY_Hangul_PreHanja, Qt::Key_Hangul_PreHanja>,
+ Xkb2Qt<XKB_KEY_Hangul_PostHanja, Qt::Key_Hangul_PostHanja>,
+ //Xkb2Qt<XKB_KEY_Hangul_SingleCandidate,Qt::Key_Hangul_SingleCandidate>,
+ //Xkb2Qt<XKB_KEY_Hangul_MultipleCandidate,Qt::Key_Hangul_MultipleCandidate>,
+ //Xkb2Qt<XKB_KEY_Hangul_PreviousCandidate,Qt::Key_Hangul_PreviousCandidate>,
+ Xkb2Qt<XKB_KEY_Hangul_SingleCandidate, Qt::Key_SingleCandidate>,
+ Xkb2Qt<XKB_KEY_Hangul_MultipleCandidate,Qt::Key_MultipleCandidate>,
+ Xkb2Qt<XKB_KEY_Hangul_PreviousCandidate,Qt::Key_PreviousCandidate>,
+ Xkb2Qt<XKB_KEY_Hangul_Special, Qt::Key_Hangul_Special>,
+ //Xkb2Qt<XKB_KEY_Hangul_switch, Qt::Key_Hangul_switch>,
+ Xkb2Qt<XKB_KEY_Hangul_switch, Qt::Key_Mode_switch>,
+
+ // dead keys
+ Xkb2Qt<XKB_KEY_dead_grave, Qt::Key_Dead_Grave>,
+ Xkb2Qt<XKB_KEY_dead_acute, Qt::Key_Dead_Acute>,
+ Xkb2Qt<XKB_KEY_dead_circumflex, Qt::Key_Dead_Circumflex>,
+ Xkb2Qt<XKB_KEY_dead_tilde, Qt::Key_Dead_Tilde>,
+ Xkb2Qt<XKB_KEY_dead_macron, Qt::Key_Dead_Macron>,
+ Xkb2Qt<XKB_KEY_dead_breve, Qt::Key_Dead_Breve>,
+ Xkb2Qt<XKB_KEY_dead_abovedot, Qt::Key_Dead_Abovedot>,
+ Xkb2Qt<XKB_KEY_dead_diaeresis, Qt::Key_Dead_Diaeresis>,
+ Xkb2Qt<XKB_KEY_dead_abovering, Qt::Key_Dead_Abovering>,
+ Xkb2Qt<XKB_KEY_dead_doubleacute, Qt::Key_Dead_Doubleacute>,
+ Xkb2Qt<XKB_KEY_dead_caron, Qt::Key_Dead_Caron>,
+ Xkb2Qt<XKB_KEY_dead_cedilla, Qt::Key_Dead_Cedilla>,
+ Xkb2Qt<XKB_KEY_dead_ogonek, Qt::Key_Dead_Ogonek>,
+ Xkb2Qt<XKB_KEY_dead_iota, Qt::Key_Dead_Iota>,
+ Xkb2Qt<XKB_KEY_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound>,
+ Xkb2Qt<XKB_KEY_dead_semivoiced_sound, Qt::Key_Dead_Semivoiced_Sound>,
+ Xkb2Qt<XKB_KEY_dead_belowdot, Qt::Key_Dead_Belowdot>,
+ Xkb2Qt<XKB_KEY_dead_hook, Qt::Key_Dead_Hook>,
+ Xkb2Qt<XKB_KEY_dead_horn, Qt::Key_Dead_Horn>,
+ Xkb2Qt<XKB_KEY_dead_stroke, Qt::Key_Dead_Stroke>,
+ Xkb2Qt<XKB_KEY_dead_abovecomma, Qt::Key_Dead_Abovecomma>,
+ Xkb2Qt<XKB_KEY_dead_abovereversedcomma, Qt::Key_Dead_Abovereversedcomma>,
+ Xkb2Qt<XKB_KEY_dead_doublegrave, Qt::Key_Dead_Doublegrave>,
+ Xkb2Qt<XKB_KEY_dead_belowring, Qt::Key_Dead_Belowring>,
+ Xkb2Qt<XKB_KEY_dead_belowmacron, Qt::Key_Dead_Belowmacron>,
+ Xkb2Qt<XKB_KEY_dead_belowcircumflex, Qt::Key_Dead_Belowcircumflex>,
+ Xkb2Qt<XKB_KEY_dead_belowtilde, Qt::Key_Dead_Belowtilde>,
+ Xkb2Qt<XKB_KEY_dead_belowbreve, Qt::Key_Dead_Belowbreve>,
+ Xkb2Qt<XKB_KEY_dead_belowdiaeresis, Qt::Key_Dead_Belowdiaeresis>,
+ Xkb2Qt<XKB_KEY_dead_invertedbreve, Qt::Key_Dead_Invertedbreve>,
+ Xkb2Qt<XKB_KEY_dead_belowcomma, Qt::Key_Dead_Belowcomma>,
+ Xkb2Qt<XKB_KEY_dead_currency, Qt::Key_Dead_Currency>,
+ Xkb2Qt<XKB_KEY_dead_a, Qt::Key_Dead_a>,
+ Xkb2Qt<XKB_KEY_dead_A, Qt::Key_Dead_A>,
+ Xkb2Qt<XKB_KEY_dead_e, Qt::Key_Dead_e>,
+ Xkb2Qt<XKB_KEY_dead_E, Qt::Key_Dead_E>,
+ Xkb2Qt<XKB_KEY_dead_i, Qt::Key_Dead_i>,
+ Xkb2Qt<XKB_KEY_dead_I, Qt::Key_Dead_I>,
+ Xkb2Qt<XKB_KEY_dead_o, Qt::Key_Dead_o>,
+ Xkb2Qt<XKB_KEY_dead_O, Qt::Key_Dead_O>,
+ Xkb2Qt<XKB_KEY_dead_u, Qt::Key_Dead_u>,
+ Xkb2Qt<XKB_KEY_dead_U, Qt::Key_Dead_U>,
+ Xkb2Qt<XKB_KEY_dead_small_schwa, Qt::Key_Dead_Small_Schwa>,
+ Xkb2Qt<XKB_KEY_dead_capital_schwa, Qt::Key_Dead_Capital_Schwa>,
+ Xkb2Qt<XKB_KEY_dead_greek, Qt::Key_Dead_Greek>,
+ Xkb2Qt<XKB_KEY_dead_lowline, Qt::Key_Dead_Lowline>,
+ Xkb2Qt<XKB_KEY_dead_aboveverticalline, Qt::Key_Dead_Aboveverticalline>,
+ Xkb2Qt<XKB_KEY_dead_belowverticalline, Qt::Key_Dead_Belowverticalline>,
+ Xkb2Qt<XKB_KEY_dead_longsolidusoverlay, Qt::Key_Dead_Longsolidusoverlay>,
+
+ // Special keys from X.org - This include multimedia keys,
+ // wireless/bluetooth/uwb keys, special launcher keys, etc.
+ Xkb2Qt<XKB_KEY_XF86Back, Qt::Key_Back>,
+ Xkb2Qt<XKB_KEY_XF86Forward, Qt::Key_Forward>,
+ Xkb2Qt<XKB_KEY_XF86Stop, Qt::Key_Stop>,
+ Xkb2Qt<XKB_KEY_XF86Refresh, Qt::Key_Refresh>,
+ Xkb2Qt<XKB_KEY_XF86Favorites, Qt::Key_Favorites>,
+ Xkb2Qt<XKB_KEY_XF86AudioMedia, Qt::Key_LaunchMedia>,
+ Xkb2Qt<XKB_KEY_XF86OpenURL, Qt::Key_OpenUrl>,
+ Xkb2Qt<XKB_KEY_XF86HomePage, Qt::Key_HomePage>,
+ Xkb2Qt<XKB_KEY_XF86Search, Qt::Key_Search>,
+ Xkb2Qt<XKB_KEY_XF86AudioLowerVolume, Qt::Key_VolumeDown>,
+ Xkb2Qt<XKB_KEY_XF86AudioMute, Qt::Key_VolumeMute>,
+ Xkb2Qt<XKB_KEY_XF86AudioRaiseVolume, Qt::Key_VolumeUp>,
+ Xkb2Qt<XKB_KEY_XF86AudioPlay, Qt::Key_MediaPlay>,
+ Xkb2Qt<XKB_KEY_XF86AudioStop, Qt::Key_MediaStop>,
+ Xkb2Qt<XKB_KEY_XF86AudioPrev, Qt::Key_MediaPrevious>,
+ Xkb2Qt<XKB_KEY_XF86AudioNext, Qt::Key_MediaNext>,
+ Xkb2Qt<XKB_KEY_XF86AudioRecord, Qt::Key_MediaRecord>,
+ Xkb2Qt<XKB_KEY_XF86AudioPause, Qt::Key_MediaPause>,
+ Xkb2Qt<XKB_KEY_XF86Mail, Qt::Key_LaunchMail>,
+ Xkb2Qt<XKB_KEY_XF86MyComputer, Qt::Key_Launch0>, // ### Qt 6: remap properly
+ Xkb2Qt<XKB_KEY_XF86Calculator, Qt::Key_Launch1>,
+ Xkb2Qt<XKB_KEY_XF86Memo, Qt::Key_Memo>,
+ Xkb2Qt<XKB_KEY_XF86ToDoList, Qt::Key_ToDoList>,
+ Xkb2Qt<XKB_KEY_XF86Calendar, Qt::Key_Calendar>,
+ Xkb2Qt<XKB_KEY_XF86PowerDown, Qt::Key_PowerDown>,
+ Xkb2Qt<XKB_KEY_XF86ContrastAdjust, Qt::Key_ContrastAdjust>,
+ Xkb2Qt<XKB_KEY_XF86Standby, Qt::Key_Standby>,
+ Xkb2Qt<XKB_KEY_XF86MonBrightnessUp, Qt::Key_MonBrightnessUp>,
+ Xkb2Qt<XKB_KEY_XF86MonBrightnessDown, Qt::Key_MonBrightnessDown>,
+ Xkb2Qt<XKB_KEY_XF86KbdLightOnOff, Qt::Key_KeyboardLightOnOff>,
+ Xkb2Qt<XKB_KEY_XF86KbdBrightnessUp, Qt::Key_KeyboardBrightnessUp>,
+ Xkb2Qt<XKB_KEY_XF86KbdBrightnessDown, Qt::Key_KeyboardBrightnessDown>,
+ Xkb2Qt<XKB_KEY_XF86PowerOff, Qt::Key_PowerOff>,
+ Xkb2Qt<XKB_KEY_XF86WakeUp, Qt::Key_WakeUp>,
+ Xkb2Qt<XKB_KEY_XF86Eject, Qt::Key_Eject>,
+ Xkb2Qt<XKB_KEY_XF86ScreenSaver, Qt::Key_ScreenSaver>,
+ Xkb2Qt<XKB_KEY_XF86WWW, Qt::Key_WWW>,
+ Xkb2Qt<XKB_KEY_XF86Sleep, Qt::Key_Sleep>,
+ Xkb2Qt<XKB_KEY_XF86LightBulb, Qt::Key_LightBulb>,
+ Xkb2Qt<XKB_KEY_XF86Shop, Qt::Key_Shop>,
+ Xkb2Qt<XKB_KEY_XF86History, Qt::Key_History>,
+ Xkb2Qt<XKB_KEY_XF86AddFavorite, Qt::Key_AddFavorite>,
+ Xkb2Qt<XKB_KEY_XF86HotLinks, Qt::Key_HotLinks>,
+ Xkb2Qt<XKB_KEY_XF86BrightnessAdjust, Qt::Key_BrightnessAdjust>,
+ Xkb2Qt<XKB_KEY_XF86Finance, Qt::Key_Finance>,
+ Xkb2Qt<XKB_KEY_XF86Community, Qt::Key_Community>,
+ Xkb2Qt<XKB_KEY_XF86AudioRewind, Qt::Key_AudioRewind>,
+ Xkb2Qt<XKB_KEY_XF86BackForward, Qt::Key_BackForward>,
+ Xkb2Qt<XKB_KEY_XF86ApplicationLeft, Qt::Key_ApplicationLeft>,
+ Xkb2Qt<XKB_KEY_XF86ApplicationRight, Qt::Key_ApplicationRight>,
+ Xkb2Qt<XKB_KEY_XF86Book, Qt::Key_Book>,
+ Xkb2Qt<XKB_KEY_XF86CD, Qt::Key_CD>,
+ Xkb2Qt<XKB_KEY_XF86Calculater, Qt::Key_Calculator>,
+ Xkb2Qt<XKB_KEY_XF86Clear, Qt::Key_Clear>,
+ Xkb2Qt<XKB_KEY_XF86ClearGrab, Qt::Key_ClearGrab>,
+ Xkb2Qt<XKB_KEY_XF86Close, Qt::Key_Close>,
+ Xkb2Qt<XKB_KEY_XF86Copy, Qt::Key_Copy>,
+ Xkb2Qt<XKB_KEY_XF86Cut, Qt::Key_Cut>,
+ Xkb2Qt<XKB_KEY_XF86Display, Qt::Key_Display>,
+ Xkb2Qt<XKB_KEY_XF86DOS, Qt::Key_DOS>,
+ Xkb2Qt<XKB_KEY_XF86Documents, Qt::Key_Documents>,
+ Xkb2Qt<XKB_KEY_XF86Excel, Qt::Key_Excel>,
+ Xkb2Qt<XKB_KEY_XF86Explorer, Qt::Key_Explorer>,
+ Xkb2Qt<XKB_KEY_XF86Game, Qt::Key_Game>,
+ Xkb2Qt<XKB_KEY_XF86Go, Qt::Key_Go>,
+ Xkb2Qt<XKB_KEY_XF86iTouch, Qt::Key_iTouch>,
+ Xkb2Qt<XKB_KEY_XF86LogOff, Qt::Key_LogOff>,
+ Xkb2Qt<XKB_KEY_XF86Market, Qt::Key_Market>,
+ Xkb2Qt<XKB_KEY_XF86Meeting, Qt::Key_Meeting>,
+ Xkb2Qt<XKB_KEY_XF86MenuKB, Qt::Key_MenuKB>,
+ Xkb2Qt<XKB_KEY_XF86MenuPB, Qt::Key_MenuPB>,
+ Xkb2Qt<XKB_KEY_XF86MySites, Qt::Key_MySites>,
+ Xkb2Qt<XKB_KEY_XF86New, Qt::Key_New>,
+ Xkb2Qt<XKB_KEY_XF86News, Qt::Key_News>,
+ Xkb2Qt<XKB_KEY_XF86OfficeHome, Qt::Key_OfficeHome>,
+ Xkb2Qt<XKB_KEY_XF86Open, Qt::Key_Open>,
+ Xkb2Qt<XKB_KEY_XF86Option, Qt::Key_Option>,
+ Xkb2Qt<XKB_KEY_XF86Paste, Qt::Key_Paste>,
+ Xkb2Qt<XKB_KEY_XF86Phone, Qt::Key_Phone>,
+ Xkb2Qt<XKB_KEY_XF86Reply, Qt::Key_Reply>,
+ Xkb2Qt<XKB_KEY_XF86Reload, Qt::Key_Reload>,
+ Xkb2Qt<XKB_KEY_XF86RotateWindows, Qt::Key_RotateWindows>,
+ Xkb2Qt<XKB_KEY_XF86RotationPB, Qt::Key_RotationPB>,
+ Xkb2Qt<XKB_KEY_XF86RotationKB, Qt::Key_RotationKB>,
+ Xkb2Qt<XKB_KEY_XF86Save, Qt::Key_Save>,
+ Xkb2Qt<XKB_KEY_XF86Send, Qt::Key_Send>,
+ Xkb2Qt<XKB_KEY_XF86Spell, Qt::Key_Spell>,
+ Xkb2Qt<XKB_KEY_XF86SplitScreen, Qt::Key_SplitScreen>,
+ Xkb2Qt<XKB_KEY_XF86Support, Qt::Key_Support>,
+ Xkb2Qt<XKB_KEY_XF86TaskPane, Qt::Key_TaskPane>,
+ Xkb2Qt<XKB_KEY_XF86Terminal, Qt::Key_Terminal>,
+ Xkb2Qt<XKB_KEY_XF86Tools, Qt::Key_Tools>,
+ Xkb2Qt<XKB_KEY_XF86Travel, Qt::Key_Travel>,
+ Xkb2Qt<XKB_KEY_XF86Video, Qt::Key_Video>,
+ Xkb2Qt<XKB_KEY_XF86Word, Qt::Key_Word>,
+ Xkb2Qt<XKB_KEY_XF86Xfer, Qt::Key_Xfer>,
+ Xkb2Qt<XKB_KEY_XF86ZoomIn, Qt::Key_ZoomIn>,
+ Xkb2Qt<XKB_KEY_XF86ZoomOut, Qt::Key_ZoomOut>,
+ Xkb2Qt<XKB_KEY_XF86Away, Qt::Key_Away>,
+ Xkb2Qt<XKB_KEY_XF86Messenger, Qt::Key_Messenger>,
+ Xkb2Qt<XKB_KEY_XF86WebCam, Qt::Key_WebCam>,
+ Xkb2Qt<XKB_KEY_XF86MailForward, Qt::Key_MailForward>,
+ Xkb2Qt<XKB_KEY_XF86Pictures, Qt::Key_Pictures>,
+ Xkb2Qt<XKB_KEY_XF86Music, Qt::Key_Music>,
+ Xkb2Qt<XKB_KEY_XF86Battery, Qt::Key_Battery>,
+ Xkb2Qt<XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth>,
+ Xkb2Qt<XKB_KEY_XF86WLAN, Qt::Key_WLAN>,
+ Xkb2Qt<XKB_KEY_XF86UWB, Qt::Key_UWB>,
+ Xkb2Qt<XKB_KEY_XF86AudioForward, Qt::Key_AudioForward>,
+ Xkb2Qt<XKB_KEY_XF86AudioRepeat, Qt::Key_AudioRepeat>,
+ Xkb2Qt<XKB_KEY_XF86AudioRandomPlay, Qt::Key_AudioRandomPlay>,
+ Xkb2Qt<XKB_KEY_XF86Subtitle, Qt::Key_Subtitle>,
+ Xkb2Qt<XKB_KEY_XF86AudioCycleTrack, Qt::Key_AudioCycleTrack>,
+ Xkb2Qt<XKB_KEY_XF86Time, Qt::Key_Time>,
+ Xkb2Qt<XKB_KEY_XF86Select, Qt::Key_Select>,
+ Xkb2Qt<XKB_KEY_XF86View, Qt::Key_View>,
+ Xkb2Qt<XKB_KEY_XF86TopMenu, Qt::Key_TopMenu>,
+ Xkb2Qt<XKB_KEY_XF86Red, Qt::Key_Red>,
+ Xkb2Qt<XKB_KEY_XF86Green, Qt::Key_Green>,
+ Xkb2Qt<XKB_KEY_XF86Yellow, Qt::Key_Yellow>,
+ Xkb2Qt<XKB_KEY_XF86Blue, Qt::Key_Blue>,
+ Xkb2Qt<XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth>,
+ Xkb2Qt<XKB_KEY_XF86Suspend, Qt::Key_Suspend>,
+ Xkb2Qt<XKB_KEY_XF86Hibernate, Qt::Key_Hibernate>,
+ Xkb2Qt<XKB_KEY_XF86TouchpadToggle, Qt::Key_TouchpadToggle>,
+ Xkb2Qt<XKB_KEY_XF86TouchpadOn, Qt::Key_TouchpadOn>,
+ Xkb2Qt<XKB_KEY_XF86TouchpadOff, Qt::Key_TouchpadOff>,
+ Xkb2Qt<XKB_KEY_XF86AudioMicMute, Qt::Key_MicMute>,
+ Xkb2Qt<XKB_KEY_XF86Launch0, Qt::Key_Launch2>, // ### Qt 6: remap properly
+ Xkb2Qt<XKB_KEY_XF86Launch1, Qt::Key_Launch3>,
+ Xkb2Qt<XKB_KEY_XF86Launch2, Qt::Key_Launch4>,
+ Xkb2Qt<XKB_KEY_XF86Launch3, Qt::Key_Launch5>,
+ Xkb2Qt<XKB_KEY_XF86Launch4, Qt::Key_Launch6>,
+ Xkb2Qt<XKB_KEY_XF86Launch5, Qt::Key_Launch7>,
+ Xkb2Qt<XKB_KEY_XF86Launch6, Qt::Key_Launch8>,
+ Xkb2Qt<XKB_KEY_XF86Launch7, Qt::Key_Launch9>,
+ Xkb2Qt<XKB_KEY_XF86Launch8, Qt::Key_LaunchA>,
+ Xkb2Qt<XKB_KEY_XF86Launch9, Qt::Key_LaunchB>,
+ Xkb2Qt<XKB_KEY_XF86LaunchA, Qt::Key_LaunchC>,
+ Xkb2Qt<XKB_KEY_XF86LaunchB, Qt::Key_LaunchD>,
+ Xkb2Qt<XKB_KEY_XF86LaunchC, Qt::Key_LaunchE>,
+ Xkb2Qt<XKB_KEY_XF86LaunchD, Qt::Key_LaunchF>,
+ Xkb2Qt<XKB_KEY_XF86LaunchE, Qt::Key_LaunchG>,
+ Xkb2Qt<XKB_KEY_XF86LaunchF, Qt::Key_LaunchH>
+ >::Data{}
+);
+
// Possible modifier states.
static const Qt::KeyboardModifiers ModsTbl[] = {
Qt::NoModifier, // 0
@@ -831,20 +853,20 @@ void QXcbKeyboard::updateXKBStateFromCore(quint16 state)
}
}
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
void QXcbKeyboard::updateXKBStateFromXI(void *modInfo, void *groupInfo)
{
if (m_config && !connection()->hasXKB()) {
- xXIModifierInfo *mods = static_cast<xXIModifierInfo *>(modInfo);
- xXIGroupInfo *group = static_cast<xXIGroupInfo *>(groupInfo);
+ 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
= xkb_state_update_mask(m_xkbState.get(),
- mods->base_mods,
- mods->latched_mods,
- mods->locked_mods,
- group->base_group,
- group->latched_group,
- group->locked_group);
+ mods->base,
+ mods->latched,
+ mods->locked,
+ group->base,
+ group->latched,
+ group->locked);
handleStateChanges(changedComponents);
}
@@ -1105,14 +1127,10 @@ int QXcbKeyboard::keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers modif
qtKey = xkbcommon_xkb_keysym_to_upper(keysym);
} else {
// check if we have a direct mapping
- int i = 0;
- while (KeyTbl[i]) {
- if (keysym == KeyTbl[i]) {
- qtKey = KeyTbl[i + 1];
- break;
- }
- i += 2;
- }
+ xkb2qt_t searchKey{keysym, 0};
+ auto it = std::lower_bound(KeyTbl.cbegin(), KeyTbl.cend(), searchKey);
+ if (it != KeyTbl.end() && !(searchKey < *it))
+ qtKey = it->qt;
}
QString text;
@@ -1461,64 +1479,6 @@ void QXcbKeyboard::resolveMaskConflicts()
}
}
-class KeyChecker
-{
-public:
- KeyChecker(xcb_window_t window, xcb_keycode_t code, xcb_timestamp_t time, quint16 state)
- : m_window(window)
- , m_code(code)
- , m_time(time)
- , m_state(state)
- , m_error(false)
- , m_release(true)
- {
- }
-
- bool checkEvent(xcb_generic_event_t *ev)
- {
- if (m_error || !ev)
- return false;
-
- int type = ev->response_type & ~0x80;
- if (type != XCB_KEY_PRESS && type != XCB_KEY_RELEASE)
- return false;
-
- xcb_key_press_event_t *event = (xcb_key_press_event_t *)ev;
-
- if (event->event != m_window || event->detail != m_code || event->state != m_state) {
- m_error = true;
- return false;
- }
-
- if (type == XCB_KEY_PRESS) {
- m_error = !m_release || event->time - m_time > 10;
- return !m_error;
- }
-
- if (m_release) {
- m_error = true;
- return false;
- }
-
- m_release = true;
- m_time = event->time;
-
- return false;
- }
-
- bool release() const { return m_release; }
- xcb_timestamp_t time() const { return m_time; }
-
-private:
- xcb_window_t m_window;
- xcb_keycode_t m_code;
- xcb_timestamp_t m_time;
- quint16 m_state;
-
- bool m_error;
- bool m_release;
-};
-
void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, xcb_keycode_t code,
quint16 state, xcb_timestamp_t time, bool fromSendEvent)
{
@@ -1532,7 +1492,6 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type,
if (type == QEvent::KeyPress)
targetWindow->updateNetWmUserTime(time);
-
ScopedXKBState sendEventState;
if (fromSendEvent) {
// Have a temporary keyboard state filled in from state
@@ -1550,7 +1509,7 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type,
struct xkb_state *xkbState = fromSendEvent ? sendEventState.get() : m_xkbState.get();
xcb_keysym_t sym = xkb_state_key_get_one_sym(xkbState, code);
- QString string = lookupString(xkbState, code);
+ QString text = lookupString(xkbState, code);
Qt::KeyboardModifiers modifiers = translateModifiers(state);
if (sym >= XKB_KEY_KP_Space && sym <= XKB_KEY_KP_9)
@@ -1575,55 +1534,43 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type,
int qtcode = keysymToQtKey(latinKeysym != XKB_KEY_NoSymbol ? latinKeysym : sym,
modifiers, xkbState, code);
- bool isAutoRepeat = false;
if (type == QEvent::KeyPress) {
- if (m_autorepeat_code == code) {
- isAutoRepeat = true;
- m_autorepeat_code = 0;
- }
+ if (m_isAutoRepeat && m_autoRepeatCode != code)
+ // Some other key was pressed while we are auto-repeating on a different key.
+ m_isAutoRepeat = false;
} else {
- // look ahead for auto-repeat
- KeyChecker checker(source->xcb_window(), code, time, state);
- xcb_generic_event_t *event = connection()->checkEvent(checker);
- if (event) {
- isAutoRepeat = true;
- free(event);
- }
- m_autorepeat_code = isAutoRepeat ? code : 0;
+ m_isAutoRepeat = false;
+ // Look at the next event in the queue to see if we are auto-repeating.
+ connection()->eventQueue()->peek(QXcbEventQueue::PeekRetainMatch,
+ [this, time, code](xcb_generic_event_t *event, int type) {
+ if (type == XCB_KEY_PRESS) {
+ auto keyPress = reinterpret_cast<xcb_key_press_event_t *>(event);
+ m_isAutoRepeat = keyPress->time == time && keyPress->detail == code;
+ if (m_isAutoRepeat)
+ m_autoRepeatCode = code;
+ }
+ return true;
+ });
}
bool filtered = false;
- QPlatformInputContext *inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext();
- if (inputContext) {
- QKeyEvent event(type, qtcode, modifiers, code, sym, state, string, isAutoRepeat, string.length());
+ if (auto inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext()) {
+ QKeyEvent event(type, qtcode, modifiers, code, sym, state, text, m_isAutoRepeat, text.size());
event.setTimestamp(time);
filtered = inputContext->filterEvent(&event);
}
- QWindow *window = targetWindow->window();
if (!filtered) {
+ QWindow *window = targetWindow->window();
#ifndef QT_NO_CONTEXTMENU
if (type == QEvent::KeyPress && qtcode == Qt::Key_Menu) {
const QPoint globalPos = window->screen()->handle()->cursor()->pos();
const QPoint pos = window->mapFromGlobal(globalPos);
QWindowSystemInterface::handleContextMenuEvent(window, false, pos, globalPos, modifiers);
}
-#endif // QT_NO_CONTEXTMENU
+#endif
QWindowSystemInterface::handleExtendedKeyEvent(window, time, type, qtcode, modifiers,
- code, sym, state, string, isAutoRepeat);
- }
-
- if (isAutoRepeat && type == QEvent::KeyRelease) {
- // since we removed it from the event queue using checkEvent we need to send the key press here
- filtered = false;
- if (inputContext) {
- QKeyEvent event(QEvent::KeyPress, qtcode, modifiers, code, sym, state, string, isAutoRepeat, string.length());
- event.setTimestamp(time);
- filtered = inputContext->filterEvent(&event);
- }
- if (!filtered)
- QWindowSystemInterface::handleExtendedKeyEvent(window, time, QEvent::KeyPress, qtcode, modifiers,
- code, sym, state, string, isAutoRepeat);
+ code, sym, state, text, m_isAutoRepeat);
}
}
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h
index c131d69267..95915fb2e6 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.h
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.h
@@ -74,7 +74,7 @@ public:
void updateXKBMods();
xkb_mod_mask_t xkbModMask(quint16 state);
void updateXKBStateFromCore(quint16 state);
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
void updateXKBStateFromXI(void *modInfo, void *groupInfo);
#endif
#if QT_CONFIG(xkb)
@@ -109,7 +109,8 @@ protected:
private:
bool m_config = false;
- xcb_keycode_t m_autorepeat_code = 0;
+ bool m_isAutoRepeat = false;
+ xcb_keycode_t m_autoRepeatCode = 0;
struct _mod_masks {
uint alt;
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
index db44e58cbb..524af5a2a7 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
@@ -54,7 +54,6 @@
#include <QtGui/qscreen.h>
#include <QtPlatformHeaders/qxcbwindowfunctions.h>
-#include <QtPlatformHeaders/qxcbintegrationfunctions.h>
#include <QtPlatformHeaders/qxcbscreenfunctions.h>
#include <stdio.h>
@@ -93,8 +92,7 @@ static int resourceType(const QByteArray &key)
return int(result - names);
}
-QXcbNativeInterface::QXcbNativeInterface() :
- m_genericEventFilterType(QByteArrayLiteral("xcb_generic_event_t"))
+QXcbNativeInterface::QXcbNativeInterface()
{
}
@@ -106,50 +104,6 @@ static inline QXcbSystemTrayTracker *systemTrayTracker(const QScreen *s)
return static_cast<const QXcbScreen *>(s->handle())->connection()->systemTrayTracker();
}
-bool QXcbNativeInterface::systemTrayAvailable(const QScreen *screen) const
-{
- return systemTrayTracker(screen);
-}
-
-bool QXcbNativeInterface::requestSystemTrayWindowDock(const QWindow *window)
-{
- return QXcbWindow::requestSystemTrayWindowDockStatic(window);
-}
-
-QRect QXcbNativeInterface::systemTrayWindowGlobalGeometry(const QWindow *window)
-{
- return QXcbWindow::systemTrayWindowGlobalGeometryStatic(window);
-}
-
-xcb_window_t QXcbNativeInterface::locateSystemTray(xcb_connection_t *conn, const QXcbScreen *screen)
-{
- if (m_sysTraySelectionAtom == XCB_ATOM_NONE) {
- const QByteArray net_sys_tray = QString::fromLatin1("_NET_SYSTEM_TRAY_S%1").arg(screen->screenNumber()).toLatin1();
- auto intern_r = Q_XCB_REPLY_UNCHECKED(xcb_intern_atom, conn,
- true, net_sys_tray.length(), net_sys_tray);
- if (!intern_r)
- return XCB_WINDOW_NONE;
-
- m_sysTraySelectionAtom = intern_r->atom;
- }
-
- auto sel_owner_r = Q_XCB_REPLY_UNCHECKED(xcb_get_selection_owner, conn, m_sysTraySelectionAtom);
- if (!sel_owner_r)
- return XCB_WINDOW_NONE;
-
- return sel_owner_r->owner;
-}
-
-bool QXcbNativeInterface::systrayVisualHasAlphaChannel()
-{
- return QXcbConnection::xEmbedSystemTrayVisualHasAlphaChannel();
-}
-
-void QXcbNativeInterface::setParentRelativeBackPixmap(QWindow *window)
-{
- QXcbWindow::setParentRelativeBackPixmapStatic(window);
-}
-
void *QXcbNativeInterface::nativeResourceForIntegration(const QByteArray &resourceString)
{
QByteArray lowerCaseResource = resourceString.toLower();
@@ -371,18 +325,6 @@ QFunctionPointer QXcbNativeInterface::platformFunction(const QByteArray &functio
if (function == QXcbWindowFunctions::setWmWindowIconTextIdentifier())
return QFunctionPointer(QXcbWindowFunctions::SetWmWindowIconText(QXcbWindow::setWindowIconTextStatic));
- if (function == QXcbWindowFunctions::setParentRelativeBackPixmapIdentifier())
- return QFunctionPointer(QXcbWindowFunctions::SetParentRelativeBackPixmap(QXcbWindow::setParentRelativeBackPixmapStatic));
-
- if (function == QXcbWindowFunctions::requestSystemTrayWindowDockIdentifier())
- return QFunctionPointer(QXcbWindowFunctions::RequestSystemTrayWindowDock(QXcbWindow::requestSystemTrayWindowDockStatic));
-
- if (function == QXcbWindowFunctions::systemTrayWindowGlobalGeometryIdentifier())
- return QFunctionPointer(QXcbWindowFunctions::SystemTrayWindowGlobalGeometry(QXcbWindow::systemTrayWindowGlobalGeometryStatic));
-
- if (function == QXcbIntegrationFunctions::xEmbedSystemTrayVisualHasAlphaChannelIdentifier())
- return QFunctionPointer(QXcbIntegrationFunctions::XEmbedSystemTrayVisualHasAlphaChannel(QXcbConnection::xEmbedSystemTrayVisualHasAlphaChannel));
-
if (function == QXcbWindowFunctions::visualIdIdentifier()) {
return QFunctionPointer(QXcbWindowFunctions::VisualId(QXcbWindow::visualIdStatic));
}
@@ -466,7 +408,7 @@ void *QXcbNativeInterface::atspiBus()
QXcbIntegration *integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration());
QXcbConnection *defaultConnection = integration->defaultConnection();
if (defaultConnection) {
- xcb_atom_t atspiBusAtom = defaultConnection->internAtom("AT_SPI_BUS");
+ auto atspiBusAtom = defaultConnection->atom(QXcbAtom::AT_SPI_BUS);
auto reply = Q_XCB_REPLY(xcb_get_property, defaultConnection->xcb_connection(),
false, defaultConnection->rootWindow(),
atspiBusAtom, XCB_ATOM_STRING, 0, 128);
@@ -495,20 +437,20 @@ void QXcbNativeInterface::setAppUserTime(QScreen* screen, xcb_timestamp_t time)
qint32 QXcbNativeInterface::generatePeekerId()
{
QXcbIntegration *integration = QXcbIntegration::instance();
- return integration->defaultConnection()->generatePeekerId();
+ return integration->defaultConnection()->eventQueue()->generatePeekerId();
}
bool QXcbNativeInterface::removePeekerId(qint32 peekerId)
{
QXcbIntegration *integration = QXcbIntegration::instance();
- return integration->defaultConnection()->removePeekerId(peekerId);
+ return integration->defaultConnection()->eventQueue()->removePeekerId(peekerId);
}
-bool QXcbNativeInterface::peekEventQueue(QXcbConnection::PeekerCallback peeker, void *peekerData,
- QXcbConnection::PeekOptions option, qint32 peekerId)
+bool QXcbNativeInterface::peekEventQueue(QXcbEventQueue::PeekerCallback peeker, void *peekerData,
+ QXcbEventQueue::PeekOptions option, qint32 peekerId)
{
QXcbIntegration *integration = QXcbIntegration::instance();
- return integration->defaultConnection()->peekEventQueue(peeker, peekerData, option, peekerId);
+ return integration->defaultConnection()->eventQueue()->peekEventQueue(peeker, peekerData, option, peekerId);
}
void QXcbNativeInterface::setStartupId(const char *data)
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h
index 6a752c68ca..4656f46be5 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.h
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h
@@ -98,7 +98,7 @@ public:
QFunctionPointer platformFunction(const QByteArray &function) const override;
- inline const QByteArray &genericEventFilterType() const { return m_genericEventFilterType; }
+ inline const QByteArray &nativeEventType() const { return m_nativeEventType; }
void *displayForWindow(QWindow *window);
void *connectionForWindow(QWindow *window);
@@ -118,15 +118,10 @@ public:
static qint32 generatePeekerId();
static bool removePeekerId(qint32 peekerId);
- static bool peekEventQueue(QXcbConnection::PeekerCallback peeker, void *peekerData = nullptr,
- QXcbConnection::PeekOptions option = QXcbConnection::PeekDefault,
+ static bool peekEventQueue(QXcbEventQueue::PeekerCallback peeker, void *peekerData = nullptr,
+ QXcbEventQueue::PeekOptions option = QXcbEventQueue::PeekDefault,
qint32 peekerId = -1);
- Q_INVOKABLE bool systemTrayAvailable(const QScreen *screen) const;
- Q_INVOKABLE void setParentRelativeBackPixmap(QWindow *window);
- Q_INVOKABLE bool systrayVisualHasAlphaChannel();
- Q_INVOKABLE bool requestSystemTrayWindowDock(const QWindow *window);
- Q_INVOKABLE QRect systemTrayWindowGlobalGeometry(const QWindow *window);
Q_INVOKABLE QString dumpConnectionNativeWindows(const QXcbConnection *connection, WId root) const;
Q_INVOKABLE QString dumpNativeWindows(WId root = 0) const;
@@ -136,9 +131,7 @@ signals:
void systemTrayWindowChanged(QScreen *screen);
private:
- xcb_window_t locateSystemTray(xcb_connection_t *conn, const QXcbScreen *screen);
-
- const QByteArray m_genericEventFilterType;
+ const QByteArray m_nativeEventType = QByteArrayLiteral("xcb_generic_event_t");
xcb_atom_t m_sysTraySelectionAtom = XCB_ATOM_NONE;
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index 7f2793b2b7..8c0ce8dd7e 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -95,12 +95,6 @@ QXcbVirtualDesktop::QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t
m_windowManagerName = QXcbWindow::windowTitle(connection, windowManager);
}
- const xcb_query_extension_reply_t *sync_reply = xcb_get_extension_data(xcb_connection(), &xcb_sync_id);
- if (!sync_reply || !sync_reply->present)
- m_syncRequestSupported = false;
- else
- m_syncRequestSupported = true;
-
xcb_depth_iterator_t depth_iterator =
xcb_screen_allowed_depths_iterator(screen);
@@ -912,16 +906,12 @@ QByteArray QXcbScreen::getEdid() const
return result;
// Try a bunch of atoms
- xcb_atom_t atom = connection()->internAtom("EDID");
- result = getOutputProperty(atom);
- if (result.isEmpty()) {
- atom = connection()->internAtom("EDID_DATA");
- result = getOutputProperty(atom);
- }
- if (result.isEmpty()) {
- atom = connection()->internAtom("XFree86_DDC_EDID1_RAWDATA");
- result = getOutputProperty(atom);
- }
+ result = getOutputProperty(atom(QXcbAtom::EDID));
+ if (result.isEmpty())
+ result = getOutputProperty(atom(QXcbAtom::EDID_DATA));
+ if (result.isEmpty())
+ result = getOutputProperty(atom(QXcbAtom::XFree86_DDC_EDID1_RAWDATA));
+
return result;
}
diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h
index 6438669e7a..4404a04f49 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.h
+++ b/src/plugins/platforms/xcb/qxcbscreen.h
@@ -102,7 +102,6 @@ public:
int antialiasingEnabled() const { return m_antialiasingEnabled; }
QString windowManagerName() const { return m_windowManagerName; }
- bool syncRequestSupported() const { return m_syncRequestSupported; }
QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &format) const;
@@ -133,7 +132,6 @@ private:
QFontEngine::SubpixelAntialiasingType m_subpixelType = QFontEngine::SubpixelAntialiasingType(-1);
int m_antialiasingEnabled = -1;
QString m_windowManagerName;
- bool m_syncRequestSupported = false;
QMap<xcb_visualid_t, xcb_visualtype_t> m_visuals;
QMap<xcb_visualid_t, quint8> m_visualDepths;
uint16_t m_rotation = XCB_RANDR_ROTATION_ROTATE_0;
@@ -188,7 +186,6 @@ public:
void windowShown(QXcbWindow *window);
QString windowManagerName() const { return m_virtualDesktop->windowManagerName(); }
- bool syncRequestSupported() const { return m_virtualDesktop->syncRequestSupported(); }
QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &format) const;
@@ -220,7 +217,6 @@ private:
xcb_randr_crtc_t m_crtc;
xcb_randr_mode_t m_mode = XCB_NONE;
bool m_primary = false;
- uint8_t m_rotation = XCB_RANDR_ROTATION_ROTATE_0;
QString m_outputName;
QSizeF m_outputSizeMillimeters;
diff --git a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp
index c98879c7df..684e603fab 100644
--- a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp
+++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp
@@ -91,8 +91,7 @@ xcb_window_t QXcbSystemTrayTracker::locateTrayWindow(const QXcbConnection *conne
return reply->owner;
}
-// API for QPlatformNativeInterface/QPlatformSystemTrayIcon: Request a window
-// to be docked on the tray.
+// Request a window to be docked on the tray.
void QXcbSystemTrayTracker::requestSystemTrayWindowDock(xcb_window_t window) const
{
xcb_client_message_event_t trayRequest;
@@ -122,23 +121,6 @@ xcb_window_t QXcbSystemTrayTracker::trayWindow()
return m_trayWindow;
}
-// API for QPlatformNativeInterface/QPlatformSystemTrayIcon: Return the geometry of a
-// a window parented on the tray. Determines the global geometry via XCB since mapToGlobal
-// does not work for the QWindow parented on the tray.
-QRect QXcbSystemTrayTracker::systemTrayWindowGlobalGeometry(xcb_window_t window) const
-{
- xcb_connection_t *conn = m_connection->xcb_connection();
- auto geomReply = Q_XCB_REPLY(xcb_get_geometry, conn, window);
- if (!geomReply)
- return QRect();
-
- auto translateReply = Q_XCB_REPLY(xcb_translate_coordinates, conn, window, m_connection->rootWindow(), 0, 0);
- if (!translateReply)
- return QRect();
-
- return QRect(QPoint(translateReply->dst_x, translateReply->dst_y), QSize(geomReply->width, geomReply->height));
-}
-
inline void QXcbSystemTrayTracker::emitSystemTrayWindowChanged()
{
if (const QPlatformScreen *ps = m_connection->primaryScreen())
@@ -162,10 +144,18 @@ void QXcbSystemTrayTracker::handleDestroyNotifyEvent(const xcb_destroy_notify_ev
}
}
-bool QXcbSystemTrayTracker::visualHasAlphaChannel()
+xcb_visualid_t QXcbSystemTrayTracker::visualId()
+{
+ xcb_visualid_t visual = netSystemTrayVisual();
+ if (visual == XCB_NONE)
+ visual = m_connection->primaryScreen()->screen()->root_visual;
+ return visual;
+}
+
+xcb_visualid_t QXcbSystemTrayTracker::netSystemTrayVisual()
{
if (m_trayWindow == XCB_WINDOW_NONE)
- return false;
+ return XCB_NONE;
xcb_atom_t tray_atom = m_connection->atom(QXcbAtom::_NET_SYSTEM_TRAY_VISUAL);
@@ -174,7 +164,7 @@ bool QXcbSystemTrayTracker::visualHasAlphaChannel()
false, m_trayWindow,
tray_atom, XCB_ATOM_VISUALID, 0, 1);
if (!systray_atom_reply)
- return false;
+ return XCB_NONE;
xcb_visualid_t systrayVisualId = XCB_NONE;
if (systray_atom_reply->value_len > 0 && xcb_get_property_value_length(systray_atom_reply.get()) > 0) {
@@ -182,12 +172,7 @@ bool QXcbSystemTrayTracker::visualHasAlphaChannel()
systrayVisualId = vids[0];
}
- if (systrayVisualId != XCB_NONE) {
- quint8 depth = m_connection->primaryScreen()->depthOfVisual(systrayVisualId);
- return depth == 32;
- }
-
- return false;
+ return systrayVisualId;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbsystemtraytracker.h b/src/plugins/platforms/xcb/qxcbsystemtraytracker.h
index a95b9374e9..d2fc24c957 100644
--- a/src/plugins/platforms/xcb/qxcbsystemtraytracker.h
+++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.h
@@ -57,13 +57,12 @@ public:
xcb_window_t trayWindow();
void requestSystemTrayWindowDock(xcb_window_t window) const;
- QRect systemTrayWindowGlobalGeometry(xcb_window_t window) const;
void notifyManagerClientMessageEvent(const xcb_client_message_event_t *);
void handleDestroyNotifyEvent(const xcb_destroy_notify_event_t *) override;
- bool visualHasAlphaChannel();
+ xcb_visualid_t visualId();
signals:
void systemTrayWindowChanged(QScreen *screen);
@@ -73,6 +72,7 @@ private:
xcb_atom_t selection);
static xcb_window_t locateTrayWindow(const QXcbConnection *connection, xcb_atom_t selection);
void emitSystemTrayWindowChanged();
+ xcb_visualid_t netSystemTrayVisual();
const xcb_atom_t m_selection;
const xcb_atom_t m_trayAtom;
diff --git a/src/plugins/platforms/xcb/qxcbvulkaninstance.cpp b/src/plugins/platforms/xcb/qxcbvulkaninstance.cpp
index 4d540defa9..b3f8a5832d 100644
--- a/src/plugins/platforms/xcb/qxcbvulkaninstance.cpp
+++ b/src/plugins/platforms/xcb/qxcbvulkaninstance.cpp
@@ -46,20 +46,9 @@ QT_BEGIN_NAMESPACE
QXcbVulkanInstance::QXcbVulkanInstance(QVulkanInstance *instance)
: m_instance(instance),
m_getPhysDevPresSupport(nullptr),
- m_createSurface(nullptr),
- m_destroySurface(nullptr)
+ m_createSurface(nullptr)
{
- if (qEnvironmentVariableIsSet("QT_VULKAN_LIB"))
- m_lib.setFileName(QString::fromUtf8(qgetenv("QT_VULKAN_LIB")));
- else
- m_lib.setFileName(QStringLiteral("vulkan"));
-
- if (!m_lib.load()) {
- qWarning("Failed to load %s: %s", qPrintable(m_lib.fileName()), qPrintable(m_lib.errorString()));
- return;
- }
-
- init(&m_lib);
+ loadVulkanLibrary(QStringLiteral("vulkan"));
}
QXcbVulkanInstance::~QXcbVulkanInstance()
@@ -114,14 +103,6 @@ VkSurfaceKHR QXcbVulkanInstance::createSurface(QXcbWindow *window)
qWarning("Failed to find vkCreateXcbSurfaceKHR");
return surface;
}
- if (!m_destroySurface) {
- m_destroySurface = reinterpret_cast<PFN_vkDestroySurfaceKHR>(
- m_vkGetInstanceProcAddr(m_vkInst, "vkDestroySurfaceKHR"));
- }
- if (!m_destroySurface) {
- qWarning("Failed to find vkDestroySurfaceKHR");
- return surface;
- }
VkXcbSurfaceCreateInfoKHR surfaceInfo;
memset(&surfaceInfo, 0, sizeof(surfaceInfo));
@@ -135,12 +116,6 @@ VkSurfaceKHR QXcbVulkanInstance::createSurface(QXcbWindow *window)
return surface;
}
-void QXcbVulkanInstance::destroySurface(VkSurfaceKHR surface)
-{
- if (m_destroySurface && surface)
- m_destroySurface(m_vkInst, surface, nullptr);
-}
-
void QXcbVulkanInstance::presentQueued(QWindow *window)
{
QXcbWindow *w = static_cast<QXcbWindow *>(window->handle());
diff --git a/src/plugins/platforms/xcb/qxcbvulkaninstance.h b/src/plugins/platforms/xcb/qxcbvulkaninstance.h
index dbe057d944..53f7345254 100644
--- a/src/plugins/platforms/xcb/qxcbvulkaninstance.h
+++ b/src/plugins/platforms/xcb/qxcbvulkaninstance.h
@@ -64,14 +64,11 @@ public:
void presentQueued(QWindow *window) override;
VkSurfaceKHR createSurface(QXcbWindow *window);
- void destroySurface(VkSurfaceKHR surface);
private:
QVulkanInstance *m_instance;
- QLibrary m_lib;
PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR m_getPhysDevPresSupport;
PFN_vkCreateXcbSurfaceKHR m_createSurface;
- PFN_vkDestroySurfaceKHR m_destroySurface;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 59b06d543e..f36bb5a51e 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -70,6 +70,9 @@
#undef class
#include <xcb/xfixes.h>
#include <xcb/shape.h>
+#if QT_CONFIG(xcb_xinput)
+#include <xcb/xinput.h>
+#endif
// xcb-icccm 3.8 support
#ifdef XCB_ICCCM_NUM_WM_SIZE_HINTS_ELEMENTS
@@ -109,11 +112,6 @@
#undef register
#endif
-#if QT_CONFIG(xinput2)
-#include <X11/extensions/XInput2.h>
-#include <X11/extensions/XI2proto.h>
-#endif
-
#define XCOORD_MAX 16383
enum {
defaultWindowWidth = 160,
@@ -200,11 +198,6 @@ void QXcbWindow::setImageFormatForVisual(const xcb_visualtype_t *visual)
}
}
-static inline bool positionIncludesFrame(QWindow *w)
-{
- return qt_window_private(w)->positionPolicy == QWindowPrivate::WindowFrameInclusive;
-}
-
#if QT_CONFIG(xcb_xlib)
static inline XTextProperty* qstringToXTP(Display *dpy, const QString& s)
{
@@ -282,11 +275,7 @@ QXcbWindow::QXcbWindow(QWindow *window)
setConnection(xcbScreen()->connection());
}
-#ifdef Q_COMPILER_CLASS_ENUM
enum : quint32 {
-#else
-enum {
-#endif
baseEventMask
= XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY
| XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_FOCUS_CHANGE,
@@ -308,6 +297,7 @@ void QXcbWindow::create()
destroy();
m_windowState = Qt::WindowNoState;
+ m_trayIconWindow = isTrayIconWindow(window());
Qt::WindowType type = window()->type();
@@ -334,9 +324,6 @@ void QXcbWindow::create()
return;
}
- // Parameters to XCreateWindow() are frame corner + inner size.
- // This fits in case position policy is frame inclusive. There is
- // currently no way to implement it for frame-exclusive geometries.
QPlatformWindow::setGeometry(rect);
if (platformScreen != currentScreen)
@@ -368,7 +355,9 @@ void QXcbWindow::create()
const xcb_visualtype_t *visual = nullptr;
- if (connection()->hasDefaultVisualId()) {
+ if (m_trayIconWindow && connection()->systemTrayTracker()) {
+ visual = platformScreen->visualForId(connection()->systemTrayTracker()->visualId());
+ } else if (connection()->hasDefaultVisualId()) {
visual = platformScreen->visualForId(connection()->defaultVisualId());
if (!visual)
qWarning() << "Failed to use requested visual id.";
@@ -408,9 +397,12 @@ void QXcbWindow::create()
| XCB_CW_SAVE_UNDER
| XCB_CW_EVENT_MASK;
- static const bool haveOpenGL = QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL);
+ static auto haveOpenGL = []() {
+ static const bool result = QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL);
+ return result;
+ };
- if ((window()->supportsOpenGL() && haveOpenGL) || m_format.hasAlpha()) {
+ if ((window()->supportsOpenGL() && haveOpenGL()) || m_format.hasAlpha()) {
m_cmap = xcb_generate_id(xcb_connection());
xcb_create_colormap(xcb_connection(),
XCB_COLORMAP_ALLOC_NONE,
@@ -448,8 +440,6 @@ void QXcbWindow::create()
connection()->addWindowEventListener(m_window, this);
- xcb_change_window_attributes(xcb_connection(), m_window, mask, values);
-
propagateSizeHints();
xcb_atom_t properties[5];
@@ -458,9 +448,7 @@ void QXcbWindow::create()
properties[propertyCount++] = atom(QXcbAtom::WM_TAKE_FOCUS);
properties[propertyCount++] = atom(QXcbAtom::_NET_WM_PING);
- m_usingSyncProtocol = platformScreen->syncRequestSupported();
-
- if (m_usingSyncProtocol)
+ if (connection()->hasXSync())
properties[propertyCount++] = atom(QXcbAtom::_NET_WM_SYNC_REQUEST);
if (window()->flags() & Qt::WindowContextHelpButtonHint)
@@ -484,7 +472,7 @@ void QXcbWindow::create()
XCB_ATOM_STRING, 8, wmClass.size(), wmClass.constData());
}
- if (m_usingSyncProtocol) {
+ if (connection()->hasXSync()) {
m_syncCounter = xcb_generate_id(xcb_connection());
xcb_sync_create_counter(xcb_connection(), m_syncCounter, m_syncValue);
@@ -504,12 +492,17 @@ void QXcbWindow::create()
atom(QXcbAtom::_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,
+ clientMachine.size(), clientMachine.constData());
+ }
+
+ // Create WM_HINTS property on the window, so we can xcb_get_wm_hints*()
+ // from various setter functions for adjusting the hints.
xcb_wm_hints_t hints;
memset(&hints, 0, sizeof(hints));
- xcb_wm_hints_set_normal(&hints);
-
- xcb_wm_hints_set_input(&hints, !(window()->flags() & Qt::WindowDoesNotAcceptFocus));
-
xcb_set_wm_hints(xcb_connection(), m_window, &hints);
xcb_window_t leader = connection()->clientLeader();
@@ -524,7 +517,7 @@ void QXcbWindow::create()
atom(QXcbAtom::_XEMBED_INFO),
32, 2, (void *)data);
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
if (connection()->hasXInput2()) {
if (connection()->xi2MouseEventsDisabled())
connection()->xi2SelectDeviceEventsCompatibility(m_window);
@@ -537,9 +530,6 @@ void QXcbWindow::create()
setWindowFlags(window()->flags());
setWindowTitle(window()->title());
- if (window()->flags() & Qt::WindowTransparentForInput)
- setTransparentForMouseEvents(true);
-
#if QT_CONFIG(xcb_xlib)
// force sync to read outstanding requests - see QTBUG-29106
XSync(static_cast<Display*>(platformScreen->connection()->xlib_display()), false);
@@ -562,6 +552,9 @@ void QXcbWindow::create()
QByteArray wmWindowRole = window()->property(wm_window_role_property_id).toByteArray();
setWmWindowRole(wmWindowRole);
}
+
+ if (m_trayIconWindow)
+ m_embedded = requestSystemTrayWindowDock();
}
QXcbWindow::~QXcbWindow()
@@ -587,7 +580,7 @@ void QXcbWindow::destroy()
if (connection()->mouseGrabber() == this)
connection()->setMouseGrabber(nullptr);
- if (m_syncCounter && m_usingSyncProtocol)
+ if (m_syncCounter && connection()->hasXSync())
xcb_sync_destroy_counter(xcb_connection(), m_syncCounter);
if (m_window) {
if (m_netWmUserTimeWindow) {
@@ -623,25 +616,23 @@ void QXcbWindow::setGeometry(const QRect &rect)
if (!newScreen)
newScreen = xcbScreen();
- const QRect wmGeometry = windowToWmGeometry(rect);
-
if (newScreen != currentScreen)
QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen());
if (qt_window_private(window())->positionAutomatic) {
const quint32 mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
const qint32 values[] = {
- qBound<qint32>(1, wmGeometry.width(), XCOORD_MAX),
- qBound<qint32>(1, wmGeometry.height(), XCOORD_MAX),
+ qBound<qint32>(1, rect.width(), XCOORD_MAX),
+ qBound<qint32>(1, rect.height(), XCOORD_MAX),
};
xcb_configure_window(xcb_connection(), m_window, mask, reinterpret_cast<const quint32*>(values));
} else {
const quint32 mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
const qint32 values[] = {
- qBound<qint32>(-XCOORD_MAX, wmGeometry.x(), XCOORD_MAX),
- qBound<qint32>(-XCOORD_MAX, wmGeometry.y(), XCOORD_MAX),
- qBound<qint32>(1, wmGeometry.width(), XCOORD_MAX),
- qBound<qint32>(1, wmGeometry.height(), XCOORD_MAX),
+ qBound<qint32>(-XCOORD_MAX, rect.x(), XCOORD_MAX),
+ qBound<qint32>(-XCOORD_MAX, rect.y(), XCOORD_MAX),
+ qBound<qint32>(1, rect.width(), XCOORD_MAX),
+ qBound<qint32>(1, rect.height(), XCOORD_MAX),
};
xcb_configure_window(xcb_connection(), m_window, mask, reinterpret_cast<const quint32*>(values));
if (window()->parent() && !window()->transientParent()) {
@@ -739,34 +730,10 @@ void QXcbWindow::setVisible(bool visible)
hide();
}
-static inline bool testShowWithoutActivating(const QWindow *window)
-{
- // QWidget-attribute Qt::WA_ShowWithoutActivating.
- const QVariant showWithoutActivating = window->property("_q_showWithoutActivating");
- return showWithoutActivating.isValid() && showWithoutActivating.toBool();
-}
-
void QXcbWindow::show()
{
if (window()->isTopLevel()) {
- xcb_get_property_cookie_t cookie = xcb_get_wm_hints_unchecked(xcb_connection(), m_window);
-
- xcb_wm_hints_t hints;
- xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, NULL);
-
- if (window()->windowStates() & Qt::WindowMinimized)
- xcb_wm_hints_set_iconic(&hints);
- else
- xcb_wm_hints_set_normal(&hints);
-
- xcb_wm_hints_set_input(&hints, !(window()->flags() & Qt::WindowDoesNotAcceptFocus));
-
- xcb_set_wm_hints(xcb_connection(), m_window, &hints);
-
- m_gravity = positionIncludesFrame(window()) ?
- XCB_GRAVITY_NORTH_WEST : XCB_GRAVITY_STATIC;
-
// update WM_NORMAL_HINTS
propagateSizeHints();
@@ -796,12 +763,14 @@ void QXcbWindow::show()
updateNetWmStateBeforeMap();
}
- if (testShowWithoutActivating(window()))
+ // QWidget-attribute Qt::WA_ShowWithoutActivating.
+ const auto showWithoutActivating = window()->property("_q_showWithoutActivating");
+ if (showWithoutActivating.isValid() && showWithoutActivating.toBool())
updateNetWmUserTime(0);
else if (connection()->time() != XCB_TIME_CURRENT_TIME)
updateNetWmUserTime(connection()->time());
- if (window()->objectName() == QLatin1String("QSystemTrayIconSysWindow"))
+ if (m_trayIconWindow)
return; // defer showing until XEMBED_EMBEDDED_NOTIFY
xcb_map_window(xcb_connection(), m_window);
@@ -819,7 +788,7 @@ void QXcbWindow::hide()
xcb_unmap_window(xcb_connection(), m_window);
// send synthetic UnmapNotify event according to icccm 4.1.4
- Q_DECLARE_XCB_EVENT(event, xcb_unmap_notify_event_t);
+ q_padded_xcb_event<xcb_unmap_notify_event_t> event = {};
event.response_type = XCB_UNMAP_NOTIFY;
event.event = xcbScreen()->root();
event.window = m_window;
@@ -1242,6 +1211,16 @@ void QXcbWindow::setWindowState(Qt::WindowStates state)
changeNetWmState(state & Qt::WindowFullScreen, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN));
}
+ xcb_get_property_cookie_t cookie = xcb_get_wm_hints_unchecked(xcb_connection(), m_window);
+ xcb_wm_hints_t hints;
+ if (xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, nullptr)) {
+ if (state & Qt::WindowMinimized)
+ xcb_wm_hints_set_iconic(&hints);
+ else
+ xcb_wm_hints_set_normal(&hints);
+ xcb_set_wm_hints(xcb_connection(), m_window, &hints);
+ }
+
connection()->sync();
m_windowState = state;
}
@@ -1364,17 +1343,10 @@ void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp)
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, atom(QXcbAtom::_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));
-#ifndef QT_NO_DEBUG
- QByteArray ba("Qt NET_WM user time window");
- xcb_change_property(xcb_connection(),
- XCB_PROP_MODE_REPLACE,
- m_netWmUserTimeWindow,
- atom(QXcbAtom::_NET_WM_NAME),
- atom(QXcbAtom::UTF8_STRING),
- 8,
- ba.length(),
- ba.constData());
-#endif
+
+ QXcbWindow::setWindowTitle(connection(), m_netWmUserTimeWindow,
+ QStringLiteral("Qt NET_WM User Time Window"));
+
} else if (!isSupportedByWM) {
// WM no longer supports it, then we should remove the
// _NET_WM_USER_TIME_WINDOW atom.
@@ -1421,9 +1393,8 @@ void QXcbWindow::updateDoesNotAcceptFocus(bool doesNotAcceptFocus)
xcb_get_property_cookie_t cookie = xcb_get_wm_hints_unchecked(xcb_connection(), m_window);
xcb_wm_hints_t hints;
- if (!xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, NULL)) {
+ if (!xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, nullptr))
return;
- }
xcb_wm_hints_set_input(&hints, !doesNotAcceptFocus);
xcb_set_wm_hints(xcb_connection(), m_window, &hints);
@@ -1452,24 +1423,7 @@ void QXcbWindow::setParent(const QPlatformWindow *parent)
void QXcbWindow::setWindowTitle(const QString &title)
{
- QString fullTitle = formatWindowTitle(title, QString::fromUtf8(" \xe2\x80\x94 ")); // unicode character U+2014, EM DASH
- const QByteArray ba = std::move(fullTitle).toUtf8();
- xcb_change_property(xcb_connection(),
- XCB_PROP_MODE_REPLACE,
- m_window,
- atom(QXcbAtom::_NET_WM_NAME),
- atom(QXcbAtom::UTF8_STRING),
- 8,
- ba.length(),
- ba.constData());
-
-#if QT_CONFIG(xcb_xlib)
- Display *dpy = static_cast<Display *>(connection()->xlib_display());
- XTextProperty *text = qstringToXTP(dpy, title);
- if (text)
- XSetWMName(dpy, m_window, text);
-#endif
- xcb_flush(xcb_connection());
+ setWindowTitle(connection(), m_window, title);
}
void QXcbWindow::setWindowIconText(const QString &title)
@@ -1541,38 +1495,28 @@ void QXcbWindow::lower()
xcb_configure_window(xcb_connection(), m_window, mask, values);
}
-// Adapt the geometry to match the WM expection with regards
-// to gravity.
-QRect QXcbWindow::windowToWmGeometry(QRect r) const
-{
- if (m_dirtyFrameMargins || m_frameMargins.isNull())
- return r;
- const bool frameInclusive = positionIncludesFrame(window());
- // XCB_GRAVITY_STATIC requires the inner geometry, whereas
- // XCB_GRAVITY_NORTH_WEST requires the frame geometry
- if (frameInclusive && m_gravity == XCB_GRAVITY_STATIC) {
- r.translate(m_frameMargins.left(), m_frameMargins.top());
- } else if (!frameInclusive && m_gravity == XCB_GRAVITY_NORTH_WEST) {
- r.translate(-m_frameMargins.left(), -m_frameMargins.top());
- }
- return r;
-}
-
void QXcbWindow::propagateSizeHints()
{
// update WM_NORMAL_HINTS
xcb_size_hints_t hints;
memset(&hints, 0, sizeof(hints));
- const QRect xRect = windowToWmGeometry(geometry());
+ const QRect rect = geometry();
+ QWindowPrivate *win = qt_window_private(window());
+
+ if (!win->positionAutomatic)
+ xcb_size_hints_set_position(&hints, true, rect.x(), rect.y());
+ if (rect.width() < QWINDOWSIZE_MAX || rect.height() < QWINDOWSIZE_MAX)
+ xcb_size_hints_set_size(&hints, true, rect.width(), rect.height());
- QWindow *win = window();
+ /* Gravity describes how to interpret x and y values the next time
+ window needs to be positioned on a screen.
+ XCB_GRAVITY_STATIC : the left top corner of the client window
+ XCB_GRAVITY_NORTH_WEST : the left top corner of the frame window */
+ auto gravity = win->positionPolicy == QWindowPrivate::WindowFrameInclusive
+ ? XCB_GRAVITY_NORTH_WEST : XCB_GRAVITY_STATIC;
- if (!qt_window_private(win)->positionAutomatic)
- xcb_size_hints_set_position(&hints, true, xRect.x(), xRect.y());
- if (xRect.width() < QWINDOWSIZE_MAX || xRect.height() < QWINDOWSIZE_MAX)
- xcb_size_hints_set_size(&hints, true, xRect.width(), xRect.height());
- xcb_size_hints_set_win_gravity(&hints, m_gravity);
+ xcb_size_hints_set_win_gravity(&hints, gravity);
QSize minimumSize = windowMinimumSize();
QSize maximumSize = windowMaximumSize();
@@ -1836,12 +1780,6 @@ void QXcbWindow::setWmWindowRole(const QByteArray &role)
role.size(), role.constData());
}
-void QXcbWindow::setParentRelativeBackPixmapStatic(QWindow *window)
-{
- if (window->handle())
- static_cast<QXcbWindow *>(window->handle())->setParentRelativeBackPixmap();
-}
-
void QXcbWindow::setParentRelativeBackPixmap()
{
const quint32 mask = XCB_CW_BACK_PIXMAP;
@@ -1849,14 +1787,7 @@ void QXcbWindow::setParentRelativeBackPixmap()
xcb_change_window_attributes(xcb_connection(), m_window, mask, values);
}
-bool QXcbWindow::requestSystemTrayWindowDockStatic(const QWindow *window)
-{
- if (window->handle())
- return static_cast<QXcbWindow *>(window->handle())->requestSystemTrayWindowDock();
- return false;
-}
-
-bool QXcbWindow::requestSystemTrayWindowDock() const
+bool QXcbWindow::requestSystemTrayWindowDock()
{
if (!connection()->systemTrayTracker())
return false;
@@ -1864,81 +1795,33 @@ bool QXcbWindow::requestSystemTrayWindowDock() const
return true;
}
-QRect QXcbWindow::systemTrayWindowGlobalGeometryStatic(const QWindow *window)
+bool QXcbWindow::handleNativeEvent(xcb_generic_event_t *event)
{
- if (window->handle())
- return static_cast<QXcbWindow *>(window->handle())->systemTrayWindowGlobalGeometry();
- return QRect();
+ auto eventType = connection()->nativeInterface()->nativeEventType();
+ long result = 0; // Used only by MS Windows
+ return QWindowSystemInterface::handleNativeEvent(window(), eventType, event, &result);
}
-QRect QXcbWindow::systemTrayWindowGlobalGeometry() const
+void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event)
{
- if (!connection()->systemTrayTracker())
- return QRect();
- return connection()->systemTrayTracker()->systemTrayWindowGlobalGeometry(m_window);
-}
+ QRect rect(event->x, event->y, event->width, event->height);
+ m_exposeRegion |= rect;
-class ExposeCompressor
-{
-public:
- ExposeCompressor(xcb_window_t window, QRegion *region)
- : m_window(window)
- , m_region(region)
- , m_pending(true)
- {
- }
+ bool pending = true;
- bool checkEvent(xcb_generic_event_t *event)
- {
- if (!event)
- return false;
- if ((event->response_type & ~0x80) != XCB_EXPOSE)
+ connection()->eventQueue()->peek(QXcbEventQueue::PeekRemoveMatchContinue,
+ [this, &pending](xcb_generic_event_t *event, int type) {
+ if (type != XCB_EXPOSE)
return false;
- xcb_expose_event_t *expose = (xcb_expose_event_t *)event;
+ auto expose = reinterpret_cast<xcb_expose_event_t *>(event);
if (expose->window != m_window)
return false;
if (expose->count == 0)
- m_pending = false;
- *m_region |= QRect(expose->x, expose->y, expose->width, expose->height);
+ pending = false;
+ m_exposeRegion |= QRect(expose->x, expose->y, expose->width, expose->height);
+ free(expose);
return true;
- }
-
- bool pending() const
- {
- return m_pending;
- }
-
-private:
- xcb_window_t m_window;
- QRegion *m_region;
- bool m_pending;
-};
-
-bool QXcbWindow::compressExposeEvent(QRegion &exposeRegion)
-{
- ExposeCompressor compressor(m_window, &exposeRegion);
- xcb_generic_event_t *filter = 0;
- do {
- filter = connection()->checkEvent(compressor);
- free(filter);
- } while (filter);
- return compressor.pending();
-}
-
-bool QXcbWindow::handleGenericEvent(xcb_generic_event_t *event, long *result)
-{
- return QWindowSystemInterface::handleNativeEvent(window(),
- connection()->nativeInterface()->genericEventFilterType(),
- event,
- result);
-}
-
-void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event)
-{
- QRect rect(event->x, event->y, event->width, event->height);
-
- m_exposeRegion |= rect;
- bool pending = compressExposeEvent(m_exposeRegion);
+ });
// if count is non-zero there are more expose events pending
if (event->count == 0 || !pending) {
@@ -1977,7 +1860,7 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
connection()->setTime(event->data.data32[1]);
m_syncValue.lo = event->data.data32[2];
m_syncValue.hi = event->data.data32[3];
- if (m_usingSyncProtocol)
+ if (connection()->hasXSync())
m_syncState = SyncReceived;
#ifndef QT_NO_WHATSTHIS
} else if (protocolAtom == atom(QXcbAtom::_NET_WM_CONTEXT_HELP)) {
@@ -2052,7 +1935,7 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *
}
m_oldWindowSize = actualGeometry.size();
- if (m_usingSyncProtocol && m_syncState == SyncReceived)
+ if (connection()->hasXSync() && m_syncState == SyncReceived)
m_syncState = SyncAndConfigureReceived;
m_dirtyFrameMargins = true;
@@ -2137,7 +2020,7 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in
updateNetWmUserTime(timestamp);
- if (m_embedded) {
+ if (m_embedded && !m_trayIconWindow) {
if (window() != QGuiApplication::focusWindow()) {
const QXcbWindow *container = static_cast<const QXcbWindow *>(parent());
Q_ASSERT(container != 0);
@@ -2149,7 +2032,7 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in
QPoint global(root_x, root_y);
if (isWheel) {
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
if (!connection()->isAtLeastXI21()) {
#endif
QPoint angleDelta;
@@ -2164,7 +2047,7 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in
if (modifiers & Qt::AltModifier)
std::swap(angleDelta.rx(), angleDelta.ry());
QWindowSystemInterface::handleWheelEvent(window(), timestamp, local, global, QPoint(), angleDelta, modifiers);
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
}
#endif
return;
@@ -2204,7 +2087,7 @@ static inline bool doCheckUnGrabAncestor(QXcbConnection *conn)
if (conn) {
const bool mouseButtonsPressed = (conn->buttonState() != Qt::NoButton);
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
return mouseButtonsPressed || (conn->hasXInput2() && !conn->xi2MouseEventsDisabled());
#else
return mouseButtonsPressed;
@@ -2231,24 +2114,6 @@ static bool ignoreEnterEvent(quint8 mode, quint8 detail, QXcbConnection *conn =
|| detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL);
}
-class EnterEventChecker
-{
-public:
- bool checkEvent(xcb_generic_event_t *event)
- {
- if (!event)
- return false;
- if ((event->response_type & ~0x80) != XCB_ENTER_NOTIFY)
- return false;
-
- xcb_enter_notify_event_t *enter = (xcb_enter_notify_event_t *)event;
- if (ignoreEnterEvent(enter->mode, enter->detail))
- return false;
-
- return true;
- }
-};
-
void QXcbWindow::handleEnterNotifyEvent(int event_x, int event_y, int root_x, int root_y,
quint8 mode, quint8 detail, xcb_timestamp_t timestamp)
{
@@ -2258,7 +2123,7 @@ void QXcbWindow::handleEnterNotifyEvent(int event_x, int event_y, int root_x, in
if (ignoreEnterEvent(mode, detail, connection()) || connection()->mousePressWindow())
return;
-#ifdef XCB_USE_XINPUT21
+#if QT_CONFIG(xcb_xinput)
// Updates scroll valuators, as user might have done some scrolling outside our X client.
connection()->xi2UpdateScrollingDevices();
#endif
@@ -2275,9 +2140,15 @@ void QXcbWindow::handleLeaveNotifyEvent(int root_x, int root_y,
if (ignoreLeaveEvent(mode, detail, connection()) || connection()->mousePressWindow())
return;
- EnterEventChecker checker;
- xcb_enter_notify_event_t *enter = (xcb_enter_notify_event_t *)connection()->checkEvent(checker);
- QXcbWindow *enterWindow = enter ? connection()->platformWindowFromId(enter->event) : 0;
+ // check if enter event is buffered
+ auto event = connection()->eventQueue()->peek([](xcb_generic_event_t *event, int type) {
+ if (type != XCB_ENTER_NOTIFY)
+ return false;
+ auto enter = reinterpret_cast<xcb_enter_notify_event_t *>(event);
+ return !ignoreEnterEvent(enter->mode, enter->detail);
+ });
+ auto enter = reinterpret_cast<xcb_enter_notify_event_t *>(event);
+ QXcbWindow *enterWindow = enter ? connection()->platformWindowFromId(enter->event) : nullptr;
if (enterWindow) {
QPoint local(enter->event_x, enter->event_y);
@@ -2330,16 +2201,18 @@ void QXcbWindow::handleMotionNotifyEvent(const xcb_motion_notify_event_t *event)
event->time, QEvent::MouseMove);
}
-#if QT_CONFIG(xinput2)
-static inline int fixed1616ToInt(FP1616 val)
+#if QT_CONFIG(xcb_xinput)
+static inline int fixed1616ToInt(xcb_input_fp1616_t val)
{
return int(qreal(val) / 0x10000);
}
+#define qt_xcb_mask_is_set(ptr, event) (((unsigned char*)(ptr))[(event)>>3] & (1 << ((event) & 7)))
+
void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event, Qt::MouseEventSource source)
{
QXcbConnection *conn = connection();
- xXIDeviceEvent *ev = reinterpret_cast<xXIDeviceEvent *>(event);
+ auto *ev = reinterpret_cast<xcb_input_button_press_event_t *>(event);
if (ev->buttons_len > 0) {
unsigned char *buttonMask = (unsigned char *) &ev[1];
@@ -2347,16 +2220,16 @@ void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event, Qt::MouseEventSource
// XIPointerEmulated being set: https://bugs.freedesktop.org/show_bug.cgi?id=98188
// Filter them out by other attributes: when their source device is a touch screen
// and the LMB is pressed.
- if (XIMaskIsSet(buttonMask, 1) && conn->isTouchScreen(ev->sourceid)) {
+ if (qt_xcb_mask_is_set(buttonMask, 1) && conn->isTouchScreen(ev->sourceid)) {
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInput, "XI2 mouse event from touch device %d was ignored", ev->sourceid);
return;
}
for (int i = 1; i <= 15; ++i)
- conn->setButtonState(conn->translateMouseButton(i), XIMaskIsSet(buttonMask, i));
+ conn->setButtonState(conn->translateMouseButton(i), qt_xcb_mask_is_set(buttonMask, i));
}
- const Qt::KeyboardModifiers modifiers = conn->keyboard()->translateModifiers(ev->mods.effective_mods);
+ const Qt::KeyboardModifiers modifiers = conn->keyboard()->translateModifiers(ev->mods.effective);
const int event_x = fixed1616ToInt(ev->event_x);
const int event_y = fixed1616ToInt(ev->event_y);
const int root_x = fixed1616ToInt(ev->root_x);
@@ -2373,47 +2246,47 @@ void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event, Qt::MouseEventSource
sourceName = me.valueToKey(source);
}
- switch (ev->evtype) {
- case XI_ButtonPress:
+ switch (ev->event_type) {
+ case XCB_INPUT_BUTTON_PRESS:
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInputEvents, "XI2 mouse press, button %d, time %d, source %s", button, ev->time, sourceName);
conn->setButtonState(button, true);
handleButtonPressEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, QEvent::MouseButtonPress, source);
break;
- case XI_ButtonRelease:
+ case XCB_INPUT_BUTTON_RELEASE:
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInputEvents, "XI2 mouse release, button %d, time %d, source %s", button, ev->time, sourceName);
conn->setButtonState(button, false);
handleButtonReleaseEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, QEvent::MouseButtonRelease, source);
break;
- case XI_Motion:
+ case XCB_INPUT_MOTION:
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
qCDebug(lcQpaXInputEvents, "XI2 mouse motion %d,%d, time %d, source %s", event_x, event_y, ev->time, sourceName);
handleMotionNotifyEvent(event_x, event_y, root_x, root_y, modifiers, ev->time, QEvent::MouseMove, source);
break;
default:
- qWarning() << "Unrecognized XI2 mouse event" << ev->evtype;
+ qWarning() << "Unrecognized XI2 mouse event" << ev->event_type;
break;
}
}
void QXcbWindow::handleXIEnterLeave(xcb_ge_event_t *event)
{
- xXIEnterEvent *ev = reinterpret_cast<xXIEnterEvent *>(event);
+ auto *ev = reinterpret_cast<xcb_input_enter_event_t *>(event);
// Compare the window with current mouse grabber to prevent deliver events to any other windows.
// If leave event occurs and the window is under mouse - allow to deliver the leave event.
QXcbWindow *mouseGrabber = connection()->mouseGrabber();
if (mouseGrabber && mouseGrabber != this
- && (ev->evtype != XI_Leave || QGuiApplicationPrivate::currentMouseWindow != window())) {
+ && (ev->event_type != XCB_INPUT_LEAVE || QGuiApplicationPrivate::currentMouseWindow != window())) {
return;
}
const int root_x = fixed1616ToInt(ev->root_x);
const int root_y = fixed1616ToInt(ev->root_y);
- switch (ev->evtype) {
- case XI_Enter: {
+ switch (ev->event_type) {
+ case XCB_INPUT_ENTER: {
const int event_x = fixed1616ToInt(ev->event_x);
const int event_y = fixed1616ToInt(ev->event_y);
qCDebug(lcQpaXInputEvents, "XI2 mouse enter %d,%d, mode %d, detail %d, time %d",
@@ -2421,7 +2294,7 @@ void QXcbWindow::handleXIEnterLeave(xcb_ge_event_t *event)
handleEnterNotifyEvent(event_x, event_y, root_x, root_y, ev->mode, ev->detail, ev->time);
break;
}
- case XI_Leave:
+ case XCB_INPUT_LEAVE:
qCDebug(lcQpaXInputEvents, "XI2 mouse leave, mode %d, detail %d, time %d",
ev->mode, ev->detail, ev->time);
connection()->keyboard()->updateXKBStateFromXI(&ev->mods, &ev->group);
@@ -2523,7 +2396,7 @@ void QXcbWindow::updateSyncRequestCounter()
// window manager does not expect a sync event yet.
return;
}
- if (m_usingSyncProtocol && (m_syncValue.lo != 0 || m_syncValue.hi != 0)) {
+ if (connection()->hasXSync() && (m_syncValue.lo != 0 || m_syncValue.hi != 0)) {
xcb_sync_set_counter(xcb_connection(), m_syncCounter, m_syncValue);
xcb_flush(xcb_connection());
@@ -2563,7 +2436,7 @@ bool QXcbWindow::setMouseGrabEnabled(bool grab)
if (grab && !connection()->canGrab())
return false;
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
if (connection()->hasXInput2() && !connection()->xi2MouseEventsDisabled()) {
bool result = connection()->xi2SetMouseGrabEnabled(m_window, grab);
if (grab && result)
@@ -2591,11 +2464,11 @@ bool QXcbWindow::setMouseGrabEnabled(bool grab)
return result;
}
-void QXcbWindow::windowEvent(QEvent *event)
+bool QXcbWindow::windowEvent(QEvent *event)
{
switch (event->type()) {
case QEvent::FocusIn:
- if (m_embedded && !event->spontaneous()) {
+ if (m_embedded && !m_trayIconWindow && !event->spontaneous()) {
QFocusEvent *focusEvent = static_cast<QFocusEvent *>(event);
switch (focusEvent->reason()) {
case Qt::TabFocusReason:
@@ -2617,7 +2490,7 @@ void QXcbWindow::windowEvent(QEvent *event)
default:
break;
}
- QPlatformWindow::windowEvent(event);
+ return QPlatformWindow::windowEvent(event);
}
bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner)
@@ -2638,7 +2511,7 @@ bool QXcbWindow::startSystemMoveResize(const QPoint &pos, int corner)
return false;
const QPoint globalPos = QHighDpi::toNativePixels(window()->mapToGlobal(pos), window()->screen());
-#ifdef XCB_USE_XINPUT22
+#if QT_CONFIG(xcb_xinput)
// ### FIXME QTBUG-53389
bool startedByTouch = connection()->startSystemMoveResizeForTouchBegin(m_window, globalPos, corner);
if (startedByTouch) {
@@ -2659,6 +2532,7 @@ bool QXcbWindow::startSystemMoveResize(const QPoint &pos, int corner)
return true;
}
+
void QXcbWindow::doStartSystemMoveResize(const QPoint &globalPos, int corner)
{
const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE);
@@ -2728,11 +2602,6 @@ void QXcbWindow::handleXEmbedMessage(const xcb_client_message_event_t *event)
case XEMBED_EMBEDDED_NOTIFY:
xcb_map_window(xcb_connection(), m_window);
xcbScreen()->windowShown(this);
- // Without Qt::WA_TranslucentBackground, we use a ParentRelative BackPixmap.
- // Clear the whole tray icon window to its background color as early as possible
- // so that we can get a clean result from grabWindow() later.
- xcb_clear_area(xcb_connection(), false, m_window, 0, 0, geometry().width(), geometry().height());
- xcb_flush(xcb_connection());
break;
case XEMBED_FOCUS_IN:
Qt::FocusReason reason;
@@ -2846,6 +2715,28 @@ QXcbScreen *QXcbWindow::xcbScreen() const
return static_cast<QXcbScreen *>(screen());
}
+void QXcbWindow::setWindowTitle(const QXcbConnection *conn, xcb_window_t window, const QString &title)
+{
+ QString fullTitle = formatWindowTitle(title, QString::fromUtf8(" \xe2\x80\x94 ")); // unicode character U+2014, EM DASH
+ const QByteArray ba = std::move(fullTitle).toUtf8();
+ xcb_change_property(conn->xcb_connection(),
+ XCB_PROP_MODE_REPLACE,
+ window,
+ conn->atom(QXcbAtom::_NET_WM_NAME),
+ conn->atom(QXcbAtom::UTF8_STRING),
+ 8,
+ ba.length(),
+ ba.constData());
+
+#if QT_CONFIG(xcb_xlib)
+ Display *dpy = static_cast<Display *>(conn->xlib_display());
+ XTextProperty *text = qstringToXTP(dpy, title);
+ if (text)
+ XSetWMName(dpy, window, text);
+#endif
+ xcb_flush(conn->xcb_connection());
+}
+
QString QXcbWindow::windowTitle(const QXcbConnection *conn, xcb_window_t window)
{
const xcb_atom_t utf8Atom = conn->atom(QXcbAtom::UTF8_STRING);
@@ -2856,6 +2747,15 @@ QString QXcbWindow::windowTitle(const QXcbConnection *conn, xcb_window_t window)
const char *name = reinterpret_cast<const char *>(xcb_get_property_value(reply.get()));
return QString::fromUtf8(name, xcb_get_property_value_length(reply.get()));
}
+
+ reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, conn->xcb_connection(),
+ false, window, conn->atom(QXcbAtom::WM_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()));
+ return QString::fromLatin1(name, xcb_get_property_value_length(reply.get()));
+ }
+
return QString();
}
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index c4f49c593c..f7d76ed3b2 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -105,7 +105,7 @@ public:
QSurfaceFormat format() const override;
- void windowEvent(QEvent *event) override;
+ bool windowEvent(QEvent *event) override;
bool startSystemResize(const QPoint &pos, Qt::Corner corner) override;
bool startSystemMove(const QPoint &pos) override;
@@ -121,7 +121,7 @@ public:
QImage::Format imageFormat() const { return m_imageFormat; }
bool imageNeedsRgbSwap() const { return m_imageRgbSwap; }
- bool handleGenericEvent(xcb_generic_event_t *event, long *result) override;
+ bool handleNativeEvent(xcb_generic_event_t *event) override;
void handleExposeEvent(const xcb_expose_event_t *event) override;
void handleClientMessageEvent(const xcb_client_message_event_t *event) override;
@@ -137,7 +137,7 @@ public:
void handleFocusInEvent(const xcb_focus_in_event_t *event) override;
void handleFocusOutEvent(const xcb_focus_out_event_t *event) override;
void handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) override;
-#if QT_CONFIG(xinput2)
+#if QT_CONFIG(xcb_xinput)
void handleXIMouseEvent(xcb_ge_event_t *, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized) override;
void handleXIEnterLeave(xcb_ge_event_t *) override;
#endif
@@ -159,14 +159,8 @@ public:
static void setWindowIconTextStatic(QWindow *window, const QString &text);
- static void setParentRelativeBackPixmapStatic(QWindow *window);
void setParentRelativeBackPixmap();
-
- static bool requestSystemTrayWindowDockStatic(const QWindow *window);
- bool requestSystemTrayWindowDock() const;
-
- static QRect systemTrayWindowGlobalGeometryStatic(const QWindow *window);
- QRect systemTrayWindowGlobalGeometry() const;
+ bool requestSystemTrayWindowDock();
uint visualId() const;
bool needsSync() const;
@@ -179,9 +173,15 @@ public:
bool startSystemMoveResize(const QPoint &pos, int corner);
void doStartSystemMoveResize(const QPoint &globalPos, int corner);
+ static bool isTrayIconWindow(QWindow *window)
+ {
+ return window->objectName() == QLatin1String("QSystemTrayIconSysWindow");
+ }
+
virtual void create();
virtual void destroy();
+ static void setWindowTitle(const QXcbConnection *conn, xcb_window_t window, const QString &title);
static QString windowTitle(const QXcbConnection *conn, xcb_window_t window);
public Q_SLOTS:
@@ -220,8 +220,6 @@ protected:
void doFocusIn();
void doFocusOut();
- bool compressExposeEvent(QRegion &exposeRegion);
-
void handleButtonPressEvent(int event_x, int event_y, int root_x, int root_y,
int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp,
QEvent::Type type, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized);
@@ -252,15 +250,13 @@ protected:
Qt::WindowStates m_windowState = Qt::WindowNoState;
- xcb_gravity_t m_gravity = XCB_GRAVITY_STATIC;
-
bool m_mapped = false;
bool m_transparent = false;
- bool m_usingSyncProtocol = false;
bool m_deferredActivation = false;
bool m_embedded = false;
bool m_alertState = false;
bool m_minimized = false;
+ bool m_trayIconWindow = false;
xcb_window_t m_netWmUserTimeWindow = XCB_NONE;
QSurfaceFormat m_format;
diff --git a/src/plugins/platforms/xcb/xcb-static/xcb-static.pro b/src/plugins/platforms/xcb/xcb-static/xcb-static.pro
index 20d8b83e7c..078b275381 100644
--- a/src/plugins/platforms/xcb/xcb-static/xcb-static.pro
+++ b/src/plugins/platforms/xcb/xcb-static/xcb-static.pro
@@ -2,7 +2,7 @@
# Statically compile in code for
# libxcb-fixes, libxcb-randr, libxcb-shm, libxcb-sync, libxcb-image,
# libxcb-keysyms, libxcb-icccm, libxcb-renderutil, libxcb-xkb,
-# libxcb-xinerama
+# libxcb-xinerama, libxcb-xinput
#
CONFIG += static
@@ -29,7 +29,8 @@ SOURCES += \
$$LIBXCB_DIR/render.c \
$$LIBXCB_DIR/shape.c \
$$LIBXCB_DIR/xkb.c \
- $$LIBXCB_DIR/xinerama.c
+ $$LIBXCB_DIR/xinerama.c \
+ $$LIBXCB_DIR/xinput.c
#
# xcb-util
diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro
index 9c4797ac26..a747b25c88 100644
--- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro
+++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro
@@ -5,7 +5,7 @@ DEFINES += QT_NO_FOREACH
QT += \
core-private gui-private \
service_support-private theme_support-private \
- eventdispatcher_support-private fontdatabase_support-private \
+ fontdatabase_support-private \
edid_support-private
qtHaveModule(linuxaccessibility_support-private): \
@@ -13,6 +13,8 @@ qtHaveModule(linuxaccessibility_support-private): \
qtConfig(vulkan): QT += vulkan_support-private
+qtConfig(glib) : QMAKE_USE_PRIVATE += glib
+
SOURCES = \
qxcbclipboard.cpp \
qxcbconnection.cpp \
@@ -27,7 +29,9 @@ SOURCES = \
qxcbcursor.cpp \
qxcbimage.cpp \
qxcbxsettings.cpp \
- qxcbsystemtraytracker.cpp
+ qxcbsystemtraytracker.cpp \
+ qxcbeventqueue.cpp \
+ qxcbeventdispatcher.cpp
HEADERS = \
qxcbclipboard.h \
@@ -45,7 +49,9 @@ HEADERS = \
qxcbimage.h \
qxcbxsettings.h \
qxcbsystemtraytracker.h \
- qxcbxkbcommon.h
+ qxcbxkbcommon.h \
+ qxcbeventqueue.h \
+ qxcbeventdispatcher.h
qtConfig(draganddrop) {
SOURCES += qxcbdrag.cpp
@@ -58,11 +64,10 @@ DEFINES += QT_BUILD_XCB_PLUGIN
qtConfig(xcb-xlib) {
QMAKE_USE += xcb_xlib
+}
- qtConfig(xinput2) {
- SOURCES += qxcbconnection_xi2.cpp
- QMAKE_USE += xinput2
- }
+qtConfig(xcb-xinput) {
+ SOURCES += qxcbconnection_xi2.cpp
}
qtConfig(xcb-sm) {
@@ -89,6 +94,7 @@ qtConfig(vulkan) {
} else {
qtConfig(xkb): QMAKE_USE += xcb_xkb
qtConfig(xcb-render): QMAKE_USE += xcb_render
+ qtConfig(xcb-xinput): QMAKE_USE += xcb_xinput
QMAKE_USE += xcb_syslibs
}
diff --git a/src/plugins/platformthemes/flatpak/flatpak.json b/src/plugins/platformthemes/flatpak/flatpak.json
deleted file mode 100644
index 71f834fd08..0000000000
--- a/src/plugins/platformthemes/flatpak/flatpak.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "Keys": [ "flatpak" ]
-}
diff --git a/src/plugins/platformthemes/flatpak/flatpak.pro b/src/plugins/platformthemes/flatpak/flatpak.pro
deleted file mode 100644
index 1e5dbb7a6c..0000000000
--- a/src/plugins/platformthemes/flatpak/flatpak.pro
+++ /dev/null
@@ -1,17 +0,0 @@
-TARGET = qflatpak
-
-PLUGIN_TYPE = platformthemes
-PLUGIN_EXTENDS = -
-PLUGIN_CLASS_NAME = QFlatpakThemePlugin
-load(qt_plugin)
-
-QT += core-private dbus gui-private theme_support-private
-
-HEADERS += \
- qflatpaktheme.h \
- qflatpakfiledialog_p.h
-
-SOURCES += \
- main.cpp \
- qflatpaktheme.cpp \
- qflatpakfiledialog.cpp
diff --git a/src/plugins/platformthemes/platformthemes.pro b/src/plugins/platformthemes/platformthemes.pro
index 02ed3406e7..3bcc659199 100644
--- a/src/plugins/platformthemes/platformthemes.pro
+++ b/src/plugins/platformthemes/platformthemes.pro
@@ -1,6 +1,6 @@
TEMPLATE = subdirs
QT_FOR_CONFIG += widgets-private
-qtConfig(dbus):qtConfig(regularexpression):qtConfig(mimetype): SUBDIRS += flatpak
+qtConfig(dbus):qtConfig(regularexpression):qtConfig(mimetype): SUBDIRS += xdgdesktopportal
qtHaveModule(widgets):qtConfig(gtk3): SUBDIRS += gtk3
diff --git a/src/plugins/platformthemes/flatpak/main.cpp b/src/plugins/platformthemes/xdgdesktopportal/main.cpp
index 7888eed8b2..64a03d479f 100644
--- a/src/plugins/platformthemes/flatpak/main.cpp
+++ b/src/plugins/platformthemes/xdgdesktopportal/main.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 Red Hat, Inc
+** Copyright (C) 2017-2018 Red Hat, Inc
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -38,24 +38,26 @@
****************************************************************************/
#include <qpa/qplatformthemeplugin.h>
-#include "qflatpaktheme.h"
+#include "qxdgdesktopportaltheme.h"
QT_BEGIN_NAMESPACE
-class QFlatpakThemePlugin : public QPlatformThemePlugin
+class QXdgDesktopPortalThemePlugin : public QPlatformThemePlugin
{
Q_OBJECT
- Q_PLUGIN_METADATA(IID QPlatformThemeFactoryInterface_iid FILE "flatpak.json")
+ Q_PLUGIN_METADATA(IID QPlatformThemeFactoryInterface_iid FILE "xdgdesktopportal.json")
public:
QPlatformTheme *create(const QString &key, const QStringList &params) override;
};
-QPlatformTheme *QFlatpakThemePlugin::create(const QString &key, const QStringList &params)
+QPlatformTheme *QXdgDesktopPortalThemePlugin::create(const QString &key, const QStringList &params)
{
Q_UNUSED(params);
- if (!key.compare(QLatin1String("flatpak"), Qt::CaseInsensitive))
- return new QFlatpakTheme;
+ if (!key.compare(QLatin1String("xdgdesktopportal"), Qt::CaseInsensitive) ||
+ !key.compare(QLatin1String("flatpak"), Qt::CaseInsensitive) ||
+ !key.compare(QLatin1String("snap"), Qt::CaseInsensitive))
+ return new QXdgDesktopPortalTheme;
return nullptr;
}
diff --git a/src/plugins/platformthemes/flatpak/qflatpakfiledialog.cpp b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp
index c31b326357..cda267d24b 100644
--- a/src/plugins/platformthemes/flatpak/qflatpakfiledialog.cpp
+++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 Red Hat, Inc
+** Copyright (C) 2017-2018 Red Hat, Inc
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -37,7 +37,7 @@
**
****************************************************************************/
-#include "qflatpakfiledialog_p.h"
+#include "qxdgdesktopportalfiledialog_p.h"
#include <QtCore/qeventloop.h>
@@ -56,7 +56,7 @@
QT_BEGIN_NAMESPACE
-QDBusArgument &operator <<(QDBusArgument &arg, const QFlatpakFileDialog::FilterCondition &filterCondition)
+QDBusArgument &operator <<(QDBusArgument &arg, const QXdgDesktopPortalFileDialog::FilterCondition &filterCondition)
{
arg.beginStructure();
arg << filterCondition.type << filterCondition.pattern;
@@ -64,20 +64,20 @@ QDBusArgument &operator <<(QDBusArgument &arg, const QFlatpakFileDialog::FilterC
return arg;
}
-const QDBusArgument &operator >>(const QDBusArgument &arg, QFlatpakFileDialog::FilterCondition &filterCondition)
+const QDBusArgument &operator >>(const QDBusArgument &arg, QXdgDesktopPortalFileDialog::FilterCondition &filterCondition)
{
uint type;
QString filterPattern;
arg.beginStructure();
arg >> type >> filterPattern;
- filterCondition.type = (QFlatpakFileDialog::ConditionType)type;
+ filterCondition.type = (QXdgDesktopPortalFileDialog::ConditionType)type;
filterCondition.pattern = filterPattern;
arg.endStructure();
return arg;
}
-QDBusArgument &operator <<(QDBusArgument &arg, const QFlatpakFileDialog::Filter filter)
+QDBusArgument &operator <<(QDBusArgument &arg, const QXdgDesktopPortalFileDialog::Filter filter)
{
arg.beginStructure();
arg << filter.name << filter.filterConditions;
@@ -85,10 +85,10 @@ QDBusArgument &operator <<(QDBusArgument &arg, const QFlatpakFileDialog::Filter
return arg;
}
-const QDBusArgument &operator >>(const QDBusArgument &arg, QFlatpakFileDialog::Filter &filter)
+const QDBusArgument &operator >>(const QDBusArgument &arg, QXdgDesktopPortalFileDialog::Filter &filter)
{
QString name;
- QFlatpakFileDialog::FilterConditionList filterConditions;
+ QXdgDesktopPortalFileDialog::FilterConditionList filterConditions;
arg.beginStructure();
arg >> name >> filterConditions;
filter.name = name;
@@ -98,9 +98,13 @@ const QDBusArgument &operator >>(const QDBusArgument &arg, QFlatpakFileDialog::F
return arg;
}
-class QFlatpakFileDialogPrivate
+class QXdgDesktopPortalFileDialogPrivate
{
public:
+ QXdgDesktopPortalFileDialogPrivate(QPlatformFileDialogHelper *nativeFileDialog)
+ : nativeFileDialog(nativeFileDialog)
+ { }
+
WId winId = 0;
bool modal = false;
bool multipleFiles = false;
@@ -111,21 +115,31 @@ public:
QStringList nameFilters;
QStringList mimeTypesFilters;
QStringList selectedFiles;
+ QPlatformFileDialogHelper *nativeFileDialog = nullptr;
};
-QFlatpakFileDialog::QFlatpakFileDialog()
+QXdgDesktopPortalFileDialog::QXdgDesktopPortalFileDialog(QPlatformFileDialogHelper *nativeFileDialog)
: QPlatformFileDialogHelper()
- , d_ptr(new QFlatpakFileDialogPrivate)
+ , d_ptr(new QXdgDesktopPortalFileDialogPrivate(nativeFileDialog))
{
+ Q_D(QXdgDesktopPortalFileDialog);
+
+ if (d->nativeFileDialog) {
+ connect(d->nativeFileDialog, SIGNAL(accept()), this, SIGNAL(accept()));
+ connect(d->nativeFileDialog, SIGNAL(reject()), this, SIGNAL(reject()));
+ }
}
-QFlatpakFileDialog::~QFlatpakFileDialog()
+QXdgDesktopPortalFileDialog::~QXdgDesktopPortalFileDialog()
{
}
-void QFlatpakFileDialog::initializeDialog()
+void QXdgDesktopPortalFileDialog::initializeDialog()
{
- Q_D(QFlatpakFileDialog);
+ Q_D(QXdgDesktopPortalFileDialog);
+
+ if (d->nativeFileDialog)
+ d->nativeFileDialog->setOptions(options());
if (options()->fileMode() == QFileDialogOptions::ExistingFiles)
d->multipleFiles = true;
@@ -148,9 +162,9 @@ void QFlatpakFileDialog::initializeDialog()
setDirectory(options()->initialDirectory());
}
-void QFlatpakFileDialog::openPortal()
+void QXdgDesktopPortalFileDialog::openPortal()
{
- Q_D(const QFlatpakFileDialog);
+ Q_D(const QXdgDesktopPortalFileDialog);
QDBusMessage message = QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.portal.Desktop"),
QLatin1String("/org/freedesktop/portal/desktop"),
@@ -256,35 +270,51 @@ void QFlatpakFileDialog::openPortal()
});
}
-bool QFlatpakFileDialog::defaultNameFilterDisables() const
+bool QXdgDesktopPortalFileDialog::defaultNameFilterDisables() const
{
return false;
}
-void QFlatpakFileDialog::setDirectory(const QUrl &directory)
+void QXdgDesktopPortalFileDialog::setDirectory(const QUrl &directory)
{
- Q_D(QFlatpakFileDialog);
+ Q_D(QXdgDesktopPortalFileDialog);
+
+ if (d->nativeFileDialog) {
+ d->nativeFileDialog->setOptions(options());
+ d->nativeFileDialog->setDirectory(directory);
+ }
d->directory = directory.path();
}
-QUrl QFlatpakFileDialog::directory() const
+QUrl QXdgDesktopPortalFileDialog::directory() const
{
- Q_D(const QFlatpakFileDialog);
+ Q_D(const QXdgDesktopPortalFileDialog);
+
+ if (d->nativeFileDialog && (options()->fileMode() == QFileDialogOptions::Directory || options()->fileMode() == QFileDialogOptions::DirectoryOnly))
+ return d->nativeFileDialog->directory();
return d->directory;
}
-void QFlatpakFileDialog::selectFile(const QUrl &filename)
+void QXdgDesktopPortalFileDialog::selectFile(const QUrl &filename)
{
- Q_D(QFlatpakFileDialog);
+ Q_D(QXdgDesktopPortalFileDialog);
+
+ if (d->nativeFileDialog) {
+ d->nativeFileDialog->setOptions(options());
+ d->nativeFileDialog->selectFile(filename);
+ }
d->selectedFiles << filename.path();
}
-QList<QUrl> QFlatpakFileDialog::selectedFiles() const
+QList<QUrl> QXdgDesktopPortalFileDialog::selectedFiles() const
{
- Q_D(const QFlatpakFileDialog);
+ Q_D(const QXdgDesktopPortalFileDialog);
+
+ if (d->nativeFileDialog && (options()->fileMode() == QFileDialogOptions::Directory || options()->fileMode() == QFileDialogOptions::DirectoryOnly))
+ return d->nativeFileDialog->selectedFiles();
QList<QUrl> files;
for (const QString &file : d->selectedFiles) {
@@ -293,25 +323,41 @@ QList<QUrl> QFlatpakFileDialog::selectedFiles() const
return files;
}
-void QFlatpakFileDialog::setFilter()
+void QXdgDesktopPortalFileDialog::setFilter()
{
- // TODO
+ Q_D(QXdgDesktopPortalFileDialog);
+
+ if (d->nativeFileDialog) {
+ d->nativeFileDialog->setOptions(options());
+ d->nativeFileDialog->setFilter();
+ }
}
-void QFlatpakFileDialog::selectNameFilter(const QString &filter)
+void QXdgDesktopPortalFileDialog::selectNameFilter(const QString &filter)
{
- Q_UNUSED(filter);
- // TODO
+ Q_D(QXdgDesktopPortalFileDialog);
+
+ if (d->nativeFileDialog) {
+ d->nativeFileDialog->setOptions(options());
+ d->nativeFileDialog->selectNameFilter(filter);
+ }
}
-QString QFlatpakFileDialog::selectedNameFilter() const
+QString QXdgDesktopPortalFileDialog::selectedNameFilter() const
{
// TODO
return QString();
}
-void QFlatpakFileDialog::exec()
+void QXdgDesktopPortalFileDialog::exec()
{
+ Q_D(QXdgDesktopPortalFileDialog);
+
+ if (d->nativeFileDialog && (options()->fileMode() == QFileDialogOptions::Directory || options()->fileMode() == QFileDialogOptions::DirectoryOnly)) {
+ 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()));
@@ -319,28 +365,34 @@ void QFlatpakFileDialog::exec()
loop.exec();
}
-void QFlatpakFileDialog::hide()
+void QXdgDesktopPortalFileDialog::hide()
{
+ Q_D(QXdgDesktopPortalFileDialog);
+
+ if (d->nativeFileDialog)
+ d->nativeFileDialog->hide();
}
-bool QFlatpakFileDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent)
+bool QXdgDesktopPortalFileDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent)
{
- Q_D(QFlatpakFileDialog);
- Q_UNUSED(windowFlags);
+ Q_D(QXdgDesktopPortalFileDialog);
initializeDialog();
d->modal = windowModality != Qt::NonModal;
d->winId = parent ? parent->winId() : 0;
+ if (d->nativeFileDialog && (options()->fileMode() == QFileDialogOptions::Directory || options()->fileMode() == QFileDialogOptions::DirectoryOnly))
+ return d->nativeFileDialog->show(windowFlags, windowModality, parent);
+
openPortal();
return true;
}
-void QFlatpakFileDialog::gotResponse(uint response, const QVariantMap &results)
+void QXdgDesktopPortalFileDialog::gotResponse(uint response, const QVariantMap &results)
{
- Q_D(QFlatpakFileDialog);
+ Q_D(QXdgDesktopPortalFileDialog);
if (!response) {
if (results.contains(QLatin1String("uris")))
diff --git a/src/plugins/platformthemes/flatpak/qflatpakfiledialog_p.h b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog_p.h
index f3e195faa0..c1f1a2c005 100644
--- a/src/plugins/platformthemes/flatpak/qflatpakfiledialog_p.h
+++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 Red Hat, Inc
+** Copyright (C) 2017-2018 Red Hat, Inc
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -36,20 +36,20 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#ifndef QFLATPAKFILEDIALOG_P_H
-#define QFLATPAKFILEDIALOG_P_H
+#ifndef QXDGDESKTOPPORTALFILEDIALOG_P_H
+#define QXDGDESKTOPPORTALFILEDIALOG_P_H
#include <qpa/qplatformdialoghelper.h>
#include <QVector>
QT_BEGIN_NAMESPACE
-class QFlatpakFileDialogPrivate;
+class QXdgDesktopPortalFileDialogPrivate;
-class QFlatpakFileDialog : public QPlatformFileDialogHelper
+class QXdgDesktopPortalFileDialog : public QPlatformFileDialogHelper
{
Q_OBJECT
- Q_DECLARE_PRIVATE(QFlatpakFileDialog)
+ Q_DECLARE_PRIVATE(QXdgDesktopPortalFileDialog)
public:
enum ConditionType : uint {
GlobalPattern = 0,
@@ -69,8 +69,8 @@ public:
};
typedef QVector<Filter> FilterList;
- QFlatpakFileDialog();
- ~QFlatpakFileDialog();
+ QXdgDesktopPortalFileDialog(QPlatformFileDialogHelper *nativeFileDialog = nullptr);
+ ~QXdgDesktopPortalFileDialog();
bool defaultNameFilterDisables() const override;
QUrl directory() const override;
@@ -92,15 +92,15 @@ private:
void initializeDialog();
void openPortal();
- QScopedPointer<QFlatpakFileDialogPrivate> d_ptr;
+ QScopedPointer<QXdgDesktopPortalFileDialogPrivate> d_ptr;
};
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QFlatpakFileDialog::FilterCondition);
-Q_DECLARE_METATYPE(QFlatpakFileDialog::FilterConditionList);
-Q_DECLARE_METATYPE(QFlatpakFileDialog::Filter);
-Q_DECLARE_METATYPE(QFlatpakFileDialog::FilterList);
+Q_DECLARE_METATYPE(QXdgDesktopPortalFileDialog::FilterCondition);
+Q_DECLARE_METATYPE(QXdgDesktopPortalFileDialog::FilterConditionList);
+Q_DECLARE_METATYPE(QXdgDesktopPortalFileDialog::Filter);
+Q_DECLARE_METATYPE(QXdgDesktopPortalFileDialog::FilterList);
-#endif // QFLATPAKFILEDIALOG_P_H
+#endif // QXDGDESKTOPPORTALFILEDIALOG_P_H
diff --git a/src/plugins/platformthemes/flatpak/qflatpaktheme.cpp b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp
index 6c5e1389cf..f07ca3f098 100644
--- a/src/plugins/platformthemes/flatpak/qflatpaktheme.cpp
+++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#include "qflatpaktheme.h"
-#include "qflatpakfiledialog_p.h"
+#include "qxdgdesktopportaltheme.h"
+#include "qxdgdesktopportalfiledialog_p.h"
#include <private/qguiapplication_p.h>
#include <qpa/qplatformtheme_p.h>
@@ -47,14 +47,14 @@
QT_BEGIN_NAMESPACE
-class QFlatpakThemePrivate : public QPlatformThemePrivate
+class QXdgDesktopPortalThemePrivate : public QPlatformThemePrivate
{
public:
- QFlatpakThemePrivate()
+ QXdgDesktopPortalThemePrivate()
: QPlatformThemePrivate()
{ }
- ~QFlatpakThemePrivate()
+ ~QXdgDesktopPortalThemePrivate()
{
delete baseTheme;
}
@@ -62,10 +62,10 @@ public:
QPlatformTheme *baseTheme;
};
-QFlatpakTheme::QFlatpakTheme()
- : d_ptr(new QFlatpakThemePrivate)
+QXdgDesktopPortalTheme::QXdgDesktopPortalTheme()
+ : d_ptr(new QXdgDesktopPortalThemePrivate)
{
- Q_D(QFlatpakTheme);
+ Q_D(QXdgDesktopPortalTheme);
QStringList themeNames;
themeNames += QGuiApplicationPrivate::platform_integration->themeNames();
@@ -92,33 +92,33 @@ QFlatpakTheme::QFlatpakTheme()
d->baseTheme = new QPlatformTheme;
}
-QPlatformMenuItem* QFlatpakTheme::createPlatformMenuItem() const
+QPlatformMenuItem* QXdgDesktopPortalTheme::createPlatformMenuItem() const
{
- Q_D(const QFlatpakTheme);
+ Q_D(const QXdgDesktopPortalTheme);
return d->baseTheme->createPlatformMenuItem();
}
-QPlatformMenu* QFlatpakTheme::createPlatformMenu() const
+QPlatformMenu* QXdgDesktopPortalTheme::createPlatformMenu() const
{
- Q_D(const QFlatpakTheme);
+ Q_D(const QXdgDesktopPortalTheme);
return d->baseTheme->createPlatformMenu();
}
-QPlatformMenuBar* QFlatpakTheme::createPlatformMenuBar() const
+QPlatformMenuBar* QXdgDesktopPortalTheme::createPlatformMenuBar() const
{
- Q_D(const QFlatpakTheme);
+ Q_D(const QXdgDesktopPortalTheme);
return d->baseTheme->createPlatformMenuBar();
}
-void QFlatpakTheme::showPlatformMenuBar()
+void QXdgDesktopPortalTheme::showPlatformMenuBar()
{
- Q_D(const QFlatpakTheme);
+ Q_D(const QXdgDesktopPortalTheme);
return d->baseTheme->showPlatformMenuBar();
}
-bool QFlatpakTheme::usePlatformNativeDialog(DialogType type) const
+bool QXdgDesktopPortalTheme::usePlatformNativeDialog(DialogType type) const
{
- Q_D(const QFlatpakTheme);
+ Q_D(const QXdgDesktopPortalTheme);
if (type == FileDialog)
return true;
@@ -126,70 +126,74 @@ bool QFlatpakTheme::usePlatformNativeDialog(DialogType type) const
return d->baseTheme->usePlatformNativeDialog(type);
}
-QPlatformDialogHelper* QFlatpakTheme::createPlatformDialogHelper(DialogType type) const
+QPlatformDialogHelper* QXdgDesktopPortalTheme::createPlatformDialogHelper(DialogType type) const
{
- Q_D(const QFlatpakTheme);
+ Q_D(const QXdgDesktopPortalTheme);
- if (type == FileDialog)
- return new QFlatpakFileDialog;
+ if (type == FileDialog) {
+ if (d->baseTheme->usePlatformNativeDialog(type))
+ return new QXdgDesktopPortalFileDialog(static_cast<QPlatformFileDialogHelper*>(d->baseTheme->createPlatformDialogHelper(type)));
+
+ return new QXdgDesktopPortalFileDialog;
+ }
return d->baseTheme->createPlatformDialogHelper(type);
}
#ifndef QT_NO_SYSTEMTRAYICON
-QPlatformSystemTrayIcon* QFlatpakTheme::createPlatformSystemTrayIcon() const
+QPlatformSystemTrayIcon* QXdgDesktopPortalTheme::createPlatformSystemTrayIcon() const
{
- Q_D(const QFlatpakTheme);
+ Q_D(const QXdgDesktopPortalTheme);
return d->baseTheme->createPlatformSystemTrayIcon();
}
#endif
-const QPalette *QFlatpakTheme::palette(Palette type) const
+const QPalette *QXdgDesktopPortalTheme::palette(Palette type) const
{
- Q_D(const QFlatpakTheme);
+ Q_D(const QXdgDesktopPortalTheme);
return d->baseTheme->palette(type);
}
-const QFont* QFlatpakTheme::font(Font type) const
+const QFont* QXdgDesktopPortalTheme::font(Font type) const
{
- Q_D(const QFlatpakTheme);
+ Q_D(const QXdgDesktopPortalTheme);
return d->baseTheme->font(type);
}
-QVariant QFlatpakTheme::themeHint(ThemeHint hint) const
+QVariant QXdgDesktopPortalTheme::themeHint(ThemeHint hint) const
{
- Q_D(const QFlatpakTheme);
+ Q_D(const QXdgDesktopPortalTheme);
return d->baseTheme->themeHint(hint);
}
-QPixmap QFlatpakTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const
+QPixmap QXdgDesktopPortalTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const
{
- Q_D(const QFlatpakTheme);
+ Q_D(const QXdgDesktopPortalTheme);
return d->baseTheme->standardPixmap(sp, size);
}
-QIcon QFlatpakTheme::fileIcon(const QFileInfo &fileInfo,
+QIcon QXdgDesktopPortalTheme::fileIcon(const QFileInfo &fileInfo,
QPlatformTheme::IconOptions iconOptions) const
{
- Q_D(const QFlatpakTheme);
+ Q_D(const QXdgDesktopPortalTheme);
return d->baseTheme->fileIcon(fileInfo, iconOptions);
}
-QIconEngine * QFlatpakTheme::createIconEngine(const QString &iconName) const
+QIconEngine * QXdgDesktopPortalTheme::createIconEngine(const QString &iconName) const
{
- Q_D(const QFlatpakTheme);
+ Q_D(const QXdgDesktopPortalTheme);
return d->baseTheme->createIconEngine(iconName);
}
-QList<QKeySequence> QFlatpakTheme::keyBindings(QKeySequence::StandardKey key) const
+QList<QKeySequence> QXdgDesktopPortalTheme::keyBindings(QKeySequence::StandardKey key) const
{
- Q_D(const QFlatpakTheme);
+ Q_D(const QXdgDesktopPortalTheme);
return d->baseTheme->keyBindings(key);
}
-QString QFlatpakTheme::standardButtonText(int button) const
+QString QXdgDesktopPortalTheme::standardButtonText(int button) const
{
- Q_D(const QFlatpakTheme);
+ Q_D(const QXdgDesktopPortalTheme);
return d->baseTheme->standardButtonText(button);
}
diff --git a/src/plugins/platformthemes/flatpak/qflatpaktheme.h b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h
index 87f79a2395..b72e676419 100644
--- a/src/plugins/platformthemes/flatpak/qflatpaktheme.h
+++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h
@@ -37,20 +37,20 @@
**
****************************************************************************/
-#ifndef QFLATPAKTHEME_H
-#define QFLATPAKTHEME_H
+#ifndef QXDGDESKTOPPORTALTHEME_H
+#define QXDGDESKTOPPORTALTHEME_H
#include <qpa/qplatformtheme.h>
QT_BEGIN_NAMESPACE
-class QFlatpakThemePrivate;
+class QXdgDesktopPortalThemePrivate;
-class QFlatpakTheme : public QPlatformTheme
+class QXdgDesktopPortalTheme : public QPlatformTheme
{
- Q_DECLARE_PRIVATE(QFlatpakTheme)
+ Q_DECLARE_PRIVATE(QXdgDesktopPortalTheme)
public:
- QFlatpakTheme();
+ QXdgDesktopPortalTheme();
QPlatformMenuItem *createPlatformMenuItem() const override;
QPlatformMenu *createPlatformMenu() const override;
@@ -81,10 +81,10 @@ public:
QString standardButtonText(int button) const override;
private:
- QScopedPointer<QFlatpakThemePrivate> d_ptr;
- Q_DISABLE_COPY(QFlatpakTheme)
+ QScopedPointer<QXdgDesktopPortalThemePrivate> d_ptr;
+ Q_DISABLE_COPY(QXdgDesktopPortalTheme)
};
QT_END_NAMESPACE
-#endif // QFLATPAKTHEME_H
+#endif // QXDGDESKTOPPORTALTHEME_H
diff --git a/src/plugins/platformthemes/xdgdesktopportal/xdgdesktopportal.json b/src/plugins/platformthemes/xdgdesktopportal/xdgdesktopportal.json
new file mode 100644
index 0000000000..c69062d9a1
--- /dev/null
+++ b/src/plugins/platformthemes/xdgdesktopportal/xdgdesktopportal.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "xdgdesktopportal", "flatpak", "snap" ]
+}
diff --git a/src/plugins/platformthemes/xdgdesktopportal/xdgdesktopportal.pro b/src/plugins/platformthemes/xdgdesktopportal/xdgdesktopportal.pro
new file mode 100644
index 0000000000..0a71484cf9
--- /dev/null
+++ b/src/plugins/platformthemes/xdgdesktopportal/xdgdesktopportal.pro
@@ -0,0 +1,17 @@
+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/printsupport/cups/qcupsprintengine.cpp b/src/plugins/printsupport/cups/qcupsprintengine.cpp
index 6c29a99705..c9683eb99d 100644
--- a/src/plugins/printsupport/cups/qcupsprintengine.cpp
+++ b/src/plugins/printsupport/cups/qcupsprintengine.cpp
@@ -104,7 +104,11 @@ void QCupsPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &v
break;
case PPK_QPageLayout: {
QPageLayout pageLayout = value.value<QPageLayout>();
- if (pageLayout.isValid() && (d->m_printDevice.isValidPageLayout(pageLayout, d->resolution) || d->m_printDevice.supportsCustomPageSizes())) {
+ if (pageLayout.isValid() && (d->m_printDevice.isValidPageLayout(pageLayout, d->resolution)
+ || d->m_printDevice.supportsCustomPageSizes()
+ || d->m_printDevice.supportedPageSizes().isEmpty())) {
+ // supportedPageSizes().isEmpty() because QPageSetupWidget::initPageSizes says
+ // "If no available printer page sizes, populate with all page sizes"
d->m_pageLayout = pageLayout;
d->setPageSize(pageLayout.pageSize());
}
@@ -132,6 +136,9 @@ QVariant QCupsPrintEngine::property(PrintEnginePropertyKey key) const
case PPK_CupsOptions:
ret = d->cupsOptions;
break;
+ case PPK_Duplex:
+ ret = d->duplex;
+ break;
default:
ret = QPdfPrintEngine::property(key);
break;
@@ -140,7 +147,9 @@ QVariant QCupsPrintEngine::property(PrintEnginePropertyKey key) const
}
-QCupsPrintEnginePrivate::QCupsPrintEnginePrivate(QPrinter::PrinterMode m) : QPdfPrintEnginePrivate(m)
+QCupsPrintEnginePrivate::QCupsPrintEnginePrivate(QPrinter::PrinterMode m)
+ : QPdfPrintEnginePrivate(m)
+ , duplex(QPrint::DuplexNone)
{
}
diff --git a/src/plugins/printsupport/cups/qcupsprintengine_p.h b/src/plugins/printsupport/cups/qcupsprintengine_p.h
index d5363bb8cc..2a1a83b9d7 100644
--- a/src/plugins/printsupport/cups/qcupsprintengine_p.h
+++ b/src/plugins/printsupport/cups/qcupsprintengine_p.h
@@ -99,6 +99,7 @@ private:
QPrintDevice m_printDevice;
QStringList cupsOptions;
QString cupsTempFile;
+ QPrint::DuplexMode duplex;
};
QT_END_NAMESPACE
diff --git a/src/plugins/printsupport/cups/qcupsprintersupport.cpp b/src/plugins/printsupport/cups/qcupsprintersupport.cpp
index a9c992a2e1..19e1df31f6 100644
--- a/src/plugins/printsupport/cups/qcupsprintersupport.cpp
+++ b/src/plugins/printsupport/cups/qcupsprintersupport.cpp
@@ -47,6 +47,15 @@
#include <QtPrintSupport/QPrinterInfo>
+#if QT_CONFIG(dialogbuttonbox)
+#include <QGuiApplication>
+#include <QDialog>
+#include <QDialogButtonBox>
+#include <QFormLayout>
+#include <QLabel>
+#include <QLineEdit>
+#endif // QT_CONFIG(dialogbuttonbox)
+
#include <cups/ppd.h>
#ifndef QT_LINUXBASE // LSB merges everything into cups.h
# include <cups/language.h>
@@ -54,9 +63,78 @@
QT_BEGIN_NAMESPACE
+#if QT_CONFIG(dialogbuttonbox)
+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
+ // the last password so we don't leak memory if called multiple times.
+ static QByteArray password;
+
+ // prompt is always "Password for %s on %s? " but we can't use it since we allow the user to change the user.
+ // That is fine because cups always calls cupsUser after calling this callback.
+ // We build our own prompt with the hostname (if not localhost) and the resource that is being used
+
+ char hostname[HTTP_MAX_HOST];
+ httpGetHostname(http, hostname, HTTP_MAX_HOST);
+
+ const QString username = QString::fromLocal8Bit(cupsUser());
+
+ QDialog dialog;
+ dialog.setWindowTitle(QCoreApplication::translate("QCupsPrinterSupport", "Authentication Needed"));
+
+ QFormLayout *layout = new QFormLayout(&dialog);
+ layout->setSizeConstraint(QLayout::SetFixedSize);
+
+ QLineEdit *usernameLE = new QLineEdit();
+ usernameLE->setText(username);
+
+ QLineEdit *passwordLE = new QLineEdit();
+ passwordLE->setEchoMode(QLineEdit::Password);
+
+ QString resourceString = QString::fromLocal8Bit(resource);
+ if (resourceString.startsWith(QStringLiteral("/printers/")))
+ resourceString = resourceString.mid(QStringLiteral("/printers/").length());
+
+ QLabel *label = new QLabel();
+ if (hostname == QStringLiteral("localhost")) {
+ label->setText(QCoreApplication::translate("QCupsPrinterSupport", "Authentication needed to use %1.").arg(resourceString));
+ } else {
+ label->setText(QCoreApplication::translate("QCupsPrinterSupport", "Authentication needed to use %1 on %2.").arg(resourceString).arg(hostname));
+ label->setWordWrap(true);
+ }
+
+ layout->addRow(label);
+ layout->addRow(new QLabel(QCoreApplication::translate("QCupsPrinterSupport", "Username:")), usernameLE);
+ layout->addRow(new QLabel(QCoreApplication::translate("QCupsPrinterSupport", "Password:")), passwordLE);
+
+ QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ layout->addRow(buttonBox);
+
+ QObject::connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
+ QObject::connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
+
+ passwordLE->setFocus();
+
+ if (dialog.exec() != QDialog::Accepted)
+ return nullptr;
+
+ if (usernameLE->text() != username)
+ cupsSetUser(usernameLE->text().toLocal8Bit().constData());
+
+ password = passwordLE->text().toLocal8Bit();
+
+ return password.constData();
+}
+#endif // QT_CONFIG(dialogbuttonbox)
+
QCupsPrinterSupport::QCupsPrinterSupport()
: QPlatformPrinterSupport()
{
+#if QT_CONFIG(dialogbuttonbox)
+ // Only show password dialog if GUI application
+ if (qobject_cast<QGuiApplication*>(QCoreApplication::instance()))
+ cupsSetPasswordCB2(getPasswordCB, nullptr /* user_data */ );
+#endif // QT_CONFIG(dialogbuttonbox)
}
QCupsPrinterSupport::~QCupsPrinterSupport()
diff --git a/src/plugins/printsupport/cups/qppdprintdevice.cpp b/src/plugins/printsupport/cups/qppdprintdevice.cpp
index f0a8105d21..51b93a0016 100644
--- a/src/plugins/printsupport/cups/qppdprintdevice.cpp
+++ b/src/plugins/printsupport/cups/qppdprintdevice.cpp
@@ -50,13 +50,6 @@
QT_BEGIN_NAMESPACE
-QPpdPrintDevice::QPpdPrintDevice()
- : QPlatformPrintDevice(),
- m_cupsDest(0),
- m_ppd(0)
-{
-}
-
QPpdPrintDevice::QPpdPrintDevice(const QString &id)
: QPlatformPrintDevice(id),
m_cupsDest(0),
@@ -69,9 +62,26 @@ QPpdPrintDevice::QPpdPrintDevice(const QString &id)
m_cupsName = parts.at(0).toUtf8();
if (parts.size() > 1)
m_cupsInstance = parts.at(1).toUtf8();
- loadPrinter();
- if (m_cupsDest && m_ppd) {
+ // Get the print instance and PPD file
+ m_cupsDest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, m_cupsName, m_cupsInstance.isNull() ? nullptr : m_cupsInstance.constData());
+ if (m_cupsDest) {
+ const char *ppdFile = cupsGetPPD(m_cupsName);
+ if (ppdFile) {
+ m_ppd = ppdOpenFile(ppdFile);
+ unlink(ppdFile);
+ }
+ if (m_ppd) {
+ ppdMarkDefaults(m_ppd);
+ cupsMarkOptions(m_ppd, m_cupsDest->num_options, m_cupsDest->options);
+ ppdLocalize(m_ppd);
+
+ 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]);
+ }
+
m_name = printerOption("printer-info");
m_location = printerOption("printer-location");
m_makeAndModel = printerOption("printer-make-and-model");
@@ -87,10 +97,6 @@ QPpdPrintDevice::QPpdPrintDevice(const QString &id)
// Cups ppd_file_t variable_sizes custom_min custom_max
// PPD MaxMediaWidth MaxMediaHeight
m_supportsCustomPageSizes = type & CUPS_PRINTER_VARIABLE;
- 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]);
}
}
}
@@ -107,7 +113,7 @@ QPpdPrintDevice::~QPpdPrintDevice()
bool QPpdPrintDevice::isValid() const
{
- return m_cupsDest && m_ppd;
+ return m_cupsDest;
}
bool QPpdPrintDevice::isDefault() const
@@ -152,8 +158,8 @@ void QPpdPrintDevice::loadPageSizes() const
}
}
}
- m_havePageSizes = true;
}
+ m_havePageSizes = true;
}
QPageSize QPpdPrintDevice::defaultPageSize() const
@@ -359,14 +365,18 @@ void QPpdPrintDevice::loadDuplexModes() const
ppd_option_t *duplexModes = ppdFindOption(m_ppd, "Duplex");
if (duplexModes) {
m_duplexModes.reserve(duplexModes->num_choices);
- for (int i = 0; i < duplexModes->num_choices; ++i)
- m_duplexModes.append(QPrintUtils::ppdChoiceToDuplexMode(duplexModes->choices[i].choice));
+ for (int i = 0; i < duplexModes->num_choices; ++i) {
+ if (ppdInstallableConflict(m_ppd, duplexModes->keyword, duplexModes->choices[i].choice) == 0) {
+ 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)
+ if (duplexModes && (ppdInstallableConflict(m_ppd, duplexModes->keyword, duplexModes->choices[0].choice) == 0)) {
m_duplexModes.append(QPrintUtils::ppdChoiceToDuplexMode(duplexModes->choices[0].choice));
+ }
}
}
// If still no result, or not added in PPD, then add None
@@ -417,7 +427,7 @@ QPrint::ColorMode QPpdPrintDevice::defaultColorMode() const
ppd_option_t *colorModel = ppdFindOption(m_ppd, "DefaultColorModel");
if (!colorModel)
colorModel = ppdFindOption(m_ppd, "ColorModel");
- if (!colorModel || (colorModel && !qstrcmp(colorModel->defchoice, "Gray")))
+ if (!colorModel || qstrcmp(colorModel->defchoice, "Gray") != 0)
return QPrint::Color;
}
return QPrint::GrayScale;
@@ -481,38 +491,6 @@ void QPpdPrintDevice::loadMimeTypes() const
}
#endif
-void QPpdPrintDevice::loadPrinter()
-{
- // Just to be safe, check if existing printer needs closing
- if (m_ppd) {
- ppdClose(m_ppd);
- m_ppd = 0;
- }
- if (m_cupsDest) {
- cupsFreeDests(1, m_cupsDest);
- m_cupsDest = 0;
- }
-
- // Get the print instance and PPD file
- m_cupsDest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, m_cupsName, m_cupsInstance.isNull() ? nullptr : m_cupsInstance.constData());
- if (m_cupsDest) {
- const char *ppdFile = cupsGetPPD(m_cupsName);
- if (ppdFile) {
- m_ppd = ppdOpenFile(ppdFile);
- unlink(ppdFile);
- }
- if (m_ppd) {
- ppdMarkDefaults(m_ppd);
- cupsMarkOptions(m_ppd, m_cupsDest->num_options, m_cupsDest->options);
- ppdLocalize(m_ppd);
- } else {
- cupsFreeDests(1, m_cupsDest);
- m_cupsDest = 0;
- m_ppd = 0;
- }
- }
-}
-
QString QPpdPrintDevice::printerOption(const QString &key) const
{
return cupsGetOption(key.toUtf8(), m_cupsDest->num_options, m_cupsDest->options);
diff --git a/src/plugins/printsupport/cups/qppdprintdevice.h b/src/plugins/printsupport/cups/qppdprintdevice.h
index 596f9aa3f5..3baf8b771b 100644
--- a/src/plugins/printsupport/cups/qppdprintdevice.h
+++ b/src/plugins/printsupport/cups/qppdprintdevice.h
@@ -65,7 +65,6 @@ QT_BEGIN_NAMESPACE
class QPpdPrintDevice : public QPlatformPrintDevice
{
public:
- QPpdPrintDevice();
explicit QPpdPrintDevice(const QString &id);
virtual ~QPpdPrintDevice();
@@ -105,7 +104,6 @@ protected:
#endif
private:
- void loadPrinter();
QString printerOption(const QString &key) const;
cups_ptype_e printerTypeFlags() const;
diff --git a/src/plugins/printsupport/windows/qwindowsprintdevice.cpp b/src/plugins/printsupport/windows/qwindowsprintdevice.cpp
index b1589c0738..f01e93d611 100644
--- a/src/plugins/printsupport/windows/qwindowsprintdevice.cpp
+++ b/src/plugins/printsupport/windows/qwindowsprintdevice.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2014 John Layt <jlayt@kde.org>
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -49,6 +49,8 @@
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);
@@ -110,7 +112,7 @@ QWindowsPrintDevice::QWindowsPrintDevice(const QString &id)
{
// 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((LPWSTR)m_id.utf16(), &m_hPrinter, NULL)) {
+ 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]);
@@ -121,15 +123,39 @@ QWindowsPrintDevice::QWindowsPrintDevice(const QString &id)
m_makeAndModel = QString::fromWCharArray(info->pDriverName); // TODO Check is not available elsewhere
m_isRemote = info->Attributes & PRINTER_ATTRIBUTE_NETWORK;
}
- m_supportsMultipleCopies = (DeviceCapabilities((LPWSTR)m_id.utf16(), NULL, DC_COPIES, NULL, NULL) > 1);
- m_supportsCollateCopies = DeviceCapabilities((LPWSTR)m_id.utf16(), NULL, DC_COLLATE, NULL, NULL);
- // Min/Max custom size is in tenths of a millimeter
- const qreal multiplier = qt_pointMultiplier(QPageLayout::Millimeter);
- DWORD min = DeviceCapabilities((LPWSTR)m_id.utf16(), NULL, DC_MINEXTENT, NULL, NULL);
- m_minimumPhysicalPageSize = QSize((LOWORD(min) / 10.0) * multiplier, (HIWORD(min) / 10.0) * multiplier);
- DWORD max = DeviceCapabilities((LPWSTR)m_id.utf16(), 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);
+ 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;
+ }
}
}
}
@@ -184,7 +210,7 @@ void QWindowsPrintDevice::loadPageSizes() const
&& 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*sizeof(POINT)]);
+ QScopedArrayPointer<POINT> winSizes(new POINT[paperCount]);
QScopedArrayPointer<wchar_t> papers(new wchar_t[paperCount]);
// Get the details and match the default paper size
@@ -205,6 +231,9 @@ void QWindowsPrintDevice::loadPageSizes() const
}
m_havePageSizes = true;
+ QWindowsPrinterInfo *info = windowsDeviceLookup()->data();
+ info[m_infoIndex].m_havePageSizes = true;
+ info[m_infoIndex].m_pageSizes = m_pageSizes;
}
QPageSize QWindowsPrintDevice::defaultPageSize() const
@@ -297,6 +326,9 @@ void QWindowsPrintDevice::loadResolutions() const
}
}
m_haveResolutions = true;
+ QWindowsPrinterInfo *info = windowsDeviceLookup()->data();
+ info[m_infoIndex].m_haveResolutions = true;
+ info[m_infoIndex].m_resolutions = m_resolutions;
}
int QWindowsPrintDevice::defaultResolution() const
@@ -319,16 +351,19 @@ int QWindowsPrintDevice::defaultResolution() const
void QWindowsPrintDevice::loadInputSlots() const
{
- DWORD binCount = DeviceCapabilities((LPWSTR)m_id.utf16(), NULL, DC_BINS, NULL, NULL);
+ const auto printerId = wcharId();
+ DWORD binCount = DeviceCapabilities(printerId, nullptr, DC_BINS, nullptr, nullptr);
if (int(binCount) > 0
- && DeviceCapabilities((LPWSTR)m_id.utf16(), NULL, DC_BINNAMES, NULL, NULL) == binCount) {
+ && DeviceCapabilities(printerId, nullptr, DC_BINNAMES, nullptr, nullptr) == binCount) {
- QScopedArrayPointer<WORD> bins(new WORD[binCount*sizeof(WORD)]);
+ 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((LPWSTR)m_id.utf16(), NULL, DC_BINS, (LPWSTR)bins.data(), NULL) == binCount
- && DeviceCapabilities((LPWSTR)m_id.utf16(), NULL, DC_BINNAMES, binNames.data(), NULL) == binCount) {
+ 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);
@@ -340,6 +375,9 @@ void QWindowsPrintDevice::loadInputSlots() const
}
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
@@ -367,12 +405,15 @@ 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((LPWSTR)m_id.utf16(), NULL, DC_DUPLEX, NULL, NULL);
+ 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);
@@ -380,6 +421,9 @@ void QWindowsPrintDevice::loadDuplexModes() const
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
@@ -403,10 +447,13 @@ QPrint::DuplexMode QWindowsPrintDevice::defaultDuplexMode() const
void QWindowsPrintDevice::loadColorModes() const
{
m_colorModes.append(QPrint::GrayScale);
- DWORD color = DeviceCapabilities((LPWSTR)m_id.utf16(), NULL, DC_COLORDEVICE, NULL, NULL);
+ 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
@@ -457,4 +504,68 @@ QString QWindowsPrintDevice::defaultPrintDeviceId()
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
index 6b51ee8785..166f0f65b2 100644
--- a/src/plugins/printsupport/windows/qwindowsprintdevice.h
+++ b/src/plugins/printsupport/windows/qwindowsprintdevice.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** 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.
@@ -57,6 +58,43 @@
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:
@@ -85,6 +123,12 @@ public:
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;
@@ -92,9 +136,16 @@ protected:
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
diff --git a/src/plugins/printsupport/windows/qwindowsprintersupport.h b/src/plugins/printsupport/windows/qwindowsprintersupport.h
index c42e7aa551..4267701145 100644
--- a/src/plugins/printsupport/windows/qwindowsprintersupport.h
+++ b/src/plugins/printsupport/windows/qwindowsprintersupport.h
@@ -46,9 +46,10 @@ QT_BEGIN_NAMESPACE
class QWindowsPrinterSupport : public QPlatformPrinterSupport
{
+ Q_DISABLE_COPY(QWindowsPrinterSupport)
public:
QWindowsPrinterSupport();
- ~QWindowsPrinterSupport();
+ ~QWindowsPrinterSupport() override;
QPrintEngine *createNativePrintEngine(QPrinter::PrinterMode printerMode, const QString &deviceId = QString()) override;
QPaintEngine *createPaintEngine(QPrintEngine *printEngine, QPrinter::PrinterMode) override;
diff --git a/src/plugins/sqldrivers/configure.json b/src/plugins/sqldrivers/configure.json
index 234f880579..4802d3b04d 100644
--- a/src/plugins/sqldrivers/configure.json
+++ b/src/plugins/sqldrivers/configure.json
@@ -229,7 +229,7 @@ Oracle driver, as the current build will most likely fail."
"summary": [
{
- "section": "Qt Sql",
+ "section": "Qt Sql Drivers",
"entries": [
"sql-db2", "sql-ibase", "sql-mysql", "sql-oci", "sql-odbc", "sql-psql",
"sql-sqlite2", "sql-sqlite", "system-sqlite", "sql-tds"
diff --git a/src/plugins/sqldrivers/configure.pri b/src/plugins/sqldrivers/configure.pri
index b69b51b679..24954e9514 100644
--- a/src/plugins/sqldrivers/configure.pri
+++ b/src/plugins/sqldrivers/configure.pri
@@ -19,9 +19,9 @@ defineTest(qtConfLibrary_psqlConfig) {
libs =
!isEmpty(libdir): libs += "-L$$libdir"
libs += "-lpq"
- $${1}.libs = "$$val_escape(libs)"
+ $${1}.libs = $$libs
includedir -= $$QMAKE_DEFAULT_INCDIRS
- $${1}.includedir = "$$val_escape(includedir)"
+ $${1}.includedir = $$includedir
export($${1}.libs)
export($${1}.includedir)
return(true)
@@ -34,7 +34,7 @@ defineTest(qtConfLibrary_psqlEnv) {
# Respect PSQL_LIBS if set
PSQL_LIBS = $$getenv(PSQL_LIBS)
!isEmpty(PSQL_LIBS) {
- $${1}.libs = $$PSQL_LIBS
+ eval($${1}.libs = $$PSQL_LIBS)
export($${1}.libs)
} else {
!qtConfLibrary_inline($$1, $$2): \
@@ -69,14 +69,14 @@ defineTest(qtConfLibrary_mysqlConfig) {
}
libs = $$cleanlibs
}
- $${1}.libs = "$$val_escape(libs)"
+ $${1}.libs = $$libs
eval(rawincludedir = $$includedir)
rawincludedir ~= s/^-I//g
includedir =
for (id, rawincludedir): \
includedir += $$clean_path($$id)
includedir -= $$QMAKE_DEFAULT_INCDIRS
- $${1}.includedir = "$$val_escape(includedir)"
+ $${1}.includedir = $$includedir
export($${1}.libs)
export($${1}.includedir)
return(true)
@@ -90,9 +90,9 @@ defineTest(qtConfLibrary_sybaseEnv) {
sybase = $$getenv(SYBASE)
!isEmpty(sybase): \
libs += "-L$${sybase}/lib"
- libs += $$getenv(SYBASE_LIBS)
+ eval(libs += $$getenv(SYBASE_LIBS))
!isEmpty(libs) {
- $${1}.libs = "$$val_escape(libs)"
+ $${1}.libs = $$libs
export($${1}.libs)
}
return(true)
diff --git a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp
index 5a100b8075..58da2a3c51 100644
--- a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp
+++ b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp
@@ -74,6 +74,10 @@ Q_DECLARE_METATYPE(MYSQL_STMT*)
# define Q_CLIENT_MULTI_STATEMENTS 0
#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));
+
QT_BEGIN_NAMESPACE
class QMYSQLDriverPrivate : public QSqlDriverPrivate
@@ -305,7 +309,9 @@ static QVariant::Type qDecodeMYSQLType(int mysqltype, uint flags)
type = QVariant::Date;
break;
case FIELD_TYPE_TIME :
- type = QVariant::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 = QVariant::String;
break;
case FIELD_TYPE_DATETIME :
case FIELD_TYPE_TIMESTAMP :
@@ -1448,7 +1454,7 @@ bool QMYSQLDriver::open(const QString& db,
d->preparedQuerysEnabled = false;
#endif
-#ifndef QT_NO_THREAD
+#if QT_CONFIG(thread)
mysql_thread_init();
#endif
@@ -1462,7 +1468,7 @@ void QMYSQLDriver::close()
{
Q_D(QMYSQLDriver);
if (isOpen()) {
-#ifndef QT_NO_THREAD
+#if QT_CONFIG(thread)
mysql_thread_end();
#endif
mysql_close(d->mysql);
diff --git a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
index 547eb2043d..1fbbcd0ef1 100644
--- a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
+++ b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
@@ -72,6 +72,7 @@ inline static QString fromSQLTCHAR(const QVarLengthArray<SQLTCHAR>& input, int s
{
QString result;
+ // Remove any trailing \0 as some drivers misguidedly append one
int realsize = qMin(size, input.size());
if(realsize > 0 && input[realsize-1] == 0)
realsize--;
@@ -458,7 +459,6 @@ static QString qGetStringData(SQLHANDLE hStmt, int column, int colSize, bool uni
// 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
- // colSize-1: remove 0 termination when there is more data to fetch
int rSize = (r == SQL_SUCCESS_WITH_INFO) ? colSize : int(lengthIndicator / sizeof(SQLTCHAR));
fieldVal += fromSQLTCHAR(buf, rSize);
if (lengthIndicator < SQLLEN(colSize*sizeof(SQLTCHAR))) {
@@ -499,9 +499,12 @@ static QString qGetStringData(SQLHANDLE hStmt, int column, int colSize, bool uni
// 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
- // colSize-1: remove 0 termination when there is more data to fetch
int rSize = (r == SQL_SUCCESS_WITH_INFO) ? colSize : lengthIndicator;
- fieldVal += QString::fromUtf8((const char *)buf.constData(), rSize);
+ // 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;
@@ -1304,7 +1307,7 @@ QVariant QODBCResult::data(int field)
bool QODBCResult::isNull(int field)
{
Q_D(const QODBCResult);
- if (field < 0 || field > d->fieldCache.size())
+ if (field < 0 || field >= d->fieldCache.size())
return true;
if (field <= d->fieldCacheIdx) {
// since there is no good way to find out whether the value is NULL
diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp
index fe9e098c12..bf0493b0c3 100644
--- a/src/plugins/sqldrivers/psql/qsql_psql.cpp
+++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp
@@ -1465,8 +1465,11 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const
precision = -1;
}
QString defVal = query.value(5).toString();
- if (!defVal.isEmpty() && defVal.at(0) == QLatin1Char('\''))
- defVal = defVal.mid(1, defVal.length() - 2);
+ if (!defVal.isEmpty() && defVal.at(0) == QLatin1Char('\'')) {
+ const int end = defVal.lastIndexOf(QLatin1Char('\''));
+ if (end > 0)
+ defVal = defVal.mid(1, end - 1);
+ }
QSqlField f(query.value(0).toString(), qDecodePSQLType(query.value(1).toInt()), tablename);
f.setRequired(query.value(2).toBool());
f.setLength(len);
diff --git a/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp b/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp
index 491d903137..f1a003ddcd 100644
--- a/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp
+++ b/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp
@@ -55,9 +55,6 @@
#include <qcache.h>
#include <qregularexpression.h>
#endif
-#if QT_CONFIG(timezone)
-#include <QTimeZone>
-#endif
#include <QScopedValueRollback>
#if defined Q_OS_WIN
@@ -421,34 +418,6 @@ bool QSQLiteResult::prepare(const QString &query)
return true;
}
-static QString secondsToOffset(int seconds)
-{
- const QChar sign = ushort(seconds < 0 ? '-' : '+');
- seconds = qAbs(seconds);
- const int hours = seconds / 3600;
- const int minutes = (seconds % 3600) / 60;
-
- return QString(QStringLiteral("%1%2:%3")).arg(sign).arg(hours, 2, 10, QLatin1Char('0')).arg(minutes, 2, 10, QLatin1Char('0'));
-}
-
-static QString timespecToString(const QDateTime &dateTime)
-{
- switch (dateTime.timeSpec()) {
- case Qt::LocalTime:
- return QString();
- case Qt::UTC:
- return QStringLiteral("Z");
- case Qt::OffsetFromUTC:
- return secondsToOffset(dateTime.offsetFromUtc());
-#if QT_CONFIG(timezone)
- case Qt::TimeZone:
- return secondsToOffset(dateTime.timeZone().offsetFromUtc(dateTime));
-#endif
- default:
- return QString();
- }
-}
-
bool QSQLiteResult::execBatch(bool arrayBind)
{
Q_UNUSED(arrayBind);
@@ -555,7 +524,7 @@ bool QSQLiteResult::exec()
break;
case QVariant::DateTime: {
const QDateTime dateTime = value.toDateTime();
- const QString str = dateTime.toString(QLatin1String("yyyy-MM-ddThh:mm:ss.zzz") + timespecToString(dateTime));
+ const QString str = dateTime.toString(Qt::ISODateWithMs);
res = sqlite3_bind_text16(d->stmt, i + 1, str.utf16(),
str.size() * sizeof(ushort), SQLITE_TRANSIENT);
break;
@@ -673,7 +642,7 @@ static void _q_regexp(sqlite3_context* context, int argc, sqlite3_value** argv)
const bool wasCached = regexp;
if (!wasCached)
- regexp = new QRegularExpression(pattern, QRegularExpression::DontCaptureOption | QRegularExpression::OptimizeOnFirstUsageOption);
+ regexp = new QRegularExpression(pattern, QRegularExpression::DontCaptureOption);
const bool found = subject.contains(*regexp);
@@ -953,13 +922,20 @@ static QSqlIndex qGetTableInfo(QSqlQuery &q, const QString &tableName, bool only
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(q.value(4));
+ fld.setDefaultValue(defVal);
ind.append(fld);
}
return ind;
diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm
index 3405f01046..2a21673054 100644
--- a/src/plugins/styles/mac/qmacstyle_mac.mm
+++ b/src/plugins/styles/mac/qmacstyle_mac.mm
@@ -143,22 +143,12 @@ static QWindow *qt_getWindow(const QWidget *widget)
return widget ? widget->window()->windowHandle() : 0;
}
-@interface QT_MANGLE_NAMESPACE(NotificationReceiver) : NSObject {
-QMacStylePrivate *mPrivate;
-}
-- (id)initWithPrivate:(QMacStylePrivate *)priv;
-- (void)scrollBarStyleDidChange:(NSNotification *)notification;
+@interface QT_MANGLE_NAMESPACE(NotificationReceiver) : NSObject
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(NotificationReceiver);
@implementation NotificationReceiver
-- (id)initWithPrivate:(QMacStylePrivate *)priv
-{
- self = [super init];
- mPrivate = priv;
- return self;
-}
- (void)scrollBarStyleDidChange:(NSNotification *)notification
{
@@ -263,33 +253,50 @@ QVector<QPointer<QObject> > QMacStylePrivate::scrollBars;
static QLinearGradient titlebarGradientActive()
{
- static QLinearGradient gradient;
- if (gradient == QLinearGradient()) {
+ 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 gradient;
+ }();
+ return qt_mac_applicationIsInDarkMode() ? darkGradient : lightGradient;
}
static QLinearGradient titlebarGradientInactive()
{
- static QLinearGradient gradient;
- if (gradient == QLinearGradient()) {
+ 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 gradient;
+ }();
+ return qt_mac_applicationIsInDarkMode() ? darkGradient : lightGradient;
}
static const QColor titlebarSeparatorLineActive(111, 111, 111);
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.
-static const QColor mainWindowGradientBegin(240, 240, 240);
-static const QColor mainWindowGradientEnd(200, 200, 200);
+static const QColor lightMainWindowGradientBegin(240, 240, 240);
+static const QColor lightMainWindowGradientEnd(200, 200, 200);
+static const QColor darkMainWindowGradientBegin(47, 47, 47);
+static const QColor darkMainWindowGradientEnd(47, 47, 47);
static const int DisclosureOffset = 4;
@@ -404,9 +411,9 @@ static bool setupSlider(NSSlider *slider, const QStyleOptionSlider *sl)
const bool ticksAbove = sl->tickPosition == QSlider::TicksAbove;
if (sl->orientation == Qt::Horizontal)
- slider.tickMarkPosition = ticksAbove ? NSTickMarkAbove : NSTickMarkBelow;
+ slider.tickMarkPosition = ticksAbove ? NSTickMarkPositionAbove : NSTickMarkPositionBelow;
else
- slider.tickMarkPosition = ticksAbove ? NSTickMarkLeft : NSTickMarkRight;
+ slider.tickMarkPosition = ticksAbove ? NSTickMarkPositionLeading : NSTickMarkPositionTrailing;
} else {
slider.numberOfTickMarks = 0;
}
@@ -1745,17 +1752,10 @@ NSView *QMacStylePrivate::cocoaControl(CocoaControl widget) const
}
Q_UNREACHABLE();
} ();
-#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_12)
const auto styleMask = NSWindowStyleMaskTitled
| NSWindowStyleMaskClosable
| NSWindowStyleMaskMiniaturizable
| NSWindowStyleMaskResizable;
-#else
- const auto styleMask = NSTitledWindowMask
- | NSClosableWindowMask
- | NSMiniaturizableWindowMask
- | NSResizableWindowMask;
-#endif
bv = [NSWindow standardWindowButton:button forStyleMask:styleMask];
[bv retain];
break;
@@ -1802,10 +1802,10 @@ NSView *QMacStylePrivate::cocoaControl(CocoaControl widget) const
auto *ctrl = static_cast<NSControl *>(bv);
switch (widget.size) {
case QStyleHelper::SizeSmall:
- ctrl.controlSize = NSSmallControlSize;
+ ctrl.controlSize = NSControlSizeSmall;
break;
case QStyleHelper::SizeMini:
- ctrl.controlSize = NSMiniControlSize;
+ ctrl.controlSize = NSControlSizeMini;
break;
default:
break;
@@ -1816,10 +1816,10 @@ NSView *QMacStylePrivate::cocoaControl(CocoaControl widget) const
pi.indeterminate = (widget.type == ProgressIndicator_Indeterminate);
switch (widget.size) {
case QStyleHelper::SizeSmall:
- pi.controlSize = NSSmallControlSize;
+ pi.controlSize = NSControlSizeSmall;
break;
case QStyleHelper::SizeMini:
- pi.controlSize = NSMiniControlSize;
+ pi.controlSize = NSControlSizeMini;
break;
default:
break;
@@ -1865,10 +1865,10 @@ NSCell *QMacStylePrivate::cocoaCell(CocoaControl widget) const
switch (widget.size) {
case QStyleHelper::SizeSmall:
- cell.controlSize = NSSmallControlSize;
+ cell.controlSize = NSControlSizeSmall;
break;
case QStyleHelper::SizeMini:
- cell.controlSize = NSMiniControlSize;
+ cell.controlSize = NSControlSizeMini;
break;
default:
break;
@@ -1936,7 +1936,7 @@ QMacStyle::QMacStyle()
Q_D(QMacStyle);
QMacAutoReleasePool pool;
- d->receiver = [[NotificationReceiver alloc] initWithPrivate:d];
+ d->receiver = [[NotificationReceiver alloc] init];
[[NSNotificationCenter defaultCenter] addObserver:d->receiver
selector:@selector(scrollBarStyleDidChange:)
name:NSPreferredScrollerStyleDidChangeNotification
@@ -2208,9 +2208,9 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW
ret = 0;
break;
case PM_TitleBarHeight: {
- NSUInteger style = NSTitledWindowMask;
+ NSUInteger style = NSWindowStyleMaskTitled;
if (widget && ((widget->windowFlags() & Qt::Tool) == Qt::Tool))
- style |= NSUtilityWindowMask;
+ style |= NSWindowStyleMaskUtilityWindow;
ret = int([NSWindow frameRectForContentRect:NSZeroRect
styleMask:style].size.height);
break; }
@@ -2820,8 +2820,7 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
{
Q_D(const QMacStyle);
QMacCGContext cg(p);
- QWindow *window = w && w->window() ? w->window()->windowHandle() :
- QStyleHelper::styleObjectWindow(opt->styleObject);
+ QWindow *window = w && w->window() ? w->window()->windowHandle() : nullptr;
d->resolveCurrentNSView(window);
switch (pe) {
case PE_IndicatorArrowUp:
@@ -3136,8 +3135,7 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
tf.bezeled = YES;
static_cast<NSTextFieldCell *>(tf.cell).bezelStyle = isRounded ? NSTextFieldRoundedBezel : NSTextFieldSquareBezel;
tf.frame = opt->rect.toCGRect();
- d->drawNSViewInRect(tf, opt->rect, p, ^(CGContextRef ctx, const CGRect &rect) {
- Q_UNUSED(ctx);
+ d->drawNSViewInRect(tf, opt->rect, p, ^(CGContextRef, const CGRect &rect) {
[tf.cell drawWithFrame:rect inView:tf];
});
} else {
@@ -3266,8 +3264,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
{
Q_D(const QMacStyle);
QMacCGContext cg(p);
- QWindow *window = w && w->window() ? w->window()->windowHandle() :
- QStyleHelper::styleObjectWindow(opt->styleObject);
+ QWindow *window = w && w->window() ? w->window()->windowHandle() : nullptr;
d->resolveCurrentNSView(window);
switch (ce) {
case CE_HeaderSection:
@@ -3468,7 +3465,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
pb.enabled = isEnabled;
[pb highlight:isPressed];
pb.state = isHighlighted && !isPressed ? NSOnState : NSOffState;
- d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef __unused ctx, const CGRect &r) {
+ d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef, const CGRect &r) {
[pb.cell drawBezelWithFrame:r inView:pb.superview];
});
[pb highlight:NO];
@@ -4210,7 +4207,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
const auto cw = QMacStylePrivate::CocoaControl(ct, QStyleHelper::SizeLarge);
auto *sv = static_cast<NSSplitView *>(d->cocoaControl(cw));
sv.frame = opt->rect.toCGRect();
- d->drawNSViewInRect(sv, opt->rect, p, ^(CGContextRef __unused ctx, const CGRect &rect) {
+ d->drawNSViewInRect(sv, opt->rect, p, ^(CGContextRef, const CGRect &rect) {
[sv drawDividerInRect:rect];
});
} else {
@@ -4253,12 +4250,13 @@ 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();
// 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
// the title bar. The following code fills the toolBar area with transparent pixels
// to make that gradient visible.
- if (w) {
+ if (w) {
#if QT_CONFIG(mainwindow)
if (QMainWindow * mainWindow = qobject_cast<QMainWindow *>(w->window())) {
if (toolBar && toolBar->toolBarArea == Qt::TopToolBarArea && mainWindow->unifiedTitleAndToolBarOnMac()) {
@@ -4268,7 +4266,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
p->fillRect(opt->rect, Qt::transparent);
p->restore();
- // Drow a horizontal separator line at the toolBar bottom if the "unified" area ends here.
+ // Draw a horizontal separator line at the toolBar bottom if the "unified" area ends here.
// There might be additional toolbars or other widgets such as tab bars in document
// mode below. Determine this by making a unified toolbar area test for the row below
// this toolbar.
@@ -4277,7 +4275,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, opt->palette.dark().color());
+ p->fillRect(separatorRect, isDarkMode ? darkModeSeparatorLine : opt->palette.dark().color());
}
break;
}
@@ -4292,21 +4290,23 @@ 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;
+
linearGrad.setColorAt(0, mainWindowGradientBegin);
linearGrad.setColorAt(1, mainWindowGradientEnd);
p->fillRect(opt->rect, linearGrad);
p->save();
if (opt->state & State_Horizontal) {
- p->setPen(mainWindowGradientBegin.lighter(114));
+ p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
- p->setPen(mainWindowGradientEnd.darker(114));
+ p->setPen(isDarkMode ? darkModeSeparatorLine :mainWindowGradientEnd.darker(114));
p->drawLine(opt->rect.bottomLeft(), opt->rect.bottomRight());
-
} else {
- p->setPen(mainWindowGradientBegin.lighter(114));
+ p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
- p->setPen(mainWindowGradientEnd.darker(114));
+ p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientEnd.darker(114));
p->drawLine(opt->rect.topRight(), opt->rect.bottomRight());
}
p->restore();
@@ -4841,8 +4841,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
{
Q_D(const QMacStyle);
QMacCGContext cg(p);
- QWindow *window = widget && widget->window() ? widget->window()->windowHandle() :
- QStyleHelper::styleObjectWindow(opt->styleObject);
+ QWindow *window = widget && widget->window() ? widget->window()->windowHandle() : nullptr;
d->resolveCurrentNSView(window);
switch (cc) {
case CC_ScrollBar:
@@ -5217,7 +5216,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
}
pb.frame = frameRect.toCGRect();
[pb highlight:isPressed];
- d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef __unused ctx, const CGRect &r) {
+ d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef, const CGRect &r) {
[pb.cell drawBezelWithFrame:r inView:pb.superview];
});
} else if (cw.type == QMacStylePrivate::ComboBox) {
@@ -5233,7 +5232,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
// TODO Render to pixmap and darken the button manually
}
- d->drawNSViewInRect(cb, frameRect, p, ^(CGContextRef __unused ctx, const CGRect &r) {
+ d->drawNSViewInRect(cb, frameRect, p, ^(CGContextRef, const CGRect &r) {
// FIXME This is usually drawn in the control's superview, but we wouldn't get inactive look in this case
[cb.cell drawWithFrame:r inView:cb];
});
@@ -5305,13 +5304,10 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
Q_UNUSED(isHovered); // FIXME No public API for this
const auto buttonRect = proxy()->subControlRect(CC_TitleBar, titlebar, sc, widget);
- const auto drawBlock = ^ (CGContextRef ctx, const CGRect &rect) {
- Q_UNUSED(ctx);
- Q_UNUSED(rect);
+ d->drawNSViewInRect(wb, buttonRect, p, ^(CGContextRef, const CGRect &rect) {
auto *wbCell = static_cast<NSButtonCell *>(wb.cell);
[wbCell drawWithFrame:rect inView:wb];
- };
- d->drawNSViewInRect(wb, buttonRect, p, drawBlock);
+ });
}
}
@@ -5376,12 +5372,6 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
d->drawToolbarButtonArrow(tb, p);
}
if (tb->state & State_On) {
- QWindow *window = 0;
- if (widget && widget->window())
- window = widget->window()->windowHandle();
- else if (opt->styleObject)
- window = opt->styleObject->property("_q_styleObjectWindow").value<QWindow *>();
-
NSView *view = window ? (NSView *)window->winId() : nil;
bool isKey = false;
if (view)
@@ -5420,8 +5410,8 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
pb.enabled = isEnabled;
[pb highlight:isPressed];
pb.state = isHighlighted && !isPressed ? NSOnState : NSOffState;
- const auto buttonRect = proxy()->subControlRect(cc, tb, SC_ToolButton, widget);
- d->drawNSViewInRect(pb, buttonRect, p, ^(CGContextRef __unused ctx, const CGRect &rect) {
+ 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];
});
}
@@ -5904,7 +5894,7 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt,
switch (ct) {
#if QT_CONFIG(spinbox)
case CT_SpinBox:
- if (const QStyleOptionSpinBox *vopt = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
+ if (qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
const int buttonWidth = 20; // FIXME Use subControlRect()
sz += QSize(buttonWidth, 0);
}
diff --git a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp
index 6add110249..7b35d1b58c 100644
--- a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp
+++ b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp
@@ -179,9 +179,7 @@ QWindowsVistaStyle::QWindowsVistaStyle()
/*!
Destructor.
*/
-QWindowsVistaStyle::~QWindowsVistaStyle()
-{
-}
+QWindowsVistaStyle::~QWindowsVistaStyle() = default;
//convert Qt state flags to uxtheme button states
static int buttonStateId(int flags, int partId)
@@ -2171,12 +2169,12 @@ QRect QWindowsVistaStyle::subControlRect(ComplexControl control, const QStyleOpt
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)) * QWindowsStylePrivate::nativeMetricScaleFactor(widget)
- - QStyleHelper::dpiScaled(4));
+ qRound(qreal(GetSystemMetrics(SM_CXSIZE)) * factor - QStyleHelper::dpiScaled(4));
const int frameWidth = proxy()->pixelMetric(PM_MdiSubWindowFrameWidth, option, widget);
const bool sysmenuHint = (tb->titleBarFlags & Qt::WindowSystemMenuHint) != 0;
@@ -2190,31 +2188,31 @@ QRect QWindowsVistaStyle::subControlRect(ComplexControl control, const QStyleOpt
rect = QRect(frameWidth, 0, width - (buttonWidth + frameWidth + 10), height);
if (isToolTitle) {
if (sysmenuHint) {
- rect.adjust(0, 0, -buttonWidth - 3, 0);
+ rect.adjust(0, 0, int(-buttonWidth - 3 * factor), 0);
}
if (minimizeHint || maximizeHint)
- rect.adjust(0, 0, -buttonWidth - 2, 0);
+ rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
} else {
if (sysmenuHint) {
- const int leftOffset = height - 8;
- rect.adjust(leftOffset, 0, 0, 4);
+ const int leftOffset = int(height - 8 * factor);
+ rect.adjust(leftOffset, 0, 0, int(4 * factor));
}
if (minimizeHint)
- rect.adjust(0, 0, -buttonWidth - 2, 0);
+ rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
if (maximizeHint)
- rect.adjust(0, 0, -buttonWidth - 2, 0);
+ rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
if (contextHint)
- rect.adjust(0, 0, -buttonWidth - 2, 0);
+ rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
if (shadeHint)
- rect.adjust(0, 0, -buttonWidth - 2, 0);
+ rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
}
- rect.translate(0, 2);
+ rect.translate(0, int(2 * factor));
rect = visualRect(option->direction, option->rect, rect);
break;
case SC_TitleBarSysMenu:
{
- const int controlTop = 6;
- const int controlHeight = height - controlTop - 3;
+ 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())
@@ -2222,7 +2220,7 @@ QRect QWindowsVistaStyle::subControlRect(ComplexControl control, const QStyleOpt
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, 3);
+ rect.translate(0, int(3 * factor));
rect = visualRect(option->direction, option->rect, rect);
}
break;
diff --git a/src/plugins/styles/windowsvista/qwindowsvistastyle_p.h b/src/plugins/styles/windowsvista/qwindowsvistastyle_p.h
index 5ffcbc6aa9..0ebb0eb41a 100644
--- a/src/plugins/styles/windowsvista/qwindowsvistastyle_p.h
+++ b/src/plugins/styles/windowsvista/qwindowsvistastyle_p.h
@@ -62,38 +62,41 @@ class QWindowsVistaStyle : public QWindowsXPStyle
Q_OBJECT
public:
QWindowsVistaStyle();
- ~QWindowsVistaStyle();
+ ~QWindowsVistaStyle() override;
void drawPrimitive(PrimitiveElement element, const QStyleOption *option,
- QPainter *painter, const QWidget *widget = 0) const;
+ QPainter *painter,
+ const QWidget *widget = nullptr) const override;
void drawControl(ControlElement element, const QStyleOption *option,
- QPainter *painter, const QWidget *widget) const;
+ QPainter *painter, const QWidget *widget) const override;
void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option,
- QPainter *painter, const QWidget *widget) const;
+ QPainter *painter, const QWidget *widget) const override;
QSize sizeFromContents(ContentsType type, const QStyleOption *option,
- const QSize &size, const QWidget *widget) const;
+ const QSize &size, const QWidget *widget) const override;
- QRect subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const;
+ QRect subElementRect(SubElement element, const QStyleOption *option,
+ const QWidget *widget) const override;
QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt,
- SubControl sc, const QWidget *widget) const;
+ SubControl sc, const QWidget *widget) const override;
SubControl hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option,
- const QPoint &pos, const QWidget *widget = 0) const;
+ const QPoint &pos, const QWidget *widget = nullptr) const override;
- QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option = 0,
- const QWidget *widget = 0) const;
+ QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option = nullptr,
+ const QWidget *widget = nullptr) const override;
QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt,
- const QWidget *widget = 0) const;
- int pixelMetric(PixelMetric metric, const QStyleOption *option = 0, const QWidget *widget = 0) const;
- int styleHint(StyleHint hint, const QStyleOption *opt = 0, const QWidget *widget = 0,
- QStyleHintReturn *returnData = 0) const;
+ const QWidget *widget = nullptr) const override;
+ int pixelMetric(PixelMetric metric, const QStyleOption *option = nullptr,
+ const QWidget *widget = nullptr) const override;
+ int styleHint(StyleHint hint, const QStyleOption *opt = nullptr,
+ const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const override;
- void polish(QWidget *widget);
- void unpolish(QWidget *widget);
- void polish(QPalette &pal);
- void polish(QApplication *app);
- void unpolish(QApplication *app);
- QPalette standardPalette() const;
+ void polish(QWidget *widget) override;
+ void unpolish(QWidget *widget) override;
+ void polish(QPalette &pal) override;
+ void polish(QApplication *app) override;
+ void unpolish(QApplication *app) override;
+ QPalette standardPalette() const override;
private:
Q_DISABLE_COPY(QWindowsVistaStyle)
diff --git a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp
index 36a8afb453..4b583e13d3 100644
--- a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp
+++ b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp
@@ -494,7 +494,8 @@ bool QWindowsXPStylePrivate::isTransparent(XPThemeData &themeData)
QRegion QWindowsXPStylePrivate::region(XPThemeData &themeData)
{
HRGN hRgn = 0;
- RECT rect = themeData.toRECT(themeData.rect);
+ 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();
@@ -523,7 +524,7 @@ QRegion QWindowsXPStylePrivate::region(XPThemeData &themeData)
RECT *r = reinterpret_cast<RECT*>(rd->Buffer);
for (uint i = 0; i < rd->rdh.nCount; ++i) {
QRect rect;
- rect.setCoords(r->left, r->top, r->right - 1, r->bottom - 1);
+ rect.setCoords(int(r->left * factor), int(r->top * factor), int((r->right - 1) * factor), int((r->bottom - 1) * factor));
++r;
region |= rect;
}
@@ -1756,9 +1757,9 @@ case PE_Frame:
else
stateId = FS_INACTIVE;
- int fwidth = frm->lineWidth + frm->midLineWidth;
+ int fwidth = int((frm->lineWidth + frm->midLineWidth) / QWindowsStylePrivate::nativeMetricScaleFactor(widget));
- XPThemeData theme(0, p, themeNumber, 0, stateId);
+ XPThemeData theme(widget, p, themeNumber, 0, stateId);
if (!theme.isValid())
break;
@@ -2949,6 +2950,7 @@ void QWindowsXPStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCo
{
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) {
@@ -2975,13 +2977,15 @@ void QWindowsXPStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCo
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(ir.x() + 3, ir.y() + 2, ir.width() - 1, ir.height(),
+ 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(ir.x() + 2, ir.y() + 1, ir.width() - 2, ir.height(),
+ 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) {
diff --git a/src/plugins/styles/windowsvista/qwindowsxpstyle_p.h b/src/plugins/styles/windowsvista/qwindowsxpstyle_p.h
index d00620eefa..7e9f4ddda6 100644
--- a/src/plugins/styles/windowsvista/qwindowsxpstyle_p.h
+++ b/src/plugins/styles/windowsvista/qwindowsxpstyle_p.h
@@ -63,35 +63,37 @@ class QWindowsXPStyle : public QWindowsStyle
public:
QWindowsXPStyle();
QWindowsXPStyle(QWindowsXPStylePrivate &dd);
- ~QWindowsXPStyle();
+ ~QWindowsXPStyle() override;
- void unpolish(QApplication*);
- void polish(QApplication*);
- void polish(QWidget*);
- void polish(QPalette&);
- void unpolish(QWidget*);
+ 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 = 0) const;
+ const QWidget *widget = nullptr) const override;
void drawControl(ControlElement element, const QStyleOption *option, QPainter *p,
- const QWidget *wwidget = 0) const;
- QRect subElementRect(SubElement r, const QStyleOption *option, const QWidget *widget = 0) const;
+ 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 = 0) const;
+ const QWidget *widget = nullptr) const override;
void drawComplexControl(ComplexControl cc, const QStyleOptionComplex *option, QPainter *p,
- const QWidget *widget = 0) const;
+ const QWidget *widget = nullptr) const override;
QSize sizeFromContents(ContentsType ct, const QStyleOption *option, const QSize &contentsSize,
- const QWidget *widget = 0) const;
- int pixelMetric(PixelMetric pm, const QStyleOption *option = 0,
- const QWidget *widget = 0) const;
- int styleHint(StyleHint hint, const QStyleOption *option = 0, const QWidget *widget = 0,
- QStyleHintReturn *returnData = 0) const;
+ 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;
+ QPalette standardPalette() const override;
QPixmap standardPixmap(StandardPixmap standardIcon, const QStyleOption *option,
- const QWidget *widget = 0) const;
- QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option = 0,
- const QWidget *widget = 0) const;
+ const QWidget *widget = nullptr) const override;
+ QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option = nullptr,
+ const QWidget *widget = nullptr) const override;
private:
Q_DISABLE_COPY(QWindowsXPStyle)