7366 lines
294 KiB
Diff
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> ¶ms)
|
|
+{
|
|
+ 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 ¶m = 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 ¤tlyLockedAlphaMap;
|
|
+}
|
|
+
|
|
+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.
|