opt/qt5/qt5-5.3.1.patch
2014-08-17 17:00:54 +10:00

7366 lines
294 KiB
Diff

diff -Naur qt-everywhere-opensource-src-5.3.1/qtbase/qmake/generators/unix/unixmake2.cpp qt-everywhere-opensource-src-5.3.1.new/qtbase/qmake/generators/unix/unixmake2.cpp
--- qt-everywhere-opensource-src-5.3.1/qtbase/qmake/generators/unix/unixmake2.cpp 2014-06-19 12:08:02.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtbase/qmake/generators/unix/unixmake2.cpp 2014-08-13 04:36:48.326242431 +0200
@@ -117,7 +117,7 @@
<< varGlue("DEFINES","-D"," -D","") << endl;
t << "CFLAGS = " << var("QMAKE_CFLAGS") << " $(DEFINES)\n";
t << "CXXFLAGS = " << var("QMAKE_CXXFLAGS") << " $(DEFINES)\n";
- t << "INCPATH = -I" << specdir();
+ t << "INCPATH = -I/usr/include -I" << specdir();
if(!project->isActiveConfig("no_include_pwd")) {
QString pwd = escapeFilePath(fileFixify(qmake_getpwd()));
if(pwd.isEmpty())
@@ -1344,7 +1344,7 @@
QTextStream t(&ft);
t << "# " << lname << " - a libtool library file\n";
t << "# Generated by qmake/libtool (" QMAKE_VERSION_STR ") (Qt "
- << QT_VERSION_STR << ") on: " << QDateTime::currentDateTime().toString();
+ << QT_VERSION_STR << ")";
t << "\n";
t << "# The name that we can dlopen(3).\n"
diff -Naur qt-everywhere-opensource-src-5.3.1/qtbase/qmake/generators/unix/unixmake2.cpp.orig qt-everywhere-opensource-src-5.3.1.new/qtbase/qmake/generators/unix/unixmake2.cpp.orig
--- qt-everywhere-opensource-src-5.3.1/qtbase/qmake/generators/unix/unixmake2.cpp.orig 1970-01-01 01:00:00.000000000 +0100
+++ qt-everywhere-opensource-src-5.3.1.new/qtbase/qmake/generators/unix/unixmake2.cpp.orig 2014-08-13 04:36:48.323242404 +0200
@@ -0,0 +1,1403 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the qmake application of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance 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 "unixmake.h"
+#include "option.h"
+#include "meta.h"
+#include <qregexp.h>
+#include <qbytearray.h>
+#include <qfile.h>
+#include <qdir.h>
+#include <qdatetime.h>
+#include <qdebug.h>
+#include <time.h>
+
+QT_BEGIN_NAMESPACE
+
+UnixMakefileGenerator::UnixMakefileGenerator() : MakefileGenerator(), init_flag(false), include_deps(false)
+{
+
+}
+
+void
+UnixMakefileGenerator::writePrlFile(QTextStream &t)
+{
+ MakefileGenerator::writePrlFile(t);
+ // libtool support
+
+ if(project->isActiveConfig("create_libtool") && project->first("TEMPLATE") == "lib") { //write .la
+ if(project->isActiveConfig("compile_libtool"))
+ warn_msg(WarnLogic, "create_libtool specified with compile_libtool can lead to conflicting .la\n"
+ "formats, create_libtool has been disabled\n");
+ else
+ writeLibtoolFile();
+ }
+ // pkg-config support
+ if(project->isActiveConfig("create_pc") && project->first("TEMPLATE") == "lib")
+ writePkgConfigFile();
+}
+
+bool
+UnixMakefileGenerator::writeMakefile(QTextStream &t)
+{
+
+ writeHeader(t);
+ if (writeDummyMakefile(t))
+ return true;
+
+ if (project->values("TEMPLATE").first() == "app" ||
+ project->values("TEMPLATE").first() == "lib" ||
+ project->values("TEMPLATE").first() == "aux") {
+ if(Option::mkfile::do_stub_makefile && MakefileGenerator::writeStubMakefile(t))
+ return true;
+ writeMakeParts(t);
+ return MakefileGenerator::writeMakefile(t);
+ } else if(project->values("TEMPLATE").first() == "subdirs") {
+ MakefileGenerator::writeSubDirs(t);
+ return true;
+ }
+ return false;
+}
+
+void
+UnixMakefileGenerator::writeMakeParts(QTextStream &t)
+{
+ QString deps = fileFixify(Option::output.fileName()), target_deps, prl;
+ bool do_incremental = (project->isActiveConfig("incremental") &&
+ !project->values("QMAKE_INCREMENTAL").isEmpty() &&
+ (!project->values("QMAKE_APP_FLAG").isEmpty() ||
+ (!project->isActiveConfig("staticlib")))),
+ src_incremental=false;
+
+ ProStringList &bundledFiles = project->values("QMAKE_BUNDLED_FILES");
+
+ t << "####### Compiler, tools and options\n\n";
+ t << "CC = " << var("QMAKE_CC") << endl;
+ t << "CXX = " << var("QMAKE_CXX") << endl;
+ t << "DEFINES = "
+ << varGlue("PRL_EXPORT_DEFINES","-D"," -D"," ")
+ << varGlue("DEFINES","-D"," -D","") << endl;
+ t << "CFLAGS = " << var("QMAKE_CFLAGS") << " $(DEFINES)\n";
+ t << "CXXFLAGS = " << var("QMAKE_CXXFLAGS") << " $(DEFINES)\n";
+ t << "INCPATH = -I" << specdir();
+ if(!project->isActiveConfig("no_include_pwd")) {
+ QString pwd = escapeFilePath(fileFixify(qmake_getpwd()));
+ if(pwd.isEmpty())
+ pwd = ".";
+ t << " -I" << pwd;
+ }
+ {
+ QString isystem = var("QMAKE_CFLAGS_ISYSTEM");
+ const ProStringList &incs = project->values("INCLUDEPATH");
+ for(int i = 0; i < incs.size(); ++i) {
+ ProString inc = escapeFilePath(incs.at(i));
+ if (inc.isEmpty())
+ continue;
+
+ if (!isystem.isEmpty() && isSystemInclude(inc.toQString()))
+ t << ' ' << isystem << ' ' << inc;
+ else
+ t << " -I" << inc;
+ }
+ }
+ if(!project->isEmpty("QMAKE_FRAMEWORKPATH_FLAGS"))
+ t << " " << var("QMAKE_FRAMEWORKPATH_FLAGS");
+ t << endl;
+
+ if(!project->isActiveConfig("staticlib")) {
+ t << "LINK = " << var("QMAKE_LINK") << endl;
+ t << "LFLAGS = " << var("QMAKE_LFLAGS") << endl;
+ t << "LIBS = $(SUBLIBS) " << var("QMAKE_LIBS") << " " << var("QMAKE_LIBS_PRIVATE") << endl;
+ }
+
+ t << "AR = " << var("QMAKE_AR") << endl;
+ t << "RANLIB = " << var("QMAKE_RANLIB") << endl;
+ t << "QMAKE = " << var("QMAKE_QMAKE") << endl;
+ t << "TAR = " << var("QMAKE_TAR") << endl;
+ t << "COMPRESS = " << var("QMAKE_GZIP") << endl;
+ if(project->isActiveConfig("compile_libtool"))
+ t << "LIBTOOL = " << var("QMAKE_LIBTOOL") << endl;
+ t << "COPY = " << var("QMAKE_COPY") << endl;
+ t << "SED = " << var("QMAKE_STREAM_EDITOR") << endl;
+ t << "COPY_FILE = " << var("QMAKE_COPY_FILE") << endl;
+ t << "COPY_DIR = " << var("QMAKE_COPY_DIR") << endl;
+ t << "STRIP = " << var("QMAKE_STRIP") << endl;
+ t << "INSTALL_FILE = " << var("QMAKE_INSTALL_FILE") << endl;
+ t << "INSTALL_DIR = " << var("QMAKE_INSTALL_DIR") << endl;
+ t << "INSTALL_PROGRAM = " << var("QMAKE_INSTALL_PROGRAM") << endl;
+
+ t << "DEL_FILE = " << var("QMAKE_DEL_FILE") << endl;
+ t << "SYMLINK = " << var("QMAKE_SYMBOLIC_LINK") << endl;
+ t << "DEL_DIR = " << var("QMAKE_DEL_DIR") << endl;
+ t << "MOVE = " << var("QMAKE_MOVE") << endl;
+ t << "CHK_DIR_EXISTS= " << var("QMAKE_CHK_DIR_EXISTS") << endl;
+ t << "MKDIR = " << var("QMAKE_MKDIR") << endl;
+
+ t << endl;
+
+ t << "####### Output directory\n\n";
+ if (! project->values("OBJECTS_DIR").isEmpty())
+ t << "OBJECTS_DIR = " << var("OBJECTS_DIR") << endl;
+ else
+ t << "OBJECTS_DIR = ./\n";
+ t << endl;
+
+ /* files */
+ t << "####### Files\n\n";
+ t << "SOURCES = " << valList(escapeFilePaths(project->values("SOURCES"))) << " "
+ << valList(escapeFilePaths(project->values("GENERATED_SOURCES"))) << endl;
+ if(do_incremental) {
+ const ProStringList &objs = project->values("OBJECTS");
+ const ProStringList &incrs = project->values("QMAKE_INCREMENTAL");
+ ProStringList incrs_out;
+ t << "OBJECTS = ";
+ for (ProStringList::ConstIterator objit = objs.begin(); objit != objs.end(); ++objit) {
+ bool increment = false;
+ for (ProStringList::ConstIterator incrit = incrs.begin(); incrit != incrs.end(); ++incrit) {
+ if ((*objit).toQString().indexOf(QRegExp((*incrit).toQString(), Qt::CaseSensitive,
+ QRegExp::Wildcard)) != -1) {
+ increment = true;
+ incrs_out.append((*objit));
+ break;
+ }
+ }
+ if(!increment)
+ t << "\\\n\t\t" << (*objit);
+ }
+ if(incrs_out.count() == objs.count()) { //we just switched places, no real incrementals to be done!
+ t << escapeFilePaths(incrs_out).join(" \\\n\t\t") << endl;
+ } else if(!incrs_out.count()) {
+ t << endl;
+ } else {
+ src_incremental = true;
+ t << endl;
+ t << "INCREMENTAL_OBJECTS = " << escapeFilePaths(incrs_out).join(" \\\n\t\t") << endl;
+ }
+ } else {
+ t << "OBJECTS = " << valList(escapeFilePaths(project->values("OBJECTS"))) << endl;
+ }
+ if(do_incremental && !src_incremental)
+ do_incremental = false;
+ t << "DIST = " << valList(fileFixify(project->values("DISTFILES").toQStringList())) << " "
+ << valList(escapeFilePaths(project->values("SOURCES"))) << endl;
+ t << "QMAKE_TARGET = " << var("QMAKE_ORIG_TARGET") << endl;
+ // The comment is important for mingw32-make.exe on Windows as otherwise trailing slashes
+ // would be interpreted as line continuation. The lack of spacing between the value and the
+ // comment is also important as otherwise quoted use of "$(DESTDIR)" would include this
+ // spacing.
+ t << "DESTDIR = " << var("DESTDIR") << "#avoid trailing-slash linebreak\n";
+ if(project->isActiveConfig("compile_libtool"))
+ t << "TARGETL = " << var("TARGET_la") << endl;
+ t << "TARGET = " << escapeFilePath(var("TARGET")) << endl;
+ if(project->isActiveConfig("plugin")) {
+ t << "TARGETD = " << escapeFilePath(var("TARGET")) << endl;
+ } else if(!project->isActiveConfig("staticlib") && project->values("QMAKE_APP_FLAG").isEmpty()) {
+ t << "TARGETA = " << escapeFilePath(var("TARGETA")) << endl;
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ t << "TARGETD = " << escapeFilePath(var("TARGET_x.y")) << endl;
+ t << "TARGET0 = " << escapeFilePath(var("TARGET_")) << endl;
+ } else if (!project->isActiveConfig("unversioned_libname")) {
+ t << "TARGET0 = " << escapeFilePath(var("TARGET_")) << endl;
+ if (project->isEmpty("QMAKE_HPUX_SHLIB")) {
+ t << "TARGETD = " << escapeFilePath(var("TARGET_x.y.z")) << endl;
+ t << "TARGET1 = " << escapeFilePath(var("TARGET_x")) << endl;
+ t << "TARGET2 = " << escapeFilePath(var("TARGET_x.y")) << endl;
+ } else {
+ t << "TARGETD = " << escapeFilePath(var("TARGET_x")) << endl;
+ }
+ }
+ }
+ writeExtraCompilerVariables(t);
+ writeExtraVariables(t);
+ t << endl;
+
+ // blasted includes
+ const ProStringList &qeui = project->values("QMAKE_EXTRA_INCLUDES");
+ ProStringList::ConstIterator it;
+ for(it = qeui.begin(); it != qeui.end(); ++it)
+ t << "include " << (*it) << endl;
+
+ /* rules */
+ t << "first: all\n";
+ t << "####### Implicit rules\n\n";
+ t << ".SUFFIXES: " << Option::obj_ext;
+ for(QStringList::Iterator cit = Option::c_ext.begin(); cit != Option::c_ext.end(); ++cit)
+ t << " " << (*cit);
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
+ t << " " << (*cppit);
+ t << endl << endl;
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit)
+ t << (*cppit) << Option::obj_ext << ":\n\t" << var("QMAKE_RUN_CXX_IMP") << endl << endl;
+ for(QStringList::Iterator cit = Option::c_ext.begin(); cit != Option::c_ext.end(); ++cit)
+ t << (*cit) << Option::obj_ext << ":\n\t" << var("QMAKE_RUN_CC_IMP") << endl << endl;
+
+ if(include_deps) {
+ if (project->isActiveConfig("gcc_MD_depends")) {
+ ProStringList objects = project->values("OBJECTS");
+ for (ProStringList::Iterator it = objects.begin(); it != objects.end(); ++it) {
+ QString d_file = (*it).toQString().replace(QRegExp(Option::obj_ext + "$"), ".d");
+ t << "-include " << d_file << endl;
+ project->values("QMAKE_DISTCLEAN") << d_file;
+ }
+ } else {
+ QString cmd=var("QMAKE_CFLAGS_DEPS") + " ";
+ cmd += varGlue("DEFINES","-D"," -D","") + varGlue("PRL_EXPORT_DEFINES"," -D"," -D","");
+ if(!project->isEmpty("QMAKE_ABSOLUTE_SOURCE_PATH"))
+ cmd += " -I" + project->first("QMAKE_ABSOLUTE_SOURCE_PATH") + " ";
+ cmd += " $(INCPATH) " + varGlue("DEPENDPATH", "-I", " -I", "");
+ ProString odir;
+ if(!project->values("OBJECTS_DIR").isEmpty())
+ odir = project->first("OBJECTS_DIR");
+
+ QString pwd = escapeFilePath(fileFixify(qmake_getpwd()));
+
+ t << "###### Dependencies\n\n";
+ t << odir << ".deps/%.d: " << pwd << "/%.cpp\n\t";
+ if(project->isActiveConfig("echo_depend_creation"))
+ t << "@echo Creating depend for $<\n\t";
+ t << mkdir_p_asstring("$(@D)", false) << "\n\t"
+ << "@$(CXX) " << cmd << " $< | sed \"s,^\\($(*F).o\\):," << odir << "\\1:,g\" >$@\n\n";
+
+ t << odir << ".deps/%.d: " << pwd << "/%.c\n\t";
+ if(project->isActiveConfig("echo_depend_creation"))
+ t << "@echo Creating depend for $<\n\t";
+ t << mkdir_p_asstring("$(@D)", false) << "\n\t"
+ << "@$(CC) " << cmd << " $< | sed \"s,^\\($(*F).o\\):," << odir << "\\1:,g\" >$@\n\n";
+
+ static const char * const src[] = { "SOURCES", "GENERATED_SOURCES", 0 };
+ for (int x = 0; src[x]; x++) {
+ const ProStringList &l = project->values(src[x]);
+ for (ProStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
+ if(!(*it).isEmpty()) {
+ QString d_file;
+ for(QStringList::Iterator cit = Option::c_ext.begin();
+ cit != Option::c_ext.end(); ++cit) {
+ if((*it).endsWith((*cit))) {
+ d_file = (*it).left((*it).length() - (*cit).length()).toQString();
+ break;
+ }
+ }
+ if(d_file.isEmpty()) {
+ for(QStringList::Iterator cppit = Option::cpp_ext.begin();
+ cppit != Option::cpp_ext.end(); ++cppit) {
+ if((*it).endsWith((*cppit))) {
+ d_file = (*it).left((*it).length() - (*cppit).length()).toQString();
+ break;
+ }
+ }
+ }
+
+ if(!d_file.isEmpty()) {
+ d_file = odir + ".deps/" + fileFixify(d_file, pwd, Option::output_dir) + ".d";
+ QStringList deps = findDependencies((*it).toQString()).filter(QRegExp(
+ "((^|/)" + Option::h_moc_mod + "|" + Option::cpp_moc_ext + "$)"));
+ if(!deps.isEmpty())
+ t << d_file << ": " << deps.join(' ') << endl;
+ t << "-include " << d_file << endl;
+ project->values("QMAKE_DISTCLEAN") += d_file;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ t << "####### Build rules\n\n";
+ if(!project->values("SUBLIBS").isEmpty()) {
+ ProString libdir = "tmp/";
+ if(!project->isEmpty("SUBLIBS_DIR"))
+ libdir = project->first("SUBLIBS_DIR");
+ t << "SUBLIBS = ";
+ const ProStringList &l = project->values("SUBLIBS");
+ for (ProStringList::ConstIterator it = l.begin(); it != l.end(); ++it)
+ t << libdir << project->first("QMAKE_PREFIX_STATICLIB") << (*it) << "."
+ << project->first("QMAKE_EXTENSION_STATICLIB") << " ";
+ t << endl << endl;
+ }
+ if ((project->isActiveConfig("depend_prl") || project->isActiveConfig("fast_depend_prl"))
+ && !project->isEmpty("QMAKE_PRL_INTERNAL_FILES")) {
+ const ProStringList &l = project->values("QMAKE_PRL_INTERNAL_FILES");
+ ProStringList::ConstIterator it;
+ for(it = l.begin(); it != l.end(); ++it) {
+ QMakeMetaInfo libinfo(project);
+ if (libinfo.readLib((*it).toQString()) && !libinfo.isEmpty("QMAKE_PRL_BUILD_DIR")) {
+ ProString dir;
+ int slsh = (*it).lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ dir = (*it).left(slsh + 1);
+ QString targ = dir + libinfo.first("QMAKE_PRL_TARGET");
+ target_deps += " " + targ;
+ t << targ;
+ if (project->isActiveConfig("fast_depend_prl"))
+ t << ":\n\t@echo \"Creating '";
+ else
+ t << ": FORCE\n\t@echo \"Creating/updating '";
+ t << targ << "'\"\n\t"
+ << "(cd " << libinfo.first("QMAKE_PRL_BUILD_DIR") << ";"
+ << "$(MAKE))\n";
+ }
+ }
+ }
+ if (!project->values("QMAKE_APP_FLAG").isEmpty() || project->first("TEMPLATE") == "aux") {
+ QString destdir = project->first("DESTDIR").toQString();
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ QString bundle_loc = project->first("QMAKE_BUNDLE_LOCATION").toQString();
+ if(!bundle_loc.isEmpty() && !bundle_loc.startsWith("/"))
+ bundle_loc.prepend("/");
+ if(!bundle_loc.endsWith("/"))
+ bundle_loc += "/";
+ destdir += project->first("QMAKE_BUNDLE") + bundle_loc;
+ }
+ if(do_incremental) {
+ //incremental target
+ QString incr_target = var("TARGET") + "_incremental";
+ if(incr_target.indexOf(Option::dir_sep) != -1)
+ incr_target = incr_target.right(incr_target.length() -
+ (incr_target.lastIndexOf(Option::dir_sep) + 1));
+ QString incr_deps, incr_objs;
+ if(project->first("QMAKE_INCREMENTAL_STYLE") == "ld") {
+ QString incr_target_dir = var("OBJECTS_DIR") + incr_target + Option::obj_ext;
+ //actual target
+ t << incr_target_dir << ": $(OBJECTS)\n\t"
+ << "ld -r -o "<< incr_target_dir << " $(OBJECTS)\n";
+ //communicated below
+ deps.prepend(incr_target_dir + " ");
+ incr_deps = "$(INCREMENTAL_OBJECTS)";
+ if(!incr_objs.isEmpty())
+ incr_objs += " ";
+ incr_objs += incr_target_dir;
+ } else {
+ //actual target
+ QString incr_target_dir = var("DESTDIR") + "lib" + incr_target + "." +
+ project->values("QMAKE_EXTENSION_SHLIB").first();
+ QString incr_lflags = var("QMAKE_LFLAGS_SHLIB") + " ";
+ if(project->isActiveConfig("debug"))
+ incr_lflags += var("QMAKE_LFLAGS_DEBUG");
+ else if (project->isActiveConfig("debug_info"))
+ incr_lflags += var("QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO");
+ else
+ incr_lflags += var("QMAKE_LFLAGS_RELEASE");
+ t << incr_target_dir << ": $(INCREMENTAL_OBJECTS)\n\t";
+ if(!destdir.isEmpty())
+ t << "\n\t" << mkdir_p_asstring(destdir) << "\n\t";
+ t << "$(LINK) " << incr_lflags << " -o "<< incr_target_dir <<
+ " $(INCREMENTAL_OBJECTS)\n";
+ //communicated below
+ if(!destdir.isEmpty()) {
+ if(!incr_objs.isEmpty())
+ incr_objs += " ";
+ incr_objs += "-L" + destdir;
+ } else {
+ if(!incr_objs.isEmpty())
+ incr_objs += " ";
+ incr_objs += "-L" + qmake_getpwd();
+ }
+ if(!incr_objs.isEmpty())
+ incr_objs += " ";
+ incr_objs += " -l" + incr_target;
+ deps.prepend(incr_target_dir + " ");
+ incr_deps = "$(OBJECTS)";
+ }
+ t << "all: " << escapeDependencyPath(deps) << " " << valGlue(escapeDependencyPaths(project->values("ALL_DEPS")),""," "," ") << "$(TARGET)"
+ << endl << endl;
+
+ //real target
+ t << var("TARGET") << ": " << var("PRE_TARGETDEPS") << " " << incr_deps << " " << target_deps
+ << " " << var("POST_TARGETDEPS") << "\n\t";
+ if(!destdir.isEmpty())
+ t << "\n\t" << mkdir_p_asstring(destdir) << "\n\t";
+ if(!project->isEmpty("QMAKE_PRE_LINK"))
+ t << var("QMAKE_PRE_LINK") << "\n\t";
+ t << "$(LINK) $(LFLAGS) " << var("QMAKE_LINK_O_FLAG") << "$(TARGET) " << incr_deps << " " << incr_objs << " $(OBJCOMP) $(LIBS)";
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" << var("QMAKE_POST_LINK");
+ t << endl << endl;
+ } else {
+ t << "all: " << escapeDependencyPath(deps) << " " << valGlue(escapeDependencyPaths(project->values("ALL_DEPS")),""," "," ") << "$(TARGET)"
+ << endl << endl;
+
+ t << "$(TARGET): " << var("PRE_TARGETDEPS") << " $(OBJECTS) "
+ << target_deps << " " << var("POST_TARGETDEPS") << "\n\t";
+ if (project->first("TEMPLATE") != "aux") {
+ if (!destdir.isEmpty())
+ t << mkdir_p_asstring(destdir) << "\n\t";
+ if (!project->isEmpty("QMAKE_PRE_LINK"))
+ t << var("QMAKE_PRE_LINK") << "\n\t";
+ t << "$(LINK) $(LFLAGS) " << var("QMAKE_LINK_O_FLAG") << "$(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS)";
+ if (!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" << var("QMAKE_POST_LINK");
+ }
+ t << endl << endl;
+ }
+ } else if(!project->isActiveConfig("staticlib")) {
+ QString destdir = unescapeFilePath(project->first("DESTDIR").toQString()), incr_deps;
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ QString bundle_loc = project->first("QMAKE_BUNDLE_LOCATION").toQString();
+ if(!bundle_loc.isEmpty() && !bundle_loc.startsWith("/"))
+ bundle_loc.prepend("/");
+ if(!bundle_loc.endsWith("/"))
+ bundle_loc += "/";
+ destdir += project->first("QMAKE_BUNDLE") + bundle_loc;
+ }
+ destdir = escapeFilePath(destdir);
+
+ if(do_incremental) {
+ ProString s_ext = project->first("QMAKE_EXTENSION_SHLIB");
+ QString incr_target = var("QMAKE_ORIG_TARGET").replace(
+ QRegExp("\\." + s_ext), "").replace(QRegExp("^lib"), "") + "_incremental";
+ if(incr_target.indexOf(Option::dir_sep) != -1)
+ incr_target = incr_target.right(incr_target.length() -
+ (incr_target.lastIndexOf(Option::dir_sep) + 1));
+ incr_target = escapeFilePath(incr_target);
+
+ if(project->first("QMAKE_INCREMENTAL_STYLE") == "ld") {
+ QString incr_target_dir = escapeFilePath(var("OBJECTS_DIR") + incr_target + Option::obj_ext);
+ //actual target
+ const QString link_deps = "$(OBJECTS) ";
+ t << incr_target_dir << ": " << link_deps << "\n\t"
+ << "ld -r -o " << incr_target_dir << " " << link_deps << endl;
+ //communicated below
+ ProStringList &cmd = project->values("QMAKE_LINK_SHLIB_CMD");
+ cmd[0] = cmd.at(0).toQString().replace("$(OBJECTS) ", "$(INCREMENTAL_OBJECTS)"); //ick
+ cmd.append(incr_target_dir);
+ deps.prepend(incr_target_dir + " ");
+ incr_deps = "$(INCREMENTAL_OBJECTS)";
+ } else {
+ //actual target
+ QString incr_target_dir = escapeFilePath(destdir + "lib" + incr_target + "." + s_ext);
+ QString incr_lflags = var("QMAKE_LFLAGS_SHLIB") + " ";
+ if(!project->isEmpty("QMAKE_LFLAGS_INCREMENTAL"))
+ incr_lflags += var("QMAKE_LFLAGS_INCREMENTAL") + " ";
+ if(project->isActiveConfig("debug"))
+ incr_lflags += var("QMAKE_LFLAGS_DEBUG");
+ else if (project->isActiveConfig("debug_info"))
+ incr_lflags += var("QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO");
+ else
+ incr_lflags += var("QMAKE_LFLAGS_RELEASE");
+ t << incr_target_dir << ": $(INCREMENTAL_OBJECTS)\n\t";
+ if(!destdir.isEmpty())
+ t << mkdir_p_asstring(destdir, false) << "\n\t";
+ t << "$(LINK) " << incr_lflags << " " << var("QMAKE_LINK_O_FLAG") << incr_target_dir <<
+ " $(INCREMENTAL_OBJECTS)\n";
+ //communicated below
+ ProStringList &cmd = project->values("QMAKE_LINK_SHLIB_CMD");
+ if(!destdir.isEmpty())
+ cmd.append(" -L" + destdir);
+ cmd.append(" -l" + incr_target);
+ deps.prepend(incr_target_dir + " ");
+ incr_deps = "$(OBJECTS)";
+ }
+
+ t << "all: " << escapeDependencyPath(deps) << " " << valGlue(escapeDependencyPaths(project->values("ALL_DEPS")),""," "," ")
+ << " " << destdir << "$(TARGET)\n\n";
+
+ //real target
+ t << destdir << "$(TARGET): " << var("PRE_TARGETDEPS") << " "
+ << incr_deps << " $(SUBLIBS) " << target_deps << " " << var("POST_TARGETDEPS");
+ } else {
+ t << "all: " << escapeDependencyPath(deps) << " " << valGlue(escapeDependencyPaths(project->values("ALL_DEPS")),""," "," ") << " " <<
+ destdir << "$(TARGET)\n\n";
+ t << destdir << "$(TARGET): " << var("PRE_TARGETDEPS")
+ << " $(OBJECTS) $(SUBLIBS) $(OBJCOMP) " << target_deps
+ << " " << var("POST_TARGETDEPS");
+ }
+ if(!destdir.isEmpty())
+ t << "\n\t" << mkdir_p_asstring(destdir, false);
+ if(!project->isEmpty("QMAKE_PRE_LINK"))
+ t << "\n\t" << var("QMAKE_PRE_LINK");
+
+ if(project->isActiveConfig("compile_libtool")) {
+ t << "\n\t"
+ << var("QMAKE_LINK_SHLIB_CMD");
+ } else if(project->isActiveConfig("plugin")) {
+ t << "\n\t"
+ << "-$(DEL_FILE) $(TARGET)\n\t"
+ << var("QMAKE_LINK_SHLIB_CMD");
+ if(!destdir.isEmpty())
+ t << "\n\t"
+ << "-$(MOVE) $(TARGET) " << destdir << " ";
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" << var("QMAKE_POST_LINK");
+ t << endl << endl;
+ } else if(!project->isEmpty("QMAKE_BUNDLE")) {
+ QString currentLink = destdir + "Versions/Current";
+ bundledFiles << currentLink << destdir + "$(TARGET)";
+ t << "\n\t"
+ << "-$(DEL_FILE) $(TARGET) $(TARGET0) $(DESTDIR)$(TARGET0)\n\t"
+ << var("QMAKE_LINK_SHLIB_CMD") << "\n\t"
+ << mkdir_p_asstring("\"`dirname $(DESTDIR)$(TARGETD)`\"", false) << "\n\t"
+ << "-$(MOVE) $(TARGET) $(DESTDIR)$(TARGETD)\n\t"
+ << mkdir_p_asstring("\"`dirname $(DESTDIR)$(TARGET0)`\"", false) << "\n\t"
+ << varGlue("QMAKE_LN_SHLIB", "-", " ",
+ " Versions/Current/$(TARGET) $(DESTDIR)$(TARGET0)") << "\n\t"
+ << "-$(DEL_FILE) " << currentLink << "\n\t"
+ << varGlue("QMAKE_LN_SHLIB","-"," ", " " + project->first("QMAKE_FRAMEWORK_VERSION") +
+ " " + currentLink) << "\n\t";
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" << var("QMAKE_POST_LINK");
+ t << endl << endl;
+ } else if(project->isEmpty("QMAKE_HPUX_SHLIB")) {
+ t << "\n\t";
+
+ if (!project->isActiveConfig("unversioned_libname"))
+ t << "-$(DEL_FILE) $(TARGET) $(TARGET0) $(TARGET1) $(TARGET2)";
+ else
+ t << "-$(DEL_FILE) $(TARGET)";
+
+ t << "\n\t" << var("QMAKE_LINK_SHLIB_CMD");
+
+ if (!project->isActiveConfig("unversioned_libname")) {
+ t << "\n\t"
+ << varGlue("QMAKE_LN_SHLIB","-"," "," $(TARGET) $(TARGET0)") << "\n\t"
+ << varGlue("QMAKE_LN_SHLIB","-"," "," $(TARGET) $(TARGET1)") << "\n\t"
+ << varGlue("QMAKE_LN_SHLIB","-"," "," $(TARGET) $(TARGET2)");
+ }
+ if (!destdir.isEmpty()) {
+ t << "\n\t"
+ << "-$(DEL_FILE) " << destdir << "$(TARGET)\n\t"
+ << "-$(MOVE) $(TARGET) " << destdir << " ";
+
+ if (!project->isActiveConfig("unversioned_libname")) {
+ t << "\n\t"
+ << "-$(DEL_FILE) " << destdir << "$(TARGET0)\n\t"
+ << "-$(DEL_FILE) " << destdir << "$(TARGET1)\n\t"
+ << "-$(DEL_FILE) " << destdir << "$(TARGET2)\n\t"
+ << "-$(MOVE) $(TARGET0) " << destdir << " \n\t"
+ << "-$(MOVE) $(TARGET1) " << destdir << " \n\t"
+ << "-$(MOVE) $(TARGET2) " << destdir << " ";
+ }
+ }
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" << var("QMAKE_POST_LINK");
+ t << endl << endl;
+ } else {
+ t << "\n\t"
+ << "-$(DEL_FILE) $(TARGET) $(TARGET0)\n\t"
+ << var("QMAKE_LINK_SHLIB_CMD") << "\n\t";
+ t << varGlue("QMAKE_LN_SHLIB",""," "," $(TARGET) $(TARGET0)");
+ if(!destdir.isEmpty())
+ t << "\n\t"
+ << "-$(DEL_FILE) " << destdir << "$(TARGET)\n\t"
+ << "-$(DEL_FILE) " << destdir << "$(TARGET0)\n\t"
+ << "-$(MOVE) $(TARGET) " << destdir << " \n\t"
+ << "-$(MOVE) $(TARGET0) " << destdir << " \n\t";
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\n\t" << var("QMAKE_POST_LINK");
+ t << endl << endl;
+ }
+ t << endl << endl;
+
+ if (! project->isActiveConfig("plugin")) {
+ t << "staticlib: $(TARGETA)\n\n";
+ t << "$(TARGETA): " << var("PRE_TARGETDEPS") << " $(OBJECTS) $(OBJCOMP)";
+ if(do_incremental)
+ t << " $(INCREMENTAL_OBJECTS)";
+ t << " " << var("POST_TARGETDEPS") << "\n\t"
+ << "-$(DEL_FILE) $(TARGETA) \n\t"
+ << var("QMAKE_AR_CMD");
+ if(do_incremental)
+ t << " $(INCREMENTAL_OBJECTS)";
+ if(!project->isEmpty("QMAKE_RANLIB"))
+ t << "\n\t$(RANLIB) $(TARGETA)";
+ t << endl << endl;
+ }
+ } else {
+ QString destdir = project->first("DESTDIR").toQString();
+ t << "all: " << escapeDependencyPath(deps) << " " << valGlue(escapeDependencyPaths(project->values("ALL_DEPS")),""," "," ") << destdir << "$(TARGET) "
+ << varGlue("QMAKE_AR_SUBLIBS", destdir, " " + destdir, "") << "\n\n"
+ << "staticlib: " << destdir << "$(TARGET)\n\n";
+ if(project->isEmpty("QMAKE_AR_SUBLIBS")) {
+ t << destdir << "$(TARGET): " << var("PRE_TARGETDEPS")
+ << " $(OBJECTS) $(OBJCOMP) " << var("POST_TARGETDEPS") << "\n\t";
+ if(!destdir.isEmpty())
+ t << mkdir_p_asstring(destdir) << "\n\t";
+ t << "-$(DEL_FILE) $(TARGET)\n\t"
+ << var("QMAKE_AR_CMD") << "\n";
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\t" << var("QMAKE_POST_LINK") << "\n";
+ if(!project->isEmpty("QMAKE_RANLIB"))
+ t << "\t$(RANLIB) $(TARGET)\n";
+ if(!destdir.isEmpty())
+ t << "\t-$(DEL_FILE) " << destdir << "$(TARGET)\n"
+ << "\t-$(MOVE) $(TARGET) " << destdir << " \n";
+ } else {
+ int max_files = project->first("QMAKE_MAX_FILES_PER_AR").toInt();
+ ProStringList objs = project->values("OBJECTS") + project->values("OBJCOMP"),
+ libs = project->values("QMAKE_AR_SUBLIBS");
+ libs.prepend("$(TARGET)");
+ for (ProStringList::Iterator libit = libs.begin(), objit = objs.begin();
+ libit != libs.end(); ++libit) {
+ ProStringList build;
+ for(int cnt = 0; cnt < max_files && objit != objs.end(); ++objit, cnt++)
+ build << (*objit);
+ QString ar;
+ if((*libit) == "$(TARGET)") {
+ t << destdir << "$(TARGET): " << var("PRE_TARGETDEPS")
+ << " " << var("POST_TARGETDEPS") << valList(build) << "\n\t";
+ ar = project->first("QMAKE_AR_CMD").toQString();
+ ar = ar.replace("$(OBJECTS)", build.join(' '));
+ } else {
+ t << (*libit) << ": " << valList(build) << "\n\t";
+ ar = "$(AR) " + (*libit) + " " + build.join(' ');
+ }
+ if(!destdir.isEmpty())
+ t << mkdir_p_asstring(destdir) << "\n\t";
+ t << "-$(DEL_FILE) " << (*libit) << "\n\t"
+ << ar << "\n";
+ if(!project->isEmpty("QMAKE_POST_LINK"))
+ t << "\t" << var("QMAKE_POST_LINK") << "\n";
+ if(!project->isEmpty("QMAKE_RANLIB"))
+ t << "\t$(RANLIB) " << (*libit) << "\n";
+ if(!destdir.isEmpty())
+ t << "\t-$(DEL_FILE) " << destdir << (*libit) << "\n"
+ << "\t-$(MOVE) " << (*libit) << " " << destdir << " \n";
+ }
+ }
+ t << endl << endl;
+ }
+
+ writeMakeQmake(t);
+ if(project->isEmpty("QMAKE_FAILED_REQUIREMENTS") && !project->isActiveConfig("no_autoqmake")) {
+ QStringList meta_files;
+ if(project->isActiveConfig("create_libtool") && project->first("TEMPLATE") == "lib" &&
+ !project->isActiveConfig("compile_libtool")) { //libtool
+ meta_files += libtoolFileName();
+ }
+ if(project->isActiveConfig("create_pc") && project->first("TEMPLATE") == "lib") { //pkg-config
+ meta_files += pkgConfigFileName();
+ }
+ if(!meta_files.isEmpty())
+ t << escapeDependencyPaths(meta_files).join(" ") << ": \n\t"
+ << "@$(QMAKE) -prl " << buildArgs() << " " << project->projectFile() << endl;
+ }
+
+ if(!project->first("QMAKE_PKGINFO").isEmpty()) {
+ ProString pkginfo = escapeFilePath(project->first("QMAKE_PKGINFO"));
+ QString destdir = project->first("DESTDIR") + project->first("QMAKE_BUNDLE") + "/Contents";
+ t << pkginfo << ": \n\t";
+ if(!destdir.isEmpty())
+ t << mkdir_p_asstring(destdir) << "\n\t";
+ t << "@$(DEL_FILE) " << pkginfo << "\n\t"
+ << "@echo \"APPL"
+ << (project->isEmpty("QMAKE_PKGINFO_TYPEINFO") ? QString::fromLatin1("????") : project->first("QMAKE_PKGINFO_TYPEINFO").left(4))
+ << "\" >" << pkginfo << endl;
+ }
+ if(!project->first("QMAKE_BUNDLE_RESOURCE_FILE").isEmpty()) {
+ ProString resources = escapeFilePath(project->first("QMAKE_BUNDLE_RESOURCE_FILE"));
+ bundledFiles << resources;
+ QString destdir = project->first("DESTDIR") + project->first("QMAKE_BUNDLE") + "/Contents/Resources";
+ t << resources << ": \n\t";
+ t << mkdir_p_asstring(destdir) << "\n\t";
+ t << "@touch " << resources << "\n\t\n";
+ }
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ //copy the plist
+ QString info_plist = escapeFilePath(fileFixify(project->first("QMAKE_INFO_PLIST").toQString())),
+ info_plist_out = escapeFilePath(project->first("QMAKE_INFO_PLIST_OUT").toQString());
+ if (info_plist.isEmpty())
+ info_plist = specdir() + QDir::separator() + "Info.plist." + project->first("TEMPLATE");
+ bundledFiles << info_plist_out;
+ QString destdir = info_plist_out.section(Option::dir_sep, 0, -2);
+ t << info_plist_out << ": \n\t";
+ if(!destdir.isEmpty())
+ t << mkdir_p_asstring(destdir, false) << "\n\t";
+ ProStringList commonSedArgs;
+ if (!project->values("VERSION").isEmpty())
+ commonSedArgs << "-e \"s,@SHORT_VERSION@," << project->first("VER_MAJ") << "." << project->first("VER_MIN") << ",g\" ";
+ commonSedArgs << "-e \"s,@TYPEINFO@,"<< (project->isEmpty("QMAKE_PKGINFO_TYPEINFO") ?
+ QString::fromLatin1("????") : project->first("QMAKE_PKGINFO_TYPEINFO").left(4)) << ",g\" ";
+ if(project->first("TEMPLATE") == "app") {
+ QString icon = fileFixify(var("ICON"));
+ QString bundlePrefix = project->first("QMAKE_TARGET_BUNDLE_PREFIX").toQString();
+ if (bundlePrefix.isEmpty())
+ bundlePrefix = "com.yourcompany";
+ if (bundlePrefix.endsWith("."))
+ bundlePrefix.chop(1);
+ QString bundleIdentifier = bundlePrefix + "." + var("QMAKE_BUNDLE");
+ if (bundleIdentifier.endsWith(".app"))
+ bundleIdentifier.chop(4);
+ t << "@$(DEL_FILE) " << info_plist_out << "\n\t"
+ << "@sed ";
+ foreach (const ProString &arg, commonSedArgs)
+ t << arg;
+ t << "-e \"s,@ICON@," << icon.section(Option::dir_sep, -1) << ",g\" "
+ << "-e \"s,@BUNDLEIDENTIFIER@," << bundleIdentifier << ",g\" "
+ << "-e \"s,@EXECUTABLE@," << var("QMAKE_ORIG_TARGET") << ",g\" "
+ << "-e \"s,@TYPEINFO@,"<< (project->isEmpty("QMAKE_PKGINFO_TYPEINFO") ?
+ QString::fromLatin1("????") : project->first("QMAKE_PKGINFO_TYPEINFO").left(4)) << ",g\" "
+ << "" << info_plist << " >" << info_plist_out << endl;
+ //copy the icon
+ if(!project->isEmpty("ICON")) {
+ QString dir = project->first("DESTDIR") + project->first("QMAKE_BUNDLE") + "/Contents/Resources/";
+ const QString icon_path = escapeFilePath(dir + icon.section(Option::dir_sep, -1));
+ bundledFiles << icon_path;
+ t << icon_path << ": " << icon << "\n\t"
+ << mkdir_p_asstring(dir) << "\n\t"
+ << "@$(DEL_FILE) " << icon_path << "\n\t"
+ << "@$(COPY_FILE) " << escapeFilePath(icon) << " " << icon_path << endl;
+ }
+ } else {
+ t << "@$(DEL_FILE) " << info_plist_out << "\n\t"
+ << "@sed ";
+ foreach (const ProString &arg, commonSedArgs)
+ t << arg;
+ t << "-e \"s,@LIBRARY@," << var("QMAKE_ORIG_TARGET") << ",g\" "
+ << "-e \"s,@TYPEINFO@,"
+ << (project->isEmpty("QMAKE_PKGINFO_TYPEINFO") ?
+ QString::fromLatin1("????") : project->first("QMAKE_PKGINFO_TYPEINFO").left(4)) << ",g\" "
+ << "" << info_plist << " >" << info_plist_out << endl;
+ }
+ //copy other data
+ if(!project->isEmpty("QMAKE_BUNDLE_DATA")) {
+ QString bundle_dir = project->first("DESTDIR") + project->first("QMAKE_BUNDLE") + "/";
+ const ProStringList &bundle_data = project->values("QMAKE_BUNDLE_DATA");
+ for(int i = 0; i < bundle_data.count(); i++) {
+ const ProStringList &files = project->values(ProKey(bundle_data[i] + ".files"));
+ QString path = bundle_dir;
+ const ProKey vkey(bundle_data[i] + ".version");
+ const ProKey pkey(bundle_data[i] + ".path");
+ if (!project->isEmpty(vkey)) {
+ QString version = project->first(vkey) + "/" +
+ project->first("QMAKE_FRAMEWORK_VERSION") + "/";
+ QString link = Option::fixPathToLocalOS(path + project->first(pkey));
+ bundledFiles << link;
+ t << link << ": \n\t"
+ << mkdir_p_asstring(path) << "\n\t"
+ << "@$(SYMLINK) " << version << project->first(pkey) << " " << path << endl;
+ path += version;
+ }
+ path += project->first(pkey).toQString();
+ path = Option::fixPathToLocalOS(path);
+ for(int file = 0; file < files.count(); file++) {
+ QString fn = files.at(file).toQString();
+ QString src = fileFixify(fn, FileFixifyAbsolute);
+ if (!QFile::exists(src))
+ src = fn;
+ src = escapeFilePath(src);
+ const QString dst = escapeFilePath(path + Option::dir_sep + fileInfo(fn).fileName());
+ bundledFiles << dst;
+ t << dst << ": " << src << "\n\t"
+ << mkdir_p_asstring(path) << "\n\t";
+ QFileInfo fi(fileInfo(fn));
+ if(fi.isDir())
+ t << "@$(DEL_FILE) -r " << dst << "\n\t"
+ << "@$(COPY_DIR) " << src << " " << dst << endl;
+ else
+ t << "@$(DEL_FILE) " << dst << "\n\t"
+ << "@$(COPY_FILE) " << src << " " << dst << endl;
+ }
+ }
+ }
+ }
+
+ ProString ddir;
+ ProString packageName(project->first("QMAKE_ORIG_TARGET"));
+ if(!project->isActiveConfig("no_dist_version"))
+ packageName += var("VERSION");
+ if (project->isEmpty("QMAKE_DISTDIR"))
+ ddir = packageName;
+ else
+ ddir = project->first("QMAKE_DISTDIR");
+
+ QString ddir_c = escapeFilePath(fileFixify((project->isEmpty("OBJECTS_DIR") ? ProString(".tmp/") :
+ project->first("OBJECTS_DIR")) + ddir,
+ Option::output_dir, Option::output_dir));
+ t << "dist: \n\t"
+ << mkdir_p_asstring(ddir_c, false) << "\n\t"
+ << "$(COPY_FILE) --parents $(DIST) " << ddir_c << Option::dir_sep << " && ";
+ if(!project->isEmpty("QMAKE_EXTRA_COMPILERS")) {
+ const ProStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
+ for (ProStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
+ const ProStringList &var = project->values(ProKey(*it + ".input"));
+ for (ProStringList::ConstIterator var_it = var.begin(); var_it != var.end(); ++var_it) {
+ const ProStringList &val = project->values((*var_it).toKey());
+ if(val.isEmpty())
+ continue;
+ t << "$(COPY_FILE) --parents " << val.join(' ') << " " << ddir_c << Option::dir_sep << " && ";
+ }
+ }
+ }
+ if(!project->isEmpty("TRANSLATIONS"))
+ t << "$(COPY_FILE) --parents " << var("TRANSLATIONS") << " " << ddir_c << Option::dir_sep << " && ";
+ t << "(cd `dirname " << ddir_c << "` && "
+ << "$(TAR) " << packageName << ".tar " << ddir << " && "
+ << "$(COMPRESS) " << packageName << ".tar) && "
+ << "$(MOVE) `dirname " << ddir_c << "`" << Option::dir_sep << packageName << ".tar.gz . && "
+ << "$(DEL_FILE) -r " << ddir_c
+ << endl << endl;
+
+ t << endl;
+
+ QString clean_targets = "compiler_clean " + var("CLEAN_DEPS");
+ if(do_incremental) {
+ t << "incrclean:\n";
+ if(src_incremental)
+ t << "\t-$(DEL_FILE) $(INCREMENTAL_OBJECTS)\n";
+ t << endl;
+ }
+
+ t << "clean:" << clean_targets << "\n\t";
+ if(!project->isEmpty("OBJECTS")) {
+ if(project->isActiveConfig("compile_libtool"))
+ t << "-$(LIBTOOL) --mode=clean $(DEL_FILE) $(OBJECTS)\n\t";
+ else
+ t << "-$(DEL_FILE) $(OBJECTS)\n\t";
+ }
+ if(doPrecompiledHeaders() && !project->isEmpty("PRECOMPILED_HEADER")) {
+ ProStringList precomp_files;
+ ProString precomph_out_dir;
+
+ if(!project->isEmpty("PRECOMPILED_DIR"))
+ precomph_out_dir = project->first("PRECOMPILED_DIR");
+ precomph_out_dir += project->first("QMAKE_ORIG_TARGET");
+ if (!project->isActiveConfig("clang_pch_style"))
+ precomph_out_dir += project->first("QMAKE_PCH_OUTPUT_EXT");
+
+ if (project->isActiveConfig("icc_pch_style")) {
+ // icc style
+ ProString pchBaseName = project->first("QMAKE_ORIG_TARGET");
+ ProString pchOutput;
+ if(!project->isEmpty("PRECOMPILED_DIR"))
+ pchOutput = project->first("PRECOMPILED_DIR");
+ pchOutput += pchBaseName + project->first("QMAKE_PCH_OUTPUT_EXT");
+ ProString sourceFile = pchOutput + Option::cpp_ext.first();
+ ProString objectFile = createObjectList(ProStringList(sourceFile)).first();
+
+ precomp_files << precomph_out_dir << sourceFile << objectFile;
+ } else {
+ // gcc style (including clang_pch_style)
+ precomph_out_dir += Option::dir_sep;
+
+ ProString header_prefix = project->first("QMAKE_PRECOMP_PREFIX");
+ ProString header_suffix = project->isActiveConfig("clang_pch_style")
+ ? project->first("QMAKE_PCH_OUTPUT_EXT") : "";
+
+ if(!project->isEmpty("QMAKE_CFLAGS_PRECOMPILE"))
+ precomp_files += precomph_out_dir + header_prefix + "c" + header_suffix;
+ if(!project->isEmpty("QMAKE_CXXFLAGS_PRECOMPILE"))
+ precomp_files += precomph_out_dir + header_prefix + "c++" + header_suffix;
+ if(project->isActiveConfig("objective_c")) {
+ if(!project->isEmpty("QMAKE_OBJCFLAGS_PRECOMPILE"))
+ precomp_files += precomph_out_dir + header_prefix + "objective-c" + header_suffix;
+ if(!project->isEmpty("QMAKE_OBJCXXFLAGS_PRECOMPILE"))
+ precomp_files += precomph_out_dir + header_prefix + "objective-c++" + header_suffix;
+ }
+ }
+ t << "-$(DEL_FILE) " << precomp_files.join(' ') << "\n\t";
+ }
+ if(!project->isEmpty("IMAGES"))
+ t << varGlue("QMAKE_IMAGE_COLLECTION", "\t-$(DEL_FILE) ", " ", "") << "\n\t";
+ if(src_incremental)
+ t << "-$(DEL_FILE) $(INCREMENTAL_OBJECTS)\n\t";
+ t << varGlue("QMAKE_CLEAN","-$(DEL_FILE) "," ","\n\t")
+ << "-$(DEL_FILE) *~ core *.core\n"
+ << varGlue("CLEAN_FILES","\t-$(DEL_FILE) "," ","") << endl << endl;
+
+ ProString destdir = project->first("DESTDIR");
+ if (!destdir.isEmpty() && !destdir.endsWith(Option::dir_sep))
+ destdir += Option::dir_sep;
+ t << "distclean: clean " << var("DISTCLEAN_DEPS") << '\n';
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ QString bundlePath = escapeFilePath(destdir + project->first("QMAKE_BUNDLE"));
+ t << "\t-$(DEL_FILE) -r " << bundlePath << endl;
+ } else if(project->isActiveConfig("compile_libtool")) {
+ t << "\t-$(LIBTOOL) --mode=clean $(DEL_FILE) $(TARGET)\n";
+ } else if(!project->isActiveConfig("staticlib") && project->values("QMAKE_APP_FLAG").isEmpty() &&
+ !project->isActiveConfig("plugin")) {
+ t << "\t-$(DEL_FILE) " << destdir << "$(TARGET) \n";
+ if (!project->isActiveConfig("unversioned_libname")) {
+ t << "\t-$(DEL_FILE) " << destdir << "$(TARGET0) " << destdir << "$(TARGET1) "
+ << destdir << "$(TARGET2) $(TARGETA)\n";
+ } else {
+ t << "\t-$(DEL_FILE) $(TARGETA)\n";
+ }
+ } else {
+ t << "\t-$(DEL_FILE) " << destdir << "$(TARGET) \n";
+ }
+ t << varGlue("QMAKE_DISTCLEAN","\t-$(DEL_FILE) "," ","\n");
+ {
+ QString ofile = Option::fixPathToTargetOS(fileFixify(Option::output.fileName()));
+ if(!ofile.isEmpty())
+ t << "\t-$(DEL_FILE) " << ofile << endl;
+ }
+ t << endl << endl;
+
+ t << "####### Sub-libraries\n\n";
+ if (!project->values("SUBLIBS").isEmpty()) {
+ ProString libdir = "tmp/";
+ if (!project->isEmpty("SUBLIBS_DIR"))
+ libdir = project->first("SUBLIBS_DIR");
+ const ProStringList &l = project->values("SUBLIBS");
+ for (it = l.begin(); it != l.end(); ++it)
+ t << libdir << project->first("QMAKE_PREFIX_STATICLIB") << (*it) << "."
+ << project->first("QMAKE_EXTENSION_STATICLIB") << ":\n\t"
+ << var(ProKey("MAKELIB" + *it)) << endl << endl;
+ }
+
+ if(doPrecompiledHeaders() && !project->isEmpty("PRECOMPILED_HEADER")) {
+ QString pchInput = project->first("PRECOMPILED_HEADER").toQString();
+ t << "###### Precompiled headers\n";
+ QString comps[] = { "C", "CXX", "OBJC", "OBJCXX", QString() };
+ for(int i = 0; !comps[i].isNull(); i++) {
+ QString pchFlags = var(ProKey("QMAKE_" + comps[i] + "FLAGS_PRECOMPILE"));
+ if(pchFlags.isEmpty())
+ continue;
+
+ QString cflags;
+ if(comps[i] == "OBJC" || comps[i] == "OBJCXX")
+ cflags += " $(CFLAGS)";
+ else
+ cflags += " $(" + comps[i] + "FLAGS)";
+
+ ProString pchBaseName = project->first("QMAKE_ORIG_TARGET");
+ ProString pchOutput;
+ if(!project->isEmpty("PRECOMPILED_DIR"))
+ pchOutput = project->first("PRECOMPILED_DIR");
+ pchOutput += pchBaseName;
+ if (!project->isActiveConfig("clang_pch_style"))
+ pchOutput += project->first("QMAKE_PCH_OUTPUT_EXT");
+
+ if (project->isActiveConfig("icc_pch_style")) {
+ // icc style
+ QString sourceFile = pchOutput + Option::cpp_ext.first();
+ QString objectFile = createObjectList(ProStringList(sourceFile)).first().toQString();
+ t << pchOutput << ": " << pchInput << " " << findDependencies(pchInput).join(" \\\n\t\t")
+ << "\n\techo \"// Automatically generated, do not modify\" > " << sourceFile
+ << "\n\trm -f " << pchOutput;
+
+ pchFlags = pchFlags.replace("${QMAKE_PCH_TEMP_SOURCE}", sourceFile)
+ .replace("${QMAKE_PCH_TEMP_OBJECT}", objectFile);
+ } else {
+ // gcc style (including clang_pch_style)
+ ProString header_prefix = project->first("QMAKE_PRECOMP_PREFIX");
+ ProString header_suffix = project->isActiveConfig("clang_pch_style")
+ ? project->first("QMAKE_PCH_OUTPUT_EXT") : "";
+ pchOutput += Option::dir_sep;
+ QString pchOutputDir = pchOutput.toQString(), pchOutputFile;
+
+ if(comps[i] == "C") {
+ pchOutputFile = "c";
+ } else if(comps[i] == "CXX") {
+ pchOutputFile = "c++";
+ } else if(project->isActiveConfig("objective_c")) {
+ if(comps[i] == "OBJC")
+ pchOutputFile = "objective-c";
+ else if(comps[i] == "OBJCXX")
+ pchOutputFile = "objective-c++";
+ }
+ if(pchOutputFile.isEmpty())
+ continue;
+ pchOutput += header_prefix + pchOutputFile + header_suffix;
+
+ t << pchOutput << ": " << pchInput << " " << findDependencies(pchInput).join(" \\\n\t\t")
+ << "\n\t" << mkdir_p_asstring(pchOutputDir);
+ }
+ pchFlags = pchFlags.replace("${QMAKE_PCH_INPUT}", pchInput)
+ .replace("${QMAKE_PCH_OUTPUT_BASE}", pchBaseName.toQString())
+ .replace("${QMAKE_PCH_OUTPUT}", pchOutput.toQString());
+
+ QString compiler;
+ if(comps[i] == "C" || comps[i] == "OBJC" || comps[i] == "OBJCXX")
+ compiler = "$(CC)";
+ else
+ compiler = "$(CXX)";
+
+ // compile command
+ t << "\n\t" << compiler << cflags << " $(INCPATH) " << pchFlags << endl << endl;
+ }
+ }
+
+ writeExtraTargets(t);
+ writeExtraCompilerTargets(t);
+}
+
+void UnixMakefileGenerator::init2()
+{
+ if(project->isEmpty("QMAKE_FRAMEWORK_VERSION"))
+ project->values("QMAKE_FRAMEWORK_VERSION").append(project->values("VER_MAJ").first());
+
+ if (project->values("TEMPLATE").first() == "aux")
+ return;
+
+ if (!project->values("QMAKE_APP_FLAG").isEmpty()) {
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ ProString bundle_loc = project->first("QMAKE_BUNDLE_LOCATION");
+ if(!bundle_loc.isEmpty() && !bundle_loc.startsWith("/"))
+ bundle_loc.prepend("/");
+ if(!bundle_loc.endsWith("/"))
+ bundle_loc += "/";
+ project->values("TARGET").first().prepend(project->first("QMAKE_BUNDLE") + bundle_loc);
+ }
+ if(!project->isEmpty("TARGET"))
+ project->values("TARGET").first().prepend(project->first("DESTDIR"));
+ if (!project->values("QMAKE_CYGWIN_EXE").isEmpty())
+ project->values("TARGET_EXT").append(".exe");
+ } else if (project->isActiveConfig("staticlib")) {
+ project->values("TARGET").first().prepend(project->first("QMAKE_PREFIX_STATICLIB"));
+ project->values("TARGET").first() += "." + project->first("QMAKE_EXTENSION_STATICLIB");
+ if(project->values("QMAKE_AR_CMD").isEmpty())
+ project->values("QMAKE_AR_CMD").append("$(AR) $(TARGET) $(OBJECTS)");
+ } else {
+ project->values("TARGETA").append(project->first("DESTDIR") + project->first("QMAKE_PREFIX_STATICLIB")
+ + project->first("TARGET") + "." + project->first("QMAKE_EXTENSION_STATICLIB"));
+ if(project->isActiveConfig("compile_libtool"))
+ project->values("TARGET_la") = ProStringList(project->first("DESTDIR") + "lib" + project->first("TARGET") + Option::libtool_ext);
+
+ ProStringList &ar_cmd = project->values("QMAKE_AR_CMD");
+ if (!ar_cmd.isEmpty())
+ ar_cmd[0] = ar_cmd.at(0).toQString().replace("(TARGET)","(TARGETA)");
+ else
+ ar_cmd.append("$(AR) $(TARGETA) $(OBJECTS)");
+ if(project->isActiveConfig("compile_libtool")) {
+ project->values("TARGET") = project->values("TARGET_la");
+ } else if(!project->isEmpty("QMAKE_BUNDLE")) {
+ ProString bundle_loc = project->first("QMAKE_BUNDLE_LOCATION");
+ if(!bundle_loc.isEmpty() && !bundle_loc.startsWith("/"))
+ bundle_loc.prepend("/");
+ if(!bundle_loc.endsWith("/"))
+ bundle_loc += "/";
+ project->values("TARGET_").append(project->first("QMAKE_BUNDLE") +
+ bundle_loc + unescapeFilePath(project->first("TARGET")));
+ project->values("TARGET_x.y").append(project->first("QMAKE_BUNDLE") +
+ "/Versions/" +
+ project->first("QMAKE_FRAMEWORK_VERSION") +
+ bundle_loc + unescapeFilePath(project->first("TARGET")));
+ } else if(project->isActiveConfig("plugin")) {
+ QString prefix;
+ if(!project->isActiveConfig("no_plugin_name_prefix"))
+ prefix = "lib";
+ project->values("TARGET_x.y.z").append(prefix +
+ project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_PLUGIN"));
+ if(project->isActiveConfig("lib_version_first"))
+ project->values("TARGET_x").append(prefix + project->first("TARGET") + "." +
+ project->first("VER_MAJ") + "." +
+ project->first("QMAKE_EXTENSION_PLUGIN"));
+ else
+ project->values("TARGET_x").append(prefix + project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_PLUGIN") +
+ "." + project->first("VER_MAJ"));
+ project->values("TARGET") = project->values("TARGET_x.y.z");
+ } else if (!project->isEmpty("QMAKE_HPUX_SHLIB")) {
+ project->values("TARGET_").append("lib" + project->first("TARGET") + ".sl");
+ if(project->isActiveConfig("lib_version_first"))
+ project->values("TARGET_x").append("lib" + project->first("VER_MAJ") + "." +
+ project->first("TARGET"));
+ else
+ project->values("TARGET_x").append("lib" + project->first("TARGET") + "." +
+ project->first("VER_MAJ"));
+ project->values("TARGET") = project->values("TARGET_x");
+ } else if (!project->isEmpty("QMAKE_AIX_SHLIB")) {
+ project->values("TARGET_").append(project->first("QMAKE_PREFIX_STATICLIB") + project->first("TARGET")
+ + "." + project->first("QMAKE_EXTENSION_STATICLIB"));
+ if(project->isActiveConfig("lib_version_first")) {
+ project->values("TARGET_x").append("lib" + project->first("TARGET") + "." +
+ project->first("VER_MAJ") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB"));
+ project->values("TARGET_x.y").append("lib" + project->first("TARGET") + "." +
+ project->first("VER_MAJ") +
+ "." + project->first("VER_MIN") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB"));
+ project->values("TARGET_x.y.z").append("lib" + project->first("TARGET") + "." +
+ project->first("VER_MAJ") + "." +
+ project->first("VER_MIN") + "." +
+ project->first("VER_PAT") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB"));
+ } else {
+ project->values("TARGET_x").append("lib" + project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB") +
+ "." + project->first("VER_MAJ"));
+ project->values("TARGET_x.y").append("lib" + project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB") +
+ "." + project->first("VER_MAJ") +
+ "." + project->first("VER_MIN"));
+ project->values("TARGET_x.y.z").append("lib" + project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB") + "." +
+ project->first("VER_MAJ") + "." +
+ project->first("VER_MIN") + "." +
+ project->first("VER_PAT"));
+ }
+ project->values("TARGET") = project->values("TARGET_x.y.z");
+ } else {
+ project->values("TARGET_").append("lib" + project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB"));
+ if(project->isActiveConfig("lib_version_first")) {
+ project->values("TARGET_x").append("lib" + project->first("TARGET") + "." +
+ project->first("VER_MAJ") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB"));
+ project->values("TARGET_x.y").append("lib" + project->first("TARGET") + "." +
+ project->first("VER_MAJ") +
+ "." + project->first("VER_MIN") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB"));
+ project->values("TARGET_x.y.z").append("lib" + project->first("TARGET") + "." +
+ project->first("VER_MAJ") + "." +
+ project->first("VER_MIN") + "." +
+ project->first("VER_PAT") + "." +
+ project->values("QMAKE_EXTENSION_SHLIB").first());
+ } else {
+ project->values("TARGET_x").append("lib" + project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB") +
+ "." + project->first("VER_MAJ"));
+ project->values("TARGET_x.y").append("lib" + project->first("TARGET") + "." +
+ project->first("QMAKE_EXTENSION_SHLIB")
+ + "." + project->first("VER_MAJ") +
+ "." + project->first("VER_MIN"));
+ project->values("TARGET_x.y.z").append("lib" + project->first("TARGET") +
+ "." +
+ project->values(
+ "QMAKE_EXTENSION_SHLIB").first() + "." +
+ project->first("VER_MAJ") + "." +
+ project->first("VER_MIN") + "." +
+ project->first("VER_PAT"));
+ }
+ if (project->isActiveConfig("unversioned_libname"))
+ project->values("TARGET") = project->values("TARGET_");
+ else
+ project->values("TARGET") = project->values("TARGET_x.y.z");
+ }
+ if(project->isEmpty("QMAKE_LN_SHLIB"))
+ project->values("QMAKE_LN_SHLIB").append("ln -s");
+ if (!project->values("QMAKE_LFLAGS_SONAME").isEmpty()) {
+ ProString soname;
+ if(project->isActiveConfig("plugin")) {
+ if(!project->values("TARGET").isEmpty())
+ soname += project->first("TARGET");
+ } else if(!project->isEmpty("QMAKE_BUNDLE")) {
+ soname += project->first("TARGET_x.y");
+ } else if(project->isActiveConfig("unversioned_soname")) {
+ soname = "lib" + project->first("QMAKE_ORIG_TARGET")
+ + "." + project->first("QMAKE_EXTENSION_SHLIB");
+ } else if(!project->values("TARGET_x").isEmpty()) {
+ soname += project->first("TARGET_x");
+ }
+ if(!soname.isEmpty()) {
+ if(project->isActiveConfig("absolute_library_soname") &&
+ project->values("INSTALLS").indexOf("target") != -1 &&
+ !project->isEmpty("target.path")) {
+ QString instpath = Option::fixPathToTargetOS(project->first("target.path").toQString());
+ if(!instpath.endsWith(Option::dir_sep))
+ instpath += Option::dir_sep;
+ soname.prepend(instpath);
+ }
+ project->values("QMAKE_LFLAGS_SONAME").first() += escapeFilePath(soname);
+ }
+ }
+ if (project->values("QMAKE_LINK_SHLIB_CMD").isEmpty())
+ project->values("QMAKE_LINK_SHLIB_CMD").append(
+ "$(LINK) $(LFLAGS) " + project->first("QMAKE_LINK_O_FLAG") + "$(TARGET) $(OBJECTS) $(LIBS) $(OBJCOMP)");
+ }
+ if (!project->values("QMAKE_APP_FLAG").isEmpty()) {
+ project->values("QMAKE_CFLAGS") += project->values("QMAKE_CFLAGS_APP");
+ project->values("QMAKE_CXXFLAGS") += project->values("QMAKE_CXXFLAGS_APP");
+ project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_APP");
+ } else if (project->isActiveConfig("dll")) {
+ if(!project->isActiveConfig("plugin") || !project->isActiveConfig("plugin_no_share_shlib_cflags")) {
+ project->values("QMAKE_CFLAGS") += project->values("QMAKE_CFLAGS_SHLIB");
+ project->values("QMAKE_CXXFLAGS") += project->values("QMAKE_CXXFLAGS_SHLIB");
+ }
+ if (project->isActiveConfig("plugin")) {
+ project->values("QMAKE_CFLAGS") += project->values("QMAKE_CFLAGS_PLUGIN");
+ project->values("QMAKE_CXXFLAGS") += project->values("QMAKE_CXXFLAGS_PLUGIN");
+ project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_PLUGIN");
+ if(project->isActiveConfig("plugin_with_soname") && !project->isActiveConfig("compile_libtool"))
+ project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_SONAME");
+ } else {
+ project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_SHLIB");
+ if(!project->isEmpty("QMAKE_LFLAGS_COMPAT_VERSION")) {
+ if(project->isEmpty("COMPAT_VERSION"))
+ project->values("QMAKE_LFLAGS") += QString(project->first("QMAKE_LFLAGS_COMPAT_VERSION") +
+ project->first("VER_MAJ") + "." +
+ project->first("VER_MIN"));
+ else
+ project->values("QMAKE_LFLAGS") += QString(project->first("QMAKE_LFLAGS_COMPAT_VERSION") +
+ project->first("COMPATIBILITY_VERSION"));
+ }
+ if(!project->isEmpty("QMAKE_LFLAGS_VERSION")) {
+ project->values("QMAKE_LFLAGS") += QString(project->first("QMAKE_LFLAGS_VERSION") +
+ project->first("VER_MAJ") + "." +
+ project->first("VER_MIN") + "." +
+ project->first("VER_PAT"));
+ }
+ if(!project->isActiveConfig("compile_libtool"))
+ project->values("QMAKE_LFLAGS") += project->values("QMAKE_LFLAGS_SONAME");
+ }
+ }
+
+ if (include_deps && project->isActiveConfig("gcc_MD_depends")) {
+ // use -MMD if we know about -isystem too
+ ProString MD_flag(project->values("QMAKE_CFLAGS_ISYSTEM").isEmpty() ? "-MD" : "-MMD");
+ project->values("QMAKE_CFLAGS") += MD_flag;
+ project->values("QMAKE_CXXFLAGS") += MD_flag;
+ }
+
+ if(!project->isEmpty("QMAKE_BUNDLE")) {
+ QString plist = fileFixify(project->first("QMAKE_INFO_PLIST").toQString(), qmake_getpwd());
+ if(plist.isEmpty())
+ plist = specdir() + QDir::separator() + "Info.plist." + project->first("TEMPLATE");
+ if(exists(Option::fixPathToLocalOS(plist))) {
+ project->values("QMAKE_INFO_PLIST_OUT").append(project->first("DESTDIR") +
+ project->first("QMAKE_BUNDLE") +
+ "/Contents/Info.plist");
+ project->values("ALL_DEPS") += project->first("QMAKE_INFO_PLIST_OUT");
+ if(!project->isEmpty("ICON") && project->first("TEMPLATE") == "app")
+ project->values("ALL_DEPS") += project->first("DESTDIR") +
+ project->first("QMAKE_BUNDLE") +
+ "/Contents/Resources/" + project->first("ICON").toQString().section('/', -1);
+ if(!project->isEmpty("QMAKE_BUNDLE_DATA")) {
+ QString bundle_dir = project->first("DESTDIR") + project->first("QMAKE_BUNDLE") + "/";
+ ProStringList &alldeps = project->values("ALL_DEPS");
+ const ProStringList &bundle_data = project->values("QMAKE_BUNDLE_DATA");
+ for(int i = 0; i < bundle_data.count(); i++) {
+ const ProStringList &files = project->values(ProKey(bundle_data[i] + ".files"));
+ QString path = bundle_dir;
+ const ProKey vkey(bundle_data[i] + ".version");
+ const ProKey pkey(bundle_data[i] + ".path");
+ if (!project->isEmpty(vkey)) {
+ alldeps += Option::fixPathToLocalOS(path + Option::dir_sep + project->first(pkey));
+ path += project->first(vkey) + "/" +
+ project->first("QMAKE_FRAMEWORK_VERSION") + "/";
+ }
+ path += project->first(pkey);
+ path = Option::fixPathToLocalOS(path);
+ for(int file = 0; file < files.count(); file++)
+ alldeps += path + Option::dir_sep + fileInfo(files[file].toQString()).fileName();
+ }
+ }
+ } else {
+ warn_msg(WarnLogic, "Could not resolve Info.plist: '%s'. Check if QMAKE_INFO_PLIST points to a valid file.", plist.toLatin1().constData());
+ }
+ }
+}
+
+QString
+UnixMakefileGenerator::libtoolFileName(bool fixify)
+{
+ QString ret = var("TARGET");
+ int slsh = ret.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ ret = ret.right(ret.length() - slsh - 1);
+ int dot = ret.indexOf('.');
+ if(dot != -1)
+ ret = ret.left(dot);
+ ret += Option::libtool_ext;
+ if(!project->isEmpty("QMAKE_LIBTOOL_DESTDIR"))
+ ret.prepend(project->first("QMAKE_LIBTOOL_DESTDIR") + Option::dir_sep);
+ if(fixify) {
+ if(QDir::isRelativePath(ret) && !project->isEmpty("DESTDIR"))
+ ret.prepend(project->first("DESTDIR").toQString());
+ ret = Option::fixPathToLocalOS(fileFixify(ret, qmake_getpwd(), Option::output_dir));
+ }
+ return ret;
+}
+
+void
+UnixMakefileGenerator::writeLibtoolFile()
+{
+ QString fname = libtoolFileName(), lname = fname;
+ mkdir(fileInfo(fname).path());
+ int slsh = lname.lastIndexOf(Option::dir_sep);
+ if(slsh != -1)
+ lname = lname.right(lname.length() - slsh - 1);
+ QFile ft(fname);
+ if(!ft.open(QIODevice::WriteOnly))
+ return;
+ project->values("ALL_DEPS").append(fileFixify(fname));
+
+ QTextStream t(&ft);
+ t << "# " << lname << " - a libtool library file\n";
+ t << "# Generated by qmake/libtool (" QMAKE_VERSION_STR ") (Qt "
+ << QT_VERSION_STR << ")";
+ t << "\n";
+
+ t << "# The name that we can dlopen(3).\n"
+ << "dlname='" << var(project->isActiveConfig("plugin") ? "TARGET" : "TARGET_x")
+ << "'\n\n";
+
+ t << "# Names of this library.\n";
+ t << "library_names='";
+ if(project->isActiveConfig("plugin")) {
+ t << var("TARGET");
+ } else {
+ if (project->isEmpty("QMAKE_HPUX_SHLIB"))
+ t << var("TARGET_x.y.z") << " ";
+ t << var("TARGET_x") << " " << var("TARGET_");
+ }
+ t << "'\n\n";
+
+ t << "# The name of the static archive.\n"
+ << "old_library='" << lname.left(lname.length()-Option::libtool_ext.length()) << ".a'\n\n";
+
+ t << "# Libraries that this one depends upon.\n";
+ ProStringList libs;
+ if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS"))
+ libs = project->values("QMAKE_INTERNAL_PRL_LIBS");
+ else
+ libs << "QMAKE_LIBS"; //obvious one
+ t << "dependency_libs='";
+ for (ProStringList::ConstIterator it = libs.begin(); it != libs.end(); ++it)
+ t << project->values((*it).toKey()).join(' ') << " ";
+ t << "'\n\n";
+
+ t << "# Version information for " << lname << "\n";
+ int maj = project->first("VER_MAJ").toInt();
+ int min = project->first("VER_MIN").toInt();
+ int pat = project->first("VER_PAT").toInt();
+ t << "current=" << (10*maj + min) << "\n" // best I can think of
+ << "age=0\n"
+ << "revision=" << pat << "\n\n";
+
+ t << "# Is this an already installed library.\n"
+ "installed=yes\n\n"; // ###
+
+ t << "# Files to dlopen/dlpreopen.\n"
+ "dlopen=''\n"
+ "dlpreopen=''\n\n";
+
+ ProString install_dir = project->first("QMAKE_LIBTOOL_LIBDIR");
+ if(install_dir.isEmpty())
+ install_dir = project->first("target.path");
+ if(install_dir.isEmpty())
+ install_dir = project->first("DESTDIR");
+ t << "# Directory that this library needs to be installed in:\n"
+ "libdir='" << Option::fixPathToTargetOS(install_dir.toQString(), false) << "'\n";
+}
+
+QT_END_NAMESPACE
diff -Naur qt-everywhere-opensource-src-5.3.1/qtbase/src/corelib/arch/qatomic_bootstrap.h qt-everywhere-opensource-src-5.3.1.new/qtbase/src/corelib/arch/qatomic_bootstrap.h
--- qt-everywhere-opensource-src-5.3.1/qtbase/src/corelib/arch/qatomic_bootstrap.h 2014-06-19 12:08:07.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtbase/src/corelib/arch/qatomic_bootstrap.h 2014-08-13 04:35:08.404435894 +0200
@@ -67,8 +67,10 @@
return --_q_value != 0;
}
- static bool testAndSetRelaxed(T &_q_value, T expectedValue, T newValue) Q_DECL_NOTHROW
+ static bool testAndSetRelaxed(T &_q_value, T expectedValue, T newValue, T *currentValue = 0) Q_DECL_NOTHROW
{
+ if (currentValue)
+ *currentValue = _q_value;
if (_q_value == expectedValue) {
_q_value = newValue;
return true;
diff -Naur qt-everywhere-opensource-src-5.3.1/qtbase/src/corelib/io/qloggingcategory.cpp qt-everywhere-opensource-src-5.3.1.new/qtbase/src/corelib/io/qloggingcategory.cpp
--- qt-everywhere-opensource-src-5.3.1/qtbase/src/corelib/io/qloggingcategory.cpp 2014-06-19 12:08:07.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtbase/src/corelib/io/qloggingcategory.cpp 2014-08-13 04:35:08.404435894 +0200
@@ -50,6 +50,18 @@
Q_GLOBAL_STATIC_WITH_ARGS(QLoggingCategory, qtDefaultCategory,
(qtDefaultCategoryName))
+#ifndef Q_ATOMIC_INT8_IS_SUPPORTED
+static void setBoolLane(QBasicAtomicInt *atomic, bool enable, int shift)
+{
+ const int bit = 1 << shift;
+
+ if (enable)
+ atomic->fetchAndOrRelaxed(bit);
+ else
+ atomic->fetchAndAndRelaxed(~bit);
+}
+#endif
+
/*!
\class QLoggingCategory
\inmodule QtCore
@@ -171,13 +183,11 @@
*/
QLoggingCategory::QLoggingCategory(const char *category)
: d(0),
- name(0),
- enabledDebug(true),
- enabledWarning(true),
- enabledCritical(true)
+ name(0)
{
Q_UNUSED(d);
Q_UNUSED(placeholder);
+ enabled.store(0x01010101); // enabledDebug = enabledWarning = enabledCritical = true;
const bool isDefaultCategory
= (category == 0) || (strcmp(category, qtDefaultCategoryName) == 0);
@@ -249,9 +259,9 @@
bool QLoggingCategory::isEnabled(QtMsgType msgtype) const
{
switch (msgtype) {
- case QtDebugMsg: return enabledDebug;
- case QtWarningMsg: return enabledWarning;
- case QtCriticalMsg: return enabledCritical;
+ case QtDebugMsg: return isDebugEnabled();
+ case QtWarningMsg: return isWarningEnabled();
+ case QtCriticalMsg: return isCriticalEnabled();
case QtFatalMsg: return true;
}
return false;
@@ -270,9 +280,15 @@
void QLoggingCategory::setEnabled(QtMsgType type, bool enable)
{
switch (type) {
- case QtDebugMsg: enabledDebug = enable; break;
- case QtWarningMsg: enabledWarning = enable; break;
- case QtCriticalMsg: enabledCritical = enable; break;
+#ifdef Q_ATOMIC_INT8_IS_SUPPORTED
+ case QtDebugMsg: bools.enabledDebug.store(enable); break;
+ case QtWarningMsg: bools.enabledWarning.store(enable); break;
+ case QtCriticalMsg: bools.enabledCritical.store(enable); break;
+#else
+ case QtDebugMsg: setBoolLane(&enabled, enable, DebugShift); break;
+ case QtWarningMsg: setBoolLane(&enabled, enable, WarningShift); break;
+ case QtCriticalMsg: setBoolLane(&enabled, enable, CriticalShift); break;
+#endif
case QtFatalMsg: break;
}
}
diff -Naur qt-everywhere-opensource-src-5.3.1/qtbase/src/corelib/io/qloggingcategory.h qt-everywhere-opensource-src-5.3.1.new/qtbase/src/corelib/io/qloggingcategory.h
--- qt-everywhere-opensource-src-5.3.1/qtbase/src/corelib/io/qloggingcategory.h 2014-06-19 12:08:07.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtbase/src/corelib/io/qloggingcategory.h 2014-08-13 04:35:08.405435896 +0200
@@ -57,10 +57,15 @@
bool isEnabled(QtMsgType type) const;
void setEnabled(QtMsgType type, bool enable);
- bool isDebugEnabled() const { return enabledDebug; }
- bool isWarningEnabled() const { return enabledWarning; }
- bool isCriticalEnabled() const { return enabledCritical; }
-
+#ifdef Q_ATOMIC_INT8_IS_SUPPORTED
+ bool isDebugEnabled() const { return bools.enabledDebug.load(); }
+ bool isWarningEnabled() const { return bools.enabledWarning.load(); }
+ bool isCriticalEnabled() const { return bools.enabledCritical.load(); }
+#else
+ bool isDebugEnabled() const { return enabled.load() >> DebugShift & 1; }
+ bool isWarningEnabled() const { return enabled.load() >> WarningShift & 1; }
+ bool isCriticalEnabled() const { return enabled.load() >> CriticalShift & 1; }
+#endif
const char *categoryName() const { return name; }
// allows usage of both factory method and variable in qCX macros
@@ -78,10 +83,24 @@
void *d; // reserved for future use
const char *name;
- bool enabledDebug;
- bool enabledWarning;
- bool enabledCritical;
- bool placeholder[5]; // reserve for future use
+#ifdef Q_BIG_ENDIAN
+ enum { DebugShift = 0, WarningShift = 8, CriticalShift = 16 };
+#else
+ enum { DebugShift = 24, WarningShift = 16, CriticalShift = 8 };
+#endif
+
+ struct AtomicBools {
+#ifdef Q_ATOMIC_INT8_IS_SUPPORTED
+ QBasicAtomicInteger<bool> enabledDebug;
+ QBasicAtomicInteger<bool> enabledWarning;
+ QBasicAtomicInteger<bool> enabledCritical;
+#endif
+ };
+ union {
+ AtomicBools bools;
+ QBasicAtomicInt enabled;
+ };
+ bool placeholder[4]; // reserve for future use
};
#define Q_DECLARE_LOGGING_CATEGORY(name) \
diff -Naur qt-everywhere-opensource-src-5.3.1/qtbase/src/dbus/qdbusintegrator.cpp qt-everywhere-opensource-src-5.3.1.new/qtbase/src/dbus/qdbusintegrator.cpp
--- qt-everywhere-opensource-src-5.3.1/qtbase/src/dbus/qdbusintegrator.cpp 2014-06-19 12:08:02.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtbase/src/dbus/qdbusintegrator.cpp 2014-08-13 04:35:08.409435892 +0200
@@ -73,18 +73,24 @@
QT_BEGIN_NAMESPACE
-static bool isDebugging;
-#define qDBusDebug if (!::isDebugging); else qDebug
+static QBasicAtomicInt isDebugging = Q_BASIC_ATOMIC_INITIALIZER(-1);
+#define qDBusDebug if (::isDebugging == 0); else qDebug
-Q_GLOBAL_STATIC_WITH_ARGS(const QString, orgFreedesktopDBusString, (QLatin1String(DBUS_SERVICE_DBUS)))
+QString orgFreedesktopDBusString()
+{
+ return QStringLiteral(DBUS_SERVICE_DBUS);
+}
static inline QString dbusServiceString()
-{ return *orgFreedesktopDBusString(); }
+{
+ return orgFreedesktopDBusString();
+}
+
static inline QString dbusInterfaceString()
{
// it's the same string, but just be sure
- Q_ASSERT(*orgFreedesktopDBusString() == QLatin1String(DBUS_INTERFACE_DBUS));
- return *orgFreedesktopDBusString();
+ Q_ASSERT(orgFreedesktopDBusString() == QLatin1String(DBUS_INTERFACE_DBUS));
+ return orgFreedesktopDBusString();
}
static inline QDebug operator<<(QDebug dbg, const QThread *th)
@@ -1022,13 +1028,12 @@
anonymousAuthenticationAllowed(false)
{
static const bool threads = q_dbus_threads_init_default();
- static const int debugging = qgetenv("QDBUS_DEBUG").toInt();
- ::isDebugging = debugging;
+ if (::isDebugging == -1)
+ ::isDebugging = qgetenv("QDBUS_DEBUG").toInt();
Q_UNUSED(threads)
- Q_UNUSED(debugging)
#ifdef QDBUS_THREAD_DEBUG
- if (debugging > 1)
+ if (::isDebugging > 1)
qdbusThreadDebug = qdbusDefaultThreadDebug;
#endif
@@ -2267,7 +2272,7 @@
watchedServices.erase(sit);
disconnectSignal(dbusServiceString(), QString(), dbusInterfaceString(),
QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(),
- this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
+ this, SLOT(serviceOwnerChangedNoLock(QString,QString,QString)));
}
}
}
diff -Naur qt-everywhere-opensource-src-5.3.1/qtbase/src/dbus/qdbusintegrator.cpp.orig qt-everywhere-opensource-src-5.3.1.new/qtbase/src/dbus/qdbusintegrator.cpp.orig
--- qt-everywhere-opensource-src-5.3.1/qtbase/src/dbus/qdbusintegrator.cpp.orig 1970-01-01 01:00:00.000000000 +0100
+++ qt-everywhere-opensource-src-5.3.1.new/qtbase/src/dbus/qdbusintegrator.cpp.orig 2014-08-13 04:35:08.398435926 +0200
@@ -0,0 +1,2517 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDBus 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 "qdbusintegrator_p.h"
+
+#include <qcoreapplication.h>
+#include <qdebug.h>
+#include <qmetaobject.h>
+#include <qobject.h>
+#include <qsocketnotifier.h>
+#include <qstringlist.h>
+#include <qtimer.h>
+#include <qthread.h>
+
+#include "qdbusargument.h"
+#include "qdbusconnection_p.h"
+#include "qdbusconnectionmanager_p.h"
+#include "qdbusinterface_p.h"
+#include "qdbusmessage.h"
+#include "qdbusmetatype.h"
+#include "qdbusmetatype_p.h"
+#include "qdbusabstractadaptor.h"
+#include "qdbusabstractadaptor_p.h"
+#include "qdbusutil_p.h"
+#include "qdbusvirtualobject.h"
+#include "qdbusmessage_p.h"
+#include "qdbuscontext_p.h"
+#include "qdbuspendingcall_p.h"
+
+#include "qdbusthreaddebug_p.h"
+
+#include <algorithm>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+static bool isDebugging;
+#define qDBusDebug if (!::isDebugging); else qDebug
+
+QString orgFreedesktopDBusString()
+{
+ return QStringLiteral(DBUS_SERVICE_DBUS);
+}
+
+static inline QString dbusServiceString()
+{
+ return orgFreedesktopDBusString();
+}
+
+static inline QString dbusInterfaceString()
+{
+ // it's the same string, but just be sure
+ Q_ASSERT(orgFreedesktopDBusString() == QLatin1String(DBUS_INTERFACE_DBUS));
+ return orgFreedesktopDBusString();
+}
+
+static inline QDebug operator<<(QDebug dbg, const QThread *th)
+{
+ dbg.nospace() << "QThread(ptr=" << (void*)th;
+ if (th && !th->objectName().isEmpty())
+ dbg.nospace() << ", name=" << th->objectName();
+ dbg.nospace() << ')';
+ return dbg.space();
+}
+
+#if QDBUS_THREAD_DEBUG
+static inline QDebug operator<<(QDebug dbg, const QDBusConnectionPrivate *conn)
+{
+ dbg.nospace() << "QDBusConnection("
+ << "ptr=" << (void*)conn
+ << ", name=" << conn->name
+ << ", baseService=" << conn->baseService
+ << ", thread=";
+ if (conn->thread() == QThread::currentThread())
+ dbg.nospace() << "same thread";
+ else
+ dbg.nospace() << conn->thread();
+ dbg.nospace() << ')';
+ return dbg.space();
+}
+
+void qdbusDefaultThreadDebug(int action, int condition, QDBusConnectionPrivate *conn)
+{
+ qDBusDebug() << QThread::currentThread()
+ << "Qt D-Bus threading action" << action
+ << (condition == QDBusLockerBase::BeforeLock ? "before lock" :
+ condition == QDBusLockerBase::AfterLock ? "after lock" :
+ condition == QDBusLockerBase::BeforeUnlock ? "before unlock" :
+ condition == QDBusLockerBase::AfterUnlock ? "after unlock" :
+ condition == QDBusLockerBase::BeforePost ? "before event posting" :
+ condition == QDBusLockerBase::AfterPost ? "after event posting" :
+ condition == QDBusLockerBase::BeforeDeliver ? "before event delivery" :
+ condition == QDBusLockerBase::AfterDeliver ? "after event delivery" :
+ condition == QDBusLockerBase::BeforeAcquire ? "before acquire" :
+ condition == QDBusLockerBase::AfterAcquire ? "after acquire" :
+ condition == QDBusLockerBase::BeforeRelease ? "before release" :
+ condition == QDBusLockerBase::AfterRelease ? "after release" :
+ "condition unknown")
+ << "in connection" << conn;
+}
+qdbusThreadDebugFunc qdbusThreadDebug = 0;
+#endif
+
+typedef void (*QDBusSpyHook)(const QDBusMessage&);
+typedef QVarLengthArray<QDBusSpyHook, 4> QDBusSpyHookList;
+Q_GLOBAL_STATIC(QDBusSpyHookList, qDBusSpyHookList)
+
+extern "C" {
+
+ // libdbus-1 callbacks
+
+static bool qDBusRealAddTimeout(QDBusConnectionPrivate *d, DBusTimeout *timeout, int ms);
+static dbus_bool_t qDBusAddTimeout(DBusTimeout *timeout, void *data)
+{
+ Q_ASSERT(timeout);
+ Q_ASSERT(data);
+
+ // qDebug("addTimeout %d", q_dbus_timeout_get_interval(timeout));
+
+ QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
+
+ if (!q_dbus_timeout_get_enabled(timeout))
+ return true;
+
+ QDBusWatchAndTimeoutLocker locker(AddTimeoutAction, d);
+ if (QCoreApplication::instance() && QThread::currentThread() == d->thread()) {
+ // correct thread
+ return qDBusRealAddTimeout(d, timeout, q_dbus_timeout_get_interval(timeout));
+ } else {
+ // wrong thread: sync back
+ QDBusConnectionCallbackEvent *ev = new QDBusConnectionCallbackEvent;
+ ev->subtype = QDBusConnectionCallbackEvent::AddTimeout;
+ d->timeoutsPendingAdd.append(qMakePair(timeout, q_dbus_timeout_get_interval(timeout)));
+ d->postEventToThread(AddTimeoutAction, d, ev);
+ return true;
+ }
+}
+
+static bool qDBusRealAddTimeout(QDBusConnectionPrivate *d, DBusTimeout *timeout, int ms)
+{
+ Q_ASSERT(d->timeouts.keys(timeout).isEmpty());
+
+ int timerId = d->startTimer(ms);
+ if (!timerId)
+ return false;
+
+ d->timeouts[timerId] = timeout;
+ return true;
+}
+
+static void qDBusRemoveTimeout(DBusTimeout *timeout, void *data)
+{
+ Q_ASSERT(timeout);
+ Q_ASSERT(data);
+
+ // qDebug("removeTimeout");
+
+ QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
+
+ QDBusWatchAndTimeoutLocker locker(RemoveTimeoutAction, d);
+
+ // is it pending addition?
+ QDBusConnectionPrivate::PendingTimeoutList::iterator pit = d->timeoutsPendingAdd.begin();
+ while (pit != d->timeoutsPendingAdd.end()) {
+ if (pit->first == timeout)
+ pit = d->timeoutsPendingAdd.erase(pit);
+ else
+ ++pit;
+ }
+
+ // is it a running timer?
+ bool correctThread = QCoreApplication::instance() && QThread::currentThread() == d->thread();
+ QDBusConnectionPrivate::TimeoutHash::iterator it = d->timeouts.begin();
+ while (it != d->timeouts.end()) {
+ if (it.value() == timeout) {
+ if (correctThread) {
+ // correct thread
+ d->killTimer(it.key());
+ } else {
+ // incorrect thread or no application, post an event for later
+ QDBusConnectionCallbackEvent *ev = new QDBusConnectionCallbackEvent;
+ ev->subtype = QDBusConnectionCallbackEvent::KillTimer;
+ ev->timerId = it.key();
+ d->postEventToThread(KillTimerAction, d, ev);
+ }
+ it = d->timeouts.erase(it);
+ break;
+ } else {
+ ++it;
+ }
+ }
+}
+
+static void qDBusToggleTimeout(DBusTimeout *timeout, void *data)
+{
+ Q_ASSERT(timeout);
+ Q_ASSERT(data);
+
+ //qDebug("ToggleTimeout");
+
+ qDBusRemoveTimeout(timeout, data);
+ qDBusAddTimeout(timeout, data);
+}
+
+static bool qDBusRealAddWatch(QDBusConnectionPrivate *d, DBusWatch *watch, int flags, int fd);
+static dbus_bool_t qDBusAddWatch(DBusWatch *watch, void *data)
+{
+ Q_ASSERT(watch);
+ Q_ASSERT(data);
+
+ QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
+
+ int flags = q_dbus_watch_get_flags(watch);
+ int fd = q_dbus_watch_get_unix_fd(watch);
+
+ if (QCoreApplication::instance() && QThread::currentThread() == d->thread()) {
+ return qDBusRealAddWatch(d, watch, flags, fd);
+ } else {
+ QDBusConnectionCallbackEvent *ev = new QDBusConnectionCallbackEvent;
+ ev->subtype = QDBusConnectionCallbackEvent::AddWatch;
+ ev->watch = watch;
+ ev->fd = fd;
+ ev->extra = flags;
+ d->postEventToThread(AddWatchAction, d, ev);
+ return true;
+ }
+}
+
+static bool qDBusRealAddWatch(QDBusConnectionPrivate *d, DBusWatch *watch, int flags, int fd)
+{
+ QDBusConnectionPrivate::Watcher watcher;
+
+ QDBusWatchAndTimeoutLocker locker(AddWatchAction, d);
+ if (flags & DBUS_WATCH_READABLE) {
+ //qDebug("addReadWatch %d", fd);
+ watcher.watch = watch;
+ if (QCoreApplication::instance()) {
+ watcher.read = new QSocketNotifier(fd, QSocketNotifier::Read, d);
+ watcher.read->setEnabled(q_dbus_watch_get_enabled(watch));
+ d->connect(watcher.read, SIGNAL(activated(int)), SLOT(socketRead(int)));
+ }
+ }
+ if (flags & DBUS_WATCH_WRITABLE) {
+ //qDebug("addWriteWatch %d", fd);
+ watcher.watch = watch;
+ if (QCoreApplication::instance()) {
+ watcher.write = new QSocketNotifier(fd, QSocketNotifier::Write, d);
+ watcher.write->setEnabled(q_dbus_watch_get_enabled(watch));
+ d->connect(watcher.write, SIGNAL(activated(int)), SLOT(socketWrite(int)));
+ }
+ }
+ d->watchers.insertMulti(fd, watcher);
+
+ return true;
+}
+
+static void qDBusRemoveWatch(DBusWatch *watch, void *data)
+{
+ Q_ASSERT(watch);
+ Q_ASSERT(data);
+
+ //qDebug("remove watch");
+
+ QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
+ int fd = q_dbus_watch_get_unix_fd(watch);
+
+ QDBusWatchAndTimeoutLocker locker(RemoveWatchAction, d);
+ QDBusConnectionPrivate::WatcherHash::iterator i = d->watchers.find(fd);
+ while (i != d->watchers.end() && i.key() == fd) {
+ if (i.value().watch == watch) {
+ if (QCoreApplication::instance() && QThread::currentThread() == d->thread()) {
+ // correct thread, delete the socket notifiers
+ delete i.value().read;
+ delete i.value().write;
+ } else {
+ // incorrect thread or no application, use delete later
+ if (i->read)
+ i->read->deleteLater();
+ if (i->write)
+ i->write->deleteLater();
+ }
+ i = d->watchers.erase(i);
+ } else {
+ ++i;
+ }
+ }
+}
+
+static void qDBusRealToggleWatch(QDBusConnectionPrivate *d, DBusWatch *watch, int fd);
+static void qDBusToggleWatch(DBusWatch *watch, void *data)
+{
+ Q_ASSERT(watch);
+ Q_ASSERT(data);
+
+ QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
+ int fd = q_dbus_watch_get_unix_fd(watch);
+
+ if (QCoreApplication::instance() && QThread::currentThread() == d->thread()) {
+ qDBusRealToggleWatch(d, watch, fd);
+ } else {
+ QDBusConnectionCallbackEvent *ev = new QDBusConnectionCallbackEvent;
+ ev->subtype = QDBusConnectionCallbackEvent::ToggleWatch;
+ ev->watch = watch;
+ ev->fd = fd;
+ d->postEventToThread(ToggleWatchAction, d, ev);
+ }
+}
+
+static void qDBusRealToggleWatch(QDBusConnectionPrivate *d, DBusWatch *watch, int fd)
+{
+ QDBusWatchAndTimeoutLocker locker(ToggleWatchAction, d);
+
+ QDBusConnectionPrivate::WatcherHash::iterator i = d->watchers.find(fd);
+ while (i != d->watchers.end() && i.key() == fd) {
+ if (i.value().watch == watch) {
+ bool enabled = q_dbus_watch_get_enabled(watch);
+ int flags = q_dbus_watch_get_flags(watch);
+
+ //qDebug("toggle watch %d to %d (write: %d, read: %d)", q_dbus_watch_get_fd(watch), enabled, flags & DBUS_WATCH_WRITABLE, flags & DBUS_WATCH_READABLE);
+
+ if (flags & DBUS_WATCH_READABLE && i.value().read)
+ i.value().read->setEnabled(enabled);
+ if (flags & DBUS_WATCH_WRITABLE && i.value().write)
+ i.value().write->setEnabled(enabled);
+ return;
+ }
+ ++i;
+ }
+}
+
+static void qDBusUpdateDispatchStatus(DBusConnection *connection, DBusDispatchStatus new_status, void *data)
+{
+ Q_ASSERT(connection);
+ Q_UNUSED(connection);
+ QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
+
+ static int slotId; // 0 is QObject::deleteLater()
+ if (!slotId) {
+ // it's ok to do this: there's no race condition because the store is atomic
+ // and we always set to the same value
+ slotId = QDBusConnectionPrivate::staticMetaObject.indexOfSlot("doDispatch()");
+ }
+
+ //qDBusDebug() << "Updating dispatcher status" << slotId;
+ if (new_status == DBUS_DISPATCH_DATA_REMAINS)
+ QDBusConnectionPrivate::staticMetaObject.method(slotId).
+ invoke(d, Qt::QueuedConnection);
+}
+
+static void qDBusNewConnection(DBusServer *server, DBusConnection *connection, void *data)
+{
+ // ### We may want to separate the server from the QDBusConnectionPrivate
+ Q_ASSERT(server); Q_UNUSED(server);
+ Q_ASSERT(connection);
+ Q_ASSERT(data);
+
+ // keep the connection alive
+ q_dbus_connection_ref(connection);
+ QDBusConnectionPrivate *serverConnection = static_cast<QDBusConnectionPrivate *>(data);
+
+ // allow anonymous authentication
+ if (serverConnection->anonymousAuthenticationAllowed)
+ q_dbus_connection_set_allow_anonymous(connection, true);
+
+ QDBusConnectionPrivate *newConnection = new QDBusConnectionPrivate(serverConnection->parent());
+ QMutexLocker locker(&QDBusConnectionManager::instance()->mutex);
+ QDBusConnectionManager::instance()->setConnection(QLatin1String("QDBusServer-") + QString::number(reinterpret_cast<qulonglong>(newConnection)), newConnection);
+ serverConnection->serverConnectionNames << newConnection->name;
+
+ // setPeer does the error handling for us
+ QDBusErrorInternal error;
+ newConnection->setPeer(connection, error);
+
+ QDBusConnection retval = QDBusConnectionPrivate::q(newConnection);
+
+ // make QDBusServer emit the newConnection signal
+ serverConnection->serverConnection(retval);
+}
+
+} // extern "C"
+
+static QByteArray buildMatchRule(const QString &service,
+ const QString &objectPath, const QString &interface,
+ const QString &member, const QStringList &argMatch, const QString & /*signature*/)
+{
+ QString result = QLatin1String("type='signal',");
+ QString keyValue = QLatin1String("%1='%2',");
+
+ if (!service.isEmpty())
+ result += keyValue.arg(QLatin1String("sender"), service);
+ if (!objectPath.isEmpty())
+ result += keyValue.arg(QLatin1String("path"), objectPath);
+ if (!interface.isEmpty())
+ result += keyValue.arg(QLatin1String("interface"), interface);
+ if (!member.isEmpty())
+ result += keyValue.arg(QLatin1String("member"), member);
+
+ // add the argument string-matching now
+ if (!argMatch.isEmpty()) {
+ keyValue = QLatin1String("arg%1='%2',");
+ for (int i = 0; i < argMatch.count(); ++i)
+ if (!argMatch.at(i).isNull())
+ result += keyValue.arg(i).arg(argMatch.at(i));
+ }
+
+ result.chop(1); // remove ending comma
+ return result.toLatin1();
+}
+
+static bool findObject(const QDBusConnectionPrivate::ObjectTreeNode *root,
+ const QString &fullpath, int &usedLength,
+ QDBusConnectionPrivate::ObjectTreeNode &result)
+{
+ if (!fullpath.compare(QLatin1String("/")) && root->obj) {
+ usedLength = 1;
+ result = *root;
+ return root;
+ }
+ int start = 0;
+ int length = fullpath.length();
+ if (fullpath.at(0) == QLatin1Char('/'))
+ start = 1;
+
+ // walk the object tree
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator node = root;
+ while (start < length && node) {
+ if (node->flags & QDBusConnection::ExportChildObjects)
+ break;
+ if ((node->flags & QDBusConnectionPrivate::VirtualObject) && (node->flags & QDBusConnection::SubPath))
+ break;
+ int end = fullpath.indexOf(QLatin1Char('/'), start);
+ end = (end == -1 ? length : end);
+ QStringRef pathComponent(&fullpath, start, end - start);
+
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator it =
+ std::lower_bound(node->children.constBegin(), node->children.constEnd(), pathComponent);
+ if (it != node->children.constEnd() && it->name == pathComponent)
+ // match
+ node = it;
+ else
+ node = 0;
+
+ start = end + 1;
+ }
+
+ // found our object
+ usedLength = (start > length ? length : start);
+ if (node) {
+ if (node->obj || !node->children.isEmpty())
+ result = *node;
+ else
+ // there really is no object here
+ // we're just looking at an unused space in the QVector
+ node = 0;
+ }
+ return node;
+}
+
+static QObject *findChildObject(const QDBusConnectionPrivate::ObjectTreeNode *root,
+ const QString &fullpath, int start)
+{
+ int length = fullpath.length();
+
+ // any object in the tree can tell us to switch to its own object tree:
+ const QDBusConnectionPrivate::ObjectTreeNode *node = root;
+ if (node && node->flags & QDBusConnection::ExportChildObjects) {
+ QObject *obj = node->obj;
+
+ while (obj) {
+ if (start >= length)
+ // we're at the correct level
+ return obj;
+
+ int pos = fullpath.indexOf(QLatin1Char('/'), start);
+ pos = (pos == -1 ? length : pos);
+ QStringRef pathComponent(&fullpath, start, pos - start);
+
+ const QObjectList children = obj->children();
+
+ // find a child with the proper name
+ QObject *next = 0;
+ QObjectList::ConstIterator it = children.constBegin();
+ QObjectList::ConstIterator end = children.constEnd();
+ for ( ; it != end; ++it)
+ if ((*it)->objectName() == pathComponent) {
+ next = *it;
+ break;
+ }
+
+ if (!next)
+ break;
+
+ obj = next;
+ start = pos + 1;
+ }
+ }
+
+ // object not found
+ return 0;
+}
+
+static bool shouldWatchService(const QString &service)
+{
+ return !service.isEmpty() && !service.startsWith(QLatin1Char(':'));
+}
+
+extern Q_DBUS_EXPORT void qDBusAddSpyHook(QDBusSpyHook);
+void qDBusAddSpyHook(QDBusSpyHook hook)
+{
+ qDBusSpyHookList()->append(hook);
+}
+
+extern "C" {
+static DBusHandlerResult
+qDBusSignalFilter(DBusConnection *connection, DBusMessage *message, void *data)
+{
+ Q_ASSERT(data);
+ Q_UNUSED(connection);
+ QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
+ if (d->mode == QDBusConnectionPrivate::InvalidMode)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ QDBusMessage amsg = QDBusMessagePrivate::fromDBusMessage(message, d->capabilities);
+ qDBusDebug() << d << "got message (signal):" << amsg;
+
+ return d->handleMessage(amsg) ?
+ DBUS_HANDLER_RESULT_HANDLED :
+ DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+}
+
+bool QDBusConnectionPrivate::handleMessage(const QDBusMessage &amsg)
+{
+ const QDBusSpyHookList *list = qDBusSpyHookList();
+ for (int i = 0; i < list->size(); ++i) {
+ qDBusDebug() << "calling the message spy hook";
+ (*(*list)[i])(amsg);
+ }
+
+ if (!ref.load())
+ return false;
+
+ switch (amsg.type()) {
+ case QDBusMessage::SignalMessage:
+ handleSignal(amsg);
+ // if there are any other filters in this DBusConnection,
+ // let them see the signal too
+ return false;
+ case QDBusMessage::MethodCallMessage:
+ handleObjectCall(amsg);
+ return true;
+ case QDBusMessage::ReplyMessage:
+ case QDBusMessage::ErrorMessage:
+ case QDBusMessage::InvalidMessage:
+ return false; // we don't handle those here
+ }
+
+ return false;
+}
+
+static void huntAndDestroy(QObject *needle, QDBusConnectionPrivate::ObjectTreeNode &haystack)
+{
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it = haystack.children.begin();
+
+ while (it != haystack.children.end()) {
+ huntAndDestroy(needle, *it);
+ if (!it->isActive())
+ it = haystack.children.erase(it);
+ else
+ it++;
+ }
+
+ if (needle == haystack.obj) {
+ haystack.obj = 0;
+ haystack.flags = 0;
+ }
+}
+
+static void huntAndUnregister(const QStringList &pathComponents, int i, QDBusConnection::UnregisterMode mode,
+ QDBusConnectionPrivate::ObjectTreeNode *node)
+{
+ if (pathComponents.count() == i) {
+ // found it
+ node->obj = 0;
+ node->flags = 0;
+
+ if (mode == QDBusConnection::UnregisterTree) {
+ // clear the sub-tree as well
+ node->children.clear(); // can't disconnect the objects because we really don't know if they can
+ // be found somewhere else in the path too
+ }
+ } else {
+ // keep going
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator end = node->children.end();
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it =
+ std::lower_bound(node->children.begin(), end, pathComponents.at(i));
+ if (it == end || it->name != pathComponents.at(i))
+ return; // node not found
+
+ huntAndUnregister(pathComponents, i + 1, mode, it);
+ if (!it->isActive())
+ node->children.erase(it);
+ }
+}
+
+static void huntAndEmit(DBusConnection *connection, DBusMessage *msg,
+ QObject *needle, const QDBusConnectionPrivate::ObjectTreeNode &haystack,
+ bool isScriptable, bool isAdaptor, const QString &path = QString())
+{
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator it = haystack.children.constBegin();
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator end = haystack.children.constEnd();
+ for ( ; it != end; ++it) {
+ if (it->isActive())
+ huntAndEmit(connection, msg, needle, *it, isScriptable, isAdaptor, path + QLatin1Char('/') + it->name);
+ }
+
+ if (needle == haystack.obj) {
+ // is this a signal we should relay?
+ if (isAdaptor && (haystack.flags & QDBusConnection::ExportAdaptors) == 0)
+ return; // no: it comes from an adaptor and we're not exporting adaptors
+ else if (!isAdaptor) {
+ int mask = isScriptable
+ ? QDBusConnection::ExportScriptableSignals
+ : QDBusConnection::ExportNonScriptableSignals;
+ if ((haystack.flags & mask) == 0)
+ return; // signal was not exported
+ }
+
+ QByteArray p = path.toLatin1();
+ if (p.isEmpty())
+ p = "/";
+ qDBusDebug() << QThread::currentThread() << "emitting signal at" << p;
+ DBusMessage *msg2 = q_dbus_message_copy(msg);
+ q_dbus_message_set_path(msg2, p);
+ q_dbus_connection_send(connection, msg2, 0);
+ q_dbus_message_unref(msg2);
+ }
+}
+
+static int findSlot(const QMetaObject *mo, const QByteArray &name, int flags,
+ const QString &signature_, QVector<int> &metaTypes)
+{
+ QByteArray msgSignature = signature_.toLatin1();
+
+ for (int idx = mo->methodCount() - 1 ; idx >= QObject::staticMetaObject.methodCount(); --idx) {
+ QMetaMethod mm = mo->method(idx);
+
+ // check access:
+ if (mm.access() != QMetaMethod::Public)
+ continue;
+
+ // check type:
+ if (mm.methodType() != QMetaMethod::Slot && mm.methodType() != QMetaMethod::Method)
+ continue;
+
+ // check name:
+ if (mm.name() != name)
+ continue;
+
+ int returnType = mm.returnType();
+ bool isAsync = qDBusCheckAsyncTag(mm.tag());
+ bool isScriptable = mm.attributes() & QMetaMethod::Scriptable;
+
+ // consistency check:
+ if (isAsync && returnType != QMetaType::Void)
+ continue;
+
+ QString errorMsg;
+ int inputCount = qDBusParametersForMethod(mm, metaTypes, errorMsg);
+ if (inputCount == -1)
+ continue; // problem parsing
+
+ metaTypes[0] = returnType;
+ bool hasMessage = false;
+ if (inputCount > 0 &&
+ metaTypes.at(inputCount) == QDBusMetaTypeId::message()) {
+ // "no input parameters" is allowed as long as the message meta type is there
+ hasMessage = true;
+ --inputCount;
+ }
+
+ // try to match the parameters
+ int i;
+ QByteArray reconstructedSignature;
+ for (i = 1; i <= inputCount; ++i) {
+ const char *typeSignature = QDBusMetaType::typeToSignature( metaTypes.at(i) );
+ if (!typeSignature)
+ break; // invalid
+
+ reconstructedSignature += typeSignature;
+ if (!msgSignature.startsWith(reconstructedSignature))
+ break;
+ }
+
+ if (reconstructedSignature != msgSignature)
+ continue; // we didn't match them all
+
+ if (hasMessage)
+ ++i;
+
+ // make sure that the output parameters have signatures too
+ if (returnType != QMetaType::UnknownType && returnType != QMetaType::Void && QDBusMetaType::typeToSignature(returnType) == 0)
+ continue;
+
+ bool ok = true;
+ for (int j = i; ok && j < metaTypes.count(); ++j)
+ if (QDBusMetaType::typeToSignature(metaTypes.at(i)) == 0)
+ ok = false;
+ if (!ok)
+ continue;
+
+ // consistency check:
+ if (isAsync && metaTypes.count() > i + 1)
+ continue;
+
+ if (mm.methodType() == QMetaMethod::Slot) {
+ if (isScriptable && (flags & QDBusConnection::ExportScriptableSlots) == 0)
+ continue; // scriptable slots not exported
+ if (!isScriptable && (flags & QDBusConnection::ExportNonScriptableSlots) == 0)
+ continue; // non-scriptable slots not exported
+ } else {
+ if (isScriptable && (flags & QDBusConnection::ExportScriptableInvokables) == 0)
+ continue; // scriptable invokables not exported
+ if (!isScriptable && (flags & QDBusConnection::ExportNonScriptableInvokables) == 0)
+ continue; // non-scriptable invokables not exported
+ }
+
+ // if we got here, this slot matched
+ return idx;
+ }
+
+ // no slot matched
+ return -1;
+}
+
+static QDBusCallDeliveryEvent * const DIRECT_DELIVERY = (QDBusCallDeliveryEvent *)1;
+
+QDBusCallDeliveryEvent* QDBusConnectionPrivate::prepareReply(QDBusConnectionPrivate *target,
+ QObject *object, int idx,
+ const QVector<int> &metaTypes,
+ const QDBusMessage &msg)
+{
+ Q_ASSERT(object);
+ Q_UNUSED(object);
+
+ int n = metaTypes.count() - 1;
+ if (metaTypes[n] == QDBusMetaTypeId::message())
+ --n;
+
+ if (msg.arguments().count() < n)
+ return 0; // too few arguments
+
+ // check that types match
+ for (int i = 0; i < n; ++i)
+ if (metaTypes.at(i + 1) != msg.arguments().at(i).userType() &&
+ msg.arguments().at(i).userType() != qMetaTypeId<QDBusArgument>())
+ return 0; // no match
+
+ // we can deliver
+ // prepare for the call
+ if (target == object)
+ return DIRECT_DELIVERY;
+ return new QDBusCallDeliveryEvent(QDBusConnection(target), idx, target, msg, metaTypes);
+}
+
+void QDBusConnectionPrivate::activateSignal(const QDBusConnectionPrivate::SignalHook& hook,
+ const QDBusMessage &msg)
+{
+ // This is called by QDBusConnectionPrivate::handleSignal to deliver a signal
+ // that was received from D-Bus
+ //
+ // Signals are delivered to slots if the parameters match
+ // Slots can have less parameters than there are on the message
+ // Slots can optionally have one final parameter that is a QDBusMessage
+ // Slots receive read-only copies of the message (i.e., pass by value or by const-ref)
+ QDBusCallDeliveryEvent *call = prepareReply(this, hook.obj, hook.midx, hook.params, msg);
+ if (call == DIRECT_DELIVERY) {
+ // short-circuit delivery
+ Q_ASSERT(this == hook.obj);
+ deliverCall(this, 0, msg, hook.params, hook.midx);
+ return;
+ }
+ if (call)
+ postEventToThread(ActivateSignalAction, hook.obj, call);
+}
+
+bool QDBusConnectionPrivate::activateCall(QObject* object, int flags, const QDBusMessage &msg)
+{
+ // This is called by QDBusConnectionPrivate::handleObjectCall to place a call
+ // to a slot on the object.
+ //
+ // The call is delivered to the first slot that matches the following conditions:
+ // - has the same name as the message's target member
+ // - ALL of the message's types are found in slot's parameter list
+ // - optionally has one more parameter of type QDBusMessage
+ // If none match, then the slot of the same name as the message target and with
+ // the first type of QDBusMessage is delivered.
+ //
+ // The D-Bus specification requires that all MethodCall messages be replied to, unless the
+ // caller specifically waived this requirement. This means that we inspect if the user slot
+ // generated a reply and, if it didn't, we will. Obviously, if the user slot doesn't take a
+ // QDBusMessage parameter, it cannot generate a reply.
+ //
+ // When a return message is generated, the slot's return type, if any, will be placed
+ // in the message's first position. If there are non-const reference parameters to the
+ // slot, they must appear at the end and will be placed in the subsequent message
+ // positions.
+
+ static const char cachePropertyName[] = "_qdbus_slotCache";
+
+ if (!object)
+ return false;
+
+#ifndef QT_NO_PROPERTIES
+ Q_ASSERT_X(QThread::currentThread() == object->thread(),
+ "QDBusConnection: internal threading error",
+ "function called for an object that is in another thread!!");
+
+ QDBusSlotCache slotCache =
+ qvariant_cast<QDBusSlotCache>(object->property(cachePropertyName));
+ QString cacheKey = msg.member(), signature = msg.signature();
+ if (!signature.isEmpty()) {
+ cacheKey.reserve(cacheKey.length() + 1 + signature.length());
+ cacheKey += QLatin1Char('.');
+ cacheKey += signature;
+ }
+
+ QDBusSlotCache::Hash::ConstIterator cacheIt = slotCache.hash.constFind(cacheKey);
+ while (cacheIt != slotCache.hash.constEnd() && cacheIt->flags != flags &&
+ cacheIt.key() == cacheKey)
+ ++cacheIt;
+ if (cacheIt == slotCache.hash.constEnd() || cacheIt.key() != cacheKey)
+ {
+ // not cached, analyze the meta object
+ const QMetaObject *mo = object->metaObject();
+ QByteArray memberName = msg.member().toUtf8();
+
+ // find a slot that matches according to the rules above
+ QDBusSlotCache::Data slotData;
+ slotData.flags = flags;
+ slotData.slotIdx = ::findSlot(mo, memberName, flags, msg.signature(), slotData.metaTypes);
+ if (slotData.slotIdx == -1) {
+ // ### this is where we want to add the connection as an arg too
+ // try with no parameters, but with a QDBusMessage
+ slotData.slotIdx = ::findSlot(mo, memberName, flags, QString(), slotData.metaTypes);
+ if (slotData.metaTypes.count() != 2 ||
+ slotData.metaTypes.at(1) != QDBusMetaTypeId::message()) {
+ // not found
+ // save the negative lookup
+ slotData.slotIdx = -1;
+ slotData.metaTypes.clear();
+ slotCache.hash.insert(cacheKey, slotData);
+ object->setProperty(cachePropertyName, QVariant::fromValue(slotCache));
+ return false;
+ }
+ }
+
+ // save to the cache
+ slotCache.hash.insert(cacheKey, slotData);
+ object->setProperty(cachePropertyName, QVariant::fromValue(slotCache));
+
+ // found the slot to be called
+ deliverCall(object, flags, msg, slotData.metaTypes, slotData.slotIdx);
+ return true;
+ } else if (cacheIt->slotIdx == -1) {
+ // negative cache
+ return false;
+ } else {
+ // use the cache
+ deliverCall(object, flags, msg, cacheIt->metaTypes, cacheIt->slotIdx);
+ return true;
+ }
+#endif // QT_NO_PROPERTIES
+ return false;
+}
+
+void QDBusConnectionPrivate::deliverCall(QObject *object, int /*flags*/, const QDBusMessage &msg,
+ const QVector<int> &metaTypes, int slotIdx)
+{
+ Q_ASSERT_X(!object || QThread::currentThread() == object->thread(),
+ "QDBusConnection: internal threading error",
+ "function called for an object that is in another thread!!");
+
+ QVarLengthArray<void *, 10> params;
+ params.reserve(metaTypes.count());
+
+ QVariantList auxParameters;
+ // let's create the parameter list
+
+ // first one is the return type -- add it below
+ params.append(0);
+
+ // add the input parameters
+ int i;
+ int pCount = qMin(msg.arguments().count(), metaTypes.count() - 1);
+ for (i = 1; i <= pCount; ++i) {
+ int id = metaTypes[i];
+ if (id == QDBusMetaTypeId::message())
+ break;
+
+ const QVariant &arg = msg.arguments().at(i - 1);
+ if (arg.userType() == id)
+ // no conversion needed
+ params.append(const_cast<void *>(arg.constData()));
+ else if (arg.userType() == qMetaTypeId<QDBusArgument>()) {
+ // convert to what the function expects
+ void *null = 0;
+ auxParameters.append(QVariant(id, null));
+
+ const QDBusArgument &in =
+ *reinterpret_cast<const QDBusArgument *>(arg.constData());
+ QVariant &out = auxParameters[auxParameters.count() - 1];
+
+ if (!QDBusMetaType::demarshall(in, out.userType(), out.data()))
+ qFatal("Internal error: demarshalling function for type '%s' (%d) failed!",
+ out.typeName(), out.userType());
+
+ params.append(const_cast<void *>(out.constData()));
+ } else {
+ qFatal("Internal error: got invalid meta type %d (%s) "
+ "when trying to convert to meta type %d (%s)",
+ arg.userType(), QMetaType::typeName(arg.userType()),
+ id, QMetaType::typeName(id));
+ }
+ }
+
+ if (metaTypes.count() > i && metaTypes[i] == QDBusMetaTypeId::message()) {
+ params.append(const_cast<void*>(static_cast<const void*>(&msg)));
+ ++i;
+ }
+
+ // output arguments
+ QVariantList outputArgs;
+ void *null = 0;
+ if (metaTypes[0] != QMetaType::Void && metaTypes[0] != QMetaType::UnknownType) {
+ QVariant arg(metaTypes[0], null);
+ outputArgs.append( arg );
+ params[0] = const_cast<void*>(outputArgs.at( outputArgs.count() - 1 ).constData());
+ }
+ for ( ; i < metaTypes.count(); ++i) {
+ QVariant arg(metaTypes[i], null);
+ outputArgs.append( arg );
+ params.append(const_cast<void*>(outputArgs.at( outputArgs.count() - 1 ).constData()));
+ }
+
+ // make call:
+ bool fail;
+ if (!object) {
+ fail = true;
+ } else {
+ // FIXME: save the old sender!
+ QDBusContextPrivate context(QDBusConnection(this), msg);
+ QDBusContextPrivate *old = QDBusContextPrivate::set(object, &context);
+ QDBusConnectionPrivate::setSender(this);
+
+ QPointer<QObject> ptr = object;
+ fail = object->qt_metacall(QMetaObject::InvokeMetaMethod,
+ slotIdx, params.data()) >= 0;
+ QDBusConnectionPrivate::setSender(0);
+ // the object might be deleted in the slot
+ if (!ptr.isNull())
+ QDBusContextPrivate::set(object, old);
+ }
+
+ // do we create a reply? Only if the caller is waiting for a reply and one hasn't been sent
+ // yet.
+ if (msg.isReplyRequired() && !msg.isDelayedReply()) {
+ if (!fail) {
+ // normal reply
+ qDBusDebug() << this << "Automatically sending reply:" << outputArgs;
+ send(msg.createReply(outputArgs));
+ } else {
+ // generate internal error
+ qWarning("Internal error: Failed to deliver message");
+ send(msg.createErrorReply(QDBusError::InternalError,
+ QLatin1String("Failed to deliver message")));
+ }
+ }
+
+ return;
+}
+
+extern bool qDBusInitThreads();
+
+QDBusConnectionPrivate::QDBusConnectionPrivate(QObject *p)
+ : QObject(p), ref(1), capabilities(0), mode(InvalidMode), connection(0), server(0), busService(0),
+ watchAndTimeoutLock(QMutex::Recursive),
+ rootNode(QString(QLatin1Char('/'))),
+ anonymousAuthenticationAllowed(false)
+{
+ static const bool threads = q_dbus_threads_init_default();
+ static const int debugging = qgetenv("QDBUS_DEBUG").toInt();
+ ::isDebugging = debugging;
+ Q_UNUSED(threads)
+ Q_UNUSED(debugging)
+
+#ifdef QDBUS_THREAD_DEBUG
+ if (debugging > 1)
+ qdbusThreadDebug = qdbusDefaultThreadDebug;
+#endif
+
+ QDBusMetaTypeId::init();
+
+ rootNode.flags = 0;
+
+ // prepopulate watchedServices:
+ // we know that the owner of org.freedesktop.DBus is itself
+ watchedServices.insert(dbusServiceString(), WatchedServiceData(dbusServiceString(), 1));
+
+ // prepopulate matchRefCounts:
+ // we know that org.freedesktop.DBus will never change owners
+ matchRefCounts.insert("type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0='org.freedesktop.DBus'", 1);
+}
+
+QDBusConnectionPrivate::~QDBusConnectionPrivate()
+{
+ if (thread() && thread() != QThread::currentThread())
+ qWarning("QDBusConnection(name=\"%s\")'s last reference in not in its creation thread! "
+ "Timer and socket errors will follow and the program will probably crash",
+ qPrintable(name));
+
+ closeConnection();
+ rootNode.children.clear(); // free resources
+ qDeleteAll(cachedMetaObjects);
+
+ if (server)
+ q_dbus_server_unref(server);
+ if (connection)
+ q_dbus_connection_unref(connection);
+
+ connection = 0;
+ server = 0;
+}
+
+void QDBusConnectionPrivate::deleteYourself()
+{
+ if (thread() && thread() != QThread::currentThread()) {
+ // last reference dropped while not in the correct thread
+ // ask the correct thread to delete
+
+ // note: since we're posting an event to another thread, we
+ // must consider deleteLater() to take effect immediately
+ deleteLater();
+ } else {
+ delete this;
+ }
+}
+
+void QDBusConnectionPrivate::closeConnection()
+{
+ QDBusWriteLocker locker(CloseConnectionAction, this);
+ ConnectionMode oldMode = mode;
+ mode = InvalidMode; // prevent reentrancy
+ baseService.clear();
+
+ if (server)
+ q_dbus_server_disconnect(server);
+
+ if (oldMode == ClientMode || oldMode == PeerMode) {
+ if (connection) {
+ q_dbus_connection_close(connection);
+ // send the "close" message
+ while (q_dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS)
+ ;
+ }
+ }
+
+ qDeleteAll(pendingCalls);
+
+ qDBusDebug() << this << "Disconnected";
+}
+
+void QDBusConnectionPrivate::checkThread()
+{
+ if (!thread()) {
+ if (QCoreApplication::instance())
+ moveToThread(QCoreApplication::instance()->thread());
+ else
+ qWarning("The thread that had QDBusConnection('%s') has died and there is no main thread",
+ qPrintable(name));
+ }
+}
+
+bool QDBusConnectionPrivate::handleError(const QDBusErrorInternal &error)
+{
+ if (!error)
+ return false; // no error
+
+ //lock.lockForWrite();
+ lastError = error;
+ //lock.unlock();
+ return true;
+}
+
+void QDBusConnectionPrivate::timerEvent(QTimerEvent *e)
+{
+ {
+ QDBusWatchAndTimeoutLocker locker(TimerEventAction, this);
+ DBusTimeout *timeout = timeouts.value(e->timerId(), 0);
+ if (timeout)
+ q_dbus_timeout_handle(timeout);
+ }
+
+ doDispatch();
+}
+
+void QDBusConnectionPrivate::customEvent(QEvent *e)
+{
+ Q_ASSERT(e->type() == QEvent::User);
+
+ QDBusConnectionCallbackEvent *ev = static_cast<QDBusConnectionCallbackEvent *>(e);
+ QDBusLockerBase::reportThreadAction(int(AddTimeoutAction) + int(ev->subtype),
+ QDBusLockerBase::BeforeDeliver, this);
+ switch (ev->subtype)
+ {
+ case QDBusConnectionCallbackEvent::AddTimeout: {
+ QDBusWatchAndTimeoutLocker locker(RealAddTimeoutAction, this);
+ while (!timeoutsPendingAdd.isEmpty()) {
+ QPair<DBusTimeout *, int> entry = timeoutsPendingAdd.takeFirst();
+ qDBusRealAddTimeout(this, entry.first, entry.second);
+ }
+ break;
+ }
+
+ case QDBusConnectionCallbackEvent::KillTimer:
+ killTimer(ev->timerId);
+ break;
+
+ case QDBusConnectionCallbackEvent::AddWatch:
+ qDBusRealAddWatch(this, ev->watch, ev->extra, ev->fd);
+ break;
+
+ case QDBusConnectionCallbackEvent::ToggleWatch:
+ qDBusRealToggleWatch(this, ev->watch, ev->fd);
+ break;
+ }
+ QDBusLockerBase::reportThreadAction(int(AddTimeoutAction) + int(ev->subtype),
+ QDBusLockerBase::AfterDeliver, this);
+}
+
+void QDBusConnectionPrivate::doDispatch()
+{
+ QDBusDispatchLocker locker(DoDispatchAction, this);
+ if (mode == ClientMode || mode == PeerMode)
+ while (q_dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS) ;
+}
+
+void QDBusConnectionPrivate::socketRead(int fd)
+{
+ QVarLengthArray<DBusWatch *, 2> pendingWatches;
+
+ {
+ QDBusWatchAndTimeoutLocker locker(SocketReadAction, this);
+ WatcherHash::ConstIterator it = watchers.constFind(fd);
+ while (it != watchers.constEnd() && it.key() == fd) {
+ if (it->watch && it->read && it->read->isEnabled())
+ pendingWatches.append(it.value().watch);
+ ++it;
+ }
+ }
+
+ for (int i = 0; i < pendingWatches.size(); ++i)
+ if (!q_dbus_watch_handle(pendingWatches[i], DBUS_WATCH_READABLE))
+ qDebug("OUT OF MEM");
+ doDispatch();
+}
+
+void QDBusConnectionPrivate::socketWrite(int fd)
+{
+ QVarLengthArray<DBusWatch *, 2> pendingWatches;
+
+ {
+ QDBusWatchAndTimeoutLocker locker(SocketWriteAction, this);
+ WatcherHash::ConstIterator it = watchers.constFind(fd);
+ while (it != watchers.constEnd() && it.key() == fd) {
+ if (it->watch && it->write && it->write->isEnabled())
+ pendingWatches.append(it.value().watch);
+ ++it;
+ }
+ }
+
+ for (int i = 0; i < pendingWatches.size(); ++i)
+ if (!q_dbus_watch_handle(pendingWatches[i], DBUS_WATCH_WRITABLE))
+ qDebug("OUT OF MEM");
+}
+
+void QDBusConnectionPrivate::objectDestroyed(QObject *obj)
+{
+ QDBusWriteLocker locker(ObjectDestroyedAction, this);
+ huntAndDestroy(obj, rootNode);
+
+ SignalHookHash::iterator sit = signalHooks.begin();
+ while (sit != signalHooks.end()) {
+ if (static_cast<QObject *>(sit.value().obj) == obj)
+ sit = disconnectSignal(sit);
+ else
+ ++sit;
+ }
+
+ obj->disconnect(this);
+}
+
+void QDBusConnectionPrivate::relaySignal(QObject *obj, const QMetaObject *mo, int signalId,
+ const QVariantList &args)
+{
+ QString interface = qDBusInterfaceFromMetaObject(mo);
+
+ QMetaMethod mm = mo->method(signalId);
+ QByteArray memberName = mm.name();
+
+ // check if it's scriptable
+ bool isScriptable = mm.attributes() & QMetaMethod::Scriptable;
+ bool isAdaptor = false;
+ for ( ; mo; mo = mo->superClass())
+ if (mo == &QDBusAbstractAdaptor::staticMetaObject) {
+ isAdaptor = true;
+ break;
+ }
+
+ QDBusReadLocker locker(RelaySignalAction, this);
+ QDBusMessage message = QDBusMessage::createSignal(QLatin1String("/"), interface,
+ QLatin1String(memberName));
+ QDBusMessagePrivate::setParametersValidated(message, true);
+ message.setArguments(args);
+ QDBusError error;
+ DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, capabilities, &error);
+ if (!msg) {
+ qWarning("QDBusConnection: Could not emit signal %s.%s: %s", qPrintable(interface), memberName.constData(),
+ qPrintable(error.message()));
+ lastError = error;
+ return;
+ }
+
+ //qDBusDebug() << "Emitting signal" << message;
+ //qDBusDebug() << "for paths:";
+ q_dbus_message_set_no_reply(msg, true); // the reply would not be delivered to anything
+ huntAndEmit(connection, msg, obj, rootNode, isScriptable, isAdaptor);
+ q_dbus_message_unref(msg);
+}
+
+void QDBusConnectionPrivate::serviceOwnerChangedNoLock(const QString &name,
+ const QString &oldOwner, const QString &newOwner)
+{
+ Q_UNUSED(oldOwner);
+// QDBusWriteLocker locker(UpdateSignalHookOwnerAction, this);
+ WatchedServicesHash::Iterator it = watchedServices.find(name);
+ if (it == watchedServices.end())
+ return;
+ if (oldOwner != it->owner)
+ qWarning("QDBusConnection: name '%s' had owner '%s' but we thought it was '%s'",
+ qPrintable(name), qPrintable(oldOwner), qPrintable(it->owner));
+
+ qDBusDebug() << this << "Updating name" << name << "from" << oldOwner << "to" << newOwner;
+ it->owner = newOwner;
+}
+
+int QDBusConnectionPrivate::findSlot(QObject* obj, const QByteArray &normalizedName,
+ QVector<int> &params)
+{
+ int midx = obj->metaObject()->indexOfMethod(normalizedName);
+ if (midx == -1)
+ return -1;
+
+ QString errorMsg;
+ int inputCount = qDBusParametersForMethod(obj->metaObject()->method(midx), params, errorMsg);
+ if ( inputCount == -1 || inputCount + 1 != params.count() )
+ return -1; // failed to parse or invalid arguments or output arguments
+
+ return midx;
+}
+
+bool QDBusConnectionPrivate::prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key,
+ const QString &service,
+ const QString &path, const QString &interface, const QString &name,
+ const QStringList &argMatch,
+ QObject *receiver, const char *signal, int minMIdx,
+ bool buildSignature)
+{
+ QByteArray normalizedName = signal + 1;
+ hook.midx = findSlot(receiver, signal + 1, hook.params);
+ if (hook.midx == -1) {
+ normalizedName = QMetaObject::normalizedSignature(signal + 1);
+ hook.midx = findSlot(receiver, normalizedName, hook.params);
+ }
+ if (hook.midx < minMIdx) {
+ if (hook.midx == -1)
+ {}
+ return false;
+ }
+
+ hook.service = service;
+ hook.path = path;
+ hook.obj = receiver;
+ hook.argumentMatch = argMatch;
+
+ // build the D-Bus signal name and signature
+ // This should not happen for QDBusConnection::connect, use buildSignature here, since
+ // QDBusConnection::connect passes false and everything else uses true
+ QString mname = name;
+ if (buildSignature && mname.isNull()) {
+ normalizedName.truncate(normalizedName.indexOf('('));
+ mname = QString::fromUtf8(normalizedName);
+ }
+ key = mname;
+ key.reserve(interface.length() + 1 + mname.length());
+ key += QLatin1Char(':');
+ key += interface;
+
+ if (buildSignature) {
+ hook.signature.clear();
+ for (int i = 1; i < hook.params.count(); ++i)
+ if (hook.params.at(i) != QDBusMetaTypeId::message())
+ hook.signature += QLatin1String( QDBusMetaType::typeToSignature( hook.params.at(i) ) );
+ }
+
+ hook.matchRule = buildMatchRule(service, path, interface, mname, argMatch, hook.signature);
+ return true; // connect to this signal
+}
+
+void QDBusConnectionPrivate::sendError(const QDBusMessage &msg, QDBusError::ErrorType code)
+{
+ if (code == QDBusError::UnknownMethod) {
+ QString interfaceMsg;
+ if (msg.interface().isEmpty())
+ interfaceMsg = QLatin1String("any interface");
+ else
+ interfaceMsg = QString::fromLatin1("interface '%1'").arg(msg.interface());
+
+ send(msg.createErrorReply(code,
+ QString::fromLatin1("No such method '%1' in %2 at object path '%3' "
+ "(signature '%4')")
+ .arg(msg.member(), interfaceMsg, msg.path(), msg.signature())));
+ } else if (code == QDBusError::UnknownInterface) {
+ send(msg.createErrorReply(QDBusError::UnknownInterface,
+ QString::fromLatin1("No such interface '%1' at object path '%2'")
+ .arg(msg.interface(), msg.path())));
+ } else if (code == QDBusError::UnknownObject) {
+ send(msg.createErrorReply(QDBusError::UnknownObject,
+ QString::fromLatin1("No such object path '%1'").arg(msg.path())));
+ }
+}
+
+bool QDBusConnectionPrivate::activateInternalFilters(const ObjectTreeNode &node,
+ const QDBusMessage &msg)
+{
+ // object may be null
+ const QString interface = msg.interface();
+
+ if (interface.isEmpty() || interface == QLatin1String(DBUS_INTERFACE_INTROSPECTABLE)) {
+ if (msg.member() == QLatin1String("Introspect") && msg.signature().isEmpty()) {
+ //qDebug() << "QDBusConnectionPrivate::activateInternalFilters introspect" << msg.d_ptr->msg;
+ QDBusMessage reply = msg.createReply(qDBusIntrospectObject(node, msg.path()));
+ send(reply);
+ return true;
+ }
+
+ if (!interface.isEmpty()) {
+ sendError(msg, QDBusError::UnknownMethod);
+ return true;
+ }
+ }
+
+ if (node.obj && (interface.isEmpty() ||
+ interface == QLatin1String(DBUS_INTERFACE_PROPERTIES))) {
+ //qDebug() << "QDBusConnectionPrivate::activateInternalFilters properties" << msg.d_ptr->msg;
+ if (msg.member() == QLatin1String("Get") && msg.signature() == QLatin1String("ss")) {
+ QDBusMessage reply = qDBusPropertyGet(node, msg);
+ send(reply);
+ return true;
+ } else if (msg.member() == QLatin1String("Set") && msg.signature() == QLatin1String("ssv")) {
+ QDBusMessage reply = qDBusPropertySet(node, msg);
+ send(reply);
+ return true;
+ } else if (msg.member() == QLatin1String("GetAll") && msg.signature() == QLatin1String("s")) {
+ QDBusMessage reply = qDBusPropertyGetAll(node, msg);
+ send(reply);
+ return true;
+ }
+
+ if (!interface.isEmpty()) {
+ sendError(msg, QDBusError::UnknownMethod);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void QDBusConnectionPrivate::activateObject(ObjectTreeNode &node, const QDBusMessage &msg,
+ int pathStartPos)
+{
+ // This is called by QDBusConnectionPrivate::handleObjectCall to place a call to a slot
+ // on the object.
+ //
+ // The call is routed through the adaptor sub-objects if we have any
+
+ // object may be null
+
+ if (node.flags & QDBusConnectionPrivate::VirtualObject) {
+ if (node.treeNode->handleMessage(msg, q(this))) {
+ return;
+ } else {
+ if (activateInternalFilters(node, msg))
+ return;
+ }
+ }
+
+ if (pathStartPos != msg.path().length()) {
+ node.flags &= ~QDBusConnection::ExportAllSignals;
+ node.obj = findChildObject(&node, msg.path(), pathStartPos);
+ if (!node.obj) {
+ sendError(msg, QDBusError::UnknownObject);
+ return;
+ }
+ }
+
+ QDBusAdaptorConnector *connector;
+ if (node.flags & QDBusConnection::ExportAdaptors &&
+ (connector = qDBusFindAdaptorConnector(node.obj))) {
+ int newflags = node.flags | QDBusConnection::ExportAllSlots;
+
+ if (msg.interface().isEmpty()) {
+ // place the call in all interfaces
+ // let the first one that handles it to work
+ QDBusAdaptorConnector::AdaptorMap::ConstIterator it =
+ connector->adaptors.constBegin();
+ QDBusAdaptorConnector::AdaptorMap::ConstIterator end =
+ connector->adaptors.constEnd();
+
+ for ( ; it != end; ++it)
+ if (activateCall(it->adaptor, newflags, msg))
+ return;
+ } else {
+ // check if we have an interface matching the name that was asked:
+ QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
+ it = std::lower_bound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
+ msg.interface());
+ if (it != connector->adaptors.constEnd() && msg.interface() == QLatin1String(it->interface)) {
+ if (!activateCall(it->adaptor, newflags, msg))
+ sendError(msg, QDBusError::UnknownMethod);
+ return;
+ }
+ }
+ }
+
+ // no adaptors matched or were exported
+ // try our standard filters
+ if (activateInternalFilters(node, msg))
+ return; // internal filters have already run or an error has been sent
+
+ // try the object itself:
+ if (node.flags & (QDBusConnection::ExportScriptableSlots|QDBusConnection::ExportNonScriptableSlots) ||
+ node.flags & (QDBusConnection::ExportScriptableInvokables|QDBusConnection::ExportNonScriptableInvokables)) {
+ bool interfaceFound = true;
+ if (!msg.interface().isEmpty())
+ interfaceFound = qDBusInterfaceInObject(node.obj, msg.interface());
+
+ if (interfaceFound) {
+ if (!activateCall(node.obj, node.flags, msg))
+ sendError(msg, QDBusError::UnknownMethod);
+ return;
+ }
+ }
+
+ // nothing matched, send an error code
+ if (msg.interface().isEmpty())
+ sendError(msg, QDBusError::UnknownMethod);
+ else
+ sendError(msg, QDBusError::UnknownInterface);
+}
+
+void QDBusConnectionPrivate::handleObjectCall(const QDBusMessage &msg)
+{
+ // if the msg is external, we were called from inside doDispatch
+ // that means the dispatchLock mutex is locked
+ // must not call out to user code in that case
+ //
+ // however, if the message is internal, handleMessage was called
+ // directly and no lock is in place. We can therefore call out to
+ // user code, if necessary
+ ObjectTreeNode result;
+ int usedLength;
+ QThread *objThread = 0;
+ QSemaphore sem;
+ bool semWait;
+
+ {
+ QDBusReadLocker locker(HandleObjectCallAction, this);
+ if (!findObject(&rootNode, msg.path(), usedLength, result)) {
+ // qDebug("Call failed: no object found at %s", qPrintable(msg.path()));
+ sendError(msg, QDBusError::UnknownObject);
+ return;
+ }
+
+ if (!result.obj) {
+ // no object -> no threading issues
+ // it's either going to be an error, or an internal filter
+ activateObject(result, msg, usedLength);
+ return;
+ }
+
+ objThread = result.obj->thread();
+ if (!objThread) {
+ send(msg.createErrorReply(QDBusError::InternalError,
+ QString::fromLatin1("Object '%1' (at path '%2')"
+ " has no thread. Cannot deliver message.")
+ .arg(result.obj->objectName(), msg.path())));
+ return;
+ }
+
+ if (!QDBusMessagePrivate::isLocal(msg)) {
+ // external incoming message
+ // post it and forget
+ postEventToThread(HandleObjectCallPostEventAction, result.obj,
+ new QDBusActivateObjectEvent(QDBusConnection(this), this, result,
+ usedLength, msg));
+ return;
+ } else if (objThread != QThread::currentThread()) {
+ // synchronize with other thread
+ postEventToThread(HandleObjectCallPostEventAction, result.obj,
+ new QDBusActivateObjectEvent(QDBusConnection(this), this, result,
+ usedLength, msg, &sem));
+ semWait = true;
+ } else {
+ semWait = false;
+ }
+ } // release the lock
+
+ if (semWait)
+ SEM_ACQUIRE(HandleObjectCallSemaphoreAction, sem);
+ else
+ activateObject(result, msg, usedLength);
+}
+
+QDBusActivateObjectEvent::~QDBusActivateObjectEvent()
+{
+ if (!handled) {
+ // we're being destroyed without delivering
+ // it means the object was deleted between posting and delivering
+ QDBusConnectionPrivate *that = QDBusConnectionPrivate::d(connection);
+ that->sendError(message, QDBusError::UnknownObject);
+ }
+
+ // semaphore releasing happens in ~QMetaCallEvent
+}
+
+void QDBusActivateObjectEvent::placeMetaCall(QObject *)
+{
+ QDBusConnectionPrivate *that = QDBusConnectionPrivate::d(connection);
+
+ QDBusLockerBase::reportThreadAction(HandleObjectCallPostEventAction,
+ QDBusLockerBase::BeforeDeliver, that);
+ that->activateObject(node, message, pathStartPos);
+ QDBusLockerBase::reportThreadAction(HandleObjectCallPostEventAction,
+ QDBusLockerBase::AfterDeliver, that);
+
+ handled = true;
+}
+
+void QDBusConnectionPrivate::handleSignal(const QString &key, const QDBusMessage& msg)
+{
+ SignalHookHash::const_iterator it = signalHooks.constFind(key);
+ SignalHookHash::const_iterator end = signalHooks.constEnd();
+ //qDebug("looking for: %s", path.toLocal8Bit().constData());
+ //qDBusDebug() << signalHooks.keys();
+ for ( ; it != end && it.key() == key; ++it) {
+ const SignalHook &hook = it.value();
+ if (!hook.service.isEmpty()) {
+ const QString owner =
+ shouldWatchService(hook.service) ?
+ watchedServices.value(hook.service).owner :
+ hook.service;
+ if (owner != msg.service())
+ continue;
+ }
+ if (!hook.path.isEmpty() && hook.path != msg.path())
+ continue;
+ if (!hook.signature.isEmpty() && hook.signature != msg.signature())
+ continue;
+ if (hook.signature.isEmpty() && !hook.signature.isNull() && !msg.signature().isEmpty())
+ continue;
+ if (!hook.argumentMatch.isEmpty()) {
+ const QVariantList arguments = msg.arguments();
+ if (hook.argumentMatch.size() > arguments.size())
+ continue;
+
+ bool matched = true;
+ for (int i = 0; i < hook.argumentMatch.size(); ++i) {
+ const QString &param = hook.argumentMatch.at(i);
+ if (param.isNull())
+ continue; // don't try to match against this
+ if (param == arguments.at(i).toString())
+ continue; // matched
+ matched = false;
+ break;
+ }
+ if (!matched)
+ continue;
+ }
+
+ activateSignal(hook, msg);
+ }
+}
+
+void QDBusConnectionPrivate::handleSignal(const QDBusMessage& msg)
+{
+ // We call handlesignal(QString, QDBusMessage) three times:
+ // one with member:interface
+ // one with member:
+ // one with :interface
+ // This allows us to match signals with wildcards on member or interface
+ // (but not both)
+
+ QString key = msg.member();
+ key.reserve(key.length() + 1 + msg.interface().length());
+ key += QLatin1Char(':');
+ key += msg.interface();
+
+ QDBusReadLocker locker(HandleSignalAction, this);
+ handleSignal(key, msg); // one try
+
+ key.truncate(msg.member().length() + 1); // keep the ':'
+ handleSignal(key, msg); // second try
+
+ key = QLatin1Char(':');
+ key += msg.interface();
+ handleSignal(key, msg); // third try
+}
+
+static dbus_int32_t server_slot = -1;
+
+void QDBusConnectionPrivate::setServer(DBusServer *s, const QDBusErrorInternal &error)
+{
+ mode = ServerMode;
+ if (!s) {
+ handleError(error);
+ return;
+ }
+
+ server = s;
+
+ dbus_bool_t data_allocated = q_dbus_server_allocate_data_slot(&server_slot);
+ if (data_allocated && server_slot < 0)
+ return;
+
+ dbus_bool_t watch_functions_set = q_dbus_server_set_watch_functions(server,
+ qDBusAddWatch,
+ qDBusRemoveWatch,
+ qDBusToggleWatch,
+ this, 0);
+ //qDebug() << "watch_functions_set" << watch_functions_set;
+ Q_UNUSED(watch_functions_set);
+
+ dbus_bool_t time_functions_set = q_dbus_server_set_timeout_functions(server,
+ qDBusAddTimeout,
+ qDBusRemoveTimeout,
+ qDBusToggleTimeout,
+ this, 0);
+ //qDebug() << "time_functions_set" << time_functions_set;
+ Q_UNUSED(time_functions_set);
+
+ q_dbus_server_set_new_connection_function(server, qDBusNewConnection, this, 0);
+
+ dbus_bool_t data_set = q_dbus_server_set_data(server, server_slot, this, 0);
+ //qDebug() << "data_set" << data_set;
+ Q_UNUSED(data_set);
+}
+
+void QDBusConnectionPrivate::setPeer(DBusConnection *c, const QDBusErrorInternal &error)
+{
+ mode = PeerMode;
+ if (!c) {
+ handleError(error);
+ return;
+ }
+
+ connection = c;
+
+ q_dbus_connection_set_exit_on_disconnect(connection, false);
+ q_dbus_connection_set_watch_functions(connection,
+ qDBusAddWatch,
+ qDBusRemoveWatch,
+ qDBusToggleWatch,
+ this, 0);
+ q_dbus_connection_set_timeout_functions(connection,
+ qDBusAddTimeout,
+ qDBusRemoveTimeout,
+ qDBusToggleTimeout,
+ this, 0);
+ q_dbus_connection_set_dispatch_status_function(connection, qDBusUpdateDispatchStatus, this, 0);
+ q_dbus_connection_add_filter(connection,
+ qDBusSignalFilter,
+ this, 0);
+
+ QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection);
+}
+
+static QDBusConnection::ConnectionCapabilities connectionCapabilies(DBusConnection *connection)
+{
+ QDBusConnection::ConnectionCapabilities result = 0;
+ typedef dbus_bool_t (*can_send_type_t)(DBusConnection *, int);
+ static can_send_type_t can_send_type = 0;
+
+#if defined(QT_LINKED_LIBDBUS)
+# if DBUS_VERSION-0 >= 0x010400
+ can_send_type = dbus_connection_can_send_type;
+# endif
+#else
+ // run-time check if the next functions are available
+ can_send_type = (can_send_type_t)qdbus_resolve_conditionally("dbus_connection_can_send_type");
+#endif
+
+#ifndef DBUS_TYPE_UNIX_FD
+# define DBUS_TYPE_UNIX_FD int('h')
+#endif
+ if (can_send_type && can_send_type(connection, DBUS_TYPE_UNIX_FD))
+ result |= QDBusConnection::UnixFileDescriptorPassing;
+
+ return result;
+}
+
+void QDBusConnectionPrivate::setConnection(DBusConnection *dbc, const QDBusErrorInternal &error)
+{
+ mode = ClientMode;
+ if (!dbc) {
+ handleError(error);
+ return;
+ }
+
+ connection = dbc;
+
+ const char *service = q_dbus_bus_get_unique_name(connection);
+ Q_ASSERT(service);
+ baseService = QString::fromUtf8(service);
+ capabilities = connectionCapabilies(connection);
+
+ q_dbus_connection_set_exit_on_disconnect(connection, false);
+ q_dbus_connection_set_watch_functions(connection, qDBusAddWatch, qDBusRemoveWatch,
+ qDBusToggleWatch, this, 0);
+ q_dbus_connection_set_timeout_functions(connection, qDBusAddTimeout, qDBusRemoveTimeout,
+ qDBusToggleTimeout, this, 0);
+ q_dbus_connection_set_dispatch_status_function(connection, qDBusUpdateDispatchStatus, this, 0);
+ q_dbus_connection_add_filter(connection, qDBusSignalFilter, this, 0);
+
+ // Initialize the hooks for the NameAcquired and NameLost signals
+ // we don't use connectSignal here because we don't need the rules to be sent to the bus
+ // the bus will always send us these two signals
+ SignalHook hook;
+ hook.service = dbusServiceString();
+ hook.path.clear(); // no matching
+ hook.obj = this;
+ hook.params << QMetaType::Void << QVariant::String; // both functions take a QString as parameter and return void
+
+ hook.midx = staticMetaObject.indexOfSlot("registerServiceNoLock(QString)");
+ Q_ASSERT(hook.midx != -1);
+ signalHooks.insert(QLatin1String("NameAcquired:" DBUS_INTERFACE_DBUS), hook);
+
+ hook.midx = staticMetaObject.indexOfSlot("unregisterServiceNoLock(QString)");
+ Q_ASSERT(hook.midx != -1);
+ signalHooks.insert(QLatin1String("NameLost:" DBUS_INTERFACE_DBUS), hook);
+
+ qDBusDebug() << this << ": connected successfully";
+
+ // schedule a dispatch:
+ QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection);
+}
+
+extern "C"{
+static void qDBusResultReceived(DBusPendingCall *pending, void *user_data)
+{
+ QDBusPendingCallPrivate *call = reinterpret_cast<QDBusPendingCallPrivate *>(user_data);
+ Q_ASSERT(call->pending == pending);
+ Q_UNUSED(pending);
+ QDBusConnectionPrivate::processFinishedCall(call);
+}
+}
+
+void QDBusConnectionPrivate::waitForFinished(QDBusPendingCallPrivate *pcall)
+{
+ Q_ASSERT(pcall->pending);
+ //Q_ASSERT(pcall->mutex.isLocked()); // there's no such function
+
+ if (pcall->waitingForFinished) {
+ // another thread is already waiting
+ pcall->waitForFinishedCondition.wait(&pcall->mutex);
+ } else {
+ pcall->waitingForFinished = true;
+ pcall->mutex.unlock();
+
+ {
+ QDBusDispatchLocker locker(PendingCallBlockAction, this);
+ q_dbus_pending_call_block(pcall->pending);
+ // QDBusConnectionPrivate::processFinishedCall() is called automatically
+ }
+ pcall->mutex.lock();
+
+ if (pcall->pending) {
+ q_dbus_pending_call_unref(pcall->pending);
+ pcall->pending = 0;
+ }
+
+ pcall->waitForFinishedCondition.wakeAll();
+ }
+}
+
+void QDBusConnectionPrivate::processFinishedCall(QDBusPendingCallPrivate *call)
+{
+ QDBusConnectionPrivate *connection = const_cast<QDBusConnectionPrivate *>(call->connection);
+
+ QMutexLocker locker(&call->mutex);
+
+ connection->pendingCalls.removeOne(call);
+
+ QDBusMessage &msg = call->replyMessage;
+ if (call->pending) {
+ // decode the message
+ DBusMessage *reply = q_dbus_pending_call_steal_reply(call->pending);
+ msg = QDBusMessagePrivate::fromDBusMessage(reply, connection->capabilities);
+ q_dbus_message_unref(reply);
+ }
+ qDBusDebug() << connection << "got message reply (async):" << msg;
+
+ // Check if the reply has the expected signature
+ call->checkReceivedSignature();
+
+ if (!call->receiver.isNull() && call->methodIdx != -1 && msg.type() == QDBusMessage::ReplyMessage) {
+ // Deliver the return values of a remote function call.
+ //
+ // There is only one connection and it is specified by idx
+ // The slot must have the same parameter types that the message does
+ // The slot may have less parameters than the message
+ // The slot may optionally have one final parameter that is QDBusMessage
+ // The slot receives read-only copies of the message (i.e., pass by value or by const-ref)
+
+ QDBusCallDeliveryEvent *e = prepareReply(connection, call->receiver, call->methodIdx,
+ call->metaTypes, msg);
+ if (e)
+ connection->postEventToThread(MessageResultReceivedAction, call->receiver, e);
+ else
+ qDBusDebug() << "Deliver failed!";
+ }
+
+ if (call->pending && !call->waitingForFinished) {
+ q_dbus_pending_call_unref(call->pending);
+ call->pending = 0;
+ }
+
+ locker.unlock();
+
+ // Are there any watchers?
+ if (call->watcherHelper)
+ call->watcherHelper->emitSignals(msg, call->sentMessage);
+
+ if (msg.type() == QDBusMessage::ErrorMessage)
+ emit connection->callWithCallbackFailed(QDBusError(msg), call->sentMessage);
+
+ if (!call->ref.deref())
+ delete call;
+}
+
+int QDBusConnectionPrivate::send(const QDBusMessage& message)
+{
+ if (QDBusMessagePrivate::isLocal(message))
+ return -1; // don't send; the reply will be retrieved by the caller
+ // through the d_ptr->localReply link
+
+ QDBusError error;
+ DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, capabilities, &error);
+ if (!msg) {
+ if (message.type() == QDBusMessage::MethodCallMessage)
+ qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\": %s",
+ qPrintable(message.service()), qPrintable(message.path()),
+ qPrintable(message.interface()), qPrintable(message.member()),
+ qPrintable(error.message()));
+ else if (message.type() == QDBusMessage::SignalMessage)
+ qWarning("QDBusConnection: error: could not send signal path \"%s\" interface \"%s\" member \"%s\": %s",
+ qPrintable(message.path()), qPrintable(message.interface()),
+ qPrintable(message.member()),
+ qPrintable(error.message()));
+ else
+ qWarning("QDBusConnection: error: could not send %s message to service \"%s\": %s",
+ message.type() == QDBusMessage::ReplyMessage ? "reply" :
+ message.type() == QDBusMessage::ErrorMessage ? "error" :
+ "invalid", qPrintable(message.service()),
+ qPrintable(error.message()));
+ lastError = error;
+ return 0;
+ }
+
+ q_dbus_message_set_no_reply(msg, true); // the reply would not be delivered to anything
+
+ qDBusDebug() << this << "sending message (no reply):" << message;
+ checkThread();
+ bool isOk = q_dbus_connection_send(connection, msg, 0);
+ int serial = 0;
+ if (isOk)
+ serial = q_dbus_message_get_serial(msg);
+
+ q_dbus_message_unref(msg);
+ return serial;
+}
+
+QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message,
+ int sendMode, int timeout)
+{
+ checkThread();
+ if ((sendMode == QDBus::BlockWithGui || sendMode == QDBus::Block)
+ && isServiceRegisteredByThread(message.service()))
+ // special case for synchronous local calls
+ return sendWithReplyLocal(message);
+
+ if (!QCoreApplication::instance() || sendMode == QDBus::Block) {
+ QDBusError err;
+ DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, capabilities, &err);
+ if (!msg) {
+ qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\": %s",
+ qPrintable(message.service()), qPrintable(message.path()),
+ qPrintable(message.interface()), qPrintable(message.member()),
+ qPrintable(err.message()));
+ lastError = err;
+ return QDBusMessage::createError(err);
+ }
+
+ qDBusDebug() << this << "sending message (blocking):" << message;
+ QDBusErrorInternal error;
+ DBusMessage *reply = q_dbus_connection_send_with_reply_and_block(connection, msg, timeout, error);
+
+ q_dbus_message_unref(msg);
+
+ if (!!error) {
+ lastError = err = error;
+ return QDBusMessage::createError(err);
+ }
+
+ QDBusMessage amsg = QDBusMessagePrivate::fromDBusMessage(reply, capabilities);
+ q_dbus_message_unref(reply);
+ qDBusDebug() << this << "got message reply (blocking):" << amsg;
+
+ return amsg;
+ } else { // use the event loop
+ QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, 0, 0, 0, timeout);
+ Q_ASSERT(pcall);
+
+ if (pcall->replyMessage.type() == QDBusMessage::InvalidMessage) {
+ pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
+ QEventLoop loop;
+ loop.connect(pcall->watcherHelper, SIGNAL(reply(QDBusMessage)), SLOT(quit()));
+ loop.connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), SLOT(quit()));
+
+ // enter the event loop and wait for a reply
+ loop.exec(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents);
+ }
+
+ QDBusMessage reply = pcall->replyMessage;
+ lastError = QDBusError(reply); // set or clear error
+
+ bool r = pcall->ref.deref();
+ Q_ASSERT(!r);
+ Q_UNUSED(r);
+
+ delete pcall;
+ return reply;
+ }
+}
+
+QDBusMessage QDBusConnectionPrivate::sendWithReplyLocal(const QDBusMessage &message)
+{
+ qDBusDebug() << this << "sending message via local-loop:" << message;
+
+ QDBusMessage localCallMsg = QDBusMessagePrivate::makeLocal(*this, message);
+ bool handled = handleMessage(localCallMsg);
+
+ if (!handled) {
+ QString interface = message.interface();
+ if (interface.isEmpty())
+ interface = QLatin1String("<no-interface>");
+ return QDBusMessage::createError(QDBusError::InternalError,
+ QString::fromLatin1("Internal error trying to call %1.%2 at %3 (signature '%4'")
+ .arg(interface, message.member(),
+ message.path(), message.signature()));
+ }
+
+ // if the message was handled, there might be a reply
+ QDBusMessage localReplyMsg = QDBusMessagePrivate::makeLocalReply(*this, localCallMsg);
+ if (localReplyMsg.type() == QDBusMessage::InvalidMessage) {
+ qWarning("QDBusConnection: cannot call local method '%s' at object %s (with signature '%s') "
+ "on blocking mode", qPrintable(message.member()), qPrintable(message.path()),
+ qPrintable(message.signature()));
+ return QDBusMessage::createError(
+ QDBusError(QDBusError::InternalError,
+ QLatin1String("local-loop message cannot have delayed replies")));
+ }
+
+ // there is a reply
+ qDBusDebug() << this << "got message via local-loop:" << localReplyMsg;
+ return localReplyMsg;
+}
+
+QDBusPendingCallPrivate *QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message,
+ QObject *receiver, const char *returnMethod,
+ const char *errorMethod, int timeout)
+{
+ if (isServiceRegisteredByThread(message.service())) {
+ // special case for local calls
+ QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate(message, this);
+ pcall->replyMessage = sendWithReplyLocal(message);
+ if (receiver && returnMethod)
+ pcall->setReplyCallback(receiver, returnMethod);
+
+ if (errorMethod) {
+ pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
+ connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), receiver, errorMethod,
+ Qt::QueuedConnection);
+ pcall->watcherHelper->moveToThread(thread());
+ }
+
+ if ((receiver && returnMethod) || errorMethod) {
+ // no one waiting, will delete pcall in processFinishedCall()
+ pcall->ref.store(1);
+ } else {
+ // set double ref to prevent race between processFinishedCall() and ref counting
+ // by QDBusPendingCall::QExplicitlySharedDataPointer<QDBusPendingCallPrivate>
+ pcall->ref.store(2);
+ }
+ processFinishedCall(pcall);
+ return pcall;
+ }
+
+ checkThread();
+ QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate(message, this);
+ if (receiver && returnMethod)
+ pcall->setReplyCallback(receiver, returnMethod);
+
+ if (errorMethod) {
+ pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
+ connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), receiver, errorMethod,
+ Qt::QueuedConnection);
+ pcall->watcherHelper->moveToThread(thread());
+ }
+
+ if ((receiver && returnMethod) || errorMethod) {
+ // no one waiting, will delete pcall in processFinishedCall()
+ pcall->ref.store(1);
+ } else {
+ // set double ref to prevent race between processFinishedCall() and ref counting
+ // by QDBusPendingCall::QExplicitlySharedDataPointer<QDBusPendingCallPrivate>
+ pcall->ref.store(2);
+ }
+
+ QDBusError error;
+ DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, capabilities, &error);
+ if (!msg) {
+ qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\": %s",
+ qPrintable(message.service()), qPrintable(message.path()),
+ qPrintable(message.interface()), qPrintable(message.member()),
+ qPrintable(error.message()));
+ pcall->replyMessage = QDBusMessage::createError(error);
+ lastError = error;
+ processFinishedCall(pcall);
+ return pcall;
+ }
+
+ qDBusDebug() << this << "sending message (async):" << message;
+ DBusPendingCall *pending = 0;
+
+ QDBusDispatchLocker locker(SendWithReplyAsyncAction, this);
+ if (q_dbus_connection_send_with_reply(connection, msg, &pending, timeout)) {
+ if (pending) {
+ q_dbus_message_unref(msg);
+
+ pcall->pending = pending;
+ q_dbus_pending_call_set_notify(pending, qDBusResultReceived, pcall, 0);
+
+ // DBus won't notify us when a peer disconnects so we need to track these ourselves
+ if (mode == QDBusConnectionPrivate::PeerMode)
+ pendingCalls.append(pcall);
+
+ return pcall;
+ } else {
+ // we're probably disconnected at this point
+ lastError = error = QDBusError(QDBusError::Disconnected, QLatin1String("Not connected to server"));
+ }
+ } else {
+ lastError = error = QDBusError(QDBusError::NoMemory, QLatin1String("Out of memory"));
+ }
+
+ q_dbus_message_unref(msg);
+ pcall->replyMessage = QDBusMessage::createError(error);
+ processFinishedCall(pcall);
+ return pcall;
+}
+
+bool QDBusConnectionPrivate::connectSignal(const QString &service,
+ const QString &path, const QString &interface, const QString &name,
+ const QStringList &argumentMatch, const QString &signature,
+ QObject *receiver, const char *slot)
+{
+ // check the slot
+ QDBusConnectionPrivate::SignalHook hook;
+ QString key;
+ QString name2 = name;
+ if (name2.isNull())
+ name2.detach();
+
+ hook.signature = signature;
+ if (!prepareHook(hook, key, service, path, interface, name, argumentMatch, receiver, slot, 0, false))
+ return false; // don't connect
+
+ // avoid duplicating:
+ QDBusConnectionPrivate::SignalHookHash::ConstIterator it = signalHooks.constFind(key);
+ QDBusConnectionPrivate::SignalHookHash::ConstIterator end = signalHooks.constEnd();
+ for ( ; it != end && it.key() == key; ++it) {
+ const QDBusConnectionPrivate::SignalHook &entry = it.value();
+ if (entry.service == hook.service &&
+ entry.path == hook.path &&
+ entry.signature == hook.signature &&
+ entry.obj == hook.obj &&
+ entry.midx == hook.midx &&
+ entry.argumentMatch == hook.argumentMatch) {
+ // no need to compare the parameters if it's the same slot
+ return true; // already there
+ }
+ }
+
+ connectSignal(key, hook);
+ return true;
+}
+
+void QDBusConnectionPrivate::connectSignal(const QString &key, const SignalHook &hook)
+{
+ signalHooks.insertMulti(key, hook);
+ connect(hook.obj, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)),
+ Qt::ConnectionType(Qt::DirectConnection | Qt::UniqueConnection));
+
+ MatchRefCountHash::iterator it = matchRefCounts.find(hook.matchRule);
+
+ if (it != matchRefCounts.end()) { // Match already present
+ it.value() = it.value() + 1;
+ return;
+ }
+
+ matchRefCounts.insert(hook.matchRule, 1);
+
+ if (connection) {
+ if (mode != QDBusConnectionPrivate::PeerMode) {
+ qDBusDebug("Adding rule: %s", hook.matchRule.constData());
+ q_dbus_bus_add_match(connection, hook.matchRule, NULL);
+
+ // Successfully connected the signal
+ // Do we need to watch for this name?
+ if (shouldWatchService(hook.service)) {
+ WatchedServicesHash::mapped_type &data = watchedServices[hook.service];
+ if (++data.refcount == 1) {
+ // we need to watch for this service changing
+ connectSignal(dbusServiceString(), QString(), dbusInterfaceString(),
+ QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(),
+ this, SLOT(serviceOwnerChangedNoLock(QString,QString,QString)));
+ data.owner = getNameOwnerNoCache(hook.service);
+ qDBusDebug() << this << "Watching service" << hook.service << "for owner changes (current owner:"
+ << data.owner << ")";
+ }
+ }
+ }
+ }
+}
+
+bool QDBusConnectionPrivate::disconnectSignal(const QString &service,
+ const QString &path, const QString &interface, const QString &name,
+ const QStringList &argumentMatch, const QString &signature,
+ QObject *receiver, const char *slot)
+{
+ // check the slot
+ QDBusConnectionPrivate::SignalHook hook;
+ QString key;
+ QString name2 = name;
+ if (name2.isNull())
+ name2.detach();
+
+ hook.signature = signature;
+ if (!prepareHook(hook, key, service, path, interface, name, argumentMatch, receiver, slot, 0, false))
+ return false; // don't disconnect
+
+ // avoid duplicating:
+ QDBusConnectionPrivate::SignalHookHash::Iterator it = signalHooks.find(key);
+ QDBusConnectionPrivate::SignalHookHash::Iterator end = signalHooks.end();
+ for ( ; it != end && it.key() == key; ++it) {
+ const QDBusConnectionPrivate::SignalHook &entry = it.value();
+ if (entry.service == hook.service &&
+ entry.path == hook.path &&
+ entry.signature == hook.signature &&
+ entry.obj == hook.obj &&
+ entry.midx == hook.midx &&
+ entry.argumentMatch == hook.argumentMatch) {
+ // no need to compare the parameters if it's the same slot
+ disconnectSignal(it);
+ return true; // it was there
+ }
+ }
+
+ // the slot was not found
+ return false;
+}
+
+QDBusConnectionPrivate::SignalHookHash::Iterator
+QDBusConnectionPrivate::disconnectSignal(SignalHookHash::Iterator &it)
+{
+ const SignalHook &hook = it.value();
+
+ bool erase = false;
+ MatchRefCountHash::iterator i = matchRefCounts.find(hook.matchRule);
+ if (i == matchRefCounts.end()) {
+ qWarning("QDBusConnectionPrivate::disconnectSignal: MatchRule not found in matchRefCounts!!");
+ } else {
+ if (i.value() == 1) {
+ erase = true;
+ matchRefCounts.erase(i);
+ }
+ else {
+ i.value() = i.value() - 1;
+ }
+ }
+
+ // we don't care about errors here
+ if (connection && erase) {
+ if (mode != QDBusConnectionPrivate::PeerMode) {
+ qDBusDebug("Removing rule: %s", hook.matchRule.constData());
+ q_dbus_bus_remove_match(connection, hook.matchRule, NULL);
+
+ // Successfully disconnected the signal
+ // Were we watching for this name?
+ WatchedServicesHash::Iterator sit = watchedServices.find(hook.service);
+ if (sit != watchedServices.end()) {
+ if (--sit.value().refcount == 0) {
+ watchedServices.erase(sit);
+ disconnectSignal(dbusServiceString(), QString(), dbusInterfaceString(),
+ QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(),
+ this, SLOT(serviceOwnerChangedNoLock(QString,QString,QString)));
+ }
+ }
+ }
+
+ }
+
+ return signalHooks.erase(it);
+}
+
+void QDBusConnectionPrivate::registerObject(const ObjectTreeNode *node)
+{
+ connect(node->obj, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)),
+ Qt::DirectConnection);
+
+ if (node->flags & (QDBusConnection::ExportAdaptors
+ | QDBusConnection::ExportScriptableSignals
+ | QDBusConnection::ExportNonScriptableSignals)) {
+ QDBusAdaptorConnector *connector = qDBusCreateAdaptorConnector(node->obj);
+
+ if (node->flags & (QDBusConnection::ExportScriptableSignals
+ | QDBusConnection::ExportNonScriptableSignals)) {
+ connector->disconnectAllSignals(node->obj);
+ connector->connectAllSignals(node->obj);
+ }
+
+ // disconnect and reconnect to avoid duplicates
+ connector->disconnect(SIGNAL(relaySignal(QObject*,const QMetaObject*,int,QVariantList)),
+ this, SLOT(relaySignal(QObject*,const QMetaObject*,int,QVariantList)));
+ connect(connector, SIGNAL(relaySignal(QObject*,const QMetaObject*,int,QVariantList)),
+ this, SLOT(relaySignal(QObject*,const QMetaObject*,int,QVariantList)),
+ Qt::DirectConnection);
+ }
+}
+
+void QDBusConnectionPrivate::unregisterObject(const QString &path, QDBusConnection::UnregisterMode mode)
+{
+ QDBusConnectionPrivate::ObjectTreeNode *node = &rootNode;
+ QStringList pathComponents;
+ int i;
+ if (path == QLatin1String("/")) {
+ i = 0;
+ } else {
+ pathComponents = path.split(QLatin1Char('/'));
+ i = 1;
+ }
+
+ huntAndUnregister(pathComponents, i, mode, node);
+}
+
+void QDBusConnectionPrivate::connectRelay(const QString &service,
+ const QString &path, const QString &interface,
+ QDBusAbstractInterface *receiver,
+ const QMetaMethod &signal)
+{
+ // this function is called by QDBusAbstractInterface when one of its signals is connected
+ // we set up a relay from D-Bus into it
+ SignalHook hook;
+ QString key;
+
+ QByteArray sig;
+ sig.append(QSIGNAL_CODE + '0');
+ sig.append(signal.methodSignature());
+ if (!prepareHook(hook, key, service, path, interface, QString(), QStringList(), receiver, sig,
+ QDBusAbstractInterface::staticMetaObject.methodCount(), true))
+ return; // don't connect
+
+ // add it to our list:
+ QDBusWriteLocker locker(ConnectRelayAction, this);
+ SignalHookHash::ConstIterator it = signalHooks.constFind(key);
+ SignalHookHash::ConstIterator end = signalHooks.constEnd();
+ for ( ; it != end && it.key() == key; ++it) {
+ const SignalHook &entry = it.value();
+ if (entry.service == hook.service &&
+ entry.path == hook.path &&
+ entry.signature == hook.signature &&
+ entry.obj == hook.obj &&
+ entry.midx == hook.midx)
+ return; // already there, no need to re-add
+ }
+
+ connectSignal(key, hook);
+}
+
+void QDBusConnectionPrivate::disconnectRelay(const QString &service,
+ const QString &path, const QString &interface,
+ QDBusAbstractInterface *receiver,
+ const QMetaMethod &signal)
+{
+ // this function is called by QDBusAbstractInterface when one of its signals is disconnected
+ // we remove relay from D-Bus into it
+ SignalHook hook;
+ QString key;
+
+ QByteArray sig;
+ sig.append(QSIGNAL_CODE + '0');
+ sig.append(signal.methodSignature());
+ if (!prepareHook(hook, key, service, path, interface, QString(), QStringList(), receiver, sig,
+ QDBusAbstractInterface::staticMetaObject.methodCount(), true))
+ return; // don't connect
+
+ // remove it from our list:
+ QDBusWriteLocker locker(DisconnectRelayAction, this);
+ SignalHookHash::Iterator it = signalHooks.find(key);
+ SignalHookHash::Iterator end = signalHooks.end();
+ for ( ; it != end && it.key() == key; ++it) {
+ const SignalHook &entry = it.value();
+ if (entry.service == hook.service &&
+ entry.path == hook.path &&
+ entry.signature == hook.signature &&
+ entry.obj == hook.obj &&
+ entry.midx == hook.midx) {
+ // found it
+ disconnectSignal(it);
+ return;
+ }
+ }
+}
+
+QString QDBusConnectionPrivate::getNameOwner(const QString& serviceName)
+{
+ if (QDBusUtil::isValidUniqueConnectionName(serviceName))
+ return serviceName;
+ if (!connection)
+ return QString();
+
+ {
+ // acquire a read lock for the cache
+ QReadLocker locker(&lock);
+ WatchedServicesHash::ConstIterator it = watchedServices.constFind(serviceName);
+ if (it != watchedServices.constEnd())
+ return it->owner;
+ }
+
+ // not cached
+ return getNameOwnerNoCache(serviceName);
+}
+
+QString QDBusConnectionPrivate::getNameOwnerNoCache(const QString &serviceName)
+{
+ QDBusMessage msg = QDBusMessage::createMethodCall(dbusServiceString(),
+ QLatin1String(DBUS_PATH_DBUS), dbusInterfaceString(),
+ QLatin1String("GetNameOwner"));
+ QDBusMessagePrivate::setParametersValidated(msg, true);
+ msg << serviceName;
+ QDBusMessage reply = sendWithReply(msg, QDBus::Block);
+ if (reply.type() == QDBusMessage::ReplyMessage)
+ return reply.arguments().at(0).toString();
+ return QString();
+}
+
+QDBusMetaObject *
+QDBusConnectionPrivate::findMetaObject(const QString &service, const QString &path,
+ const QString &interface, QDBusError &error)
+{
+ // service must be a unique connection name
+ if (!interface.isEmpty()) {
+ QDBusReadLocker locker(FindMetaObject1Action, this);
+ QDBusMetaObject *mo = cachedMetaObjects.value(interface, 0);
+ if (mo)
+ return mo;
+ }
+
+ // introspect the target object
+ QDBusMessage msg = QDBusMessage::createMethodCall(service, path,
+ QLatin1String(DBUS_INTERFACE_INTROSPECTABLE),
+ QLatin1String("Introspect"));
+ QDBusMessagePrivate::setParametersValidated(msg, true);
+
+ QDBusMessage reply = sendWithReply(msg, QDBus::Block);
+
+ // it doesn't exist yet, we have to create it
+ QDBusWriteLocker locker(FindMetaObject2Action, this);
+ QDBusMetaObject *mo = 0;
+ if (!interface.isEmpty())
+ mo = cachedMetaObjects.value(interface, 0);
+ if (mo)
+ // maybe it got created when we switched from read to write lock
+ return mo;
+
+ QString xml;
+ if (reply.type() == QDBusMessage::ReplyMessage) {
+ if (reply.signature() == QLatin1String("s"))
+ // fetch the XML description
+ xml = reply.arguments().at(0).toString();
+ } else {
+ error = QDBusError(reply);
+ lastError = error;
+ if (reply.type() != QDBusMessage::ErrorMessage || error.type() != QDBusError::UnknownMethod)
+ return 0; // error
+ }
+
+ // release the lock and return
+ QDBusMetaObject *result = QDBusMetaObject::createMetaObject(interface, xml,
+ cachedMetaObjects, error);
+ lastError = error;
+ return result;
+}
+
+void QDBusConnectionPrivate::registerService(const QString &serviceName)
+{
+ QDBusWriteLocker locker(RegisterServiceAction, this);
+ registerServiceNoLock(serviceName);
+}
+
+void QDBusConnectionPrivate::registerServiceNoLock(const QString &serviceName)
+{
+ serviceNames.append(serviceName);
+}
+
+void QDBusConnectionPrivate::unregisterService(const QString &serviceName)
+{
+ QDBusWriteLocker locker(UnregisterServiceAction, this);
+ unregisterServiceNoLock(serviceName);
+}
+
+void QDBusConnectionPrivate::unregisterServiceNoLock(const QString &serviceName)
+{
+ serviceNames.removeAll(serviceName);
+}
+
+bool QDBusConnectionPrivate::isServiceRegisteredByThread(const QString &serviceName)
+{
+ if (!serviceName.isEmpty() && serviceName == baseService)
+ return true;
+ if (serviceName == dbusServiceString())
+ return false;
+
+ QDBusReadLocker locker(UnregisterServiceAction, this);
+ return serviceNames.contains(serviceName);
+}
+
+void QDBusConnectionPrivate::postEventToThread(int action, QObject *object, QEvent *ev)
+{
+ QDBusLockerBase::reportThreadAction(action, QDBusLockerBase::BeforePost, this);
+ QCoreApplication::postEvent(object, ev);
+ QDBusLockerBase::reportThreadAction(action, QDBusLockerBase::AfterPost, this);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff -Naur qt-everywhere-opensource-src-5.3.1/qtbase/src/gui/opengl/qopenglfunctions.cpp qt-everywhere-opensource-src-5.3.1.new/qtbase/src/gui/opengl/qopenglfunctions.cpp
--- qt-everywhere-opensource-src-5.3.1/qtbase/src/gui/opengl/qopenglfunctions.cpp 2014-06-19 12:08:06.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtbase/src/gui/opengl/qopenglfunctions.cpp 2014-08-13 04:35:08.402435904 +0200
@@ -283,46 +283,48 @@
QSurfaceFormat format = QOpenGLContext::currentContext()->format();
QOpenGLExtensionMatcher extensions;
- // Recognize features by extension name.
- if (extensions.match("GL_ARB_multitexture"))
- features |= QOpenGLFunctions::Multitexture;
- if (extensions.match("GL_ARB_shader_objects"))
- features |= QOpenGLFunctions::Shaders;
- if (extensions.match("GL_EXT_framebuffer_object") ||
- extensions.match("GL_ARB_framebuffer_object"))
- features |= QOpenGLFunctions::Framebuffers;
- if (extensions.match("GL_EXT_blend_color"))
- features |= QOpenGLFunctions::BlendColor;
- if (extensions.match("GL_EXT_blend_equation_separate"))
- features |= QOpenGLFunctions::BlendEquationSeparate;
- if (extensions.match("GL_EXT_blend_func_separate"))
- features |= QOpenGLFunctions::BlendFuncSeparate;
- if (extensions.match("GL_EXT_blend_subtract"))
- features |= QOpenGLFunctions::BlendSubtract;
- if (extensions.match("GL_ARB_texture_compression"))
- features |= QOpenGLFunctions::CompressedTextures;
- if (extensions.match("GL_ARB_multisample"))
- features |= QOpenGLFunctions::Multisample;
- if (extensions.match("GL_ARB_texture_non_power_of_two"))
- features |= QOpenGLFunctions::NPOTTextures |
- QOpenGLFunctions::NPOTTextureRepeat;
-
- // assume version 2.0 or higher
- features |= QOpenGLFunctions::BlendColor |
- QOpenGLFunctions::BlendEquation |
- QOpenGLFunctions::Multitexture |
- QOpenGLFunctions::CompressedTextures |
- QOpenGLFunctions::Multisample |
- QOpenGLFunctions::BlendFuncSeparate |
- QOpenGLFunctions::Buffers |
- QOpenGLFunctions::Shaders |
- QOpenGLFunctions::StencilSeparate |
- QOpenGLFunctions::BlendEquationSeparate |
- QOpenGLFunctions::NPOTTextures |
- QOpenGLFunctions::NPOTTextureRepeat;
-
if (format.majorVersion() >= 3)
features |= QOpenGLFunctions::Framebuffers;
+ else if (extensions.match("GL_EXT_framebuffer_object") ||
+ extensions.match("GL_ARB_framebuffer_object"))
+ features |= QOpenGLFunctions::Framebuffers;
+
+ if (format.majorVersion() >= 2) {
+ features |= QOpenGLFunctions::BlendColor |
+ QOpenGLFunctions::BlendEquation |
+ QOpenGLFunctions::BlendSubtract |
+ QOpenGLFunctions::Multitexture |
+ QOpenGLFunctions::CompressedTextures |
+ QOpenGLFunctions::Multisample |
+ QOpenGLFunctions::BlendFuncSeparate |
+ QOpenGLFunctions::Buffers |
+ QOpenGLFunctions::Shaders |
+ QOpenGLFunctions::StencilSeparate |
+ QOpenGLFunctions::BlendEquationSeparate |
+ QOpenGLFunctions::NPOTTextures |
+ QOpenGLFunctions::NPOTTextureRepeat;
+ } else {
+ // Recognize features by extension name.
+ if (extensions.match("GL_ARB_multitexture"))
+ features |= QOpenGLFunctions::Multitexture;
+ if (extensions.match("GL_ARB_shader_objects"))
+ features |= QOpenGLFunctions::Shaders;
+ if (extensions.match("GL_EXT_blend_color"))
+ features |= QOpenGLFunctions::BlendColor;
+ if (extensions.match("GL_EXT_blend_equation_separate"))
+ features |= QOpenGLFunctions::BlendEquationSeparate;
+ if (extensions.match("GL_EXT_blend_subtract"))
+ features |= QOpenGLFunctions::BlendSubtract;
+ if (extensions.match("GL_EXT_blend_func_separate"))
+ features |= QOpenGLFunctions::BlendFuncSeparate;
+ if (extensions.match("GL_ARB_texture_compression"))
+ features |= QOpenGLFunctions::CompressedTextures;
+ if (extensions.match("GL_ARB_multisample"))
+ features |= QOpenGLFunctions::Multisample;
+ if (extensions.match("GL_ARB_texture_non_power_of_two"))
+ features |= QOpenGLFunctions::NPOTTextures |
+ QOpenGLFunctions::NPOTTextureRepeat;
+ }
const QPair<int, int> version = format.version();
if (version < qMakePair(3, 0)
diff -Naur qt-everywhere-opensource-src-5.3.1/qtbase/src/gui/text/qfontengine_ft.cpp qt-everywhere-opensource-src-5.3.1.new/qtbase/src/gui/text/qfontengine_ft.cpp
--- qt-everywhere-opensource-src-5.3.1/qtbase/src/gui/text/qfontengine_ft.cpp 2014-06-19 12:08:06.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtbase/src/gui/text/qfontengine_ft.cpp 2014-08-13 04:35:08.422435865 +0200
@@ -70,7 +70,7 @@
#include FT_CONFIG_OPTIONS_H
#endif
-#if defined(FT_LCD_FILTER_H) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING)
+#if defined(FT_LCD_FILTER_H)
#define QT_USE_FREETYPE_LCDFILTER
#endif
diff -Naur qt-everywhere-opensource-src-5.3.1/qtbase/src/gui/text/qfontengine_ft.cpp.orig qt-everywhere-opensource-src-5.3.1.new/qtbase/src/gui/text/qfontengine_ft.cpp.orig
--- qt-everywhere-opensource-src-5.3.1/qtbase/src/gui/text/qfontengine_ft.cpp.orig 1970-01-01 01:00:00.000000000 +0100
+++ qt-everywhere-opensource-src-5.3.1.new/qtbase/src/gui/text/qfontengine_ft.cpp.orig 2014-06-19 12:08:06.000000000 +0200
@@ -0,0 +1,2158 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdir.h"
+#include "qmetatype.h"
+#include "qtextstream.h"
+#include "qvariant.h"
+#include "qfontengine_ft_p.h"
+#include "private/qimage_p.h"
+#include <private/qstringiterator_p.h>
+
+#ifndef QT_NO_FREETYPE
+
+#include "qfile.h"
+#include "qfileinfo.h"
+#include "qthreadstorage.h"
+#include <qmath.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_OUTLINE_H
+#include FT_SYNTHESIS_H
+#include FT_TRUETYPE_TABLES_H
+#include FT_TYPE1_TABLES_H
+#include FT_GLYPH_H
+
+#if defined(FT_LCD_FILTER_H)
+#include FT_LCD_FILTER_H
+#endif
+
+#if defined(FT_CONFIG_OPTIONS_H)
+#include FT_CONFIG_OPTIONS_H
+#endif
+
+#if defined(FT_LCD_FILTER_H) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING)
+#define QT_USE_FREETYPE_LCDFILTER
+#endif
+
+#ifdef QT_LINUXBASE
+#include FT_ERRORS_H
+#endif
+
+#if !defined(QT_MAX_CACHED_GLYPH_SIZE)
+# define QT_MAX_CACHED_GLYPH_SIZE 64
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*
+ * Freetype 2.1.7 and earlier used width/height
+ * for matching sizes in the BDF and PCF loaders.
+ * This has been fixed for 2.1.8.
+ */
+#if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20105
+#define X_SIZE(face,i) ((face)->available_sizes[i].x_ppem)
+#define Y_SIZE(face,i) ((face)->available_sizes[i].y_ppem)
+#else
+#define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
+#define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
+#endif
+
+/* FreeType 2.1.10 starts to provide FT_GlyphSlot_Embolden */
+#if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20110
+#define Q_FT_GLYPHSLOT_EMBOLDEN(slot) FT_GlyphSlot_Embolden(slot)
+#else
+#define Q_FT_GLYPHSLOT_EMBOLDEN(slot)
+#endif
+
+/* FreeType 2.1.10 starts to provide FT_GlyphSlot_Oblique */
+#if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20110
+#define Q_HAS_FT_GLYPHSLOT_OBLIQUE
+#define Q_FT_GLYPHSLOT_OBLIQUE(slot) FT_GlyphSlot_Oblique(slot)
+#else
+#define Q_FT_GLYPHSLOT_OBLIQUE(slot)
+#endif
+
+#define FLOOR(x) ((x) & -64)
+#define CEIL(x) (((x)+63) & -64)
+#define TRUNC(x) ((x) >> 6)
+#define ROUND(x) (((x)+32) & -64)
+
+static bool ft_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *length)
+{
+ FT_Face face = (FT_Face)user_data;
+
+ bool result = false;
+ if (FT_IS_SFNT(face)) {
+ FT_ULong len = *length;
+ result = FT_Load_Sfnt_Table(face, tag, 0, buffer, &len) == FT_Err_Ok;
+ *length = len;
+ Q_ASSERT(!result || int(*length) > 0);
+ }
+
+ return result;
+}
+
+
+// -------------------------- Freetype support ------------------------------
+
+class QtFreetypeData
+{
+public:
+ QtFreetypeData()
+ : library(0)
+ { }
+ ~QtFreetypeData();
+
+ FT_Library library;
+ QHash<QFontEngine::FaceId, QFreetypeFace *> faces;
+};
+
+QtFreetypeData::~QtFreetypeData()
+{
+ for (QHash<QFontEngine::FaceId, QFreetypeFace *>::ConstIterator iter = faces.begin(); iter != faces.end(); ++iter)
+ iter.value()->cleanup();
+ faces.clear();
+ FT_Done_FreeType(library);
+ library = 0;
+}
+
+#ifdef QT_NO_THREAD
+Q_GLOBAL_STATIC(QtFreetypeData, theFreetypeData)
+
+QtFreetypeData *qt_getFreetypeData()
+{
+ return theFreetypeData();
+}
+#else
+Q_GLOBAL_STATIC(QThreadStorage<QtFreetypeData *>, theFreetypeData)
+
+QtFreetypeData *qt_getFreetypeData()
+{
+ QtFreetypeData *&freetypeData = theFreetypeData()->localData();
+ if (!freetypeData)
+ freetypeData = new QtFreetypeData;
+ return freetypeData;
+}
+#endif
+
+FT_Library qt_getFreetype()
+{
+ QtFreetypeData *freetypeData = qt_getFreetypeData();
+ if (!freetypeData->library)
+ FT_Init_FreeType(&freetypeData->library);
+ return freetypeData->library;
+}
+
+int QFreetypeFace::fsType() const
+{
+ int fsType = 0;
+ TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
+ if (os2)
+ fsType = os2->fsType;
+ return fsType;
+}
+
+int QFreetypeFace::getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints)
+{
+ if (int error = FT_Load_Glyph(face, glyph, flags))
+ return error;
+
+ if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
+ return Err_Invalid_SubTable;
+
+ *nPoints = face->glyph->outline.n_points;
+ if (!(*nPoints))
+ return Err_Ok;
+
+ if (point > *nPoints)
+ return Err_Invalid_SubTable;
+
+ *xpos = QFixed::fromFixed(face->glyph->outline.points[point].x);
+ *ypos = QFixed::fromFixed(face->glyph->outline.points[point].y);
+
+ return Err_Ok;
+}
+
+extern QByteArray qt_fontdata_from_index(int);
+
+/*
+ * One font file can contain more than one font (bold/italic for example)
+ * find the right one and return it.
+ *
+ * Returns the freetype face or 0 in case of an empty file or any other problems
+ * (like not being able to open the file)
+ */
+QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
+ const QByteArray &fontData)
+{
+ if (face_id.filename.isEmpty() && fontData.isEmpty())
+ return 0;
+
+ QtFreetypeData *freetypeData = qt_getFreetypeData();
+ if (!freetypeData->library)
+ FT_Init_FreeType(&freetypeData->library);
+
+ QFreetypeFace *freetype = freetypeData->faces.value(face_id, 0);
+ if (freetype) {
+ freetype->ref.ref();
+ } else {
+ QScopedPointer<QFreetypeFace> newFreetype(new QFreetypeFace);
+ FT_Face face;
+ if (!face_id.filename.isEmpty()) {
+ QString fileName = QFile::decodeName(face_id.filename);
+ if (face_id.filename.startsWith(":qmemoryfonts/")) {
+ // from qfontdatabase.cpp
+ QByteArray idx = face_id.filename;
+ idx.remove(0, 14); // remove ':qmemoryfonts/'
+ bool ok = false;
+ newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
+ if (!ok)
+ newFreetype->fontData = QByteArray();
+ } else if (!QFileInfo(fileName).isNativePath()) {
+ QFile file(fileName);
+ if (!file.open(QIODevice::ReadOnly)) {
+ return 0;
+ }
+ newFreetype->fontData = file.readAll();
+ }
+ } else {
+ newFreetype->fontData = fontData;
+ }
+ if (!newFreetype->fontData.isEmpty()) {
+ if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.index, &face)) {
+ return 0;
+ }
+ } else if (FT_New_Face(freetypeData->library, face_id.filename, face_id.index, &face)) {
+ return 0;
+ }
+ newFreetype->face = face;
+
+ newFreetype->hbFace = 0;
+ newFreetype->hbFace_destroy_func = 0;
+
+ newFreetype->ref.store(1);
+ newFreetype->xsize = 0;
+ newFreetype->ysize = 0;
+ newFreetype->matrix.xx = 0x10000;
+ newFreetype->matrix.yy = 0x10000;
+ newFreetype->matrix.xy = 0;
+ newFreetype->matrix.yx = 0;
+ newFreetype->unicode_map = 0;
+ newFreetype->symbol_map = 0;
+
+ memset(newFreetype->cmapCache, 0, sizeof(newFreetype->cmapCache));
+
+ for (int i = 0; i < newFreetype->face->num_charmaps; ++i) {
+ FT_CharMap cm = newFreetype->face->charmaps[i];
+ switch(cm->encoding) {
+ case FT_ENCODING_UNICODE:
+ newFreetype->unicode_map = cm;
+ break;
+ case FT_ENCODING_APPLE_ROMAN:
+ case FT_ENCODING_ADOBE_LATIN_1:
+ if (!newFreetype->unicode_map || newFreetype->unicode_map->encoding != FT_ENCODING_UNICODE)
+ newFreetype->unicode_map = cm;
+ break;
+ case FT_ENCODING_ADOBE_CUSTOM:
+ case FT_ENCODING_MS_SYMBOL:
+ if (!newFreetype->symbol_map)
+ newFreetype->symbol_map = cm;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!FT_IS_SCALABLE(newFreetype->face) && newFreetype->face->num_fixed_sizes == 1)
+ FT_Set_Char_Size (face, X_SIZE(newFreetype->face, 0), Y_SIZE(newFreetype->face, 0), 0, 0);
+
+ FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
+ QT_TRY {
+ freetypeData->faces.insert(face_id, newFreetype.data());
+ } QT_CATCH(...) {
+ newFreetype.take()->release(face_id);
+ // we could return null in principle instead of throwing
+ QT_RETHROW;
+ }
+ freetype = newFreetype.take();
+ }
+ return freetype;
+}
+
+void QFreetypeFace::cleanup()
+{
+ if (hbFace && hbFace_destroy_func) {
+ hbFace_destroy_func(hbFace);
+ hbFace = 0;
+ }
+ FT_Done_Face(face);
+ face = 0;
+}
+
+void QFreetypeFace::release(const QFontEngine::FaceId &face_id)
+{
+ if (!ref.deref()) {
+ if (face) {
+ QtFreetypeData *freetypeData = qt_getFreetypeData();
+
+ cleanup();
+
+ if (freetypeData->faces.contains(face_id))
+ freetypeData->faces.take(face_id);
+
+ if (freetypeData->faces.isEmpty()) {
+ FT_Done_FreeType(freetypeData->library);
+ freetypeData->library = 0;
+ }
+ }
+
+ delete this;
+ }
+}
+
+
+void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing)
+{
+ *ysize = qRound(fontDef.pixelSize * 64);
+ *xsize = *ysize * fontDef.stretch / 100;
+ *outline_drawing = false;
+
+ /*
+ * Bitmap only faces must match exactly, so find the closest
+ * one (height dominant search)
+ */
+ if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
+ int best = 0;
+ for (int i = 1; i < face->num_fixed_sizes; i++) {
+ if (qAbs(*ysize - Y_SIZE(face,i)) <
+ qAbs (*ysize - Y_SIZE(face, best)) ||
+ (qAbs (*ysize - Y_SIZE(face, i)) ==
+ qAbs (*ysize - Y_SIZE(face, best)) &&
+ qAbs (*xsize - X_SIZE(face, i)) <
+ qAbs (*xsize - X_SIZE(face, best)))) {
+ best = i;
+ }
+ }
+ if (FT_Set_Char_Size (face, X_SIZE(face, best), Y_SIZE(face, best), 0, 0) == 0) {
+ *xsize = X_SIZE(face, best);
+ *ysize = Y_SIZE(face, best);
+ } else {
+ int err = 1;
+ if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) && ysize == 0 && face->num_fixed_sizes >= 1) {
+ // work around FT 2.1.10 problem with BDF without PIXEL_SIZE property
+ err = FT_Set_Pixel_Sizes(face, face->available_sizes[0].width, face->available_sizes[0].height);
+ if (err && face->num_fixed_sizes == 1)
+ err = 0; //even more of a workaround...
+ }
+
+ if (err)
+ *xsize = *ysize = 0;
+ }
+ } else {
+ *outline_drawing = (*xsize > (QT_MAX_CACHED_GLYPH_SIZE<<6) || *ysize > (QT_MAX_CACHED_GLYPH_SIZE<<6));
+ }
+}
+
+QFontEngine::Properties QFreetypeFace::properties() const
+{
+ QFontEngine::Properties p;
+ p.postscriptName = FT_Get_Postscript_Name(face);
+ PS_FontInfoRec font_info;
+ if (FT_Get_PS_Font_Info(face, &font_info) == 0)
+ p.copyright = font_info.notice;
+ if (FT_IS_SCALABLE(face)) {
+ p.ascent = face->ascender;
+ p.descent = -face->descender;
+ p.leading = face->height - face->ascender + face->descender;
+ p.emSquare = face->units_per_EM;
+ p.boundingBox = QRectF(face->bbox.xMin, -face->bbox.yMax,
+ face->bbox.xMax - face->bbox.xMin,
+ face->bbox.yMax - face->bbox.yMin);
+ } else {
+ p.ascent = QFixed::fromFixed(face->size->metrics.ascender);
+ p.descent = QFixed::fromFixed(-face->size->metrics.descender);
+ p.leading = QFixed::fromFixed(face->size->metrics.height - face->size->metrics.ascender + face->size->metrics.descender);
+ p.emSquare = face->size->metrics.y_ppem;
+// p.boundingBox = QRectF(-p.ascent.toReal(), 0, (p.ascent + p.descent).toReal(), face->size->metrics.max_advance/64.);
+ p.boundingBox = QRectF(0, -p.ascent.toReal(),
+ face->size->metrics.max_advance/64, (p.ascent + p.descent).toReal() );
+ }
+ p.italicAngle = 0;
+ p.capHeight = p.ascent;
+ p.lineWidth = face->underline_thickness;
+ return p;
+}
+
+bool QFreetypeFace::getSfntTable(uint tag, uchar *buffer, uint *length) const
+{
+ return ft_getSfntTable(face, tag, buffer, length);
+}
+
+/* Some fonts (such as MingLiu rely on hinting to scale different
+ components to their correct sizes. While this is really broken (it
+ should be done in the component glyph itself, not the hinter) we
+ will have to live with it.
+
+ This means we can not use FT_LOAD_NO_HINTING to get the glyph
+ outline. All we can do is to load the unscaled glyph and scale it
+ down manually when required.
+*/
+static void scaleOutline(FT_Face face, FT_GlyphSlot g, FT_Fixed x_scale, FT_Fixed y_scale)
+{
+ x_scale = FT_MulDiv(x_scale, 1 << 10, face->units_per_EM);
+ y_scale = FT_MulDiv(y_scale, 1 << 10, face->units_per_EM);
+ FT_Vector *p = g->outline.points;
+ const FT_Vector *e = p + g->outline.n_points;
+ while (p < e) {
+ p->x = FT_MulFix(p->x, x_scale);
+ p->y = FT_MulFix(p->y, y_scale);
+ ++p;
+ }
+}
+
+#define GLYPH2PATH_DEBUG QT_NO_QDEBUG_MACRO // qDebug
+void QFreetypeFace::addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale)
+{
+ const qreal factor = 1/64.;
+ scaleOutline(face, g, x_scale, y_scale);
+
+ QPointF cp = point.toPointF();
+
+ // convert the outline to a painter path
+ int i = 0;
+ for (int j = 0; j < g->outline.n_contours; ++j) {
+ int last_point = g->outline.contours[j];
+ GLYPH2PATH_DEBUG() << "contour:" << i << "to" << last_point;
+ QPointF start = QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
+ if (!(g->outline.tags[i] & 1)) { // start point is not on curve:
+ if (!(g->outline.tags[last_point] & 1)) { // end point is not on curve:
+ GLYPH2PATH_DEBUG() << " start and end point are not on curve";
+ start = (QPointF(g->outline.points[last_point].x*factor,
+ -g->outline.points[last_point].y*factor) + start) / 2.0;
+ } else {
+ GLYPH2PATH_DEBUG() << " end point is on curve, start is not";
+ start = QPointF(g->outline.points[last_point].x*factor,
+ -g->outline.points[last_point].y*factor);
+ }
+ --i; // to use original start point as control point below
+ }
+ start += cp;
+ GLYPH2PATH_DEBUG() << " start at" << start;
+
+ path->moveTo(start);
+ QPointF c[4];
+ c[0] = start;
+ int n = 1;
+ while (i < last_point) {
+ ++i;
+ c[n] = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
+ GLYPH2PATH_DEBUG() << " " << i << c[n] << "tag =" << (int)g->outline.tags[i]
+ << ": on curve =" << (bool)(g->outline.tags[i] & 1);
+ ++n;
+ switch (g->outline.tags[i] & 3) {
+ case 2:
+ // cubic bezier element
+ if (n < 4)
+ continue;
+ c[3] = (c[3] + c[2])/2;
+ --i;
+ break;
+ case 0:
+ // quadratic bezier element
+ if (n < 3)
+ continue;
+ c[3] = (c[1] + c[2])/2;
+ c[2] = (2*c[1] + c[3])/3;
+ c[1] = (2*c[1] + c[0])/3;
+ --i;
+ break;
+ case 1:
+ case 3:
+ if (n == 2) {
+ GLYPH2PATH_DEBUG() << " lineTo" << c[1];
+ path->lineTo(c[1]);
+ c[0] = c[1];
+ n = 1;
+ continue;
+ } else if (n == 3) {
+ c[3] = c[2];
+ c[2] = (2*c[1] + c[3])/3;
+ c[1] = (2*c[1] + c[0])/3;
+ }
+ break;
+ }
+ GLYPH2PATH_DEBUG() << " cubicTo" << c[1] << c[2] << c[3];
+ path->cubicTo(c[1], c[2], c[3]);
+ c[0] = c[3];
+ n = 1;
+ }
+
+ if (n == 1) {
+ GLYPH2PATH_DEBUG() << " closeSubpath";
+ path->closeSubpath();
+ } else {
+ c[3] = start;
+ if (n == 2) {
+ c[2] = (2*c[1] + c[3])/3;
+ c[1] = (2*c[1] + c[0])/3;
+ }
+ GLYPH2PATH_DEBUG() << " close cubicTo" << c[1] << c[2] << c[3];
+ path->cubicTo(c[1], c[2], c[3]);
+ }
+ ++i;
+ }
+}
+
+extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path);
+
+void QFreetypeFace::addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool)
+{
+ if (slot->format != FT_GLYPH_FORMAT_BITMAP
+ || slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
+ return;
+
+ QPointF cp = point.toPointF();
+ qt_addBitmapToPath(cp.x() + TRUNC(slot->metrics.horiBearingX), cp.y() - TRUNC(slot->metrics.horiBearingY),
+ slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path);
+}
+
+QFontEngineFT::Glyph::~Glyph()
+{
+ delete [] data;
+}
+
+static const uint subpixel_filter[3][3] = {
+ { 180, 60, 16 },
+ { 38, 180, 38 },
+ { 16, 60, 180 }
+};
+
+static inline uint filterPixel(uint red, uint green, uint blue, bool legacyFilter)
+{
+ uint res;
+ if (legacyFilter) {
+ uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8;
+ uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8;
+ uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8;
+ res = (mid << 24) + (high << 16) + (mid << 8) + low;
+ } else {
+ uint alpha = green;
+ res = (alpha << 24) + (red << 16) + (green << 8) + blue;
+ }
+ return res;
+}
+
+static void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
+{
+ int h = height;
+ const int offs = bgr ? -1 : 1;
+ const int w = width * 3;
+ while (h--) {
+ uint *dd = dst;
+ for (int x = 0; x < w; x += 3) {
+ uint red = src[x+1-offs];
+ uint green = src[x+1];
+ uint blue = src[x+1+offs];
+ *dd = filterPixel(red, green, blue, legacyFilter);
+ ++dd;
+ }
+ dst += width;
+ src += src_pitch;
+ }
+}
+
+static void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
+{
+ int h = height;
+ const int offs = bgr ? -src_pitch : src_pitch;
+ while (h--) {
+ for (int x = 0; x < width; x++) {
+ uint red = src[x+src_pitch-offs];
+ uint green = src[x+src_pitch];
+ uint blue = src[x+src_pitch+offs];
+ dst[x] = filterPixel(red, green, blue, legacyFilter);
+ }
+ dst += width;
+ src += 3*src_pitch;
+ }
+}
+
+static void convertGRAYToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch) {
+ for (int y = 0; y < height; ++y) {
+ int readpos = (y * src_pitch);
+ int writepos = (y * width);
+ for (int x = 0; x < width; ++x) {
+ dst[writepos + x] = (0xFF << 24) + (src[readpos + x] << 16) + (src[readpos + x] << 8) + src[readpos + x];
+ }
+ }
+}
+
+static void convoluteBitmap(const uchar *src, uchar *dst, int width, int height, int pitch)
+{
+ // convolute the bitmap with a triangle filter to get rid of color fringes
+ // If we take account for a gamma value of 2, we end up with
+ // weights of 1, 4, 9, 4, 1. We use an approximation of 1, 3, 8, 3, 1 here,
+ // as this nicely sums up to 16 :)
+ int h = height;
+ while (h--) {
+ dst[0] = dst[1] = 0;
+ //
+ for (int x = 2; x < width - 2; ++x) {
+ uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2];
+ dst[x] = (uchar) (sum >> 4);
+ }
+ dst[width - 2] = dst[width - 1] = 0;
+ src += pitch;
+ dst += pitch;
+ }
+}
+
+QFontEngineFT::QFontEngineFT(const QFontDef &fd)
+ : QFontEngine(Freetype)
+{
+ fontDef = fd;
+ matrix.xx = 0x10000;
+ matrix.yy = 0x10000;
+ matrix.xy = 0;
+ matrix.yx = 0;
+ cache_cost = 100;
+ kerning_pairs_loaded = false;
+ transform = false;
+ embolden = false;
+ obliquen = false;
+ antialias = true;
+ freetype = 0;
+ default_load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
+#ifndef Q_OS_WIN
+ default_hint_style = HintNone;
+#else
+ default_hint_style = HintFull;
+#endif
+ subpixelType = Subpixel_None;
+ lcdFilterType = 0;
+#if defined(FT_LCD_FILTER_H)
+ lcdFilterType = (int)((quintptr) FT_LCD_FILTER_DEFAULT);
+#endif
+ defaultFormat = Format_None;
+ embeddedbitmap = false;
+ const QByteArray env = qgetenv("QT_NO_FT_CACHE");
+ cacheEnabled = env.isEmpty() || env.toInt() == 0;
+ m_subPixelPositionCount = 4;
+}
+
+QFontEngineFT::~QFontEngineFT()
+{
+ if (freetype)
+ freetype->release(face_id);
+}
+
+bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
+ const QByteArray &fontData)
+{
+ return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData));
+}
+
+bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
+ QFreetypeFace *freetypeFace)
+{
+ freetype = freetypeFace;
+ if (!freetype) {
+ xsize = 0;
+ ysize = 0;
+ return false;
+ }
+ defaultFormat = format;
+ this->antialias = antialias;
+
+ if (!antialias)
+ glyphFormat = QFontEngine::Format_Mono;
+ else
+ glyphFormat = defaultFormat;
+
+ face_id = faceId;
+
+ symbol = freetype->symbol_map != 0;
+ PS_FontInfoRec psrec;
+ // don't assume that type1 fonts are symbol fonts by default
+ if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) {
+ symbol = bool(fontDef.family.contains(QLatin1String("symbol"), Qt::CaseInsensitive));
+ }
+
+ lbearing = rbearing = SHRT_MIN;
+ freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing);
+
+ FT_Face face = lockFace();
+
+ if (FT_IS_SCALABLE(face)) {
+ bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
+ if (fake_oblique) {
+#if !defined(Q_HAS_FT_GLYPHSLOT_OBLIQUE)
+ matrix.xy = 0x10000*3/10;
+ transform = true;
+#else
+ obliquen = true;
+#endif
+ }
+ FT_Set_Transform(face, &matrix, 0);
+ freetype->matrix = matrix;
+ // fake bold
+ if ((fontDef.weight >= QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face))
+ embolden = true;
+ // underline metrics
+ line_thickness = QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
+ underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
+ } else {
+ // ad hoc algorithm
+ int score = fontDef.weight * fontDef.pixelSize;
+ line_thickness = score / 700;
+ // looks better with thicker line for small pointsizes
+ if (line_thickness < 2 && score >= 1050)
+ line_thickness = 2;
+ underline_position = ((line_thickness * 2) + 3) / 6;
+ }
+ if (line_thickness < 1)
+ line_thickness = 1;
+
+ metrics = face->size->metrics;
+
+ /*
+ TrueType fonts with embedded bitmaps may have a bitmap font specific
+ ascent/descent in the EBLC table. There is no direct public API
+ to extract those values. The only way we've found is to trick freetype
+ into thinking that it's not a scalable font in FT_SelectSize so that
+ the metrics are retrieved from the bitmap strikes.
+ */
+ if (FT_IS_SCALABLE(face)) {
+ for (int i = 0; i < face->num_fixed_sizes; ++i) {
+ if (xsize == X_SIZE(face, i) && ysize == Y_SIZE(face, i)) {
+ face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
+
+ FT_Select_Size(face, i);
+ metrics.ascender = face->size->metrics.ascender;
+ metrics.descender = face->size->metrics.descender;
+ FT_Set_Char_Size(face, xsize, ysize, 0, 0);
+
+ face->face_flags |= FT_FACE_FLAG_SCALABLE;
+ break;
+ }
+ }
+ }
+
+ fontDef.styleName = QString::fromUtf8(face->style_name);
+
+ if (!freetype->hbFace) {
+ faceData.user_data = face;
+ faceData.get_font_table = ft_getSfntTable;
+ freetype->hbFace = harfbuzzFace();
+ freetype->hbFace_destroy_func = face_destroy_func;
+ } else {
+ Q_ASSERT(!face_);
+ face_ = freetype->hbFace;
+ }
+ face_destroy_func = 0; // we share the HB face in QFreeTypeFace, so do not let ~QFontEngine() destroy it
+
+ unlockFace();
+
+ fsType = freetype->fsType();
+ return true;
+}
+
+void QFontEngineFT::setDefaultHintStyle(HintStyle style)
+{
+ default_hint_style = style;
+}
+
+int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
+ bool &hsubpixel, int &vfactor) const
+{
+ int load_flags = FT_LOAD_DEFAULT | default_load_flags;
+ int load_target = default_hint_style == HintLight
+ ? FT_LOAD_TARGET_LIGHT
+ : FT_LOAD_TARGET_NORMAL;
+
+ if (format == Format_Mono) {
+ load_target = FT_LOAD_TARGET_MONO;
+ } else if (format == Format_A32) {
+ if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) {
+ if (default_hint_style == HintFull)
+ load_target = FT_LOAD_TARGET_LCD;
+ hsubpixel = true;
+ } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) {
+ if (default_hint_style == HintFull)
+ load_target = FT_LOAD_TARGET_LCD_V;
+ vfactor = 3;
+ }
+ }
+
+ if (set && set->outline_drawing)
+ load_flags = FT_LOAD_NO_BITMAP;
+
+ if (default_hint_style == HintNone || (flags & DesignMetrics) || (set && set->outline_drawing))
+ load_flags |= FT_LOAD_NO_HINTING;
+ else
+ load_flags |= load_target;
+
+ return load_flags;
+}
+
+QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
+ QFixed subPixelPosition,
+ GlyphFormat format,
+ bool fetchMetricsOnly) const
+{
+// Q_ASSERT(freetype->lock == 1);
+
+ if (format == Format_None) {
+ if (defaultFormat != Format_None) {
+ format = defaultFormat;
+ } else {
+ format = Format_Mono;
+ }
+ }
+
+ Glyph *g = set ? set->getGlyph(glyph, subPixelPosition) : 0;
+ if (g && g->format == format && (fetchMetricsOnly || g->data))
+ return g;
+
+ QFontEngineFT::GlyphInfo info;
+
+ Q_ASSERT(format != Format_None);
+ bool hsubpixel = false;
+ int vfactor = 1;
+ int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
+
+ if (format != Format_Mono && !embeddedbitmap)
+ load_flags |= FT_LOAD_NO_BITMAP;
+
+ FT_Matrix matrix = freetype->matrix;
+ bool transform = matrix.xx != 0x10000
+ || matrix.yy != 0x10000
+ || matrix.xy != 0
+ || matrix.yx != 0;
+
+ if (transform)
+ load_flags |= FT_LOAD_NO_BITMAP;
+
+ FT_Face face = freetype->face;
+
+ FT_Vector v;
+ v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.toReal() * 64);
+ v.y = 0;
+ FT_Set_Transform(face, &freetype->matrix, &v);
+
+ FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
+ if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
+ load_flags &= ~FT_LOAD_NO_BITMAP;
+ err = FT_Load_Glyph(face, glyph, load_flags);
+ }
+ if (err == FT_Err_Too_Few_Arguments) {
+ // this is an error in the bytecode interpreter, just try to run without it
+ load_flags |= FT_LOAD_FORCE_AUTOHINT;
+ err = FT_Load_Glyph(face, glyph, load_flags);
+ }
+ if (err != FT_Err_Ok)
+ qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
+
+ FT_GlyphSlot slot = face->glyph;
+
+ if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
+ if (obliquen) {
+ Q_FT_GLYPHSLOT_OBLIQUE(slot);
+
+ // While Embolden alters the metrics of the slot, oblique does not, so we need
+ // to fix this ourselves.
+ transform = true;
+ FT_Matrix m;
+ m.xx = 0x10000;
+ m.yx = 0x0;
+ m.xy = 0x6000;
+ m.yy = 0x10000;
+
+ FT_Matrix_Multiply(&m, &matrix);
+ }
+
+ FT_Library library = qt_getFreetype();
+
+ info.xOff = TRUNC(ROUND(slot->advance.x));
+ info.yOff = 0;
+
+ if ((set && set->outline_drawing) || fetchMetricsOnly) {
+ int left = FLOOR(slot->metrics.horiBearingX);
+ int right = CEIL(slot->metrics.horiBearingX + slot->metrics.width);
+ int top = CEIL(slot->metrics.horiBearingY);
+ int bottom = FLOOR(slot->metrics.horiBearingY - slot->metrics.height);
+ int width = right-left;
+ int height = top-bottom;
+
+ // If any of the metrics are too large to fit, don't cache them
+ if (qAbs(info.xOff) >= 128
+ || qAbs(TRUNC(top)) >= 128
+ || TRUNC(width) >= 256
+ || TRUNC(height) >= 256
+ || qAbs(TRUNC(left)) >= 128
+ || qAbs(TRUNC(ROUND(slot->advance.x))) >= 128) {
+ return 0;
+ }
+
+ g = new Glyph;
+ g->data = 0;
+ g->linearAdvance = slot->linearHoriAdvance >> 10;
+ g->width = TRUNC(width);
+ g->height = TRUNC(height);
+ g->x = TRUNC(left);
+ g->y = TRUNC(top);
+ g->advance = TRUNC(ROUND(slot->advance.x));
+ g->format = format;
+
+ if (set)
+ set->setGlyph(glyph, subPixelPosition, g);
+
+ return g;
+ }
+
+ uchar *glyph_buffer = 0;
+ int glyph_buffer_size = 0;
+#if defined(QT_USE_FREETYPE_LCDFILTER)
+ bool useFreetypeRenderGlyph = false;
+ if (slot->format == FT_GLYPH_FORMAT_OUTLINE && (hsubpixel || vfactor != 1)) {
+ err = FT_Library_SetLcdFilter(library, (FT_LcdFilter)lcdFilterType);
+ if (err == FT_Err_Ok)
+ useFreetypeRenderGlyph = true;
+ }
+
+ if (useFreetypeRenderGlyph) {
+ err = FT_Render_Glyph(slot, hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V);
+
+ if (err != FT_Err_Ok)
+ qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
+
+ FT_Library_SetLcdFilter(library, FT_LCD_FILTER_NONE);
+
+ info.height = slot->bitmap.rows / vfactor;
+ info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
+ info.x = -slot->bitmap_left;
+ info.y = slot->bitmap_top;
+
+ glyph_buffer_size = info.width * info.height * 4;
+ glyph_buffer = new uchar[glyph_buffer_size];
+
+ if (hsubpixel)
+ convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, false);
+ else if (vfactor != 1)
+ convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, false);
+ } else
+#endif
+ {
+ int left = slot->metrics.horiBearingX;
+ int right = slot->metrics.horiBearingX + slot->metrics.width;
+ int top = slot->metrics.horiBearingY;
+ int bottom = slot->metrics.horiBearingY - slot->metrics.height;
+ if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) {
+ int l, r, t, b;
+ FT_Vector vector;
+ vector.x = left;
+ vector.y = top;
+ FT_Vector_Transform(&vector, &matrix);
+ l = r = vector.x;
+ t = b = vector.y;
+ vector.x = right;
+ vector.y = top;
+ FT_Vector_Transform(&vector, &matrix);
+ if (l > vector.x) l = vector.x;
+ if (r < vector.x) r = vector.x;
+ if (t < vector.y) t = vector.y;
+ if (b > vector.y) b = vector.y;
+ vector.x = right;
+ vector.y = bottom;
+ FT_Vector_Transform(&vector, &matrix);
+ if (l > vector.x) l = vector.x;
+ if (r < vector.x) r = vector.x;
+ if (t < vector.y) t = vector.y;
+ if (b > vector.y) b = vector.y;
+ vector.x = left;
+ vector.y = bottom;
+ FT_Vector_Transform(&vector, &matrix);
+ if (l > vector.x) l = vector.x;
+ if (r < vector.x) r = vector.x;
+ if (t < vector.y) t = vector.y;
+ if (b > vector.y) b = vector.y;
+ left = l;
+ right = r;
+ top = t;
+ bottom = b;
+ }
+ left = FLOOR(left);
+ right = CEIL(right);
+ bottom = FLOOR(bottom);
+ top = CEIL(top);
+
+ int hpixels = TRUNC(right - left);
+ // subpixel position requires one more pixel
+ if (subPixelPosition > 0 && format != Format_Mono)
+ hpixels++;
+
+ if (hsubpixel)
+ hpixels = hpixels*3 + 8;
+ info.width = hpixels;
+ info.height = TRUNC(top - bottom);
+ info.x = -TRUNC(left);
+ info.y = TRUNC(top);
+ if (hsubpixel) {
+ info.width /= 3;
+ info.x += 1;
+ }
+
+ bool large_glyph = (((short)(slot->linearHoriAdvance>>10) != slot->linearHoriAdvance>>10)
+ || ((uchar)(info.width) != info.width)
+ || ((uchar)(info.height) != info.height)
+ || ((signed char)(info.x) != info.x)
+ || ((signed char)(info.y) != info.y)
+ || ((signed char)(info.xOff) != info.xOff));
+
+ if (large_glyph) {
+ delete [] glyph_buffer;
+ return 0;
+ }
+
+ int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
+ (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
+ glyph_buffer_size = pitch * info.height;
+ glyph_buffer = new uchar[glyph_buffer_size];
+
+ if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
+ FT_Bitmap bitmap;
+ bitmap.rows = info.height*vfactor;
+ bitmap.width = hpixels;
+ bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
+ if (!hsubpixel && vfactor == 1 && format != Format_A32)
+ bitmap.buffer = glyph_buffer;
+ else
+ bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
+ memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
+ bitmap.pixel_mode = format == Format_Mono ? FT_PIXEL_MODE_MONO : FT_PIXEL_MODE_GRAY;
+ FT_Matrix matrix;
+ matrix.xx = (hsubpixel ? 3 : 1) << 16;
+ matrix.yy = vfactor << 16;
+ matrix.yx = matrix.xy = 0;
+
+ FT_Outline_Transform(&slot->outline, &matrix);
+ FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
+ FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
+ if (hsubpixel) {
+ Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
+ Q_ASSERT(antialias);
+ uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
+ bool useLegacyLcdFilter = false;
+#if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
+ useLegacyLcdFilter = (lcdFilterType == FT_LCD_FILTER_LEGACY);
+#endif
+ uchar *buffer = bitmap.buffer;
+ if (!useLegacyLcdFilter) {
+ convoluteBitmap(bitmap.buffer, convoluted, bitmap.width, info.height, bitmap.pitch);
+ buffer = convoluted;
+ }
+ convertRGBToARGB(buffer + 1, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, useLegacyLcdFilter);
+ delete [] convoluted;
+ } else if (vfactor != 1) {
+ convertRGBToARGB_V(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, true);
+ } else if (format == Format_A32 && bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) {
+ convertGRAYToARGB(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch);
+ }
+
+ if (bitmap.buffer != glyph_buffer)
+ delete [] bitmap.buffer;
+ } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
+ Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
+ uchar *src = slot->bitmap.buffer;
+ uchar *dst = glyph_buffer;
+ int h = slot->bitmap.rows;
+ if (format == Format_Mono) {
+ int bytes = ((info.width + 7) & ~7) >> 3;
+ while (h--) {
+ memcpy (dst, src, bytes);
+ dst += pitch;
+ src += slot->bitmap.pitch;
+ }
+ } else {
+ if (hsubpixel) {
+ while (h--) {
+ uint *dd = (uint *)dst;
+ *dd++ = 0;
+ for (int x = 0; x < slot->bitmap.width; x++) {
+ uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
+ *dd++ = a;
+ }
+ *dd++ = 0;
+ dst += pitch;
+ src += slot->bitmap.pitch;
+ }
+ } else if (vfactor != 1) {
+ while (h--) {
+ uint *dd = (uint *)dst;
+ for (int x = 0; x < slot->bitmap.width; x++) {
+ uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
+ *dd++ = a;
+ }
+ dst += pitch;
+ src += slot->bitmap.pitch;
+ }
+ } else {
+ while (h--) {
+ for (int x = 0; x < slot->bitmap.width; x++) {
+ unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
+ dst[x] = a;
+ }
+ dst += pitch;
+ src += slot->bitmap.pitch;
+ }
+ }
+ }
+ } else {
+ qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
+ delete [] glyph_buffer;
+ return 0;
+ }
+ }
+
+
+ if (!g) {
+ g = new Glyph;
+ g->data = 0;
+ }
+
+ g->linearAdvance = slot->linearHoriAdvance >> 10;
+ g->width = info.width;
+ g->height = info.height;
+ g->x = -info.x;
+ g->y = info.y;
+ g->advance = info.xOff;
+ g->format = format;
+ delete [] g->data;
+ g->data = glyph_buffer;
+
+ if (set)
+ set->setGlyph(glyph, subPixelPosition, g);
+
+ return g;
+}
+
+QFontEngine::FaceId QFontEngineFT::faceId() const
+{
+ return face_id;
+}
+
+QFontEngine::Properties QFontEngineFT::properties() const
+{
+ Properties p = freetype->properties();
+ if (p.postscriptName.isEmpty()) {
+ p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());
+ }
+
+ return freetype->properties();
+}
+
+QFixed QFontEngineFT::emSquareSize() const
+{
+ if (FT_IS_SCALABLE(freetype->face))
+ return freetype->face->units_per_EM;
+ else
+ return freetype->face->size->metrics.y_ppem;
+}
+
+bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const
+{
+ return ft_getSfntTable(freetype->face, tag, buffer, length);
+}
+
+int QFontEngineFT::synthesized() const
+{
+ int s = 0;
+ if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
+ s = SynthesizedItalic;
+ if ((fontDef.weight >= QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
+ s |= SynthesizedBold;
+ if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
+ s |= SynthesizedStretch;
+ return s;
+}
+
+QFixed QFontEngineFT::ascent() const
+{
+ return QFixed::fromFixed(metrics.ascender);
+}
+
+QFixed QFontEngineFT::descent() const
+{
+ return QFixed::fromFixed(-metrics.descender);
+}
+
+QFixed QFontEngineFT::leading() const
+{
+ return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
+}
+
+QFixed QFontEngineFT::xHeight() const
+{
+ TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
+ if (os2 && os2->sxHeight) {
+ lockFace();
+ QFixed answer = QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
+ unlockFace();
+ return answer;
+ }
+ return QFontEngine::xHeight();
+}
+
+QFixed QFontEngineFT::averageCharWidth() const
+{
+ TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
+ if (os2 && os2->xAvgCharWidth) {
+ lockFace();
+ QFixed answer = QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.x_ppem)/freetype->face->units_per_EM;
+ unlockFace();
+ return answer;
+ }
+ return QFontEngine::averageCharWidth();
+}
+
+qreal QFontEngineFT::maxCharWidth() const
+{
+ return metrics.max_advance >> 6;
+}
+
+static const ushort char_table[] = {
+ 40,
+ 67,
+ 70,
+ 75,
+ 86,
+ 88,
+ 89,
+ 91,
+ 95,
+ 102,
+ 114,
+ 124,
+ 127,
+ 205,
+ 645,
+ 884,
+ 922,
+ 1070,
+ 12386
+};
+
+static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
+
+
+qreal QFontEngineFT::minLeftBearing() const
+{
+ if (lbearing == SHRT_MIN)
+ (void) minRightBearing(); // calculates both
+ return lbearing.toReal();
+}
+
+qreal QFontEngineFT::minRightBearing() const
+{
+ if (rbearing == SHRT_MIN) {
+ lbearing = rbearing = 0;
+ for (int i = 0; i < char_table_entries; ++i) {
+ const glyph_t glyph = glyphIndex(char_table[i]);
+ if (glyph != 0) {
+ glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyph);
+ lbearing = qMin(lbearing, gi.x);
+ rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
+ }
+ }
+ }
+ return rbearing.toReal();
+}
+
+QFixed QFontEngineFT::lineThickness() const
+{
+ return line_thickness;
+}
+
+QFixed QFontEngineFT::underlinePosition() const
+{
+ return underline_position;
+}
+
+void QFontEngineFT::doKerning(QGlyphLayout *g, QFontEngine::ShaperFlags flags) const
+{
+ if (!kerning_pairs_loaded) {
+ kerning_pairs_loaded = true;
+ lockFace();
+ if (freetype->face->size->metrics.x_ppem != 0) {
+ QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
+ unlockFace();
+ const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
+ } else {
+ unlockFace();
+ }
+ }
+
+ if (shouldUseDesignMetrics(flags) && !(fontDef.styleStrategy & QFont::ForceIntegerMetrics))
+ flags |= DesignMetrics;
+ else
+ flags &= ~DesignMetrics;
+
+ QFontEngine::doKerning(g, flags);
+}
+
+QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransform &matrix)
+{
+ if (matrix.type() > QTransform::TxShear)
+ return 0;
+
+ // FT_Set_Transform only supports scalable fonts
+ if (!FT_IS_SCALABLE(freetype->face))
+ return 0;
+
+ FT_Matrix m;
+ m.xx = FT_Fixed(matrix.m11() * 65536);
+ m.xy = FT_Fixed(-matrix.m21() * 65536);
+ m.yx = FT_Fixed(-matrix.m12() * 65536);
+ m.yy = FT_Fixed(matrix.m22() * 65536);
+
+ QGlyphSet *gs = 0;
+
+ for (int i = 0; i < transformedGlyphSets.count(); ++i) {
+ const QGlyphSet &g = transformedGlyphSets.at(i);
+ if (g.transformationMatrix.xx == m.xx
+ && g.transformationMatrix.xy == m.xy
+ && g.transformationMatrix.yx == m.yx
+ && g.transformationMatrix.yy == m.yy) {
+
+ // found a match, move it to the front
+ transformedGlyphSets.move(i, 0);
+ gs = &transformedGlyphSets[0];
+ break;
+ }
+ }
+
+ if (!gs) {
+ // don't try to load huge fonts
+ bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= QT_MAX_CACHED_GLYPH_SIZE;
+ if (draw_as_outline)
+ return 0;
+
+ // don't cache more than 10 transformations
+ if (transformedGlyphSets.count() >= 10) {
+ transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
+ } else {
+ transformedGlyphSets.prepend(QGlyphSet());
+ }
+ gs = &transformedGlyphSets[0];
+ gs->clear();
+ gs->transformationMatrix = m;
+ gs->outline_drawing = draw_as_outline;
+ }
+
+ return gs;
+}
+
+bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs,
+ const QFixedPoint *positions,
+ GlyphFormat format)
+{
+ FT_Face face = 0;
+
+ for (int i = 0; i < num_glyphs; ++i) {
+ QFixed spp = subPixelPositionForX(positions[i].x);
+ Glyph *glyph = gs ? gs->getGlyph(glyphs[i], spp) : 0;
+ if (glyph == 0 || glyph->format != format) {
+ if (!face) {
+ face = lockFace();
+ FT_Matrix m = matrix;
+ FT_Matrix_Multiply(&gs->transformationMatrix, &m);
+ FT_Set_Transform(face, &m, 0);
+ freetype->matrix = m;
+ }
+ if (!loadGlyph(gs, glyphs[i], spp, format)) {
+ unlockFace();
+ return false;
+ }
+ }
+ }
+
+ if (face)
+ unlockFace();
+
+ return true;
+}
+
+void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
+{
+ FT_Face face = lockFace(Unscaled);
+ FT_Set_Transform(face, 0, 0);
+ FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
+
+ int left = face->glyph->metrics.horiBearingX;
+ int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
+ int top = face->glyph->metrics.horiBearingY;
+ int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
+
+ QFixedPoint p;
+ p.x = 0;
+ p.y = 0;
+
+ metrics->width = QFixed::fromFixed(right-left);
+ metrics->height = QFixed::fromFixed(top-bottom);
+ metrics->x = QFixed::fromFixed(left);
+ metrics->y = QFixed::fromFixed(-top);
+ metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
+
+ if (!FT_IS_SCALABLE(freetype->face))
+ QFreetypeFace::addBitmapToPath(face->glyph, p, path);
+ else
+ QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
+
+ FT_Set_Transform(face, &freetype->matrix, 0);
+ unlockFace();
+}
+
+bool QFontEngineFT::supportsTransformation(const QTransform &transform) const
+{
+ // The freetype engine falls back to QFontEngine for tranformed glyphs,
+ // which uses fast-tranform and produces very ugly results, so we claim
+ // to support just translations.
+ return transform.type() <= QTransform::TxTranslate;
+}
+
+void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
+{
+ if (!glyphs.numGlyphs)
+ return;
+
+ if (FT_IS_SCALABLE(freetype->face)) {
+ QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
+ } else {
+ QVarLengthArray<QFixedPoint> positions;
+ QVarLengthArray<glyph_t> positioned_glyphs;
+ QTransform matrix;
+ matrix.translate(x, y);
+ getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
+
+ FT_Face face = lockFace(Unscaled);
+ for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
+ FT_UInt glyph = positioned_glyphs[gl];
+ FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO);
+ freetype->addBitmapToPath(face->glyph, positions[gl], path);
+ }
+ unlockFace();
+ }
+}
+
+void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
+ QPainterPath *path, QTextItem::RenderFlags)
+{
+ FT_Face face = lockFace(Unscaled);
+
+ for (int gl = 0; gl < numGlyphs; gl++) {
+ FT_UInt glyph = glyphs[gl];
+
+ FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
+
+ FT_GlyphSlot g = face->glyph;
+ if (g->format != FT_GLYPH_FORMAT_OUTLINE)
+ continue;
+ if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(g);
+ if (obliquen) Q_FT_GLYPHSLOT_OBLIQUE(g);
+ QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
+ }
+ unlockFace();
+}
+
+glyph_t QFontEngineFT::glyphIndex(uint ucs4) const
+{
+ glyph_t glyph = ucs4 < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[ucs4] : 0;
+ if (glyph == 0) {
+ FT_Face face = freetype->face;
+ glyph = FT_Get_Char_Index(face, ucs4);
+ if (glyph == 0) {
+ // Certain fonts don't have no-break space and tab,
+ // while we usually want to render them as space
+ if (ucs4 == QChar::Nbsp || ucs4 == QChar::Tabulation) {
+ glyph = FT_Get_Char_Index(face, QChar::Space);
+ } else if (freetype->symbol_map) {
+ // Symbol fonts can have more than one CMAPs, FreeType should take the
+ // correct one for us by default, so we always try FT_Get_Char_Index
+ // first. If it didn't work (returns 0), we will explicitly set the
+ // CMAP to symbol font one and try again. symbol_map is not always the
+ // correct one because in certain fonts like Wingdings symbol_map only
+ // contains PUA codepoints instead of the common ones.
+ FT_Set_Charmap(face, freetype->symbol_map);
+ glyph = FT_Get_Char_Index(face, ucs4);
+ FT_Set_Charmap(face, freetype->unicode_map);
+ }
+ }
+ if (ucs4 < QFreetypeFace::cmapCacheSize)
+ freetype->cmapCache[ucs4] = glyph;
+ }
+
+ return glyph;
+}
+
+bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
+ QFontEngine::ShaperFlags flags) const
+{
+ Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
+ if (*nglyphs < len) {
+ *nglyphs = len;
+ return false;
+ }
+
+ int glyph_pos = 0;
+ if (freetype->symbol_map) {
+ FT_Face face = freetype->face;
+ QStringIterator it(str, str + len);
+ while (it.hasNext()) {
+ uint uc = it.next();
+ glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
+ if ( !glyphs->glyphs[glyph_pos] ) {
+ // Symbol fonts can have more than one CMAPs, FreeType should take the
+ // correct one for us by default, so we always try FT_Get_Char_Index
+ // first. If it didn't work (returns 0), we will explicitly set the
+ // CMAP to symbol font one and try again. symbol_map is not always the
+ // correct one because in certain fonts like Wingdings symbol_map only
+ // contains PUA codepoints instead of the common ones.
+ glyph_t glyph = FT_Get_Char_Index(face, uc);
+ // Certain symbol fonts don't have no-break space (0xa0) and tab (0x9),
+ // while we usually want to render them as space
+ if (!glyph && (uc == 0xa0 || uc == 0x9)) {
+ uc = 0x20;
+ glyph = FT_Get_Char_Index(face, uc);
+ }
+ if (!glyph) {
+ FT_Set_Charmap(face, freetype->symbol_map);
+ glyph = FT_Get_Char_Index(face, uc);
+ FT_Set_Charmap(face, freetype->unicode_map);
+ }
+ glyphs->glyphs[glyph_pos] = glyph;
+ if (uc < QFreetypeFace::cmapCacheSize)
+ freetype->cmapCache[uc] = glyph;
+ }
+ ++glyph_pos;
+ }
+ } else {
+ FT_Face face = freetype->face;
+ QStringIterator it(str, str + len);
+ while (it.hasNext()) {
+ uint uc = it.next();
+ glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
+ if (!glyphs->glyphs[glyph_pos]) {
+ {
+ redo:
+ glyph_t glyph = FT_Get_Char_Index(face, uc);
+ if (!glyph && (uc == 0xa0 || uc == 0x9)) {
+ uc = 0x20;
+ goto redo;
+ }
+ glyphs->glyphs[glyph_pos] = glyph;
+ if (uc < QFreetypeFace::cmapCacheSize)
+ freetype->cmapCache[uc] = glyph;
+ }
+ }
+ ++glyph_pos;
+ }
+ }
+
+ *nglyphs = glyph_pos;
+ glyphs->numGlyphs = glyph_pos;
+
+ if (!(flags & GlyphIndicesOnly))
+ recalcAdvances(glyphs, flags);
+
+ return true;
+}
+
+bool QFontEngineFT::shouldUseDesignMetrics(QFontEngine::ShaperFlags flags) const
+{
+ if (!FT_IS_SCALABLE(freetype->face))
+ return false;
+
+ return default_hint_style == HintNone || default_hint_style == HintLight || (flags & DesignMetrics);
+}
+
+void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
+{
+ FT_Face face = 0;
+ bool design = shouldUseDesignMetrics(flags);
+ for (int i = 0; i < glyphs->numGlyphs; i++) {
+ Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs->glyphs[i]) : 0;
+ // Since we are passing Format_None to loadGlyph, use same default format logic as loadGlyph
+ GlyphFormat acceptableFormat = (defaultFormat != Format_None) ? defaultFormat : Format_Mono;
+ if (g && g->format == acceptableFormat) {
+ glyphs->advances[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
+ } else {
+ if (!face)
+ face = lockFace();
+ g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs->glyphs[i], 0, Format_None, true);
+ glyphs->advances[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
+ : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
+ if (!cacheEnabled)
+ delete g;
+ }
+ }
+ if (face)
+ unlockFace();
+
+ if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
+ for (int i = 0; i < glyphs->numGlyphs; ++i)
+ glyphs->advances[i] = glyphs->advances[i].round();
+ }
+}
+
+glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
+{
+ FT_Face face = 0;
+
+ glyph_metrics_t overall;
+ // initialize with line height, we get the same behaviour on all platforms
+ overall.y = -ascent();
+ overall.height = ascent() + descent();
+
+ QFixed ymax = 0;
+ QFixed xmax = 0;
+ for (int i = 0; i < glyphs.numGlyphs; i++) {
+ Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs.glyphs[i]) : 0;
+ if (!g) {
+ if (!face)
+ face = lockFace();
+ g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs.glyphs[i], 0, Format_None, true);
+ }
+ if (g) {
+ QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
+ QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
+ overall.x = qMin(overall.x, x);
+ overall.y = qMin(overall.y, y);
+ xmax = qMax(xmax, x + g->width);
+ ymax = qMax(ymax, y + g->height);
+ overall.xoff += g->advance;
+ if (!cacheEnabled)
+ delete g;
+ } else {
+ int left = FLOOR(face->glyph->metrics.horiBearingX);
+ int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
+ int top = CEIL(face->glyph->metrics.horiBearingY);
+ int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
+
+ QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
+ QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
+ overall.x = qMin(overall.x, x);
+ overall.y = qMin(overall.y, y);
+ xmax = qMax(xmax, x + TRUNC(right - left));
+ ymax = qMax(ymax, y + TRUNC(top - bottom));
+ overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x)));
+ }
+ }
+ overall.height = qMax(overall.height, ymax - overall.y);
+ overall.width = xmax - overall.x;
+
+ if (face)
+ unlockFace();
+
+ return overall;
+}
+
+glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
+{
+ FT_Face face = 0;
+ glyph_metrics_t overall;
+ Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyph) : 0;
+ if (!g) {
+ face = lockFace();
+ g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyph, 0, Format_None, true);
+ }
+ if (g) {
+ overall.x = g->x;
+ overall.y = -g->y;
+ overall.width = g->width;
+ overall.height = g->height;
+ overall.xoff = g->advance;
+ if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ overall.xoff = overall.xoff.round();
+ if (!cacheEnabled)
+ delete g;
+ } else {
+ int left = FLOOR(face->glyph->metrics.horiBearingX);
+ int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
+ int top = CEIL(face->glyph->metrics.horiBearingY);
+ int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
+
+ overall.width = TRUNC(right-left);
+ overall.height = TRUNC(top-bottom);
+ overall.x = TRUNC(left);
+ overall.y = -TRUNC(top);
+ overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
+ }
+ if (face)
+ unlockFace();
+ return overall;
+}
+
+glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
+{
+ return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
+}
+
+static FT_Matrix QTransformToFTMatrix(const QTransform &matrix)
+{
+ FT_Matrix m;
+
+ m.xx = FT_Fixed(matrix.m11() * 65536);
+ m.xy = FT_Fixed(-matrix.m21() * 65536);
+ m.yx = FT_Fixed(-matrix.m12() * 65536);
+ m.yy = FT_Fixed(matrix.m22() * 65536);
+
+ return m;
+}
+
+glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
+{
+ FT_Face face = 0;
+ glyph_metrics_t overall;
+ QGlyphSet *glyphSet = 0;
+ FT_Matrix ftMatrix = QTransformToFTMatrix(matrix);
+ if (cacheEnabled) {
+ if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
+ // TODO move everything here to a method of its own to access glyphSets
+ // to be shared with a new method that will replace loadTransformedGlyphSet()
+ for (int i = 0; i < transformedGlyphSets.count(); ++i) {
+ const QGlyphSet &g = transformedGlyphSets.at(i);
+ if (g.transformationMatrix.xx == ftMatrix.xx
+ && g.transformationMatrix.xy == ftMatrix.xy
+ && g.transformationMatrix.yx == ftMatrix.yx
+ && g.transformationMatrix.yy == ftMatrix.yy) {
+
+ // found a match, move it to the front
+ transformedGlyphSets.move(i, 0);
+ glyphSet = &transformedGlyphSets[0];
+ break;
+ }
+ }
+
+ if (!glyphSet) {
+ // don't cache more than 10 transformations
+ if (transformedGlyphSets.count() >= 10) {
+ transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
+ } else {
+ transformedGlyphSets.prepend(QGlyphSet());
+ }
+ glyphSet = &transformedGlyphSets[0];
+ glyphSet->clear();
+ glyphSet->transformationMatrix = ftMatrix;
+ }
+ Q_ASSERT(glyphSet);
+ } else {
+ glyphSet = &defaultGlyphSet;
+ }
+ }
+ Glyph * g = glyphSet ? glyphSet->getGlyph(glyph, subPixelPosition) : 0;
+ if (!g || g->format != format) {
+ face = lockFace();
+ FT_Matrix m = this->matrix;
+ FT_Matrix_Multiply(&ftMatrix, &m);
+ freetype->matrix = m;
+ g = loadGlyph(glyphSet, glyph, subPixelPosition, format, false);
+ }
+
+ if (g) {
+ overall.x = g->x;
+ overall.y = -g->y;
+ overall.width = g->width;
+ overall.height = g->height;
+ overall.xoff = g->advance;
+ if (!glyphSet)
+ delete g;
+ } else {
+ int left = FLOOR(face->glyph->metrics.horiBearingX);
+ int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
+ int top = CEIL(face->glyph->metrics.horiBearingY);
+ int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
+
+ overall.width = TRUNC(right-left);
+ overall.height = TRUNC(top-bottom);
+ overall.x = TRUNC(left);
+ overall.y = -TRUNC(top);
+ overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
+ }
+ if (face)
+ unlockFace();
+ return overall;
+}
+
+QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixelPosition,
+ QFontEngine::GlyphFormat neededFormat,
+ const QTransform &t, QPoint *offset)
+{
+ Q_ASSERT(currentlyLockedAlphaMap.isNull());
+ lockFace();
+
+ if (isBitmapFont())
+ neededFormat = Format_Mono;
+ else if (neededFormat == Format_None && defaultFormat != Format_None)
+ neededFormat = defaultFormat;
+ else if (neededFormat == Format_None)
+ neededFormat = Format_A8;
+
+ QImage::Format format;
+ switch (neededFormat) {
+ case Format_Mono:
+ format = QImage::Format_Mono;
+ break;
+ case Format_A8:
+ format = QImage::Format_Indexed8;
+ break;
+ case Format_A32:
+ format = QImage::Format_ARGB32;
+ break;
+ default:
+ Q_ASSERT(false);
+ format = QImage::Format_Invalid;
+ };
+
+ QFontEngineFT::Glyph *glyph;
+ QScopedPointer<QFontEngineFT::Glyph> glyphGuard;
+ if (cacheEnabled) {
+ QFontEngineFT::QGlyphSet *gset = &defaultGlyphSet;
+ QFontEngine::HintStyle hintStyle = default_hint_style;
+ if (t.type() >= QTransform::TxScale) {
+ // disable hinting if the glyphs are transformed
+ default_hint_style = HintNone;
+ if (t.isAffine())
+ gset = loadTransformedGlyphSet(t);
+ else
+ gset = 0;
+ }
+
+ if (gset) {
+ FT_Matrix m = matrix;
+ FT_Matrix_Multiply(&gset->transformationMatrix, &m);
+ FT_Set_Transform(freetype->face, &m, 0);
+ freetype->matrix = m;
+ }
+
+ if (!gset || gset->outline_drawing || !loadGlyph(gset, glyphIndex, subPixelPosition,
+ neededFormat)) {
+ default_hint_style = hintStyle;
+ return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t,
+ offset);
+ }
+ default_hint_style = hintStyle;
+
+ glyph = gset->getGlyph(glyphIndex, subPixelPosition);
+ } else {
+ FT_Matrix m = matrix;
+ FT_Matrix extra = QTransformToFTMatrix(t);
+ FT_Matrix_Multiply(&extra, &m);
+ FT_Set_Transform(freetype->face, &m, 0);
+ freetype->matrix = m;
+ glyph = loadGlyph(0, glyphIndex, subPixelPosition, neededFormat);
+ glyphGuard.reset(glyph);
+ }
+
+ if (glyph == 0 || glyph->data == 0 || glyph->width == 0 || glyph->height == 0) {
+ unlockFace();
+ return 0;
+ }
+
+ int pitch;
+ switch (neededFormat) {
+ case Format_Mono:
+ pitch = ((glyph->width + 31) & ~31) >> 3;
+ break;
+ case Format_A8:
+ pitch = (glyph->width + 3) & ~3;
+ break;
+ case Format_A32:
+ pitch = glyph->width * 4;
+ break;
+ default:
+ Q_ASSERT(false);
+ pitch = 0;
+ };
+
+ if (offset != 0)
+ *offset = QPoint(glyph->x, -glyph->y);
+
+ currentlyLockedAlphaMap = QImage(glyph->data, glyph->width, glyph->height, pitch, format);
+ if (!glyphGuard.isNull())
+ currentlyLockedAlphaMap = currentlyLockedAlphaMap.copy();
+ Q_ASSERT(!currentlyLockedAlphaMap.isNull());
+
+ QImageData *data = currentlyLockedAlphaMap.data_ptr();
+ data->is_locked = true;
+
+ return &currentlyLockedAlphaMap;
+}
+
+void QFontEngineFT::unlockAlphaMapForGlyph()
+{
+ Q_ASSERT(!currentlyLockedAlphaMap.isNull());
+ unlockFace();
+ currentlyLockedAlphaMap = QImage();
+}
+
+QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format)
+{
+ return defaultGlyphSet.outline_drawing ? 0 :
+ loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, g, subPixelPosition, format);
+}
+
+QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
+{
+ lockFace();
+
+ QScopedPointer<Glyph> glyph(loadGlyphFor(g, subPixelPosition, antialias ? Format_A8 : Format_Mono));
+ if (!glyph || !glyph->data) {
+ unlockFace();
+ return QFontEngine::alphaMapForGlyph(g);
+ }
+
+ const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
+
+ QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
+ if (antialias) {
+ QVector<QRgb> colors(256);
+ for (int i=0; i<256; ++i)
+ colors[i] = qRgba(0, 0, 0, i);
+ img.setColorTable(colors);
+ } else {
+ QVector<QRgb> colors(2);
+ colors[0] = qRgba(0, 0, 0, 0);
+ colors[1] = qRgba(0, 0, 0, 255);
+ img.setColorTable(colors);
+ }
+ Q_ASSERT(img.bytesPerLine() == pitch);
+ if (glyph->width) {
+ for (int y = 0; y < glyph->height; ++y)
+ memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
+ }
+ if (cacheEnabled)
+ glyph.take();
+ unlockFace();
+
+ return img;
+}
+
+QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t)
+{
+ if (t.type() > QTransform::TxTranslate)
+ return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
+
+ lockFace();
+
+ QScopedPointer<Glyph> glyph(loadGlyphFor(g, subPixelPosition, Format_A32));
+ if (!glyph || !glyph->data) {
+ unlockFace();
+ return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
+ }
+
+ QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
+ memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
+
+ if (cacheEnabled)
+ glyph.take();
+ unlockFace();
+
+ return img;
+}
+
+void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
+{
+ defaultGlyphSet.removeGlyphFromCache(glyph, 0);
+}
+
+int QFontEngineFT::glyphCount() const
+{
+ int count = 0;
+ FT_Face face = lockFace();
+ if (face) {
+ count = face->num_glyphs;
+ unlockFace();
+ }
+ return count;
+}
+
+FT_Face QFontEngineFT::lockFace(Scaling scale) const
+{
+ freetype->lock();
+ FT_Face face = freetype->face;
+ if (scale == Unscaled) {
+ FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
+ freetype->xsize = face->units_per_EM << 6;
+ freetype->ysize = face->units_per_EM << 6;
+ } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
+ FT_Set_Char_Size(face, xsize, ysize, 0, 0);
+ freetype->xsize = xsize;
+ freetype->ysize = ysize;
+ }
+ if (freetype->matrix.xx != matrix.xx ||
+ freetype->matrix.yy != matrix.yy ||
+ freetype->matrix.xy != matrix.xy ||
+ freetype->matrix.yx != matrix.yx) {
+ freetype->matrix = matrix;
+ FT_Set_Transform(face, &freetype->matrix, 0);
+ }
+
+ return face;
+}
+
+void QFontEngineFT::unlockFace() const
+{
+ freetype->unlock();
+}
+
+FT_Face QFontEngineFT::non_locked_face() const
+{
+ return freetype->face;
+}
+
+
+QFontEngineFT::QGlyphSet::QGlyphSet()
+ : outline_drawing(false)
+{
+ transformationMatrix.xx = 0x10000;
+ transformationMatrix.yy = 0x10000;
+ transformationMatrix.xy = 0;
+ transformationMatrix.yx = 0;
+ memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
+ fast_glyph_count = 0;
+}
+
+QFontEngineFT::QGlyphSet::~QGlyphSet()
+{
+ clear();
+}
+
+void QFontEngineFT::QGlyphSet::clear()
+{
+ if (fast_glyph_count > 0) {
+ for (int i = 0; i < 256; ++i) {
+ if (fast_glyph_data[i]) {
+ delete fast_glyph_data[i];
+ fast_glyph_data[i] = 0;
+ }
+ }
+ fast_glyph_count = 0;
+ }
+ qDeleteAll(glyph_data);
+ glyph_data.clear();
+}
+
+void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
+{
+ if (useFastGlyphData(index, subPixelPosition)) {
+ if (fast_glyph_data[index]) {
+ delete fast_glyph_data[index];
+ fast_glyph_data[index] = 0;
+ if (fast_glyph_count > 0)
+ --fast_glyph_count;
+ }
+ } else {
+ delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition));
+ }
+}
+
+void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
+{
+ if (useFastGlyphData(index, subPixelPosition)) {
+ if (!fast_glyph_data[index])
+ ++fast_glyph_count;
+ fast_glyph_data[index] = glyph;
+ } else {
+ glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph);
+ }
+}
+
+int QFontEngineFT::getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints)
+{
+ lockFace();
+ bool hsubpixel = true;
+ int vfactor = 1;
+ int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor);
+ int result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints);
+ unlockFace();
+ return result;
+}
+
+bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
+{
+ if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
+ return false;
+
+ // Increase the reference of this QFreetypeFace since one more QFontEngineFT
+ // will be using it
+ freetype->ref.ref();
+
+ default_load_flags = fe->default_load_flags;
+ default_hint_style = fe->default_hint_style;
+ antialias = fe->antialias;
+ transform = fe->transform;
+ embolden = fe->embolden;
+ obliquen = fe->obliquen;
+ subpixelType = fe->subpixelType;
+ lcdFilterType = fe->lcdFilterType;
+ embeddedbitmap = fe->embeddedbitmap;
+
+ return true;
+}
+
+QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
+{
+ QFontDef fontDef(this->fontDef);
+ fontDef.pixelSize = pixelSize;
+ QFontEngineFT *fe = new QFontEngineFT(fontDef);
+ if (!fe->initFromFontEngine(this)) {
+ delete fe;
+ return 0;
+ } else {
+ return fe;
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_FREETYPE
diff -Naur qt-everywhere-opensource-src-5.3.1/qtbase/src/gui/text/qtextengine.cpp qt-everywhere-opensource-src-5.3.1.new/qtbase/src/gui/text/qtextengine.cpp
--- qt-everywhere-opensource-src-5.3.1/qtbase/src/gui/text/qtextengine.cpp 2014-06-19 12:08:06.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtbase/src/gui/text/qtextengine.cpp 2014-08-13 04:35:08.420435869 +0200
@@ -1549,6 +1549,7 @@
case QChar::Script_Hiragana:
case QChar::Script_Katakana:
case QChar::Script_Bopomofo:
+ case QChar::Script_Gujarati:
analysis[i].script = QChar::Script_Common;
break;
default:
diff -Naur qt-everywhere-opensource-src-5.3.1/qtbase/src/plugins/platforms/xcb/qxcbkeyboard.cpp qt-everywhere-opensource-src-5.3.1.new/qtbase/src/plugins/platforms/xcb/qxcbkeyboard.cpp
--- qt-everywhere-opensource-src-5.3.1/qtbase/src/plugins/platforms/xcb/qxcbkeyboard.cpp 2014-06-19 12:08:08.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtbase/src/plugins/platforms/xcb/qxcbkeyboard.cpp 2014-08-13 04:35:08.411435885 +0200
@@ -929,6 +929,15 @@
i += 2;
}
+ if (rmod_masks.meta) {
+ // translate Super/Hyper keys to Meta if we're using them as the MetaModifier
+ if (rmod_masks.meta == rmod_masks.super && (code == Qt::Key_Super_L || code == Qt::Key_Super_R)) {
+ code = Qt::Key_Meta;
+ } else if (rmod_masks.meta == rmod_masks.hyper && (code == Qt::Key_Hyper_L || code == Qt::Key_Hyper_R)) {
+ code = Qt::Key_Meta;
+ }
+ }
+
return code;
}
diff -Naur qt-everywhere-opensource-src-5.3.1/qtbase/src/plugins/platforms/xcb/qxcbscreen.cpp qt-everywhere-opensource-src-5.3.1.new/qtbase/src/plugins/platforms/xcb/qxcbscreen.cpp
--- qt-everywhere-opensource-src-5.3.1/qtbase/src/plugins/platforms/xcb/qxcbscreen.cpp 2014-06-19 12:08:08.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtbase/src/plugins/platforms/xcb/qxcbscreen.cpp 2014-08-13 04:35:08.400435918 +0200
@@ -106,6 +106,11 @@
qDebug(" root ID........: %x", screen()->root);
#endif
+ QScopedPointer<xcb_get_window_attributes_reply_t, QScopedPointerPodDeleter> rootAttribs(
+ xcb_get_window_attributes_reply(xcb_connection(),
+ xcb_get_window_attributes_unchecked(xcb_connection(), screen()->root), NULL));
+ const quint32 existingEventMask = rootAttribs.isNull() ? 0 : rootAttribs->your_event_mask;
+
const quint32 mask = XCB_CW_EVENT_MASK;
const quint32 values[] = {
// XCB_CW_EVENT_MASK
@@ -113,6 +118,7 @@
| XCB_EVENT_MASK_LEAVE_WINDOW
| XCB_EVENT_MASK_PROPERTY_CHANGE
| XCB_EVENT_MASK_STRUCTURE_NOTIFY // for the "MANAGER" atom (system tray notification).
+ | existingEventMask // don't overwrite the event mask on the root window
};
xcb_change_window_attributes(xcb_connection(), screen()->root, mask, values);
diff -Naur qt-everywhere-opensource-src-5.3.1/qtbase/src/plugins/platforms/xcb/qxcbxsettings.cpp qt-everywhere-opensource-src-5.3.1.new/qtbase/src/plugins/platforms/xcb/qxcbxsettings.cpp
--- qt-everywhere-opensource-src-5.3.1/qtbase/src/plugins/platforms/xcb/qxcbxsettings.cpp 2014-06-19 12:08:08.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtbase/src/plugins/platforms/xcb/qxcbxsettings.cpp 2014-08-13 04:35:08.418435872 +0200
@@ -42,6 +42,7 @@
#include "qxcbxsettings.h"
#include <QtCore/QByteArray>
+#include <QtCore/QtEndian>
#include <X11/extensions/XIproto.h>
@@ -149,47 +150,67 @@
{
if (xSettings.length() < 12)
return;
- // we ignore byteorder for now
- char byteOrder = xSettings.at(1);
- Q_UNUSED(byteOrder);
- uint number_of_settings = *reinterpret_cast<const uint *>(xSettings.mid(8,4).constData());
+ char byteOrder = xSettings.at(0);
+ if (byteOrder != LSBFirst && byteOrder != MSBFirst) {
+ qWarning("%s ByteOrder byte %d not 0 or 1", Q_FUNC_INFO , byteOrder);
+ return;
+ }
+
+#define ADJUST_BO(b, t, x) \
+ ((b == LSBFirst) ? \
+ qFromLittleEndian<t>((const uchar *)(x)) : \
+ qFromBigEndian<t>((const uchar *)(x)))
+#define VALIDATE_LENGTH(x) \
+ if ((size_t)xSettings.length() < (offset + local_offset + 12 + x)) { \
+ qWarning("%s Length %d runs past end of data", Q_FUNC_INFO , x); \
+ return; \
+ }
+ uint number_of_settings = ADJUST_BO(byteOrder, quint32, xSettings.mid(8,4).constData());
const char *data = xSettings.constData() + 12;
size_t offset = 0;
for (uint i = 0; i < number_of_settings; i++) {
int local_offset = 0;
+ VALIDATE_LENGTH(2);
XSettingsType type = static_cast<XSettingsType>(*reinterpret_cast<const quint8 *>(data + offset));
local_offset += 2;
- quint16 name_len = *reinterpret_cast<const quint16 *>(data + offset + local_offset);
+ VALIDATE_LENGTH(2);
+ quint16 name_len = ADJUST_BO(byteOrder, quint16, data + offset + local_offset);
local_offset += 2;
+ VALIDATE_LENGTH(name_len);
QByteArray name(data + offset + local_offset, name_len);
local_offset += round_to_nearest_multiple_of_4(name_len);
- int last_change_serial = *reinterpret_cast<const int *>(data + offset + local_offset);
+ VALIDATE_LENGTH(4);
+ int last_change_serial = ADJUST_BO(byteOrder, qint32, data + offset + local_offset);
Q_UNUSED(last_change_serial);
local_offset += 4;
QVariant value;
if (type == XSettingsTypeString) {
- int value_length = *reinterpret_cast<const int *>(data + offset + local_offset);
+ VALIDATE_LENGTH(4);
+ int value_length = ADJUST_BO(byteOrder, qint32, data + offset + local_offset);
local_offset+=4;
+ VALIDATE_LENGTH(value_length);
QByteArray value_string(data + offset + local_offset, value_length);
value.setValue(value_string);
local_offset += round_to_nearest_multiple_of_4(value_length);
} else if (type == XSettingsTypeInteger) {
- int value_length = *reinterpret_cast<const int *>(data + offset + local_offset);
+ VALIDATE_LENGTH(4);
+ int value_length = ADJUST_BO(byteOrder, qint32, data + offset + local_offset);
local_offset += 4;
value.setValue(value_length);
} else if (type == XSettingsTypeColor) {
- quint16 red = *reinterpret_cast<const quint16 *>(data + offset + local_offset);
+ VALIDATE_LENGTH(2*4);
+ quint16 red = ADJUST_BO(byteOrder, quint16, data + offset + local_offset);
local_offset += 2;
- quint16 green = *reinterpret_cast<const quint16 *>(data + offset + local_offset);
+ quint16 green = ADJUST_BO(byteOrder, quint16, data + offset + local_offset);
local_offset += 2;
- quint16 blue = *reinterpret_cast<const quint16 *>(data + offset + local_offset);
+ quint16 blue = ADJUST_BO(byteOrder, quint16, data + offset + local_offset);
local_offset += 2;
- quint16 alpha= *reinterpret_cast<const quint16 *>(data + offset + local_offset);
+ quint16 alpha= ADJUST_BO(byteOrder, quint16, data + offset + local_offset);
local_offset += 2;
QColor color_value(red,green,blue,alpha);
value.setValue(color_value);
diff -Naur qt-everywhere-opensource-src-5.3.1/qtbase/src/widgets/util/qsystemtrayicon.cpp qt-everywhere-opensource-src-5.3.1.new/qtbase/src/widgets/util/qsystemtrayicon.cpp
--- qt-everywhere-opensource-src-5.3.1/qtbase/src/widgets/util/qsystemtrayicon.cpp 2014-06-19 12:08:03.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtbase/src/widgets/util/qsystemtrayicon.cpp 2014-08-13 04:35:08.413435882 +0200
@@ -672,6 +672,74 @@
QWidget::timerEvent(e);
}
+//////////////////////////////////////////////////////////////////////
+void QSystemTrayIconPrivate::install_sys_qpa()
+{
+ qpa_sys->init();
+ QObject::connect(qpa_sys, SIGNAL(activated(QPlatformSystemTrayIcon::ActivationReason)),
+ q_func(), SLOT(_q_emitActivated(QPlatformSystemTrayIcon::ActivationReason)));
+ QObject::connect(qpa_sys, &QPlatformSystemTrayIcon::messageClicked,
+ q_func(), &QSystemTrayIcon::messageClicked);
+ updateMenu_sys();
+ updateIcon_sys();
+ updateToolTip_sys();
+}
+
+void QSystemTrayIconPrivate::remove_sys_qpa()
+{
+ qpa_sys->cleanup();
+}
+
+QRect QSystemTrayIconPrivate::geometry_sys_qpa() const
+{
+ return qpa_sys->geometry();
+}
+
+void QSystemTrayIconPrivate::updateIcon_sys_qpa()
+{
+ qpa_sys->updateIcon(icon);
+}
+
+void QSystemTrayIconPrivate::updateMenu_sys_qpa()
+{
+ if (menu) {
+ if (!menu->platformMenu()) {
+ QPlatformMenu *platformMenu = qpa_sys->createMenu();
+ if (platformMenu)
+ menu->setPlatformMenu(platformMenu);
+ }
+ qpa_sys->updateMenu(menu->platformMenu());
+ }
+}
+
+void QSystemTrayIconPrivate::updateToolTip_sys_qpa()
+{
+ qpa_sys->updateToolTip(toolTip);
+}
+
+void QSystemTrayIconPrivate::showMessage_sys_qpa(const QString &message,
+ const QString &title,
+ QSystemTrayIcon::MessageIcon icon,
+ int msecs)
+{
+ QIcon notificationIcon;
+ switch (icon) {
+ case QSystemTrayIcon::Information:
+ notificationIcon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation);
+ break;
+ case QSystemTrayIcon::Warning:
+ notificationIcon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning);
+ break;
+ case QSystemTrayIcon::Critical:
+ notificationIcon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical);
+ break;
+ default:
+ break;
+ }
+ qpa_sys->showMessage(message, title, notificationIcon,
+ static_cast<QPlatformSystemTrayIcon::MessageIcon>(icon), msecs);
+}
+
QT_END_NAMESPACE
#endif // QT_NO_SYSTEMTRAYICON
diff -Naur qt-everywhere-opensource-src-5.3.1/qtbase/src/widgets/util/qsystemtrayicon_p.h qt-everywhere-opensource-src-5.3.1.new/qtbase/src/widgets/util/qsystemtrayicon_p.h
--- qt-everywhere-opensource-src-5.3.1/qtbase/src/widgets/util/qsystemtrayicon_p.h 2014-06-19 12:08:03.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtbase/src/widgets/util/qsystemtrayicon_p.h 2014-08-13 04:35:08.414435881 +0200
@@ -98,6 +98,15 @@
QSystemTrayIconSys *sys;
QPlatformSystemTrayIcon *qpa_sys;
bool visible;
+
+private:
+ void install_sys_qpa();
+ void remove_sys_qpa();
+ void updateIcon_sys_qpa();
+ void updateToolTip_sys_qpa();
+ void updateMenu_sys_qpa();
+ QRect geometry_sys_qpa() const;
+ void showMessage_sys_qpa(const QString &msg, const QString &title, QSystemTrayIcon::MessageIcon icon, int secs);
};
class QBalloonTip : public QWidget
diff -Naur qt-everywhere-opensource-src-5.3.1/qtbase/src/widgets/util/qsystemtrayicon_qpa.cpp qt-everywhere-opensource-src-5.3.1.new/qtbase/src/widgets/util/qsystemtrayicon_qpa.cpp
--- qt-everywhere-opensource-src-5.3.1/qtbase/src/widgets/util/qsystemtrayicon_qpa.cpp 2014-06-19 12:08:03.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtbase/src/widgets/util/qsystemtrayicon_qpa.cpp 2014-08-13 04:35:08.414435881 +0200
@@ -65,28 +65,20 @@
void QSystemTrayIconPrivate::install_sys()
{
- if (qpa_sys) {
- qpa_sys->init();
- QObject::connect(qpa_sys, SIGNAL(activated(QPlatformSystemTrayIcon::ActivationReason)),
- q_func(), SLOT(_q_emitActivated(QPlatformSystemTrayIcon::ActivationReason)));
- QObject::connect(qpa_sys, SIGNAL(messageClicked()),
- q_func(), SIGNAL(messageClicked()));
- updateMenu_sys();
- updateIcon_sys();
- updateToolTip_sys();
- }
+ if (qpa_sys)
+ install_sys_qpa();
}
void QSystemTrayIconPrivate::remove_sys()
{
if (qpa_sys)
- qpa_sys->cleanup();
+ remove_sys_qpa();
}
QRect QSystemTrayIconPrivate::geometry_sys() const
{
if (qpa_sys)
- return qpa_sys->geometry();
+ return geometry_sys_qpa();
else
return QRect();
}
@@ -94,25 +86,19 @@
void QSystemTrayIconPrivate::updateIcon_sys()
{
if (qpa_sys)
- qpa_sys->updateIcon(icon);
+ updateIcon_sys_qpa();
}
void QSystemTrayIconPrivate::updateMenu_sys()
{
- if (qpa_sys && menu) {
- if (!menu->platformMenu()) {
- QPlatformMenu *platformMenu = qpa_sys->createMenu();
- if (platformMenu)
- menu->setPlatformMenu(platformMenu);
- }
- qpa_sys->updateMenu(menu->platformMenu());
- }
+ if (qpa_sys)
+ updateMenu_sys_qpa();
}
void QSystemTrayIconPrivate::updateToolTip_sys()
{
if (qpa_sys)
- qpa_sys->updateToolTip(toolTip);
+ updateToolTip_sys_qpa();
}
bool QSystemTrayIconPrivate::isSystemTrayAvailable_sys()
@@ -138,25 +124,8 @@
QSystemTrayIcon::MessageIcon icon,
int msecs)
{
- if (!qpa_sys)
- return;
-
- QIcon notificationIcon;
- switch (icon) {
- case QSystemTrayIcon::Information:
- notificationIcon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation);
- break;
- case QSystemTrayIcon::Warning:
- notificationIcon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning);
- break;
- case QSystemTrayIcon::Critical:
- notificationIcon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical);
- break;
- default:
- break;
- }
- qpa_sys->showMessage(message, title, notificationIcon,
- static_cast<QPlatformSystemTrayIcon::MessageIcon>(icon), msecs);
+ if (qpa_sys)
+ showMessage_sys_qpa(message, title, icon, msecs);
}
QT_END_NAMESPACE
diff -Naur qt-everywhere-opensource-src-5.3.1/qtbase/src/widgets/util/qsystemtrayicon_x11.cpp qt-everywhere-opensource-src-5.3.1.new/qtbase/src/widgets/util/qsystemtrayicon_x11.cpp
--- qt-everywhere-opensource-src-5.3.1/qtbase/src/widgets/util/qsystemtrayicon_x11.cpp 2014-06-19 12:08:03.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtbase/src/widgets/util/qsystemtrayicon_x11.cpp 2014-08-13 04:35:08.414435881 +0200
@@ -55,6 +55,9 @@
#include <qscreen.h>
#include <qbackingstore.h>
#include <qpa/qplatformnativeinterface.h>
+#include <qpa/qplatformsystemtrayicon.h>
+#include <qpa/qplatformtheme.h>
+#include <private/qguiapplication_p.h>
#include <qdebug.h>
#ifndef QT_NO_SYSTEMTRAYICON
@@ -209,16 +212,22 @@
QSystemTrayIconPrivate::QSystemTrayIconPrivate()
: sys(0),
+ qpa_sys(QGuiApplicationPrivate::platformTheme()->createPlatformSystemTrayIcon()),
visible(false)
{
}
QSystemTrayIconPrivate::~QSystemTrayIconPrivate()
{
+ delete qpa_sys;
}
void QSystemTrayIconPrivate::install_sys()
{
+ if (qpa_sys) {
+ install_sys_qpa();
+ return;
+ }
Q_Q(QSystemTrayIcon);
if (!sys && locateSystemTray()) {
sys = new QSystemTrayIconSys(q);
@@ -229,6 +238,8 @@
QRect QSystemTrayIconPrivate::geometry_sys() const
{
+ if (qpa_sys)
+ return geometry_sys_qpa();
if (!sys)
return QRect();
return sys->globalGeometry();
@@ -236,6 +247,10 @@
void QSystemTrayIconPrivate::remove_sys()
{
+ if (qpa_sys) {
+ remove_sys_qpa();
+ return;
+ }
if (!sys)
return;
QBalloonTip::hideBalloon();
@@ -246,17 +261,26 @@
void QSystemTrayIconPrivate::updateIcon_sys()
{
+ if (qpa_sys) {
+ updateIcon_sys_qpa();
+ return;
+ }
if (sys)
sys->updateIcon();
}
void QSystemTrayIconPrivate::updateMenu_sys()
{
-
+ if (qpa_sys)
+ updateMenu_sys_qpa();
}
void QSystemTrayIconPrivate::updateToolTip_sys()
{
+ if (qpa_sys) {
+ updateToolTip_sys_qpa();
+ return;
+ }
if (!sys)
return;
#ifndef QT_NO_TOOLTIP
@@ -266,6 +290,11 @@
bool QSystemTrayIconPrivate::isSystemTrayAvailable_sys()
{
+ QScopedPointer<QPlatformSystemTrayIcon> sys(QGuiApplicationPrivate::platformTheme()->createPlatformSystemTrayIcon());
+ if (sys)
+ return sys->isSystemTrayAvailable();
+
+ // no QPlatformSystemTrayIcon so fall back to default xcb platform behavior
const QString platform = QGuiApplication::platformName();
if (platform.compare(QStringLiteral("xcb"), Qt::CaseInsensitive) == 0)
return locateSystemTray();
@@ -274,12 +303,21 @@
bool QSystemTrayIconPrivate::supportsMessages_sys()
{
+ QScopedPointer<QPlatformSystemTrayIcon> sys(QGuiApplicationPrivate::platformTheme()->createPlatformSystemTrayIcon());
+ if (sys)
+ return sys->supportsMessages();
+
+ // no QPlatformSystemTrayIcon so fall back to default xcb platform behavior
return true;
}
void QSystemTrayIconPrivate::showMessage_sys(const QString &message, const QString &title,
QSystemTrayIcon::MessageIcon icon, int msecs)
{
+ if (qpa_sys) {
+ showMessage_sys_qpa(message, title, icon, msecs);
+ return;
+ }
if (!sys)
return;
const QPoint g = sys->globalGeometry().topLeft();
diff -Naur qt-everywhere-opensource-src-5.3.1/qtbase/tests/auto/corelib/io/qdebug/qdebug.pro qt-everywhere-opensource-src-5.3.1.new/qtbase/tests/auto/corelib/io/qdebug/qdebug.pro
--- qt-everywhere-opensource-src-5.3.1/qtbase/tests/auto/corelib/io/qdebug/qdebug.pro 2014-06-19 12:08:01.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtbase/tests/auto/corelib/io/qdebug/qdebug.pro 2014-08-13 04:35:08.405435896 +0200
@@ -1,5 +1,5 @@
CONFIG += testcase parallel_test
TARGET = tst_qdebug
-QT = core testlib
+QT = core testlib concurrent
SOURCES = tst_qdebug.cpp
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
diff -Naur qt-everywhere-opensource-src-5.3.1/qtbase/tests/auto/corelib/io/qdebug/tst_qdebug.cpp qt-everywhere-opensource-src-5.3.1.new/qtbase/tests/auto/corelib/io/qdebug/tst_qdebug.cpp
--- qt-everywhere-opensource-src-5.3.1/qtbase/tests/auto/corelib/io/qdebug/tst_qdebug.cpp 2014-06-19 12:08:01.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtbase/tests/auto/corelib/io/qdebug/tst_qdebug.cpp 2014-08-13 04:35:08.405435896 +0200
@@ -44,6 +44,9 @@
#include <QtCore/QtDebug>
#include <QtTest/QtTest>
+#include <QtConcurrentRun>
+#include <QFutureSynchronizer>
+
class tst_QDebug: public QObject
{
Q_OBJECT
@@ -59,6 +62,7 @@
void qDebugQLatin1String() const;
void textStreamModifiers() const;
void defaultMessagehandler() const;
+ void threadSafety() const;
};
void tst_QDebug::assignment() const
@@ -305,5 +309,41 @@
QVERIFY(same);
}
+QMutex s_mutex;
+QStringList s_messages;
+QSemaphore s_sema;
+
+static void threadSafeMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
+{
+ QMutexLocker lock(&s_mutex);
+ s_messages.append(msg);
+ Q_UNUSED(type);
+ Q_UNUSED(context);
+}
+
+static void doDebug() // called in each thread
+{
+ s_sema.acquire();
+ qDebug() << "doDebug";
+}
+
+void tst_QDebug::threadSafety() const
+{
+ MessageHandlerSetter mhs(threadSafeMessageHandler);
+ const int numThreads = 10;
+ QThreadPool::globalInstance()->setMaxThreadCount(numThreads);
+ QFutureSynchronizer<void> sync;
+ for (int i = 0; i < numThreads; ++i) {
+ sync.addFuture(QtConcurrent::run(&doDebug));
+ }
+ s_sema.release(numThreads);
+ sync.waitForFinished();
+ QMutexLocker lock(&s_mutex);
+ QCOMPARE(s_messages.count(), numThreads);
+ for (int i = 0; i < numThreads; ++i) {
+ QCOMPARE(s_messages.at(i), QStringLiteral("doDebug"));
+ }
+}
+
QTEST_MAIN(tst_QDebug);
#include "tst_qdebug.moc"
diff -Naur qt-everywhere-opensource-src-5.3.1/qtwebkit/Source/JavaScriptCore/JavaScriptCore.pri qt-everywhere-opensource-src-5.3.1.new/qtwebkit/Source/JavaScriptCore/JavaScriptCore.pri
--- qt-everywhere-opensource-src-5.3.1/qtwebkit/Source/JavaScriptCore/JavaScriptCore.pri 2014-06-19 12:08:23.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtwebkit/Source/JavaScriptCore/JavaScriptCore.pri 2014-08-13 04:14:29.357784981 +0200
@@ -7,6 +7,12 @@
SOURCE_DIR = $${ROOT_WEBKIT_DIR}/Source/JavaScriptCore
+equals(QT_ARCH, arm)|equals(QT_ARCH, aarch64)|equals(QT_ARCH, i386)|equals(QT_ARCH, i686)|equals(QT_ARCH, x86_64)| equals(QT_ARCH, powerpc64)|equals(QT_ARCH, powerpc) {
+ message("JavaScriptCore workaround for QtWebkit: do not build with -g, but with -g1")
+ QMAKE_CXXFLAGS_RELEASE -= -g
+ QMAKE_CXXFLAGS_RELEASE += -g1
+}
+
JAVASCRIPTCORE_GENERATED_SOURCES_DIR = $${ROOT_BUILD_DIR}/Source/JavaScriptCore/$${GENERATED_SOURCES_DESTDIR}
INCLUDEPATH += \
diff -Naur qt-everywhere-opensource-src-5.3.1/qtwebkit/Source/QtWebKit.pro qt-everywhere-opensource-src-5.3.1.new/qtwebkit/Source/QtWebKit.pro
--- qt-everywhere-opensource-src-5.3.1/qtwebkit/Source/QtWebKit.pro 2014-06-19 12:08:26.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtwebkit/Source/QtWebKit.pro 2014-08-13 04:13:16.564919490 +0200
@@ -7,6 +7,11 @@
TEMPLATE = subdirs
CONFIG += ordered
+CONFIG(release):!CONFIG(standalone_package) {
+ contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols
+ unix:contains(QT_CONFIG, reduce_relocations):CONFIG += bsymbolic_functions
+}
+
api.file = api.pri
SUBDIRS += api
diff -Naur qt-everywhere-opensource-src-5.3.1/qtwebkit/Source/WebCore/WebCore.pri qt-everywhere-opensource-src-5.3.1.new/qtwebkit/Source/WebCore/WebCore.pri
--- qt-everywhere-opensource-src-5.3.1/qtwebkit/Source/WebCore/WebCore.pri 2014-06-19 12:08:15.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtwebkit/Source/WebCore/WebCore.pri 2014-08-13 04:18:36.403328716 +0200
@@ -7,6 +7,12 @@
SOURCE_DIR = $${ROOT_WEBKIT_DIR}/Source/WebCore
+equals(QT_ARCH, arm)|equals(QT_ARCH, aarch64)|equals(QT_ARCH, i386)|equals(QT_ARCH, i686)|equals(QT_ARCH, x86_64)| equals(QT_ARCH, powerpc64)|equals(QT_ARCH, powerpc) {
+ message("WebCore workaround for QtWebkit: do not build with -g, but with -g1")
+ QMAKE_CXXFLAGS_RELEASE -= -g
+ QMAKE_CXXFLAGS_RELEASE += -g1
+}
+
QT *= network sql core-private gui-private
WEBCORE_GENERATED_SOURCES_DIR = $${ROOT_BUILD_DIR}/Source/WebCore/$${GENERATED_SOURCES_DESTDIR}
@@ -301,6 +307,8 @@
unix:!mac:*-g++*:QMAKE_CXXFLAGS += -ffunction-sections
}
unix:!mac:*-g++*:QMAKE_CXXFLAGS += -fdata-sections
+unix:!mac:*-g++*:!equals(QT_ARCH, powerpc):!equals(QT_ARCH, s390):!equals(QT_ARCH, mips):!equals(QT_ARCH, arm):QMAKE_LFLAGS += -Wl,--no-keep-memory
+unix:!mac:*-g++*:!equals(QT_ARCH, powerpc):!equals(QT_ARCH, s390):!equals(QT_ARCH, mips):!equals(QT_ARCH, arm):QMAKE_LFLAGS += -Wl,--reduce-memory-overheads
unix:!mac:*-g++*:QMAKE_LFLAGS += -Wl,--gc-sections
linux*-g++*:QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
diff -Naur qt-everywhere-opensource-src-5.3.1/qtwebkit/Source/WebCore/WebCore.pri.orig qt-everywhere-opensource-src-5.3.1.new/qtwebkit/Source/WebCore/WebCore.pri.orig
--- qt-everywhere-opensource-src-5.3.1/qtwebkit/Source/WebCore/WebCore.pri.orig 1970-01-01 01:00:00.000000000 +0100
+++ qt-everywhere-opensource-src-5.3.1.new/qtwebkit/Source/WebCore/WebCore.pri.orig 2014-08-13 04:15:02.022724637 +0200
@@ -0,0 +1,316 @@
+# -------------------------------------------------------------------
+# This file contains shared rules used both when building WebCore
+# itself, and by targets that use WebCore.
+#
+# See 'Tools/qmake/README' for an overview of the build system
+# -------------------------------------------------------------------
+
+SOURCE_DIR = $${ROOT_WEBKIT_DIR}/Source/WebCore
+
+equals(QT_ARCH, arm)|equals(QT_ARCH, aarch64)|equals(QT_ARCH, i386)|equals(QT_ARCH, i686)|equals(QT_ARCH, x86_64)| equals(QT_ARCH, powerpc64)|equals(QT_ARCH, powerpc) {
+ message("WebCore workaround for QtWebkit: do not build with -g, but with -g1")
+ QMAKE_CXXFLAGS_RELEASE -= -g
+ QMAKE_CXXFLAGS_RELEASE += -g1
+}
+
+QT *= network sql core-private gui-private
+
+WEBCORE_GENERATED_SOURCES_DIR = $${ROOT_BUILD_DIR}/Source/WebCore/$${GENERATED_SOURCES_DESTDIR}
+
+INCLUDEPATH += \
+ $$SOURCE_DIR \
+ $$SOURCE_DIR/Modules/filesystem \
+ $$SOURCE_DIR/Modules/geolocation \
+ $$SOURCE_DIR/Modules/indexeddb \
+ $$SOURCE_DIR/Modules/navigatorcontentutils \
+ $$SOURCE_DIR/Modules/notifications \
+ $$SOURCE_DIR/Modules/proximity \
+ $$SOURCE_DIR/Modules/quota \
+ $$SOURCE_DIR/Modules/webaudio \
+ $$SOURCE_DIR/Modules/webdatabase \
+ $$SOURCE_DIR/Modules/websockets \
+ $$SOURCE_DIR/accessibility \
+ $$SOURCE_DIR/bindings \
+ $$SOURCE_DIR/bindings/generic \
+ $$SOURCE_DIR/bridge \
+ $$SOURCE_DIR/bridge/qt \
+ $$SOURCE_DIR/css \
+ $$SOURCE_DIR/dom \
+ $$SOURCE_DIR/dom/default \
+ $$SOURCE_DIR/editing \
+ $$SOURCE_DIR/fileapi \
+ $$SOURCE_DIR/history \
+ $$SOURCE_DIR/html \
+ $$SOURCE_DIR/html/canvas \
+ $$SOURCE_DIR/html/forms \
+ $$SOURCE_DIR/html/parser \
+ $$SOURCE_DIR/html/shadow \
+ $$SOURCE_DIR/html/track \
+ $$SOURCE_DIR/inspector \
+ $$SOURCE_DIR/loader \
+ $$SOURCE_DIR/loader/appcache \
+ $$SOURCE_DIR/loader/archive \
+ $$SOURCE_DIR/loader/cache \
+ $$SOURCE_DIR/loader/icon \
+ $$SOURCE_DIR/mathml \
+ $$SOURCE_DIR/page \
+ $$SOURCE_DIR/page/animation \
+ $$SOURCE_DIR/page/qt \
+ $$SOURCE_DIR/page/scrolling \
+ $$SOURCE_DIR/page/scrolling/coordinatedgraphics \
+ $$SOURCE_DIR/platform \
+ $$SOURCE_DIR/platform/animation \
+ $$SOURCE_DIR/platform/audio \
+ $$SOURCE_DIR/platform/graphics \
+ $$SOURCE_DIR/platform/graphics/cpu/arm \
+ $$SOURCE_DIR/platform/graphics/cpu/arm/filters \
+ $$SOURCE_DIR/platform/graphics/filters \
+ $$SOURCE_DIR/platform/graphics/filters/texmap \
+ $$SOURCE_DIR/platform/graphics/opengl \
+ $$SOURCE_DIR/platform/graphics/opentype \
+ $$SOURCE_DIR/platform/graphics/qt \
+ $$SOURCE_DIR/platform/graphics/surfaces \
+ $$SOURCE_DIR/platform/graphics/texmap \
+ $$SOURCE_DIR/platform/graphics/texmap/coordinated \
+ $$SOURCE_DIR/platform/graphics/transforms \
+ $$SOURCE_DIR/platform/image-decoders \
+ $$SOURCE_DIR/platform/image-decoders/bmp \
+ $$SOURCE_DIR/platform/image-decoders/ico \
+ $$SOURCE_DIR/platform/image-decoders/gif \
+ $$SOURCE_DIR/platform/image-decoders/jpeg \
+ $$SOURCE_DIR/platform/image-decoders/png \
+ $$SOURCE_DIR/platform/image-decoders/webp \
+ $$SOURCE_DIR/platform/leveldb \
+ $$SOURCE_DIR/platform/mock \
+ $$SOURCE_DIR/platform/network \
+ $$SOURCE_DIR/platform/network/qt \
+ $$SOURCE_DIR/platform/qt \
+ $$SOURCE_DIR/platform/sql \
+ $$SOURCE_DIR/platform/text \
+ $$SOURCE_DIR/platform/text/transcoder \
+ $$SOURCE_DIR/plugins \
+ $$SOURCE_DIR/rendering \
+ $$SOURCE_DIR/rendering/mathml \
+ $$SOURCE_DIR/rendering/shapes \
+ $$SOURCE_DIR/rendering/style \
+ $$SOURCE_DIR/rendering/svg \
+ $$SOURCE_DIR/storage \
+ $$SOURCE_DIR/svg \
+ $$SOURCE_DIR/svg/animation \
+ $$SOURCE_DIR/svg/graphics \
+ $$SOURCE_DIR/svg/graphics/filters \
+ $$SOURCE_DIR/svg/properties \
+ $$SOURCE_DIR/testing \
+ $$SOURCE_DIR/websockets \
+ $$SOURCE_DIR/workers \
+ $$SOURCE_DIR/xml \
+ $$SOURCE_DIR/xml/parser \
+ $$SOURCE_DIR/../ThirdParty
+
+INCLUDEPATH += \
+ $$SOURCE_DIR/bridge/jsc \
+ $$SOURCE_DIR/bindings/js \
+ $$SOURCE_DIR/bridge/c \
+ $$SOURCE_DIR/testing/js
+
+INCLUDEPATH += $$WEBCORE_GENERATED_SOURCES_DIR
+
+enable?(XSLT) {
+ use?(LIBXML2) {
+ mac {
+ QMAKE_CXXFLAGS += -iwithsysroot /usr/include/libxslt -iwithsysroot /usr/include/libxml2
+ LIBS += -lxml2 -lxslt
+ } else {
+ PKGCONFIG += libxslt libxml-2.0
+ }
+ } else {
+ QT *= xmlpatterns
+ }
+} else:!mac:use?(LIBXML2) {
+ PKGCONFIG += libxml-2.0
+}
+
+use?(ZLIB) {
+ LIBS += -lz
+}
+
+enable?(NETSCAPE_PLUGIN_API) {
+ unix {
+ mac {
+ INCLUDEPATH += platform/mac
+ # Note: XP_MACOSX is defined in npapi.h
+ } else {
+ xlibAvailable() {
+ CONFIG *= x11
+ LIBS += -lXrender
+ DEFINES += MOZ_X11
+ }
+ DEFINES += XP_UNIX
+ DEFINES += ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE=1
+ }
+ }
+ win32-* {
+ LIBS += \
+ -ladvapi32 \
+ -lgdi32 \
+ -lshell32 \
+ -lshlwapi \
+ -luser32 \
+ -lversion
+ }
+}
+
+have?(qtsensors):if(enable?(ORIENTATION_EVENTS)|enable?(DEVICE_ORIENTATION)): QT += sensors
+
+use?(QT_MOBILITY_SYSTEMINFO) {
+ CONFIG *= mobility
+ MOBILITY *= systeminfo
+}
+
+enable?(GAMEPAD) {
+ INCLUDEPATH += \
+ $$SOURCE_DIR/platform/linux \
+ $$SOURCE_DIR/Modules/gamepad
+}
+
+use?(GLIB) {
+ PKGCONFIG *= glib-2.0 gio-2.0
+}
+
+use?(GSTREAMER) {
+ use?(GSTREAMER010) {
+ PKGCONFIG += gstreamer-0.10 gstreamer-app-0.10 gstreamer-base-0.10 gstreamer-interfaces-0.10 gstreamer-pbutils-0.10 gstreamer-plugins-base-0.10 gstreamer-video-0.10
+ } else {
+ DEFINES += GST_API_VERSION=1.0
+ DEFINES += GST_API_VERSION_1
+ PKGCONFIG += gstreamer-1.0 gstreamer-app-1.0 gstreamer-base-1.0 gstreamer-pbutils-1.0 gstreamer-plugins-base-1.0 gstreamer-video-1.0 gstreamer-audio-1.0
+ }
+}
+
+enable?(VIDEO) {
+ use?(GSTREAMER) {
+ INCLUDEPATH += $$SOURCE_DIR/platform/graphics/gstreamer
+ } else:use?(QT_MULTIMEDIA) {
+ QT *= multimedia
+ }
+}
+
+enable?(WEB_AUDIO) {
+ use?(GSTREAMER) {
+ DEFINES += WTF_USE_WEBAUDIO_GSTREAMER=1
+ INCLUDEPATH += $$SOURCE_DIR/platform/audio/gstreamer
+ use?(GSTREAMER010) {
+ PKGCONFIG += gstreamer-audio-0.10 gstreamer-fft-0.10
+ } else {
+ PKGCONFIG += gstreamer-audio-1.0 gstreamer-fft-1.0
+ }
+ }
+}
+
+use?(3D_GRAPHICS) {
+ win32: {
+ mingw: {
+ # Make sure OpenGL libs are after the webcore lib so MinGW can resolve symbols
+ contains(QT_CONFIG, opengles2) {
+ CONFIG(debug, debug|release):contains(QT_CONFIG, angle) {
+ LIBS += $$QMAKE_LIBS_OPENGL_ES2_DEBUG
+ } else {
+ LIBS += $$QMAKE_LIBS_OPENGL_ES2
+ }
+ } else {
+ LIBS += $$QMAKE_LIBS_OPENGL
+ }
+ }
+ } else {
+ contains(QT_CONFIG, opengles2): CONFIG += egl
+ }
+}
+
+use?(GRAPHICS_SURFACE) {
+ mac: LIBS += -framework IOSurface -framework CoreFoundation
+ linux-*: {
+ LIBS += -lXcomposite -lXrender
+ CONFIG *= x11
+ }
+}
+
+have?(sqlite3) {
+ mac {
+ LIBS += -lsqlite3
+ } else {
+ PKGCONFIG += sqlite3
+ }
+} else {
+ SQLITE3SRCDIR = $$(SQLITE3SRCDIR)
+ isEmpty(SQLITE3SRCDIR): SQLITE3SRCDIR = ../../../qtbase/src/3rdparty/sqlite/
+ exists($${SQLITE3SRCDIR}/sqlite3.c) {
+ INCLUDEPATH += $${SQLITE3SRCDIR}
+ DEFINES += SQLITE_CORE SQLITE_OMIT_LOAD_EXTENSION SQLITE_OMIT_COMPLETE
+ } else {
+ INCLUDEPATH += $${SQLITE3SRCDIR}
+ LIBS += -lsqlite3
+ }
+}
+
+use?(system_leveldb): LIBS += -lleveldb -lmemenv
+
+use?(libjpeg): LIBS += -ljpeg
+use?(libpng): LIBS += -lpng
+use?(webp): LIBS += -lwebp
+
+enable?(opencl) {
+ LIBS += -lOpenCL
+ INCLUDEPATH += $$SOURCE_DIR/platform/graphics/gpu/opencl
+}
+
+mac {
+ LIBS += -framework Carbon -framework AppKit -framework IOKit
+}
+
+win32 {
+ INCLUDEPATH += $$SOURCE_DIR/platform/win
+
+ wince* {
+ # see https://bugs.webkit.org/show_bug.cgi?id=43442
+ DEFINES += HAVE_LOCALTIME_S=0
+
+ LIBS += -lmmtimer
+ LIBS += -lole32
+ }
+ else {
+ LIBS += -lgdi32
+ LIBS += -lole32
+ LIBS += -luser32
+ }
+}
+
+# Remove whole program optimizations due to miscompilations
+win32-msvc2005|win32-msvc2008|win32-msvc2010|win32-msvc2012|win32-msvc2013|wince*:{
+ QMAKE_CFLAGS_LTCG -= -GL
+ QMAKE_CXXFLAGS_LTCG -= -GL
+
+ # Disable incremental linking for windows 32bit OS debug build as WebKit is so big
+ # that linker failes to link incrementally in debug mode.
+ ARCH = $$(PROCESSOR_ARCHITECTURE)
+ WOW64ARCH = $$(PROCESSOR_ARCHITEW6432)
+ equals(ARCH, x86):{
+ isEmpty(WOW64ARCH): QMAKE_LFLAGS_DEBUG += /INCREMENTAL:NO
+ }
+}
+
+mac {
+ LIBS_PRIVATE += -framework Carbon -framework AppKit
+}
+
+# -ffunction-section conflicts with -pg option
+!contains(CONFIG, gprof) {
+ unix:!mac:*-g++*:QMAKE_CXXFLAGS += -ffunction-sections
+}
+unix:!mac:*-g++*:QMAKE_CXXFLAGS += -fdata-sections
+unix:!mac:*-g++*:QMAKE_LFLAGS += -Wl,--gc-sections
+linux*-g++*:QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
+
+enable_fast_mobile_scrolling: DEFINES += ENABLE_FAST_MOBILE_SCROLLING=1
+
+build?(qttestsupport):have?(FONTCONFIG): PKGCONFIG += fontconfig
+
diff -Naur qt-everywhere-opensource-src-5.3.1/qtwebkit/Source/WebKit2/WebKit2.pri qt-everywhere-opensource-src-5.3.1.new/qtwebkit/Source/WebKit2/WebKit2.pri
--- qt-everywhere-opensource-src-5.3.1/qtwebkit/Source/WebKit2/WebKit2.pri 2014-06-19 12:08:26.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtwebkit/Source/WebKit2/WebKit2.pri 2014-08-13 04:15:55.276626229 +0200
@@ -9,6 +9,12 @@
WEBKIT2_GENERATED_SOURCES_DIR = $${ROOT_BUILD_DIR}/Source/WebKit2/$${GENERATED_SOURCES_DESTDIR}
+equals(QT_ARCH, arm)|equals(QT_ARCH, aarch64)|equals(QT_ARCH, i386)|equals(QT_ARCH, i686)|equals(QT_ARCH, x86_64)| equals(QT_ARCH, powerpc64)|equals(QT_ARCH, powerpc) {
+ message("WebKit2 workaround for QtWebkit: do not build with -g, but with -g1")
+ QMAKE_CXXFLAGS_RELEASE -= -g
+ QMAKE_CXXFLAGS_RELEASE += -g1
+}
+
INCLUDEPATH += \
$$SOURCE_DIR \
$$SOURCE_DIR/Platform \
diff -Naur qt-everywhere-opensource-src-5.3.1/qtwebkit/Source/WTF/WTF.pri qt-everywhere-opensource-src-5.3.1.new/qtwebkit/Source/WTF/WTF.pri
--- qt-everywhere-opensource-src-5.3.1/qtwebkit/Source/WTF/WTF.pri 2014-06-19 12:08:13.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtwebkit/Source/WTF/WTF.pri 2014-08-13 04:17:09.728488903 +0200
@@ -8,6 +8,12 @@
# All external modules should include WTF headers by prefixing with "wtf" (#include <wtf/some/thing.h>).
INCLUDEPATH += $$PWD
+equals(QT_ARCH, arm)|equals(QT_ARCH, aarch64)|equals(QT_ARCH, i386)|equals(QT_ARCH, i686)|equals(QT_ARCH, x86_64)| equals(QT_ARCH, powerpc64)|equals(QT_ARCH, powerpc) {
+ message("WTF workaround for QtWebkit: do not build with -g, but with -g1")
+ QMAKE_CXXFLAGS_RELEASE -= -g
+ QMAKE_CXXFLAGS_RELEASE += -g1
+}
+
mac {
# Mac OS does ship libicu but not the associated header files.
# Therefore WebKit provides adequate header files.
diff -Naur qt-everywhere-opensource-src-5.3.1/qtwebkit/Tools/qmake/mkspecs/features/unix/default_post.prf qt-everywhere-opensource-src-5.3.1.new/qtwebkit/Tools/qmake/mkspecs/features/unix/default_post.prf
--- qt-everywhere-opensource-src-5.3.1/qtwebkit/Tools/qmake/mkspecs/features/unix/default_post.prf 2014-06-19 12:08:13.000000000 +0200
+++ qt-everywhere-opensource-src-5.3.1.new/qtwebkit/Tools/qmake/mkspecs/features/unix/default_post.prf 2014-08-13 04:18:05.571385661 +0200
@@ -38,7 +38,7 @@
linux-*g++* {
!production_build {
# Treat warnings as errors on x86/Linux/GCC
- isEqual(QT_ARCH,x86_64)|isEqual(QT_ARCH,i386): QMAKE_CXXFLAGS += -Werror
+ #isEqual(QT_ARCH,x86_64)|isEqual(QT_ARCH,i386): QMAKE_CXXFLAGS += -Werror
}
}
@@ -56,7 +56,7 @@
}
}
-contains(TEMPLATE, app): CONFIG += rpath
+#contains(TEMPLATE, app): CONFIG += rpath
CONFIG(debug, debug|release)|force_debug_info|separate_debug_info {
# Make ld not cache the symbol tables of input files in memory to avoid memory exhaustion during the linking phase.