diff options
148 files changed, 4993 insertions, 2921 deletions
diff --git a/config.tests/qpa/egl-x11/egl-x11.cpp b/config.tests/qpa/egl-x11/egl-x11.cpp new file mode 100644 index 0000000000..f5c2ae7260 --- /dev/null +++ b/config.tests/qpa/egl-x11/egl-x11.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the config.tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <EGL/egl.h> +#include <xcb/xcb.h> +#include <X11/Xlib.h> +#include <X11/Xlib-xcb.h> + +// Check if EGL is compatible with X. Some EGL implementations, typically on +// embedded devices, are not intended to be used together with X. EGL support +// has to be disabled in plugins like xcb in this case since the native display, +// window and pixmap types will be different than what an X-based platform +// plugin would expect. + +int main(int, char **) +{ + Display *dpy = EGL_DEFAULT_DISPLAY; + EGLNativeDisplayType egldpy = XOpenDisplay(""); + dpy = egldpy; + EGLNativeWindowType w = XCreateWindow(dpy, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + XDestroyWindow(dpy, w); + XCloseDisplay(dpy); + return 0; +} diff --git a/config.tests/qpa/egl-x11/egl-x11.pro b/config.tests/qpa/egl-x11/egl-x11.pro new file mode 100644 index 0000000000..c4e94ca40c --- /dev/null +++ b/config.tests/qpa/egl-x11/egl-x11.pro @@ -0,0 +1,12 @@ +SOURCES = egl-x11.cpp + +for(p, QMAKE_LIBDIR_EGL) { + exists($$p):LIBS += -L$$p +} + +!isEmpty(QMAKE_INCDIR_EGL): INCLUDEPATH += $$QMAKE_INCDIR_EGL +!isEmpty(QMAKE_LIBS_EGL): LIBS += $$QMAKE_LIBS_EGL + +CONFIG -= qt + +LIBS += -lxcb -lX11 -lX11-xcb @@ -613,6 +613,7 @@ CFG_OPENVG_LC_INCLUDES=no CFG_OPENVG_SHIVA=auto CFG_OPENVG_ON_OPENGL=auto CFG_EGL=auto +CFG_EGL_X=auto CFG_FONTCONFIG=auto CFG_FREETYPE=auto CFG_HARFBUZZ=no @@ -780,6 +781,8 @@ QT_LIBS_GLIB= # default qpa platform QT_QPA_DEFAULT_PLATFORM= +# default print support plugin +QT_PRINTSUPPORT_DEFAULT_PLUGIN= # Android vars CFG_DEFAULT_ANDROID_NDK_ROOT=$ANDROID_NDK_ROOT @@ -1473,6 +1476,7 @@ while [ "$#" -gt 0 ]; do egl) if [ "$VAL" = "yes" ] || [ "$VAL" = "no" ]; then CFG_EGL="$VAL" + CFG_EGL_X="$VAL" else UNKNOWN_OPT=yes fi @@ -5366,6 +5370,11 @@ if [ "$CFG_EGL" != "no" ]; then fi # detect EGL support if compileTest qpa/egl "EGL" $QMAKE_CFLAGS_EGL $QMAKE_LIBS_EGL; then CFG_EGL=yes + if compileTest qpa/egl-x11 "EGL-X11" $QMAKE_CFLAGS_EGL $QMAKE_LIBS_EGL; then + CFG_EGL_X=yes + else + CFG_EGL_X=no + fi elif [ "$CFG_EGL" = "yes" ]; then echo " The EGL functionality test failed; EGL is required by some QPA plugins to manage contexts & surfaces." echo " You might need to modify the include and library search paths by editing" @@ -5373,6 +5382,7 @@ if [ "$CFG_EGL" != "no" ]; then exit 1 else CFG_EGL=no + CFG_EGL_X=no fi fi @@ -5427,6 +5437,15 @@ if [ -z "$QT_QPA_DEFAULT_PLATFORM" ]; then fi fi +# Determine print support plugin belonging to the default QPA platform +if [ "$QT_QPA_DEFAULT_PLATFORM" = "cocoa" ]; then + QT_PRINTSUPPORT_DEFAULT_PLUGIN=cocoaprintersupport +elif [ "$QT_QPA_DEFAULT_PLATFORM" = "windows" ]; then + QT_PRINTSUPPORT_DEFAULT_PLUGIN=windowsprintersupport +elif [ "$QT_QPA_DEFAULT_PLATFORM" = "xcb" ]; then + QT_PRINTSUPPORT_DEFAULT_PLUGIN=cupsprintersupport +fi + if [ -n "$QMAKE_CFLAGS_XCB" ] || [ -n "$QMAKE_LIBS_XCB" ]; then QMakeVar set QMAKE_CFLAGS_XCB "$QMAKE_CFLAGS_XCB" QMakeVar set QMAKE_LIBS_XCB "$QMAKE_LIBS_XCB" @@ -5752,6 +5771,13 @@ else QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_EGL" fi +# enable egl on X +if [ "$CFG_EGL_X" = "yes" ]; then + QT_CONFIG="$QT_CONFIG egl_x11" +else + QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_EGL_X11" +fi + # enable eglfs if [ "$CFG_EGLFS" = "yes" ]; then QT_CONFIG="$QT_CONFIG eglfs" @@ -6412,6 +6438,7 @@ EOF fi echo "#define QT_QPA_DEFAULT_PLATFORM_NAME \"$QT_QPA_DEFAULT_PLATFORM\"" >>"$outpath/src/corelib/global/qconfig.h.new" +echo "#define QT_QPA_DEFAULT_PRINTSUPPORTPLUGIN_NAME \"QT_PRINTSUPPORT_DEFAULT_PLUGIN\"" >>"$outpath/src/corelib/global/qconfig.h.new" # avoid unecessary rebuilds by copying only if qconfig.h has changed if cmp -s "$outpath/src/corelib/global/qconfig.h" "$outpath/src/corelib/global/qconfig.h.new"; then @@ -6499,6 +6526,7 @@ EOF if [ "$CFG_SHARED" = "no" ]; then echo "QT_DEFAULT_QPA_PLUGIN = q$QT_QPA_DEFAULT_PLATFORM" >> "$QTCONFIG.tmp" + echo "QT_DEFAULT_PRINTSUPPORTPLUGIN = $QT_PRINTSUPPORT_DEFAULT_PLUGIN" >> "$QTCONFIG.tmp" echo >> "$QTCONFIG.tmp" fi @@ -6775,6 +6803,9 @@ report_support " getifaddrs ..........." "$CFG_GETIFADDRS" report_support " IPv6 ifname .........." "$CFG_IPV6IFNAME" report_support " OpenSSL .............." "$CFG_OPENSSL" yes "loading libraries at run-time" linked "linked to the libraries" report_support " NIS ...................." "$CFG_NIS" +report_support " EGL ...................." "$CFG_EGL" +report_support " EGL on X ..............." "$CFG_EGL_X" +report_support " GLX ...................." "$CFG_XCB_GLX" report_support " OpenGL ................." "$CFG_OPENGL" yes "Desktop OpenGL" es2 "OpenGL ES 2.x" report_support " OpenVG ................." "$CFG_OPENVG-$CFG_OPENVG_SHIVA" yes-yes "ShivaVG" yes-no "native" report_support " PCRE ..................." "$CFG_PCRE" yes "system library" qt "bundled copy" diff --git a/examples/widgets/mainwindows/mainwindow/colorswatch.cpp b/examples/widgets/mainwindows/mainwindow/colorswatch.cpp index 00a35afa4c..b39c45118c 100644 --- a/examples/widgets/mainwindows/mainwindow/colorswatch.cpp +++ b/examples/widgets/mainwindows/mainwindow/colorswatch.cpp @@ -636,7 +636,7 @@ void BlueTitleBar::paintEvent(QPaintEvent*) centerPm.height(), centerPm); } -void BlueTitleBar::mousePressEvent(QMouseEvent *event) +void BlueTitleBar::mouseReleaseEvent(QMouseEvent *event) { QPoint pos = event->pos(); diff --git a/examples/widgets/mainwindows/mainwindow/colorswatch.h b/examples/widgets/mainwindows/mainwindow/colorswatch.h index 11f924ddb7..b83a6ba76a 100644 --- a/examples/widgets/mainwindows/mainwindow/colorswatch.h +++ b/examples/widgets/mainwindows/mainwindow/colorswatch.h @@ -124,7 +124,7 @@ public: QSize minimumSizeHint() const; protected: void paintEvent(QPaintEvent *event); - void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); public slots: void updateMask(); diff --git a/mkspecs/features/moc.prf b/mkspecs/features/moc.prf index 100edc2d98..c0b5682446 100644 --- a/mkspecs/features/moc.prf +++ b/mkspecs/features/moc.prf @@ -8,6 +8,8 @@ isEmpty(QMAKE_EXT_CPP_MOC):QMAKE_EXT_CPP_MOC = .moc MOC_INCLUDEPATH = for (inc, INCLUDEPATH): \ MOC_INCLUDEPATH += $$absolute_path($$inc, $$_PRO_FILE_PWD_) +!no_include_pwd:!isEqual(OUT_PWD, $$_PRO_FILE_PWD_): \ + MOC_INCLUDEPATH += . MOC_INCLUDEPATH = $$QMAKESPEC $$_PRO_FILE_PWD_ $$MOC_INCLUDEPATH $$QMAKE_DEFAULT_INCDIRS # On Windows, put the includes into a .inc file which moc will read, if the project diff --git a/mkspecs/features/qt.prf b/mkspecs/features/qt.prf index 83a8778654..fb83e59e65 100644 --- a/mkspecs/features/qt.prf +++ b/mkspecs/features/qt.prf @@ -172,6 +172,8 @@ contains(QT_CONFIG, static) { else: \ QTPLUGIN += $$QT_DEFAULT_QPA_PLUGIN } + needs_printsupport_plugin: \ + QTPLUGIN += $$QT_DEFAULT_PRINTSUPPORTPLUGIN import_plugins:!isEmpty(QTPLUGIN) { IMPORT_FILE_CONT = \ "// This file is autogenerated by qmake. It imports static plugin classes for" \ diff --git a/mkspecs/features/win32/windeployqt.prf b/mkspecs/features/win32/windeployqt.prf new file mode 100644 index 0000000000..f49df47ffe --- /dev/null +++ b/mkspecs/features/win32/windeployqt.prf @@ -0,0 +1,19 @@ +# Extra target for running windeployqt +qtPrepareTool(QMAKE_WINDEPLOYQT, windeployqt) +build_pass { + load(resolve_target) + + isEmpty(WINDEPLOYQT_OPTIONS): WINDEPLOYQT_OPTIONS = -qmldir $$shell_quote($$shell_path($$_PRO_FILE_PWD_)) + WINDEPLOYQT_TARGET = $$shell_quote($$shell_path($$QMAKE_RESOLVED_TARGET)) + WINDEPLOYQT_OUTPUT = $$shell_quote($$shell_path($$dirname(QMAKE_RESOLVED_TARGET)/$$basename(TARGET).windeployqt)) + windeployqt.target = windeployqt + windeployqt.commands = $$QMAKE_WINDEPLOYQT $$WINDEPLOYQT_OPTIONS -list target $$WINDEPLOYQT_TARGET > $$WINDEPLOYQT_OUTPUT + + windeployqt_clean.commands = if exist $$WINDEPLOYQT_OUTPUT for /f %i in ($$WINDEPLOYQT_OUTPUT) do $$QMAKE_DEL_FILE %~fi && $$QMAKE_DEL_DIR %~pi + QMAKE_EXTRA_TARGETS += windeployqt_clean + DISTCLEAN_DEPS += windeployqt_clean + QMAKE_DISTCLEAN += $$WINDEPLOYQT_OUTPUT +} else { + windeployqt.CONFIG += recursive +} +QMAKE_EXTRA_TARGETS += windeployqt diff --git a/mkspecs/winphone-x86-msvc2012/qmake.conf b/mkspecs/winphone-x86-msvc2012/qmake.conf index 1329370900..4b8a92ea3b 100644 --- a/mkspecs/winphone-x86-msvc2012/qmake.conf +++ b/mkspecs/winphone-x86-msvc2012/qmake.conf @@ -13,7 +13,7 @@ QMAKE_LFLAGS += /MACHINE:X86 QMAKE_LIBS += WindowsPhoneCore.lib PhoneAppModelHost.lib ws2_32.lib -VCPROJ_ARCH = x86 +VCPROJ_ARCH = Win32 MSVC_VER = 11.0 WINSDK_VER = 8.0 WINTARGET_VER = WP80 diff --git a/mkspecs/winrt-arm-msvc2012/qmake.conf b/mkspecs/winrt-arm-msvc2012/qmake.conf index 41594a3547..b2603cfb2f 100644 --- a/mkspecs/winrt-arm-msvc2012/qmake.conf +++ b/mkspecs/winrt-arm-msvc2012/qmake.conf @@ -17,3 +17,4 @@ MSVC_VER = 11.0 WINSDK_VER = 8.0 WINTARGET_VER = win8 WINRT_MANIFEST = $$PWD/../common/winrt_winphone/manifests/8.0/AppxManifest.xml.in +WINRT_MANIFEST.architecture = arm diff --git a/mkspecs/winrt-arm-msvc2013/qmake.conf b/mkspecs/winrt-arm-msvc2013/qmake.conf index 83ab228d7f..d1ab60723d 100644 --- a/mkspecs/winrt-arm-msvc2013/qmake.conf +++ b/mkspecs/winrt-arm-msvc2013/qmake.conf @@ -19,3 +19,4 @@ MSVC_VER = 12.0 WINSDK_VER = 8.1 WINTARGET_VER = winv6.3 WINRT_MANIFEST = $$PWD/../common/winrt_winphone/manifests/8.1/AppxManifest.xml.in +WINRT_MANIFEST.architecture = arm diff --git a/mkspecs/winrt-x64-msvc2012/qmake.conf b/mkspecs/winrt-x64-msvc2012/qmake.conf index f6e360ae12..a0c64c695f 100644 --- a/mkspecs/winrt-x64-msvc2012/qmake.conf +++ b/mkspecs/winrt-x64-msvc2012/qmake.conf @@ -17,3 +17,4 @@ MSVC_VER = 11.0 WINSDK_VER = 8.0 WINTARGET_VER = win8 WINRT_MANIFEST = $$PWD/../common/winrt_winphone/manifests/8.0/AppxManifest.xml.in +WINRT_MANIFEST.architecture = x64 diff --git a/mkspecs/winrt-x64-msvc2013/qmake.conf b/mkspecs/winrt-x64-msvc2013/qmake.conf index 2c01450ed4..594d0dafd0 100644 --- a/mkspecs/winrt-x64-msvc2013/qmake.conf +++ b/mkspecs/winrt-x64-msvc2013/qmake.conf @@ -19,3 +19,4 @@ MSVC_VER = 12.0 WINSDK_VER = 8.1 WINTARGET_VER = winv6.3 WINRT_MANIFEST = $$PWD/../common/winrt_winphone/manifests/8.1/AppxManifest.xml.in +WINRT_MANIFEST.architecture = x64 diff --git a/mkspecs/winrt-x86-msvc2012/qmake.conf b/mkspecs/winrt-x86-msvc2012/qmake.conf index 664212624c..6e6ea4664d 100644 --- a/mkspecs/winrt-x86-msvc2012/qmake.conf +++ b/mkspecs/winrt-x86-msvc2012/qmake.conf @@ -12,8 +12,9 @@ QMAKE_LFLAGS += /SAFESEH /MACHINE:X86 QMAKE_LIBS += windowscodecs.lib kernel32.lib ole32.lib -VCPROJ_ARCH = x86 +VCPROJ_ARCH = Win32 MSVC_VER = 11.0 WINSDK_VER = 8.0 WINTARGET_VER = win8 WINRT_MANIFEST = $$PWD/../common/winrt_winphone/manifests/8.0/AppxManifest.xml.in +WINRT_MANIFEST.architecture = x86 diff --git a/mkspecs/winrt-x86-msvc2013/qmake.conf b/mkspecs/winrt-x86-msvc2013/qmake.conf index 384b51a1e6..77b906c7d3 100644 --- a/mkspecs/winrt-x86-msvc2013/qmake.conf +++ b/mkspecs/winrt-x86-msvc2013/qmake.conf @@ -14,8 +14,9 @@ QMAKE_LFLAGS += /SAFESEH /MACHINE:X86 QMAKE_LIBS += windowscodecs.lib kernel32.lib ole32.lib -VCPROJ_ARCH = x86 +VCPROJ_ARCH = Win32 MSVC_VER = 12.0 WINSDK_VER = 8.1 WINTARGET_VER = winv6.3 WINRT_MANIFEST = $$PWD/../common/winrt_winphone/manifests/8.1/AppxManifest.xml.in +WINRT_MANIFEST.architecture = x86 diff --git a/qmake/generators/win32/msbuild_objectmodel.cpp b/qmake/generators/win32/msbuild_objectmodel.cpp index f37c3180f4..4f946001bf 100644 --- a/qmake/generators/win32/msbuild_objectmodel.cpp +++ b/qmake/generators/win32/msbuild_objectmodel.cpp @@ -774,6 +774,10 @@ void VCXProjectWriter::write(XmlOutput &xml, VCProject &tool) write(xml, config.preLink); xml << closetag(); + + // windeployqt + if (!config.windeployqt.ExcludedFromBuild) + write(xml, config.windeployqt); } // The file filters are added in a separate file for MSBUILD. @@ -1734,6 +1738,42 @@ void VCXProjectWriter::write(XmlOutput &xml, const VCDeploymentTool &tool) // SmartDevice deployment not supported in VS 2010 } +void VCXProjectWriter::write(XmlOutput &xml, const VCWinDeployQtTool &tool) +{ + const QString name = QStringLiteral("WinDeployQt_") + tool.config->Name; + xml << tag("Target") + << attrTag(_Name, name) + << attrTag("Condition", generateCondition(*tool.config)) + << attrTag("Inputs", "$(OutDir)\\$(TargetName).exe") + << attrTag("Outputs", tool.Record) + << tag(_Message) + << attrTag("Text", tool.CommandLine) + << closetag() + << tag("Exec") + << attrTag("Command", tool.CommandLine) + << closetag() + << closetag() + << tag("Target") + << attrTag(_Name, QStringLiteral("PopulateWinDeployQtItems_") + tool.config->Name) + << attrTag("Condition", generateCondition(*tool.config)) + << attrTag("AfterTargets", "Link") + << attrTag("DependsOnTargets", name) + << tag("ReadLinesFromFile") + << attrTag("File", tool.Record) + << tag("Output") + << attrTag("TaskParameter", "Lines") + << attrTag("ItemName", "DeploymentItems") + << closetag() + << closetag() + << tag(_ItemGroup) + << tag("None") + << attrTag("Include", "@(DeploymentItems)") + << attrTagT("DeploymentContent", _True) + << closetag() + << closetag() + << closetag(); +} + void VCXProjectWriter::write(XmlOutput &xml, const VCConfiguration &tool) { xml << tag("PropertyGroup") diff --git a/qmake/generators/win32/msbuild_objectmodel.h b/qmake/generators/win32/msbuild_objectmodel.h index 7fb83233f4..2f02e66eb9 100644 --- a/qmake/generators/win32/msbuild_objectmodel.h +++ b/qmake/generators/win32/msbuild_objectmodel.h @@ -174,6 +174,7 @@ public: void write(XmlOutput &, const VCResourceCompilerTool &); void write(XmlOutput &, const VCEventTool &); void write(XmlOutput &, const VCDeploymentTool &); + void write(XmlOutput &, const VCWinDeployQtTool &); void write(XmlOutput &, const VCConfiguration &); void write(XmlOutput &, VCFilter &); diff --git a/qmake/generators/win32/msvc_nmake.cpp b/qmake/generators/win32/msvc_nmake.cpp index acccdc1bdc..24465ad152 100644 --- a/qmake/generators/win32/msvc_nmake.cpp +++ b/qmake/generators/win32/msvc_nmake.cpp @@ -123,6 +123,8 @@ NmakeMakefileGenerator::writeMakefile(QTextStream &t) } else if (arch == QStringLiteral("x64")) { compiler = QStringLiteral("x86_amd64"); compilerArch = QStringLiteral("amd64"); + } else { + arch = QStringLiteral("x86"); } const QString msvcVer = project->first("MSVC_VER").toQString(); diff --git a/qmake/generators/win32/msvc_objectmodel.cpp b/qmake/generators/win32/msvc_objectmodel.cpp index 3217500916..1a92b79a09 100644 --- a/qmake/generators/win32/msvc_objectmodel.cpp +++ b/qmake/generators/win32/msvc_objectmodel.cpp @@ -2794,6 +2794,12 @@ void VCProjectWriter::write(XmlOutput &xml, const VCDeploymentTool &tool) << closetag(tool.DeploymentTag); } +void VCProjectWriter::write(XmlOutput &xml, const VCWinDeployQtTool &tool) +{ + Q_UNUSED(xml); + Q_UNUSED(tool); +} + void VCProjectWriter::write(XmlOutput &xml, const VCConfiguration &tool) { xml << tag(_Configuration) diff --git a/qmake/generators/win32/msvc_objectmodel.h b/qmake/generators/win32/msvc_objectmodel.h index 7c51f6a67a..0aa5736d2a 100644 --- a/qmake/generators/win32/msvc_objectmodel.h +++ b/qmake/generators/win32/msvc_objectmodel.h @@ -860,6 +860,24 @@ public: ~VCPreLinkEventTool(){} }; +class VCWinDeployQtTool : public VCToolBase +{ +public: + VCWinDeployQtTool() {} + ~VCWinDeployQtTool() {} + +protected: + bool parseOption(const char *) { return false; } + +public: + // Variables + QString Record; + QString CommandLine; + bool ExcludedFromBuild; + + VCConfiguration * config; +}; + class VCConfiguration { public: @@ -900,6 +918,7 @@ public: VCDeploymentTool deployment; VCPreLinkEventTool preLink; VCResourceCompilerTool resource; + VCWinDeployQtTool windeployqt; }; struct VCFilterFile @@ -1156,6 +1175,7 @@ public: virtual void write(XmlOutput &, const VCResourceCompilerTool &); virtual void write(XmlOutput &, const VCEventTool &); virtual void write(XmlOutput &, const VCDeploymentTool &); + virtual void write(XmlOutput &, const VCWinDeployQtTool &); virtual void write(XmlOutput &, const VCConfiguration &); virtual void write(XmlOutput &, VCFilter &); diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp index 829be89097..ce9dc6d9ec 100644 --- a/qmake/generators/win32/msvc_vcproj.cpp +++ b/qmake/generators/win32/msvc_vcproj.cpp @@ -1021,6 +1021,7 @@ void VcprojGenerator::initConfiguration() if ((!project->isHostBuild() && !project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH")) || conf.WinRT) initDeploymentTool(); + initWinDeployQtTool(); initPreLinkEventTools(); if (!isDebug) @@ -1323,6 +1324,22 @@ void VcprojGenerator::initDeploymentTool() } } +void VcprojGenerator::initWinDeployQtTool() +{ + VCConfiguration &conf = vcProject.Configuration; + conf.windeployqt.ExcludedFromBuild = true; + if (project->isActiveConfig("windeployqt")) { + conf.windeployqt.Record = QStringLiteral("$(TargetName).windeployqt.$(Platform).$(Configuration)"); + conf.windeployqt.CommandLine = + MakefileGenerator::shellQuote(QDir::toNativeSeparators(project->first("QMAKE_WINDEPLOYQT").toQString())) + + QLatin1Char(' ') + project->values("WINDEPLOYQT_OPTIONS").join(QLatin1Char(' ')) + + QStringLiteral(" -list relative -dir \"$(MSBuildProjectDirectory)\" \"$(OutDir)\\$(TargetName).exe\" > ") + + MakefileGenerator::shellQuote(conf.windeployqt.Record); + conf.windeployqt.config = &vcProject.Configuration; + conf.windeployqt.ExcludedFromBuild = false; + } +} + void VcprojGenerator::initPreLinkEventTools() { VCConfiguration &conf = vcProject.Configuration; diff --git a/qmake/generators/win32/msvc_vcproj.h b/qmake/generators/win32/msvc_vcproj.h index d531085307..4a25d11766 100644 --- a/qmake/generators/win32/msvc_vcproj.h +++ b/qmake/generators/win32/msvc_vcproj.h @@ -109,6 +109,7 @@ protected: void initPreBuildEventTools(); void initPostBuildEventTools(); void initDeploymentTool(); + void initWinDeployQtTool(); void initPreLinkEventTools(); void initRootFiles(); void initSourceFiles(); diff --git a/src/corelib/codecs/qutfcodec.cpp b/src/corelib/codecs/qutfcodec.cpp index 20bacb1584..a5d16b0b54 100644 --- a/src/corelib/codecs/qutfcodec.cpp +++ b/src/corelib/codecs/qutfcodec.cpp @@ -46,6 +46,7 @@ #include "qchar.h" #include "private/qsimd_p.h" +#include "private/qstringiterator_p.h" QT_BEGIN_NAMESPACE @@ -503,21 +504,21 @@ QByteArray QUtf32::convertFromUnicode(const QChar *uc, int len, QTextCodec::Conv } data += 4; } + + QStringIterator i(uc, uc + len); if (endian == BigEndianness) { - for (int i = 0; i < len; ++i) { - uint cp = uc[i].unicode(); - if (uc[i].isHighSurrogate() && i < len - 1) - cp = QChar::surrogateToUcs4(cp, uc[++i].unicode()); + while (i.hasNext()) { + uint cp = i.next(); + *(data++) = cp >> 24; *(data++) = (cp >> 16) & 0xff; *(data++) = (cp >> 8) & 0xff; *(data++) = cp & 0xff; } } else { - for (int i = 0; i < len; ++i) { - uint cp = uc[i].unicode(); - if (uc[i].isHighSurrogate() && i < len - 1) - cp = QChar::surrogateToUcs4(cp, uc[++i].unicode()); + while (i.hasNext()) { + uint cp = i.next(); + *(data++) = cp & 0xff; *(data++) = (cp >> 8) & 0xff; *(data++) = (cp >> 16) & 0xff; diff --git a/src/corelib/doc/snippets/code/src_corelib_tools_qstringiterator.cpp b/src/corelib/doc/snippets/code/src_corelib_tools_qstringiterator.cpp new file mode 100644 index 0000000000..178c6feb0a --- /dev/null +++ b/src/corelib/doc/snippets/code/src_corelib_tools_qstringiterator.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QString> +#include <QStringIterator> +#include <QDebug> + +int main() +{ + +{ +//! [0] +QString string(QStringLiteral("a string")); +QStringIterator i(string); +//! [0] + +//! [1] +// will print 97, 32, 115, 116, etc.; +// that is, the decimal value of the code points in the Unicode string "a string" +while (i.hasNext()) + qDebug() << i.next(); +//! [1] +} + +{ +//! [2] +QString string(QStringLiteral("𝄞 is the G clef")); +QStringIterator i(string); +qDebug() << hex << i.next(); // will print 1d11e (U+1D11E, MUSICAL SYMBOL G CLEF) +qDebug() << hex << i.next(); // will print 20 (U+0020, SPACE) +qDebug() << hex << i.next(); // will print 69 (U+0069, LATIN SMALL LETTER I) +//! [2] +} + +} diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index 10b0d63fb0..64dd544cf0 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -322,6 +322,8 @@ void QMessageLogger::debug(QMessageLogger::CategoryFunction catFunc, const char *msg, ...) const { const QLoggingCategory &cat = (*catFunc)(); + if (!cat.isDebugEnabled()) + return; QMessageLogContext ctxt; ctxt.copy(context); diff --git a/src/corelib/global/qprocessordetection.h b/src/corelib/global/qprocessordetection.h index a5eff7c7ce..cf7ee1b7aa 100644 --- a/src/corelib/global/qprocessordetection.h +++ b/src/corelib/global/qprocessordetection.h @@ -331,8 +331,7 @@ the size of the register). On some architectures where a pointer could be smaller than the register, the macro is defined above. - Try our best to define it to a literal, so it can be used in the preprocessor, - but fall back to sizeof(void*) on practically every 32-bit build. + Falls back to QT_POINTER_SIZE if not set explicitly for the platform. */ #ifndef Q_PROCESSOR_WORDSIZE # ifdef __SIZEOF_POINTER__ @@ -341,7 +340,7 @@ # elif defined(_LP64) || defined(__LP64__) || defined(WIN64) || defined(_WIN64) # define Q_PROCESSOR_WORDSIZE 8 # else -# define Q_PROCESSOR_WORDSIZE sizeof(void*) +# define Q_PROCESSOR_WORDSIZE QT_POINTER_SIZE # endif #endif diff --git a/src/corelib/io/qloggingcategory.cpp b/src/corelib/io/qloggingcategory.cpp index de77dd9a6e..5fa346dce5 100644 --- a/src/corelib/io/qloggingcategory.cpp +++ b/src/corelib/io/qloggingcategory.cpp @@ -83,9 +83,8 @@ Q_GLOBAL_STATIC_WITH_ARGS(QLoggingCategory, qtDefaultCategory, \section1 Default category configuration - In the default configuration \l isWarningEnabled() and \l isCriticalEnabled() - will return \c true. \l isDebugEnabled() will return \c true only - for the \c "default" category. + In the default configuration \l isWarningEnabled() , \l isDebugEnabled() and + \l isCriticalEnabled() will return \c true. \section1 Changing the configuration of a category @@ -111,21 +110,20 @@ Q_GLOBAL_STATIC_WITH_ARGS(QLoggingCategory, qtDefaultCategory, QLoggingCategory::QLoggingCategory(const char *category) : d(0), name(0), - enabledDebug(false), + enabledDebug(true), enabledWarning(true), enabledCritical(true) { Q_UNUSED(d); Q_UNUSED(placeholder); - bool isDefaultCategory + const bool isDefaultCategory = (category == 0) || (strcmp(category, qtDefaultCategoryName) == 0); + // normalize "default" category name, so that we can just do + // pointer comparison in QLoggingRegistry::updateCategory if (isDefaultCategory) { - // normalize default category names, so that we can just do - // pointer comparison in QLoggingRegistry::updateCategory name = qtDefaultCategoryName; - enabledDebug = true; } else { name = category; } diff --git a/src/corelib/io/qloggingregistry.cpp b/src/corelib/io/qloggingregistry.cpp index a82e6f65f4..fd25ff697e 100644 --- a/src/corelib/io/qloggingregistry.cpp +++ b/src/corelib/io/qloggingregistry.cpp @@ -283,9 +283,13 @@ QLoggingRegistry *QLoggingRegistry::instance() */ void QLoggingRegistry::defaultCategoryFilter(QLoggingCategory *cat) { - // QLoggingCategory() normalizes all "default" strings + // QLoggingCategory() normalizes "default" strings // to qtDefaultCategoryName - bool debug = (cat->categoryName() == qtDefaultCategoryName); + bool debug = true; + char c; + if (!memcmp(cat->categoryName(), "qt", 2) && (!(c = cat->categoryName()[2]) || c == '.')) + debug = false; + bool warning = true; bool critical = true; diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 3118034b88..d5d964eaec 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -186,6 +186,8 @@ void QCoreApplicationPrivate::processCommandLineArguments() continue; } QByteArray arg = argv[i]; + if (arg.startsWith("--")) + arg.remove(0, 1); if (arg.startsWith("-qmljsdebugger=")) { qmljs_debug_arguments = QString::fromLocal8Bit(arg.right(arg.length() - 15)); } else if (arg == "-qmljsdebugger" && i < argc - 1) { diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index 03c5b943d6..db5c13157c 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -442,7 +442,7 @@ void QThreadPrivate::finish(void *arg, bool lockAnyway) #ifndef Q_OS_WINRT CloseHandle(d->handle); #else - CloseHandle(d->handle->native_handle()); + d->handle->detach(); delete d->handle; #endif d->handle = 0; @@ -642,8 +642,6 @@ void QThread::terminate() TerminateThread(d->handle, 0); #else // !Q_OS_WINRT qWarning("QThread::terminate: Terminate is not supported on WinRT"); - CloseHandle(d->handle->native_handle()); - d->handle = 0; #endif // Q_OS_WINRT QThreadPrivate::finish(this, false); } @@ -683,7 +681,8 @@ bool QThread::wait(unsigned long time) } #else // !Q_OS_WINRT if (d->handle->joinable()) { - switch (WaitForSingleObjectEx(d->handle->native_handle(), time, FALSE)) { + HANDLE handle = d->handle->native_handle(); + switch (WaitForSingleObjectEx(handle, time, FALSE)) { case WAIT_OBJECT_0: ret = true; d->handle->join(); @@ -712,6 +711,7 @@ bool QThread::wait(unsigned long time) #ifndef Q_OS_WINRT CloseHandle(d->handle); #else + d->handle->detach(); delete d->handle; #endif d->handle = 0; diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index 6d2cba7703..e38a5f569a 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -2208,7 +2208,17 @@ static int qt_timezone() time_t clock = time(NULL); struct tm t; localtime_r(&clock, &t); - return t.tm_gmtoff; + // QTBUG-36080 Workaround for systems without the POSIX timezone + // variable. This solution is not very efficient but fixing it is up to + // the libc implementations. + // + // tm_gmtoff has some important differences compared to the timezone + // variable: + // - It returns the number of seconds east of UTC, and we want the + // number of seconds west of UTC. + // - It also takes DST into account, so we need to adjust it to always + // get the Standard Time offset. + return -t.tm_gmtoff + (t.tm_isdst ? SECS_PER_HOUR : 0L); #else return timezone; #endif // Q_OS_WIN diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index f5e25f1de9..9f939dd795 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -54,6 +54,7 @@ #include <qlist.h> #include "qlocale.h" #include "qlocale_p.h" +#include "qstringbuilder.h" #include "qstringmatcher.h" #include "qvarlengtharray.h" #include "qtools_p.h" @@ -76,6 +77,7 @@ #include "qchar.cpp" #include "qstringmatcher.cpp" +#include "qstringiterator_p.h" #ifdef Q_OS_WIN # include <qt_windows.h> @@ -188,6 +190,16 @@ template <uint MaxCount> struct UnrollTailLoop return UnrollTailLoop<MaxCount - 1>::exec(count - 1, returnIfExited, loopCheck, returnIfFailed, i + 1); } + + template <typename Functor> + static inline void exec(int count, Functor code) + { + /* equivalent to: + * for (int i = 0; i < count; ++i) + * code(i); + */ + exec(count, 0, [=](int i) -> bool { code(i); return false; }, [](int) { return 0; }); + } }; template <> template <typename RetType, typename Functor1, typename Functor2> inline RetType UnrollTailLoop<0>::exec(int, RetType returnIfExited, Functor1, Functor2, int) @@ -205,25 +217,29 @@ static void qt_from_latin1(ushort *dst, const char *str, size_t size) * The same method gives no improvement with NEON. */ #if defined(__SSE2__) - if (size >= 16) { - int chunkCount = size >> 4; // divided by 16 + const char *e = str + size; + qptrdiff offset = 0; + + // we're going to read str[offset..offset+15] (16 bytes) + for ( ; str + offset + 15 < e; offset += 16) { const __m128i nullMask = _mm_set1_epi32(0); - for (int i = 0; i < chunkCount; ++i) { - const __m128i chunk = _mm_loadu_si128((__m128i*)str); // load - str += 16; + const __m128i chunk = _mm_loadu_si128((__m128i*)(str + offset)); // load - // unpack the first 8 bytes, padding with zeros - const __m128i firstHalf = _mm_unpacklo_epi8(chunk, nullMask); - _mm_storeu_si128((__m128i*)dst, firstHalf); // store - dst += 8; + // unpack the first 8 bytes, padding with zeros + const __m128i firstHalf = _mm_unpacklo_epi8(chunk, nullMask); + _mm_storeu_si128((__m128i*)(dst + offset), firstHalf); // store - // unpack the last 8 bytes, padding with zeros - const __m128i secondHalf = _mm_unpackhi_epi8 (chunk, nullMask); - _mm_storeu_si128((__m128i*)dst, secondHalf); // store - dst += 8; - } - size = size % 16; + // unpack the last 8 bytes, padding with zeros + const __m128i secondHalf = _mm_unpackhi_epi8 (chunk, nullMask); + _mm_storeu_si128((__m128i*)(dst + offset + 8), secondHalf); // store } + + size = size % 16; + dst += offset; + str += offset; +# ifdef Q_COMPILER_LAMBDA + return UnrollTailLoop<15>::exec(size, [=](int i) { dst[i] = (uchar)str[i]; }); +# endif #endif #if defined(__mips_dsp) if (size > 20) @@ -293,61 +309,62 @@ static inline __m128i mergeQuestionMarks(__m128i chunk) static void qt_to_latin1(uchar *dst, const ushort *src, int length) { - if (length) { #if defined(__SSE2__) - if (length >= 16) { - const int chunkCount = length >> 4; // divided by 16 + uchar *e = dst + length; + qptrdiff offset = 0; - for (int i = 0; i < chunkCount; ++i) { - __m128i chunk1 = _mm_loadu_si128((__m128i*)src); // load - chunk1 = mergeQuestionMarks(chunk1); - src += 8; + // we're going to write to dst[offset..offset+15] (16 bytes) + for ( ; dst + offset + 15 < e; offset += 16) { + __m128i chunk1 = _mm_loadu_si128((__m128i*)(src + offset)); // load + chunk1 = mergeQuestionMarks(chunk1); - __m128i chunk2 = _mm_loadu_si128((__m128i*)src); // load - chunk2 = mergeQuestionMarks(chunk2); - src += 8; + __m128i chunk2 = _mm_loadu_si128((__m128i*)(src + offset + 8)); // load + chunk2 = mergeQuestionMarks(chunk2); - // pack the two vector to 16 x 8bits elements - const __m128i result = _mm_packus_epi16(chunk1, chunk2); + // pack the two vector to 16 x 8bits elements + const __m128i result = _mm_packus_epi16(chunk1, chunk2); + _mm_storeu_si128((__m128i*)(dst + offset), result); // store + } - _mm_storeu_si128((__m128i*)dst, result); // store - dst += 16; - } - length = length % 16; - } + length = length % 16; + dst += offset; + src += offset; + +# ifdef Q_COMPILER_LAMBDA + return UnrollTailLoop<15>::exec(length, [=](int i) { dst[i] = (src[i]>0xff) ? '?' : (uchar) src[i]; }); +# endif #elif defined(__ARM_NEON__) - // Refer to the documentation of the SSE2 implementation - // this use eactly the same method as for SSE except: - // 1) neon has unsigned comparison - // 2) packing is done to 64 bits (8 x 8bits component). - if (length >= 16) { - const int chunkCount = length >> 3; // divided by 8 - const uint16x8_t questionMark = vdupq_n_u16('?'); // set - const uint16x8_t thresholdMask = vdupq_n_u16(0xff); // set - for (int i = 0; i < chunkCount; ++i) { - uint16x8_t chunk = vld1q_u16((uint16_t *)src); // load - src += 8; - - const uint16x8_t offLimitMask = vcgtq_u16(chunk, thresholdMask); // chunk > thresholdMask - const uint16x8_t offLimitQuestionMark = vandq_u16(offLimitMask, questionMark); // offLimitMask & questionMark - const uint16x8_t correctBytes = vbicq_u16(chunk, offLimitMask); // !offLimitMask & chunk - chunk = vorrq_u16(correctBytes, offLimitQuestionMark); // correctBytes | offLimitQuestionMark - const uint8x8_t result = vmovn_u16(chunk); // narrowing move->packing - vst1_u8(dst, result); // store - dst += 8; - } - length = length % 8; + // Refer to the documentation of the SSE2 implementation + // this use eactly the same method as for SSE except: + // 1) neon has unsigned comparison + // 2) packing is done to 64 bits (8 x 8bits component). + if (length >= 16) { + const int chunkCount = length >> 3; // divided by 8 + const uint16x8_t questionMark = vdupq_n_u16('?'); // set + const uint16x8_t thresholdMask = vdupq_n_u16(0xff); // set + for (int i = 0; i < chunkCount; ++i) { + uint16x8_t chunk = vld1q_u16((uint16_t *)src); // load + src += 8; + + const uint16x8_t offLimitMask = vcgtq_u16(chunk, thresholdMask); // chunk > thresholdMask + const uint16x8_t offLimitQuestionMark = vandq_u16(offLimitMask, questionMark); // offLimitMask & questionMark + const uint16x8_t correctBytes = vbicq_u16(chunk, offLimitMask); // !offLimitMask & chunk + chunk = vorrq_u16(correctBytes, offLimitQuestionMark); // correctBytes | offLimitQuestionMark + const uint8x8_t result = vmovn_u16(chunk); // narrowing move->packing + vst1_u8(dst, result); // store + dst += 8; } + length = length % 8; + } #endif #if defined(__mips_dsp) - qt_toLatin1_mips_dsp_asm(dst, src, length); + qt_toLatin1_mips_dsp_asm(dst, src, length); #else - while (length--) { - *dst++ = (*src>0xff) ? '?' : (uchar) *src; - ++src; - } -#endif + while (length--) { + *dst++ = (*src>0xff) ? '?' : (uchar) *src; + ++src; } +#endif } // Unicode case-insensitive comparison @@ -1325,21 +1342,13 @@ const QString::Null QString::null = { }; int QString::toUcs4_helper(const ushort *uc, int length, uint *out) { - int i = 0; - const ushort *const e = uc + length; - while (uc < e) { - uint u = *uc; - if (QChar::isHighSurrogate(u) && uc + 1 < e) { - ushort low = uc[1]; - if (QChar::isLowSurrogate(low)) { - ++uc; - u = QChar::surrogateToUcs4(u, low); - } - } - out[i++] = u; - ++uc; - } - return i; + int count = 0; + + QStringIterator i(reinterpret_cast<const QChar *>(uc), reinterpret_cast<const QChar *>(uc + length)); + while (i.hasNext()) + out[count++] = i.next(); + + return count; } /*! \fn int QString::toWCharArray(wchar_t *array) const @@ -4315,8 +4324,12 @@ QByteArray QString::toUtf8_helper(const QString &str) Returns a UCS-4/UTF-32 representation of the string as a QVector<uint>. - UCS-4 is a Unicode codec and is lossless. All characters from this string - can be encoded in UCS-4. The vector is not null terminated. + UCS-4 is a Unicode codec and therefore it is lossless. All characters from + this string will be encoded in UCS-4. Any invalid sequence of code units in + this string is replaced by the Unicode's replacement character + (QChar::ReplacementCharacter, which corresponds to \c{U+FFFD}). + + The returned vector is not NUL terminated. \sa fromUtf8(), toUtf8(), toLatin1(), toLocal8Bit(), QTextCodec, fromUcs4(), toWCharArray() */ @@ -9529,8 +9542,12 @@ QByteArray QStringRef::toUtf8() const Returns a UCS-4/UTF-32 representation of the string as a QVector<uint>. - UCS-4 is a Unicode codec and is lossless. All characters from this string - can be encoded in UCS-4. + UCS-4 is a Unicode codec and therefore it is lossless. All characters from + this string will be encoded in UCS-4. Any invalid sequence of code units in + this string is replaced by the Unicode's replacement character + (QChar::ReplacementCharacter, which corresponds to \c{U+FFFD}). + + The returned vector is not NUL terminated. \sa toUtf8(), toLatin1(), toLocal8Bit(), QTextCodec */ @@ -9987,4 +10004,13 @@ QString QString::toHtmlEscaped() const \endlist */ + +/*! + \internal + */ +void QAbstractConcatenable::appendLatin1To(const char *a, int len, QChar *out) +{ + qt_from_latin1(reinterpret_cast<ushort *>(out), a, uint(len)); +} + QT_END_NAMESPACE diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index 0b7ca1f444..8fb817d519 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -505,6 +505,13 @@ public: static QString fromUcs4(const uint *, int size = -1); static QString fromRawData(const QChar *, int size); +#if defined(Q_COMPILER_UNICODE_STRINGS) + static QString fromUtf16(const char16_t *str, int size = -1) + { return fromUtf16(reinterpret_cast<const ushort *>(str), size); } + static QString fromUcs4(const char32_t *str, int size = -1) + { return fromUcs4(reinterpret_cast<const uint *>(str), size); } +#endif + #if QT_DEPRECATED_SINCE(5, 0) QT_DEPRECATED static inline QString fromAscii(const char *str, int size = -1) { return fromLatin1(str, size); } diff --git a/src/corelib/tools/qstringbuilder.h b/src/corelib/tools/qstringbuilder.h index 489357f5fd..f0670999d7 100644 --- a/src/corelib/tools/qstringbuilder.h +++ b/src/corelib/tools/qstringbuilder.h @@ -65,6 +65,7 @@ protected: { *out++ = QLatin1Char(a); } + static void appendLatin1To(const char *a, int len, QChar *out); }; template <typename T> struct QConcatenable {}; @@ -222,7 +223,7 @@ template <> struct QConcatenable<QCharRef> : private QAbstractConcatenable { *out++ = QChar(c); } }; -template <> struct QConcatenable<QLatin1String> +template <> struct QConcatenable<QLatin1String> : private QAbstractConcatenable { typedef QLatin1String type; typedef QString ConvertTo; @@ -230,10 +231,8 @@ template <> struct QConcatenable<QLatin1String> static int size(const QLatin1String a) { return a.size(); } static inline void appendTo(const QLatin1String a, QChar *&out) { - if (a.data()) { - for (const char *s = a.data(); *s; ) - *out++ = QLatin1Char(*s++); - } + appendLatin1To(a.latin1(), a.size(), out); + out += a.size(); } static inline void appendTo(const QLatin1String a, char *&out) { diff --git a/src/corelib/tools/qstringiterator.qdoc b/src/corelib/tools/qstringiterator.qdoc new file mode 100644 index 0000000000..510d5fbccf --- /dev/null +++ b/src/corelib/tools/qstringiterator.qdoc @@ -0,0 +1,328 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QStringIterator + \since 5.3 + \inmodule QtCore + \ingroup tools + + \internal + + \brief The QStringIterator class provides a Unicode-aware iterator over QString. + + \reentrant + + QStringIterator is a Java-like, bidirectional, const iterator over the contents of a + QString. Unlike QString's own iterators, which manage the individual UTF-16 code units, + QStringIterator is Unicode-aware: it will transparently handle the \e{surrogate pairs} + that may be present in a QString, and return the individual Unicode code points. + + You can create a QStringIterator that iterates over a given + QString by passing the string to the QStringIterator's constructor: + + \snippet code/src_corelib_tools_qstringiterator.cpp 0 + + A newly created QStringIterator will point before the first position in the + string. It is possible to check whether the iterator can be advanced by + calling hasNext(), and actually advance it (and obtain the next code point) + by calling next(): + + \snippet code/src_corelib_tools_qstringiterator.cpp 1 + + Similarly, the hasPrevious() and previous() functions can be used to iterate backwards. + + The peekNext() and peekPrevious() functions will return the code point + respectively after and behind the iterator's current position, but unlike + next() and previous() they will not move the iterator. + Similarly, the advance() and recede() functions will move the iterator + respectively after and behind the iterator's current position, but they + will not return the code point the iterator has moved through. + + \section1 Unicode handling + + QString and all of its functions work in terms of UTF-16 code units. Unicode code points + that fall outside the Basic Multilingual Plane (U+10000 to U+10FFFF) will therefore + be represented by \e{surrogate pairs} in a QString, that is, a sequence of two + UTF-16 code units that encode a single code point. + + QStringIterator will automatically handle surrogate pairs inside a QString, + and return the correctly decoded code point, while also moving the iterator by + the right amount of code units to match the decoded code points. + + For instance: + + \snippet code/src_corelib_tools_qstringiterator.cpp 2 + + If the iterator is not able to decode the next code point (or the previous + one, when iterating backwards), then it will return \c{0xFFFD}, that is, + Unicode's replacement character (see QChar::ReplacementCharacter). + It is possible to make QStringIterator return another value when it encounters + a decoding problem; please refer to the each function documentation for + more details. + + \section1 Unchecked iteration + + It is possible to optimize iterating over a QString contents by skipping + some checks. This is in general not safe to do, because a QString is allowed + to contain malformed UTF-16 data; however, if we can trust a given QString, + then we can use the optimized \e{unchecked} functions. + + QStringIterator provides the \e{unchecked} counterparts for next(), + peekNext(), advance(), previous(), peekPrevious(), and recede(): + they're called, respectively, + nextUnchecked(), peekNextUnchecked(), advanceUnchecked(), + previousUnchecked(), peekPreviousUnchecked(), recedeUnchecked(). + The counterparts work exactly like the original ones, + but they're faster as they're allowed to make certain assumptions about + the string contents. + + \note please be extremely careful when using QStringIterator's unchecked functions, + as using them on a string containing malformed data leads to undefined behavior. + + \sa QString, QChar +*/ + +/*! + \fn QStringIterator::QStringIterator(const QString &string) + + Constructs an iterator over the contents of \a string. The iterator will point + before the first position in the string. + + The string \a string must remain valid while the iterator is being used. +*/ + +/*! + \fn QStringIterator::QStringIterator(const QChar *begin, const QChar *end) + + Constructs an iterator which iterates over the range from \a begin to \a end. + The iterator will point before \a begin. + + The range from \a begin to \a end must remain valid while the iterator is being used. +*/ + +/*! + \fn QString::const_iterator QStringIterator::position() const + + Returns the current position of the iterator. +*/ + +/*! + \fn void QStringIterator::setPosition(QString::const_iterator position) + + Sets the iterator's current position to \a position, which must be inside + of the iterable range. +*/ + +/*! + \fn bool QStringIterator::hasNext() const + + Returns true if the iterator has not reached the end of the valid iterable range + and therefore can move forward; false otherwise. + + \sa next() +*/ + +/*! + \fn void QStringIterator::advance() + + Advances the iterator by one Unicode code point. + + \note calling this function when the iterator is past the end of the iterable range + leads to undefined behavior. + + \sa next(), hasNext() +*/ + +/*! + \fn void QStringIterator::advanceUnchecked() + + Advances the iterator by one Unicode code point. + + \note calling this function when the iterator is past the end of the iterable range + or on a QString containing malformed UTF-16 data leads to undefined behavior. + + \sa advance(), next(), hasNext() +*/ + +/*! + \fn uint QStringIterator::peekNextUnchecked() const + + Returns the Unicode code point that is immediately after the iterator's current + position. The current position is not changed. + + \note calling this function when the iterator is past the end of the iterable range + or on a QString containing malformed UTF-16 data leads to undefined behavior. + + \sa peekNext(), next(), hasNext() +*/ + +/*! + \fn uint QStringIterator::peekNext(uint invalidAs = QChar::ReplacementCharacter) const + + Returns the Unicode code point that is immediately after the iterator's current + position. The current position is not changed. + + If the iterator is not able to decode the UTF-16 data after the iterator's current + position, this function returns \a invalidAs (by default, QChar::ReplacementCharacter, + which corresponds to \c{U+FFFD}). + + \note calling this function when the iterator is past the end of the iterable range + leads to undefined behavior. + + \sa next(), hasNext() +*/ + +/*! + \fn uint QStringIterator::nextUnchecked() + + Advances the iterator's current position by one Unicode code point, + and returns the Unicode code point that gets pointed by the iterator. + + \note calling this function when the iterator is past the end of the iterable range + or on a QString containing malformed UTF-16 data leads to undefined behavior. + + \sa next(), hasNext() +*/ + +/*! + \fn uint QStringIterator::next(uint invalidAs = QChar::ReplacementCharacter) + + Advances the iterator's current position by one Unicode code point, + and returns the Unicode code point that gets pointed by the iterator. + + If the iterator is not able to decode the UTF-16 data at the iterator's current + position, this function returns \a invalidAs (by default, QChar::ReplacementCharacter, + which corresponds to \c{U+FFFD}). + + \note calling this function when the iterator is past the end of the iterable range + leads to undefined behavior. + + \sa peekNext(), hasNext() +*/ + + +/*! + \fn bool QStringIterator::hasPrevious() const + + Returns true if the iterator is after the beginning of the valid iterable range + and therefore can move backwards; false otherwise. + + \sa previous() +*/ + +/*! + \fn void QStringIterator::recede() + + Moves the iterator back by one Unicode code point. + + \note calling this function when the iterator is before the beginning of the iterable range + leads to undefined behavior. + + \sa previous(), hasPrevious() +*/ + +/*! + \fn void QStringIterator::recedeUnchecked() + + Moves the iterator back by one Unicode code point. + + \note calling this function when the iterator is before the beginning of the iterable range + or on a QString containing malformed UTF-16 data leads to undefined behavior. + + \sa recede(), previous(), hasPrevious() +*/ + +/*! + \fn uint QStringIterator::peekPreviousUnchecked() const + + Returns the Unicode code point that is immediately before the iterator's current + position. The current position is not changed. + + \note calling this function when the iterator is before the beginning of the iterable range + or on a QString containing malformed UTF-16 data leads to undefined behavior. + + \sa previous(), hasPrevious() +*/ + +/*! + \fn uint QStringIterator::peekPrevious(uint invalidAs = QChar::ReplacementCharacter) const + + Returns the Unicode code point that is immediately before the iterator's current + position. The current position is not changed. + + If the iterator is not able to decode the UTF-16 data before the iterator's current + position, this function returns \a invalidAs (by default, QChar::ReplacementCharacter, + which corresponds to \c{U+FFFD}). + + \note calling this function when the iterator is before the beginning of the iterable range + leads to undefined behavior. + + \sa previous(), hasPrevious() +*/ + +/*! + \fn uint QStringIterator::previousUnchecked() + + Moves the iterator's current position back by one Unicode code point, + and returns the Unicode code point that gets pointed by the iterator. + + \note calling this function when the iterator is before the beginning of the iterable range + or on a QString containing malformed UTF-16 data leads to undefined behavior. + + \sa previous(), hasPrevious() +*/ + +/*! + \fn uint QStringIterator::previous(uint invalidAs = QChar::ReplacementCharacter) + + Moves the iterator's current position back by one Unicode code point, + and returns the Unicode code point that gets pointed by the iterator. + + If the iterator is not able to decode the UTF-16 data at the iterator's current + position, this function returns \a invalidAs (by default, QChar::ReplacementCharacter, + which corresponds to \c{U+FFFD}). + + \note calling this function when the iterator is before the beginning of the iterable range + leads to undefined behavior. + + \sa peekPrevious(), hasPrevious() +*/ diff --git a/src/corelib/tools/qstringiterator_p.h b/src/corelib/tools/qstringiterator_p.h new file mode 100644 index 0000000000..c3986f0477 --- /dev/null +++ b/src/corelib/tools/qstringiterator_p.h @@ -0,0 +1,233 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSTRINGITERATOR_H +#define QSTRINGITERATOR_H + +#include <QtCore/qstring.h> + +QT_BEGIN_NAMESPACE + +class QStringIterator +{ + QString::const_iterator i, pos, e; + +public: + inline explicit QStringIterator(const QString &string) + : i(string.constBegin()), + pos(string.constBegin()), + e(string.constEnd()) + { + } + + inline explicit QStringIterator(const QChar *begin, const QChar *end) + : i(begin), + pos(begin), + e(end) + { + } + + inline QString::const_iterator position() const + { + return pos; + } + + inline void setPosition(QString::const_iterator position) + { + Q_ASSERT_X(i <= position && position <= e, Q_FUNC_INFO, "position out of bounds"); + pos = position; + } + + // forward iteration + + inline bool hasNext() const + { + return pos < e; + } + + inline void advance() + { + Q_ASSERT_X(hasNext(), Q_FUNC_INFO, "iterator hasn't a next item"); + + if (Q_UNLIKELY((pos++)->isHighSurrogate())) { + if (Q_LIKELY(pos != e && pos->isLowSurrogate())) + ++pos; + } + } + + inline void advanceUnchecked() + { + Q_ASSERT_X(hasNext(), Q_FUNC_INFO, "iterator hasn't a next item"); + + if (Q_UNLIKELY((pos++)->isHighSurrogate())) + ++pos; + } + + inline uint peekNextUnchecked() const + { + Q_ASSERT_X(hasNext(), Q_FUNC_INFO, "iterator hasn't a next item"); + + if (Q_UNLIKELY(pos->isHighSurrogate())) + return QChar::surrogateToUcs4(pos[0], pos[1]); + + return pos->unicode(); + } + + inline uint peekNext(uint invalidAs = QChar::ReplacementCharacter) const + { + Q_ASSERT_X(hasNext(), Q_FUNC_INFO, "iterator hasn't a next item"); + + if (Q_UNLIKELY(pos->isSurrogate())) { + if (Q_LIKELY(pos->isHighSurrogate())) { + const QChar *low = pos + 1; + if (Q_LIKELY(low != e && low->isLowSurrogate())) + return QChar::surrogateToUcs4(*pos, *low); + } + return invalidAs; + } + + return pos->unicode(); + } + + inline uint nextUnchecked() + { + Q_ASSERT_X(hasNext(), Q_FUNC_INFO, "iterator hasn't a next item"); + + const QChar cur = *pos++; + if (Q_UNLIKELY(cur.isHighSurrogate())) + return QChar::surrogateToUcs4(cur, *pos++); + return cur.unicode(); + } + + inline uint next(uint invalidAs = QChar::ReplacementCharacter) + { + Q_ASSERT_X(hasNext(), Q_FUNC_INFO, "iterator hasn't a next item"); + + const QChar uc = *pos++; + if (Q_UNLIKELY(uc.isSurrogate())) { + if (Q_LIKELY(uc.isHighSurrogate() && pos < e && pos->isLowSurrogate())) + return QChar::surrogateToUcs4(uc, *pos++); + return invalidAs; + } + + return uc.unicode(); + } + + // backwards iteration + + inline bool hasPrevious() const + { + return pos > i; + } + + inline void recede() + { + Q_ASSERT_X(hasPrevious(), Q_FUNC_INFO, "iterator hasn't a previous item"); + + if (Q_UNLIKELY((--pos)->isLowSurrogate())) { + const QChar *high = pos - 1; + if (Q_LIKELY(high != i - 1 && high->isHighSurrogate())) + --pos; + } + } + + inline void recedeUnchecked() + { + Q_ASSERT_X(hasPrevious(), Q_FUNC_INFO, "iterator hasn't a previous item"); + + if (Q_UNLIKELY((--pos)->isLowSurrogate())) + --pos; + } + + inline uint peekPreviousUnchecked() const + { + Q_ASSERT_X(hasPrevious(), Q_FUNC_INFO, "iterator hasn't a previous item"); + + if (Q_UNLIKELY(pos[-1].isLowSurrogate())) + return QChar::surrogateToUcs4(pos[-2], pos[-1]); + return pos[-1].unicode(); + } + + inline uint peekPrevious(uint invalidAs = QChar::ReplacementCharacter) const + { + Q_ASSERT_X(hasPrevious(), Q_FUNC_INFO, "iterator hasn't a previous item"); + + if (Q_UNLIKELY(pos[-1].isSurrogate())) { + if (Q_LIKELY(pos[-1].isLowSurrogate())) { + const QChar *high = pos - 2; + if (Q_LIKELY(high != i - 1 && high->isHighSurrogate())) + return QChar::surrogateToUcs4(*high, pos[-1]); + } + return invalidAs; + } + + return pos[-1].unicode(); + } + + inline uint previousUnchecked() + { + Q_ASSERT_X(hasPrevious(), Q_FUNC_INFO, "iterator hasn't a previous item"); + + const QChar cur = *--pos; + if (Q_UNLIKELY(cur.isLowSurrogate())) + return QChar::surrogateToUcs4(*--pos, cur); + return cur.unicode(); + } + + inline uint previous(uint invalidAs = QChar::ReplacementCharacter) + { + Q_ASSERT_X(hasPrevious(), Q_FUNC_INFO, "iterator hasn't a previous item"); + + const QChar uc = *--pos; + if (Q_UNLIKELY(uc.isSurrogate())) { + if (Q_LIKELY(uc.isLowSurrogate() && pos > i && pos[-1].isHighSurrogate())) + return QChar::surrogateToUcs4(*--pos, uc); + return invalidAs; + } + + return uc.unicode(); + } +}; + +QT_END_NAMESPACE + +#endif // QSTRINGITERATOR_H diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index ba995b047d..4ebd6ccd66 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -56,6 +56,7 @@ HEADERS += \ tools/qstack.h \ tools/qstring.h \ tools/qstringbuilder.h \ + tools/qstringiterator_p.h \ tools/qstringlist.h \ tools/qstringmatcher.h \ tools/qtextboundaryfinder.h \ diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index f549a04dfb..48c262ae7a 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -1719,7 +1719,7 @@ void QImage::fill(const QColor &color) if (d->depth == 32) { uint pixel = color.rgba(); if (d->format == QImage::Format_ARGB32_Premultiplied || d->format == QImage::Format_RGBA8888_Premultiplied) - pixel = PREMUL(pixel); + pixel = qPremultiply(pixel); fill((uint) pixel); } else if (d->format == QImage::Format_RGB16) { @@ -2204,17 +2204,17 @@ void QImage::setPixel(int x, int y, uint index_or_rgb) case Format_RGB32: //make sure alpha is 255, we depend on it in qdrawhelper for cases // when image is set as a texture pattern on a qbrush - ((uint *)s)[x] = uint(255 << 24) | index_or_rgb; + ((uint *)s)[x] = 0xff000000 | index_or_rgb; return; case Format_ARGB32: case Format_ARGB32_Premultiplied: ((uint *)s)[x] = index_or_rgb; return; case Format_RGB16: - ((quint16 *)s)[x] = qConvertRgb32To16(INV_PREMUL(index_or_rgb)); + ((quint16 *)s)[x] = qConvertRgb32To16(qUnpremultiply(index_or_rgb)); return; case Format_RGBX8888: - ((uint *)s)[x] = ARGB2RGBA(index_or_rgb | 0xff000000); + ((uint *)s)[x] = ARGB2RGBA(0xff000000 | index_or_rgb); return; case Format_RGBA8888: case Format_RGBA8888_Premultiplied: diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index 9b79f4ccc0..e856959d51 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -77,7 +77,7 @@ static const uchar bitflip[256] = { 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255 }; -const uchar *qt_get_bitflip_array() // called from QPixmap code +const uchar *qt_get_bitflip_array() { return bitflip; } @@ -187,7 +187,7 @@ static void convert_ARGB_to_ARGB_PM(QImageData *dest, const QImageData *src, Qt: for (int i = 0; i < src->height; ++i) { const QRgb *end = src_data + src->width; while (src_data < end) { - *dest_data = PREMUL(*src_data); + *dest_data = qPremultiply(*src_data); ++src_data; ++dest_data; } @@ -304,7 +304,7 @@ static void convert_ARGB_to_RGBA_PM(QImageData *dest, const QImageData *src, Qt: for (int i = 0; i < src->height; ++i) { const quint32 *end = src_data + src->width; while (src_data < end) { - *dest_data = ARGB2RGBA(PREMUL(*src_data)); + *dest_data = ARGB2RGBA(qPremultiply(*src_data)); ++src_data; ++dest_data; } @@ -376,7 +376,7 @@ static void convert_RGBA_to_ARGB_PM(QImageData *dest, const QImageData *src, Qt: for (int i = 0; i < src->height; ++i) { const quint32 *end = src_data + src->width; while (src_data < end) { - *dest_data = PREMUL(RGBA2ARGB(*src_data)); + *dest_data = qPremultiply(RGBA2ARGB(*src_data)); ++src_data; ++dest_data; } @@ -395,7 +395,7 @@ static bool convert_RGBA_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversio for (int i = 0; i < data->height; ++i) { const QRgb *end = rgb_data + data->width; while (rgb_data < end) { - *rgb_data = PREMUL(RGBA2ARGB(*rgb_data)); + *rgb_data = qPremultiply(RGBA2ARGB(*rgb_data)); ++rgb_data; } rgb_data += pad; @@ -429,7 +429,7 @@ static bool convert_indexed8_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConve data->colortable[i] = qRgb(i, i, i); } else { for (int i = 0; i < data->colortable.size(); ++i) - data->colortable[i] = PREMUL(data->colortable.at(i)); + data->colortable[i] = qPremultiply(data->colortable.at(i)); // Fill the rest of the table in case src_data > colortable.size() const int oldSize = data->colortable.size(); @@ -604,7 +604,7 @@ static void convert_ARGB_PM_to_ARGB(QImageData *dest, const QImageData *src, Qt: for (int i = 0; i < src->height; ++i) { const QRgb *end = src_data + src->width; while (src_data < end) { - *dest_data = INV_PREMUL(*src_data); + *dest_data = qUnpremultiply(*src_data); ++src_data; ++dest_data; } @@ -628,7 +628,7 @@ static void convert_ARGB_PM_to_RGB(QImageData *dest, const QImageData *src, Qt:: for (int i = 0; i < src->height; ++i) { const QRgb *end = src_data + src->width; while (src_data < end) { - *dest_data = 0xff000000 | INV_PREMUL(*src_data); + *dest_data = 0xff000000 | qUnpremultiply(*src_data); ++src_data; ++dest_data; } @@ -652,7 +652,7 @@ static void convert_ARGB_PM_to_RGBx(QImageData *dest, const QImageData *src, Qt: for (int i = 0; i < src->height; ++i) { const QRgb *end = src_data + src->width; while (src_data < end) { - *dest_data = ARGB2RGBA(0xff000000 | INV_PREMUL(*src_data)); + *dest_data = ARGB2RGBA(0xff000000 | qUnpremultiply(*src_data)); ++src_data; ++dest_data; } @@ -676,7 +676,7 @@ static void convert_ARGB_PM_to_RGBA(QImageData *dest, const QImageData *src, Qt: for (int i = 0; i < src->height; ++i) { const QRgb *end = src_data + src->width; while (src_data < end) { - *dest_data = ARGB2RGBA(INV_PREMUL(*src_data)); + *dest_data = ARGB2RGBA(qUnpremultiply(*src_data)); ++src_data; ++dest_data; } @@ -748,7 +748,7 @@ static void convert_RGBA_PM_to_ARGB(QImageData *dest, const QImageData *src, Qt: for (int i = 0; i < src->height; ++i) { const QRgb *end = src_data + src->width; while (src_data < end) { - *dest_data = INV_PREMUL(RGBA2ARGB(*src_data)); + *dest_data = qUnpremultiply(RGBA2ARGB(*src_data)); ++src_data; ++dest_data; } @@ -772,7 +772,7 @@ static void convert_RGBA_PM_to_RGB(QImageData *dest, const QImageData *src, Qt:: for (int i = 0; i < src->height; ++i) { const QRgb *end = src_data + src->width; while (src_data < end) { - *dest_data = 0xff000000 | INV_PREMUL(RGBA2ARGB(*src_data)); + *dest_data = 0xff000000 | qUnpremultiply(RGBA2ARGB(*src_data)); ++src_data; ++dest_data; } @@ -862,7 +862,7 @@ static QVector<QRgb> fix_color_table(const QVector<QRgb> &ctbl, QImage::Format f } else if (format == QImage::Format_ARGB32_Premultiplied) { // check if the color table has alpha for (int i = 0; i < colorTable.size(); ++i) - colorTable[i] = PREMUL(colorTable.at(i)); + colorTable[i] = qPremultiply(colorTable.at(i)); } return colorTable; } diff --git a/src/gui/image/qimage_sse2.cpp b/src/gui/image/qimage_sse2.cpp index 0d6eac4ea2..037846c9aa 100644 --- a/src/gui/image/qimage_sse2.cpp +++ b/src/gui/image/qimage_sse2.cpp @@ -94,7 +94,7 @@ bool convert_ARGB_to_ARGB_PM_inplace_sse2(QImageData *data, Qt::ImageConversionF if (*p < 0x00ffffff) *p = 0; else if (*p < 0xff000000) - *p = PREMUL(*p); + *p = qPremultiply(*p); } d = reinterpret_cast<__m128i*>(p+pad); diff --git a/src/gui/image/qpixmap_blitter.cpp b/src/gui/image/qpixmap_blitter.cpp index 4c1b30a6d8..839a7a709f 100644 --- a/src/gui/image/qpixmap_blitter.cpp +++ b/src/gui/image/qpixmap_blitter.cpp @@ -148,7 +148,7 @@ void QBlittablePlatformPixmap::fill(const QColor &color) m_alpha = true; } - uint pixel = PREMUL(color.rgba()); + uint pixel = qPremultiply(color.rgba()); const QPixelLayout *layout = &qPixelLayouts[blittable()->lock()->format()]; Q_ASSERT(layout->convertFromARGB32PM); layout->convertFromARGB32PM(&pixel, &pixel, 1, layout, 0); diff --git a/src/gui/image/qpixmap_raster.cpp b/src/gui/image/qpixmap_raster.cpp index 37259adcd2..1465fea8b9 100644 --- a/src/gui/image/qpixmap_raster.cpp +++ b/src/gui/image/qpixmap_raster.cpp @@ -208,7 +208,7 @@ void QRasterPlatformPixmap::fill(const QColor &color) } } } - pixel = PREMUL(color.rgba()); + pixel = qPremultiply(color.rgba()); const QPixelLayout *layout = &qPixelLayouts[image.format()]; layout->convertFromARGB32PM(&pixel, &pixel, 1, layout, 0); } else { diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 76cebcb00c..f0431ebd9d 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1019,6 +1019,8 @@ void QGuiApplicationPrivate::createPlatformIntegration() continue; } QByteArray arg = argv[i]; + if (arg.startsWith("--")) + arg.remove(0, 1); if (arg == "-platformpluginpath") { if (++i < argc) platformPluginPath = QLatin1String(argv[i]); @@ -1099,6 +1101,8 @@ void QGuiApplicationPrivate::init() continue; } QByteArray arg = argv[i]; + if (arg.startsWith("--")) + arg.remove(0, 1); if (arg == "-plugin") { if (++i < argc) pluginList << argv[i]; diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp index fe29627c5a..2364f465b6 100644 --- a/src/gui/kernel/qplatformwindow.cpp +++ b/src/gui/kernel/qplatformwindow.cpp @@ -127,6 +127,18 @@ QRect QPlatformWindow::geometry() const return d->rect; } +/*! + Returns the geometry of a window in 'normal' state + (neither maximized, fullscreen nor minimized) for saving geometries to + application settings. + + \since 5.3 +*/ +QRect QPlatformWindow::normalGeometry() const +{ + return QRect(); +} + QMargins QPlatformWindow::frameMargins() const { return QMargins(); diff --git a/src/gui/kernel/qplatformwindow.h b/src/gui/kernel/qplatformwindow.h index 7dfbae036f..0adeb223f1 100644 --- a/src/gui/kernel/qplatformwindow.h +++ b/src/gui/kernel/qplatformwindow.h @@ -84,6 +84,7 @@ public: virtual void setGeometry(const QRect &rect); virtual QRect geometry() const; + virtual QRect normalGeometry() const; virtual QMargins frameMargins() const; diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 8ec74fdf31..42f61399d9 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -163,9 +163,7 @@ QWindow::QWindow(QScreen *targetScreen) //if your applications aborts here, then chances are your creating a QWindow before the //screen list is populated. Q_ASSERT(d->screen); - - connect(d->screen, SIGNAL(destroyed(QObject*)), this, SLOT(screenDestroyed(QObject*))); - QGuiApplicationPrivate::window_list.prepend(this); + d->init(); } /*! @@ -188,8 +186,7 @@ QWindow::QWindow(QWindow *parent) d->screen = parent->screen(); if (!d->screen) d->screen = QGuiApplication::primaryScreen(); - connect(d->screen, SIGNAL(destroyed(QObject*)), this, SLOT(screenDestroyed(QObject*))); - QGuiApplicationPrivate::window_list.prepend(this); + d->init(); } /*! @@ -214,8 +211,7 @@ QWindow::QWindow(QWindowPrivate &dd, QWindow *parent) d->screen = parent->screen(); if (!d->screen) d->screen = QGuiApplication::primaryScreen(); - connect(d->screen, SIGNAL(destroyed(QObject*)), this, SLOT(screenDestroyed(QObject*))); - QGuiApplicationPrivate::window_list.prepend(this); + d->init(); } /*! @@ -233,6 +229,13 @@ QWindow::~QWindow() destroy(); } +void QWindowPrivate::init() +{ + Q_Q(QWindow); + QObject::connect(screen, SIGNAL(destroyed(QObject*)), q, SLOT(screenDestroyed(QObject*))); + QGuiApplicationPrivate::window_list.prepend(q); +} + /*! \enum QWindow::Visibility \since 5.1 diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h index 8ebbf5d508..4305edea51 100644 --- a/src/gui/kernel/qwindow_p.h +++ b/src/gui/kernel/qwindow_p.h @@ -108,6 +108,8 @@ public: { } + void init(); + void maybeQuitOnLastWindowClosed(); #ifndef QT_NO_CURSOR void setCursor(const QCursor *c = 0); diff --git a/src/gui/opengl/opengl.pri b/src/gui/opengl/opengl.pri index d249b855f5..cadba26797 100644 --- a/src/gui/opengl/opengl.pri +++ b/src/gui/opengl/opengl.pri @@ -31,7 +31,8 @@ contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles2) { opengl/qopenglversionfunctions.h \ opengl/qopenglversionfunctionsfactory_p.h \ opengl/qopenglvertexarrayobject.h \ - opengl/qopengldebug.h + opengl/qopengldebug.h \ + opengl/qopengltextureblitter_p.h SOURCES += opengl/qopengl.cpp \ opengl/qopenglfunctions.cpp \ @@ -51,7 +52,8 @@ contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles2) { opengl/qopenglversionfunctions.cpp \ opengl/qopenglversionfunctionsfactory.cpp \ opengl/qopenglvertexarrayobject.cpp \ - opengl/qopengldebug.cpp + opengl/qopengldebug.cpp \ + opengl/qopengltextureblitter.cpp !wince* { HEADERS += opengl/qopengltexture.h \ diff --git a/src/gui/opengl/qopenglgradientcache.cpp b/src/gui/opengl/qopenglgradientcache.cpp index 9c4fbbe013..9c312808a2 100644 --- a/src/gui/opengl/qopenglgradientcache.cpp +++ b/src/gui/opengl/qopenglgradientcache.cpp @@ -168,7 +168,7 @@ void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient uint current_color = ARGB_COMBINE_ALPHA(colors[0], alpha); qreal incr = 1.0 / qreal(size); qreal fpos = 1.5 * incr; - colorTable[pos++] = ARGB2RGBA(PREMUL(current_color)); + colorTable[pos++] = ARGB2RGBA(qPremultiply(current_color)); while (fpos <= s.first().first) { colorTable[pos] = colorTable[pos - 1]; @@ -177,13 +177,13 @@ void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient } if (colorInterpolation) - current_color = PREMUL(current_color); + current_color = qPremultiply(current_color); for (int i = 0; i < s.size() - 1; ++i) { qreal delta = 1/(s[i+1].first - s[i].first); uint next_color = ARGB_COMBINE_ALPHA(colors[i+1], alpha); if (colorInterpolation) - next_color = PREMUL(next_color); + next_color = qPremultiply(next_color); while (fpos < s[i+1].first && pos < size) { int dist = int(256 * ((fpos - s[i].first) * delta)); @@ -191,7 +191,7 @@ void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient if (colorInterpolation) colorTable[pos] = ARGB2RGBA(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)); else - colorTable[pos] = ARGB2RGBA(PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist))); + colorTable[pos] = ARGB2RGBA(qPremultiply(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist))); ++pos; fpos += incr; } @@ -200,7 +200,7 @@ void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient Q_ASSERT(s.size() > 0); - uint last_color = ARGB2RGBA(PREMUL(ARGB_COMBINE_ALPHA(colors[s.size() - 1], alpha))); + uint last_color = ARGB2RGBA(qPremultiply(ARGB_COMBINE_ALPHA(colors[s.size() - 1], alpha))); for (;pos < size; ++pos) colorTable[pos] = last_color; diff --git a/src/gui/opengl/qopengltexture.cpp b/src/gui/opengl/qopengltexture.cpp index 1d16c3ecaa..9a9f277b1b 100644 --- a/src/gui/opengl/qopengltexture.cpp +++ b/src/gui/opengl/qopengltexture.cpp @@ -319,15 +319,21 @@ void QOpenGLTexturePrivate::allocateMutableStorage() return; case QOpenGLTexture::Target1D: - for (int level = 0; level < mipLevels; ++level) - texFuncs->glTextureImage1D(textureId, target, bindingTarget, level, format, - mipLevelSize(level, dimensions[0]), - 0, - QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, 0); + if (features.testFlag(QOpenGLTexture::Texture1D)) { + for (int level = 0; level < mipLevels; ++level) + texFuncs->glTextureImage1D(textureId, target, bindingTarget, level, format, + mipLevelSize(level, dimensions[0]), + 0, + QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, 0); + } else { + qWarning("1D textures are not supported"); + return; + } break; case QOpenGLTexture::Target1DArray: - if (features.testFlag(QOpenGLTexture::TextureArrays)) { + if (features.testFlag(QOpenGLTexture::Texture1D) + && features.testFlag(QOpenGLTexture::TextureArrays)) { for (int level = 0; level < mipLevels; ++level) texFuncs->glTextureImage2D(textureId, target, bindingTarget, level, format, mipLevelSize(level, dimensions[0]), @@ -335,7 +341,7 @@ void QOpenGLTexturePrivate::allocateMutableStorage() 0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, 0); } else { - qWarning("Array textures are not supported"); + qWarning("1D array textures are not supported"); return; } break; @@ -433,16 +439,22 @@ void QOpenGLTexturePrivate::allocateImmutableStorage() return; case QOpenGLTexture::Target1D: - texFuncs->glTextureStorage1D(textureId, target, bindingTarget, mipLevels, format, - dimensions[0]); + if (features.testFlag(QOpenGLTexture::Texture1D)) { + texFuncs->glTextureStorage1D(textureId, target, bindingTarget, mipLevels, format, + dimensions[0]); + } else { + qWarning("1D textures are not supported"); + return; + } break; case QOpenGLTexture::Target1DArray: - if (features.testFlag(QOpenGLTexture::TextureArrays)) { + if (features.testFlag(QOpenGLTexture::Texture1D) + && features.testFlag(QOpenGLTexture::TextureArrays)) { texFuncs->glTextureStorage2D(textureId, target, bindingTarget, mipLevels, format, dimensions[0], layers); } else { - qWarning("Array textures are not supported"); + qWarning("1D array textures are not supported"); return; } break; @@ -1356,6 +1368,7 @@ QOpenGLTexture *QOpenGLTexturePrivate::createTextureView(QOpenGLTexture::Target \value NPOTTextures Basic support for non-power-of-two textures \value NPOTTextureRepeat Full support for non-power-of-two textures including texture repeat modes + \value Texture1D Support for the 1 dimensional texture target */ /*! @@ -2427,6 +2440,10 @@ bool QOpenGLTexture::hasFeature(Feature feature) supported = ctx->hasExtension(QByteArrayLiteral("GL_ARB_texture_non_power_of_two")); break; + case Texture1D: + supported = f.version() >= qMakePair(1, 1); + break; + case MaxFeatureFlag: break; } diff --git a/src/gui/opengl/qopengltexture.h b/src/gui/opengl/qopengltexture.h index bb632454ad..0c272456f6 100644 --- a/src/gui/opengl/qopengltexture.h +++ b/src/gui/opengl/qopengltexture.h @@ -404,8 +404,9 @@ public: AnisotropicFiltering = 0x00000400, NPOTTextures = 0x00000800, NPOTTextureRepeat = 0x00001000, + Texture1D = 0x00002000, #ifndef Q_QDOC - MaxFeatureFlag = 0x00002000 + MaxFeatureFlag = 0x00004000 #endif }; Q_DECLARE_FLAGS(Features, Feature) diff --git a/src/gui/opengl/qopengltextureblitter.cpp b/src/gui/opengl/qopengltextureblitter.cpp new file mode 100644 index 0000000000..1fbdd20207 --- /dev/null +++ b/src/gui/opengl/qopengltextureblitter.cpp @@ -0,0 +1,394 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qopengltextureblitter_p.h" + +#include <QtGui/QOpenGLBuffer> +#include <QtGui/QOpenGLShaderProgram> +#include <QtGui/QOpenGLVertexArrayObject> +#include <QtGui/QOpenGLContext> + +QT_BEGIN_NAMESPACE + +static const char vertex_shader150[] = + "#version 150 core\n" + "in vec3 vertexCoord;" + "in vec2 textureCoord;" + "out vec2 uv;" + "uniform mat4 vertexTransform;" + "uniform mat3 textureTransform;" + "void main() {" + " uv = (textureTransform * vec3(textureCoord,1.0)).xy;" + " gl_Position = vertexTransform * vec4(vertexCoord,1.0);" + "}"; + +static const char fragment_shader150[] = + "#version 150 core\n" + "in vec2 uv;" + "out vec4 fragcolor;" + "uniform sampler2D textureSampler;" + "uniform bool swizzle;" + "void main() {" + " if (swizzle) {" + " fragcolor = texture(textureSampler, uv).bgra;" + " } else {" + " fragcolor = texture(textureSampler,uv);" + " }" + "}"; + +static const char vertex_shader[] = + "attribute highp vec3 vertexCoord;" + "attribute highp vec2 textureCoord;" + "varying highp vec2 uv;" + "uniform highp mat4 vertexTransform;" + "uniform highp mat3 textureTransform;" + "void main() {" + " uv = (textureTransform * vec3(textureCoord,1.0)).xy;" + " gl_Position = vertexTransform * vec4(vertexCoord,1.0);" + "}"; + +static const char fragment_shader[] = + "varying highp vec2 uv;" + "uniform sampler2D textureSampler;" + "uniform bool swizzle;" + "void main() {" + " if (swizzle) {" + " gl_FragColor = texture2D(textureSampler, uv).bgra;" + " } else {" + " gl_FragColor = texture2D(textureSampler,uv);" + " }" + "}"; + +static const GLfloat vertex_buffer_data[] = { + -1,-1, 0, + -1, 1, 0, + 1,-1, 0, + -1, 1, 0, + 1,-1, 0, + 1, 1, 0 +}; + +static const GLfloat texture_buffer_data[] = { + 0, 0, + 0, 1, + 1, 0, + 0, 1, + 1, 0, + 1, 1 +}; + +class TextureBinder +{ +public: + TextureBinder(GLuint textureId) + { + glBindTexture(GL_TEXTURE_2D, textureId); + } + ~TextureBinder() + { + glBindTexture(GL_TEXTURE_2D, 0); + } +}; + +class QOpenGLTextureBlitterPrivate +{ +public: + enum TextureMatrixUniform { + User, + Identity, + IdentityFlipped + }; + + QOpenGLTextureBlitterPrivate() + : program(0) + , vertexCoordAttribPos(0) + , vertexTransformUniformPos(0) + , textureCoordAttribPos(0) + , textureTransformUniformPos(0) + , swizzle(false) + , swizzleOld(false) + , textureMatrixUniformState(User) + , vao(new QOpenGLVertexArrayObject()) + { } + + void blit(GLuint texture, const QMatrix4x4 &vertexTransform, const QMatrix3x3 &textureTransform); + void blit(GLuint texture, const QMatrix4x4 &vertexTransform, QOpenGLTextureBlitter::Origin origin); + + void prepareProgram(const QMatrix4x4 &vertexTransform) + { + vertexBuffer.bind(); + program->setAttributeBuffer(vertexCoordAttribPos, GL_FLOAT, 0, 3, 0); + program->enableAttributeArray(vertexCoordAttribPos); + vertexBuffer.release(); + + program->setUniformValue(vertexTransformUniformPos, vertexTransform); + + textureBuffer.bind(); + program->setAttributeBuffer(textureCoordAttribPos, GL_FLOAT, 0, 2, 0); + program->enableAttributeArray(textureCoordAttribPos); + textureBuffer.release(); + + if (swizzle != swizzleOld) { + program->setUniformValue(swizzleUniformPos, swizzle); + swizzleOld = swizzle; + } + } + + QOpenGLBuffer vertexBuffer; + QOpenGLBuffer textureBuffer; + QScopedPointer<QOpenGLShaderProgram> program; + GLuint vertexCoordAttribPos; + GLuint vertexTransformUniformPos; + GLuint textureCoordAttribPos; + GLuint textureTransformUniformPos; + GLuint swizzleUniformPos; + bool swizzle; + bool swizzleOld; + TextureMatrixUniform textureMatrixUniformState; + QScopedPointer<QOpenGLVertexArrayObject> vao; +}; + +void QOpenGLTextureBlitterPrivate::blit(GLuint texture, + const QMatrix4x4 &vertexTransform, + const QMatrix3x3 &textureTransform) +{ + TextureBinder binder(texture); + prepareProgram(vertexTransform); + + program->setUniformValue(textureTransformUniformPos, textureTransform); + textureMatrixUniformState = User; + + glDrawArrays(GL_TRIANGLES, 0, 6); +} + +void QOpenGLTextureBlitterPrivate::blit(GLuint texture, + const QMatrix4x4 &vertexTransform, + QOpenGLTextureBlitter::Origin origin) +{ + TextureBinder binder(texture); + prepareProgram(vertexTransform); + + if (origin == QOpenGLTextureBlitter::OriginTopLeft) { + if (textureMatrixUniformState != IdentityFlipped) { + QMatrix3x3 flipped; + flipped(1,1) = -1; + program->setUniformValue(textureTransformUniformPos, flipped); + textureMatrixUniformState = IdentityFlipped; + } + } else if (textureMatrixUniformState != Identity) { + program->setUniformValue(textureTransformUniformPos, QMatrix3x3()); + textureMatrixUniformState = Identity; + } + + glDrawArrays(GL_TRIANGLES, 0, 6); +} + +QOpenGLTextureBlitter::QOpenGLTextureBlitter() + : d_ptr(new QOpenGLTextureBlitterPrivate) +{ +} + +QOpenGLTextureBlitter::~QOpenGLTextureBlitter() +{ +} + +bool QOpenGLTextureBlitter::create() +{ + QOpenGLContext *currentContext = QOpenGLContext::currentContext(); + if (!currentContext) + return false; + + Q_D(QOpenGLTextureBlitter); + + d->vao->create(); + d->vao->bind(); + + if (d->program) + return true; + + d->program.reset(new QOpenGLShaderProgram()); + + QSurfaceFormat format = currentContext->format(); + + if (format.profile() == QSurfaceFormat::CoreProfile && format.version() >= qMakePair(3,2)) { + d->program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertex_shader150); + d->program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragment_shader150); + } else { + d->program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertex_shader); + d->program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragment_shader); + } + d->program->link(); + if (!d->program->isLinked()) { + qWarning() << Q_FUNC_INFO << "Could not link shader program:\n" << d->program->log(); + return false; + } + + d->program->bind(); + + d->vertexBuffer.create(); + d->vertexBuffer.bind(); + d->vertexBuffer.allocate(vertex_buffer_data, sizeof(vertex_buffer_data) * sizeof(vertex_buffer_data[0])); + d->vertexBuffer.release(); + + d->textureBuffer.create(); + d->textureBuffer.bind(); + d->textureBuffer.allocate(texture_buffer_data, sizeof(texture_buffer_data) * sizeof(texture_buffer_data[0])); + d->textureBuffer.release(); + + d->vertexCoordAttribPos = d->program->attributeLocation("vertexCoord"); + d->vertexTransformUniformPos = d->program->uniformLocation("vertexTransform"); + d->textureCoordAttribPos = d->program->attributeLocation("textureCoord"); + d->textureTransformUniformPos = d->program->uniformLocation("textureTransform"); + d->swizzleUniformPos = d->program->uniformLocation("swizzle"); + + d->program->setUniformValue(d->swizzleUniformPos,false); + + d->vao->release(); + + return true; +} + +void QOpenGLTextureBlitter::destroy() +{ + Q_D(QOpenGLTextureBlitter); + d->program.reset(); + d->vertexBuffer.destroy(); + d->textureBuffer.destroy(); + d->vao.reset(); +} + +void QOpenGLTextureBlitter::bind() +{ + Q_D(QOpenGLTextureBlitter); + + d->vao->bind(); + + d->program->bind(); + + d->vertexBuffer.bind(); + d->program->setAttributeBuffer(d->vertexCoordAttribPos, GL_FLOAT, 0, 3, 0); + d->program->enableAttributeArray(d->vertexCoordAttribPos); + d->vertexBuffer.release(); + + d->textureBuffer.bind(); + d->program->setAttributeBuffer(d->textureCoordAttribPos, GL_FLOAT, 0, 2, 0); + d->program->enableAttributeArray(d->textureCoordAttribPos); + d->textureBuffer.release(); +} + +void QOpenGLTextureBlitter::release() +{ + Q_D(QOpenGLTextureBlitter); + d->program->release(); + d->vao->release(); +} + +void QOpenGLTextureBlitter::setSwizzleRB(bool swizzle) +{ + Q_D(QOpenGLTextureBlitter); + d->swizzle = swizzle; +} + +void QOpenGLTextureBlitter::blit(GLuint texture, + const QMatrix4x4 &targetTransform, + Origin sourceOrigin) +{ + Q_D(QOpenGLTextureBlitter); + d->blit(texture,targetTransform, sourceOrigin); +} + +void QOpenGLTextureBlitter::blit(GLuint texture, + const QMatrix4x4 &targetTransform, + const QMatrix3x3 &sourceTransform) +{ + Q_D(QOpenGLTextureBlitter); + d->blit(texture, targetTransform, sourceTransform); +} + +QMatrix4x4 QOpenGLTextureBlitter::targetTransform(const QRectF &target, + const QRect &viewport, + Origin origin) +{ + qreal x_scale = target.size().width() / viewport.width(); + qreal y_scale = target.size().height() / viewport.height(); + + const QPointF relative_to_viewport = target.topLeft() - viewport.topLeft(); + qreal x_translate = ((relative_to_viewport.x() / viewport.width()) + (x_scale / 2)) * 2 - 1; + qreal y_translate = ((relative_to_viewport.y() / viewport.height()) + (y_scale / 2)) * 2 - 1; + + if (origin == OriginTopLeft) { + y_translate = -y_translate; + } + + QMatrix4x4 vertexMatrix; + + vertexMatrix.translate(x_translate, y_translate); + vertexMatrix.scale(x_scale, y_scale); + return vertexMatrix; +} + +QMatrix3x3 QOpenGLTextureBlitter::sourceTransform(const QRectF &subTexture, + const QSize &textureSize, + Origin origin) +{ + qreal x_scale = subTexture.width() / textureSize.width(); + qreal y_scale = subTexture.height() / textureSize.height(); + + const QPointF topLeft = subTexture.topLeft(); + qreal x_translate = topLeft.x() / textureSize.width(); + qreal y_translate = topLeft.y() / textureSize.height(); + + if (origin == OriginTopLeft) { + y_translate += (y_translate * 2) + y_scale; + y_scale = y_scale - 1; + } + + QMatrix3x3 matrix; + matrix(0,2) = x_translate; + matrix(1,2) = y_translate; + + matrix(0,0) = x_scale; + matrix(1,1) = y_scale; + + return matrix; +} + +QT_END_NAMESPACE diff --git a/src/gui/opengl/qopengltextureblitter_p.h b/src/gui/opengl/qopengltextureblitter_p.h new file mode 100644 index 0000000000..5164d8630e --- /dev/null +++ b/src/gui/opengl/qopengltextureblitter_p.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENGLTEXTUREBLITTER_P_H +#define QOPENGLTEXTUREBLITTER_P_H + +#include <QtGui/qopengl.h> +#include <QtGui/QMatrix3x3> + +QT_BEGIN_NAMESPACE + +class QOpenGLTextureBlitterPrivate; + + +class Q_GUI_EXPORT QOpenGLTextureBlitter +{ +public: + QOpenGLTextureBlitter(); + ~QOpenGLTextureBlitter(); + + enum Origin { + OriginBottomLeft, + OriginTopLeft + }; + + bool create(); + void destroy(); + + void bind(); + void release(); + + void setSwizzleRB(bool swizzle); + + void blit(GLuint texture, const QMatrix4x4 &targetTransform, Origin sourceOrigin); + void blit(GLuint texture, const QMatrix4x4 &targetTransform, const QMatrix3x3 &sourceTransform); + + static QMatrix4x4 targetTransform(const QRectF &target, const QRect &viewport, Origin origin); + static QMatrix3x3 sourceTransform(const QRectF &subTexture, const QSize &textureSize, Origin origin); + +private: + Q_DISABLE_COPY(QOpenGLTextureBlitter); + Q_DECLARE_PRIVATE(QOpenGLTextureBlitter); + QScopedPointer<QOpenGLTextureBlitterPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif //QOPENGLTEXTUREBLITTER_P_H diff --git a/src/gui/opengl/qopengltexturehelper.cpp b/src/gui/opengl/qopengltexturehelper.cpp index 4da9b3f164..4f8762483f 100644 --- a/src/gui/opengl/qopengltexturehelper.cpp +++ b/src/gui/opengl/qopengltexturehelper.cpp @@ -119,15 +119,6 @@ QOpenGLTextureHelper::QOpenGLTextureHelper(QOpenGLContext *context) CompressedTextureImage1D = &QOpenGLTextureHelper::qt_CompressedTextureImage1D; CompressedTextureImage2D = &QOpenGLTextureHelper::qt_CompressedTextureImage2D; CompressedTextureImage3D = &QOpenGLTextureHelper::qt_CompressedTextureImage3D; -#if defined(QT_OPENGL_ES_2) - if (context->hasExtension(QByteArrayLiteral("GL_OES_texture_3D"))) { - TexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*)>(context->getProcAddress(QByteArrayLiteral("glTexImage3DOES"))); - TexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*)>(context->getProcAddress(QByteArrayLiteral("glTexSubImage3DOES"))); - CompressedTexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexImage3DOES"))); - CompressedTexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexSubImage3DOES"))); - } -#endif - #if !defined(QT_OPENGL_ES_2) } #endif @@ -148,6 +139,9 @@ QOpenGLTextureHelper::QOpenGLTextureHelper(QOpenGLContext *context) } #endif + // wglGetProcAddress should not be used to (and indeed will not) load OpenGL <= 1.1 functions. + // Hence, we resolve them "the hard way" + #if defined(Q_OS_WIN) && !defined(QT_OPENGL_ES_2) HMODULE handle = GetModuleHandleA("opengl32.dll"); @@ -200,18 +194,30 @@ QOpenGLTextureHelper::QOpenGLTextureHelper(QOpenGLContext *context) TexSubImage1D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLsizei , GLenum , GLenum , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glTexSubImage1D"))); #endif - // OpenGL 1.2 - TexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLsizei , GLsizei , GLsizei , GLint , GLenum , GLenum , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glTexImage3D"))); - TexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLint , GLint , GLsizei , GLsizei , GLsizei , GLenum , GLenum , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glTexSubImage3D"))); +#if defined(QT_OPENGL_ES_2) + if (context->hasExtension(QByteArrayLiteral("GL_OES_texture_3D"))) { + TexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*)>(context->getProcAddress(QByteArrayLiteral("glTexImage3DOES"))); + TexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*)>(context->getProcAddress(QByteArrayLiteral("glTexSubImage3DOES"))); + CompressedTexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexImage3DOES"))); + CompressedTexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexSubImage3DOES"))); + } else +#endif + { + // OpenGL 1.2 + TexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLsizei , GLsizei , GLsizei , GLint , GLenum , GLenum , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glTexImage3D"))); + TexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLint , GLint , GLsizei , GLsizei , GLsizei , GLenum , GLenum , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glTexSubImage3D"))); + + // OpenGL 1.3 + CompressedTexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLenum , GLsizei , GLsizei , GLsizei , GLint , GLsizei , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexImage3D"))); + CompressedTexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLint , GLint , GLsizei , GLsizei , GLsizei , GLenum , GLsizei , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexSubImage3D"))); + } // OpenGL 1.3 GetCompressedTexImage = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glGetCompressedTexImage"))); CompressedTexSubImage1D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLsizei , GLenum , GLsizei , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexSubImage1D"))); CompressedTexSubImage2D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLint , GLsizei , GLsizei , GLenum , GLsizei , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexSubImage2D"))); - CompressedTexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLint , GLint , GLsizei , GLsizei , GLsizei , GLenum , GLsizei , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexSubImage3D"))); CompressedTexImage1D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLenum , GLsizei , GLint , GLsizei , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexImage1D"))); CompressedTexImage2D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLenum , GLsizei , GLsizei , GLint , GLsizei , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexImage2D"))); - CompressedTexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLenum , GLsizei , GLsizei , GLsizei , GLint , GLsizei , const GLvoid *)>(context->getProcAddress(QByteArrayLiteral("glCompressedTexImage3D"))); ActiveTexture = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum )>(context->getProcAddress(QByteArrayLiteral("glActiveTexture"))); // OpenGL 3.0 diff --git a/src/gui/opengl/qopengltexturehelper_p.h b/src/gui/opengl/qopengltexturehelper_p.h index 1cb2592a42..cce0c092fd 100644 --- a/src/gui/opengl/qopengltexturehelper_p.h +++ b/src/gui/opengl/qopengltexturehelper_p.h @@ -695,7 +695,9 @@ public: } private: - // Typedefs and pointers to member functions used to switch between EXT_direct_state_access and our own emulated DSA + // Typedefs and pointers to member functions used to switch between EXT_direct_state_access and our own emulated DSA. + // The argument match the corresponding GL function, but there's an extra "GLenum bindingTarget" which gets used with + // the DSA emulation -- it contains the right GL_BINDING_TEXTURE_X to use. typedef void (QOpenGLTextureHelper::*TextureParameteriMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLint param); typedef void (QOpenGLTextureHelper::*TextureParameterivMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLint *params); typedef void (QOpenGLTextureHelper::*TextureParameterfMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLfloat param); diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp index 706273c151..b9d3ca888e 100644 --- a/src/gui/painting/qcolor.cpp +++ b/src/gui/painting/qcolor.cpp @@ -2499,6 +2499,41 @@ QDataStream &operator>>(QDataStream &stream, QColor &color) } #endif // QT_NO_DATASTREAM +// A table of precalculated results of 0x00ff00ff/alpha use by qUnpremultiply: +const uint qt_inv_premul_factor[256] = { + 0, 16711935, 8355967, 5570645, 4177983, 3342387, 2785322, 2387419, + 2088991, 1856881, 1671193, 1519266, 1392661, 1285533, 1193709, 1114129, + 1044495, 983055, 928440, 879575, 835596, 795806, 759633, 726605, + 696330, 668477, 642766, 618960, 596854, 576273, 557064, 539094, + 522247, 506422, 491527, 477483, 464220, 451673, 439787, 428511, + 417798, 407608, 397903, 388649, 379816, 371376, 363302, 355573, + 348165, 341059, 334238, 327685, 321383, 315319, 309480, 303853, + 298427, 293191, 288136, 283253, 278532, 273966, 269547, 265268, + 261123, 257106, 253211, 249431, 245763, 242201, 238741, 235379, + 232110, 228930, 225836, 222825, 219893, 217038, 214255, 211543, + 208899, 206320, 203804, 201348, 198951, 196611, 194324, 192091, + 189908, 187774, 185688, 183647, 181651, 179698, 177786, 175915, + 174082, 172287, 170529, 168807, 167119, 165464, 163842, 162251, + 160691, 159161, 157659, 156186, 154740, 153320, 151926, 150557, + 149213, 147893, 146595, 145321, 144068, 142837, 141626, 140436, + 139266, 138115, 136983, 135869, 134773, 133695, 132634, 131590, + 130561, 129549, 128553, 127572, 126605, 125653, 124715, 123792, + 122881, 121984, 121100, 120229, 119370, 118524, 117689, 116866, + 116055, 115254, 114465, 113686, 112918, 112160, 111412, 110675, + 109946, 109228, 108519, 107818, 107127, 106445, 105771, 105106, + 104449, 103800, 103160, 102527, 101902, 101284, 100674, 100071, + 99475, 98887, 98305, 97730, 97162, 96600, 96045, 95496, + 94954, 94417, 93887, 93362, 92844, 92331, 91823, 91322, + 90825, 90334, 89849, 89368, 88893, 88422, 87957, 87497, + 87041, 86590, 86143, 85702, 85264, 84832, 84403, 83979, + 83559, 83143, 82732, 82324, 81921, 81521, 81125, 80733, + 80345, 79961, 79580, 79203, 78829, 78459, 78093, 77729, + 77370, 77013, 76660, 76310, 75963, 75619, 75278, 74941, + 74606, 74275, 73946, 73620, 73297, 72977, 72660, 72346, + 72034, 71725, 71418, 71114, 70813, 70514, 70218, 69924, + 69633, 69344, 69057, 68773, 68491, 68211, 67934, 67659, + 67386, 67116, 66847, 66581, 66317, 66055, 65795, 65537 +}; /***************************************************************************** QColor global functions (documentation only) @@ -2581,6 +2616,26 @@ QDataStream &operator>>(QDataStream &stream, QColor &color) */ /*! + \fn QRgb qPremultiply(QRgb rgb) + \since 5.3 + \relates QColor + + Converts an unpremultiplied ARGB quadruplet \a rgb into a premultiplied ARGB quadruplet. + + \sa qUnpremultiply() +*/ + +/*! + \fn QRgb qUnpremultiply(QRgb rgb) + \since 5.3 + \relates QColor + + Converts a premultiplied ARGB quadruplet \a rgb into an unpremultiplied ARGB quadruplet. + + \sa qPremultiply() +*/ + +/*! \fn QColor QColor::convertTo(Spec colorSpec) const Creates a copy of \e this color in the format specified by \a colorSpec. diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 1851734bbc..52a6b5d211 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -255,7 +255,7 @@ static const uint *QT_FASTCALL convertRGBFromARGB32PM(uint *buffer, const uint * Q_CONSTEXPR uchar blueRightShift = 8 - blueWidth<Format>(); for (int i = 0; i < count; ++i) { - const uint color = INV_PREMUL(src[i]); + const uint color = qUnpremultiply(src[i]); const uint red = ((color >> redRightShift) & redMask) << redShift<Format>(); const uint green = ((color >> greenRightShift) & greenMask) << greenShift<Format>(); const uint blue = ((color >> blueRightShift) & blueMask) << blueShift<Format>(); @@ -387,7 +387,7 @@ static const uint *QT_FASTCALL convertToARGB32PM(uint *buffer, const uint *src, red = (red << redLeftShift) | (red >> redRightShift); green = (green << greenLeftShift) | (green >> greenRightShift); blue = (blue << blueLeftShift) | (blue >> blueRightShift); - buffer[i] = PREMUL((alpha << 24) | (red << 16) | (green << 8) | blue); + buffer[i] = qPremultiply((alpha << 24) | (red << 16) | (green << 8) | blue); } } return buffer; @@ -446,7 +446,7 @@ static const uint *QT_FASTCALL convertFromARGB32PM(uint *buffer, const uint *src if (!layout->premultiplied) { for (int i = 0; i < count; ++i) - buffer[i] = INV_PREMUL(src[i]); + buffer[i] = qUnpremultiply(src[i]); src = buffer; } for (int i = 0; i < count; ++i) { @@ -505,7 +505,7 @@ static const uint *QT_FASTCALL convertRGB16FromARGB32PM(uint *buffer, const uint const QPixelLayout *, const QRgb *) { for (int i = 0; i < count; ++i) - buffer[i] = qConvertRgb32To16(INV_PREMUL(src[i])); + buffer[i] = qConvertRgb32To16(qUnpremultiply(src[i])); return buffer; } #endif @@ -515,7 +515,7 @@ static const uint *QT_FASTCALL convertIndexedToARGB32PM(uint *buffer, const uint const QPixelLayout *, const QRgb *clut) { for (int i = 0; i < count; ++i) - buffer[i] = PREMUL(clut[src[i]]); + buffer[i] = qPremultiply(clut[src[i]]); return buffer; } @@ -529,7 +529,7 @@ static const uint *QT_FASTCALL convertARGB32ToARGB32PM(uint *buffer, const uint const QPixelLayout *, const QRgb *) { for (int i = 0; i < count; ++i) - buffer[i] = PREMUL(src[i]); + buffer[i] = qPremultiply(src[i]); return buffer; } @@ -545,7 +545,7 @@ static const uint *QT_FASTCALL convertRGBA8888ToARGB32PM(uint *buffer, const uin const QPixelLayout *, const QRgb *) { for (int i = 0; i < count; ++i) - buffer[i] = PREMUL(RGBA2ARGB(src[i])); + buffer[i] = qPremultiply(RGBA2ARGB(src[i])); return buffer; } @@ -553,7 +553,7 @@ static const uint *QT_FASTCALL convertARGB32FromARGB32PM(uint *buffer, const uin const QPixelLayout *, const QRgb *) { for (int i = 0; i < count; ++i) - buffer[i] = INV_PREMUL(src[i]); + buffer[i] = qUnpremultiply(src[i]); return buffer; } @@ -569,7 +569,7 @@ static const uint *QT_FASTCALL convertRGBA8888FromARGB32PM(uint *buffer, const u const QPixelLayout *, const QRgb *) { for (int i = 0; i < count; ++i) - buffer[i] = ARGB2RGBA(INV_PREMUL(src[i])); + buffer[i] = ARGB2RGBA(qUnpremultiply(src[i])); return buffer; } @@ -585,7 +585,7 @@ static const uint *QT_FASTCALL convertRGBXFromARGB32PM(uint *buffer, const uint const QPixelLayout *, const QRgb *) { for (int i = 0; i < count; ++i) - buffer[i] = ARGB2RGBA(0xff000000 | INV_PREMUL(src[i])); + buffer[i] = ARGB2RGBA(0xff000000 | qUnpremultiply(src[i])); return buffer; } @@ -853,9 +853,9 @@ static DestFetchProc destFetchProc[QImage::NImageFormats] = */ static inline QRgb findNearestColor(QRgb color, QRasterBuffer *rbuf) { - QRgb color_0 = PREMUL(rbuf->destColor0); - QRgb color_1 = PREMUL(rbuf->destColor1); - color = PREMUL(color); + QRgb color_0 = qPremultiply(rbuf->destColor0); + QRgb color_1 = qPremultiply(rbuf->destColor1); + color = qPremultiply(color); int r = qRed(color); int g = qGreen(color); @@ -6250,7 +6250,7 @@ static void qt_rectfill_nonpremul_argb32(QRasterBuffer *rasterBuffer, quint32 color) { qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()), - INV_PREMUL(color), x, y, width, height, rasterBuffer->bytesPerLine()); + qUnpremultiply(color), x, y, width, height, rasterBuffer->bytesPerLine()); } static void qt_rectfill_rgba(QRasterBuffer *rasterBuffer, @@ -6266,7 +6266,7 @@ static void qt_rectfill_nonpremul_rgba(QRasterBuffer *rasterBuffer, quint32 color) { qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()), - ARGB2RGBA(INV_PREMUL(color)), x, y, width, height, rasterBuffer->bytesPerLine()); + ARGB2RGBA(qUnpremultiply(color)), x, y, width, height, rasterBuffer->bytesPerLine()); } diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index 0f98b07229..bbeb73f0af 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -599,14 +599,6 @@ static Q_ALWAYS_INLINE uint BYTE_MUL(uint x, uint a) { return (uint(t)) | (uint(t >> 24)); } -static Q_ALWAYS_INLINE uint PREMUL(uint x) { - uint a = x >> 24; - quint64 t = (((quint64(x)) | ((quint64(x)) << 24)) & 0x00ff00ff00ff00ff) * a; - t = (t + ((t >> 8) & 0xff00ff00ff00ff) + 0x80008000800080) >> 8; - t &= 0x000000ff00ff00ff; - return (uint(t)) | (uint(t >> 24)) | (a << 24); -} - #else // 32-bit versions static Q_ALWAYS_INLINE uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b) { @@ -639,20 +631,9 @@ static Q_ALWAYS_INLINE uint BYTE_MUL(uint x, uint a) { # pragma pop #endif -static Q_ALWAYS_INLINE uint PREMUL(uint x) { - uint a = x >> 24; - uint t = (x & 0xff00ff) * a; - t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8; - t &= 0xff00ff; - - x = ((x >> 8) & 0xff) * a; - x = (x + ((x >> 8) & 0xff) + 0x80); - x &= 0xff00; - x |= t | (a << 24); - return x; -} #endif + #if Q_BYTE_ORDER == Q_BIG_ENDIAN static Q_ALWAYS_INLINE quint32 RGBA2ARGB(quint32 x) { quint32 rgb = x >> 8; @@ -691,17 +672,9 @@ static Q_ALWAYS_INLINE uint BYTE_MUL_RGB16_32(uint x, uint a) { return t; } -static Q_ALWAYS_INLINE uint INV_PREMUL(uint p) { - const uint alpha = qAlpha(p); - if (alpha == 255) - return p; - if (alpha == 0) - return 0; - // (p*(0x00ff00ff/alpha)) >> 16 == (p*255)/alpha for all p and alpha <= 256. - const uint invAlpha = 0x00ff00ffU / alpha; - // We add 0x8000 to get even rounding. The rounding also ensures that PREMUL(INV_PREMUL(p)) == p for all p. - return qRgba((qRed(p)*invAlpha + 0x8000)>>16, (qGreen(p)*invAlpha + 0x8000)>>16, (qBlue(p)*invAlpha + 0x8000)>>16, alpha); -} +// FIXME: Remove when all Qt modules have stopped using PREMUL and INV_PREMUL +#define PREMUL(x) qPremultiply(x) +#define INV_PREMUL(p) qUnpremultiply(p) struct quint24 { quint24(uint value); diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index bdd0d9cd4c..9a2e49618c 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -1823,7 +1823,7 @@ void QRasterPaintEngine::fillRect(const QRectF &r, const QColor &color) Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); - d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity)); + d->solid_color_filler.solid.color = qPremultiply(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity)); if ((d->solid_color_filler.solid.color & 0xff000000) == 0 && s->composition_mode == QPainter::CompositionMode_SourceOver) { return; @@ -2272,7 +2272,7 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe | ((((color & 0xff00ff00) >> 8) * s->intOpacity) & 0xff00ff00); break; default: - d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color, s->intOpacity)); + d->solid_color_filler.solid.color = qPremultiply(ARGB_COMBINE_ALPHA(color, s->intOpacity)); break; } @@ -3662,7 +3662,7 @@ QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color) QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB); QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied); - QRgb fg = PREMUL(color.rgba()); + QRgb fg = qPremultiply(color.rgba()); QRgb bg = 0; int height = sourceImage.height(); @@ -3702,8 +3702,8 @@ QImage::Format QRasterBuffer::prepare(QImage *image) drawHelper = qDrawHelper + format; if (image->depth() == 1 && image->colorTable().size() == 2) { monoDestinationWithClut = true; - destColor0 = PREMUL(image->colorTable()[0]); - destColor1 = PREMUL(image->colorTable()[1]); + destColor0 = qPremultiply(image->colorTable()[0]); + destColor1 = qPremultiply(image->colorTable()[1]); } return format; @@ -4260,8 +4260,8 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint } if (colorInterpolation) { - first_color = PREMUL(first_color); - second_color = PREMUL(second_color); + first_color = qPremultiply(first_color); + second_color = qPremultiply(second_color); } int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1)); @@ -4282,7 +4282,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint if (colorInterpolation) colorTable[i] = first_color; else - colorTable[i] = PREMUL(first_color); + colorTable[i] = qPremultiply(first_color); } if (i < second_index) { @@ -4311,7 +4311,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint if (colorInterpolation) colorTable[i] = color; else - colorTable[i] = PREMUL(color); + colorTable[i] = qPremultiply(color); } } @@ -4319,7 +4319,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint if (colorInterpolation) colorTable[i] = second_color; else - colorTable[i] = PREMUL(second_color); + colorTable[i] = qPremultiply(second_color); } return; @@ -4327,7 +4327,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity); if (stopCount == 1) { - current_color = PREMUL(current_color); + current_color = qPremultiply(current_color); for (int i = 0; i < size; ++i) colorTable[i] = current_color; return; @@ -4344,7 +4344,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint qreal dpos = 1.5 * incr; // current position in gradient stop list (0 to 1) // Up to first point - colorTable[pos++] = PREMUL(current_color); + colorTable[pos++] = qPremultiply(current_color); while (dpos <= begin_pos) { colorTable[pos] = colorTable[pos - 1]; ++pos; @@ -4366,8 +4366,8 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity); if (colorInterpolation) { - current_color = PREMUL(current_color); - next_color = PREMUL(next_color); + current_color = qPremultiply(current_color); + next_color = qPremultiply(next_color); } qreal diff = stops[current_stop+1].first - stops[current_stop].first; @@ -4384,7 +4384,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint if (colorInterpolation) colorTable[pos] = INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist); else - colorTable[pos] = PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)); + colorTable[pos] = qPremultiply(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)); ++pos; dpos += incr; @@ -4408,8 +4408,8 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint if (colorInterpolation) { if (skip != 1) - current_color = PREMUL(current_color); - next_color = PREMUL(next_color); + current_color = qPremultiply(current_color); + next_color = qPremultiply(next_color); } qreal diff = stops[current_stop+1].first - stops[current_stop].first; @@ -4421,7 +4421,7 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint } // After last point - current_color = PREMUL(ARGB_COMBINE_ALPHA(stops[stopCount - 1].second.rgba(), opacity)); + current_color = qPremultiply(ARGB_COMBINE_ALPHA(stops[stopCount - 1].second.rgba(), opacity)); while (pos < size - 1) { colorTable[pos] = current_color; ++pos; @@ -4455,7 +4455,7 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode type = Solid; QColor c = qbrush_color(brush); QRgb rgba = c.rgba(); - solid.color = PREMUL(ARGB_COMBINE_ALPHA(rgba, alpha)); + solid.color = qPremultiply(ARGB_COMBINE_ALPHA(rgba, alpha)); if ((solid.color & 0xff000000) == 0 && compositionMode == QPainter::CompositionMode_SourceOver) { type = None; diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 2944130eaa..1fc044aa44 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5845,11 +5845,8 @@ void QPainter::drawText(const QPointF &p, const QString &str, int tf, int justif int numGlyphs = len; QVarLengthGlyphLayoutArray glyphs(len); QFontEngine *fontEngine = d->state->font.d->engineForScript(QChar::Script_Common); - if (!fontEngine->stringToCMap(str.data(), len, &glyphs, &numGlyphs, 0)) { - glyphs.resize(numGlyphs); - if (!fontEngine->stringToCMap(str.data(), len, &glyphs, &numGlyphs, 0)) - Q_ASSERT_X(false, Q_FUNC_INFO, "stringToCMap shouldn't fail twice"); - } + if (!fontEngine->stringToCMap(str.data(), len, &glyphs, &numGlyphs, 0)) + Q_UNREACHABLE(); QTextItemInt gf(glyphs, &d->state->font, str.data(), len, fontEngine); drawTextItem(p, gf); diff --git a/src/gui/painting/qrgb.h b/src/gui/painting/qrgb.h index 3c2bc5b97a..d8e19302d1 100644 --- a/src/gui/painting/qrgb.h +++ b/src/gui/painting/qrgb.h @@ -43,6 +43,7 @@ #define QRGB_H #include <QtCore/qglobal.h> +#include <QtCore/qprocessordetection.h> QT_BEGIN_NAMESPACE @@ -79,6 +80,48 @@ inline Q_DECL_CONSTEXPR int qGray(QRgb rgb) // convert RGB to gra inline Q_DECL_CONSTEXPR bool qIsGray(QRgb rgb) { return qRed(rgb) == qGreen(rgb) && qRed(rgb) == qBlue(rgb); } + +#if Q_PROCESSOR_WORDSIZE == 8 // 64-bit version +inline QRgb qPremultiply(QRgb x) +{ + const uint a = qAlpha(x); + quint64 t = (((quint64(x)) | ((quint64(x)) << 24)) & 0x00ff00ff00ff00ff) * a; + t = (t + ((t >> 8) & 0xff00ff00ff00ff) + 0x80008000800080) >> 8; + t &= 0x000000ff00ff00ff; + return (uint(t)) | (uint(t >> 24)) | (a << 24); +} +#else // 32-bit version +inline QRgb qPremultiply(QRgb x) +{ + const uint a = qAlpha(x); + uint t = (x & 0xff00ff) * a; + t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8; + t &= 0xff00ff; + + x = ((x >> 8) & 0xff) * a; + x = (x + ((x >> 8) & 0xff) + 0x80); + x &= 0xff00; + x |= t | (a << 24); + return x; +} +#endif + +Q_GUI_EXPORT extern const uint qt_inv_premul_factor[]; + +inline QRgb qUnpremultiply(QRgb p) +{ + const uint alpha = qAlpha(p); + // Alpha 255 and 0 are the two most common values, which makes them beneficial to short-cut. + if (alpha == 255) + return p; + if (alpha == 0) + return 0; + // (p*(0x00ff00ff/alpha)) >> 16 == (p*255)/alpha for all p and alpha <= 256. + const uint invAlpha = qt_inv_premul_factor[alpha]; + // We add 0x8000 to get even rounding. The rounding also ensures that qPremultiply(qUnpremultiply(p)) == p for all p. + return qRgba((qRed(p)*invAlpha + 0x8000)>>16, (qGreen(p)*invAlpha + 0x8000)>>16, (qBlue(p)*invAlpha + 0x8000)>>16, alpha); +} + QT_END_NAMESPACE #endif // QRGB_H diff --git a/src/gui/text/qdistancefield.cpp b/src/gui/text/qdistancefield.cpp index e584b66a25..f2b88c4692 100644 --- a/src/gui/text/qdistancefield.cpp +++ b/src/gui/text/qdistancefield.cpp @@ -739,13 +739,19 @@ bool qt_fontHasNarrowOutlines(QFontEngine *fontEngine) if (!fe) return false; - QGlyphLayout glyphs; + const QChar uc(QLatin1Char('O')); + glyph_t glyph; - glyphs.glyphs = &glyph; + + QGlyphLayout glyphs; glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; int numGlyphs = 1; - QChar uc = QLatin1Char('O'); - fe->stringToCMap(&uc, 1, &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly); + + if (!fe->stringToCMap(&uc, 1, &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(numGlyphs == 1); + QImage im = fe->alphaMapForGlyph(glyph, QFixed(), QTransform()); Q_ASSERT(fe->ref.load() == 0); diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index f2951611ff..12761d0d3e 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -2533,7 +2533,9 @@ bool QFontInfo::fixedPitch() const QChar ch[2] = { QLatin1Char('i'), QLatin1Char('m') }; QGlyphLayoutArray<2> g; int l = 2; - engine->stringToCMap(ch, 2, &g, &l, 0); + if (!engine->stringToCMap(ch, 2, &g, &l, 0)) + Q_UNREACHABLE(); + Q_ASSERT(l == 2); engine->fontDef.fixedPitch = g.advances[0] == g.advances[1]; engine->fontDef.fixedPitchComputed = true; } diff --git a/src/gui/text/qfontdatabase.h b/src/gui/text/qfontdatabase.h index 708b8cbd58..9986ef6c60 100644 --- a/src/gui/text/qfontdatabase.h +++ b/src/gui/text/qfontdatabase.h @@ -167,8 +167,6 @@ private: friend class QFontPrivate; friend class QFontDialog; friend class QFontDialogPrivate; - friend class QFontEngineMultiXLFD; - friend class QFontEngineMultiQWS; friend class QFontEngineMultiQPA; QFontDatabasePrivate *d; diff --git a/src/gui/text/qfontdatabase_qpa.cpp b/src/gui/text/qfontdatabase_qpa.cpp index 6f4971e267..1972f5d58c 100644 --- a/src/gui/text/qfontdatabase_qpa.cpp +++ b/src/gui/text/qfontdatabase_qpa.cpp @@ -182,10 +182,17 @@ QFontEngine *loadSingleEngine(int script, QFontCache::Key key(def,script); QFontEngine *engine = QFontCache::instance()->findEngine(key); if (!engine) { - engine = pfdb->fontEngine(def, QChar::Script(script), size->handle); + engine = pfdb->fontEngine(def, size->handle); if (engine) { - QFontCache::Key key(def,script); - QFontCache::instance()->instance()->insertEngine(key,engine); + // Also check for OpenType tables when using complex scripts + if (!engine->supportsScript(QChar::Script(script))) { + qWarning(" OpenType support missing for script %d", script); + if (engine->ref.load() == 0) + delete engine; + return 0; + } + + QFontCache::instance()->insertEngine(key, engine); } } return engine; @@ -221,10 +228,10 @@ QFontEngine *loadEngine(int script, const QFontDef &request, pfMultiEngine->setFallbackFamiliesList(fallbacks); engine = pfMultiEngine; - // Cache Multi font engine as well in case we got the FT single + // Cache Multi font engine as well in case we got the single // font engine when we are actually looking for a Multi one QFontCache::Key key(request, script, 1); - QFontCache::instance()->instance()->insertEngine(key, engine); + QFontCache::instance()->insertEngine(key, engine); } return engine; diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 71866119d4..14ce5d2396 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -48,6 +48,7 @@ #include "qvarlengtharray.h" #include <qmath.h> #include <qendian.h> +#include <private/qstringiterator_p.h> #ifdef QT_ENABLE_HARFBUZZ_NG # include "qharfbuzzng_p.h" @@ -395,23 +396,39 @@ glyph_metrics_t QFontEngine::boundingBox(glyph_t glyph, const QTransform &matrix QFixed QFontEngine::xHeight() const { - QGlyphLayoutArray<8> glyphs; - int nglyphs = 7; QChar x((ushort)'x'); - stringToCMap(&x, 1, &glyphs, &nglyphs, GlyphIndicesOnly); - glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyphs.glyphs[0]); + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!stringToCMap(&x, 1, &glyphs, &nglyphs, GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyph); return bb.height; } QFixed QFontEngine::averageCharWidth() const { - QGlyphLayoutArray<8> glyphs; - int nglyphs = 7; QChar x((ushort)'x'); - stringToCMap(&x, 1, &glyphs, &nglyphs, GlyphIndicesOnly); - glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyphs.glyphs[0]); + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!stringToCMap(&x, 1, &glyphs, &nglyphs, GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyph); return bb.xoff; } @@ -470,11 +487,22 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform ++current; if (glyphs.justifications[i].nKashidas) { QChar ch(0x640); // Kashida character - QGlyphLayoutArray<8> g; - int nglyphs = 7; - stringToCMap(&ch, 1, &g, &nglyphs, 0); + + glyph_t kashidaGlyph; + QFixed kashidaWidth; + + QGlyphLayout g; + g.numGlyphs = 1; + g.glyphs = &kashidaGlyph; + g.advances = &kashidaWidth; + + int nglyphs = 1; + if (!stringToCMap(&ch, 1, &g, &nglyphs, 0)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + for (uint k = 0; k < glyphs.justifications[i].nKashidas; ++k) { - xpos -= g.advances[0]; + xpos -= kashidaWidth; QFixed gpos_x = xpos + glyphs.offsets[i].x; QFixed gpos_y = ypos + glyphs.offsets[i].y; @@ -486,7 +514,7 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform } positions[current].x = gpos_x; positions[current].y = gpos_y; - glyphs_out[current] = g.glyphs[0]; + glyphs_out[current] = kashidaGlyph; ++current; } } else { @@ -1348,14 +1376,12 @@ bool QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyph } int ucs4Length = 0; - for (int i = 0; i < len; ++i) { - if (str[i].isHighSurrogate() && i + 1 < len && str[i + 1].isLowSurrogate()) - ++ucs4Length; - ++ucs4Length; + QStringIterator it(str, str + len); + while (it.hasNext()) { + it.advance(); + glyphs->glyphs[ucs4Length++] = 0; } - memset(glyphs->glyphs, 0, ucs4Length * sizeof(glyph_t)); - *nglyphs = ucs4Length; glyphs->numGlyphs = ucs4Length; @@ -1547,9 +1573,10 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len, if (!(flags & GlyphIndicesOnly)) glyphs->advances[glyph_pos] = QFixed(); int num = 2; - QGlyphLayout offs = glyphs->mid(glyph_pos, num); - engine->stringToCMap(str + i, surrogate ? 2 : 1, &offs, &num, flags); - Q_ASSERT(num == 1); // surrogates only give 1 glyph + QGlyphLayout g = glyphs->mid(glyph_pos, num); + if (!engine->stringToCMap(str + i, surrogate ? 2 : 1, &g, &num, flags)) + Q_UNREACHABLE(); + Q_ASSERT(num == 1); if (glyphs->glyphs[glyph_pos]) { // set the high byte to indicate which engine the glyph came from glyphs->glyphs[glyph_pos] |= (x << 24); @@ -1860,16 +1887,11 @@ bool QFontEngineMulti::canRender(const QChar *string, int len) QGlyphLayout g; g.numGlyphs = nglyphs; g.glyphs = glyphs.data(); - if (!stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly)) { - glyphs.resize(nglyphs); - g.numGlyphs = nglyphs; - g.glyphs = glyphs.data(); - if (!stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly)) - Q_ASSERT_X(false, Q_FUNC_INFO, "stringToCMap shouldn't fail twice"); - } + if (!stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly)) + Q_UNREACHABLE(); for (int i = 0; i < nglyphs; i++) { - if (g.glyphs[i] == 0) + if (glyphs[i] == 0) return false; } diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index 5499757c3b..665932e4a5 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -1283,13 +1283,22 @@ qreal QFontEngineFT::minRightBearing() const { if (rbearing == SHRT_MIN) { lbearing = rbearing = 0; - const QChar *ch = (const QChar *)(const void*)char_table; - QGlyphLayoutArray<char_table_entries> glyphs; + + const QChar *ch = reinterpret_cast<const QChar *>(char_table); + + glyph_t glyphs[char_table_entries]; + + QGlyphLayout g; + g.glyphs = glyphs; + g.numGlyphs = char_table_entries; int ng = char_table_entries; - stringToCMap(ch, char_table_entries, &glyphs, &ng, GlyphIndicesOnly); + if (!stringToCMap(ch, char_table_entries, &g, &ng, GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(ng == char_table_entries); + while (--ng) { - if (glyphs.glyphs[ng]) { - glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]); + if (glyphs[ng]) { + glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs[ng]); lbearing = qMin(lbearing, gi.x); rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width)); } diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp index 08105834ea..2f4709afe4 100644 --- a/src/gui/text/qfontmetrics.cpp +++ b/src/gui/text/qfontmetrics.cpp @@ -458,12 +458,19 @@ int QFontMetrics::leftBearing(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<10> glyphs; - int nglyphs = 9; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly); - // ### can nglyphs != 1 happen at all? Not currently I think + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + qreal lb; - engine->getGlyphBearings(glyphs.glyphs[0], &lb); + engine->getGlyphBearings(glyph, &lb); return qRound(lb); } @@ -493,12 +500,19 @@ int QFontMetrics::rightBearing(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<10> glyphs; - int nglyphs = 9; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly); - // ### can nglyphs != 1 happen at all? Not currently I think + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + qreal rb; - engine->getGlyphBearings(glyphs.glyphs[0], 0, &rb); + engine->getGlyphBearings(glyph, 0, &rb); return qRound(rb); } @@ -538,11 +552,8 @@ int QFontMetrics::width(const QString &text, int len, int flags) const int numGlyphs = len; QVarLengthGlyphLayoutArray glyphs(numGlyphs); QFontEngine *engine = d->engineForScript(QChar::Script_Common); - if (!engine->stringToCMap(text.data(), len, &glyphs, &numGlyphs, 0)) { - glyphs.resize(numGlyphs); - if (!engine->stringToCMap(text.data(), len, &glyphs, &numGlyphs, 0)) - Q_ASSERT_X(false, Q_FUNC_INFO, "stringToCMap shouldn't fail twice"); - } + if (!engine->stringToCMap(text.data(), len, &glyphs, &numGlyphs, 0)) + Q_UNREACHABLE(); QFixed width; for (int i = 0; i < numGlyphs; ++i) @@ -594,10 +605,20 @@ int QFontMetrics::width(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<8> glyphs; - int nglyphs = 7; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0); - return qRound(glyphs.advances[0]); + QFixed advance; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyph_t glyph; + glyphs.glyphs = &glyph; + glyphs.advances = &advance; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + return qRound(advance); } /*! \obsolete @@ -639,10 +660,20 @@ int QFontMetrics::charWidth(const QString &text, int pos) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<8> glyphs; - int nglyphs = 7; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0); - width = qRound(glyphs.advances[0]); + QFixed advance; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyph_t glyph; + glyphs.glyphs = &glyph; + glyphs.advances = &advance; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + width = qRound(advance); } return width; } @@ -708,10 +739,18 @@ QRect QFontMetrics::boundingRect(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<10> glyphs; - int nglyphs = 9; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly); - glyph_metrics_t gm = engine->boundingBox(glyphs.glyphs[0]); + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + glyph_metrics_t gm = engine->boundingBox(glyph); return QRect(qRound(gm.x), qRound(gm.y), qRound(gm.width), qRound(gm.height)); } @@ -1326,12 +1365,19 @@ qreal QFontMetricsF::leftBearing(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<10> glyphs; - int nglyphs = 9; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly); - // ### can nglyphs != 1 happen at all? Not currently I think + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + qreal lb; - engine->getGlyphBearings(glyphs.glyphs[0], &lb); + engine->getGlyphBearings(glyph, &lb); return lb; } @@ -1361,12 +1407,19 @@ qreal QFontMetricsF::rightBearing(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<10> glyphs; - int nglyphs = 9; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly); - // ### can nglyphs != 1 happen at all? Not currently I think + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + qreal rb; - engine->getGlyphBearings(glyphs.glyphs[0], 0, &rb); + engine->getGlyphBearings(glyph, 0, &rb); return rb; } @@ -1431,10 +1484,20 @@ qreal QFontMetricsF::width(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<8> glyphs; - int nglyphs = 7; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0); - return glyphs.advances[0].toReal(); + QFixed advance; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyph_t glyph; + glyphs.glyphs = &glyph; + glyphs.advances = &advance; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + return advance.toReal(); } /*! @@ -1496,10 +1559,18 @@ QRectF QFontMetricsF::boundingRect(QChar ch) const d->alterCharForCapitalization(ch); - QGlyphLayoutArray<10> glyphs; - int nglyphs = 9; - engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly); - glyph_metrics_t gm = engine->boundingBox(glyphs.glyphs[0]); + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &glyph; + + int nglyphs = 1; + if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + glyph_metrics_t gm = engine->boundingBox(glyph); return QRectF(gm.x.toReal(), gm.y.toReal(), gm.width.toReal(), gm.height.toReal()); } diff --git a/src/gui/text/qfontsubset.cpp b/src/gui/text/qfontsubset.cpp index 152e15a54d..2109b16bb5 100644 --- a/src/gui/text/qfontsubset.cpp +++ b/src/gui/text/qfontsubset.cpp @@ -201,12 +201,22 @@ static void checkRanges(QPdf::ByteStream &ts, QByteArray &ranges, int &nranges) QVector<int> QFontSubset::getReverseMap() const { QVector<int> reverseMap(0x10000, 0); - QGlyphLayoutArray<10> glyphs; + + glyph_t glyph; + + QGlyphLayout glyphs; + glyphs.glyphs = &glyph; + glyphs.numGlyphs = 1; + for (uint uc = 0; uc < 0x10000; ++uc) { QChar ch(uc); - int nglyphs = 10; - fontEngine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly); - int idx = glyph_indices.indexOf(glyphs.glyphs[0]); + + int nglyphs = 1; + if (!fontEngine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + int idx = glyph_indices.indexOf(glyph); if (idx >= 0 && !reverseMap.at(idx)) reverseMap[idx] = uc; } diff --git a/src/gui/text/qharfbuzzng.cpp b/src/gui/text/qharfbuzzng.cpp index 010f955c60..9f77083102 100644 --- a/src/gui/text/qharfbuzzng.cpp +++ b/src/gui/text/qharfbuzzng.cpp @@ -397,13 +397,7 @@ _hb_qt_font_get_glyph(hb_font_t * /*font*/, void *font_data, QFontEngine *fe = (QFontEngine *)font_data; Q_ASSERT(fe); - glyph_t glyphs[2] = { 0, 0 }; - - QGlyphLayout g; - g.numGlyphs = 2; - g.glyphs = glyphs; - - QChar chars[4]; + QChar chars[2]; int numChars = 0; if (Q_UNLIKELY(QChar::requiresSurrogates(unicode))) { chars[numChars++] = QChar(QChar::highSurrogate(unicode)); @@ -422,11 +416,14 @@ _hb_qt_font_get_glyph(hb_font_t * /*font*/, void *font_data, } #endif - int numGlyphs = g.numGlyphs; - bool ok = fe->stringToCMap(chars, numChars, &g, &numGlyphs, QFontEngine::GlyphIndicesOnly); - Q_ASSERT(ok); Q_UNUSED(ok) + QGlyphLayout g; + g.numGlyphs = numChars; + g.glyphs = glyph; - *glyph = g.glyphs[0]; + int numGlyphs = numChars; + if (!fe->stringToCMap(chars, numChars, &g, &numGlyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); + Q_ASSERT(numGlyphs == 1); return true; } @@ -448,7 +445,7 @@ _hb_qt_font_get_glyph_h_advance(hb_font_t *font, void *font_data, fe->recalcAdvances(&g, QFontEngine::ShaperFlags(hb_qt_font_get_use_design_metrics(font))); - return g.advances[0].value(); + return advance.value(); } static hb_position_t @@ -497,7 +494,7 @@ _hb_qt_font_get_glyph_h_kerning(hb_font_t *font, void *font_data, fe->doKerning(&g, QFontEngine::ShaperFlags(hb_qt_font_get_use_design_metrics(font))); - return g.advances[0].value(); + return advance.value(); } static hb_position_t diff --git a/src/gui/text/qplatformfontdatabase.cpp b/src/gui/text/qplatformfontdatabase.cpp index 37610a9099..7936831e13 100644 --- a/src/gui/text/qplatformfontdatabase.cpp +++ b/src/gui/text/qplatformfontdatabase.cpp @@ -289,13 +289,11 @@ QFontEngineMulti *QPlatformFontDatabase::fontEngineMulti(QFontEngine *fontEngine Returns the font engine that can be used to render the font described by the font definition, \a fontDef, in the specified \a script. */ -QFontEngine *QPlatformFontDatabase::fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle) +QFontEngine *QPlatformFontDatabase::fontEngine(const QFontDef &fontDef, void *handle) { - Q_UNUSED(script); - Q_UNUSED(handle); QByteArray *fileDataPtr = static_cast<QByteArray *>(handle); QFontEngineQPA *engine = new QFontEngineQPA(fontDef,*fileDataPtr); - //qDebug() << fontDef.pixelSize << fontDef.weight << fontDef.style << fontDef.stretch << fontDef.styleHint << fontDef.styleStrategy << fontDef.family << script; + //qDebug() << fontDef.pixelSize << fontDef.weight << fontDef.style << fontDef.stretch << fontDef.styleHint << fontDef.styleStrategy << fontDef.family; return engine; } diff --git a/src/gui/text/qplatformfontdatabase.h b/src/gui/text/qplatformfontdatabase.h index 6053f11051..5f2c9a74ba 100644 --- a/src/gui/text/qplatformfontdatabase.h +++ b/src/gui/text/qplatformfontdatabase.h @@ -97,7 +97,7 @@ public: virtual ~QPlatformFontDatabase(); virtual void populateFontDatabase(); virtual QFontEngineMulti *fontEngineMulti(QFontEngine *fontEngine, QChar::Script script); - virtual QFontEngine *fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle); + virtual QFontEngine *fontEngine(const QFontDef &fontDef, void *handle); virtual QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const; virtual QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName); virtual void releaseHandle(void *handle); diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp index e26f7cdc93..449278df06 100644 --- a/src/gui/text/qrawfont.cpp +++ b/src/gui/text/qrawfont.cpp @@ -479,16 +479,8 @@ QVector<quint32> QRawFont::glyphIndexesForString(const QString &text) const QGlyphLayout glyphs; glyphs.numGlyphs = numGlyphs; glyphs.glyphs = glyphIndexes.data(); - if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly)) { - glyphIndexes.resize(numGlyphs); - - glyphs.numGlyphs = numGlyphs; - glyphs.glyphs = glyphIndexes.data(); - if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly)) { - Q_ASSERT_X(false, Q_FUNC_INFO, "stringToCMap shouldn't fail twice"); - return QVector<quint32>(); - } - } + if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly)) + Q_UNREACHABLE(); glyphIndexes.resize(numGlyphs); return glyphIndexes; @@ -565,10 +557,11 @@ bool QRawFont::advancesForGlyphIndexes(const quint32 *glyphIndexes, QPointF *adv if (!d->isValid() || numGlyphs <= 0) return false; + QVarLengthArray<QFixed> tmpAdvances(numGlyphs); + QGlyphLayout glyphs; glyphs.glyphs = const_cast<glyph_t *>(glyphIndexes); glyphs.numGlyphs = numGlyphs; - QVarLengthArray<QFixed> tmpAdvances(numGlyphs); glyphs.advances = tmpAdvances.data(); bool design = layoutFlags & UseDesignMetrics; @@ -578,7 +571,7 @@ bool QRawFont::advancesForGlyphIndexes(const quint32 *glyphIndexes, QPointF *adv d->fontEngine->doKerning(&glyphs, design ? QFontEngine::DesignMetrics : QFontEngine::ShaperFlag(0)); for (int i=0; i<numGlyphs; ++i) - advances[i] = QPointF(glyphs.advances[i].toReal(), 0.0); + advances[i] = QPointF(tmpAdvances[i].toReal(), 0.0); return true; } diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 2893d8b9b2..8a1096c269 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -932,18 +932,8 @@ void QTextEngine::shapeText(int item) const int nGlyphs = initialGlyphs.numGlyphs; QFontEngine::ShaperFlags shaperFlags(QFontEngine::GlyphIndicesOnly); - if (!fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags)) { - nGlyphs = qMax(nGlyphs, itemLength); // ### needed for QFontEngine::stringToCMap() to not fail twice - if (!ensureSpace(nGlyphs)) { - Q_UNREACHABLE(); // ### report OOM error somehow - return; - } - initialGlyphs = availableGlyphs(&si); - if (!fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags)) { - Q_UNREACHABLE(); // ### if this happens there is a bug in the fontengine - return; - } - } + if (!fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags)) + Q_UNREACHABLE(); uint lastEngine = 0; for (int i = 0, glyph_pos = 0; i < itemLength; ++i, ++glyph_pos) { @@ -1393,9 +1383,9 @@ void QTextEngine::shape(int item) const if (layoutData->items[item].analysis.flags == QScriptAnalysis::Object) { ensureSpace(1); if (block.docHandle()) { - QTextFormat format = formats()->format(formatIndex(&layoutData->items[item])); docLayout()->resizeInlineObject(QTextInlineObject(item, const_cast<QTextEngine *>(this)), - layoutData->items[item].position + block.position(), format); + layoutData->items[item].position + block.position(), + format(&layoutData->items[item])); } } else if (layoutData->items[item].analysis.flags == QScriptAnalysis::Tab) { // set up at least the ascent/descent/leading of the script item for the tab @@ -1427,7 +1417,7 @@ void QTextEngine::invalidate() minWidth = 0; maxWidth = 0; if (specialData) - specialData->resolvedFormatIndices.clear(); + specialData->resolvedFormats.clear(); resetFontEngineCache(); } @@ -1501,8 +1491,18 @@ void QTextEngine::itemize() const { QVarLengthArray<uchar> scripts(length); QUnicodeTools::initScripts(string, length, scripts.data()); - for (int i = 0; i < length; ++i) - analysis[i].script = scripts.at(i); + for (int i = 0; i < length; ++i) { + ushort script = scripts.at(i); + switch (script) { + case QChar::Script_Hiragana: + case QChar::Script_Katakana: + script = QChar::Script_Han; + break; + default: + break; + } + analysis[i].script = script; + } } const ushort *uc = string; @@ -1596,10 +1596,9 @@ void QTextEngine::itemize() const #ifndef QT_NO_RAWFONT if (useRawFont && specialData) { int lastIndex = 0; - const QTextFormatCollection *collection = formats(); for (int i = 0; i < specialData->addFormats.size(); ++i) { const QTextLayout::FormatRange &range = specialData->addFormats.at(i); - const QTextCharFormat format = collection->charFormat(specialData->addFormatIndices.at(i)); + const QTextCharFormat &format = range.format; if (format.hasProperty(QTextFormat::FontCapitalization)) { itemizer.generate(lastIndex, range.start - lastIndex, QFont::MixedCase); itemizer.generate(range.start, range.length, format.fontCapitalization()); @@ -1996,11 +1995,22 @@ static void set(QJustificationPoint *point, int type, const QGlyphLayout &glyph, if (type >= QGlyphAttributes::Arabic_Normal) { QChar ch(0x640); // Kashida character - QGlyphLayoutArray<8> glyphs; - int nglyphs = 7; - fe->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0); - if (glyphs.glyphs[0] != 0 && glyphs.advances[0].value() != 0) { - point->kashidaWidth = glyphs.advances[0]; + + glyph_t kashidaGlyph; + QFixed kashidaWidth; + + QGlyphLayout glyphs; + glyphs.numGlyphs = 1; + glyphs.glyphs = &kashidaGlyph; + glyphs.advances = &kashidaWidth; + + int nglyphs = 1; + if (!fe->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0)) + Q_UNREACHABLE(); + Q_ASSERT(nglyphs == 1); + + if (kashidaGlyph != 0 && kashidaWidth != 0) { + point->kashidaWidth = kashidaWidth; } else { point->type = QGlyphAttributes::NoJustification; point->kashidaWidth = 0; @@ -2360,8 +2370,12 @@ void QTextEngine::freeMemory() int QTextEngine::formatIndex(const QScriptItem *si) const { - if (specialData && !specialData->resolvedFormatIndices.isEmpty()) - return specialData->resolvedFormatIndices.at(si - &layoutData->items[0]); + if (specialData && !specialData->resolvedFormats.isEmpty()) { + QTextFormatCollection *collection = formats(); + Q_ASSERT(collection); + return collection->indexForFormat(specialData->resolvedFormats.at(si - &layoutData->items[0])); + } + QTextDocumentPrivate *p = block.docHandle(); if (!p) return -1; @@ -2474,23 +2488,6 @@ void QTextEngine::setPreeditArea(int position, const QString &preeditText) clearLineData(); } -QList<QTextLayout::FormatRange> QTextEngine::additionalFormats() const -{ - QList<QTextLayout::FormatRange> formatList; - if (!specialData) - return formatList; - - formatList = specialData->addFormats; - if (!specialData->addFormatIndices.isEmpty()) { - const QTextFormatCollection *formats = this->formats(); - Q_ASSERT(formats); - for (int i = 0; i < specialData->addFormatIndices.size(); ++i) - formatList[i].format = formats->charFormat(specialData->addFormatIndices.at(i)); - } - - return formatList; -} - void QTextEngine::setAdditionalFormats(const QList<QTextLayout::FormatRange> &formatList) { if (formatList.isEmpty()) { @@ -2501,7 +2498,6 @@ void QTextEngine::setAdditionalFormats(const QList<QTextLayout::FormatRange> &fo specialData = 0; } else { specialData->addFormats.clear(); - specialData->addFormatIndices.clear(); } } else { if (!specialData) { @@ -2516,19 +2512,17 @@ void QTextEngine::setAdditionalFormats(const QList<QTextLayout::FormatRange> &fo void QTextEngine::indexAdditionalFormats() { - specialData->addFormatIndices.resize(specialData->addFormats.count()); - - QTextFormatCollection *formats = this->formats(); - - if (!formats) { + QTextFormatCollection *collection = formats(); + if (!collection) { Q_ASSERT(!block.docHandle()); specialData->formats.reset(new QTextFormatCollection); - formats = specialData->formats.data(); + collection = specialData->formats.data(); } + // replace with shared copies for (int i = 0; i < specialData->addFormats.count(); ++i) { - specialData->addFormatIndices[i] = formats->indexForFormat(specialData->addFormats.at(i).format); - specialData->addFormats[i].format = QTextCharFormat(); + QTextCharFormat &format = specialData->addFormats[i].format; + format = collection->charFormat(collection->indexForFormat(format)); } } @@ -2648,10 +2642,10 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int if (feForEllipsis->type() == QFontEngine::Mac) feForEllipsis = fe; - if (feForEllipsis->canRender(&ellipsisChar, 1)) { - int nGlyphs = 1; - feForEllipsis->stringToCMap(&ellipsisChar, 1, &ellipsisGlyph, &nGlyphs, 0); - } + int nGlyphs = 1; + if (!feForEllipsis->stringToCMap(&ellipsisChar, 1, &ellipsisGlyph, &nGlyphs, 0)) + Q_UNREACHABLE(); + Q_ASSERT(nGlyphs == 1); } if (ellipsisGlyph.glyphs[0]) { @@ -2663,8 +2657,9 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int QGlyphLayoutArray<3> glyphs; int nGlyphs = 3; if (!fe->stringToCMap(dotDotDot.constData(), 3, &glyphs, &nGlyphs, 0)) - // should never happen... - return layoutData->string; + Q_UNREACHABLE(); + Q_ASSERT(nGlyphs == 3); + for (int i = 0; i < nGlyphs; ++i) ellipsisWidth += glyphs.advances[i]; ellipsisText = dotDotDot; @@ -2944,14 +2939,12 @@ public: void QTextEngine::resolveAdditionalFormats() const { if (!specialData || specialData->addFormats.isEmpty() - || !specialData->resolvedFormatIndices.isEmpty()) + || !specialData->resolvedFormats.isEmpty()) return; QTextFormatCollection *collection = formats(); - specialData->resolvedFormatIndices.clear(); - QVector<int> indices(layoutData->items.count()); - + specialData->resolvedFormats.resize(layoutData->items.count()); QVarLengthArray<int, 64> addFormatSortedByStart; addFormatSortedByStart.reserve(specialData->addFormats.count()); @@ -2987,21 +2980,22 @@ void QTextEngine::resolveAdditionalFormats() const currentFormats.remove(currentFormatIterator - currentFormats.begin()); ++endIt; } - QTextCharFormat format; + + QTextCharFormat &format = specialData->resolvedFormats[i]; if (block.docHandle()) { // when we have a docHandle, formatIndex might still return a valid index based // on the preeditPosition. for all other cases, we cleared the resolved format indices format = collection->charFormat(formatIndex(si)); } - - foreach (int cur, currentFormats) { - Q_ASSERT(specialData->addFormats.at(cur).start <= si->position - && specialData->addFormats.at(cur).start + specialData->addFormats.at(cur).length >= end); - format.merge(collection->format(specialData->addFormatIndices.at(cur))); + if (!currentFormats.isEmpty()) { + foreach (int cur, currentFormats) { + const QTextLayout::FormatRange &range = specialData->addFormats.at(cur); + Q_ASSERT(range.start <= si->position && range.start + range.length >= end); + format.merge(range.format); + } + format = collection->charFormat(collection->indexForFormat(format)); // get shared copy } - indices[i] = collection->indexForFormat(format); } - specialData->resolvedFormatIndices = indices; } QFixed QTextEngine::leadingSpaceWidth(const QScriptLine &line) diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index d399123609..1616a78937 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -603,7 +603,8 @@ public: void setPreeditArea(int position, const QString &text); inline bool hasFormats() const { return block.docHandle() || (specialData && !specialData->addFormats.isEmpty()); } - QList<QTextLayout::FormatRange> additionalFormats() const; + inline QList<QTextLayout::FormatRange> additionalFormats() const + { return specialData ? specialData->addFormats : QList<QTextLayout::FormatRange>(); } void setAdditionalFormats(const QList<QTextLayout::FormatRange> &formatList); private: @@ -613,8 +614,7 @@ private: int preeditPosition; QString preeditText; QList<QTextLayout::FormatRange> addFormats; - QVector<int> addFormatIndices; - QVector<int> resolvedFormatIndices; + QVector<QTextCharFormat> resolvedFormats; // only used when no docHandle is available QScopedPointer<QTextFormatCollection> formats; }; diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index c6e5160edc..0c9866c6cf 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -239,9 +239,7 @@ int QTextInlineObject::formatIndex() const */ QTextFormat QTextInlineObject::format() const { - if (!eng->block.docHandle()) - return QTextFormat(); - return eng->formats()->format(eng->formatIndex(&eng->layoutData->items[itm])); + return eng->format(&eng->layoutData->items[itm]); } /*! @@ -1812,9 +1810,10 @@ void QTextLine::layout_helper(int maxGlyphs) lbh.whiteSpaceOrObject = true; lbh.tmpData.length++; - QTextFormat format = eng->formats()->format(eng->formatIndex(&eng->layoutData->items[item])); - if (eng->block.docHandle()) - eng->docLayout()->positionInlineObject(QTextInlineObject(item, eng), eng->block.position() + current.position, format); + if (eng->block.docHandle()) { + QTextInlineObject inlineObject(item, eng); + eng->docLayout()->positionInlineObject(inlineObject, eng->block.position() + current.position, inlineObject.format()); + } lbh.tmpData.textWidth += current.width; diff --git a/src/opengl/gl2paintengineex/qglgradientcache.cpp b/src/opengl/gl2paintengineex/qglgradientcache.cpp index e0df4ccdf6..6160554472 100644 --- a/src/opengl/gl2paintengineex/qglgradientcache.cpp +++ b/src/opengl/gl2paintengineex/qglgradientcache.cpp @@ -184,7 +184,7 @@ void QGL2GradientCache::generateGradientColorTable(const QGradient& gradient, ui uint current_color = ARGB_COMBINE_ALPHA(colors[0], alpha); qreal incr = 1.0 / qreal(size); qreal fpos = 1.5 * incr; - colorTable[pos++] = qtToGlColor(PREMUL(current_color)); + colorTable[pos++] = qtToGlColor(qPremultiply(current_color)); while (fpos <= s.first().first) { colorTable[pos] = colorTable[pos - 1]; @@ -193,13 +193,13 @@ void QGL2GradientCache::generateGradientColorTable(const QGradient& gradient, ui } if (colorInterpolation) - current_color = PREMUL(current_color); + current_color = qPremultiply(current_color); for (int i = 0; i < s.size() - 1; ++i) { qreal delta = 1/(s[i+1].first - s[i].first); uint next_color = ARGB_COMBINE_ALPHA(colors[i+1], alpha); if (colorInterpolation) - next_color = PREMUL(next_color); + next_color = qPremultiply(next_color); while (fpos < s[i+1].first && pos < size) { int dist = int(256 * ((fpos - s[i].first) * delta)); @@ -207,7 +207,7 @@ void QGL2GradientCache::generateGradientColorTable(const QGradient& gradient, ui if (colorInterpolation) colorTable[pos] = qtToGlColor(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)); else - colorTable[pos] = qtToGlColor(PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist))); + colorTable[pos] = qtToGlColor(qPremultiply(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist))); ++pos; fpos += incr; } @@ -216,7 +216,7 @@ void QGL2GradientCache::generateGradientColorTable(const QGradient& gradient, ui Q_ASSERT(s.size() > 0); - uint last_color = qtToGlColor(PREMUL(ARGB_COMBINE_ALPHA(colors[s.size() - 1], alpha))); + uint last_color = qtToGlColor(qPremultiply(ARGB_COMBINE_ALPHA(colors[s.size() - 1], alpha))); for (;pos < size; ++pos) colorTable[pos] = last_color; diff --git a/src/platformsupport/eglconvenience/qeglconvenience.cpp b/src/platformsupport/eglconvenience/qeglconvenience.cpp index f51e471560..e561a6bc55 100644 --- a/src/platformsupport/eglconvenience/qeglconvenience.cpp +++ b/src/platformsupport/eglconvenience/qeglconvenience.cpp @@ -41,7 +41,7 @@ #include <QByteArray> -#if (defined(Q_OS_UNIX) && !defined(Q_OS_QNX)) +#ifdef Q_OS_LINUX #include <sys/ioctl.h> #include <linux/fb.h> #include <private/qmath_p.h> @@ -433,7 +433,7 @@ void q_printEglConfig(EGLDisplay display, EGLConfig config) qWarning("\n"); } -#if (defined(Q_OS_UNIX) && !defined(Q_OS_QNX)) +#ifdef Q_OS_LINUX QSizeF q_physicalScreenSizeFromFb(int framebufferDevice, const QSize &screenSize) { @@ -535,6 +535,6 @@ int q_screenDepthFromFb(int framebufferDevice) return depth; } -#endif // Q_OS_UNIX +#endif // Q_OS_LINUX QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp index 33f3601b97..1ed5ede3e8 100644 --- a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp +++ b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp @@ -113,27 +113,18 @@ void QBasicFontDatabase::populateFontDatabase() } } -QFontEngine *QBasicFontDatabase::fontEngine(const QFontDef &fontDef, QChar::Script script, void *usrPtr) +QFontEngine *QBasicFontDatabase::fontEngine(const QFontDef &fontDef, void *usrPtr) { - QFontEngineFT *engine; FontFile *fontfile = static_cast<FontFile *> (usrPtr); QFontEngine::FaceId fid; fid.filename = QFile::encodeName(fontfile->fileName); fid.index = fontfile->indexValue; - engine = new QFontEngineFT(fontDef); bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias); QFontEngineFT::GlyphFormat format = antialias? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono; - if (!engine->init(fid,antialias,format)) { - delete engine; - engine = 0; - return engine; - } - if (engine->invalid()) { - delete engine; - engine = 0; - } else if (!engine->supportsScript(script)) { - qWarning(" OpenType support missing for script %d", int(script)); + + QFontEngineFT *engine = new QFontEngineFT(fontDef); + if (!engine->init(fid, antialias, format) || engine->invalid()) { delete engine; engine = 0; } diff --git a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase_p.h b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase_p.h index 4d6fd2ceeb..45d7218ece 100644 --- a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase_p.h +++ b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase_p.h @@ -58,7 +58,7 @@ class QBasicFontDatabase : public QPlatformFontDatabase { public: void populateFontDatabase(); - QFontEngine *fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle); + QFontEngine *fontEngine(const QFontDef &fontDef, void *handle); QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const; QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName); diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp index c1ffa1b4fa..8b16e7520a 100644 --- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp +++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp @@ -516,7 +516,7 @@ QFontEngineMulti *QFontconfigDatabase::fontEngineMulti(QFontEngine *fontEngine, return new QFontEngineMultiFontConfig(fontEngine, script); } -QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, QChar::Script script, void *usrPtr) +QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, void *usrPtr) { if (!usrPtr) return 0; @@ -652,16 +652,7 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, QChar::Script sc FcPatternDestroy(pattern); - if (!engine->init(fid,antialias,format)) { - delete engine; - engine = 0; - return engine; - } - if (engine->invalid()) { - delete engine; - engine = 0; - } else if (!engine->supportsScript(script)) { - qWarning(" OpenType support missing for script %d", int(script)); + if (!engine->init(fid, antialias, format) || engine->invalid()) { delete engine; engine = 0; } diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h index 6d6dae680e..9f1fd28144 100644 --- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h +++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h @@ -52,7 +52,7 @@ class QFontconfigDatabase : public QBasicFontDatabase public: void populateFontDatabase(); QFontEngineMulti *fontEngineMulti(QFontEngine *fontEngine, QChar::Script script); - QFontEngine *fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle); + QFontEngine *fontEngine(const QFontDef &fontDef, void *handle); QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const; QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName); QString resolveFontFamilyAlias(const QString &family) const; diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index 473fdf895a..ab2e9c1f1a 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm @@ -278,10 +278,8 @@ void QCoreTextFontDatabase::releaseHandle(void *handle) CFRelease(CTFontDescriptorRef(handle)); } -QFontEngine *QCoreTextFontDatabase::fontEngine(const QFontDef &f, QChar::Script script, void *usrPtr) +QFontEngine *QCoreTextFontDatabase::fontEngine(const QFontDef &f, void *usrPtr) { - Q_UNUSED(script); - qreal scaledPointSize = f.pixelSize; // When 96 DPI is forced, the Mac plugin will use DPI 72 for some diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h index ce2eba41d0..1560d36644 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h @@ -72,7 +72,7 @@ public: QCoreTextFontDatabase(); ~QCoreTextFontDatabase(); void populateFontDatabase(); - QFontEngine *fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle); + QFontEngine *fontEngine(const QFontDef &fontDef, void *handle); QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const; QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName); diff --git a/src/platformsupport/glxconvenience/qglxconvenience.cpp b/src/platformsupport/glxconvenience/qglxconvenience.cpp index 11d9377db7..4630b12a57 100644 --- a/src/platformsupport/glxconvenience/qglxconvenience.cpp +++ b/src/platformsupport/glxconvenience/qglxconvenience.cpp @@ -39,6 +39,10 @@ ** ****************************************************************************/ +// We have to include this before the X11 headers dragged in by +// qglxconvenience_p.h. +#include <QtCore/QByteArray> + #include "qglxconvenience_p.h" #include <QtCore/QVector> @@ -116,6 +120,27 @@ QVector<int> qglx_buildSpec(const QSurfaceFormat &format, int drawableBit) GLXFBConfig qglx_findConfig(Display *display, int screen , const QSurfaceFormat &format, int drawableBit) { + // Allow forcing LIBGL_ALWAYS_SOFTWARE for Qt 5 applications only. + // This is most useful with drivers that only support OpenGL 1. + // We need OpenGL 2, but the user probably doesn't want + // LIBGL_ALWAYS_SOFTWARE in OpenGL 1 apps. + static bool checkedForceSoftwareOpenGL = false; + static bool forceSoftwareOpenGL = false; + if (!checkedForceSoftwareOpenGL) { + // If LIBGL_ALWAYS_SOFTWARE is already set, don't mess with it. + // We want to unset LIBGL_ALWAYS_SOFTWARE at the end so it does not + // get inherited by other processes, of course only if it wasn't + // already set before. + if (!qEnvironmentVariableIsEmpty("QT_XCB_FORCE_SOFTWARE_OPENGL") + && !qEnvironmentVariableIsSet("LIBGL_ALWAYS_SOFTWARE")) + forceSoftwareOpenGL = true; + + checkedForceSoftwareOpenGL = true; + } + + if (forceSoftwareOpenGL) + qputenv("LIBGL_ALWAYS_SOFTWARE", QByteArrayLiteral("1")); + bool reduced = true; GLXFBConfig chosenConfig = 0; QSurfaceFormat reducedFormat = format; @@ -159,6 +184,10 @@ GLXFBConfig qglx_findConfig(Display *display, int screen , const QSurfaceFormat reducedFormat = qglx_reduceSurfaceFormat(reducedFormat,&reduced); } + // unset LIBGL_ALWAYS_SOFTWARE now so other processes don't inherit it + if (forceSoftwareOpenGL) + qunsetenv("LIBGL_ALWAYS_SOFTWARE"); + return chosenConfig; } diff --git a/src/plugins/bearer/connman/connman.pro b/src/plugins/bearer/connman/connman.pro index cccdff0fdb..0da2dfacf6 100644 --- a/src/plugins/bearer/connman/connman.pro +++ b/src/plugins/bearer/connman/connman.pro @@ -5,6 +5,8 @@ PLUGIN_CLASS_NAME = QConnmanEnginePlugin load(qt_plugin) QT = core network-private dbus +CONFIG += link_pkgconfig +packagesExist(connectionagent) { DEFINES += QT_HAS_CONNECTIONAGENT } HEADERS += qconnmanservice_linux_p.h \ qofonoservice_linux_p.h \ diff --git a/src/plugins/bearer/connman/qconnmanengine.cpp b/src/plugins/bearer/connman/qconnmanengine.cpp index eac0d2b813..aee56eb034 100644 --- a/src/plugins/bearer/connman/qconnmanengine.cpp +++ b/src/plugins/bearer/connman/qconnmanengine.cpp @@ -41,7 +41,6 @@ #include "qconnmanengine.h" #include "qconnmanservice_linux_p.h" -#include "qofonoservice_linux_p.h" #include "../qnetworksession_impl.h" #include <QtNetwork/private/qnetworkconfiguration_p.h> @@ -55,7 +54,11 @@ #include <QtDBus/QDBusInterface> #include <QtDBus/QDBusMessage> #include <QtDBus/QDBusReply> - +#ifdef QT_HAS_CONNECTIONAGENT +#include <sys/inotify.h> +#include <fcntl.h> +#include <qcore_unix_p.h> +#endif #ifndef QT_NO_BEARERMANAGEMENT #ifndef QT_NO_DBUS @@ -63,7 +66,10 @@ QT_BEGIN_NAMESPACE QConnmanEngine::QConnmanEngine(QObject *parent) : QBearerEngineImpl(parent), - connmanManager(new QConnmanManagerInterface(this)) + connmanManager(new QConnmanManagerInterface(this)), + ofonoManager(new QOfonoManagerInterface(this)), + ofonoNetwork(0), + ofonoContextManager(0) { qDBusRegisterMetaType<ConnmanMap>(); qDBusRegisterMetaType<ConnmanMapList>(); @@ -72,6 +78,9 @@ QConnmanEngine::QConnmanEngine(QObject *parent) QConnmanEngine::~QConnmanEngine() { +#ifdef QT_HAS_CONNECTIONAGENT + qt_safe_close(inotifyFileDescriptor); +#endif } bool QConnmanEngine::connmanAvailable() const @@ -82,26 +91,56 @@ bool QConnmanEngine::connmanAvailable() const void QConnmanEngine::initialize() { - connect(connmanManager,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), - this,SLOT(propertyChangedContext(QString,QString,QDBusVariant))); + QMutexLocker locker(&mutex); + connect(ofonoManager,SIGNAL(modemChanged()),this,SLOT(changedModem())); + + ofonoNetwork = new QOfonoNetworkRegistrationInterface(ofonoManager->currentModem(),this); + ofonoContextManager = new QOfonoDataConnectionManagerInterface(ofonoManager->currentModem(),this); + connect(ofonoContextManager,SIGNAL(roamingAllowedChanged(bool)),this,SLOT(reEvaluateCellular())); connect(connmanManager,SIGNAL(servicesChanged(ConnmanMapList, QList<QDBusObjectPath>)), this, SLOT(updateServices(ConnmanMapList, QList<QDBusObjectPath>))); - foreach (const QString &techPath, connmanManager->getTechnologies()) { - QConnmanTechnologyInterface *tech; - tech = new QConnmanTechnologyInterface(techPath, this); + connect(connmanManager,SIGNAL(servicesReady(QStringList)),this,SLOT(servicesReady(QStringList))); + connect(connmanManager,SIGNAL(scanFinished()),this,SLOT(finishedScan())); - connect(tech,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), - this,SLOT(technologyPropertyChangedContext(QString,QString,QDBusVariant))); + foreach (const QString &servPath, connmanManager->getServices()) { + addServiceConfiguration(servPath); + } + Q_EMIT updateCompleted(); +#ifdef QT_HAS_CONNECTIONAGENT + QSettings confFile(QStringLiteral("nemomobile"),QStringLiteral("connectionagent")); + + inotifyFileDescriptor = ::inotify_init(); + inotifyWatcher = ::inotify_add_watch(inotifyFileDescriptor, QFile::encodeName(confFile.fileName()), IN_MODIFY); + if (inotifyWatcher > 0) { + QSocketNotifier *notifier = new QSocketNotifier(inotifyFileDescriptor, QSocketNotifier::Read, this); + connect(notifier, SIGNAL(activated(int)), this, SLOT(inotifyActivated())); } +#endif +} - foreach (const QString &servPath, connmanManager->getServices()) { +void QConnmanEngine::changedModem() +{ + QMutexLocker locker(&mutex); + if (ofonoNetwork) + delete ofonoNetwork; + + ofonoNetwork = new QOfonoNetworkRegistrationInterface(ofonoManager->currentModem(),this); + + if (ofonoContextManager) + delete ofonoContextManager; + ofonoContextManager = new QOfonoDataConnectionManagerInterface(ofonoManager->currentModem(),this); +} + +void QConnmanEngine::servicesReady(const QStringList &list) +{ + QMutexLocker locker(&mutex); + foreach (const QString &servPath, list) { addServiceConfiguration(servPath); } - // Get current list of access points. - getConfigurations(); + Q_EMIT updateCompleted(); } QList<QNetworkConfigurationPrivate *> QConnmanEngine::getConfigurations() @@ -129,13 +168,6 @@ QList<QNetworkConfigurationPrivate *> QConnmanEngine::getConfigurations() return fetchedConfigurations; } -void QConnmanEngine::doRequestUpdate() -{ - connmanManager->requestScan(""); - getConfigurations(); - emit updateCompleted(); -} - QString QConnmanEngine::getInterfaceFromId(const QString &id) { QMutexLocker locker(&mutex); @@ -151,24 +183,25 @@ bool QConnmanEngine::hasIdentifier(const QString &id) void QConnmanEngine::connectToId(const QString &id) { QMutexLocker locker(&mutex); - QString servicePath = serviceFromId(id); - QConnmanServiceInterface serv(servicePath); - if(!serv.isValid()) { + + QConnmanServiceInterface *serv = connmanServiceInterfaces.value(id); + + if (!serv->isValid()) { emit connectionError(id, QBearerEngineImpl::InterfaceLookupError); } else { - serv.connect(); + serv->connect(); } } void QConnmanEngine::disconnectFromId(const QString &id) { QMutexLocker locker(&mutex); - QString servicePath = serviceFromId(id); - QConnmanServiceInterface serv(servicePath); - if(!serv.isValid()) { + QConnmanServiceInterface *serv = connmanServiceInterfaces.value(id); + + if (!serv->isValid()) { emit connectionError(id, DisconnectionError); } else { - serv.disconnect(); + serv->disconnect(); } } @@ -178,31 +211,32 @@ void QConnmanEngine::requestUpdate() QTimer::singleShot(0, this, SLOT(doRequestUpdate())); } +void QConnmanEngine::doRequestUpdate() +{ + connmanManager->requestScan("wifi"); +} + +void QConnmanEngine::finishedScan() +{ +} + void QConnmanEngine::updateServices(const ConnmanMapList &changed, const QList<QDBusObjectPath> &removed) { + QMutexLocker locker(&mutex); + foreach (const QDBusObjectPath &objectPath, removed) { - removeConfiguration(QString::number(qHash(objectPath.path()))); + removeConfiguration(objectPath.path()); } foreach (const ConnmanMap &connmanMap, changed) { - const QString id = QString::number(qHash(connmanMap.objectPath.path())); + const QString id = connmanMap.objectPath.path(); if (accessPointConfigurations.contains(id)) { - configurationChange(id); + configurationChange(connmanServiceInterfaces.value(id)); } else { addServiceConfiguration(connmanMap.objectPath.path()); } } -} - -QString QConnmanEngine::serviceFromId(const QString &id) -{ - QMutexLocker locker(&mutex); - foreach (const QString &service, serviceNetworks) { - if (id == QString::number(qHash(service))) - return service; - } - - return QString(); + Q_EMIT updateCompleted(); } QNetworkSession::State QConnmanEngine::sessionStateForId(const QString &id) @@ -211,25 +245,24 @@ QNetworkSession::State QConnmanEngine::sessionStateForId(const QString &id) QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); - if (!ptr) + if (!ptr || !ptr->isValid) return QNetworkSession::Invalid; - if (!ptr->isValid) { - return QNetworkSession::Invalid; + QString service = id; + QConnmanServiceInterface *serv = connmanServiceInterfaces.value(service); - } - QString service = serviceFromId(id); - QConnmanServiceInterface serv(service); - QString servState = serv.getState(); + QString servState = serv->state(); - if(serv.isFavorite() && (servState == "idle" || servState == "failure")) { + if (serv->favorite() && (servState == QLatin1String("idle") || servState == QLatin1String("failure"))) { return QNetworkSession::Disconnected; } - if(servState == "association" || servState == "configuration" || servState == "login") { + if (servState == QLatin1String("association") || servState == QLatin1String("configuration") + || servState == QLatin1String("ready")) { return QNetworkSession::Connecting; } - if(servState == "ready" || servState == "online") { + + if (servState == QLatin1String("online")) { return QNetworkSession::Connected; } @@ -300,88 +333,36 @@ QNetworkSessionPrivate *QConnmanEngine::createSessionBackend() QNetworkConfigurationPrivatePointer QConnmanEngine::defaultConfiguration() { - return QNetworkConfigurationPrivatePointer(); -} - -void QConnmanEngine::propertyChangedContext(const QString &path,const QString &item, const QDBusVariant &value) -{ - Q_UNUSED(path); - - QMutexLocker locker(&mutex); - if(item == "Services") { - QDBusArgument arg = qvariant_cast<QDBusArgument>(value.variant()); - QStringList list = qdbus_cast<QStringList>(arg); - - if(list.count() > accessPointConfigurations.count()) { - foreach (const QString &service, list) { - addServiceConfiguration(service); - } - } - } - - if(item == "Technologies") { - QDBusArgument arg = qvariant_cast<QDBusArgument>(value.variant()); - QStringList newlist = qdbus_cast<QStringList>(arg); - if(newlist.count() > 0) { - QMap<QString,QConnmanTechnologyInterface *> oldtech = technologies; - - foreach (const QString &listPath, newlist) { - if(!oldtech.contains(listPath)) { - QConnmanTechnologyInterface *tech; - tech = new QConnmanTechnologyInterface(listPath,this); - connect(tech,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), - this,SLOT(technologyPropertyChangedContext(QString,QString,QDBusVariant))); - technologies.insert(listPath, tech); - } - } - } - } - if(item == "State") { -// qDebug() << value.variant(); - } -} - -void QConnmanEngine::servicePropertyChangedContext(const QString &path,const QString &item, const QDBusVariant &value) -{ - QMutexLocker locker(&mutex); - if(item == "State") { - configurationChange(QString::number(qHash(path))); - - if(value.variant().toString() == "failure") { - QConnmanServiceInterface serv(path); - emit connectionError(QString::number(qHash(path)), ConnectError); + const QMutexLocker locker(&mutex); + Q_FOREACH (const QString &servPath, connmanManager->getServices()) { + if (connmanServiceInterfaces.contains(servPath)) { + if (accessPointConfigurations.contains(servPath)) + return accessPointConfigurations.value(servPath); } } + return QNetworkConfigurationPrivatePointer(); } -void QConnmanEngine::technologyPropertyChangedContext(const QString & path, const QString &item, const QDBusVariant &value) +void QConnmanEngine::serviceStateChanged(const QString &state) { - if(item == "State") { - if(value.variant().toString() == "offline") { - QConnmanTechnologyInterface tech(path); - disconnect(&tech,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), - this,SLOT(technologyPropertyChangedContext(QString,QString,QDBusVariant))); + QConnmanServiceInterface *service = qobject_cast<QConnmanServiceInterface *>(sender()); + configurationChange(service); - technologies.remove(path); - } + if (state == QStringLiteral("failure")) { + emit connectionError(service->path(), ConnectError); } } -void QConnmanEngine::configurationChange(const QString &id) +void QConnmanEngine::configurationChange(QConnmanServiceInterface *serv) { QMutexLocker locker(&mutex); + QString id = serv->path(); if (accessPointConfigurations.contains(id)) { bool changed = false; QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); - - QString servicePath = serviceFromId(id); - QConnmanServiceInterface *serv; - serv = new QConnmanServiceInterface(servicePath); - QString networkName = serv->getName(); - - QNetworkConfiguration::StateFlags curState = getStateForService(servicePath); - + QString networkName = serv->name(); + QNetworkConfiguration::StateFlags curState = getStateForService(serv->path()); ptr->mutex.lock(); if (!ptr->isValid) { @@ -414,26 +395,31 @@ void QConnmanEngine::configurationChange(const QString &id) QNetworkConfiguration::StateFlags QConnmanEngine::getStateForService(const QString &service) { QMutexLocker locker(&mutex); - QConnmanServiceInterface serv(service); + QConnmanServiceInterface *serv = connmanServiceInterfaces.value(service); + QString state = serv->state(); + QNetworkConfiguration::StateFlags flag = QNetworkConfiguration::Defined; - if (serv.getType() == "cellular") { - if (serv.isSetupRequired() || !serv.isAutoConnect() || (serv.isRoaming() && isAlwaysAskRoaming())) { - flag = ( flag | QNetworkConfiguration::Defined); + + if (serv->type() == QLatin1String("cellular")) { + + if (!serv->autoConnect() + || (serv->roaming() + && (isAlwaysAskRoaming() || !isRoamingAllowed(serv->path())))) { + flag = (flag | QNetworkConfiguration::Defined); } else { - flag = ( flag | QNetworkConfiguration::Discovered); + flag = (flag | QNetworkConfiguration::Discovered); } } else { - if (serv.isFavorite()) { - if (serv.isAutoConnect()) { - flag = ( flag | QNetworkConfiguration::Discovered); + if (serv->favorite()) { + if (serv->autoConnect()) { + flag = (flag | QNetworkConfiguration::Discovered); } } else { flag = QNetworkConfiguration::Undefined; } } - - if (serv.getState() == "ready" || serv.getState() == "online") { - flag = ( flag | QNetworkConfiguration::Active); + if (state == QLatin1String("online")) { + flag = (flag | QNetworkConfiguration::Active); } return flag; @@ -441,51 +427,35 @@ QNetworkConfiguration::StateFlags QConnmanEngine::getStateForService(const QStri QNetworkConfiguration::BearerType QConnmanEngine::typeToBearer(const QString &type) { - if (type == "wifi") + if (type == QLatin1String("wifi")) return QNetworkConfiguration::BearerWLAN; - if (type == "ethernet") + if (type == QLatin1String("ethernet")) return QNetworkConfiguration::BearerEthernet; - if (type == "bluetooth") + if (type == QLatin1String("bluetooth")) return QNetworkConfiguration::BearerBluetooth; - if (type == "cellular") { + if (type == QLatin1String("cellular")) { return ofonoTechToBearerType(type); } - if (type == "wimax") + if (type == QLatin1String("wimax")) return QNetworkConfiguration::BearerWiMAX; -// if(type == "gps") -// if(type == "vpn") - return QNetworkConfiguration::BearerUnknown; } QNetworkConfiguration::BearerType QConnmanEngine::ofonoTechToBearerType(const QString &/*type*/) { - QOfonoManagerInterface ofonoManager(this); - QOfonoNetworkRegistrationInterface ofonoNetwork(ofonoManager.currentModem().path(),this); - - if(ofonoNetwork.isValid()) { - foreach (const QDBusObjectPath &op,ofonoNetwork.getOperators() ) { - QOfonoNetworkOperatorInterface opIface(op.path(),this); - - foreach (const QString &opTech, opIface.getTechnologies()) { - - if(opTech == "gsm") { - return QNetworkConfiguration::Bearer2G; - } - if(opTech == "edge"){ - return QNetworkConfiguration::BearerCDMA2000; //wrong, I know - } - if(opTech == "umts"){ - return QNetworkConfiguration::BearerWCDMA; - } - if(opTech == "hspa"){ - return QNetworkConfiguration::BearerHSPA; - } - if(opTech == "lte"){ - return QNetworkConfiguration::BearerWiMAX; //not exact - } - } + if (ofonoNetwork) { + QString currentTechnology = ofonoNetwork->getTechnology(); + if (currentTechnology == QLatin1String("gsm")) { + return QNetworkConfiguration::Bearer2G; + } else if (currentTechnology == QLatin1String("edge")) { + return QNetworkConfiguration::BearerCDMA2000; //wrong, I know + } else if (currentTechnology == QLatin1String("umts")) { + return QNetworkConfiguration::BearerWCDMA; + } else if (currentTechnology == QLatin1String("hspa")) { + return QNetworkConfiguration::BearerHSPA; + } else if (currentTechnology == QLatin1String("lte")) { + return QNetworkConfiguration::BearerWiMAX; //not exact } } return QNetworkConfiguration::BearerUnknown; @@ -493,12 +463,9 @@ QNetworkConfiguration::BearerType QConnmanEngine::ofonoTechToBearerType(const QS bool QConnmanEngine::isRoamingAllowed(const QString &context) { - QOfonoManagerInterface ofonoManager(this); - QString modemPath = ofonoManager.currentModem().path(); - QOfonoDataConnectionManagerInterface dc(modemPath,this); - foreach (const QDBusObjectPath &dcPath,dc.getPrimaryContexts()) { - if(dcPath.path().contains(context.section("_",-1))) { - return dc.isRoamingAllowed(); + foreach (const QString &dcPath, ofonoContextManager->contexts()) { + if (dcPath.contains(context.section("_",-1))) { + return ofonoContextManager->roamingAllowed(); } } return false; @@ -510,14 +477,11 @@ void QConnmanEngine::removeConfiguration(const QString &id) if (accessPointConfigurations.contains(id)) { - QString service = serviceFromId(id); - QConnmanServiceInterface serv(service); - - disconnect(&serv,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), - this,SLOT(servicePropertyChangedContext(QString,QString,QDBusVariant))); - - serviceNetworks.removeOne(service); - + disconnect(connmanServiceInterfaces.value(id),SIGNAL(stateChanged(QString)), + this,SLOT(serviceStateChanged(QString))); + serviceNetworks.removeOne(id); + QConnmanServiceInterface *service = connmanServiceInterfaces.take(id); + delete service; QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(id); foundConfigurations.removeOne(ptr.data()); locker.unlock(); @@ -529,35 +493,32 @@ void QConnmanEngine::removeConfiguration(const QString &id) void QConnmanEngine::addServiceConfiguration(const QString &servicePath) { QMutexLocker locker(&mutex); - QConnmanServiceInterface *serv; - serv = new QConnmanServiceInterface(servicePath); + if (!connmanServiceInterfaces.contains(servicePath)) { + QConnmanServiceInterface *serv = new QConnmanServiceInterface(servicePath); + connmanServiceInterfaces.insert(serv->path(),serv); + } - const QString id = QString::number(qHash(servicePath)); + if (!accessPointConfigurations.contains(servicePath)) { - if (!accessPointConfigurations.contains(id)) { serviceNetworks.append(servicePath); - connect(serv,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), - this,SLOT(servicePropertyChangedContext(QString,QString,QDBusVariant))); + connect(connmanServiceInterfaces.value(servicePath),SIGNAL(stateChanged(QString)), + this,SLOT(serviceStateChanged(QString))); + QNetworkConfigurationPrivate* cpPriv = new QNetworkConfigurationPrivate(); + QConnmanServiceInterface *service = connmanServiceInterfaces.value(servicePath); - QString networkName = serv->getName(); + QString networkName = service->name(); - const QString connectionType = serv->getType(); - if (connectionType == "ethernet") { + const QString connectionType = service->type(); + if (connectionType == QLatin1String("ethernet")) { cpPriv->bearerType = QNetworkConfiguration::BearerEthernet; - } else if (connectionType == "wifi") { + } else if (connectionType == QLatin1String("wifi")) { cpPriv->bearerType = QNetworkConfiguration::BearerWLAN; - } else if (connectionType == "cellular") { - cpPriv->bearerType = ofonoTechToBearerType("cellular"); - if(servicePath.isEmpty()) { - networkName = serv->getAPN(); - if(networkName.isEmpty()) { - networkName = serv->getName(); - } - } - cpPriv->roamingSupported = isRoamingAllowed(servicePath); - } else if (connectionType == "wimax") { + } else if (connectionType == QLatin1String("cellular")) { + cpPriv->bearerType = ofonoTechToBearerType(QLatin1String("cellular")); + cpPriv->roamingSupported = service->roaming() && isRoamingAllowed(servicePath); + } else if (connectionType == QLatin1String("wimax")) { cpPriv->bearerType = QNetworkConfiguration::BearerWiMAX; } else { cpPriv->bearerType = QNetworkConfiguration::BearerUnknown; @@ -565,10 +526,10 @@ void QConnmanEngine::addServiceConfiguration(const QString &servicePath) cpPriv->name = networkName; cpPriv->isValid = true; - cpPriv->id = id; + cpPriv->id = servicePath; cpPriv->type = QNetworkConfiguration::InternetAccessPoint; - if(serv->getSecurity() == "none") { + if (service->security() == QStringLiteral("none")) { cpPriv->purpose = QNetworkConfiguration::PublicPurpose; } else { cpPriv->purpose = QNetworkConfiguration::PrivatePurpose; @@ -578,13 +539,16 @@ void QConnmanEngine::addServiceConfiguration(const QString &servicePath) QNetworkConfigurationPrivatePointer ptr(cpPriv); accessPointConfigurations.insert(ptr->id, ptr); - foundConfigurations.append(cpPriv); - configInterfaces[cpPriv->id] = serv->getInterface(); + if (connectionType == QLatin1String("cellular")) { + foundConfigurations.append(cpPriv); + } else { + foundConfigurations.prepend(cpPriv); + } + configInterfaces[cpPriv->id] = service->serviceInterface(); locker.unlock(); - emit configurationAdded(ptr); + Q_EMIT configurationAdded(ptr); locker.relock(); - emit updateCompleted(); } } @@ -595,10 +559,39 @@ bool QConnmanEngine::requiresPolling() const bool QConnmanEngine::isAlwaysAskRoaming() { - QSettings confFile(QStringLiteral("nemomobile"), QStringLiteral("connectionagent")); +#ifdef QT_HAS_CONNECTIONAGENT + QSettings confFile(QStringLiteral("nemomobile"),QStringLiteral("connectionagent")); confFile.beginGroup(QStringLiteral("Connectionagent")); return confFile.value(QStringLiteral("askForRoaming")).toBool(); +#else + return false; +#endif } + +void QConnmanEngine::reEvaluateCellular() +{ + Q_FOREACH (const QString &servicePath, connmanManager->getServices()) { + if (servicePath.contains("cellular") && accessPointConfigurations.contains(servicePath)) { + configurationChange(connmanServiceInterfaces.value(servicePath)); + } + } +} + +void QConnmanEngine::inotifyActivated() +{ +#ifdef QT_HAS_CONNECTIONAGENT + + char buffer[1024]; + int len = qt_safe_read(inotifyFileDescriptor, (void *)buffer, sizeof(buffer)); + if (len > 0) { + struct inotify_event *event = (struct inotify_event *)buffer; + if (event->wd == inotifyWatcher && (event->mask & IN_MODIFY) == 0) { + QTimer::singleShot(1000, this, SLOT(reEvaluateCellular())); //give this time to finish write + } + } +#endif +} + QT_END_NAMESPACE #endif // QT_NO_DBUS diff --git a/src/plugins/bearer/connman/qconnmanengine.h b/src/plugins/bearer/connman/qconnmanengine.h index 49a1a91d29..4a4e91659b 100644 --- a/src/plugins/bearer/connman/qconnmanengine.h +++ b/src/plugins/bearer/connman/qconnmanengine.h @@ -56,6 +56,7 @@ #include "../qbearerengine_impl.h" #include "qconnmanservice_linux_p.h" +#include "qofonoservice_linux_p.h" #include <QMap> #include <QVariant> @@ -91,28 +92,32 @@ public: virtual quint64 bytesReceived(const QString &id); virtual quint64 startTime(const QString &id); - virtual QNetworkConfigurationManager::Capabilities capabilities() const; virtual QNetworkConfigurationPrivatePointer defaultConfiguration(); - void configurationChange(const QString &id); QList<QNetworkConfigurationPrivate *> getConfigurations(); - private Q_SLOTS: void doRequestUpdate(); - void servicePropertyChangedContext(const QString &,const QString &,const QDBusVariant &); - void propertyChangedContext(const QString &,const QString &,const QDBusVariant &); - void technologyPropertyChangedContext(const QString &,const QString &, const QDBusVariant &); void updateServices(const ConnmanMapList &changed, const QList<QDBusObjectPath> &removed); + void servicesReady(const QStringList &); + void finishedScan(); + void changedModem(); + void serviceStateChanged(const QString &state); + void configurationChange(QConnmanServiceInterface * service); + void reEvaluateCellular(); + void inotifyActivated(); private: QConnmanManagerInterface *connmanManager; + QOfonoManagerInterface *ofonoManager; + QOfonoNetworkRegistrationInterface *ofonoNetwork; + QOfonoDataConnectionManagerInterface *ofonoContextManager; + QList<QNetworkConfigurationPrivate *> foundConfigurations; - QString serviceFromId(const QString &id); QString networkFromId(const QString &id); QNetworkConfiguration::StateFlags getStateForService(const QString &service); @@ -130,6 +135,11 @@ private: QNetworkConfiguration::BearerType ofonoTechToBearerType(const QString &type); bool isRoamingAllowed(const QString &context); bool isAlwaysAskRoaming(); + QMap <QString,QConnmanServiceInterface *> connmanServiceInterfaces; + + int inotifyWatcher; + int inotifyFileDescriptor; + protected: bool requiresPolling() const; }; diff --git a/src/plugins/bearer/connman/qconnmanservice_linux.cpp b/src/plugins/bearer/connman/qconnmanservice_linux.cpp index 6d9ee265c6..46b24f77dd 100644 --- a/src/plugins/bearer/connman/qconnmanservice_linux.cpp +++ b/src/plugins/bearer/connman/qconnmanservice_linux.cpp @@ -75,708 +75,380 @@ const QDBusArgument &operator>>(const QDBusArgument &argument, ConnmanMap &map) } QConnmanManagerInterface::QConnmanManagerInterface( QObject *parent) - : QDBusAbstractInterface(QLatin1String(CONNMAN_SERVICE), - QLatin1String(CONNMAN_MANAGER_PATH), + : QDBusAbstractInterface(QStringLiteral(CONNMAN_SERVICE), + QStringLiteral(CONNMAN_MANAGER_PATH), CONNMAN_MANAGER_INTERFACE, QDBusConnection::systemBus(), parent) { qDBusRegisterMetaType<ConnmanMap>(); qDBusRegisterMetaType<ConnmanMapList>(); -} -QConnmanManagerInterface::~QConnmanManagerInterface() -{ -} + QList<QVariant> argumentList; + QDBusPendingReply<QVariantMap> props_reply = asyncCallWithArgumentList(QLatin1String("GetProperties"), argumentList); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(props_reply, this); -void QConnmanManagerInterface::connectNotify(const QMetaMethod &signal) -{ - static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QConnmanManagerInterface::propertyChanged); - if (signal == propertyChangedSignal) { - if(!connection().connect(QLatin1String(CONNMAN_SERVICE), - QLatin1String(CONNMAN_MANAGER_PATH), - QLatin1String(CONNMAN_MANAGER_INTERFACE), - QLatin1String("PropertyChanged"), - this,SIGNAL(propertyChanged(QString,QDBusVariant)))) { - qWarning() << "PropertyChanged not connected"; - } - } + QObject::connect(watcher,SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(propertiesReply(QDBusPendingCallWatcher*))); - static const QMetaMethod stateChangedSignal = QMetaMethod::fromSignal(&QConnmanManagerInterface::stateChanged); - if (signal == stateChangedSignal) { - if (!connection().connect(QLatin1String(CONNMAN_SERVICE), - QLatin1String(CONNMAN_MANAGER_PATH), - QLatin1String(CONNMAN_MANAGER_INTERFACE), - QLatin1String("StateChanged"), - this,SIGNAL(stateChanged(QString)))) { - qWarning() << "StateChanged not connected"; + QDBusConnection::systemBus().connect(QStringLiteral(CONNMAN_SERVICE), + QStringLiteral(CONNMAN_MANAGER_PATH), + QStringLiteral(CONNMAN_SERVICE_INTERFACE), + QStringLiteral("PropertyChanged"), + this,SLOT(changedProperty(QString,QDBusVariant))); - } - } - static const QMetaMethod propertyChangedContextSignal = QMetaMethod::fromSignal(&QConnmanManagerInterface::propertyChangedContext); - if (signal == propertyChangedContextSignal) { - QConnmanDBusHelper *helper; - helper = new QConnmanDBusHelper(this); - - QDBusConnection::systemBus().connect(QLatin1String(CONNMAN_SERVICE), - QLatin1String(CONNMAN_MANAGER_PATH), - QLatin1String(CONNMAN_MANAGER_INTERFACE), - QLatin1String("PropertyChanged"), - helper,SLOT(propertyChanged(QString,QDBusVariant))); + QDBusConnection::systemBus().connect(QStringLiteral(CONNMAN_SERVICE), + QStringLiteral(CONNMAN_MANAGER_PATH), + QStringLiteral(CONNMAN_SERVICE_INTERFACE), + QStringLiteral("TechnologyAdded"), + this,SLOT(technologyAdded(QDBusObjectPath,QVariantMap))); - QObject::connect(helper,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), - this,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), Qt::UniqueConnection); - } - static const QMetaMethod servicesChangedSignal = QMetaMethod::fromSignal(&QConnmanManagerInterface::servicesChanged); - if (signal == servicesChangedSignal) { - if (!connection().connect(QLatin1String(CONNMAN_SERVICE), - QLatin1String(CONNMAN_MANAGER_PATH), - QLatin1String(CONNMAN_MANAGER_INTERFACE), - QLatin1String("ServicesChanged"), - this,SLOT(onServicesChanged(ConnmanMapList, QList<QDBusObjectPath>)))) { - qWarning() << "servicesChanged not connected"; - } - } -} - -void QConnmanManagerInterface::onServicesChanged(const ConnmanMapList &changed, const QList<QDBusObjectPath> &removed) -{ - emit servicesChanged(changed, removed); -} - - -void QConnmanManagerInterface::disconnectNotify(const QMetaMethod &signal) -{ - static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QConnmanManagerInterface::propertyChanged); - if (signal == propertyChangedSignal) { - - } -} - -QVariant QConnmanManagerInterface::getProperty(const QString &property) -{ - QVariant var; - QVariantMap map = getProperties(); - if (map.contains(property)) { - var = map.value(property); - } else { - qDebug() << "does not contain" << property; - } - return var; -} - -QVariantMap QConnmanManagerInterface::getProperties() -{ - if(this->isValid()) { - QDBusReply<QVariantMap > reply = this->call(QLatin1String("GetProperties")); - return reply.value(); - } else return QVariantMap(); -} + QDBusConnection::systemBus().connect(QStringLiteral(CONNMAN_SERVICE), + QStringLiteral(CONNMAN_MANAGER_PATH), + QStringLiteral(CONNMAN_SERVICE_INTERFACE), + QStringLiteral("TechnologyRemoved"), + this,SLOT(technologyRemoved(QDBusObjectPath))); -QString QConnmanManagerInterface::getState() -{ - QDBusReply<QString > reply = this->call("GetState"); - return reply.value(); -} + QList<QVariant> argumentList2; + QDBusPendingReply<ConnmanMapList> serv_reply = asyncCallWithArgumentList(QLatin1String("GetServices"), argumentList2); + QDBusPendingCallWatcher *watcher2 = new QDBusPendingCallWatcher(serv_reply, this); -bool QConnmanManagerInterface::setProperty(const QString &name, const QDBusVariant &value) -{ - Q_UNUSED(name); - Q_UNUSED(value); - return false; -} + QObject::connect(watcher2,SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(servicesReply(QDBusPendingCallWatcher*))); -QDBusObjectPath QConnmanManagerInterface::createProfile(const QString &/*name*/) -{ - return QDBusObjectPath(); } -bool QConnmanManagerInterface::removeProfile(QDBusObjectPath /*path*/) +QConnmanManagerInterface::~QConnmanManagerInterface() { - return false; } -bool QConnmanManagerInterface::requestScan(const QString &type) +void QConnmanManagerInterface::changedProperty(const QString &name, const QDBusVariant &value) { - QDBusReply<QString> reply = this->call(QLatin1String("RequestScan"), QVariant::fromValue(type)); - - bool ok = true; - if(reply.error().type() == QDBusError::InvalidArgs) { - qWarning() << reply.error().message(); - ok = false; - } - return ok; + propertiesCacheMap[name] = value.variant(); } -bool QConnmanManagerInterface::enableTechnology(const QString &type) +void QConnmanManagerInterface::propertiesReply(QDBusPendingCallWatcher *call) { - QDBusReply<QList<QDBusObjectPath> > reply = this->call(QLatin1String("EnableTechnology"), QVariant::fromValue(type)); - bool ok = true; - if(reply.error().type() == QDBusError::InvalidArgs) { - qWarning() << reply.error().message(); - ok = false; - } - return ok; -} + QDBusPendingReply<QVariantMap> props_reply = *call; -bool QConnmanManagerInterface::disableTechnology(const QString &type) -{ - QDBusReply<QList<QDBusObjectPath> > reply = this->call(QLatin1String("DisableTechnology"), QVariant::fromValue(type)); - bool ok = true; - if(reply.error().type() == QDBusError::InvalidArgs) { - qWarning() << reply.error().message(); - ok = false; + if (props_reply.isError()) { + qDebug() << props_reply.error().message(); + } else { + propertiesCacheMap = props_reply.value(); } - return ok; + call->deleteLater(); } -QDBusObjectPath QConnmanManagerInterface::connectService(QVariantMap &map) +void QConnmanManagerInterface::servicesReply(QDBusPendingCallWatcher *call) { - QDBusReply<QDBusObjectPath > reply = this->call(QLatin1String("ConnectService"), QVariant::fromValue(map)); - if(!reply.isValid()) { - qDebug() << reply.error().message(); + QDBusPendingReply<ConnmanMapList> serv_reply = *call; + if (serv_reply.isError()) { + qDebug() << serv_reply.error().message(); + } else { + servicesList.clear(); //connman list changes order + ConnmanMap connmanobj; + Q_FOREACH (connmanobj, serv_reply.value()) { + servicesList << connmanobj.objectPath.path(); + } + Q_EMIT servicesReady(servicesList); } - return reply; + call->deleteLater(); } -void QConnmanManagerInterface::registerAgent(QDBusObjectPath &/*path*/) -{ -} - -void QConnmanManagerInterface::unregisterAgent(QDBusObjectPath /*path*/) +void QConnmanManagerInterface::connectNotify(const QMetaMethod &signal) { -} - -void QConnmanManagerInterface::registerCounter(const QString &path, quint32 interval) -{ QDBusReply<QList<QDBusObjectPath> > reply = this->call(QLatin1String("RegisterCounter"), - QVariant::fromValue(path), - QVariant::fromValue(interval)); - if(reply.error().type() == QDBusError::InvalidArgs) { - qWarning() << reply.error().message(); + static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QConnmanManagerInterface::propertyChanged); + if (signal == propertyChangedSignal) { + if (!connection().connect(QStringLiteral(CONNMAN_SERVICE), + QStringLiteral(CONNMAN_MANAGER_PATH), + QStringLiteral(CONNMAN_MANAGER_INTERFACE), + QStringLiteral("PropertyChanged"), + this,SIGNAL(propertyChanged(QString,QDBusVariant)))) { + qWarning() << "PropertyChanged not connected"; + } } -} -void QConnmanManagerInterface::unregisterCounter(const QString &path) -{ QDBusReply<QList<QDBusObjectPath> > reply = this->call(QLatin1String("UnregisterCounter"), - QVariant::fromValue(path)); - if(reply.error().type() == QDBusError::InvalidArgs) { - qWarning() << reply.error().message(); + static const QMetaMethod servicesChangedSignal = QMetaMethod::fromSignal(&QConnmanManagerInterface::servicesChanged); + if (signal == servicesChangedSignal) { + if (!connection().connect(QStringLiteral(CONNMAN_SERVICE), + QStringLiteral(CONNMAN_MANAGER_PATH), + QStringLiteral(CONNMAN_MANAGER_INTERFACE), + QStringLiteral("ServicesChanged"), + this,SLOT(onServicesChanged(ConnmanMapList, QList<QDBusObjectPath>)))) { + qWarning() << "servicesChanged not connected"; + } } } -QString QConnmanManagerInterface::requestSession(const QString &bearerName) -{ - QDBusReply<QList<QDBusObjectPath> > reply = this->call(QLatin1String("RequestSession"), - QVariant::fromValue(bearerName)); - return QString(); -} - -void QConnmanManagerInterface::releaseSession() -{ - QDBusReply<QList<QDBusObjectPath> > reply = this->call(QLatin1String("ReleaseSession")); -} - - -QDBusObjectPath QConnmanManagerInterface::lookupService(const QString &service) +void QConnmanManagerInterface::onServicesChanged(const ConnmanMapList &changed, const QList<QDBusObjectPath> &removed) { - QDBusReply<QDBusObjectPath > reply = this->call(QLatin1String("LookupService"), QVariant::fromValue(service)); - if(!reply.isValid()) { - qDebug() << reply.error().message(); + ConnmanMap connmanobj; + servicesList.clear(); //connman list changes order + Q_FOREACH (connmanobj, changed) { + const QString svcPath(connmanobj.objectPath.path()); + servicesList << svcPath; } - return reply; -} -// properties - -QStringList QConnmanManagerInterface::getAvailableTechnologies() -{ - QVariant var = getProperty("AvailableTechnologies"); - return qdbus_cast<QStringList>(var); + Q_EMIT servicesChanged(changed, removed); } -QStringList QConnmanManagerInterface::getEnabledTechnologies() +QVariant QConnmanManagerInterface::getProperty(const QString &property) { - QVariant var = getProperty("EnabledTechnologies"); - return qdbus_cast<QStringList>(var); + QVariant var; + var = propertiesCacheMap.value(property); + return var; } -QStringList QConnmanManagerInterface::getConnectedTechnologies() +QVariantMap QConnmanManagerInterface::getProperties() { - QVariant var = getProperty("ConnectedTechnologies"); - return qdbus_cast<QStringList>(var); + if (propertiesCacheMap.isEmpty()) { + QDBusPendingReply<QVariantMap> reply = call(QLatin1String("GetProperties")); + reply.waitForFinished(); + if (!reply.isError()) { + propertiesCacheMap = reply.value(); + } + } + return propertiesCacheMap; } -QString QConnmanManagerInterface::getDefaultTechnology() +QString QConnmanManagerInterface::getState() { - QVariant var = getProperty("DefaultTechnology"); - return qdbus_cast<QString>(var); + return getProperty(QStringLiteral("State")).toString(); } bool QConnmanManagerInterface::getOfflineMode() { - QVariant var = getProperty("OfflineMode"); + QVariant var = getProperty(QStringLiteral("OfflineMode")); return qdbus_cast<bool>(var); } -QString QConnmanManagerInterface::getActiveProfile() -{ - QVariant var = getProperty("ActiveProfile"); - return qdbus_cast<QString>(var); -} - -QStringList QConnmanManagerInterface::getProfiles() -{ - QVariant var = getProperty("Profiles"); - return qdbus_cast<QStringList>(var); -} - QStringList QConnmanManagerInterface::getTechnologies() { - QStringList list; - QDBusReply<ConnmanMapList> replyList = this->call(QLatin1String("GetTechnologies")); - if (replyList.isValid()) { - Q_FOREACH (ConnmanMap map, replyList.value()) { - list << map.objectPath.path(); - } - } else { - // try for older version - QVariant var = getProperty("Technologies"); - if (!var.isNull()) { - list = qdbus_cast<QStringList>(var); + if (technologiesMap.isEmpty()) { + QDBusPendingReply<ConnmanMapList> reply = call(QLatin1String("GetTechnologies")); + reply.waitForFinished(); + if (!reply.isError()) { + Q_FOREACH (ConnmanMap map, reply.value()) { + if (!technologiesMap.contains(map.objectPath.path())) { + technologyAdded(map.objectPath, map.propertyMap); + } + } } } - return list; + return technologiesMap.keys(); } QStringList QConnmanManagerInterface::getServices() { - QStringList list; - QDBusReply<ConnmanMapList> replyList = this->call(QLatin1String("GetServices")); - if (replyList.isValid()) { - Q_FOREACH (ConnmanMap map, replyList.value()) { - list << map.objectPath.path(); - } - } else { - QVariant var = getProperty("Services"); - if (!var.isNull()) { - list = qdbus_cast<QStringList>(var); + if (servicesList.isEmpty()) { + QDBusPendingReply<ConnmanMapList> reply = call(QLatin1String("GetServices")); + reply.waitForFinished(); + if (!reply.isError()) { + Q_FOREACH (ConnmanMap map, reply.value()) { + servicesList << map.objectPath.path(); + } } } - return list; + return servicesList; } -QString QConnmanManagerInterface::getPathForTechnology(const QString &name) +void QConnmanManagerInterface::requestScan(const QString &type) { - foreach (const QString &path, getTechnologies()) { - if(path.contains(name)) { - return path; + Q_FOREACH (QConnmanTechnologyInterface *tech, technologiesMap) { + if (tech->type() == type) { + tech->scan(); } } - return ""; -} - - -////////////////////////// -QConnmanProfileInterface::QConnmanProfileInterface(const QString &dbusPathName,QObject *parent) - : QDBusAbstractInterface(QLatin1String(CONNMAN_SERVICE), - dbusPathName, - CONNMAN_PROFILE_INTERFACE, - QDBusConnection::systemBus(), parent) -{ -} - -QConnmanProfileInterface::~QConnmanProfileInterface() -{ } -void QConnmanProfileInterface::connectNotify(const QMetaMethod &signal) +void QConnmanManagerInterface::technologyAdded(const QDBusObjectPath &path, const QVariantMap &) { - static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QConnmanProfileInterface::propertyChanged); - if (signal == propertyChangedSignal) { - QDBusConnection::systemBus().connect(QLatin1String(CONNMAN_SERVICE), - this->path(), - QLatin1String(CONNMAN_PROFILE_INTERFACE), - QLatin1String("PropertyChanged"), - this,SIGNAL(propertyChanged(QString,QDBusVariant))); + if (!technologiesList.contains(path.path())) { + technologiesList << path.path(); + QConnmanTechnologyInterface *tech; + tech = new QConnmanTechnologyInterface(path.path(),this); + technologiesMap.insert(path.path(),tech); + connect(tech,SIGNAL(scanFinished()),this,SIGNAL(scanFinished())); } } -void QConnmanProfileInterface::disconnectNotify(const QMetaMethod &signal) +void QConnmanManagerInterface::technologyRemoved(const QDBusObjectPath &path) { - static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QConnmanProfileInterface::propertyChanged); - if (signal == propertyChangedSignal) { - + if (technologiesList.contains(path.path())) { + technologiesList.removeOne(path.path()); + QConnmanTechnologyInterface * tech = technologiesMap.take(path.path()); + delete tech; } } -QVariantMap QConnmanProfileInterface::getProperties() +QConnmanServiceInterface::QConnmanServiceInterface(const QString &dbusPathName,QObject *parent) + : QDBusAbstractInterface(QStringLiteral(CONNMAN_SERVICE), + dbusPathName, + CONNMAN_SERVICE_INTERFACE, + QDBusConnection::systemBus(), parent) { - QDBusReply<QVariantMap > reply = this->call(QLatin1String("GetProperties")); - return reply.value(); -} + QList<QVariant> argumentList; + QDBusPendingReply<QVariantMap> props_reply = asyncCallWithArgumentList(QLatin1String("GetProperties"), argumentList); -QVariant QConnmanProfileInterface::getProperty(const QString &property) -{ - QVariant var; - QVariantMap map = getProperties(); - if (map.contains(property)) { - var = map.value(property); - } - return var; -} + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(props_reply, this); -// properties -QString QConnmanProfileInterface::getName() -{ + QObject::connect(watcher,SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(propertiesReply(QDBusPendingCallWatcher*))); - QVariant var = getProperty("Name"); - return qdbus_cast<QString>(var); + QDBusConnection::systemBus().connect(QStringLiteral(CONNMAN_SERVICE), + path(), + QStringLiteral(CONNMAN_SERVICE_INTERFACE), + QStringLiteral("PropertyChanged"), + this,SLOT(changedProperty(QString,QDBusVariant))); } -bool QConnmanProfileInterface::isOfflineMode() -{ - QVariant var = getProperty("OfflineMode"); - return qdbus_cast<bool>(var); -} - -QStringList QConnmanProfileInterface::getServices() +QConnmanServiceInterface::~QConnmanServiceInterface() { - QVariant var = getProperty("Services"); - return qdbus_cast<QStringList>(var); } - -/////////////////////////// -QConnmanServiceInterface::QConnmanServiceInterface(const QString &dbusPathName,QObject *parent) - : QDBusAbstractInterface(QLatin1String(CONNMAN_SERVICE), - dbusPathName, - CONNMAN_SERVICE_INTERFACE, - QDBusConnection::systemBus(), parent) +QVariantMap QConnmanServiceInterface::getProperties() { + if (propertiesCacheMap.isEmpty()) { + QDBusPendingReply<QVariantMap> reply = call(QLatin1String("GetProperties")); + reply.waitForFinished(); + if (!reply.isError()) { + propertiesCacheMap = reply.value(); + Q_EMIT propertiesReady(); + } + } + return propertiesCacheMap; } -QConnmanServiceInterface::~QConnmanServiceInterface() +void QConnmanServiceInterface::propertiesReply(QDBusPendingCallWatcher *call) { + QDBusPendingReply<QVariantMap> props_reply = *call; + if (props_reply.isError()) { + qDebug() << props_reply.error().message(); + return; + } + propertiesCacheMap = props_reply.value(); + Q_EMIT propertiesReady(); } void QConnmanServiceInterface::connectNotify(const QMetaMethod &signal) { static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QConnmanServiceInterface::propertyChanged); if (signal == propertyChangedSignal) { - QDBusConnection::systemBus().connect(QLatin1String(CONNMAN_SERVICE), - this->path(), - QLatin1String(CONNMAN_SERVICE_INTERFACE), - QLatin1String("PropertyChanged"), + QDBusConnection::systemBus().connect(QStringLiteral(CONNMAN_SERVICE), + path(), + QStringLiteral(CONNMAN_SERVICE_INTERFACE), + QStringLiteral("PropertyChanged"), this,SIGNAL(propertyChanged(QString,QDBusVariant))); } - static const QMetaMethod propertyChangedContextSignal = QMetaMethod::fromSignal(&QConnmanServiceInterface::propertyChangedContext); - if (signal == propertyChangedContextSignal) { - QConnmanDBusHelper *helper; - helper = new QConnmanDBusHelper(this); - - QDBusConnection::systemBus().connect(QLatin1String(CONNMAN_SERVICE), - this->path(), - QLatin1String(CONNMAN_SERVICE_INTERFACE), - QLatin1String("PropertyChanged"), - helper,SLOT(propertyChanged(QString,QDBusVariant))); - - QObject::connect(helper,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), - this,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), Qt::UniqueConnection); - } -} - -void QConnmanServiceInterface::disconnectNotify(const QMetaMethod &signal) -{ - static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QConnmanServiceInterface::propertyChanged); - if (signal == propertyChangedSignal) { - - } } -QVariantMap QConnmanServiceInterface::getProperties() +void QConnmanServiceInterface::changedProperty(const QString &name, const QDBusVariant &value) { - if(this->isValid()) { - QDBusReply<QVariantMap> reply = this->call(QLatin1String("GetProperties")); - return reply.value(); - } - else - return QVariantMap(); + propertiesCacheMap[name] = value.variant(); + if (name == QStringLiteral("State")) + Q_EMIT stateChanged(value.variant().toString()); } QVariant QConnmanServiceInterface::getProperty(const QString &property) { QVariant var; QVariantMap map = getProperties(); - if (map.contains(property)) { - var = map.value(property); - } + var = map.value(property); return var; } void QConnmanServiceInterface::connect() { - this->asyncCall(QLatin1String("Connect")); + asyncCall(QLatin1String("Connect")); } void QConnmanServiceInterface::disconnect() { - QDBusReply<QVariantMap> reply = this->call(QLatin1String("Disconnect")); + asyncCall(QLatin1String("Disconnect")); } void QConnmanServiceInterface::remove() { - QDBusReply<QVariantMap> reply = this->call(QLatin1String("Remove")); + asyncCall(QLatin1String("Remove")); } // properties -QString QConnmanServiceInterface::getState() +QString QConnmanServiceInterface::state() { - QVariant var = getProperty("State"); + QVariant var = getProperty(QStringLiteral("State")); return qdbus_cast<QString>(var); } -QString QConnmanServiceInterface::getError() +QString QConnmanServiceInterface::lastError() { - QVariant var = getProperty("Error"); + QVariant var = getProperty(QStringLiteral("Error")); return qdbus_cast<QString>(var); } -QString QConnmanServiceInterface::getName() +QString QConnmanServiceInterface::name() { - QVariant var = getProperty("Name"); + QVariant var = getProperty(QStringLiteral("Name")); return qdbus_cast<QString>(var); } -QString QConnmanServiceInterface::getType() +QString QConnmanServiceInterface::type() { - QVariant var = getProperty("Type"); + QVariant var = getProperty(QStringLiteral("Type")); return qdbus_cast<QString>(var); } -QString QConnmanServiceInterface::getMode() +QString QConnmanServiceInterface::security() { - QVariant var = getProperty("Mode"); + QVariant var = getProperty(QStringLiteral("Security")); return qdbus_cast<QString>(var); } -QString QConnmanServiceInterface::getSecurity() +bool QConnmanServiceInterface::favorite() { - QVariant var = getProperty("Security"); - return qdbus_cast<QString>(var); -} - -QString QConnmanServiceInterface::getPassphrase() -{ - QVariant var = getProperty("Passphrase"); - return qdbus_cast<QString>(var); -} - -bool QConnmanServiceInterface::isPassphraseRequired() -{ - QVariant var = getProperty("PassphraseRequired"); - return qdbus_cast<bool>(var); -} - -quint8 QConnmanServiceInterface::getSignalStrength() -{ - QVariant var = getProperty("Strength"); - return qdbus_cast<quint8>(var); -} - -bool QConnmanServiceInterface::isFavorite() -{ - QVariant var = getProperty("Favorite"); + QVariant var = getProperty(QStringLiteral("Favorite")); return qdbus_cast<bool>(var); } -bool QConnmanServiceInterface::isImmutable() +bool QConnmanServiceInterface::autoConnect() { - QVariant var = getProperty("Immutable"); + QVariant var = getProperty(QStringLiteral("AutoConnect")); return qdbus_cast<bool>(var); } -bool QConnmanServiceInterface::isAutoConnect() +bool QConnmanServiceInterface::roaming() { - QVariant var = getProperty("AutoConnect"); + QVariant var = getProperty(QStringLiteral("Roaming")); return qdbus_cast<bool>(var); } -bool QConnmanServiceInterface::isSetupRequired() -{ - QVariant var = getProperty("SetupRequired"); - return qdbus_cast<bool>(var); -} - -QString QConnmanServiceInterface::getAPN() -{ - QVariant var = getProperty("APN"); - return qdbus_cast<QString>(var); -} - -QString QConnmanServiceInterface::getMCC() -{ - QVariant var = getProperty("MCC"); - return qdbus_cast<QString>(var); -} - -QString QConnmanServiceInterface::getMNC() -{ - QVariant var = getProperty("MNC"); - return qdbus_cast<QString>(var); -} - -bool QConnmanServiceInterface::isRoaming() -{ - QVariant var = getProperty("Roaming"); - return qdbus_cast<bool>(var); -} - -QStringList QConnmanServiceInterface::getNameservers() -{ - QVariant var = getProperty("NameServers"); - return qdbus_cast<QStringList>(var); -} - -QStringList QConnmanServiceInterface::getDomains() -{ - QVariant var = getProperty("Domains"); - return qdbus_cast<QStringList>(var); -} - -QVariantMap QConnmanServiceInterface::getIPv4() +QVariantMap QConnmanServiceInterface::ethernet() { - QVariant var = getProperty("IPv4"); + QVariant var = getProperty(QStringLiteral("Ethernet")); return qdbus_cast<QVariantMap >(var); } -QVariantMap QConnmanServiceInterface::getIPv4Configuration() -{ - QVariant var = getProperty("IPv4.Configuration"); - return qdbus_cast<QVariantMap >(var); -} - -QVariantMap QConnmanServiceInterface::getProxy() -{ - QVariant var = getProperty("Proxy"); - return qdbus_cast<QVariantMap >(var); -} - -QVariantMap QConnmanServiceInterface::getEthernet() -{ - QVariant var = getProperty("Ethernet"); - return qdbus_cast<QVariantMap >(var); -} - -QString QConnmanServiceInterface::getMethod() -{ - QVariant var; - QVariantMap map = getEthernet(); - QMapIterator<QString,QVariant> it(map); - while(it.hasNext()) { - it.next(); - if(it.key() == "Method") { - return it.value().toString(); - } - } - return QString(); -} - -QString QConnmanServiceInterface::getInterface() -{ - QVariant var; - QVariantMap map = getEthernet(); - - QMapIterator<QString,QVariant> it(map); - while(it.hasNext()) { - it.next(); - if(it.key() == "Interface") { - return it.value().toString(); - } - } - - return QString(); -} - -QString QConnmanServiceInterface::getMacAddress() -{ - QVariant var; - QVariantMap map = getEthernet(); - - QMapIterator<QString,QVariant> it(map); - while(it.hasNext()) { - it.next(); - if(it.key() == "Address") { - return it.value().toString(); - } - } - return QString(); -} - -quint16 QConnmanServiceInterface::getMtu() -{ - quint16 mtu=0; - QVariant var; - QVariantMap map = getEthernet(); - - QMapIterator<QString,QVariant> it(map); - while(it.hasNext()) { - it.next(); - if(it.key() == "MTU") { - return it.value().toUInt(); - } - } - return mtu; -} - -quint16 QConnmanServiceInterface::getSpeed() +QString QConnmanServiceInterface::serviceInterface() { - quint16 speed=0; - QVariant var; - QVariantMap map = getEthernet(); - - QMapIterator<QString,QVariant> it(map); - while(it.hasNext()) { - it.next(); - if(it.key() == "Speed") { - return it.value().toUInt(); - } - } - return speed; + QVariantMap map = ethernet(); + return map.value(QStringLiteral("Interface")).toString(); } -QString QConnmanServiceInterface::getDuplex() -{ - QVariant var; - QVariantMap map = getEthernet(); - - QMapIterator<QString,QVariant> it(map); - while(it.hasNext()) { - it.next(); - if(it.key() == "Duplex") { - return it.value().toString(); - } - } - return QString(); -} - - bool QConnmanServiceInterface::isOfflineMode() { - QVariant var = getProperty("OfflineMode"); + QVariant var = getProperty(QStringLiteral("OfflineMode")); return qdbus_cast<bool>(var); } -QStringList QConnmanServiceInterface::getServices() +QStringList QConnmanServiceInterface::services() { - QVariant var = getProperty("Services"); + QVariant var = getProperty(QStringLiteral("Services")); return qdbus_cast<QStringList>(var); } - ////////////////////////// QConnmanTechnologyInterface::QConnmanTechnologyInterface(const QString &dbusPathName,QObject *parent) - : QDBusAbstractInterface(QLatin1String(CONNMAN_SERVICE), + : QDBusAbstractInterface(QStringLiteral(CONNMAN_SERVICE), dbusPathName, CONNMAN_TECHNOLOGY_INTERFACE, QDBusConnection::systemBus(), parent) @@ -791,154 +463,52 @@ void QConnmanTechnologyInterface::connectNotify(const QMetaMethod &signal) { static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QConnmanTechnologyInterface::propertyChanged); if (signal == propertyChangedSignal) { - QDBusConnection::systemBus().connect(QLatin1String(CONNMAN_SERVICE), - this->path(), - QLatin1String(CONNMAN_TECHNOLOGY_INTERFACE), - QLatin1String("PropertyChanged"), + QDBusConnection::systemBus().connect(QStringLiteral(CONNMAN_SERVICE), + path(), + QStringLiteral(CONNMAN_TECHNOLOGY_INTERFACE), + QStringLiteral("PropertyChanged"), this,SIGNAL(propertyChanged(QString,QDBusVariant))); } - static const QMetaMethod propertyChangedContextSignal = QMetaMethod::fromSignal(&QConnmanTechnologyInterface::propertyChangedContext); - if (signal == propertyChangedContextSignal) { - QConnmanDBusHelper *helper; - helper = new QConnmanDBusHelper(this); - - QDBusConnection::systemBus().connect(QLatin1String(CONNMAN_SERVICE), - this->path(), - QLatin1String(CONNMAN_TECHNOLOGY_INTERFACE), - QLatin1String("PropertyChanged"), - helper,SLOT(propertyChanged(QString,QDBusVariant))); - - QObject::connect(helper,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), - this,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), Qt::UniqueConnection); - } } -void QConnmanTechnologyInterface::disconnectNotify(const QMetaMethod &signal) +QVariantMap QConnmanTechnologyInterface::properties() { - static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QConnmanTechnologyInterface::propertyChanged); - if (signal == propertyChangedSignal) { - + if (propertiesMap.isEmpty()) { + QDBusPendingReply<QVariantMap> reply = call(QLatin1String("GetProperties")); + reply.waitForFinished(); + propertiesMap = reply.value(); } -} - -QVariantMap QConnmanTechnologyInterface::getProperties() -{ - QDBusReply<QVariantMap> reply = this->call(QLatin1String("GetProperties")); - return reply.value(); + return propertiesMap; } QVariant QConnmanTechnologyInterface::getProperty(const QString &property) { QVariant var; - QVariantMap map = getProperties(); - if (map.contains(property)) { - var = map.value(property); - } + QVariantMap map = properties(); + var = map.value(property); return var; } -// properties -QString QConnmanTechnologyInterface::getState() -{ - QVariant var = getProperty("State"); - return qdbus_cast<QString>(var); -} - -QString QConnmanTechnologyInterface::getName() -{ - QVariant var = getProperty("Name"); - return qdbus_cast<QString>(var); -} - -QString QConnmanTechnologyInterface::getType() +QString QConnmanTechnologyInterface::type() { - QVariant var = getProperty("Type"); + QVariant var = getProperty(QStringLiteral("Type")); return qdbus_cast<QString>(var); } - -////////////////////////////////// -QConnmanAgentInterface::QConnmanAgentInterface(const QString &dbusPathName, QObject *parent) - : QDBusAbstractInterface(QLatin1String(CONNMAN_SERVICE), - dbusPathName, - CONNMAN_AGENT_INTERFACE, - QDBusConnection::systemBus(), parent) -{ -} - -QConnmanAgentInterface::~QConnmanAgentInterface() -{ -} - -void QConnmanAgentInterface::connectNotify(const QMetaMethod &signal) -{ - Q_UNUSED(signal); -} - -void QConnmanAgentInterface::disconnectNotify(const QMetaMethod &signal) -{ - Q_UNUSED(signal); -} - - -void QConnmanAgentInterface::release() -{ -} - -void QConnmanAgentInterface::reportError(QDBusObjectPath &/*path*/, const QString &/*error*/) -{ -} - -void QConnmanAgentInterface::cancel() -{ -} - - -///////////////////////////////////////// -QConnmanCounterInterface::QConnmanCounterInterface(const QString &dbusPathName,QObject *parent) - : QDBusAbstractInterface(QLatin1String(CONNMAN_SERVICE), - dbusPathName, - CONNMAN_COUNTER_INTERFACE, - QDBusConnection::systemBus(), parent) -{ -} - -QConnmanCounterInterface::~QConnmanCounterInterface() -{ -} - -quint32 QConnmanCounterInterface::getReceivedByteCount() -{ - return 0; -} - -quint32 QConnmanCounterInterface::getTransmittedByteCount() -{ - return 0; -} - -quint64 QConnmanCounterInterface::getTimeOnline() -{ - return 0; -} - -///////////////////////////////////////// -QConnmanDBusHelper::QConnmanDBusHelper(QObject * parent) - : QObject(parent) -{ -} - -QConnmanDBusHelper::~QConnmanDBusHelper() +void QConnmanTechnologyInterface::scan() { + QDBusPendingReply<> reply = asyncCall(QLatin1String("Scan")); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); + connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(scanReply(QDBusPendingCallWatcher*))); } -void QConnmanDBusHelper::propertyChanged(const QString &item, const QDBusVariant &var) +void QConnmanTechnologyInterface::scanReply(QDBusPendingCallWatcher *call) { - QDBusMessage msg = this->message(); - Q_EMIT propertyChangedContext(msg.path() ,item, var); + Q_EMIT scanFinished(); + call->deleteLater(); } -///////////////// QT_END_NAMESPACE #endif // QT_NO_DBUS diff --git a/src/plugins/bearer/connman/qconnmanservice_linux_p.h b/src/plugins/bearer/connman/qconnmanservice_linux_p.h index 6996fef5a7..250f90e2d0 100644 --- a/src/plugins/bearer/connman/qconnmanservice_linux_p.h +++ b/src/plugins/bearer/connman/qconnmanservice_linux_p.h @@ -73,19 +73,9 @@ #define CONNMAN_SERVICE "net.connman" #define CONNMAN_PATH "/net/connman" - -#define CONNMAN_DEBUG_INTERFACE CONNMAN_SERVICE ".Debug" -#define CONNMAN_ERROR_INTERFACE CONNMAN_SERVICE ".Error" -#define CONNMAN_AGENT_INTERFACE CONNMAN_SERVICE ".Agent" -#define CONNMAN_COUNTER_INTERFACE CONNMAN_SERVICE ".Counter" - -#define CONNMAN_MANAGER_INTERFACE CONNMAN_SERVICE ".Manager" -#define CONNMAN_MANAGER_PATH "/" - -#define CONNMAN_TASK_INTERFACE CONNMAN_SERVICE ".Task" -#define CONNMAN_PROFILE_INTERFACE CONNMAN_SERVICE ".Profile" -#define CONNMAN_SERVICE_INTERFACE CONNMAN_SERVICE ".Service" -#define CONNMAN_PROVIDER_INTERFACE CONNMAN_SERVICE ".Provider" +#define CONNMAN_MANAGER_INTERFACE CONNMAN_SERVICE ".Manager" +#define CONNMAN_MANAGER_PATH "/" +#define CONNMAN_SERVICE_INTERFACE CONNMAN_SERVICE ".Service" #define CONNMAN_TECHNOLOGY_INTERFACE CONNMAN_SERVICE ".Technology" #endif @@ -108,6 +98,9 @@ QT_BEGIN_NAMESPACE QDBusArgument &operator<<(QDBusArgument &argument, const ConnmanMap &obj); const QDBusArgument &operator>>(const QDBusArgument &argument, ConnmanMap &obj); +class QConnmanTechnologyInterface; +class QConnmanServiceInterface; + class QConnmanManagerInterface : public QDBusAbstractInterface { Q_OBJECT @@ -117,39 +110,16 @@ public: QConnmanManagerInterface( QObject *parent = 0); ~QConnmanManagerInterface(); - QDBusObjectPath path() const; - + QDBusObjectPath path() const; QVariantMap getProperties(); - bool setProperty(const QString &name, const QDBusVariant &value); - QDBusObjectPath createProfile(const QString &name); - bool removeProfile(QDBusObjectPath path); - bool requestScan(const QString &type); - bool enableTechnology(const QString &type); - bool disableTechnology(const QString &type); - QDBusObjectPath connectService(QVariantMap &map); - void registerAgent(QDBusObjectPath &path); - void unregisterAgent(QDBusObjectPath path); - void registerCounter(const QString &path, quint32 interval); - void unregisterCounter(const QString &path); - - QString requestSession(const QString &bearerName); - void releaseSession(); - - // properties + QString getState(); - QStringList getAvailableTechnologies(); - QStringList getEnabledTechnologies(); - QStringList getConnectedTechnologies(); - QString getDefaultTechnology(); bool getOfflineMode(); - QString getActiveProfile(); - QStringList getProfiles(); - QStringList getTechnologies(); + QStringList getTechnologies(); QStringList getServices(); - QDBusObjectPath lookupService(const QString &); - - QString getPathForTechnology(const QString &tech); + void requestScan(const QString &type); + QHash<QString, QConnmanTechnologyInterface *> technologiesMap; Q_SIGNALS: void propertyChanged(const QString &, const QDBusVariant &value); @@ -157,41 +127,28 @@ Q_SIGNALS: void propertyChangedContext(const QString &,const QString &,const QDBusVariant &); void servicesChanged(const ConnmanMapList&, const QList<QDBusObjectPath> &); + void servicesReady(const QStringList &); + void scanFinished(); + protected: void connectNotify(const QMetaMethod &signal); - void disconnectNotify(const QMetaMethod &signal); QVariant getProperty(const QString &); +private: + QVariantMap propertiesCacheMap; + QStringList servicesList; + QStringList technologiesList; + private slots: void onServicesChanged(const ConnmanMapList&, const QList<QDBusObjectPath> &); + void changedProperty(const QString &, const QDBusVariant &value); -}; - -class QConnmanProfileInterfacePrivate; -class QConnmanProfileInterface : public QDBusAbstractInterface -{ - Q_OBJECT - -public: + void propertiesReply(QDBusPendingCallWatcher *call); + void servicesReply(QDBusPendingCallWatcher *call); - explicit QConnmanProfileInterface(const QString &dbusPathName,QObject *parent = 0); - ~QConnmanProfileInterface(); + void technologyAdded(const QDBusObjectPath &technology, const QVariantMap &properties); + void technologyRemoved(const QDBusObjectPath &technology); - QVariantMap getProperties(); -// properties - QString getName(); - bool isOfflineMode(); - QStringList getServices(); - -Q_SIGNALS: - void propertyChanged(const QString &, const QDBusVariant &value); -private: - QConnmanProfileInterfacePrivate *d; - -protected: - void connectNotify(const QMetaMethod &signal); - void disconnectNotify(const QMetaMethod &signal); - QVariant getProperty(const QString &); }; class QConnmanServiceInterface : public QDBusAbstractInterface @@ -208,52 +165,37 @@ public: void connect(); void disconnect(); void remove(); - // void moveBefore(QDBusObjectPath &service); - // void moveAfter(QDBusObjectPath &service); // properties - QString getState(); - QString getError(); - QString getName(); - QString getType(); - QString getMode(); - QString getSecurity(); - QString getPassphrase(); - bool isPassphraseRequired(); - quint8 getSignalStrength(); - bool isFavorite(); - bool isImmutable(); - bool isAutoConnect(); - bool isSetupRequired(); - QString getAPN(); - QString getMCC(); - QString getMNC(); - bool isRoaming(); - QStringList getNameservers(); - QStringList getDomains(); - QVariantMap getIPv4(); - QVariantMap getIPv4Configuration(); - QVariantMap getProxy(); - QVariantMap getEthernet(); - - QString getMethod(); - QString getInterface(); - QString getMacAddress(); - quint16 getMtu(); - quint16 getSpeed(); - QString getDuplex(); + QString state(); + QString lastError(); + QString name(); + QString type(); + QString security(); + bool favorite(); + bool autoConnect(); + bool roaming(); + QVariantMap ethernet(); + QString serviceInterface(); bool isOfflineMode(); - QStringList getServices(); + QStringList services(); Q_SIGNALS: void propertyChanged(const QString &, const QDBusVariant &value); void propertyChangedContext(const QString &,const QString &,const QDBusVariant &); + void propertiesReady(); + void stateChanged(const QString &state); protected: void connectNotify(const QMetaMethod &signal); - void disconnectNotify(const QMetaMethod &signal); QVariant getProperty(const QString &); +private: + QVariantMap propertiesCacheMap; +private slots: + void propertiesReply(QDBusPendingCallWatcher *call); + void changedProperty(const QString &, const QDBusVariant &value); + }; class QConnmanTechnologyInterface : public QDBusAbstractInterface @@ -265,72 +207,21 @@ public: explicit QConnmanTechnologyInterface(const QString &dbusPathName,QObject *parent = 0); ~QConnmanTechnologyInterface(); - QVariantMap getProperties(); -// properties - QString getState(); - QString getName(); - QString getType(); + QString type(); + void scan(); Q_SIGNALS: void propertyChanged(const QString &, const QDBusVariant &value); void propertyChangedContext(const QString &,const QString &,const QDBusVariant &); + void scanFinished(); protected: void connectNotify(const QMetaMethod &signal); - void disconnectNotify(const QMetaMethod &signal); QVariant getProperty(const QString &); - -}; - -class QConnmanAgentInterface : public QDBusAbstractInterface -{ - Q_OBJECT - -public: - - explicit QConnmanAgentInterface(const QString &dbusPathName,QObject *parent = 0); - ~QConnmanAgentInterface(); - - void release(); - void reportError(QDBusObjectPath &path, const QString &error); -// dict requestInput(QDBusObjectPath &path, dict fields); - void cancel(); -protected: - void connectNotify(const QMetaMethod &signal); - void disconnectNotify(const QMetaMethod &signal); -}; - -class QConnmanCounterInterfacePrivate; -class QConnmanCounterInterface : public QDBusAbstractInterface -{ - Q_OBJECT - -public: - - explicit QConnmanCounterInterface(const QString &dbusPathName, QObject *parent = 0); - ~QConnmanCounterInterface(); - -// void release(); - QString getInterface(); - quint32 getReceivedByteCount(); - quint32 getTransmittedByteCount(); - quint64 getTimeOnline(); - private: - QConnmanCounterInterfacePrivate *d; -}; - -class QConnmanDBusHelper: public QObject, protected QDBusContext - { - Q_OBJECT - public: - QConnmanDBusHelper(QObject *parent = 0); - ~QConnmanDBusHelper(); + QVariantMap properties(); + QVariantMap propertiesMap; + void scanReply(QDBusPendingCallWatcher *call); - public slots: - void propertyChanged(const QString &, const QDBusVariant &); - -Q_SIGNALS: - void propertyChangedContext(const QString &,const QString &,const QDBusVariant &); }; QT_END_NAMESPACE diff --git a/src/plugins/bearer/connman/qofonoservice_linux.cpp b/src/plugins/bearer/connman/qofonoservice_linux.cpp index 1983276d94..f5da52a341 100644 --- a/src/plugins/bearer/connman/qofonoservice_linux.cpp +++ b/src/plugins/bearer/connman/qofonoservice_linux.cpp @@ -75,256 +75,133 @@ const QDBusArgument &operator>>(const QDBusArgument &argument, ObjectPathPropert QT_BEGIN_NAMESPACE QOfonoManagerInterface::QOfonoManagerInterface( QObject *parent) - : QDBusAbstractInterface(QLatin1String(OFONO_SERVICE), - QLatin1String(OFONO_MANAGER_PATH), + : QDBusAbstractInterface(QStringLiteral(OFONO_SERVICE), + QStringLiteral(OFONO_MANAGER_PATH), OFONO_MANAGER_INTERFACE, QDBusConnection::systemBus(), parent) { qDBusRegisterMetaType<ObjectPathProperties>(); qDBusRegisterMetaType<PathPropertiesList>(); + + QDBusConnection::systemBus().connect(QStringLiteral(OFONO_SERVICE), + QStringLiteral(OFONO_MANAGER_PATH), + QStringLiteral(OFONO_MANAGER_INTERFACE), + QStringLiteral("ModemAdded"), + this,SLOT(modemAdded(QDBusObjectPath, QVariantMap))); + QDBusConnection::systemBus().connect(QStringLiteral(OFONO_SERVICE), + QStringLiteral(OFONO_MANAGER_PATH), + QStringLiteral(OFONO_MANAGER_INTERFACE), + QStringLiteral("ModemRemoved"), + this,SLOT(modemRemoved(QDBusObjectPath))); } QOfonoManagerInterface::~QOfonoManagerInterface() { } -QList <QDBusObjectPath> QOfonoManagerInterface::getModems() +QStringList QOfonoManagerInterface::getModems() { - QList <QDBusObjectPath> modemList; - QList<QVariant> argumentList; - QDBusReply<PathPropertiesList > reply = this->asyncCallWithArgumentList(QLatin1String("GetModems"), argumentList); - if (reply.isValid()) { - foreach (ObjectPathProperties modem, reply.value()) { - modemList << modem.path; + if (modemList.isEmpty()) { + QList<QVariant> argumentList; + QDBusPendingReply<PathPropertiesList> reply = asyncCallWithArgumentList(QLatin1String("GetModems"), argumentList); + reply.waitForFinished(); + if (!reply.isError()) { + foreach (ObjectPathProperties modem, reply.value()) { + modemList << modem.path.path(); + } + } else { + qDebug() << reply.error().message(); } } return modemList; } -QDBusObjectPath QOfonoManagerInterface::currentModem() +QString QOfonoManagerInterface::currentModem() { - QList<QDBusObjectPath> modems = getModems(); - foreach (const QDBusObjectPath &modem, modems) { - QOfonoModemInterface device(modem.path()); + QStringList modems = getModems(); + foreach (const QString &modem, modems) { + QOfonoModemInterface device(modem); if (device.isPowered() && device.isOnline()) return modem; } - return QDBusObjectPath(); -} - - -void QOfonoManagerInterface::connectNotify(const QMetaMethod &signal) -{ - static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QOfonoManagerInterface::propertyChanged); - if (signal == propertyChangedSignal) { - if (!connection().connect(QLatin1String(OFONO_SERVICE), - QLatin1String(OFONO_MANAGER_PATH), - QLatin1String(OFONO_MANAGER_INTERFACE), - QLatin1String("PropertyChanged"), - this,SIGNAL(propertyChanged(QString,QDBusVariant)))) { - qWarning() << "PropertyCHanged not connected"; - } - } - - static const QMetaMethod propertyChangedContextSignal = QMetaMethod::fromSignal(&QOfonoManagerInterface::propertyChangedContext); - if (signal == propertyChangedContextSignal) { - QOfonoDBusHelper *helper; - helper = new QOfonoDBusHelper(this); - - QDBusConnection::systemBus().connect(QLatin1String(OFONO_SERVICE), - QLatin1String(OFONO_MANAGER_PATH), - QLatin1String(OFONO_MANAGER_INTERFACE), - QLatin1String("PropertyChanged"), - helper,SLOT(propertyChanged(QString,QDBusVariant))); - - - QObject::connect(helper,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), - this,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant))); - } + return QString(); } -void QOfonoManagerInterface::disconnectNotify(const QMetaMethod &signal) +void QOfonoManagerInterface::modemAdded(const QDBusObjectPath &path, const QVariantMap &/*var*/) { - static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QOfonoManagerInterface::propertyChanged); - if (signal == propertyChangedSignal) { - + if (!modemList.contains(path.path())) { + modemList << path.path(); + Q_EMIT modemChanged(); } } -QVariant QOfonoManagerInterface::getProperty(const QString &property) +void QOfonoManagerInterface::modemRemoved(const QDBusObjectPath &path) { - QVariantMap map = getProperties(); - if (map.contains(property)) { - return map.value(property); - } else { - qDebug() << Q_FUNC_INFO << "does not contain" << property; + if (modemList.contains(path.path())) { + modemList.removeOne(path.path()); + Q_EMIT modemChanged(); } - return QVariant(); -} - -QVariantMap QOfonoManagerInterface::getProperties() -{ - QDBusReply<QVariantMap > reply = this->call(QLatin1String("GetProperties")); - if (reply.isValid()) - return reply.value(); - else - return QVariantMap(); -} - -QOfonoDBusHelper::QOfonoDBusHelper(QObject * parent) - : QObject(parent) -{ -} - -QOfonoDBusHelper::~QOfonoDBusHelper() -{ -} - -void QOfonoDBusHelper::propertyChanged(const QString &item, const QDBusVariant &var) -{ - QDBusMessage msg = this->message(); - Q_EMIT propertyChangedContext(msg.path() ,item, var); } QOfonoModemInterface::QOfonoModemInterface(const QString &dbusPathName, QObject *parent) - : QDBusAbstractInterface(QLatin1String(OFONO_SERVICE), + : QDBusAbstractInterface(QStringLiteral(OFONO_SERVICE), dbusPathName, OFONO_MODEM_INTERFACE, QDBusConnection::systemBus(), parent) { + QDBusConnection::systemBus().connect(QStringLiteral(OFONO_SERVICE), + path(), + OFONO_MODEM_INTERFACE, + QStringLiteral("PropertyChanged"), + this,SLOT(propertyChanged(QString,QDBusVariant))); } QOfonoModemInterface::~QOfonoModemInterface() { } -bool QOfonoModemInterface::isPowered() +void QOfonoModemInterface::propertyChanged(const QString &name,const QDBusVariant &value) { - QVariant var = getProperty("Powered"); - return qdbus_cast<bool>(var); + propertiesMap[name] = value.variant(); } -bool QOfonoModemInterface::isOnline() +bool QOfonoModemInterface::isPowered() { - QVariant var = getProperty("Online"); + QVariant var = getProperty(QStringLiteral("Powered")); return qdbus_cast<bool>(var); } -QString QOfonoModemInterface::getName() -{ - QVariant var = getProperty("Name"); - return qdbus_cast<QString>(var); -} - -QString QOfonoModemInterface::getManufacturer() -{ - QVariant var = getProperty("Manufacturer"); - return qdbus_cast<QString>(var); - -} - -QString QOfonoModemInterface::getModel() -{ - - QVariant var = getProperty("Model"); - return qdbus_cast<QString>(var); -} - -QString QOfonoModemInterface::getRevision() -{ - QVariant var = getProperty("Revision"); - return qdbus_cast<QString>(var); - -} -QString QOfonoModemInterface::getSerial() -{ - QVariant var = getProperty("Serial"); - return qdbus_cast<QString>(var); - -} - -QStringList QOfonoModemInterface::getFeatures() -{ - //sms, sim - QVariant var = getProperty("Features"); - return qdbus_cast<QStringList>(var); -} - -QStringList QOfonoModemInterface::getInterfaces() -{ - QVariant var = getProperty("Interfaces"); - return qdbus_cast<QStringList>(var); -} - -QString QOfonoModemInterface::defaultInterface() +bool QOfonoModemInterface::isOnline() { - foreach (const QString &modem,getInterfaces()) { - return modem; - } - return QString(); + QVariant var = getProperty(QStringLiteral("Online")); + return qdbus_cast<bool>(var); } - -void QOfonoModemInterface::connectNotify(const QMetaMethod &signal) +QVariantMap QOfonoModemInterface::getProperties() { - static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QOfonoModemInterface::propertyChanged); - if (signal == propertyChangedSignal) { - if (!connection().connect(QLatin1String(OFONO_SERVICE), - this->path(), - QLatin1String(OFONO_MODEM_INTERFACE), - QLatin1String("PropertyChanged"), - this,SIGNAL(propertyChanged(QString,QDBusVariant)))) { - qWarning() << "PropertyCHanged not connected"; - } + if (propertiesMap.isEmpty()) { + QList<QVariant> argumentList; + QDBusPendingReply<QVariantMap> reply = asyncCallWithArgumentList(QLatin1String("GetProperties"), argumentList); + if (!reply.isError()) { + propertiesMap = reply.value(); } - - static const QMetaMethod propertyChangedContextSignal = QMetaMethod::fromSignal(&QOfonoModemInterface::propertyChangedContext); - if (signal == propertyChangedContextSignal) { - QOfonoDBusHelper *helper; - helper = new QOfonoDBusHelper(this); - - QDBusConnection::systemBus().connect(QLatin1String(OFONO_SERVICE), - this->path(), - QLatin1String(OFONO_MODEM_INTERFACE), - QLatin1String("PropertyChanged"), - helper,SLOT(propertyChanged(QString,QDBusVariant))); - - - QObject::connect(helper,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), - this,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), Qt::UniqueConnection); - }} - -void QOfonoModemInterface::disconnectNotify(const QMetaMethod &signal) -{ - static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QOfonoModemInterface::propertyChanged); - if (signal == propertyChangedSignal) { - } -} - -QVariantMap QOfonoModemInterface::getProperties() -{ - QDBusReply<QVariantMap > reply = this->call(QLatin1String("GetProperties")); - return reply.value(); + return propertiesMap; } QVariant QOfonoModemInterface::getProperty(const QString &property) { QVariant var; QVariantMap map = getProperties(); - if (map.contains(property)) { - var = map.value(property); - } else { - qDebug() << Q_FUNC_INFO << "does not contain" << property; - } + var = map.value(property); return var; } QOfonoNetworkRegistrationInterface::QOfonoNetworkRegistrationInterface(const QString &dbusPathName, QObject *parent) - : QDBusAbstractInterface(QLatin1String(OFONO_SERVICE), + : QDBusAbstractInterface(QStringLiteral(OFONO_SERVICE), dbusPathName, OFONO_NETWORK_REGISTRATION_INTERFACE, QDBusConnection::systemBus(), parent) @@ -335,337 +212,33 @@ QOfonoNetworkRegistrationInterface::~QOfonoNetworkRegistrationInterface() { } -QString QOfonoNetworkRegistrationInterface::getStatus() -{ - /* - "unregistered" Not registered to any network - "registered" Registered to home network - "searching" Not registered, but searching - "denied" Registration has been denied - "unknown" Status is unknown - "roaming" Registered, but roaming*/ - QVariant var = getProperty("Status"); - return qdbus_cast<QString>(var); -} - -quint16 QOfonoNetworkRegistrationInterface::getLac() -{ - QVariant var = getProperty("LocationAreaCode"); - return var.value<quint16>(); -} - - -quint32 QOfonoNetworkRegistrationInterface::getCellId() -{ - QVariant var = getProperty("CellId"); - return var.value<quint32>(); -} - QString QOfonoNetworkRegistrationInterface::getTechnology() { - // "gsm", "edge", "umts", "hspa","lte" - QVariant var = getProperty("Technology"); - return qdbus_cast<QString>(var); -} - -QString QOfonoNetworkRegistrationInterface::getOperatorName() -{ - QVariant var = getProperty("Name"); + QVariant var = getProperty(QStringLiteral("Technology")); return qdbus_cast<QString>(var); } -int QOfonoNetworkRegistrationInterface::getSignalStrength() -{ - QVariant var = getProperty("Strength"); - return qdbus_cast<int>(var); - -} - -QString QOfonoNetworkRegistrationInterface::getBaseStation() -{ - QVariant var = getProperty("BaseStation"); - return qdbus_cast<QString>(var); -} - -QList <QDBusObjectPath> QOfonoNetworkRegistrationInterface::getOperators() -{ - QList <QDBusObjectPath> operatorList; - QList<QVariant> argumentList; - QDBusReply<PathPropertiesList > reply = this->asyncCallWithArgumentList(QLatin1String("GetOperators"), - argumentList); - if (reply.isValid()) { - foreach (ObjectPathProperties netop, reply.value()) { - operatorList << netop.path; - } - } - return operatorList; -} - -void QOfonoNetworkRegistrationInterface::connectNotify(const QMetaMethod &signal) -{ - static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QOfonoNetworkRegistrationInterface::propertyChanged); - if (signal == propertyChangedSignal) { - if (!connection().connect(QLatin1String(OFONO_SERVICE), - this->path(), - QLatin1String(OFONO_NETWORK_REGISTRATION_INTERFACE), - QLatin1String("PropertyChanged"), - this,SIGNAL(propertyChanged(QString,QDBusVariant)))) { - qWarning() << "PropertyCHanged not connected"; - } - } - - static const QMetaMethod propertyChangedContextSignal = QMetaMethod::fromSignal(&QOfonoNetworkRegistrationInterface::propertyChangedContext); - if (signal == propertyChangedContextSignal) { - QOfonoDBusHelper *helper; - helper = new QOfonoDBusHelper(this); - - QDBusConnection::systemBus().connect(QLatin1String(OFONO_SERVICE), - this->path(), - QLatin1String(OFONO_NETWORK_REGISTRATION_INTERFACE), - QLatin1String("PropertyChanged"), - helper,SLOT(propertyChanged(QString,QDBusVariant))); - - - QObject::connect(helper,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), - this,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), Qt::UniqueConnection); - } -} - -void QOfonoNetworkRegistrationInterface::disconnectNotify(const QMetaMethod &signal) -{ - static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QOfonoNetworkRegistrationInterface::propertyChanged); - if (signal == propertyChangedSignal) { - - } -} - QVariant QOfonoNetworkRegistrationInterface::getProperty(const QString &property) { QVariant var; QVariantMap map = getProperties(); - if (map.contains(property)) { - var = map.value(property); - } else { - qDebug() << Q_FUNC_INFO << "does not contain" << property; - } + var = map.value(property); return var; } QVariantMap QOfonoNetworkRegistrationInterface::getProperties() { - QDBusReply<QVariantMap > reply = this->call(QLatin1String("GetProperties")); - return reply.value(); -} - - - -QOfonoNetworkOperatorInterface::QOfonoNetworkOperatorInterface(const QString &dbusPathName, QObject *parent) - : QDBusAbstractInterface(QLatin1String(OFONO_SERVICE), - dbusPathName, - OFONO_NETWORK_OPERATOR_INTERFACE, - QDBusConnection::systemBus(), parent) -{ -} - -QOfonoNetworkOperatorInterface::~QOfonoNetworkOperatorInterface() -{ -} - -QString QOfonoNetworkOperatorInterface::getName() -{ - QVariant var = getProperty("Name"); - return qdbus_cast<QString>(var); -} - -QString QOfonoNetworkOperatorInterface::getStatus() -{ - // "unknown", "available", "current" and "forbidden" - QVariant var = getProperty("Status"); - return qdbus_cast<QString>(var); -} - -QString QOfonoNetworkOperatorInterface::getMcc() -{ - QVariant var = getProperty("MobileCountryCode"); - return qdbus_cast<QString>(var); -} - -QString QOfonoNetworkOperatorInterface::getMnc() -{ - QVariant var = getProperty("MobileNetworkCode"); - return qdbus_cast<QString>(var); -} - -QStringList QOfonoNetworkOperatorInterface::getTechnologies() -{ - QVariant var = getProperty("Technologies"); - return qdbus_cast<QStringList>(var); -} - -void QOfonoNetworkOperatorInterface::connectNotify(const QMetaMethod &signal) -{ - Q_UNUSED(signal); -// static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QOfonoNetworkOperatorInterface::propertyChanged); -// if (signal == propertyChangedSignal) { -// if (!connection().connect(QLatin1String(OFONO_SERVICE), -// this->path(), -// QLatin1String(OFONO_NETWORK_OPERATOR_INTERFACE), -// QLatin1String("PropertyChanged"), -// this,SIGNAL(propertyChanged(QString,QDBusVariant)))) { -// qWarning() << "PropertyCHanged not connected"; -// } -// } - -// static const QMetaMethod propertyChangedContextSignal = QMetaMethod::fromSignal(&QOfonoNetworkOperatorInterface::propertyChangedContext); -// if (signal == propertyChangedContextSignal) { -// QOfonoDBusHelper *helper; -// helper = new QOfonoDBusHelper(this); - -// QDBusConnection::systemBus().connect(QLatin1String(OFONO_SERVICE), -// this->path(), -// QLatin1String(OFONO_NETWORK_OPERATOR_INTERFACE), -// QLatin1String("PropertyChanged"), -// helper,SLOT(propertyChanged(QString,QDBusVariant))); - - -// QObject::connect(helper,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), -// this,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), Qt::UniqueConnection); -// } -} - -void QOfonoNetworkOperatorInterface::disconnectNotify(const QMetaMethod &signal) -{ - Q_UNUSED(signal); -// static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QOfonoNetworkOperatorInterface::propertyChanged); -// if (signal == propertyChangedSignal) { - -// } -} - -QVariant QOfonoNetworkOperatorInterface::getProperty(const QString &property) -{ - QVariant var; - QVariantMap map = getProperties(); - if (map.contains(property)) { - var = map.value(property); - } else { - qDebug() << Q_FUNC_INFO << "does not contain" << property; - } - return var; -} - -QVariantMap QOfonoNetworkOperatorInterface::getProperties() -{ - QDBusReply<QVariantMap > reply = this->call(QLatin1String("GetProperties")); - return reply.value(); -} - -QOfonoSimInterface::QOfonoSimInterface(const QString &dbusPathName, QObject *parent) - : QDBusAbstractInterface(QLatin1String(OFONO_SERVICE), - dbusPathName, - OFONO_SIM_MANAGER_INTERFACE, - QDBusConnection::systemBus(), parent) -{ -} - -QOfonoSimInterface::~QOfonoSimInterface() -{ -} - -bool QOfonoSimInterface::isPresent() -{ - QVariant var = getProperty("Present"); - return qdbus_cast<bool>(var); -} - -QString QOfonoSimInterface::getHomeMcc() -{ - QVariant var = getProperty("MobileCountryCode"); - return qdbus_cast<QString>(var); -} - -QString QOfonoSimInterface::getHomeMnc() -{ - QVariant var = getProperty("MobileNetworkCode"); - return qdbus_cast<QString>(var); -} - -// QStringList subscriberNumbers(); -// QMap<QString,QString> serviceNumbers(); -QString QOfonoSimInterface::pinRequired() -{ - QVariant var = getProperty("PinRequired"); - return qdbus_cast<QString>(var); -} - -QString QOfonoSimInterface::lockedPins() -{ - QVariant var = getProperty("LockedPins"); - return qdbus_cast<QString>(var); -} - -QString QOfonoSimInterface::cardIdentifier() -{ - QVariant var = getProperty("CardIdentifier"); - return qdbus_cast<QString>(var); -} - -void QOfonoSimInterface::connectNotify(const QMetaMethod &signal) -{ - Q_UNUSED(signal); -// static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QOfonoSimInterface::propertyChanged); -// if (signal == propertyChangedSignal) { -// if (!connection().connect(QLatin1String(OFONO_SERVICE), -// this->path(), -// QLatin1String(OFONO_SIM_MANAGER_INTERFACE), -// QLatin1String("PropertyChanged"), -// this,SIGNAL(propertyChanged(QString,QDBusVariant)))) { -// qWarning() << "PropertyCHanged not connected"; -// } -// } - -// static const QMetaMethod propertyChangedContextSignal = QMetaMethod::fromSignal(&QOfonoSimInterface::propertyChangedContext); -// if (signal == propertyChangedContextSignal) { -// QOfonoDBusHelper *helper; -// helper = new QOfonoDBusHelper(this); - -// QDBusConnection::systemBus().connect(QLatin1String(OFONO_SERVICE), -// this->path(), -// QLatin1String(OFONO_SIM_MANAGER_INTERFACE), -// QLatin1String("PropertyChanged"), -// helper,SLOT(propertyChanged(QString,QDBusVariant))); - - -// QObject::connect(helper,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), -// this,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), Qt::UniqueConnection); -// } -} - -void QOfonoSimInterface::disconnectNotify(const QMetaMethod &signal) -{ - Q_UNUSED(signal); -// static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QOfonoSimInterface::propertyChanged); -// if (signal == propertyChangedSignal) { - -// } -} - -QVariant QOfonoSimInterface::getProperty(const QString &property) -{ - QVariant var; - QVariantMap map = getProperties(); - if (map.contains(property)) { - var = map.value(property); - } else { - qDebug() << Q_FUNC_INFO << "does not contain" << property; + if (propertiesMap.isEmpty()) { + QList<QVariant> argumentList; + QDBusPendingReply<QVariantMap> reply = asyncCallWithArgumentList(QLatin1String("GetProperties"), argumentList); + reply.waitForFinished(); + if (!reply.isError()) { + propertiesMap = reply.value(); + } else { + qDebug() << reply.error().message(); + } } - return var; -} - -QVariantMap QOfonoSimInterface::getProperties() -{ - QDBusReply<QVariantMap > reply = this->call(QLatin1String("GetProperties")); - return reply.value(); + return propertiesMap; } QOfonoDataConnectionManagerInterface::QOfonoDataConnectionManagerInterface(const QString &dbusPathName, QObject *parent) @@ -674,340 +247,62 @@ QOfonoDataConnectionManagerInterface::QOfonoDataConnectionManagerInterface(const OFONO_DATA_CONNECTION_MANAGER_INTERFACE, QDBusConnection::systemBus(), parent) { + QDBusConnection::systemBus().connect(QLatin1String(OFONO_SERVICE), + path(), + QLatin1String(OFONO_MODEM_INTERFACE), + QLatin1String("PropertyChanged"), + this,SLOT(propertyChanged(QString,QDBusVariant))); } QOfonoDataConnectionManagerInterface::~QOfonoDataConnectionManagerInterface() { } -QList<QDBusObjectPath> QOfonoDataConnectionManagerInterface::getPrimaryContexts() +QStringList QOfonoDataConnectionManagerInterface::contexts() { - QList <QDBusObjectPath> contextList; - QList<QVariant> argumentList; - QDBusReply<PathPropertiesList > reply = this->asyncCallWithArgumentList(QLatin1String("GetContexts"), - argumentList); - if (reply.isValid()) { - foreach (ObjectPathProperties context, reply.value()) { - contextList << context.path; + if (contextList.isEmpty()) { + QDBusPendingReply<PathPropertiesList > reply = call(QLatin1String("GetContexts")); + reply.waitForFinished(); + if (!reply.isError()) { + foreach (ObjectPathProperties context, reply.value()) { + contextList << context.path.path(); + } } } return contextList; } -bool QOfonoDataConnectionManagerInterface::isAttached() -{ - QVariant var = getProperty("Attached"); - return qdbus_cast<bool>(var); -} - -bool QOfonoDataConnectionManagerInterface::isRoamingAllowed() +bool QOfonoDataConnectionManagerInterface::roamingAllowed() { - QVariant var = getProperty("RoamingAllowed"); + QVariant var = getProperty(QStringLiteral("RoamingAllowed")); return qdbus_cast<bool>(var); } -bool QOfonoDataConnectionManagerInterface::isPowered() -{ - QVariant var = getProperty("Powered"); - return qdbus_cast<bool>(var); -} - -void QOfonoDataConnectionManagerInterface::connectNotify(const QMetaMethod &signal) -{ - Q_UNUSED(signal); -// static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QOfonoDataConnectionManagerInterface::propertyChanged); -// if (signal == propertyChangedSignal) { -// if (!connection().connect(QLatin1String(OFONO_SERVICE), -// this->path(), -// QLatin1String(OFONO_DATA_CONNECTION_MANAGER_INTERFACE), -// QLatin1String("PropertyChanged"), -// this,SIGNAL(propertyChanged(QString,QDBusVariant)))) { -// qWarning() << "PropertyCHanged not connected"; -// } -// } - -// static const QMetaMethod propertyChangedContextSignal = QMetaMethod::fromSignal(&QOfonoDataConnectionManagerInterface::propertyChangedContext); -// if (signal == propertyChangedContextSignal) { -// QOfonoDBusHelper *helper; -// helper = new QOfonoDBusHelper(this); - -// QDBusConnection::systemBus().connect(QLatin1String(OFONO_SERVICE), -// this->path(), -// QLatin1String(OFONO_DATA_CONNECTION_MANAGER_INTERFACE), -// QLatin1String("PropertyChanged"), -// helper,SLOT(propertyChanged(QString,QDBusVariant))); - - -// QObject::connect(helper,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), -// this,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), Qt::UniqueConnection); -// } -} - -void QOfonoDataConnectionManagerInterface::disconnectNotify(const QMetaMethod &signal) -{ - Q_UNUSED(signal); -// static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QOfonoDataConnectionManagerInterface::propertyChanged); -// if (signal == propertyChangedSignal) { - -// } -} - QVariant QOfonoDataConnectionManagerInterface::getProperty(const QString &property) { QVariant var; QVariantMap map = getProperties(); - if (map.contains(property)) { - var = map.value(property); - } else { - qDebug() << Q_FUNC_INFO << "does not contain" << property; - } + var = map.value(property); return var; } QVariantMap QOfonoDataConnectionManagerInterface::getProperties() { - QDBusReply<QVariantMap > reply = this->call(QLatin1String("GetProperties")); - return reply.value(); -} - -QOfonoConnectionContextInterface::QOfonoConnectionContextInterface(const QString &dbusPathName, QObject *parent) - : QDBusAbstractInterface(QLatin1String(OFONO_SERVICE), - dbusPathName, - OFONO_DATA_CONTEXT_INTERFACE, - QDBusConnection::systemBus(), parent) -{ -} - -QOfonoConnectionContextInterface::~QOfonoConnectionContextInterface() -{ -} - -bool QOfonoConnectionContextInterface::isActive() -{ - QVariant var = getProperty("Active"); - return qdbus_cast<bool>(var); -} - -QString QOfonoConnectionContextInterface::getApName() -{ - QVariant var = getProperty("AccessPointName"); - return qdbus_cast<QString>(var); -} - -QString QOfonoConnectionContextInterface::getType() -{ - QVariant var = getProperty("Type"); - return qdbus_cast<QString>(var); -} - -QString QOfonoConnectionContextInterface::getName() -{ - QVariant var = getProperty("Name"); - return qdbus_cast<QString>(var); -} - -QVariantMap QOfonoConnectionContextInterface::getSettings() -{ - QVariant var = getProperty("Settings"); - return qdbus_cast<QVariantMap>(var); -} - -QString QOfonoConnectionContextInterface::getInterface() -{ - QVariant var = getProperty("Interface"); - return qdbus_cast<QString>(var); -} - -QString QOfonoConnectionContextInterface::getAddress() -{ - QVariant var = getProperty("Address"); - return qdbus_cast<QString>(var); -} - -bool QOfonoConnectionContextInterface::setActive(bool on) -{ -// this->setProperty("Active", QVariant(on)); - - return setProp("Active", QVariant::fromValue(on)); -} - -bool QOfonoConnectionContextInterface::setApn(const QString &name) -{ - return setProp("AccessPointName", QVariant::fromValue(name)); -} - -void QOfonoConnectionContextInterface::connectNotify(const QMetaMethod &signal) -{ - Q_UNUSED(signal); -// static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QOfonoConnectionContextInterface::propertyChanged); -// if (signal == propertyChangedSignal) { -// if (!connection().connect(QLatin1String(OFONO_SERVICE), -// this->path(), -// QLatin1String(OFONO_DATA_CONTEXT_INTERFACE), -// QLatin1String("PropertyChanged"), -// this,SIGNAL(propertyChanged(QString,QDBusVariant)))) { -// qWarning() << "PropertyCHanged not connected"; -// } -// } - -// static const QMetaMethod propertyChangedContextSignal = QMetaMethod::fromSignal(&QOfonoConnectionContextInterface::propertyChangedContext); -// if (signal == propertyChangedContextSignal) { -// QOfonoDBusHelper *helper; -// helper = new QOfonoDBusHelper(this); - -// QDBusConnection::systemBus().connect(QLatin1String(OFONO_SERVICE), -// this->path(), -// QLatin1String(OFONO_DATA_CONTEXT_INTERFACE), -// QLatin1String("PropertyChanged"), -// helper,SLOT(propertyChanged(QString,QDBusVariant))); - - -// QObject::connect(helper,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), -// this,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), Qt::UniqueConnection); -// } -} - -void QOfonoConnectionContextInterface::disconnectNotify(const QMetaMethod &signal) -{ - Q_UNUSED(signal); -// static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QOfonoConnectionContextInterface::propertyChanged); -// if (signal == propertyChangedSignal) { - -// } -} - -QVariant QOfonoConnectionContextInterface::getProperty(const QString &property) -{ - QVariant var; - QVariantMap map = getProperties(); - if (map.contains(property)) { - var = map.value(property); - } else { - qDebug() << Q_FUNC_INFO << "does not contain" << property; - } - return var; -} - -QVariantMap QOfonoConnectionContextInterface::getProperties() -{ - QDBusReply<QVariantMap > reply = this->call(QLatin1String("GetProperties")); - return reply.value(); -} - -bool QOfonoConnectionContextInterface::setProp(const QString &property, const QVariant &var) -{ - QList<QVariant> args; - args << QVariant::fromValue(property) << QVariant::fromValue(QDBusVariant(var)); - - QDBusMessage reply = this->callWithArgumentList(QDBus::AutoDetect, - QLatin1String("SetProperty"), - args); - bool ok = true; - if (reply.type() != QDBusMessage::ReplyMessage) { - qWarning() << reply.errorMessage(); - ok = false; - } - qWarning() << reply.errorMessage(); - return ok; -} - -QOfonoSmsInterface::QOfonoSmsInterface(const QString &dbusPathName, QObject *parent) - : QDBusAbstractInterface(QLatin1String(OFONO_SERVICE), - dbusPathName, - OFONO_SMS_MANAGER_INTERFACE, - QDBusConnection::systemBus(), parent) -{ -} - -QOfonoSmsInterface::~QOfonoSmsInterface() -{ -} - -void QOfonoSmsInterface::connectNotify(const QMetaMethod &signal) -{ - static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QOfonoSmsInterface::propertyChanged); - if (signal == propertyChangedSignal) { - if (!connection().connect(QLatin1String(OFONO_SERVICE), - this->path(), - QLatin1String(OFONO_SMS_MANAGER_INTERFACE), - QLatin1String("PropertyChanged"), - this,SIGNAL(propertyChanged(QString,QDBusVariant)))) { - qWarning() << "PropertyCHanged not connected"; - } - } - - static const QMetaMethod propertyChangedContextSignal = QMetaMethod::fromSignal(&QOfonoSmsInterface::propertyChangedContext); - if (signal == propertyChangedContextSignal) { - QOfonoDBusHelper *helper; - helper = new QOfonoDBusHelper(this); - - QDBusConnection::systemBus().connect(QLatin1String(OFONO_SERVICE), - this->path(), - QLatin1String(OFONO_SMS_MANAGER_INTERFACE), - QLatin1String("PropertyChanged"), - helper,SLOT(propertyChanged(QString,QDBusVariant))); - - - QObject::connect(helper,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant)), - this,SIGNAL(propertyChangedContext(QString,QString,QDBusVariant))); - } - - static const QMetaMethod immediateMessageSignal = QMetaMethod::fromSignal(&QOfonoSmsInterface::immediateMessage); - if (signal == immediateMessageSignal) { - if (!connection().connect(QLatin1String(OFONO_SERVICE), - this->path(), - QLatin1String(OFONO_SMS_MANAGER_INTERFACE), - QLatin1String("ImmediateMessage"), - this,SIGNAL(immediateMessage(QString,QVariantMap)))) { - qWarning() << "PropertyCHanged not connected"; - } - } - - static const QMetaMethod incomingMessageSignal = QMetaMethod::fromSignal(&QOfonoSmsInterface::incomingMessage); - if (signal == incomingMessageSignal) { - if (!connection().connect(QLatin1String(OFONO_SERVICE), - this->path(), - QLatin1String(OFONO_SMS_MANAGER_INTERFACE), - QLatin1String("IncomingMessage"), - this,SIGNAL(incomingMessage(QString,QVariantMap)))) { - qWarning() << "PropertyCHanged not connected"; + if (propertiesMap.isEmpty()) { + QList<QVariant> argumentList; + QDBusPendingReply<QVariantMap> reply = asyncCallWithArgumentList(QLatin1String("GetProperties"), argumentList); + if (!reply.isError()) { + propertiesMap = reply.value(); } } + return propertiesMap; } -void QOfonoSmsInterface::disconnectNotify(const QMetaMethod &signal) -{ - static const QMetaMethod propertyChangedSignal = QMetaMethod::fromSignal(&QOfonoSmsInterface::propertyChanged); - if (signal == propertyChangedSignal) { - - } -} - -QVariant QOfonoSmsInterface::getProperty(const QString &property) -{ - QVariant var; - QVariantMap map = getProperties(); - if (map.contains(property)) { - var = map.value(property); - } else { - qDebug() << Q_FUNC_INFO << "does not contain" << property; - } - return var; -} - -QVariantMap QOfonoSmsInterface::getProperties() -{ - QDBusReply<QVariantMap > reply = this->call(QLatin1String("GetProperties")); - return reply.value(); -} - -void QOfonoSmsInterface::sendMessage(const QString &to, const QString &message) +void QOfonoDataConnectionManagerInterface::propertyChanged(const QString &name, const QDBusVariant &value) { - QDBusReply<QString> reply = this->call(QLatin1String("SendMessage"), - QVariant::fromValue(to), - QVariant::fromValue(message)); - if (reply.error().type() == QDBusError::InvalidArgs) - qWarning("%s", qPrintable(reply.error().message())); + propertiesMap[name] = value.variant(); + if (name == QStringLiteral("RoamingAllowed")) + Q_EMIT roamingAllowedChanged(value.variant().toBool()); } QT_END_NAMESPACE diff --git a/src/plugins/bearer/connman/qofonoservice_linux_p.h b/src/plugins/bearer/connman/qofonoservice_linux_p.h index 4802e0dc70..8fea465fd0 100644 --- a/src/plugins/bearer/connman/qofonoservice_linux_p.h +++ b/src/plugins/bearer/connman/qofonoservice_linux_p.h @@ -71,18 +71,10 @@ #define OFONO_SERVICE "org.ofono" #define OFONO_MANAGER_INTERFACE "org.ofono.Manager" #define OFONO_MANAGER_PATH "/" + #define OFONO_MODEM_INTERFACE "org.ofono.Modem" #define OFONO_NETWORK_REGISTRATION_INTERFACE "org.ofono.NetworkRegistration" -#define OFONO_NETWORK_OPERATOR_INTERFACE "org.ofono.NetworkOperator" #define OFONO_DATA_CONNECTION_MANAGER_INTERFACE "org.ofono.ConnectionManager" -#define OFONO_SIM_MANAGER_INTERFACE "org.ofono.SimManager" -#define OFONO_DATA_CONTEXT_INTERFACE "org.ofono.ConnectionContext" - -#define OFONO_SMS_MANAGER_INTERFACE "org.ofono.SmsManager" -#define OFONO_PHONEBOOK_INTERFACE "org.ofono.Phonebook" -#define OFONO_MESSAGE_WAITING_INTERFACE "org.ofono.MessageWaiting" - - QT_BEGIN_NAMESPACE @@ -108,35 +100,15 @@ public: QOfonoManagerInterface( QObject *parent = 0); ~QOfonoManagerInterface(); - QDBusObjectPath path() const; - - QVariantMap getProperties(); - bool setProperty(const QString &name, const QDBusVariant &value); - QList <QDBusObjectPath> getModems(); - QDBusObjectPath currentModem(); - -Q_SIGNALS: - void propertyChanged(const QString &, const QDBusVariant &value); - void propertyChangedContext(const QString &,const QString &,const QDBusVariant &); -protected: - void connectNotify(const QMetaMethod &signal); - void disconnectNotify(const QMetaMethod &signal); - QVariant getProperty(const QString &); - -}; - - -class QOfonoDBusHelper: public QObject, protected QDBusContext - { - Q_OBJECT - public: - QOfonoDBusHelper(QObject *parent = 0); - ~QOfonoDBusHelper(); - - public slots: - void propertyChanged(const QString &, const QDBusVariant &); - Q_SIGNALS: - void propertyChangedContext(const QString &,const QString &,const QDBusVariant &); + QStringList getModems(); + QString currentModem(); +signals: + void modemChanged(); +private: + QStringList modemList; +private slots: + void modemAdded(const QDBusObjectPath &path, const QVariantMap &var); + void modemRemoved(const QDBusObjectPath &path); }; class QOfonoModemInterface : public QDBusAbstractInterface @@ -148,27 +120,13 @@ public: explicit QOfonoModemInterface(const QString &dbusModemPathName, QObject *parent = 0); ~QOfonoModemInterface(); - QVariantMap getProperties(); - //properties bool isPowered(); bool isOnline(); - QString getName(); - QString getManufacturer(); - QString getModel(); - QString getRevision(); - QString getSerial(); - - QStringList getFeatures(); //sms, sim - QStringList getInterfaces(); - QString defaultInterface(); - -protected: - void connectNotify(const QMetaMethod &signal); - void disconnectNotify(const QMetaMethod &signal); +private: + QVariantMap getProperties(); + QVariantMap propertiesMap; QVariant getProperty(const QString &); -Q_SIGNALS: void propertyChanged(const QString &, const QDBusVariant &value); - void propertyChangedContext(const QString &,const QString &,const QDBusVariant &); }; @@ -181,80 +139,16 @@ public: explicit QOfonoNetworkRegistrationInterface(const QString &dbusModemPathName, QObject *parent = 0); ~QOfonoNetworkRegistrationInterface(); - QVariantMap getProperties(); - - //properties - QString getStatus(); - quint16 getLac(); - quint32 getCellId(); QString getTechnology(); - QString getOperatorName(); - int getSignalStrength(); - QString getBaseStation(); - QList <QDBusObjectPath> getOperators(); - -protected: - void connectNotify(const QMetaMethod &signal); - void disconnectNotify(const QMetaMethod &signal); - QVariant getProperty(const QString &); -Q_SIGNALS: - void propertyChanged(const QString &, const QDBusVariant &value); - void propertyChangedContext(const QString &,const QString &,const QDBusVariant &); - -}; - -class QOfonoNetworkOperatorInterface : public QDBusAbstractInterface -{ - Q_OBJECT - -public: -//modem or operator paths - explicit QOfonoNetworkOperatorInterface(const QString &dbusPathName, QObject *parent = 0); - ~QOfonoNetworkOperatorInterface(); - - QVariantMap getProperties(); - - //properties - QString getName(); - QString getStatus();// "unknown", "available", "current" and "forbidden" - QString getMcc(); - QString getMnc(); - QStringList getTechnologies(); - -protected: - void connectNotify(const QMetaMethod &signal); - void disconnectNotify(const QMetaMethod &signal); - QVariant getProperty(const QString &); -}; - -class QOfonoSimInterface : public QDBusAbstractInterface -{ - Q_OBJECT - -public: - - explicit QOfonoSimInterface(const QString &dbusModemPathName, QObject *parent = 0); - ~QOfonoSimInterface(); +private: QVariantMap getProperties(); - - //properties - bool isPresent(); - QString getHomeMcc(); - QString getHomeMnc(); -// QStringList subscriberNumbers(); -// QMap<QString,QString> serviceNumbers(); - QString pinRequired(); - QString lockedPins(); - QString cardIdentifier(); - -protected: - void connectNotify(const QMetaMethod &signal); - void disconnectNotify(const QMetaMethod &signal); QVariant getProperty(const QString &); + QVariantMap propertiesMap; +Q_SIGNALS: + void propertyChanged(const QString &, const QDBusVariant &value); }; - class QOfonoDataConnectionManagerInterface : public QDBusAbstractInterface { Q_OBJECT @@ -264,82 +158,20 @@ public: explicit QOfonoDataConnectionManagerInterface(const QString &dbusPathName, QObject *parent = 0); ~QOfonoDataConnectionManagerInterface(); + QStringList contexts(); + bool roamingAllowed(); +Q_SIGNALS: + void roamingAllowedChanged(bool); +private: QVariantMap getProperties(); - - //properties - QList<QDBusObjectPath> getPrimaryContexts(); - bool isAttached(); - bool isRoamingAllowed(); - bool isPowered(); - - bool setPower(bool on); - -protected: - void connectNotify(const QMetaMethod &signal); - void disconnectNotify(const QMetaMethod &signal); - QVariant getProperty(const QString &); -}; - - -class QOfonoConnectionContextInterface : public QDBusAbstractInterface -{ - Q_OBJECT - -public: - - explicit QOfonoConnectionContextInterface(const QString &dbusPathName, QObject *parent = 0); - ~QOfonoConnectionContextInterface(); - - QVariantMap getProperties(); - - //properties - bool isActive(); - QString getApName(); - QString getType(); - QString getName(); - QVariantMap getSettings(); - QString getInterface(); - QString getAddress(); - - bool setActive(bool on); - bool setApn(const QString &name); - -protected: - void connectNotify(const QMetaMethod &signal); - void disconnectNotify(const QMetaMethod &signal); - QVariant getProperty(const QString &); - bool setProp(const QString &, const QVariant &var); -}; - -class QOfonoSmsInterface : public QDBusAbstractInterface -{ - Q_OBJECT - -public: - - explicit QOfonoSmsInterface(const QString &dbusModemPathName, QObject *parent = 0); - ~QOfonoSmsInterface(); - - QVariantMap getProperties(); - void sendMessage(const QString &to, const QString &message); - - //properties - QString serviceCenterAddress(); - bool useDeliveryReports(); - QString bearer(); - -protected: - void connectNotify(const QMetaMethod &signal); - void disconnectNotify(const QMetaMethod &signal); + QVariantMap propertiesMap; QVariant getProperty(const QString &); - -Q_SIGNALS: + QStringList contextList; +private slots: void propertyChanged(const QString &, const QDBusVariant &value); - void propertyChangedContext(const QString &,const QString &,const QDBusVariant &); - void immediateMessage(const QString &message, const QVariantMap &info); - void incomingMessage(const QString &message, const QVariantMap &info); }; + QT_END_NAMESPACE #endif // QT_NO_DBUS diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp index f59a80d74e..dd86a80d23 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.cpp +++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp @@ -338,6 +338,7 @@ void QAndroidPlatformScreen::surfaceChanged(JNIEnv *env, jobject surface, int w, if (m_nativeSurface) ANativeWindow_release(m_nativeSurface); m_nativeSurface = ANativeWindow_fromSurface(env, surface); + QMetaObject::invokeMethod(this, "setDirty", Qt::QueuedConnection, Q_ARG(QRect, QRect(0, 0, w, h))); } else { if (m_nativeSurface) { ANativeWindow_release(m_nativeSurface); diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm index ee69cd7d86..29eed73535 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm @@ -75,7 +75,9 @@ #include "qcocoaeventdispatcher.h" #include "qcocoaautoreleasepool.h" +#include "qcocoawindow.h" +#include "qcocoahelpers.h" #include "qguiapplication.h" #include "qevent.h" #include "qhash.h" @@ -95,11 +97,6 @@ QT_BEGIN_NAMESPACE QT_USE_NAMESPACE -enum { - QtCocoaEventSubTypeWakeup = SHRT_MAX, - QtCocoaEventSubTypePostMessage = SHRT_MAX-1 -}; - static inline CFRunLoopRef mainRunLoop() { return CFRunLoopGetMain(); @@ -625,7 +622,7 @@ NSModalSession QCocoaEventDispatcherPrivate::currentModalSession() if (!info.session) { QCocoaAutoReleasePool pool; - NSWindow *nswindow = static_cast<NSWindow *>(QGuiApplication::platformNativeInterface()->nativeResourceForWindow("nswindow", info.window)); + NSWindow *nswindow = static_cast<QCocoaWindow *>(info.window->handle())->nativeWindow(); if (!nswindow) continue; diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index 4b637a707d..6f76892d93 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -42,6 +42,7 @@ #include "qcocoaglcontext.h" #include "qcocoawindow.h" #include "qcocoaautoreleasepool.h" +#include "qcocoahelpers.h" #include <qdebug.h> #include <QtCore/private/qcore_mac_p.h> #include <QtPlatformSupport/private/cglconvenience_p.h> @@ -151,6 +152,11 @@ QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLCo [m_context setValues:&zeroOpacity forParameter:NSOpenGLCPSurfaceOpacity]; } + + // 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]; + updateSurfaceFormat(); } diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h index 64e1640a69..419bf631aa 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.h +++ b/src/plugins/platforms/cocoa/qcocoahelpers.h @@ -162,6 +162,39 @@ CGContextRef qt_mac_cg_context(QPaintDevice *pdev); CGImageRef qt_mac_toCGImage(const QImage &qImage, bool isMask, uchar **dataCopy); QImage qt_mac_toQImage(CGImageRef image); +template<typename T> +T qt_mac_resolveOption(const T &fallback, const QByteArray &environment) +{ + // check for environment variable + if (!environment.isEmpty()) { + QByteArray env = qgetenv(environment); + if (!env.isEmpty()) + return T(env.toInt()); // works when T is bool, int. + } + + return fallback; +} + +template<typename T> +T qt_mac_resolveOption(const T &fallback, QWindow *window, const QByteArray &property, const QByteArray &environment) +{ + // check for environment variable + if (!environment.isEmpty()) { + QByteArray env = qgetenv(environment); + if (!env.isEmpty()) + return T(env.toInt()); // works when T is bool, int. + } + + // check for window property + if (window && !property.isNull()) { + QVariant windowProperty = window->property(property); + if (windowProperty.isValid()) + return windowProperty.value<T>(); + } + + // return default value. + return fallback; +} QT_END_NAMESPACE #endif //QCOCOAHELPERS_H diff --git a/src/plugins/platforms/cocoa/qcocoainputcontext.mm b/src/plugins/platforms/cocoa/qcocoainputcontext.mm index 79b1c0856f..f119699004 100644 --- a/src/plugins/platforms/cocoa/qcocoainputcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoainputcontext.mm @@ -43,6 +43,7 @@ #include "qcocoainputcontext.h" #include "qcocoanativeinterface.h" #include "qcocoaautoreleasepool.h" +#include "qcocoawindow.h" #include <QtCore/QRect> #include <QtGui/QGuiApplication> @@ -98,13 +99,12 @@ void QCocoaInputContext::reset() { QPlatformInputContext::reset(); - if (!mWindow) return; + if (!mWindow) + return; - QCocoaNativeInterface *nativeInterface = qobject_cast<QCocoaNativeInterface *>(QGuiApplication::platformNativeInterface()); - if (!nativeInterface) return; - - QNSView *view = static_cast<QNSView *>(nativeInterface->nativeResourceForWindow("nsview", mWindow)); - if (!view) return; + QNSView *view = static_cast<QCocoaWindow *>(mWindow->handle())->qtView(); + if (!view) + return; QCocoaAutoReleasePool pool; NSInputManager *currentIManager = [NSInputManager currentInputManager]; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index 8babfcf8ae..b1b73e5f08 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -134,6 +134,9 @@ public: void updateScreens(); QCocoaScreen *screenAtIndex(int index); + void setToolbar(QWindow *window, NSToolbar *toolbar); + NSToolbar *toolbar(QWindow *window) const; + void clearToolbars(); private: static QCocoaIntegration *mInstance; @@ -150,6 +153,8 @@ private: QScopedPointer<QCocoaNativeInterface> mNativeInterface; QScopedPointer<QCocoaServices> mServices; QScopedPointer<QCocoaKeyMapper> mKeyboardMapper; + + QHash<QWindow *, NSToolbar *> mToolbars; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index e8cf5ca69b..0c1ddf9ad8 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -301,6 +301,8 @@ QCocoaIntegration::~QCocoaIntegration() while (!mScreens.isEmpty()) { delete mScreens.takeLast(); } + + clearToolbars(); } QCocoaIntegration *QCocoaIntegration::instance() @@ -466,4 +468,27 @@ QList<int> QCocoaIntegration::possibleKeys(const QKeyEvent *event) const return mKeyboardMapper->possibleKeys(event); } +void QCocoaIntegration::setToolbar(QWindow *window, NSToolbar *toolbar) +{ + if (NSToolbar *prevToolbar = mToolbars.value(window)) + [prevToolbar release]; + + [toolbar retain]; + mToolbars.insert(window, toolbar); +} + +NSToolbar *QCocoaIntegration::toolbar(QWindow *window) const +{ + return mToolbars.value(window); +} + +void QCocoaIntegration::clearToolbars() +{ + QHash<QWindow *, NSToolbar *>::const_iterator it = mToolbars.constBegin(); + while (it != mToolbars.constEnd()) { + [it.value() release]; + } + mToolbars.clear(); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.h b/src/plugins/platforms/cocoa/qcocoanativeinterface.h index 4bcb348acb..bf7e85619a 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.h +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.h @@ -135,6 +135,11 @@ private: // Request a unified title and toolbar look for the window. static void setContentBorderThickness(QWindow *window, int topThickness, int bottomThickness); + + // Sets a NSToolbar instance for the given QWindow. The + // toolbar will be attached to the native NSWindow when + // that is created; + static void setNSToolbar(QWindow *window, void *nsToolbar); }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm index eb520b97c9..85ce96a8b6 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm @@ -47,6 +47,7 @@ #include "qmacmime.h" #include "qcocoahelpers.h" #include "qcocoaapplication.h" +#include "qcocoaintegration.h" #include <qbytearray.h> #include <qwindow.h> @@ -125,6 +126,8 @@ QPlatformNativeInterface::NativeResourceForIntegrationFunction QCocoaNativeInter return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setEmbeddedInForeignView); if (resource.toLower() == "setcontentborderthickness") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setContentBorderThickness); + if (resource.toLower() == "setnstoolbar") + return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setNSToolbar); return 0; } @@ -285,4 +288,16 @@ void QCocoaNativeInterface::setContentBorderThickness(QWindow *window, int topTh cocoaWindow->setContentBorderThickness(topThickness, bottomThickness); } +void QCocoaNativeInterface::setNSToolbar(QWindow *window, void *nsToolbar) +{ + if (!window) + return; + + QCocoaIntegration::instance()->setToolbar(window, static_cast<NSToolbar *>(nsToolbar)); + + QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle()); + if (cocoaWindow) + cocoaWindow->updateNSToolbar(); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 7b9768fcd9..256f5ee6fb 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -129,6 +129,8 @@ public: NSView *contentView() const; void setContentView(NSView *contentView); + QNSView *qtView() const; + NSWindow *nativeWindow() const; void setEmbeddedInForeignView(bool subwindow); @@ -162,6 +164,7 @@ public: void registerTouch(bool enable); void setContentBorderThickness(int topThickness, int bottomThickness); void applyContentBorderThickness(NSWindow *window); + void updateNSToolbar(); qreal devicePixelRatio() const; bool isWindowExposable(); diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 70a08bbea5..d71fe1ee18 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -45,6 +45,7 @@ #include "qcocoaeventdispatcher.h" #include "qcocoaglcontext.h" #include "qcocoahelpers.h" +#include "qcocoanativeinterface.h" #include "qnsview.h" #include <QtCore/qfileinfo.h> #include <QtCore/private/qcore_mac_p.h> @@ -250,9 +251,15 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) // problem, except if the appilcation wants to have a "custom" viewport. // (like the hellogl example) if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7 - && tlw->surfaceType() == QSurface::OpenGLSurface) - [m_contentView setWantsBestResolutionOpenGLSurface:YES]; + && tlw->surfaceType() == QSurface::OpenGLSurface) { + BOOL enable = qt_mac_resolveOption(YES, tlw, "_q_mac_wantsBestResolutionOpenGLSurface", + "QT_MAC_WANTS_BEST_RESOLUTION_OPENGL_SURFACE"); + [m_contentView setWantsBestResolutionOpenGLSurface:enable]; + } #endif + BOOL enable = qt_mac_resolveOption(NO, tlw, "_q_mac_wantsLayer", + "QT_MAC_WANTS_LAYER"); + [m_contentView setWantsLayer:enable]; } setGeometry(tlw->geometry()); recreateWindow(parent()); @@ -527,11 +534,13 @@ void QCocoaWindow::setVisible(bool visible) if (m_glContext) m_glContext->windowWasHidden(); QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher()); - Q_ASSERT(cocoaEventDispatcher != 0); - QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(cocoaEventDispatcher)); + QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = 0; + if (cocoaEventDispatcher) + cocoaEventDispatcherPrivate = static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(cocoaEventDispatcher)); if (m_nsWindow) { if (m_hasModalSession) { - cocoaEventDispatcherPrivate->endModalSession(window()); + if (cocoaEventDispatcherPrivate) + cocoaEventDispatcherPrivate->endModalSession(window()); m_hasModalSession = false; } else { if ([m_nsWindow isSheet]) @@ -539,7 +548,8 @@ void QCocoaWindow::setVisible(bool visible) } hide(); - if (m_nsWindow == [NSApp keyWindow] && !cocoaEventDispatcherPrivate->currentModalSession()) { + if (m_nsWindow == [NSApp keyWindow] + && !(cocoaEventDispatcherPrivate && cocoaEventDispatcherPrivate->currentModalSession())) { // Probably because we call runModalSession: outside [NSApp run] in QCocoaEventDispatcher // (e.g., when show()-ing a modal QDialog instead of exec()-ing it), it can happen that // the current NSWindow is still key after being ordered out. Then, after checking we @@ -933,6 +943,16 @@ void QCocoaWindow::setContentView(NSView *contentView) recreateWindow(parent()); // Adds the content view to parent NSView } +QNSView *QCocoaWindow::qtView() const +{ + return m_qtView; +} + +NSWindow *QCocoaWindow::nativeWindow() const +{ + return m_nsWindow; +} + void QCocoaWindow::setEmbeddedInForeignView(bool embedded) { m_contentViewIsToBeEmbedded = embedded; @@ -1100,6 +1120,11 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) const qreal opacity = qt_window_private(window())->opacity; if (!qFuzzyCompare(opacity, qreal(1.0))) setOpacity(opacity); + + // top-level QWindows may have an attached NSToolBar, call + // update function which will attach to the NSWindow. + if (!parentWindow) + updateNSToolbar(); } void QCocoaWindow::reinsertChildWindow(QCocoaWindow *child) @@ -1365,6 +1390,19 @@ void QCocoaWindow::applyContentBorderThickness(NSWindow *window) } } +void QCocoaWindow::updateNSToolbar() +{ + if (!m_nsWindow) + return; + + NSToolbar *toolbar = QCocoaIntegration::instance()->toolbar(window()); + + if ([m_nsWindow toolbar] == toolbar) + return; + + [m_nsWindow setToolbar: toolbar]; + [m_nsWindow setShowsToolbarButton:YES]; +} qreal QCocoaWindow::devicePixelRatio() const { diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 58c732de98..9920d428e9 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -1383,6 +1383,12 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) [self tryToPerform:aSelector with:self]; } +- (void)cancelOperation:(id)sender +{ + if (!m_platformWindow || m_platformWindow->windowShouldBehaveAsPanel()) + [super cancelOperation:sender]; +} + - (void) insertText:(id)aString replacementRange:(NSRange)replacementRange { Q_UNUSED(replacementRange) diff --git a/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp b/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp index dbfd8d99dc..dfb766db32 100644 --- a/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp +++ b/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp @@ -44,10 +44,12 @@ #include <QtPlatformSupport/private/qeglconvenience_p.h> #include <QtCore/QRegularExpression> +#if defined(Q_OS_LINUX) #include <fcntl.h> #include <unistd.h> #include <linux/fb.h> #include <sys/ioctl.h> +#endif #include <private/qcore_unix_p.h> diff --git a/src/plugins/platforms/ios/ios.pro b/src/plugins/platforms/ios/ios.pro index 1dfb07ba08..175cc3f8bd 100644 --- a/src/plugins/platforms/ios/ios.pro +++ b/src/plugins/platforms/ios/ios.pro @@ -36,5 +36,8 @@ HEADERS = \ qiosinputcontext.h \ qiostheme.h \ qiosglobal.h \ - qiosservices.h + qiosservices.h \ + quiview.h +OTHER_FILES = \ + quiview_textinput.mm diff --git a/src/plugins/platforms/ios/qiosinputcontext.h b/src/plugins/platforms/ios/qiosinputcontext.h index 533ba686e1..aec1686b93 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.h +++ b/src/plugins/platforms/ios/qiosinputcontext.h @@ -50,6 +50,7 @@ QT_BEGIN_NAMESPACE @class QIOSKeyboardListener; +@class QUIView; class QIOSInputContext : public QPlatformInputContext { @@ -64,14 +65,19 @@ public: void setFocusObject(QObject *object); void focusWindowChanged(QWindow *focusWindow); - void scrollRootView(); + void cursorRectangleChanged(); + void scrollToCursor(); + void scroll(int y); + + void update(Qt::InputMethodQueries); + void reset(); + void commit(); private: QIOSKeyboardListener *m_keyboardListener; - UIView<UIKeyInput> *m_focusView; - QTransform m_inputItemTransform; + QUIView *m_focusView; bool m_hasPendingHideRequest; - bool m_inSetFocusObject; + QObject *m_focusObject; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index 39a22f367e..15f5082f62 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -42,6 +42,7 @@ #include "qiosglobal.h" #include "qiosinputcontext.h" #include "qioswindow.h" +#include "quiview.h" #include <QGuiApplication> @interface QIOSKeyboardListener : NSObject { @@ -49,6 +50,7 @@ QIOSInputContext *m_context; BOOL m_keyboardVisible; BOOL m_keyboardVisibleAndDocked; + BOOL m_ignoreKeyboardChanges; QRectF m_keyboardRect; QRectF m_keyboardEndRect; NSTimeInterval m_duration; @@ -66,6 +68,7 @@ m_context = context; m_keyboardVisible = NO; m_keyboardVisibleAndDocked = NO; + m_ignoreKeyboardChanges = NO; m_duration = 0; m_curve = UIViewAnimationCurveEaseOut; m_viewController = 0; @@ -128,6 +131,8 @@ - (void) keyboardDidChangeFrame:(NSNotification *)notification { + if (m_ignoreKeyboardChanges) + return; m_keyboardRect = [self getKeyboardRect:notification]; m_context->emitKeyboardRectChanged(); @@ -140,11 +145,13 @@ // If the keyboard was visible and docked from before, this is just a geometry // change (normally caused by an orientation change). In that case, update scroll: if (m_keyboardVisibleAndDocked) - m_context->scrollRootView(); + m_context->scrollToCursor(); } - (void) keyboardWillShow:(NSNotification *)notification { + if (m_ignoreKeyboardChanges) + return; // Note that UIKeyboardWillShowNotification is only sendt when the keyboard is docked. m_keyboardVisibleAndDocked = YES; m_keyboardEndRect = [self getKeyboardRect:notification]; @@ -152,15 +159,17 @@ m_duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; m_curve = UIViewAnimationCurve([notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue] << 16); } - m_context->scrollRootView(); + m_context->scrollToCursor(); } - (void) keyboardWillHide:(NSNotification *)notification { + if (m_ignoreKeyboardChanges) + return; // Note that UIKeyboardWillHideNotification is also sendt when the keyboard is undocked. m_keyboardVisibleAndDocked = NO; m_keyboardEndRect = [self getKeyboardRect:notification]; - m_context->scrollRootView(); + m_context->scroll(0); } @end @@ -170,10 +179,10 @@ QIOSInputContext::QIOSInputContext() , m_keyboardListener([[QIOSKeyboardListener alloc] initWithQIOSInputContext:this]) , m_focusView(0) , m_hasPendingHideRequest(false) - , m_inSetFocusObject(false) + , m_focusObject(0) { if (isQtApplication()) - connect(qGuiApp->inputMethod(), &QInputMethod::cursorRectangleChanged, this, &QIOSInputContext::scrollRootView); + connect(qGuiApp->inputMethod(), &QInputMethod::cursorRectangleChanged, this, &QIOSInputContext::cursorRectangleChanged); connect(qGuiApp, &QGuiApplication::focusWindowChanged, this, &QIOSInputContext::focusWindowChanged); } @@ -216,76 +225,101 @@ bool QIOSInputContext::isInputPanelVisible() const return m_keyboardListener->m_keyboardVisible; } -void QIOSInputContext::setFocusObject(QObject *) +void QIOSInputContext::setFocusObject(QObject *focusObject) { - m_inputItemTransform = qApp->inputMethod()->inputItemTransform(); + m_focusObject = focusObject; - if (!m_focusView || !m_focusView.isFirstResponder) + if (!focusObject || !m_focusView || !m_focusView.isFirstResponder) { + scroll(0); return; + } - // Since m_focusView is the first responder, it means that the keyboard is open and we - // should update keyboard layout. But there seem to be no way to tell it to reread the - // UITextInputTraits from m_focusView. To work around that, we quickly resign first - // responder status just to reassign it again. To not remove the focusObject in the same - // go, we need to call the super implementation of resignFirstResponder. Since the call - // will cause a 'keyboardWillHide' notification to be sendt, we also block scrollRootView - // to avoid artifacts: - m_inSetFocusObject = true; - SEL sel = @selector(resignFirstResponder); - [[m_focusView superclass] instanceMethodForSelector:sel](m_focusView, sel); - m_inSetFocusObject = false; - [m_focusView becomeFirstResponder]; + reset(); + + if (m_keyboardListener->m_keyboardVisibleAndDocked) + scrollToCursor(); } void QIOSInputContext::focusWindowChanged(QWindow *focusWindow) { - UIView<UIKeyInput> *view = reinterpret_cast<UIView<UIKeyInput> *>(focusWindow->handle()->winId()); + QUIView *view = focusWindow ? reinterpret_cast<QUIView *>(focusWindow->handle()->winId()) : 0; if ([m_focusView isFirstResponder]) [view becomeFirstResponder]; [m_focusView release]; m_focusView = [view retain]; + + if (view.window != m_keyboardListener->m_viewController.view) + scroll(0); } -void QIOSInputContext::scrollRootView() +void QIOSInputContext::cursorRectangleChanged() { - // Scroll the root view (screen) if: - // - our backend controls the root view controller on the main screen (no hybrid app) - // - the focus object is on the same screen as the keyboard. - // - the first responder is a QUIView, and not some other foreign UIView. - // - the keyboard is docked. Otherwise the user can move the keyboard instead. - // - the inputItem has not been moved/scrolled - if (!isQtApplication() || !m_focusView || m_inSetFocusObject) + if (!m_keyboardListener->m_keyboardVisibleAndDocked) return; - if (m_inputItemTransform != qApp->inputMethod()->inputItemTransform()) { - // The inputItem has moved since the last scroll update. To avoid competing - // with the application where the cursor/inputItem should be, we bail: + // Check if the cursor has changed position inside the input item. Since + // qApp->inputMethod()->cursorRectangle() will also change when the input item + // itself moves, we need to ask the focus object for ImCursorRectangle: + static QPoint prevCursor; + QInputMethodQueryEvent queryEvent(Qt::ImCursorRectangle); + QCoreApplication::sendEvent(m_focusObject, &queryEvent); + QPoint cursor = queryEvent.value(Qt::ImCursorRectangle).toRect().topLeft(); + if (cursor != prevCursor) + scrollToCursor(); + prevCursor = cursor; +} + +void QIOSInputContext::scrollToCursor() +{ + if (!isQtApplication() || !m_focusView) return; - } UIView *view = m_keyboardListener->m_viewController.view; - qreal scrollTo = 0; - - if (m_focusView.isFirstResponder - && m_keyboardListener->m_keyboardVisibleAndDocked - && m_focusView.window == view.window) { - QRectF cursorRect = qGuiApp->inputMethod()->cursorRectangle(); - cursorRect.translate(m_focusView.qwindow->geometry().topLeft()); - qreal keyboardY = m_keyboardListener->m_keyboardEndRect.y(); - int statusBarY = qGuiApp->primaryScreen()->availableGeometry().y(); - const int margin = 20; - - if (cursorRect.bottomLeft().y() > keyboardY - margin) - scrollTo = qMin(view.bounds.size.height - keyboardY, cursorRect.y() - statusBarY - margin); - } + if (view.window != m_focusView.window) + return; - if (scrollTo != view.bounds.origin.y) { - // Scroll the view the same way a UIScrollView works: by changing bounds.origin: - CGRect newBounds = view.bounds; - newBounds.origin.y = scrollTo; - [UIView animateWithDuration:m_keyboardListener->m_duration delay:0 - options:m_keyboardListener->m_curve - animations:^{ view.bounds = newBounds; } - completion:0]; - } + const int margin = 20; + QRectF translatedCursorPos = qApp->inputMethod()->cursorRectangle(); + translatedCursorPos.translate(m_focusView.qwindow->geometry().topLeft()); + qreal keyboardY = m_keyboardListener->m_keyboardEndRect.y(); + int statusBarY = qGuiApp->primaryScreen()->availableGeometry().y(); + + scroll((translatedCursorPos.bottomLeft().y() < keyboardY - margin) ? 0 + : qMin(view.bounds.size.height - keyboardY, translatedCursorPos.y() - statusBarY - margin)); } + +void QIOSInputContext::scroll(int y) +{ + // Scroll the view the same way a UIScrollView + // works: by changing bounds.origin: + UIView *view = m_keyboardListener->m_viewController.view; + if (y == view.bounds.origin.y) + return; + + CGRect newBounds = view.bounds; + newBounds.origin.y = y; + [UIView animateWithDuration:m_keyboardListener->m_duration delay:0 + options:m_keyboardListener->m_curve + animations:^{ view.bounds = newBounds; } + completion:0]; +} + +void QIOSInputContext::update(Qt::InputMethodQueries query) +{ + [m_focusView updateInputMethodWithQuery:query]; +} + +void QIOSInputContext::reset() +{ + // Since the call to reset will cause a 'keyboardWillHide' + // notification to be sendt, we block keyboard nofifications to avoid artifacts: + m_keyboardListener->m_ignoreKeyboardChanges = true; + [m_focusView reset]; + m_keyboardListener->m_ignoreKeyboardChanges = false; +} + +void QIOSInputContext::commit() +{ + [m_focusView commit]; +} + diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm index 15a52e89ec..41a253e605 100644 --- a/src/plugins/platforms/ios/qioswindow.mm +++ b/src/plugins/platforms/ios/qioswindow.mm @@ -41,6 +41,7 @@ #include "qiosglobal.h" #include "qioswindow.h" +#include "quiview.h" #include "qioscontext.h" #include "qiosinputcontext.h" #include "qiosscreen.h" @@ -58,33 +59,19 @@ #include <QtDebug> -@interface QUIView : UIView <UIKeyInput> -{ -@public - UITextAutocapitalizationType autocapitalizationType; - UITextAutocorrectionType autocorrectionType; - BOOL enablesReturnKeyAutomatically; - UIKeyboardAppearance keyboardAppearance; - UIKeyboardType keyboardType; - UIReturnKeyType returnKeyType; - BOOL secureTextEntry; - QIOSWindow *m_qioswindow; - QHash<UITouch *, QWindowSystemInterface::TouchPoint> m_activeTouches; - int m_nextTouchId; -} - -@property(nonatomic) UITextAutocapitalizationType autocapitalizationType; -@property(nonatomic) UITextAutocorrectionType autocorrectionType; -@property(nonatomic) BOOL enablesReturnKeyAutomatically; -@property(nonatomic) UIKeyboardAppearance keyboardAppearance; -@property(nonatomic) UIKeyboardType keyboardType; -@property(nonatomic) UIReturnKeyType returnKeyType; -@property(nonatomic, getter=isSecureTextEntry) BOOL secureTextEntry; - -@end +// Include category as an alternative to using -ObjC (Apple QA1490) +#include "quiview_textinput.mm" @implementation QUIView +@synthesize autocapitalizationType; +@synthesize autocorrectionType; +@synthesize enablesReturnKeyAutomatically; +@synthesize keyboardAppearance; +@synthesize keyboardType; +@synthesize returnKeyType; +@synthesize secureTextEntry; + + (Class)layerClass { return [CAEAGLLayer class]; @@ -112,6 +99,7 @@ self.hidden = YES; self.multipleTouchEnabled = YES; + m_inSendEventToFocusObject = NO; } return self; @@ -314,109 +302,6 @@ QWindowSystemInterface::flushWindowSystemEvents(); } -@synthesize autocapitalizationType; -@synthesize autocorrectionType; -@synthesize enablesReturnKeyAutomatically; -@synthesize keyboardAppearance; -@synthesize keyboardType; -@synthesize returnKeyType; -@synthesize secureTextEntry; - -- (BOOL)canBecomeFirstResponder -{ - return YES; -} - -- (BOOL)becomeFirstResponder -{ - // Note: QIOSInputContext controls our first responder status based on - // whether or not the keyboard should be open or closed. - [self updateTextInputTraits]; - return [super becomeFirstResponder]; -} - -- (BOOL)resignFirstResponder -{ - // Resigning first responed status means that the virtual keyboard was closed, or - // some other view became first responder. In either case we clear the focus object to - // avoid blinking cursors in line edits etc: - if (m_qioswindow) - static_cast<QWindowPrivate *>(QObjectPrivate::get(m_qioswindow->window()))->clearFocusObject(); - return [super resignFirstResponder]; -} - -- (BOOL)hasText -{ - return YES; -} - -- (void)insertText:(NSString *)text -{ - QString string = QString::fromUtf8([text UTF8String]); - int key = 0; - if ([text isEqualToString:@"\n"]) { - key = (int)Qt::Key_Return; - if (self.returnKeyType == UIReturnKeyDone) - [self resignFirstResponder]; - } - - // Send key event to window system interface - QWindowSystemInterface::handleKeyEvent( - 0, QEvent::KeyPress, key, Qt::NoModifier, string, false, int(string.length())); - QWindowSystemInterface::handleKeyEvent( - 0, QEvent::KeyRelease, key, Qt::NoModifier, string, false, int(string.length())); -} - -- (void)deleteBackward -{ - // Send key event to window system interface - QWindowSystemInterface::handleKeyEvent( - 0, QEvent::KeyPress, (int)Qt::Key_Backspace, Qt::NoModifier); - QWindowSystemInterface::handleKeyEvent( - 0, QEvent::KeyRelease, (int)Qt::Key_Backspace, Qt::NoModifier); -} - -- (void)updateTextInputTraits -{ - // Ask the current focus object what kind of input it - // expects, and configure the keyboard appropriately: - QObject *focusObject = QGuiApplication::focusObject(); - if (!focusObject) - return; - QInputMethodQueryEvent queryEvent(Qt::ImEnabled | Qt::ImHints); - if (!QCoreApplication::sendEvent(focusObject, &queryEvent)) - return; - if (!queryEvent.value(Qt::ImEnabled).toBool()) - return; - - Qt::InputMethodHints hints = static_cast<Qt::InputMethodHints>(queryEvent.value(Qt::ImHints).toUInt()); - - self.returnKeyType = (hints & Qt::ImhMultiLine) ? UIReturnKeyDefault : UIReturnKeyDone; - self.secureTextEntry = BOOL(hints & Qt::ImhHiddenText); - self.autocorrectionType = (hints & Qt::ImhNoPredictiveText) ? - UITextAutocorrectionTypeNo : UITextAutocorrectionTypeDefault; - - if (hints & Qt::ImhUppercaseOnly) - self.autocapitalizationType = UITextAutocapitalizationTypeAllCharacters; - else if (hints & Qt::ImhNoAutoUppercase) - self.autocapitalizationType = UITextAutocapitalizationTypeNone; - else - self.autocapitalizationType = UITextAutocapitalizationTypeSentences; - - if (hints & Qt::ImhUrlCharactersOnly) - self.keyboardType = UIKeyboardTypeURL; - else if (hints & Qt::ImhEmailCharactersOnly) - self.keyboardType = UIKeyboardTypeEmailAddress; - else if (hints & Qt::ImhDigitsOnly) - self.keyboardType = UIKeyboardTypeNumberPad; - else if (hints & Qt::ImhFormattedNumbersOnly) - self.keyboardType = UIKeyboardTypeDecimalPad; - else if (hints & Qt::ImhDialableCharactersOnly) - self.keyboardType = UIKeyboardTypeNumberPad; - else - self.keyboardType = UIKeyboardTypeDefault; -} - @end @implementation UIView (QIOS) diff --git a/src/plugins/platforms/ios/quiview.h b/src/plugins/platforms/ios/quiview.h new file mode 100644 index 0000000000..575dedab89 --- /dev/null +++ b/src/plugins/platforms/ios/quiview.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#import <UIKit/UIKit.h> +#include "qioswindow.h" + +@interface QUIView : UIView +{ +@public + UITextAutocapitalizationType autocapitalizationType; + UITextAutocorrectionType autocorrectionType; + BOOL enablesReturnKeyAutomatically; + UIKeyboardAppearance keyboardAppearance; + UIKeyboardType keyboardType; + UIReturnKeyType returnKeyType; + BOOL secureTextEntry; + QIOSWindow *m_qioswindow; + QHash<UITouch *, QWindowSystemInterface::TouchPoint> m_activeTouches; + int m_nextTouchId; + QString m_markedText; + BOOL m_inSendEventToFocusObject; +} + +@property(nonatomic, assign) id<UITextInputDelegate> inputDelegate; +@property(nonatomic) UITextAutocapitalizationType autocapitalizationType; +@property(nonatomic) UITextAutocorrectionType autocorrectionType; +@property(nonatomic) UITextSpellCheckingType spellCheckingType; +@property(nonatomic) BOOL enablesReturnKeyAutomatically; +@property(nonatomic) UIKeyboardAppearance keyboardAppearance; +@property(nonatomic) UIKeyboardType keyboardType; +@property(nonatomic) UIReturnKeyType returnKeyType; +@property(nonatomic, getter=isSecureTextEntry) BOOL secureTextEntry; + +@end + +@interface QUIView (TextInput) <UITextInput> +- (void)updateInputMethodWithQuery:(Qt::InputMethodQueries)query; +- (void)reset; +- (void)commit; +@end diff --git a/src/plugins/platforms/ios/quiview_textinput.mm b/src/plugins/platforms/ios/quiview_textinput.mm new file mode 100644 index 0000000000..d0088d415a --- /dev/null +++ b/src/plugins/platforms/ios/quiview_textinput.mm @@ -0,0 +1,557 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui/qtextformat.h> + +class StaticVariables +{ +public: + QInputMethodQueryEvent inputMethodQueryEvent; + QTextCharFormat markedTextFormat; + + StaticVariables() : inputMethodQueryEvent(Qt::ImQueryInput) + { + // There seems to be no way to query how the preedit text + // should be drawn. So we need to hard-code the color. + QSysInfo::MacVersion iosVersion = QSysInfo::MacintoshVersion; + if (iosVersion < QSysInfo::MV_IOS_7_0) + markedTextFormat.setBackground(QColor(235, 239, 247)); + else + markedTextFormat.setBackground(QColor(206, 221, 238)); + } +}; + +Q_GLOBAL_STATIC(StaticVariables, staticVariables); + +// ------------------------------------------------------------------------- + +@interface QUITextPosition : UITextPosition +{ +} + +@property (nonatomic) NSUInteger index; ++ (QUITextPosition *)positionWithIndex:(NSUInteger)index; + +@end + +@implementation QUITextPosition + ++ (QUITextPosition *)positionWithIndex:(NSUInteger)index +{ + QUITextPosition *pos = [[QUITextPosition alloc] init]; + pos.index = index; + return [pos autorelease]; +} + +@end + +// ------------------------------------------------------------------------- + +@interface QUITextRange : UITextRange +{ +} + +@property (nonatomic) NSRange range; ++ (QUITextRange *)rangeWithNSRange:(NSRange)range; + +@end + +@implementation QUITextRange + ++ (QUITextRange *)rangeWithNSRange:(NSRange)nsrange +{ + QUITextRange *range = [[QUITextRange alloc] init]; + range.range = nsrange; + return [range autorelease]; +} + +- (UITextPosition *)start +{ + return [QUITextPosition positionWithIndex:self.range.location]; +} + +- (UITextPosition *)end +{ + return [QUITextPosition positionWithIndex:(self.range.location + self.range.length)]; +} + +- (NSRange) range +{ + return _range; +} + +-(BOOL)isEmpty +{ + return (self.range.length == 0); +} + +@end + +// ------------------------------------------------------------------------- + +@implementation QUIView (TextInput) + +- (BOOL)canBecomeFirstResponder +{ + return YES; +} + +- (BOOL)becomeFirstResponder +{ + // Note: QIOSInputContext controls our first responder status based on + // whether or not the keyboard should be open or closed. + [self updateTextInputTraits]; + return [super becomeFirstResponder]; +} + +- (BOOL)resignFirstResponder +{ + // Resigning first responed status means that the virtual keyboard was closed, or + // some other view became first responder. In either case we clear the focus object to + // avoid blinking cursors in line edits etc: + if (m_qioswindow) + static_cast<QWindowPrivate *>(QObjectPrivate::get(m_qioswindow->window()))->clearFocusObject(); + return [super resignFirstResponder]; +} + +- (void)updateInputMethodWithQuery:(Qt::InputMethodQueries)query +{ + Q_UNUSED(query); + + QObject *focusObject = QGuiApplication::focusObject(); + if (!focusObject) + return; + + if (!m_inSendEventToFocusObject) { + if (query & (Qt::ImCursorPosition | Qt::ImAnchorPosition)) + [self.inputDelegate selectionWillChange:id<UITextInput>(self)]; + if (query & Qt::ImSurroundingText) + [self.inputDelegate textWillChange:id<UITextInput>(self)]; + } + + // Note that we ignore \a query, and instead update using Qt::ImQueryInput. This enables us to just + // store the event without copying out the result from the event each time. Besides, we seem to be + // called with Qt::ImQueryInput when only changing selection, and always if typing text. So there would + // not be any performance gain by only updating \a query. + staticVariables()->inputMethodQueryEvent = QInputMethodQueryEvent(Qt::ImQueryInput); + QCoreApplication::sendEvent(focusObject, &staticVariables()->inputMethodQueryEvent); + + if (!m_inSendEventToFocusObject) { + if (query & (Qt::ImCursorPosition | Qt::ImAnchorPosition)) + [self.inputDelegate selectionDidChange:id<UITextInput>(self)]; + if (query & Qt::ImSurroundingText) + [self.inputDelegate textDidChange:id<UITextInput>(self)]; + } +} + +- (void)sendEventToFocusObject:(QEvent &)e +{ + QObject *focusObject = QGuiApplication::focusObject(); + if (!focusObject) + return; + + // While sending the event, we will receive back updateInputMethodWithQuery calls. + // To not confuse iOS, we cannot not call textWillChange/textDidChange at that + // point since it will cause spell checking etc to fail. So we use a guard. + m_inSendEventToFocusObject = YES; + QCoreApplication::sendEvent(focusObject, &e); + m_inSendEventToFocusObject = NO; +} + +- (void)reset +{ + [self.inputDelegate textWillChange:id<UITextInput>(self)]; + [self setMarkedText:@"" selectedRange:NSMakeRange(0, 0)]; + [self updateInputMethodWithQuery:Qt::ImQueryInput]; + + if ([self isFirstResponder]) { + // There seem to be no way to inform that the keyboard needs to update (since + // text input traits might have changed). As a work-around, we quickly resign + // first responder status just to reassign it again: + [super resignFirstResponder]; + [self updateTextInputTraits]; + [super becomeFirstResponder]; + } + [self.inputDelegate textDidChange:id<UITextInput>(self)]; +} + +- (void)commit +{ + [self.inputDelegate textWillChange:id<UITextInput>(self)]; + [self unmarkText]; + [self.inputDelegate textDidChange:id<UITextInput>(self)]; +} + +- (QVariant)imValue:(Qt::InputMethodQuery)query +{ + return staticVariables()->inputMethodQueryEvent.value(query); +} + +-(id<UITextInputTokenizer>)tokenizer +{ + return [[[UITextInputStringTokenizer alloc] initWithTextInput:id<UITextInput>(self)] autorelease]; +} + +-(UITextPosition *)beginningOfDocument +{ + return [QUITextPosition positionWithIndex:0]; +} + +-(UITextPosition *)endOfDocument +{ + int endPosition = [self imValue:Qt::ImSurroundingText].toString().length(); + return [QUITextPosition positionWithIndex:endPosition]; +} + +- (void)setSelectedTextRange:(UITextRange *)range +{ + QUITextRange *r = static_cast<QUITextRange *>(range); + QList<QInputMethodEvent::Attribute> attrs; + attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, r.range.location, r.range.length, 0); + QInputMethodEvent e(m_markedText, attrs); + [self sendEventToFocusObject:e]; +} + +- (UITextRange *)selectedTextRange { + int cursorPos = [self imValue:Qt::ImCursorPosition].toInt(); + int anchorPos = [self imValue:Qt::ImAnchorPosition].toInt(); + return [QUITextRange rangeWithNSRange:NSMakeRange(cursorPos, (anchorPos - cursorPos))]; +} + +- (NSString *)textInRange:(UITextRange *)range +{ + int s = static_cast<QUITextPosition *>([range start]).index; + int e = static_cast<QUITextPosition *>([range end]).index; + return [self imValue:Qt::ImSurroundingText].toString().mid(s, e - s).toNSString(); +} + +- (void)setMarkedText:(NSString *)markedText selectedRange:(NSRange)selectedRange +{ + Q_UNUSED(selectedRange); + + m_markedText = markedText ? QString::fromNSString(markedText) : QString(); + + QList<QInputMethodEvent::Attribute> attrs; + attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, markedText.length, staticVariables()->markedTextFormat); + QInputMethodEvent e(m_markedText, attrs); + [self sendEventToFocusObject:e]; +} + +- (void)unmarkText +{ + if (m_markedText.isEmpty()) + return; + + QInputMethodEvent e; + e.setCommitString(m_markedText); + [self sendEventToFocusObject:e]; + + m_markedText.clear(); +} + +- (NSComparisonResult)comparePosition:(UITextPosition *)position toPosition:(UITextPosition *)other +{ + int p = static_cast<QUITextPosition *>(position).index; + int o = static_cast<QUITextPosition *>(other).index; + if (p > o) + return NSOrderedAscending; + else if (p < o) + return NSOrderedDescending; + return NSOrderedSame; +} + +- (UITextRange *)markedTextRange { + return m_markedText.isEmpty() ? nil : [QUITextRange rangeWithNSRange:NSMakeRange(0, m_markedText.length())]; +} + +- (UITextRange *)textRangeFromPosition:(UITextPosition *)fromPosition toPosition:(UITextPosition *)toPosition +{ + int f = static_cast<QUITextPosition *>(fromPosition).index; + int t = static_cast<QUITextPosition *>(toPosition).index; + return [QUITextRange rangeWithNSRange:NSMakeRange(f, t - f)]; +} + +- (UITextPosition *)positionFromPosition:(UITextPosition *)position offset:(NSInteger)offset +{ + int p = static_cast<QUITextPosition *>(position).index; + return [QUITextPosition positionWithIndex:p + offset]; +} + +- (UITextPosition *)positionFromPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction offset:(NSInteger)offset +{ + int p = static_cast<QUITextPosition *>(position).index; + return [QUITextPosition positionWithIndex:(direction == UITextLayoutDirectionRight ? p + offset : p - offset)]; +} + +- (UITextPosition *)positionWithinRange:(UITextRange *)range farthestInDirection:(UITextLayoutDirection)direction +{ + NSRange r = static_cast<QUITextRange *>(range).range; + if (direction == UITextLayoutDirectionRight) + return [QUITextPosition positionWithIndex:r.location + r.length]; + return [QUITextPosition positionWithIndex:r.location]; +} + +- (NSInteger)offsetFromPosition:(UITextPosition *)fromPosition toPosition:(UITextPosition *)toPosition +{ + int f = static_cast<QUITextPosition *>(fromPosition).index; + int t = static_cast<QUITextPosition *>(toPosition).index; + return t - f; +} + +- (UIView *)textInputView +{ + // iOS expects rects we return from other UITextInput methods + // to be relative to the view this method returns. + // Since QInputMethod returns rects relative to the top level + // QWindow, that is also the view we need to return. + QPlatformWindow *topLevel = m_qioswindow; + while (QPlatformWindow *p = topLevel->parent()) + topLevel = p; + return reinterpret_cast<UIView *>(topLevel->winId()); +} + +- (CGRect)firstRectForRange:(UITextRange *)range +{ + QObject *focusObject = QGuiApplication::focusObject(); + if (!focusObject) + return CGRectZero; + + // Using a work-around to get the current rect until + // a better API is in place: + if (!m_markedText.isEmpty()) + return CGRectZero; + + int cursorPos = [self imValue:Qt::ImCursorPosition].toInt(); + int anchorPos = [self imValue:Qt::ImAnchorPosition].toInt(); + + NSRange r = static_cast<QUITextRange*>(range).range; + QList<QInputMethodEvent::Attribute> attrs; + attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, r.location, 0, 0); + QInputMethodEvent e(m_markedText, attrs); + [self sendEventToFocusObject:e]; + QRectF startRect = qApp->inputMethod()->cursorRectangle(); + + attrs = QList<QInputMethodEvent::Attribute>(); + attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, r.location + r.length, 0, 0); + e = QInputMethodEvent(m_markedText, attrs); + [self sendEventToFocusObject:e]; + QRectF endRect = qApp->inputMethod()->cursorRectangle(); + + if (cursorPos != int(r.location + r.length) || cursorPos != anchorPos) { + attrs = QList<QInputMethodEvent::Attribute>(); + attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, cursorPos, (cursorPos - anchorPos), 0); + e = QInputMethodEvent(m_markedText, attrs); + [self sendEventToFocusObject:e]; + } + + return toCGRect(startRect.united(endRect)); +} + +- (CGRect)caretRectForPosition:(UITextPosition *)position +{ + Q_UNUSED(position); + // Assume for now that position is always the same as + // cursor index until a better API is in place: + QRectF cursorRect = qApp->inputMethod()->cursorRectangle(); + return toCGRect(cursorRect); +} + +- (void)replaceRange:(UITextRange *)range withText:(NSString *)text +{ + [self setSelectedTextRange:range]; + + QInputMethodEvent e; + e.setCommitString(QString::fromNSString(text)); + [self sendEventToFocusObject:e]; +} + +- (void)setBaseWritingDirection:(UITextWritingDirection)writingDirection forRange:(UITextRange *)range +{ + Q_UNUSED(writingDirection); + Q_UNUSED(range); + // Writing direction is handled by QLocale +} + +- (UITextWritingDirection)baseWritingDirectionForPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction +{ + Q_UNUSED(position); + Q_UNUSED(direction); + if (QLocale::system().textDirection() == Qt::RightToLeft) + return UITextWritingDirectionRightToLeft; + return UITextWritingDirectionLeftToRight; +} + +- (UITextRange *)characterRangeByExtendingPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction +{ + int p = static_cast<QUITextPosition *>(position).index; + if (direction == UITextLayoutDirectionLeft) + return [QUITextRange rangeWithNSRange:NSMakeRange(0, p)]; + int l = [self imValue:Qt::ImSurroundingText].toString().length(); + return [QUITextRange rangeWithNSRange:NSMakeRange(p, l - p)]; +} + +- (UITextPosition *)closestPositionToPoint:(CGPoint)point +{ + // No API in Qt for determining this. Use sensible default instead: + Q_UNUSED(point); + return [QUITextPosition positionWithIndex:[self imValue:Qt::ImCursorPosition].toInt()]; +} + +- (UITextPosition *)closestPositionToPoint:(CGPoint)point withinRange:(UITextRange *)range +{ + // No API in Qt for determining this. Use sensible default instead: + Q_UNUSED(point); + Q_UNUSED(range); + return [QUITextPosition positionWithIndex:[self imValue:Qt::ImCursorPosition].toInt()]; +} + +- (UITextRange *)characterRangeAtPoint:(CGPoint)point +{ + // No API in Qt for determining this. Use sensible default instead: + Q_UNUSED(point); + return [QUITextRange rangeWithNSRange:NSMakeRange([self imValue:Qt::ImCursorPosition].toInt(), 0)]; +} + +- (void)setMarkedTextStyle:(NSDictionary *)style +{ + Q_UNUSED(style); + // No-one is going to change our style. If UIKit itself did that + // it would be very welcome, since then we knew how to style marked + // text instead of just guessing... +} + +- (NSDictionary *)textStylingAtPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction +{ + Q_UNUSED(position); + Q_UNUSED(direction); + + QObject *focusObject = QGuiApplication::focusObject(); + if (!focusObject) + return [NSDictionary dictionary]; + + // 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. + QInputMethodQueryEvent e(Qt::ImFont); + QCoreApplication::sendEvent(focusObject, &e); + QFont qfont = qvariant_cast<QFont>(e.value(Qt::ImFont)); + UIFont *uifont = [UIFont fontWithName:qfont.family().toNSString() size:qfont.pointSize()]; + return [NSDictionary dictionaryWithObject:uifont forKey:UITextInputTextFontKey]; +} + +-(NSDictionary *)markedTextStyle +{ + return [NSDictionary dictionary]; +} + +- (BOOL)hasText +{ + return YES; +} + +- (void)insertText:(NSString *)text +{ + QObject *focusObject = QGuiApplication::focusObject(); + if (!focusObject) + return; + + if ([text isEqualToString:@"\n"] && self.returnKeyType == UIReturnKeyDone) + [self resignFirstResponder]; + + QInputMethodEvent e; + e.setCommitString(QString::fromNSString(text)); + [self sendEventToFocusObject:e]; +} + +- (void)deleteBackward +{ + // Since we're posting im events directly to the focus object, we should do the + // same for key events. Otherwise they might end up in a different place or out + // of sync with im events. + QKeyEvent press(QEvent::KeyPress, (int)Qt::Key_Backspace, Qt::NoModifier); + QKeyEvent release(QEvent::KeyRelease, (int)Qt::Key_Backspace, Qt::NoModifier); + [self sendEventToFocusObject:press]; + [self sendEventToFocusObject:release]; +} + +- (void)updateTextInputTraits +{ + // Ask the current focus object what kind of input it + // expects, and configure the keyboard appropriately: + QObject *focusObject = QGuiApplication::focusObject(); + if (!focusObject) + return; + QInputMethodQueryEvent queryEvent(Qt::ImEnabled | Qt::ImHints); + if (!QCoreApplication::sendEvent(focusObject, &queryEvent)) + return; + if (!queryEvent.value(Qt::ImEnabled).toBool()) + return; + + Qt::InputMethodHints hints = static_cast<Qt::InputMethodHints>(queryEvent.value(Qt::ImHints).toUInt()); + + self.returnKeyType = (hints & Qt::ImhMultiLine) ? UIReturnKeyDefault : UIReturnKeyDone; + self.secureTextEntry = BOOL(hints & Qt::ImhHiddenText); + self.autocorrectionType = (hints & Qt::ImhNoPredictiveText) ? + UITextAutocorrectionTypeNo : UITextAutocorrectionTypeDefault; + self.spellCheckingType = (hints & Qt::ImhNoPredictiveText) ? + UITextSpellCheckingTypeNo : UITextSpellCheckingTypeDefault; + + if (hints & Qt::ImhUppercaseOnly) + self.autocapitalizationType = UITextAutocapitalizationTypeAllCharacters; + else if (hints & Qt::ImhNoAutoUppercase) + self.autocapitalizationType = UITextAutocapitalizationTypeNone; + else + self.autocapitalizationType = UITextAutocapitalizationTypeSentences; + + if (hints & Qt::ImhUrlCharactersOnly) + self.keyboardType = UIKeyboardTypeURL; + else if (hints & Qt::ImhEmailCharactersOnly) + self.keyboardType = UIKeyboardTypeEmailAddress; + else if (hints & Qt::ImhDigitsOnly) + self.keyboardType = UIKeyboardTypeNumberPad; + else if (hints & Qt::ImhFormattedNumbersOnly) + self.keyboardType = UIKeyboardTypeDecimalPad; + else if (hints & Qt::ImhDialableCharactersOnly) + self.keyboardType = UIKeyboardTypeNumberPad; + else + self.keyboardType = UIKeyboardTypeDefault; +} + +@end diff --git a/src/plugins/platforms/kms/qkmsintegration.cpp b/src/plugins/platforms/kms/qkmsintegration.cpp index 63c6d08bdc..868886a0dd 100644 --- a/src/plugins/platforms/kms/qkmsintegration.cpp +++ b/src/plugins/platforms/kms/qkmsintegration.cpp @@ -66,9 +66,28 @@ QT_BEGIN_NAMESPACE QKmsIntegration::QKmsIntegration() : QPlatformIntegration(), m_fontDatabase(new QGenericUnixFontDatabase()), - m_nativeInterface(new QKmsNativeInterface) + m_nativeInterface(new QKmsNativeInterface), + m_vtHandler(0), + m_deviceDiscovery(0) { - setenv("EGL_PLATFORM", "drm",1); +} + +QKmsIntegration::~QKmsIntegration() +{ + delete m_deviceDiscovery; + foreach (QKmsDevice *device, m_devices) { + delete device; + } + foreach (QPlatformScreen *screen, m_screens) { + delete screen; + } + delete m_fontDatabase; + delete m_vtHandler; +} + +void QKmsIntegration::initialize() +{ + qputenv("EGL_PLATFORM", "drm"); m_vtHandler = new QFbVtHandler; m_deviceDiscovery = QDeviceDiscovery::create(QDeviceDiscovery::Device_DRM | QDeviceDiscovery::Device_DRM_PrimaryGPU, 0); @@ -88,19 +107,6 @@ QKmsIntegration::QKmsIntegration() #endif } -QKmsIntegration::~QKmsIntegration() -{ - delete m_deviceDiscovery; - foreach (QKmsDevice *device, m_devices) { - delete device; - } - foreach (QPlatformScreen *screen, m_screens) { - delete screen; - } - delete m_fontDatabase; - delete m_vtHandler; -} - void QKmsIntegration::addDevice(const QString &deviceNode) { m_devices.append(new QKmsDevice(deviceNode, this)); diff --git a/src/plugins/platforms/kms/qkmsintegration.h b/src/plugins/platforms/kms/qkmsintegration.h index bba4f53d7c..3d3f1722e9 100644 --- a/src/plugins/platforms/kms/qkmsintegration.h +++ b/src/plugins/platforms/kms/qkmsintegration.h @@ -60,16 +60,17 @@ public: QKmsIntegration(); ~QKmsIntegration(); - bool hasCapability(QPlatformIntegration::Capability cap) const; + void initialize() Q_DECL_OVERRIDE; + bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE; - QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; - QPlatformWindow *createPlatformWindow(QWindow *window) const; - QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const Q_DECL_OVERRIDE; + QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const Q_DECL_OVERRIDE; - QPlatformFontDatabase *fontDatabase() const; - QAbstractEventDispatcher *createEventDispatcher() const; + QPlatformFontDatabase *fontDatabase() const Q_DECL_OVERRIDE; + QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE; - QPlatformNativeInterface *nativeInterface() const; + QPlatformNativeInterface *nativeInterface() const Q_DECL_OVERRIDE; void addScreen(QKmsScreen *screen); QObject *createDevice(const char *); diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 8380aba13b..b69ec1e30f 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -969,7 +969,8 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, if (lParam & ENDSESSION_LOGOFF) fflush(NULL); - return !sessionManager->wasCanceled(); + *result = sessionManager->wasCanceled() ? 0 : 1; + return true; } case QtWindows::EndSessionApplicationEvent: { QWindowsSessionManager *sessionManager = platformSessionManager(); diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 2abfb426cc..f0770d7d18 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -502,11 +502,31 @@ template <class BaseClass> QWindowsDialogHelperBase<BaseClass>::QWindowsDialogHelperBase() : m_nativeDialog(0), m_ownerWindow(0), - m_timerId(0) + m_timerId(0), + m_thread(0) { } template <class BaseClass> +void QWindowsDialogHelperBase<BaseClass>::cleanupThread() +{ + if (m_thread) { // Thread may be running if the dialog failed to close. + if (m_thread->isRunning()) + m_thread->wait(500); + if (m_thread->isRunning()) { + m_thread->terminate(); + m_thread->wait(300); + if (m_thread->isRunning()) + qCCritical(lcQpaDialogs) <<__FUNCTION__ << "Failed to terminate thread."; + else + qCWarning(lcQpaDialogs) << __FUNCTION__ << "Thread terminated."; + } + delete m_thread; + m_thread = 0; + } +} + +template <class BaseClass> QWindowsNativeDialogBase *QWindowsDialogHelperBase<BaseClass>::nativeDialog() const { if (m_nativeDialog.isNull()) { @@ -559,7 +579,6 @@ void QWindowsDialogThread::run() { qCDebug(lcQpaDialogs) << '>' << __FUNCTION__; m_dialog->exec(m_owner); - deleteLater(); qCDebug(lcQpaDialogs) << '<' << __FUNCTION__; } @@ -587,6 +606,7 @@ bool QWindowsDialogHelperBase<BaseClass>::show(Qt::WindowFlags, // a subsequent call to exec() may follow. So, start an idle timer // which will start the dialog thread. If exec() is then called, the // timer is stopped and dialog->exec() is called directly. + cleanupThread(); if (modal) { m_timerId = this->startTimer(0); } else { @@ -599,8 +619,9 @@ template <class BaseClass> void QWindowsDialogHelperBase<BaseClass>::startDialogThread() { Q_ASSERT(!m_nativeDialog.isNull()); - QWindowsDialogThread *thread = new QWindowsDialogThread(m_nativeDialog, m_ownerWindow); - thread->start(); + Q_ASSERT(!m_thread); + m_thread = new QWindowsDialogThread(m_nativeDialog, m_ownerWindow); + m_thread->start(); stopTimer(); } diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.h b/src/plugins/platforms/windows/qwindowsdialoghelpers.h index 1501b02bd9..bcf9f544b5 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.h +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.h @@ -52,6 +52,7 @@ QT_BEGIN_NAMESPACE class QFileDialog; class QDialog; +class QThread; class QWindowsNativeDialogBase; namespace QWindowsDialogs @@ -68,6 +69,7 @@ class QWindowsDialogHelperBase : public BaseClass Q_DISABLE_COPY(QWindowsDialogHelperBase) public: typedef QSharedPointer<QWindowsNativeDialogBase> QWindowsNativeDialogBasePtr; + ~QWindowsDialogHelperBase() { cleanupThread(); } virtual void exec(); virtual bool show(Qt::WindowFlags windowFlags, @@ -88,10 +90,12 @@ private: inline QWindowsNativeDialogBase *ensureNativeDialog(); inline void startDialogThread(); inline void stopTimer(); + void cleanupThread(); QWindowsNativeDialogBasePtr m_nativeDialog; HWND m_ownerWindow; int m_timerId; + QThread *m_thread; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index 8f3ccdc0be..60c3daff23 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -673,14 +673,6 @@ QWindowsOleDropTarget::Release(void) return m_refs; } -QWindow *QWindowsOleDropTarget::findDragOverWindow(const POINTL &pt) const -{ - if (QWindowsWindow *child = - QWindowsWindow::baseWindowOf(m_window)->childAtScreenPoint(QPoint(pt.x, pt.y))) - return child->window(); - return m_window; -} - void QWindowsOleDropTarget::handleDrag(QWindow *window, DWORD grfKeyState, const QPoint &point, LPDWORD pdwEffect) { @@ -735,10 +727,9 @@ QWindowsOleDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) if (IDropTargetHelper* dh = QWindowsDrag::instance()->dropHelper()) dh->DragOver(reinterpret_cast<POINT*>(&pt), *pdwEffect); - QWindow *dragOverWindow = findDragOverWindow(pt); - qCDebug(lcQpaMime) << __FUNCTION__ << "widget=" << dragOverWindow << " key=" << grfKeyState + qCDebug(lcQpaMime) << __FUNCTION__ << "m_window" << m_window << "key=" << grfKeyState << "pt=" << pt.x << pt.y; - const QPoint tmpPoint = QWindowsGeometryHint::mapFromGlobal(dragOverWindow, QPoint(pt.x,pt.y)); + const QPoint tmpPoint = QWindowsGeometryHint::mapFromGlobal(m_window, QPoint(pt.x,pt.y)); // see if we should compress this event if ((tmpPoint == m_lastPoint || m_answerRect.contains(tmpPoint)) && m_lastKeyState == grfKeyState) { @@ -747,7 +738,7 @@ QWindowsOleDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) return NOERROR; } - handleDrag(dragOverWindow, grfKeyState, tmpPoint, pdwEffect); + handleDrag(m_window, grfKeyState, tmpPoint, pdwEffect); return NOERROR; } @@ -774,12 +765,10 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState, if (IDropTargetHelper* dh = QWindowsDrag::instance()->dropHelper()) dh->Drop(pDataObj, reinterpret_cast<POINT*>(&pt), *pdwEffect); - QWindow *dropWindow = findDragOverWindow(pt); - qCDebug(lcQpaMime) << __FUNCTION__ << ' ' << m_window - << " on " << dropWindow << " keys=" << grfKeyState << " pt=" << pt.x << ',' << pt.y; + << "keys=" << grfKeyState << "pt=" << pt.x << ',' << pt.y; - m_lastPoint = QWindowsGeometryHint::mapFromGlobal(dropWindow, QPoint(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 so if // it doesn't then use the last known button state; if ((grfKeyState & KEY_STATE_BUTTON_MASK) == 0) @@ -789,7 +778,7 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState, QWindowsDrag *windowsDrag = QWindowsDrag::instance(); const QPlatformDropQtResponse response = - QWindowSystemInterface::handleDrop(dropWindow, windowsDrag->dropData(), m_lastPoint, + QWindowSystemInterface::handleDrop(m_window, windowsDrag->dropData(), m_lastPoint, translateToQDragDropActions(*pdwEffect)); if (response.isAccepted()) { diff --git a/src/plugins/platforms/windows/qwindowsdrag.h b/src/plugins/platforms/windows/qwindowsdrag.h index 33da4d6cc5..4f758fbf3f 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.h +++ b/src/plugins/platforms/windows/qwindowsdrag.h @@ -74,7 +74,6 @@ public: STDMETHOD(Drop)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect); private: - inline QWindow *findDragOverWindow(const POINTL &pt) const; void handleDrag(QWindow *window, DWORD grfKeyState, const QPoint &, LPDWORD pdwEffect); ULONG m_refs; diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index c273219181..3bd24fdaab 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -1038,12 +1038,12 @@ QWindowsFontDatabase::~QWindowsFontDatabase() removeApplicationFonts(); } -QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle) +QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, void *handle) { - QFontEngine *fe = QWindowsFontDatabase::createEngine(script, fontDef, + QFontEngine *fe = QWindowsFontDatabase::createEngine(QChar::Script_Common, fontDef, 0, QWindowsContext::instance()->defaultDPI(), false, QStringList(), sharedFontData()); - qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef << script << fe << handle; + qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef << fe << handle; return fe; } @@ -1746,14 +1746,6 @@ QFontEngine *QWindowsFontDatabase::createEngine(int script, const QFontDef &requ QWindowsFontEngine *few = new QWindowsFontEngine(request.family, hfont, stockFont, lf, data); if (preferClearTypeAA) few->glyphFormat = QFontEngineGlyphCache::Raster_RGBMask; - - // Also check for OpenType tables when using complex scripts - if (!few->supportsScript(QChar::Script(script))) { - qWarning(" OpenType support missing for script %d", int(script)); - delete few; - return 0; - } - few->initFontInfo(request, fontHdc, dpi); fe = few; } diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.h b/src/plugins/platforms/windows/qwindowsfontdatabase.h index 7dfcfbc2b5..1e13fc2559 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.h +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.h @@ -78,7 +78,7 @@ public: ~QWindowsFontDatabase(); virtual void populateFontDatabase(); - virtual QFontEngine *fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle); + virtual QFontEngine *fontEngine(const QFontDef &fontDef, void *handle); virtual QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); virtual QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const; virtual QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName); diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp index c4fc2f4759..c9160e4a75 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp @@ -422,10 +422,10 @@ void QWindowsFontDatabaseFT::populate(const QString &family) ReleaseDC(0, dummy); } -QFontEngine * QWindowsFontDatabaseFT::fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle) +QFontEngine * QWindowsFontDatabaseFT::fontEngine(const QFontDef &fontDef, void *handle) { - QFontEngine *fe = QBasicFontDatabase::fontEngine(fontDef, script, handle); - qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef.family << script << fe << handle; + QFontEngine *fe = QBasicFontDatabase::fontEngine(fontDef, handle); + qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef.family << fe << handle; return fe; } diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h index 9544974ad1..bad6c54bf4 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h @@ -52,7 +52,7 @@ class QWindowsFontDatabaseFT : public QBasicFontDatabase { public: void populateFontDatabase(); - QFontEngine *fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle); + QFontEngine *fontEngine(const QFontDef &fontDef, void *handle); QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const; diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index b046879314..9bfe4e6e26 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -988,7 +988,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex if (dummyWindow) DestroyWindow(dummyWindow); - qCDebug(lcQpaGl()) << __FUNCTION__ << this << (tryExtensions ? "ARB" : "GDI") + qCDebug(lcQpaGl) << __FUNCTION__ << this << (tryExtensions ? "ARB" : "GDI") << " requested: " << context->format() << "\n obtained #" << m_pixelFormat << (m_extensionsUsed ? "ARB" : "GDI") << m_obtainedFormat << "\n " << m_obtainedPixelFormatDescriptor << " swap interval: " << obtainedSwapInternal diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 5b6fced031..256967d25f 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -882,20 +882,8 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) setFlag(OpenGL_ES2); #endif } - if (aWindow->isTopLevel()) { - switch (type) { - case Qt::Window: - case Qt::Dialog: - case Qt::Sheet: - case Qt::Drawer: - case Qt::Popup: - case Qt::Tool: - registerDropSite(); - break; - default: - break; - } - } + updateDropSite(); + #ifndef Q_OS_WINCE if (QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch) { if (QWindowsContext::user32dll.registerTouchWindow(m_data.hwnd, 0)) { @@ -944,7 +932,7 @@ void QWindowsWindow::destroyWindow() context->clearWindowUnderMouse(); if (hasMouseCapture()) setMouseGrabEnabled(false); - unregisterDropSite(); + setDropSiteEnabled(false); #ifdef QT_OPENGL_ES_2 if (m_eglSurface) { qCDebug(lcQpaGl) << __FUNCTION__ << "Freeing EGL surface " << m_eglSurface << window(); @@ -967,31 +955,44 @@ void QWindowsWindow::destroyWindow() } } -void QWindowsWindow::registerDropSite() +void QWindowsWindow::updateDropSite() { -#ifndef QT_NO_CLIPBOARD -# ifndef QT_NO_DRAGANDDROP - if (m_data.hwnd && !m_dropTarget) { - m_dropTarget = new QWindowsOleDropTarget(window()); - RegisterDragDrop(m_data.hwnd, m_dropTarget); - CoLockObjectExternal(m_dropTarget, true, true); + bool enabled = false; + if (window()->isTopLevel()) { + switch (window()->type()) { + case Qt::Window: + case Qt::Dialog: + case Qt::Sheet: + case Qt::Drawer: + case Qt::Popup: + case Qt::Tool: + enabled = true; + break; + default: + break; + } } -# endif // !QT_NO_DRAGANDDROP -#endif // !QT_NO_CLIPBOARD + setDropSiteEnabled(enabled); } -void QWindowsWindow::unregisterDropSite() +void QWindowsWindow::setDropSiteEnabled(bool dropEnabled) { -#ifndef QT_NO_CLIPBOARD -# ifndef QT_NO_DRAGANDDROP - if (m_data.hwnd && m_dropTarget) { + if (isDropSiteEnabled() == dropEnabled) + return; + qCDebug(lcQpaMime) << __FUNCTION__ << window() << dropEnabled; +#if !defined(QT_NO_CLIPBOARD) && !defined(QT_NO_DRAGANDDROP) + if (dropEnabled) { + Q_ASSERT(m_data.hwnd); + m_dropTarget = new QWindowsOleDropTarget(window()); + RegisterDragDrop(m_data.hwnd, m_dropTarget); + CoLockObjectExternal(m_dropTarget, true, true); + } else { m_dropTarget->Release(); CoLockObjectExternal(m_dropTarget, false, true); RevokeDragDrop(m_data.hwnd); m_dropTarget = 0; } -# endif // !QT_NO_DRAGANDDROP -#endif // !QT_NO_CLIPBOARD +#endif // !QT_NO_CLIPBOARD && !QT_NO_DRAGANDDROP } // Returns topmost QWindowsWindow ancestor even if there are embedded windows in the chain. @@ -1188,7 +1189,7 @@ void QWindowsWindow::setParent(const QPlatformWindow *newParent) setParent_sys(newParent); } -void QWindowsWindow::setParent_sys(const QPlatformWindow *parent) const +void QWindowsWindow::setParent_sys(const QPlatformWindow *parent) { // Use GetAncestor instead of GetParent, as GetParent can return owner window for toplevels HWND oldParentHWND = GetAncestor(m_data.hwnd, GA_PARENT); @@ -1217,8 +1218,11 @@ void QWindowsWindow::setParent_sys(const QPlatformWindow *parent) const // WS_CHILD/WS_POPUP must be manually set/cleared in addition // to dialog frames, etc (see SetParent() ) if the top level state changes. // Force toplevel state as QWindow::isTopLevel cannot be relied upon here. - if (wasTopLevel != isTopLevel) + if (wasTopLevel != isTopLevel) { + setDropSiteEnabled(false); setWindowFlags_sys(window()->flags(), unsigned(isTopLevel ? WindowCreationData::ForceTopLevel : WindowCreationData::ForceChild)); + updateDropSite(); + } } } @@ -1234,6 +1238,28 @@ void QWindowsWindow::handleCompositionSettingsChanged() applyBlurBehindWindow(handle()); } +static QRect normalFrameGeometry(HWND hwnd) +{ +#ifndef Q_OS_WINCE + WINDOWPLACEMENT wp; + wp.length = sizeof(WINDOWPLACEMENT); + if (GetWindowPlacement(hwnd, &wp)) + return qrectFromRECT(wp.rcNormalPosition); +#else + Q_UNUSED(hwnd) +#endif + return QRect(); +} + +QRect QWindowsWindow::normalGeometry() const +{ + // Check for fake 'fullscreen' mode. + const bool fakeFullScreen = m_savedFrameGeometry.isValid() && window()->windowState() == Qt::WindowFullScreen; + const QRect frame = fakeFullScreen ? m_savedFrameGeometry : normalFrameGeometry(m_data.hwnd); + const QMargins margins = fakeFullScreen ? QWindowsGeometryHint::frame(m_savedStyle, 0) : frameMargins(); + return frame.isValid() ? frame.marginsRemoved(margins) : frame; +} + void QWindowsWindow::setGeometry(const QRect &rectIn) { QRect rect = rectIn; @@ -1436,8 +1462,10 @@ void QWindowsWindow::setWindowFlags(Qt::WindowFlags flags) const QRect oldGeometry = geometry(); if (m_data.flags != flags) { m_data.flags = flags; - if (m_data.hwnd) + if (m_data.hwnd) { m_data = setWindowFlags_sys(flags); + updateDropSite(); + } } // When switching to a frameless window, geometry // may change without a WM_MOVE. Report change manually. @@ -1593,10 +1621,9 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) m_savedStyle = style(); #ifndef Q_OS_WINCE if (oldState == Qt::WindowMinimized) { - WINDOWPLACEMENT wp; - wp.length = sizeof(WINDOWPLACEMENT); - if (GetWindowPlacement(m_data.hwnd, &wp)) - m_savedFrameGeometry = qrectFromRECT(wp.rcNormalPosition); + const QRect nf = normalFrameGeometry(m_data.hwnd); + if (nf.isValid()) + m_savedFrameGeometry = nf; } else { #endif m_savedFrameGeometry = frameGeometry_sys(); diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 3a9516e0e5..1d515fd2fe 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -162,6 +162,7 @@ public: virtual QSurfaceFormat format() const { return m_format; } virtual void setGeometry(const QRect &rect); virtual QRect geometry() const { return m_data.geometry; } + QRect normalGeometry() const Q_DECL_OVERRIDE; virtual void setVisible(bool visible); bool isVisible() const; @@ -277,11 +278,12 @@ private: inline QWindowsWindowData setWindowFlags_sys(Qt::WindowFlags wt, unsigned flags = 0) const; inline bool isFullScreen_sys() const; inline void setWindowState_sys(Qt::WindowState newState); - inline void setParent_sys(const QPlatformWindow *parent) const; + inline void setParent_sys(const QPlatformWindow *parent); inline void updateTransientParent() const; void destroyWindow(); - void registerDropSite(); - void unregisterDropSite(); + inline bool isDropSiteEnabled() const { return m_dropTarget != 0; } + void setDropSiteEnabled(bool enabled); + void updateDropSite(); void handleGeometryChange(); void handleWindowStateChange(Qt::WindowState state); inline void destroyIcon(); diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index ecbf28bab9..1803282071 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -145,18 +145,15 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char if (argc) { int j = 1; for (int i = 1; i < argc; i++) { - char *arg = argv[i]; - if (arg) { - if (!strcmp(arg, "-display") && i < argc - 1) { - displayName = argv[++i]; - arg = 0; - } else if (!strcmp(arg, "-name") && i < argc - 1) { - m_instanceName = argv[++i]; - arg = 0; - } - } - if (arg) - argv[j++] = arg; + QByteArray arg(argv[i]); + if (arg.startsWith("--")) + arg.remove(0, 1); + if (arg == "-display" && i < argc - 1) + displayName = argv[++i]; + else if (arg == "-name" && i < argc - 1) + m_instanceName = argv[++i]; + else + argv[j++] = argv[i]; } argc = j; } // argc diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 3d79f742b3..58abc7abfe 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -1375,6 +1375,7 @@ void QXcbWindow::requestActivateWindow() updateNetWmUserTime(connection()->time()); if (window()->isTopLevel() + && !(window()->flags() & Qt::X11BypassWindowManagerHint) && connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::_NET_ACTIVE_WINDOW))) { xcb_client_message_event_t event; @@ -1390,10 +1391,10 @@ void QXcbWindow::requestActivateWindow() event.data.data32[4] = 0; Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event)); + } else { + Q_XCB_CALL(xcb_set_input_focus(xcb_connection(), XCB_INPUT_FOCUS_PARENT, m_window, connection()->time())); } - Q_XCB_CALL(xcb_set_input_focus(xcb_connection(), XCB_INPUT_FOCUS_PARENT, m_window, connection()->time())); - connection()->sync(); } diff --git a/src/plugins/platforms/xcb/xcb-plugin.pro b/src/plugins/platforms/xcb/xcb-plugin.pro index 67f2d8a911..4727262f3f 100644 --- a/src/plugins/platforms/xcb/xcb-plugin.pro +++ b/src/plugins/platforms/xcb/xcb-plugin.pro @@ -90,7 +90,7 @@ contains(QT_CONFIG, opengl) { DEFINES += XCB_HAS_XCB_GLX LIBS += -lxcb-glx } - } else:contains(QT_CONFIG, egl) { + } else:contains(QT_CONFIG, egl):contains(QT_CONFIG, egl_x11) { DEFINES += XCB_USE_EGL CONFIG += egl HEADERS += qxcbeglsurface.h diff --git a/src/printsupport/dialogs/qprintpreviewdialog.cpp b/src/printsupport/dialogs/qprintpreviewdialog.cpp index 4692fb5c3c..c0c8a759aa 100644 --- a/src/printsupport/dialogs/qprintpreviewdialog.cpp +++ b/src/printsupport/dialogs/qprintpreviewdialog.cpp @@ -65,6 +65,15 @@ #ifndef QT_NO_PRINTPREVIEWDIALOG +static void initResources() +{ + static bool resourcesInitialized = false; + if (!resourcesInitialized) { + Q_INIT_RESOURCE(qprintdialog); + resourcesInitialized = true; + } +} + QT_BEGIN_NAMESPACE namespace { @@ -217,6 +226,8 @@ void QPrintPreviewDialogPrivate::init(QPrinter *_printer) { Q_Q(QPrintPreviewDialog); + initResources(); + if (_printer) { preview = new QPrintPreviewWidget(_printer, q); printer = _printer; diff --git a/src/printsupport/printsupport.pro b/src/printsupport/printsupport.pro index ee4f9f72df..a92d36f7bc 100644 --- a/src/printsupport/printsupport.pro +++ b/src/printsupport/printsupport.pro @@ -1,6 +1,7 @@ TARGET = QtPrintSupport QT = core-private gui-private widgets-private +MODULE_CONFIG = needs_printsupport_plugin DEFINES += QT_NO_USING_NAMESPACE QMAKE_DOCS = $$PWD/doc/qtprintsupport.qdocconf diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index 1f84a4b5c4..fdf0fcdbdb 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -446,7 +446,8 @@ void QApplicationPrivate::process_cmdline() continue; } QByteArray arg = argv[i]; - arg = arg; + if (arg.startsWith("--")) + arg.remove(0, 1); QString s; if (arg == "-qdevel" || arg == "-qdebug") { // obsolete argument diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index c7f8e18118..672c4156cd 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -50,6 +50,7 @@ #include <private/qwidgetbackingstore_p.h> #include <qpa/qwindowsysteminterface_p.h> #include <qpa/qplatformtheme.h> +#include <qpa/qplatformwindow.h> #include <private/qgesturemanager_p.h> QT_BEGIN_NAMESPACE @@ -547,6 +548,24 @@ void QWidgetWindow::updateGeometry() m_widget->data->fstrut_dirty = false; } +Qt::WindowState effectiveState(Qt::WindowStates state); + +// Store normal geometry used for saving application settings. +void QWidgetWindow::updateNormalGeometry() +{ + QTLWExtra *tle = m_widget->d_func()->maybeTopData(); + if (!tle) + return; + // Ask platform window, default to widget geometry. + QRect normalGeometry; + if (const QPlatformWindow *pw = handle()) + normalGeometry = pw->normalGeometry(); + if (!normalGeometry.isValid() && effectiveState(m_widget->windowState()) == Qt::WindowNoState) + normalGeometry = m_widget->geometry(); + if (normalGeometry.isValid()) + tle->normalGeometry = normalGeometry; +} + void QWidgetWindow::handleMoveEvent(QMoveEvent *event) { updateGeometry(); @@ -692,8 +711,6 @@ void QWidgetWindow::handleExposeEvent(QExposeEvent *event) } } -Qt::WindowState effectiveState(Qt::WindowStates state); - void QWidgetWindow::handleWindowStateChangedEvent(QWindowStateChangeEvent *event) { // QWindow does currently not know 'active'. @@ -712,16 +729,12 @@ void QWidgetWindow::handleWindowStateChangedEvent(QWindowStateChangeEvent *event widgetState |= Qt::WindowMinimized; break; case Qt::WindowMaximized: - if (effectiveState(widgetState) == Qt::WindowNoState) - if (QTLWExtra *tle = m_widget->d_func()->maybeTopData()) - tle->normalGeometry = m_widget->geometry(); + updateNormalGeometry(); widgetState |= Qt::WindowMaximized; widgetState &= ~(Qt::WindowMinimized | Qt::WindowFullScreen); break; case Qt::WindowFullScreen: - if (effectiveState(widgetState) == Qt::WindowNoState) - if (QTLWExtra *tle = m_widget->d_func()->maybeTopData()) - tle->normalGeometry = m_widget->geometry(); + updateNormalGeometry(); widgetState |= Qt::WindowFullScreen; widgetState &= ~(Qt::WindowMinimized); break; diff --git a/src/widgets/kernel/qwidgetwindow_qpa_p.h b/src/widgets/kernel/qwidgetwindow_qpa_p.h index ffde44dd27..8d6f14a669 100644 --- a/src/widgets/kernel/qwidgetwindow_qpa_p.h +++ b/src/widgets/kernel/qwidgetwindow_qpa_p.h @@ -104,6 +104,7 @@ private slots: private: void updateGeometry(); + void updateNormalGeometry(); enum FocusWidgets { FirstFocusWidget, diff --git a/tests/auto/corelib/codecs/utf8/tst_utf8.cpp b/tests/auto/corelib/codecs/utf8/tst_utf8.cpp index e18f6f73b9..b00fd0dfd4 100644 --- a/tests/auto/corelib/codecs/utf8/tst_utf8.cpp +++ b/tests/auto/corelib/codecs/utf8/tst_utf8.cpp @@ -53,7 +53,11 @@ public: // test data: QTextCodec *codec; QString (*from8BitPtr)(const char *, int); +#ifdef Q_COMPILER_REF_QUALIFIERS + QByteArray (QString:: *to8Bit)() const &; +#else QByteArray (QString:: *to8Bit)() const; +#endif inline QString from8Bit(const QByteArray &ba) { return from8BitPtr(ba.constData(), ba.length()); } diff --git a/tests/auto/corelib/io/qloggingcategory/tst_qloggingcategory.cpp b/tests/auto/corelib/io/qloggingcategory/tst_qloggingcategory.cpp index 26f10385b3..47a5d6044e 100644 --- a/tests/auto/corelib/io/qloggingcategory/tst_qloggingcategory.cpp +++ b/tests/auto/corelib/io/qloggingcategory/tst_qloggingcategory.cpp @@ -271,8 +271,8 @@ private slots: QCOMPARE(defaultCategory.isEnabled(QtCriticalMsg), true); QLoggingCategory customCategory("custom"); - QCOMPARE(customCategory.isDebugEnabled(), false); - QCOMPARE(customCategory.isEnabled(QtDebugMsg), false); + QCOMPARE(customCategory.isDebugEnabled(), true); + QCOMPARE(customCategory.isEnabled(QtDebugMsg), true); QCOMPARE(customCategory.isWarningEnabled(), true); QCOMPARE(customCategory.isEnabled(QtWarningMsg), true); QCOMPARE(customCategory.isCriticalEnabled(), true); @@ -309,7 +309,7 @@ private slots: QLoggingCategory cat("custom"); QCOMPARE(customCategoryFilterArgs, QStringList() << "custom"); - QVERIFY(cat.isDebugEnabled()); + QVERIFY(!cat.isDebugEnabled()); customCategoryFilterArgs.clear(); // install default filter @@ -319,7 +319,7 @@ private slots: QCOMPARE(customCategoryFilterArgs.size(), 0); QVERIFY(QLoggingCategory::defaultCategory()->isDebugEnabled()); - QVERIFY(!cat.isDebugEnabled()); + QVERIFY(cat.isDebugEnabled()); // install default filter currentFilter = @@ -328,7 +328,7 @@ private slots: QCOMPARE(customCategoryFilterArgs.size(), 0); QVERIFY(QLoggingCategory::defaultCategory()->isDebugEnabled()); - QVERIFY(!cat.isDebugEnabled()); + QVERIFY(cat.isDebugEnabled()); } void qDebugMacros() @@ -397,8 +397,12 @@ private slots: QLoggingCategory customCategory("custom"); // Check custom debug logMessage.clear(); + buf = QStringLiteral("custom.debug: Check debug with no filter active"); + qCDebug(customCategory, "Check debug with no filter active"); + QCOMPARE(logMessage, buf); + qCDebug(customCategory) << "Check debug with no filter active"; - QCOMPARE(logMessage, QString()); + QCOMPARE(logMessage, buf); // Check custom warning buf = QStringLiteral("custom.warning: Check warning with no filter active"); @@ -414,16 +418,16 @@ private slots: QLoggingCategory::installFilter(customCategoryFilter); // Check custom debug - buf = QStringLiteral("custom.debug: Check debug with filter active"); + logMessage.clear(); qCDebug(customCategory) << "Check debug with filter active"; - QCOMPARE(logMessage, buf); + QCOMPARE(logMessage, QString()); // Check different macro/category variants buf = QStringLiteral("tst.log.debug: Check debug with no filter active"); qCDebug(TST_LOG) << "Check debug with no filter active"; - QCOMPARE(logMessage, buf); + QCOMPARE(logMessage, QString()); qCDebug(TST_LOG, "Check debug with no filter active"); - QCOMPARE(logMessage, buf); + QCOMPARE(logMessage, QString()); buf = QStringLiteral("tst.log.warning: Check warning with no filter active"); qCWarning(TST_LOG) << "Check warning with no filter active"; QCOMPARE(logMessage, buf); @@ -441,8 +445,9 @@ private slots: // Check custom debug logMessage.clear(); + buf = QStringLiteral("custom.debug: Check debug with no filter active"); qCDebug(customCategory) << "Check debug with no filter active"; - QCOMPARE(logMessage, QString()); + QCOMPARE(logMessage, buf); } void checkLegacyMessageLogger() @@ -477,11 +482,11 @@ private slots: QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); // Check category debug - logMessage = "should not change"; - buf = logMessage; + buf = QStringLiteral("tst.log.debug: Check category Debug with no log active"); qCDebug(TST_LOG) << "Check category Debug with no log active"; QCOMPARE(logMessage, buf); + // Check default warning buf = QStringLiteral("tst.log.warning: Check category Warning with no log active"); qCWarning(TST_LOG) << "Check category Warning with no log active"; @@ -763,8 +768,7 @@ private slots: { // "" -> custom category QLoggingCategory mycategoryobject1(""); - logMessage = "no change"; - QString buf = QStringLiteral("no change"); + QString buf = QStringLiteral(".debug: My Category Object"); qCDebug(mycategoryobject1) << "My Category Object"; QCOMPARE(cleanLogLine(logMessage), cleanLogLine(buf)); diff --git a/tests/auto/corelib/tools/qstring/tst_qstring.cpp b/tests/auto/corelib/tools/qstring/tst_qstring.cpp index b201028aad..629a095f9d 100644 --- a/tests/auto/corelib/tools/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/tools/qstring/tst_qstring.cpp @@ -223,6 +223,8 @@ private slots: void split_regexp(); void fromUtf16_data(); void fromUtf16(); + void fromUtf16_char16_data(); + void fromUtf16_char16(); void latin1String(); void nanAndInf(); void compare_data(); @@ -3968,14 +3970,15 @@ void tst_QString::fromAscii() void tst_QString::fromUcs4() { + const uint *null = 0; QString s; - s = QString::fromUcs4( 0 ); + s = QString::fromUcs4( null ); QVERIFY( s.isNull() ); QCOMPARE( s.size(), 0 ); - s = QString::fromUcs4( 0, 0 ); + s = QString::fromUcs4( null, 0 ); QVERIFY( s.isNull() ); QCOMPARE( s.size(), 0 ); - s = QString::fromUcs4( 0, 5 ); + s = QString::fromUcs4( null, 5 ); QVERIFY( s.isNull() ); QCOMPARE( s.size(), 0 ); @@ -3996,20 +3999,98 @@ void tst_QString::fromUcs4() s = QString::fromUcs4( &smp, 1 ); QVERIFY( !s.isNull() ); QCOMPARE( s.size(), 2 ); + +#ifdef Q_COMPILER_UNICODE_STRINGS + static const char32_t str1[] = U"Hello Unicode World"; + s = QString::fromUcs4(str1, sizeof(str1) / sizeof(str1[0]) - 1); + QCOMPARE(s, QString("Hello Unicode World")); + + s = QString::fromUcs4(str1); + QCOMPARE(s, QString("Hello Unicode World")); + + s = QString::fromUcs4(str1, 5); + QCOMPARE(s, QString("Hello")); + + s = QString::fromUcs4(U"\u221212\U000020AC\U00010000"); + QCOMPARE(s, QString::fromUtf8("\342\210\222" "12" "\342\202\254" "\360\220\200\200")); +#endif } void tst_QString::toUcs4() { QString s; + QVector<uint> ucs4; QCOMPARE( s.toUcs4().size(), 0 ); - QChar bmp = QLatin1Char('a'); + static const QChar bmp = QLatin1Char('a'); s = QString(&bmp, 1); - QCOMPARE( s.toUcs4().size(), 1 ); + ucs4 = s.toUcs4(); + QCOMPARE( ucs4.size(), 1 ); + QCOMPARE( ucs4.at(0), 0x0061u ); + +#define QSTRING_FROM_QCHARARRAY(x) (QString((x), sizeof(x)/sizeof((x)[0]))) + + static const QChar smp[] = { QChar::highSurrogate(0x10000), QChar::lowSurrogate(0x10000) }; + s = QSTRING_FROM_QCHARARRAY(smp); + ucs4 = s.toUcs4(); + QCOMPARE( ucs4.size(), 1 ); + QCOMPARE( ucs4.at(0), 0x10000u ); + + static const QChar smp2[] = { QChar::highSurrogate(0x10000), QChar::lowSurrogate(0x10000), QChar::highSurrogate(0x10000), QChar::lowSurrogate(0x10000) }; + s = QSTRING_FROM_QCHARARRAY(smp2); + ucs4 = s.toUcs4(); + QCOMPARE( ucs4.size(), 2 ); + QCOMPARE( ucs4.at(0), 0x10000u ); + QCOMPARE( ucs4.at(1), 0x10000u ); + + static const QChar invalid_01[] = { QChar(0xd800) }; + s = QSTRING_FROM_QCHARARRAY(invalid_01); + ucs4 = s.toUcs4(); + QCOMPARE( ucs4.size(), 1 ); + QCOMPARE( ucs4.at(0), 0xFFFDu ); + + static const QChar invalid_02[] = { QChar(0xdc00) }; + s = QSTRING_FROM_QCHARARRAY(invalid_02); + ucs4 = s.toUcs4(); + QCOMPARE( ucs4.size(), 1 ); + QCOMPARE( ucs4.at(0), 0xFFFDu ); + + static const QChar invalid_03[] = { QLatin1Char('a'), QChar(0xd800), QLatin1Char('b') }; + s = QSTRING_FROM_QCHARARRAY(invalid_03); + ucs4 = s.toUcs4(); + QCOMPARE( ucs4.size(), 3 ); + QCOMPARE( ucs4.at(0), 0x0061u ); + QCOMPARE( ucs4.at(1), 0xFFFDu ); + QCOMPARE( ucs4.at(2), 0x0062u ); + + static const QChar invalid_04[] = { QLatin1Char('a'), QChar(0xdc00), QLatin1Char('b') }; + s = QSTRING_FROM_QCHARARRAY(invalid_04); + ucs4 = s.toUcs4(); + QCOMPARE( ucs4.size(), 3 ); + QCOMPARE( ucs4.at(0), 0x0061u ); + QCOMPARE( ucs4.at(1), 0xFFFDu ); + QCOMPARE( ucs4.at(2), 0x0062u ); + + static const QChar invalid_05[] = { QLatin1Char('a'), QChar(0xd800), QChar(0xd800), QLatin1Char('b') }; + s = QSTRING_FROM_QCHARARRAY(invalid_05); + ucs4 = s.toUcs4(); + QCOMPARE( ucs4.size(), 4 ); + QCOMPARE( ucs4.at(0), 0x0061u ); + QCOMPARE( ucs4.at(1), 0xFFFDu ); + QCOMPARE( ucs4.at(2), 0xFFFDu ); + QCOMPARE( ucs4.at(3), 0x0062u ); + + static const QChar invalid_06[] = { QLatin1Char('a'), QChar(0xdc00), QChar(0xdc00), QLatin1Char('b') }; + s = QSTRING_FROM_QCHARARRAY(invalid_06); + ucs4 = s.toUcs4(); + QCOMPARE( ucs4.size(), 4 ); + QCOMPARE( ucs4.at(0), 0x0061u ); + QCOMPARE( ucs4.at(1), 0xFFFDu ); + QCOMPARE( ucs4.at(2), 0xFFFDu ); + QCOMPARE( ucs4.at(3), 0x0062u ); + +#undef QSTRING_FROM_QCHARARRAY - QChar smp[] = { QChar::highSurrogate(0x10000), QChar::lowSurrogate(0x10000) }; - s = QString(smp, 2); - QCOMPARE( s.toUcs4().size(), 1 ); } void tst_QString::arg() @@ -4991,6 +5072,25 @@ void tst_QString::fromUtf16() QCOMPARE(QString::fromUtf16(ucs2.utf16(), len), res); } +void tst_QString::fromUtf16_char16_data() +{ +#ifdef Q_COMPILER_UNICODE_STRINGS + fromUtf16_data(); +#else + QSKIP("Compiler does not support C++11 unicode strings"); +#endif +} + +void tst_QString::fromUtf16_char16() +{ +#ifdef Q_COMPILER_UNICODE_STRINGS + QFETCH(QString, ucs2); + QFETCH(QString, res); + QFETCH(int, len); + + QCOMPARE(QString::fromUtf16(reinterpret_cast<const char16_t *>(ucs2.utf16()), len), res); +#endif +} void tst_QString::latin1String() { diff --git a/tests/auto/corelib/tools/qstringiterator/qstringiterator.pro b/tests/auto/corelib/tools/qstringiterator/qstringiterator.pro new file mode 100644 index 0000000000..e5e625d520 --- /dev/null +++ b/tests/auto/corelib/tools/qstringiterator/qstringiterator.pro @@ -0,0 +1,5 @@ +CONFIG += testcase parallel_test +TARGET = tst_qstringiterator +QT = core core-private testlib +SOURCES = tst_qstringiterator.cpp + diff --git a/tests/auto/corelib/tools/qstringiterator/tst_qstringiterator.cpp b/tests/auto/corelib/tools/qstringiterator/tst_qstringiterator.cpp new file mode 100644 index 0000000000..d06d052676 --- /dev/null +++ b/tests/auto/corelib/tools/qstringiterator/tst_qstringiterator.cpp @@ -0,0 +1,675 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QtCore/QString> +#include <private/qstringiterator_p.h> + +class tst_QStringIterator : public QObject +{ + Q_OBJECT +private slots: + void sweep_data(); + void sweep(); + + void position(); +}; + +void tst_QStringIterator::sweep_data() +{ + QTest::addColumn<QString>("string"); + QTest::addColumn<bool>("valid"); + QTest::addColumn<int>("count"); + + QTest::newRow("sweep_00") << QString::fromUtf8("", 0) << true << 0; + QTest::newRow("sweep_01") << QString::fromUtf8("a", 1) << true << 1; + QTest::newRow("sweep_02") << QString::fromUtf8("a string", 8) << true << 8; + QTest::newRow("sweep_03") << QString::fromUtf8("\xc3\xa0\xc3\xa8\xc3\xac\xc3\xb2\xc3\xb9", 10) << true << 5; + QTest::newRow("sweep_04") << QString::fromUtf8("\xc3\x9f\xe2\x80\x94\xc2\xa1", 7) << true << 3; + QTest::newRow("sweep_05") << QString::fromUtf8("\xe6\xb0\xb4\xe6\xb0\xb5\xe6\xb0\xb6\xe6\xb0\xb7\xe6\xb0\xb8\xe6\xb0\xb9", 18) << true << 6; + QTest::newRow("sweep_06") << QString::fromUtf8("\xf0\x9f\x98\x81\xf0\x9f\x98\x82\x61\x62\x63\xf0\x9f\x98\x83\xc4\x91\xc3\xa8\xef\xac\x80\xf0\x9f\x98\x84\xf0\x9f\x98\x85", 30) << true << 11; + QTest::newRow("sweep_07") << QString::fromUtf8("\xf0\x9f\x82\xaa\xf0\x9f\x82\xab\xf0\x9f\x82\xad\xf0\x9f\x82\xae\xf0\x9f\x82\xa1\x20\x52\x4f\x59\x41\x4c\x20\x46\x4c\x55\x53\x48\x20\x4f\x46\x20\x53\x50\x41\x44\x45\x53", 42) << true << 27; + QTest::newRow("sweep_08") << QString::fromUtf8("abc\0def", 7) << true << 7; + QTest::newRow("sweep_09") << QString::fromUtf8("\xc3\xa0\xce\xb2\xc3\xa7\xf0\x9f\x80\xb9\xf0\x9f\x80\xb8\x00\xf0\x9f\x80\xb1\x00\xf0\x9f\x80\xb3\xf0\x9f\x81\x85\xe1\xb8\x8a\xc4\x99\xc6\x92", 35) << true << 13; + + QTest::newRow("sweep_invalid_00") << QString(QChar(0xd800)) << false << 1; + QTest::newRow("sweep_invalid_01") << QString(QChar(0xdc00)) << false << 1; + QTest::newRow("sweep_invalid_02") << QString(QChar(0xdbff)) << false << 1; + QTest::newRow("sweep_invalid_03") << QString(QChar(0xdfff)) << false << 1; + +#define QSTRING_FROM_QCHARARRAY(x) (QString((x), sizeof(x)/sizeof((x)[0]))) + + static const QChar invalid_04[] = { + QLatin1Char('i'), QLatin1Char('n'), QLatin1Char('v'), + QLatin1Char('a'), QLatin1Char('l'), QLatin1Char('i'), + QLatin1Char('d'), QChar(0xd800) + }; + QTest::newRow("sweep_invalid_04") << QSTRING_FROM_QCHARARRAY(invalid_04) << false << 8; + + static const QChar invalid_05[] = { + QLatin1Char('i'), QLatin1Char('n'), QLatin1Char('v'), + QLatin1Char('a'), QLatin1Char('l'), QLatin1Char('i'), + QLatin1Char('d'), QChar(0xd800), QLatin1Char('x') + }; + QTest::newRow("sweep_invalid_05") << QSTRING_FROM_QCHARARRAY(invalid_05) << false << 9; + + static const QChar invalid_06[] = { + QLatin1Char('i'), QLatin1Char('n'), QLatin1Char('v'), + QLatin1Char('a'), QLatin1Char('l'), QLatin1Char('i'), + QLatin1Char('d'), QChar(0xdc00) + }; + QTest::newRow("sweep_invalid_06") << QSTRING_FROM_QCHARARRAY(invalid_06) << false << 8; + + static const QChar invalid_07[] = { + QLatin1Char('i'), QLatin1Char('n'), QLatin1Char('v'), + QLatin1Char('a'), QLatin1Char('l'), QLatin1Char('i'), + QLatin1Char('d'), QChar(0xdc00), QLatin1Char('x') + }; + QTest::newRow("sweep_invalid_07") << QSTRING_FROM_QCHARARRAY(invalid_07) << false << 9; + + static const QChar invalid_08[] = { + QChar(0xd800), + QLatin1Char('i'), QLatin1Char('n'), QLatin1Char('v'), + QLatin1Char('a'), QLatin1Char('l'), QLatin1Char('i'), + QLatin1Char('d') + }; + QTest::newRow("sweep_invalid_08") << QSTRING_FROM_QCHARARRAY(invalid_08) << false << 8; + + static const QChar invalid_09[] = { + QChar(0xdc00), + QLatin1Char('i'), QLatin1Char('n'), QLatin1Char('v'), + QLatin1Char('a'), QLatin1Char('l'), QLatin1Char('i'), + QLatin1Char('d') + }; + QTest::newRow("sweep_invalid_09") << QSTRING_FROM_QCHARARRAY(invalid_09) << false << 8; + + static const QChar invalid_10[] = { + QChar(0xd800), QChar(0xd800), + QLatin1Char('i'), QLatin1Char('n'), QLatin1Char('v'), + QLatin1Char('a'), QLatin1Char('l'), QLatin1Char('i'), + QLatin1Char('d') + }; + QTest::newRow("sweep_invalid_10") << QSTRING_FROM_QCHARARRAY(invalid_10) << false << 9; + + static const QChar invalid_11[] = { + QChar(0xdc00), QChar(0xd800), + QLatin1Char('i'), QLatin1Char('n'), QLatin1Char('v'), + QLatin1Char('a'), QLatin1Char('l'), QLatin1Char('i'), + QLatin1Char('d') + }; + QTest::newRow("sweep_invalid_11") << QSTRING_FROM_QCHARARRAY(invalid_11) << false << 9; + + static const QChar invalid_12[] = { + QChar(0xdc00), QChar(0xdc00), + QLatin1Char('i'), QLatin1Char('n'), QLatin1Char('v'), + QLatin1Char('a'), QLatin1Char('l'), QLatin1Char('i'), + QLatin1Char('d') + }; + QTest::newRow("sweep_invalid_12") << QSTRING_FROM_QCHARARRAY(invalid_12) << false << 9; + + static const QChar invalid_13[] = { + QLatin1Char('i'), QLatin1Char('n'), QLatin1Char('v'), + QChar(0xd800), QChar(0xdf00), // U+10300 OLD ITALIC LETTER A + QLatin1Char('a'), QLatin1Char('l'), QLatin1Char('i'), + QLatin1Char('d'), QChar(0xd800) + }; + QTest::newRow("sweep_invalid_13") << QSTRING_FROM_QCHARARRAY(invalid_13) << false << 9; + + static const QChar invalid_14[] = { + QLatin1Char('i'), QLatin1Char('n'), QLatin1Char('v'), + QChar(0xd800), QChar(0xdf00), // U+10300 OLD ITALIC LETTER A + QLatin1Char('a'), QLatin1Char('l'), QLatin1Char('i'), + QLatin1Char('d'), QChar(0xd800), QLatin1Char('x') + }; + QTest::newRow("sweep_invalid_14") << QSTRING_FROM_QCHARARRAY(invalid_14) << false << 10; + + static const QChar invalid_15[] = { + QLatin1Char('i'), QLatin1Char('n'), QLatin1Char('v'), + QChar(0xd800), QChar(0xdf00), // U+10300 OLD ITALIC LETTER A + QLatin1Char('a'), QLatin1Char('l'), QLatin1Char('i'), + QLatin1Char('d'), QChar(0xdc00) + }; + QTest::newRow("sweep_invalid_15") << QSTRING_FROM_QCHARARRAY(invalid_15) << false << 9; + + static const QChar invalid_16[] = { + QLatin1Char('i'), QLatin1Char('n'), QLatin1Char('v'), + QChar(0xd800), QChar(0xdf00), // U+10300 OLD ITALIC LETTER A + QLatin1Char('a'), QLatin1Char('l'), QLatin1Char('i'), + QLatin1Char('d'), QChar(0xdc00), QLatin1Char('x') + }; + QTest::newRow("sweep_invalid_16") << QSTRING_FROM_QCHARARRAY(invalid_16) << false << 10; + + static const QChar invalid_17[] = { + QChar(0xd800), + QLatin1Char('i'), QLatin1Char('n'), QLatin1Char('v'), + QChar(0xd800), QChar(0xdf00), // U+10300 OLD ITALIC LETTER A + QLatin1Char('a'), QLatin1Char('l'), QLatin1Char('i'), + QLatin1Char('d') + }; + QTest::newRow("sweep_invalid_17") << QSTRING_FROM_QCHARARRAY(invalid_17) << false << 9; + + static const QChar invalid_18[] = { + QChar(0xdc00), + QLatin1Char('i'), QLatin1Char('n'), QLatin1Char('v'), + QChar(0xd800), QChar(0xdf00), // U+10300 OLD ITALIC LETTER A + QLatin1Char('a'), QLatin1Char('l'), QLatin1Char('i'), + QLatin1Char('d') + }; + QTest::newRow("sweep_invalid_18") << QSTRING_FROM_QCHARARRAY(invalid_18) << false << 9; + +#undef QSTRING_FROM_QCHARARRAY +} + +void tst_QStringIterator::sweep() +{ + QFETCH(QString, string); + QFETCH(bool, valid); + + QStringIterator i(string); + int count = 0; + QString rebuiltString; + + while (i.hasNext()) { + const uint peekedCodePoint = i.peekNext(~0u); + const uint codePoint = i.next(~0u); + + QVERIFY(peekedCodePoint == codePoint); + + if (codePoint == ~0u) + rebuiltString += *(i.position() - 1); + else + rebuiltString += QString::fromUcs4(&codePoint, 1); + + ++count; + } + + QTEST(count, "count"); + QTEST(rebuiltString, "string"); + rebuiltString.clear(); + + while (i.hasPrevious()) { + const uint peekedCodePoint = i.peekPrevious(~0u); + const uint codePoint = i.previous(~0u); + + QVERIFY(peekedCodePoint == codePoint); + + --count; + } + + QCOMPARE(count, 0); + + while (i.hasNext()) { + i.advance(); + ++count; + } + + QTEST(count, "count"); + + while (i.hasPrevious()) { + i.recede(); + --count; + } + + QCOMPARE(count, 0); + + if (valid) { + while (i.hasNext()) { + const uint peekedCodePoint = i.peekNextUnchecked(); + const uint codePoint = i.nextUnchecked(); + + QVERIFY(peekedCodePoint == codePoint); + QVERIFY(codePoint <= 0x10FFFFu); + rebuiltString += QString::fromUcs4(&codePoint, 1); + ++count; + } + + QTEST(count, "count"); + QTEST(rebuiltString, "string"); + + while (i.hasPrevious()) { + const uint peekedCodePoint = i.peekPreviousUnchecked(); + const uint codePoint = i.previousUnchecked(); + + QVERIFY(peekedCodePoint == codePoint); + + --count; + } + + QCOMPARE(count, 0); + + while (i.hasNext()) { + i.advanceUnchecked(); + ++count; + } + + QTEST(count, "count"); + + while (i.hasPrevious()) { + i.recedeUnchecked(); + --count; + } + + QCOMPARE(count, 0); + } +} + +void tst_QStringIterator::position() +{ + static const QChar stringData[] = + { + // codeunit count: 0 + QLatin1Char('a'), QLatin1Char('b'), QLatin1Char('c'), + // codeunit count: 3 + QChar(0x00A9), // U+00A9 COPYRIGHT SIGN + // codeunit count: 4 + QChar(0x00AE), // U+00AE REGISTERED SIGN + // codeunit count: 5 + QLatin1Char('d'), QLatin1Char('e'), QLatin1Char('f'), + // codeunit count: 8 + QLatin1Char('\0'), + // codeunit count: 9 + QLatin1Char('g'), QLatin1Char('h'), QLatin1Char('i'), + // codeunit count: 12 + QChar(0xD834), QChar(0xDD1E), // U+1D11E MUSICAL SYMBOL G CLEF + // codeunit count: 14 + QChar(0xD834), QChar(0xDD21), // U+1D121 MUSICAL SYMBOL C CLEF + // codeunit count: 16 + QLatin1Char('j'), + // codeunit count: 17 + QChar(0xD800), // stray high surrogate + // codeunit count: 18 + QLatin1Char('k'), + // codeunit count: 19 + QChar(0xDC00), // stray low surrogate + // codeunit count: 20 + QLatin1Char('l'), + // codeunit count: 21 + QChar(0xD800), QChar(0xD800), // two high surrogates + // codeunit count: 23 + QLatin1Char('m'), + // codeunit count: 24 + QChar(0xDC00), QChar(0xDC00), // two low surrogates + // codeunit count: 26 + QLatin1Char('n'), + // codeunit count: 27 + QChar(0xD800), QChar(0xD800), QChar(0xDC00), // stray high surrogate followed by valid pair + // codeunit count: 30 + QLatin1Char('o'), + // codeunit count: 31 + QChar(0xDC00), QChar(0xD800), QChar(0xDC00), // stray low surrogate followed by valid pair + // codeunit count: 34 + QLatin1Char('p') + // codeunit count: 35 + }; + + const QString string(stringData, sizeof(stringData) / sizeof(stringData[0])); + QStringIterator i(string); + + QCOMPARE(i.position(), string.constBegin()); + QVERIFY(i.hasNext()); + QVERIFY(!i.hasPrevious()); + + i.setPosition(string.constEnd()); + QCOMPARE(i.position(), string.constEnd()); + QVERIFY(!i.hasNext()); + QVERIFY(i.hasPrevious()); + +#define QCHAR_UNICODE_VALUE(x) ((uint)(QChar(x).unicode())) + + const QString::const_iterator begin = string.constBegin(); + i.setPosition(begin); + QCOMPARE(i.position(), begin); + QCOMPARE(i.peekNext(), QCHAR_UNICODE_VALUE(QLatin1Char('a'))); + QCOMPARE(i.next(), QCHAR_UNICODE_VALUE(QLatin1Char('a'))); + + QCOMPARE(i.position(), begin + 1); + + i.setPosition(begin + 2); + QCOMPARE(i.position(), begin + 2); + QCOMPARE(i.peekNext(), QCHAR_UNICODE_VALUE(QLatin1Char('c'))); + QCOMPARE(i.next(), QCHAR_UNICODE_VALUE(QLatin1Char('c'))); + + QCOMPARE(i.position(), begin + 3); + QCOMPARE(i.peekNext(), QCHAR_UNICODE_VALUE(0x00A9)); + QCOMPARE(i.next(), QCHAR_UNICODE_VALUE(0x00A9)); + + QCOMPARE(i.position(), begin + 4); + QCOMPARE(i.peekNext(), QCHAR_UNICODE_VALUE(0x00AE)); + QCOMPARE(i.next(), QCHAR_UNICODE_VALUE(0x00AE)); + + QCOMPARE(i.position(), begin + 5); + QCOMPARE(i.peekPrevious(), QCHAR_UNICODE_VALUE(0x00AE)); + QCOMPARE(i.previous(), QCHAR_UNICODE_VALUE(0x00AE)); + + QCOMPARE(i.position(), begin + 4); + QCOMPARE(i.peekPrevious(), QCHAR_UNICODE_VALUE(0x00A9)); + QCOMPARE(i.previous(), QCHAR_UNICODE_VALUE(0x00A9)); + + QCOMPARE(i.position(), begin + 3); + + i.setPosition(begin + 8); + QCOMPARE(i.position(), begin + 8); + QCOMPARE(i.peekNext(), QCHAR_UNICODE_VALUE(QLatin1Char('\0'))); + QCOMPARE(i.next(), QCHAR_UNICODE_VALUE(QLatin1Char('\0'))); + + QCOMPARE(i.position(), begin + 9); + QCOMPARE(i.peekNext(), QCHAR_UNICODE_VALUE(QLatin1Char('g'))); + QCOMPARE(i.next(), QCHAR_UNICODE_VALUE(QLatin1Char('g'))); + + QCOMPARE(i.position(), begin + 10); + QCOMPARE(i.peekPrevious(), QCHAR_UNICODE_VALUE(QLatin1Char('g'))); + QCOMPARE(i.previous(), QCHAR_UNICODE_VALUE(QLatin1Char('g'))); + + QCOMPARE(i.position(), begin + 9); + QCOMPARE(i.peekPrevious(), QCHAR_UNICODE_VALUE(QLatin1Char('\0'))); + QCOMPARE(i.previous(), QCHAR_UNICODE_VALUE(QLatin1Char('\0'))); + + QCOMPARE(i.position(), begin + 8); + QCOMPARE(i.peekPrevious(), QCHAR_UNICODE_VALUE(QLatin1Char('f'))); + QCOMPARE(i.previous(), QCHAR_UNICODE_VALUE(QLatin1Char('f'))); + + QCOMPARE(i.position(), begin + 7); + + i.advanceUnchecked(); + i.advanceUnchecked(); + i.advanceUnchecked(); + i.advanceUnchecked(); + i.advanceUnchecked(); + + QCOMPARE(i.position(), begin + 12); + QCOMPARE(i.peekNext(), 0x1D11Eu); + QCOMPARE(i.next(), 0x1D11Eu); + + QCOMPARE(i.position(), begin + 14); + QCOMPARE(i.peekNext(), 0x1D121u); + QCOMPARE(i.next(), 0x1D121u); + + QCOMPARE(i.position(), begin + 16); + QCOMPARE(i.peekNext(), QCHAR_UNICODE_VALUE(QLatin1Char('j'))); + QCOMPARE(i.next(), QCHAR_UNICODE_VALUE(QLatin1Char('j'))); + + QCOMPARE(i.position(), begin + 17); + QCOMPARE(i.peekPrevious(), QCHAR_UNICODE_VALUE(QLatin1Char('j'))); + QCOMPARE(i.previous(), QCHAR_UNICODE_VALUE(QLatin1Char('j'))); + + QCOMPARE(i.position(), begin + 16); + QCOMPARE(i.peekPrevious(), 0x1D121u); + QCOMPARE(i.previous(), 0x1D121u); + + QCOMPARE(i.position(), begin + 14); + QCOMPARE(i.peekPrevious(), 0x1D11Eu); + QCOMPARE(i.previous(), 0x1D11Eu); + + QCOMPARE(i.position(), begin + 12); + + + i.setPosition(begin + 13); + QCOMPARE(i.position(), begin + 13); + + QCOMPARE(i.peekNext(), 0xFFFDu); + QCOMPARE(i.next(), 0xFFFDu); + + QCOMPARE(i.position(), begin + 14); + QCOMPARE(i.peekNext(), 0x1D121u); + QCOMPARE(i.next(), 0x1D121u); + + QCOMPARE(i.position(), begin + 16); + + + i.setPosition(begin + 15); + QCOMPARE(i.position(), begin + 15); + + QCOMPARE(i.peekPrevious(), 0xFFFDu); + QCOMPARE(i.previous(), 0xFFFDu); + + QCOMPARE(i.position(), begin + 14); + QCOMPARE(i.peekPrevious(), 0x1D11Eu); + QCOMPARE(i.previous(), 0x1D11Eu); + + QCOMPARE(i.position(), begin + 12); + + i.advanceUnchecked(); + i.advanceUnchecked(); + + QCOMPARE(i.position(), begin + 16); + QCOMPARE(i.peekNext(), QCHAR_UNICODE_VALUE(QLatin1Char('j'))); + QCOMPARE(i.next(), QCHAR_UNICODE_VALUE(QLatin1Char('j'))); + + QCOMPARE(i.position(), begin + 17); + QCOMPARE(i.peekNext(), 0xFFFDu); + QCOMPARE(i.next(), 0xFFFDu); + + QCOMPARE(i.position(), begin + 18); + QCOMPARE(i.peekNext(), QCHAR_UNICODE_VALUE(QLatin1Char('k'))); + QCOMPARE(i.next(), QCHAR_UNICODE_VALUE(QLatin1Char('k'))); + + QCOMPARE(i.position(), begin + 19); + QCOMPARE(i.peekNext(), 0xFFFDu); + QCOMPARE(i.next(), 0xFFFDu); + + QCOMPARE(i.position(), begin + 20); + QCOMPARE(i.peekNext(), QCHAR_UNICODE_VALUE(QLatin1Char('l'))); + QCOMPARE(i.next(), QCHAR_UNICODE_VALUE(QLatin1Char('l'))); + + QCOMPARE(i.position(), begin + 21); + QCOMPARE(i.peekNext(), 0xFFFDu); + QCOMPARE(i.next(), 0xFFFDu); + + QCOMPARE(i.position(), begin + 22); + QCOMPARE(i.peekNext(), 0xFFFDu); + QCOMPARE(i.next(), 0xFFFDu); + + QCOMPARE(i.position(), begin + 23); + QCOMPARE(i.peekNext(), QCHAR_UNICODE_VALUE(QLatin1Char('m'))); + QCOMPARE(i.next(), QCHAR_UNICODE_VALUE(QLatin1Char('m'))); + + QCOMPARE(i.position(), begin + 24); + QCOMPARE(i.peekNext(), 0xFFFDu); + QCOMPARE(i.next(), 0xFFFDu); + + QCOMPARE(i.position(), begin + 25); + QCOMPARE(i.peekNext(), 0xFFFDu); + QCOMPARE(i.next(), 0xFFFDu); + + QCOMPARE(i.position(), begin + 26); + QCOMPARE(i.peekNext(), QCHAR_UNICODE_VALUE(QLatin1Char('n'))); + QCOMPARE(i.next(), QCHAR_UNICODE_VALUE(QLatin1Char('n'))); + + QCOMPARE(i.position(), begin + 27); + QCOMPARE(i.peekNext(), 0xFFFDu); + QCOMPARE(i.next(), 0xFFFDu); + + QCOMPARE(i.position(), begin + 28); + QCOMPARE(i.peekNext(), 0x10000u); + QCOMPARE(i.next(), 0x10000u); + + QCOMPARE(i.position(), begin + 30); + QCOMPARE(i.peekNext(), QCHAR_UNICODE_VALUE(QLatin1Char('o'))); + QCOMPARE(i.next(), QCHAR_UNICODE_VALUE(QLatin1Char('o'))); + + QCOMPARE(i.position(), begin + 31); + QCOMPARE(i.peekNext(), 0xFFFDu); + QCOMPARE(i.next(), 0xFFFDu); + + QCOMPARE(i.position(), begin + 32); + QCOMPARE(i.peekNext(), 0x10000u); + QCOMPARE(i.next(), 0x10000u); + + QCOMPARE(i.position(), begin + 34); + QCOMPARE(i.peekNext(), QCHAR_UNICODE_VALUE(QLatin1Char('p'))); + QCOMPARE(i.next(), QCHAR_UNICODE_VALUE(QLatin1Char('p'))); + + QVERIFY(!i.hasNext()); + + QCOMPARE(i.position(), begin + 35); + QCOMPARE(i.peekPrevious(), QCHAR_UNICODE_VALUE(QLatin1Char('p'))); + QCOMPARE(i.previous(), QCHAR_UNICODE_VALUE(QLatin1Char('p'))); + + QCOMPARE(i.position(), begin + 34); + QCOMPARE(i.peekPrevious(), 0x10000u); + QCOMPARE(i.previous(), 0x10000u); + + QCOMPARE(i.position(), begin + 32); + QCOMPARE(i.peekPrevious(), 0xFFFDu); + QCOMPARE(i.previous(), 0xFFFDu); + + QCOMPARE(i.position(), begin + 31); + QCOMPARE(i.peekPrevious(), QCHAR_UNICODE_VALUE(QLatin1Char('o'))); + QCOMPARE(i.previous(), QCHAR_UNICODE_VALUE(QLatin1Char('o'))); + + QCOMPARE(i.position(), begin + 30); + QCOMPARE(i.peekPrevious(), 0x10000u); + QCOMPARE(i.previous(), 0x10000u); + + QCOMPARE(i.position(), begin + 28); + QCOMPARE(i.peekPrevious(), 0xFFFDu); + QCOMPARE(i.previous(), 0xFFFDu); + + QCOMPARE(i.position(), begin + 27); + QCOMPARE(i.peekPrevious(), QCHAR_UNICODE_VALUE(QLatin1Char('n'))); + QCOMPARE(i.previous(), QCHAR_UNICODE_VALUE(QLatin1Char('n'))); + + QCOMPARE(i.position(), begin + 26); + QCOMPARE(i.peekPrevious(), 0xFFFDu); + QCOMPARE(i.previous(), 0xFFFDu); + + QCOMPARE(i.position(), begin + 25); + QCOMPARE(i.peekPrevious(), 0xFFFDu); + QCOMPARE(i.previous(), 0xFFFDu); + + QCOMPARE(i.position(), begin + 24); + QCOMPARE(i.peekPrevious(), QCHAR_UNICODE_VALUE(QLatin1Char('m'))); + QCOMPARE(i.previous(), QCHAR_UNICODE_VALUE(QLatin1Char('m'))); + + QCOMPARE(i.position(), begin + 23); + QCOMPARE(i.peekPrevious(), 0xFFFDu); + QCOMPARE(i.previous(), 0xFFFDu); + + QCOMPARE(i.position(), begin + 22); + QCOMPARE(i.peekPrevious(), 0xFFFDu); + QCOMPARE(i.previous(), 0xFFFDu); + + QCOMPARE(i.position(), begin + 21); + QCOMPARE(i.peekPrevious(), QCHAR_UNICODE_VALUE(QLatin1Char('l'))); + QCOMPARE(i.previous(), QCHAR_UNICODE_VALUE(QLatin1Char('l'))); + + QCOMPARE(i.position(), begin + 20); + QCOMPARE(i.peekPrevious(), 0xFFFDu); + QCOMPARE(i.previous(), 0xFFFDu); + + QCOMPARE(i.position(), begin + 19); + QCOMPARE(i.peekPrevious(), QCHAR_UNICODE_VALUE(QLatin1Char('k'))); + QCOMPARE(i.previous(), QCHAR_UNICODE_VALUE(QLatin1Char('k'))); + + QCOMPARE(i.position(), begin + 18); + QCOMPARE(i.peekPrevious(), 0xFFFDu); + QCOMPARE(i.previous(), 0xFFFDu); + + QCOMPARE(i.position(), begin + 17); + QCOMPARE(i.peekPrevious(), QCHAR_UNICODE_VALUE(QLatin1Char('j'))); + QCOMPARE(i.previous(), QCHAR_UNICODE_VALUE(QLatin1Char('j'))); + + i.setPosition(begin + 29); + QCOMPARE(i.position(), begin + 29); + QCOMPARE(i.peekNext(), 0xFFFDu); + QCOMPARE(i.next(), 0xFFFDu); + + QCOMPARE(i.position(), begin + 30); + QCOMPARE(i.peekNext(), QCHAR_UNICODE_VALUE(QLatin1Char('o'))); + QCOMPARE(i.next(), QCHAR_UNICODE_VALUE(QLatin1Char('o'))); + + QCOMPARE(i.position(), begin + 31); + QCOMPARE(i.peekPrevious(), QCHAR_UNICODE_VALUE(QLatin1Char('o'))); + QCOMPARE(i.previous(), QCHAR_UNICODE_VALUE(QLatin1Char('o'))); + + QCOMPARE(i.position(), begin + 30); + QCOMPARE(i.peekPrevious(), 0x10000u); + QCOMPARE(i.previous(), 0x10000u); + + QCOMPARE(i.position(), begin + 28); + + i.setPosition(begin + 33); + QCOMPARE(i.position(), begin + 33); + QCOMPARE(i.peekNext(), 0xFFFDu); + QCOMPARE(i.next(), 0xFFFDu); + + QCOMPARE(i.position(), begin + 34); + QCOMPARE(i.peekNext(), QCHAR_UNICODE_VALUE(QLatin1Char('p'))); + QCOMPARE(i.next(), QCHAR_UNICODE_VALUE(QLatin1Char('p'))); + + QCOMPARE(i.position(), begin + 35); + QCOMPARE(i.peekPrevious(), QCHAR_UNICODE_VALUE(QLatin1Char('p'))); + QCOMPARE(i.previous(), QCHAR_UNICODE_VALUE(QLatin1Char('p'))); + + QCOMPARE(i.position(), begin + 34); + QCOMPARE(i.peekPrevious(), 0x10000u); + QCOMPARE(i.previous(), 0x10000u); + + QCOMPARE(i.position(), begin + 32); + + + i.setPosition(begin + 16); + QCOMPARE(i.position(), begin + 16); + + i.recedeUnchecked(); + i.recedeUnchecked(); + QCOMPARE(i.position(), begin + 12); + + i.recedeUnchecked(); + i.recedeUnchecked(); + i.recedeUnchecked(); + i.recedeUnchecked(); + QCOMPARE(i.position(), begin + 8); + + i.recedeUnchecked(); + i.recedeUnchecked(); + i.recedeUnchecked(); + i.recedeUnchecked(); + i.recedeUnchecked(); + i.recedeUnchecked(); + QCOMPARE(i.position(), begin + 2); + +#undef QCHAR_UNICODE_VALUE +} + +QTEST_APPLESS_MAIN(tst_QStringIterator) + +#include "tst_qstringiterator.moc" diff --git a/tests/auto/corelib/tools/tools.pro b/tests/auto/corelib/tools/tools.pro index 286afdfd18..bf2f222769 100644 --- a/tests/auto/corelib/tools/tools.pro +++ b/tests/auto/corelib/tools/tools.pro @@ -44,6 +44,7 @@ SUBDIRS=\ qstring \ qstring_no_cast_from_bytearray \ qstringbuilder \ + qstringiterator \ qstringlist \ qstringmatcher \ qstringref \ diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index 38b629cad7..ecbe774f22 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -4816,73 +4816,68 @@ static inline QByteArray msgRgbMismatch(unsigned actual, unsigned expected) QByteArrayLiteral(" != 0x") + QByteArray::number(expected, 16); } -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) -QT_BEGIN_NAMESPACE -extern Q_GUI_EXPORT QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat = 0); -QT_END_NAMESPACE - -// grabs the window *without including any overlapping windows* -static QPixmap grabWindow(QWindow *window, int x, int y, int width, int height) -{ - const HWND hwnd = (HWND)window->winId(); - - // Create and setup bitmap - const HDC displayDc = ::GetDC(0); - const HDC bitmapDc = ::CreateCompatibleDC(displayDc); - const HBITMAP bitmap = ::CreateCompatibleBitmap(displayDc, width, height); - const HGDIOBJ oldBitmap = ::SelectObject(bitmapDc, bitmap); - - // copy data - const HDC windowDc = ::GetDC(hwnd); - ::BitBlt(bitmapDc, 0, 0, width, height, windowDc, x, y, SRCCOPY); - - // clean up all but bitmap - ::ReleaseDC(hwnd, windowDc); - ::SelectObject(bitmapDc, oldBitmap); - ::DeleteDC(bitmapDc); - - const QPixmap pixmap = qt_pixmapFromWinHBITMAP(bitmap); - - ::DeleteObject(bitmap); - ::ReleaseDC(0, displayDc); - - return pixmap; -} -#else -// fallback for other platforms. static QPixmap grabWindow(QWindow *window, int x, int y, int width, int height) { QScreen *screen = window->screen(); return screen ? screen->grabWindow(window->winId(), x, y, width, height) : QPixmap(); } -#endif //defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) - -#define VERIFY_COLOR(child, region, color) do { \ - const QRegion r = QRegion(region); \ - QWindow *window = child.window()->windowHandle(); \ - Q_ASSERT(window); \ - const QPoint offset = child.mapTo(child.window(), QPoint(0,0)); \ - for (int i = 0; i < r.rects().size(); ++i) { \ - const QRect rect = r.rects().at(i).translated(offset); \ - for (int t = 0; t < 5; t++) { \ - const QPixmap pixmap = grabWindow(window, \ - rect.left(), rect.top(), \ - rect.width(), rect.height()); \ - QCOMPARE(pixmap.size(), rect.size()); \ - QPixmap expectedPixmap(pixmap); /* ensure equal formats */ \ - expectedPixmap.detach(); \ - expectedPixmap.fill(color); \ - QImage image = pixmap.toImage(); \ - uint alphaCorrection = image.format() == QImage::Format_RGB32 ? 0xff000000 : 0; \ - uint firstPixel = image.pixel(0,0) | alphaCorrection; \ - if ( firstPixel != QColor(color).rgb() && t < 4 ) \ - { QTest::qWait(200); continue; } \ - QVERIFY2(firstPixel == QColor(color).rgb(), msgRgbMismatch(firstPixel, QColor(color).rgb())); \ - QCOMPARE(pixmap, expectedPixmap); \ - break; \ - } \ - } \ -} while (0) + +#define VERIFY_COLOR(child, region, color) verifyColor(child, region, color, __LINE__) + +bool verifyColor(QWidget &child, const QRegion ®ion, const QColor &color, unsigned int callerLine) +{ + const QRegion r = QRegion(region); + QWindow *window = child.window()->windowHandle(); + Q_ASSERT(window); + const QPoint offset = child.mapTo(child.window(), QPoint(0,0)); + bool grabBackingStore = false; + for (int i = 0; i < r.rects().size(); ++i) { + QRect rect = r.rects().at(i).translated(offset); + for (int t = 0; t < 6; t++) { + const QPixmap pixmap = grabBackingStore + ? child.grab(rect) + : grabWindow(window, rect.left(), rect.top(), rect.width(), rect.height()); + if (!QTest::qCompare(pixmap.size(), rect.size(), "pixmap.size()", "rect.size()", __FILE__, callerLine)) + return false; + QPixmap expectedPixmap(pixmap); /* ensure equal formats */ + expectedPixmap.detach(); + expectedPixmap.fill(color); + QImage image = pixmap.toImage(); + uint alphaCorrection = image.format() == QImage::Format_RGB32 ? 0xff000000 : 0; + uint firstPixel = image.pixel(0,0) | alphaCorrection; + if (t < 5) { + /* Normal run. + If it succeeds: return success + If it fails: do not return, but wait a bit and reiterate (retry) + */ + if (firstPixel == QColor(color).rgb() + && image == expectedPixmap.toImage()) { + return true; + } else { + if (t == 4) { + grabBackingStore = true; + rect = r.rects().at(i); + } else { + QTest::qWait(200); + } + } + } else { + // Last run, report failure if it still fails + if (!QTest::qVerify(firstPixel == QColor(color).rgb(), + "firstPixel == QColor(color).rgb()", + qPrintable(msgRgbMismatch(firstPixel, QColor(color).rgb())), + __FILE__, callerLine)) + return false; + if (!QTest::qVerify(image == expectedPixmap.toImage(), + "image == expectedPixmap.toImage()", + "grabbed pixmap differs from expected pixmap", + __FILE__, callerLine)) + return false; + } + } + } + return true; +} void tst_QWidget::popupEnterLeave() { diff --git a/tests/manual/cocoa/qmaccocoaviewcontainer/main.mm b/tests/manual/cocoa/qmaccocoaviewcontainer/main.mm index d276961b93..6919562ddc 100644 --- a/tests/manual/cocoa/qmaccocoaviewcontainer/main.mm +++ b/tests/manual/cocoa/qmaccocoaviewcontainer/main.mm @@ -42,6 +42,7 @@ #import "TestMouseMovedNSView.h" #include <QtGui> +#include <QtWidgets> #include <QMacCocoaViewContainer> class MyWidget : public QWidget diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro index 381922288f..c9072c4e9e 100644 --- a/tests/manual/manual.pro +++ b/tests/manual/manual.pro @@ -47,6 +47,8 @@ unc !contains(QT_CONFIG, openssl):!contains(QT_CONFIG, openssl-linked):SUBDIRS -= qssloptions +contains(QT_CONFIG, opengl):SUBDIRS += qopengltextureblitter + win32 { SUBDIRS -= network_remote_stresstest network_stresstest # disable some tests on wince because of missing dependencies diff --git a/tests/manual/qopengltextureblitter/main.cpp b/tests/manual/qopengltextureblitter/main.cpp new file mode 100644 index 0000000000..3e9c30932a --- /dev/null +++ b/tests/manual/qopengltextureblitter/main.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qopengltextureblitwindow.h" +#include <QtGui/QGuiApplication> + +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + + QOpenGLTextureBlitWindow window; + window.show(); + + return app.exec(); +} diff --git a/tests/manual/qopengltextureblitter/qopengltextureblitter.pro b/tests/manual/qopengltextureblitter/qopengltextureblitter.pro new file mode 100644 index 0000000000..95f1c14e5a --- /dev/null +++ b/tests/manual/qopengltextureblitter/qopengltextureblitter.pro @@ -0,0 +1,12 @@ +TEMPLATE = app +TARGET = qopengltextureblitter +INCLUDEPATH += . + +QT+=gui-private +# Input +HEADERS += \ + qopengltextureblitwindow.h + +SOURCES += \ + main.cpp \ + qopengltextureblitwindow.cpp diff --git a/tests/manual/qopengltextureblitter/qopengltextureblitwindow.cpp b/tests/manual/qopengltextureblitter/qopengltextureblitwindow.cpp new file mode 100644 index 0000000000..0dac669887 --- /dev/null +++ b/tests/manual/qopengltextureblitter/qopengltextureblitwindow.cpp @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qopengltextureblitwindow.h" + +#include <QtGui/QPainter> +#include <QtGui/QOpenGLTexture> +#include <QtGui/QMatrix4x4> + +#include <QtCore/QCoreApplication> +#include <QtCore/QDebug> + +QOpenGLTextureBlitWindow::QOpenGLTextureBlitWindow() + : QWindow() + , m_context(new QOpenGLContext(this)) +{ + resize(500,500); + setSurfaceType(OpenGLSurface); + QSurfaceFormat surfaceFormat = format(); + if (QCoreApplication::arguments().contains(QStringLiteral("-coreprofile"))) { + surfaceFormat.setVersion(3,2); + surfaceFormat.setProfile(QSurfaceFormat::CoreProfile); + } + + setFormat(surfaceFormat); + create(); + m_context->setFormat(surfaceFormat); + m_context->create(); + + m_context->makeCurrent(this); + + m_blitter.create(); +} + +void QOpenGLTextureBlitWindow::render() +{ + m_context->makeCurrent(this); + + QRect viewport(0,0,dWidth(),dHeight()); + glViewport(0,0,dWidth(), dHeight()); + + glClearColor(0.f, .6f, .0f, 0.f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + QOpenGLTexture texture(m_image); + texture.create(); + + QRectF topLeft(QPointF(0,0), QPointF(dWidth()/2.0, dHeight()/2.0)); + QRectF topRight(QPointF(dWidth()/2.0,0), QPointF(dWidth(), dHeight()/2.0)); + QRectF bottomLeft(QPointF(0, dHeight()/2.0), QPointF(dWidth() /2.0, dHeight())); + QRectF bottomRight(QPoint(dWidth()/2.0, dHeight()/2.0), QPointF(dWidth(), dHeight())); + + QOpenGLTextureBlitter::Origin topLeftOrigin = QOpenGLTextureBlitter::OriginTopLeft; + QOpenGLTextureBlitter::Origin bottomLeftOrigin = QOpenGLTextureBlitter::OriginBottomLeft; + QMatrix4x4 topRightVertexFlipped = QOpenGLTextureBlitter::targetTransform(topRight, viewport, topLeftOrigin); + QMatrix4x4 bottomLeftVertex = QOpenGLTextureBlitter::targetTransform(bottomLeft, viewport, topLeftOrigin); + QMatrix4x4 bottomRightVertexFlipped = QOpenGLTextureBlitter::targetTransform(bottomRight, viewport, topLeftOrigin); + + QMatrix3x3 texTopLeft = QOpenGLTextureBlitter::sourceTransform(topLeft, m_image.size(), topLeftOrigin); + QMatrix3x3 texTopRight = QOpenGLTextureBlitter::sourceTransform(topRight, m_image.size(), topLeftOrigin); + QMatrix3x3 texBottomLeft = QOpenGLTextureBlitter::sourceTransform(bottomLeft, m_image.size(), topLeftOrigin); + QMatrix3x3 texBottomRight = QOpenGLTextureBlitter::sourceTransform(bottomRight, m_image.size(), bottomLeftOrigin); + + QSizeF subSize(topLeft.width()/2, topLeft.height()/2); + QRectF subTopLeft(topLeft.topLeft(), subSize); + QRectF subTopRight(QPointF(topLeft.topLeft().x() + topLeft.width() / 2, topLeft.topLeft().y()),subSize); + QRectF subBottomLeft(QPointF(topLeft.topLeft().x(), topLeft.topLeft().y() + topLeft.height() / 2), subSize); + QRectF subBottomRight(QPointF(topLeft.topLeft().x() + topLeft.width() / 2, topLeft.topLeft().y() + topLeft.height() / 2), subSize); + + QMatrix4x4 subTopLeftVertex = QOpenGLTextureBlitter::targetTransform(subTopLeft, viewport, topLeftOrigin); + QMatrix4x4 subTopRightVertex = QOpenGLTextureBlitter::targetTransform(subTopRight, viewport, topLeftOrigin); + QMatrix4x4 subBottomLeftVertex = QOpenGLTextureBlitter::targetTransform(subBottomLeft, viewport, topLeftOrigin); + QMatrix4x4 subBottomRightVertex = QOpenGLTextureBlitter::targetTransform(subBottomRight, viewport, topLeftOrigin); + + m_blitter.bind(); + m_blitter.blit(texture.textureId(), subTopLeftVertex, texBottomRight); + m_blitter.blit(texture.textureId(), subTopRightVertex, texBottomLeft); + m_blitter.blit(texture.textureId(), subBottomLeftVertex, texTopRight); + m_blitter.blit(texture.textureId(), subBottomRightVertex, texTopLeft); + + m_blitter.blit(texture.textureId(), topRightVertexFlipped, topLeftOrigin); + m_blitter.blit(texture.textureId(), bottomLeftVertex, bottomLeftOrigin); + + m_blitter.setSwizzleRB(true); + m_blitter.blit(texture.textureId(), bottomRightVertexFlipped, texTopLeft); + m_blitter.setSwizzleRB(false); + m_blitter.release(); + + m_context->swapBuffers(this); +} + + +void QOpenGLTextureBlitWindow::exposeEvent(QExposeEvent *event) +{ + Q_UNUSED(event); + render(); +} + +void QOpenGLTextureBlitWindow::resizeEvent(QResizeEvent *event) +{ + Q_UNUSED(event); + m_image = QImage(size() * devicePixelRatio(), QImage::Format_ARGB32_Premultiplied); + + m_image.fill(Qt::gray); + + QPainter p(&m_image); + + QPen pen(Qt::red); + pen.setWidth(5); + p.setPen(pen); + + QFont font = p.font(); + font.setPixelSize(qMin(m_image.height(), m_image.width()) / 20); + p.setFont(font); + + int dx = dWidth() / 5; + int dy = dHeight() / 5; + for (int y = 0; y < 5; y++) { + for (int x = 0; x < 5; x++) { + QRect textRect(x * dx, y*dy, dx,dy); + QString text = QString("[%1,%2]").arg(x).arg(y); + p.drawText(textRect,text); + } + } + + p.drawRect(QRectF(2.5,2.5,dWidth() - 5, dHeight() - 5)); + +} + diff --git a/tests/manual/qopengltextureblitter/qopengltextureblitwindow.h b/tests/manual/qopengltextureblitter/qopengltextureblitwindow.h new file mode 100644 index 0000000000..855e173b1a --- /dev/null +++ b/tests/manual/qopengltextureblitter/qopengltextureblitwindow.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENGLTEXTUREBLITWINDOW_H +#define QOPENGLTEXTUREBLITWINDOW_H + +#include <QtGui/QWindow> +#include <QtGui/QOpenGLContext> +#include <QtGui/private/qopengltextureblitter_p.h> + +class QOpenGLTextureBlitWindow : public QWindow +{ + Q_OBJECT +public: + QOpenGLTextureBlitWindow(); + + void render(); +protected: + void exposeEvent(QExposeEvent *event); + void resizeEvent(QResizeEvent *event); + +private: + qreal dWidth() const { return width() * devicePixelRatio(); } + qreal dHeight() const { return height() * devicePixelRatio(); } + + QScopedPointer<QOpenGLContext> m_context; + QOpenGLTextureBlitter m_blitter; + QImage m_image; +}; + +#endif diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index c9ca0fc597..c6d1002f23 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -3291,8 +3291,10 @@ void Configure::generateQConfigPri() if (!dictionary["QT_NAMESPACE"].isEmpty()) configStream << "#namespaces" << endl << "QT_NAMESPACE = " << dictionary["QT_NAMESPACE"] << endl; - if (dictionary[ "SHARED" ] == "no") - configStream << "QT_DEFAULT_QPA_PLUGIN = q" << qpaPlatformName() << endl; + if (dictionary[ "SHARED" ] == "no") { + configStream << "QT_DEFAULT_QPA_PLUGIN = q" << qpaPlatformName() << endl + << "QT_DEFAULT_PRINTSUPPORTPLUGIN = " << qpaPrintSupportPluginName() << endl; + } if (!configStream.flush()) dictionary[ "DONE" ] = "error"; @@ -3474,7 +3476,8 @@ void Configure::generateConfigfiles() for (int i = 0; i < qconfigList.count(); ++i) tmpStream << addDefine(qconfigList.at(i)); - tmpStream<<"#define QT_QPA_DEFAULT_PLATFORM_NAME \"" << qpaPlatformName() << "\""<<endl; + tmpStream << "#define QT_QPA_DEFAULT_PLATFORM_NAME \"" << qpaPlatformName() << "\"" << endl + << "#define QT_QPA_DEFAULT_PRINTSUPPORTPLUGIN_NAME \"" << qpaPrintSupportPluginName() << "\"" << endl; if (!tmpStream.flush()) dictionary[ "DONE" ] = "error"; @@ -4405,6 +4408,11 @@ QString Configure::qpaPlatformName() const } } +QString Configure::qpaPrintSupportPluginName() const +{ + return platform() == WINDOWS ? QStringLiteral("windowsprintersupport") : QString(); +} + int Configure::platform() const { const QString qMakeSpec = dictionary.value("QMAKESPEC"); diff --git a/tools/configure/configureapp.h b/tools/configure/configureapp.h index 3e0e691dab..36668f18ba 100644 --- a/tools/configure/configureapp.h +++ b/tools/configure/configureapp.h @@ -100,6 +100,7 @@ public: int platform() const; QString platformName() const; QString qpaPlatformName() const; + QString qpaPrintSupportPluginName() const; private: bool checkAngleAvailability(QString *errorMessage = 0) const; |