Merge remote-tracking branch 'origin/stable' into dev
Conflicts: src/corelib/tools/qstring.cpp Change-Id: Ifc6cd3a0f1cf14cc0fe6cf30afb0c7f40cfdbc3e
This commit is contained in:
commit
8c6755aeec
@ -49,7 +49,6 @@ static const int ConnectTimeout = 60 * 1000;
|
||||
static const int KeepAliveInterval = 30 * 1000;
|
||||
static const int RateControlTimerDelay = 2000;
|
||||
static const int MinimalHeaderSize = 48;
|
||||
static const int FullHeaderSize = 68;
|
||||
static const char ProtocolId[] = "BitTorrent protocol";
|
||||
static const char ProtocolIdSize = 19;
|
||||
|
||||
|
@ -64,7 +64,6 @@ static const int RateControlTimerDelay = 1000;
|
||||
static const int MinimumTimeBeforeRevisit = 30;
|
||||
static const int MaxUploads = 4;
|
||||
static const int UploadScheduleInterval = 10000;
|
||||
static const int EndGamePieces = 5;
|
||||
|
||||
class TorrentPiece {
|
||||
public:
|
||||
|
@ -44,8 +44,6 @@
|
||||
#include <QtGui/QImage>
|
||||
#include <QtCore/QPropertyAnimation>
|
||||
|
||||
static const qreal FACE_SIZE = 0.4;
|
||||
|
||||
static const qreal speeds[] = { 3.8f, 4.4f, 5.6f };
|
||||
static const qreal amplitudes[] = { 2.0f, 2.5f, 3.0f };
|
||||
|
||||
|
@ -49,10 +49,7 @@
|
||||
static const qreal tee_height = 0.311126;
|
||||
static const qreal cross_width = 0.25;
|
||||
static const qreal bar_thickness = 0.113137;
|
||||
static const qreal inside_diam = 0.20;
|
||||
static const qreal outside_diam = 0.30;
|
||||
static const qreal logo_depth = 0.10;
|
||||
static const int num_divisions = 32;
|
||||
|
||||
//! [0]
|
||||
struct Geometry
|
||||
|
@ -142,7 +142,7 @@ void MainWindow::showAlbumDetails(QModelIndex index)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!trackList->count() == 0)
|
||||
if (trackList->count() != 0)
|
||||
trackList->show();
|
||||
}
|
||||
|
||||
|
@ -44,10 +44,7 @@
|
||||
* demonstrates use of QThread, says hello in another thread and terminates
|
||||
*/
|
||||
|
||||
//! [1]
|
||||
// hellothread/hellothread.cpp
|
||||
void HelloThread::run()
|
||||
{
|
||||
qDebug() << "hello from worker thread " << thread()->currentThreadId();
|
||||
}
|
||||
//! [1]
|
||||
|
@ -42,13 +42,12 @@
|
||||
#define HELLOTHREAD_H
|
||||
|
||||
#include <QThread>
|
||||
//! [1]
|
||||
// hellothread/hellothread.h
|
||||
|
||||
class HelloThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
void run();
|
||||
};
|
||||
//! [1]
|
||||
|
||||
#endif // HELLOTHREAD_H
|
||||
|
@ -41,7 +41,6 @@
|
||||
#include <QtCore>
|
||||
#include "hellothread.h"
|
||||
|
||||
//! [1]
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
@ -51,4 +50,3 @@ int main(int argc, char *argv[])
|
||||
thread.wait(); // do not exit before the thread is completed!
|
||||
return 0;
|
||||
}
|
||||
//! [1]
|
||||
|
@ -84,7 +84,7 @@ protected:
|
||||
virtual QString escapeFilePath(const QString &path) const;
|
||||
ProString escapeFilePath(const ProString &path) const { return MakefileGenerator::escapeFilePath(path); }
|
||||
bool doPrecompiledHeaders() const { return false; }
|
||||
virtual bool doDepends() const { return false; } //never necesary
|
||||
virtual bool doDepends() const { return writingUnixMakefileGenerator && UnixMakefileGenerator::doDepends(); }
|
||||
};
|
||||
|
||||
inline ProjectBuilderMakefileGenerator::~ProjectBuilderMakefileGenerator()
|
||||
|
@ -42,16 +42,6 @@
|
||||
#include <QMutex>
|
||||
#include <QThreadStorage>
|
||||
|
||||
#include "threads.h"
|
||||
|
||||
//! [0]
|
||||
void MyThread::run()
|
||||
//! [0] //! [1]
|
||||
{
|
||||
//! [1] //! [2]
|
||||
}
|
||||
//! [2]
|
||||
|
||||
#define Counter ReentrantCounter
|
||||
|
||||
//! [3]
|
||||
|
@ -1,51 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the documentation of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||
** of its contributors may be used to endorse or promote products derived
|
||||
** from this software without specific prior written permission.
|
||||
**
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QThread>
|
||||
|
||||
//! [0]
|
||||
class MyThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
void run();
|
||||
};
|
||||
//! [0]
|
@ -172,109 +172,16 @@
|
||||
|
||||
\section2 Which Qt Thread Technology Should You Use?
|
||||
|
||||
Sometimes you want to do more than just running a method in the context of
|
||||
another thread. You may want to have an object which lives in another
|
||||
thread that provides a service to the GUI thread. Maybe you want another
|
||||
thread to stay alive forever to poll hardware ports and send a signal to
|
||||
the GUI thread when something noteworthy has happened. Qt provides
|
||||
different solutions for developing threaded applications. The right
|
||||
solution depends on the purpose of the new thread as well as on the
|
||||
thread's lifetime.
|
||||
|
||||
\table
|
||||
\header
|
||||
\li Lifetime of thread
|
||||
\li Development task
|
||||
\li Solution
|
||||
\row
|
||||
\li One call
|
||||
\li Run one method within another thread and quit the thread when the
|
||||
method is finished.
|
||||
\li Qt provides different solutions:
|
||||
\list
|
||||
\li Write a function and run it with QtConcurrent::run()
|
||||
\li Derive a class from QRunnable and run it in the global thread
|
||||
pool with QThreadPool::globalInstance()->start()
|
||||
\li Derive a class from QThread, reimplement the QThread::run()
|
||||
method and use QThread::start() to run it.
|
||||
\endlist
|
||||
|
||||
\row
|
||||
\li One call
|
||||
\li Operations are to be performed on all items of a container.
|
||||
Processing should be performed using all available cores. A common
|
||||
example is to produce thumbnails from a list of images.
|
||||
\li QtConcurrent provides the \l{QtConcurrent::}{map()} function for
|
||||
applying operations on every container element,
|
||||
\l{QtConcurrent::}{filter()} for selecting container elements, and
|
||||
the option of specifying a reduce function for combining the
|
||||
remaining elements.
|
||||
\row
|
||||
\li One call
|
||||
\li A long running operation has to be put in another thread. During the
|
||||
course of processing, status information should be sent to the GUI
|
||||
thread.
|
||||
\li Use QThread, reimplement run and emit signals as needed. Connect the
|
||||
signals to the GUI thread's slots using queued signal/slot
|
||||
connections.
|
||||
|
||||
\row
|
||||
\li Permanent
|
||||
\li Have an object living in another thread and let it perform different
|
||||
tasks upon request.
|
||||
This means communication to and from the worker thread is required.
|
||||
\li Derive a class from QObject and implement the necessary slots and
|
||||
signals, move the object to a thread with a running event loop and
|
||||
communicate with the object over queued signal/slot connections.
|
||||
\row
|
||||
\li Permanent
|
||||
\li Have an object living in another thread, let the object perform
|
||||
repeated tasks such as polling a port and enable communication with
|
||||
the GUI thread.
|
||||
\li Same as above but also use a timer in the worker thread to implement
|
||||
polling. However, the best solution for polling is to avoid it
|
||||
completely. Sometimes using QSocketNotifier is an alternative.
|
||||
\endtable
|
||||
See the \l{Multithreading Technologies in Qt} page for an introduction to the
|
||||
different approaches to multithreading to Qt, and for guidelines on how to
|
||||
choose among them.
|
||||
|
||||
|
||||
\section1 Qt Thread Basics
|
||||
|
||||
QThread is a very convenient cross platform abstraction of native platform
|
||||
threads. Starting a thread is very simple. Let us look at a short piece of
|
||||
code that generates another thread which says hello in that thread and then
|
||||
exits.
|
||||
|
||||
\snippet ../widgets/tutorials/threads/hellothread/hellothread.h 1
|
||||
|
||||
We derive a class from QThread and reimplement the \l{QThread::}{run()}
|
||||
method.
|
||||
|
||||
\snippet ../widgets/tutorials/threads/hellothread/hellothread.cpp 1
|
||||
|
||||
The run method contains the code that will be run in a separate thread. In
|
||||
this example, a message containing the thread ID will be printed.
|
||||
QThread::start() will call the method in another thread.
|
||||
|
||||
\snippet ../widgets/tutorials/threads/hellothread/main.cpp 1
|
||||
|
||||
To start the thread, our thread object needs to be instantiated. The
|
||||
\l{QThread::}{start()} method creates a new thread and calls the
|
||||
reimplemented \l{QThread::}{run()} method in this new thread. Right after
|
||||
\l{QThread::}{start()} is called, two program counters walk through the
|
||||
program code. The main function starts with only the GUI thread running and
|
||||
it should terminate with only the GUI thread running. Exiting the program
|
||||
when another thread is still busy is a programming error, and therefore,
|
||||
wait is called which blocks the calling thread until the
|
||||
\l{QThread::}{run()} method has completed.
|
||||
|
||||
This is the result of running the code:
|
||||
|
||||
\code
|
||||
//bad code
|
||||
hello from GUI thread 3079423696
|
||||
hello from worker thread 3076111216
|
||||
\endcode
|
||||
|
||||
The following sections describe how QObjects interact with threads, how
|
||||
programs can safely access data from multiple threads, and how asynchronous
|
||||
execution produces results without blocking a thread.
|
||||
|
||||
\section2 QObject and Threads
|
||||
|
||||
|
@ -41,7 +41,7 @@
|
||||
|
||||
\ingroup frameworks-technologies
|
||||
|
||||
\nextpage Starting Threads with QThread
|
||||
\nextpage Multithreading Technologies in Qt
|
||||
|
||||
Qt provides thread support in the form of platform-independent
|
||||
threading classes, a thread-safe way of posting events, and
|
||||
@ -59,7 +59,7 @@
|
||||
\list
|
||||
\li \l{Recommended Reading}
|
||||
\li \l{The Threading Classes}
|
||||
\li \l{Starting Threads with QThread}
|
||||
\li \l{Multithreading Technologies in Qt}
|
||||
\li \l{Synchronizing Threads}
|
||||
\li \l{Reentrancy and Thread-Safety}
|
||||
\li \l{Threads and QObjects}
|
||||
@ -112,59 +112,182 @@
|
||||
*/
|
||||
|
||||
/*!
|
||||
\page threads-starting.html
|
||||
\title Starting Threads with QThread
|
||||
\page threads-technologies.html
|
||||
\title Multithreading Technologies in Qt
|
||||
\ingroup qt-basic-concepts
|
||||
\brief An overview and comparison of different ways to use threads in Qt.
|
||||
|
||||
\ingroup frameworks-technologies
|
||||
|
||||
\contentspage Thread Support in Qt
|
||||
\previouspage Thread Support in Qt
|
||||
\nextpage Synchronizing Threads
|
||||
|
||||
A QThread instance represents a thread and provides the means to
|
||||
\l{QThread::start()}{start()} a thread, which will then execute the
|
||||
reimplementation of QThread::run(). The \c run() implementation is for a
|
||||
thread what the \c main() entry point is for the application. All code
|
||||
executed in a call stack that starts in the \c run() function is executed
|
||||
by the new thread, and the thread finishes when the function returns.
|
||||
QThread emits signals to indicate that the thread started or finished
|
||||
executing.
|
||||
Qt offers many classes and functions for working with threads. Below are
|
||||
three different approaches that Qt programmers can use to implement
|
||||
multithreaded applications.
|
||||
|
||||
\section1 Creating a Thread
|
||||
|
||||
To create a thread, subclass QThread and reimplement its
|
||||
\l{QThread::run()}{run()} function. For example:
|
||||
\section1 QThread: Low-Level API with Optional Event Loops
|
||||
|
||||
\snippet threads/threads.h 0
|
||||
\codeline
|
||||
\snippet threads/threads.cpp 0
|
||||
\snippet threads/threads.cpp 1
|
||||
\dots
|
||||
\snippet threads/threads.cpp 2
|
||||
QThread is the foundation of all thread control in Qt. Each QThread
|
||||
instance represents and controls one thread.
|
||||
|
||||
\section1 Starting a Thread
|
||||
QThread can either be instantiated directly or subclassed. Instantiating a
|
||||
QThread provides a parallel event loop, allowing QObject slots to be invoked
|
||||
in a secondary thread. Subclassing a QThread allows the application to initialize
|
||||
the new thread before starting its event loop, or to run parallel code
|
||||
without an event loop.
|
||||
|
||||
Then, create an instance of the thread object and call
|
||||
QThread::start(). Note that you must create the QApplication (or
|
||||
QCoreApplication) object before you can create a QThread.
|
||||
See the \l{QThread}{QThread class reference} and the \l{Threading and
|
||||
Concurrent Programming Examples}{threading examples} for demonstrations on
|
||||
how to use QThread.
|
||||
|
||||
The function will return immediately and the
|
||||
main thread will continue. The code that appears in the
|
||||
\l{QThread::run()}{run()} reimplementation will then be executed
|
||||
in a separate thread.
|
||||
|
||||
Creating threads is explained in more detail in the QThread
|
||||
documentation.
|
||||
\section1 QThreadPool and QRunnable: Reusing Threads
|
||||
|
||||
Note that QCoreApplication::exec() must always be called from the
|
||||
main thread (the thread that executes \c{main()}), not from a
|
||||
QThread. In GUI applications, the main thread is also called the
|
||||
GUI thread because it's the only thread that is allowed to
|
||||
perform GUI-related operations.
|
||||
Creating and destroying threads frequently can be expensive. To reduce this
|
||||
overhead, existing threads can be reused for new tasks. QThreadPool is a
|
||||
collection of reuseable QThreads.
|
||||
|
||||
To run code in one of a QThreadPool's threads, reimplement QRunnable::run()
|
||||
and instantiate the subclassed QRunnable. Use QThreadPool::start() to put
|
||||
the QRunnable in the QThreadPool's run queue. When a thread becomes available,
|
||||
the code within QRunnable::run() will execute in that thread.
|
||||
|
||||
Each Qt application has a global thread pool, which is accessible through
|
||||
QThreadPool::globalInstance(). This global thread pool automatically maintains
|
||||
an optimal number of threads based on the number of cores in the CPU. However,
|
||||
a separate QThreadPool can be created and managed explicitly.
|
||||
|
||||
|
||||
\section1 Qt Concurrent: Using a High-level API
|
||||
|
||||
The \l{Qt Concurrent} module provides high-level functions that deal with some
|
||||
common parallel computation patterns: map, filter, and reduce. Unlike QThread
|
||||
and QRunnable, these functions do not require the use of low-level threading
|
||||
primitives such as mutexes or semaphores. \l {Qt Concurrent} will automatically
|
||||
adjust the number of threads used according to the number of processor cores
|
||||
available, so applications written today will continue to scale when deployed
|
||||
later on a system with more cores.
|
||||
|
||||
This module also provides the QtConcurrent::run() function, which can run
|
||||
any function in a thread managed by the global QThreadPool.
|
||||
|
||||
See the \l{Qt Concurrent} module documentation for details on the individual functions.
|
||||
|
||||
|
||||
\section1 Choosing an Appropriate Approach
|
||||
|
||||
As demonstrated above, Qt provides different solutions for developing threaded
|
||||
applications. The right solution for a given application depends on the purpose
|
||||
of the new thread and the thread's lifetime. Below is a comparison of Qt's
|
||||
threading technologies, followed by recommended solutions for some example use cases.
|
||||
|
||||
\section2 Comparison of Solutions
|
||||
|
||||
\table
|
||||
\header
|
||||
\li Feature/Characteristic
|
||||
\li QThread
|
||||
\li QRunnable
|
||||
\li Qt Concurrent\sup{*}
|
||||
\row
|
||||
\li Supports different thread priorities
|
||||
\li Yes
|
||||
\li
|
||||
\li
|
||||
\row
|
||||
\li Supports an event loop
|
||||
\li Yes
|
||||
\li
|
||||
\li
|
||||
\row
|
||||
\li Supports transferring data to the thread using signals
|
||||
\li Yes (received by a worker QObject)
|
||||
\li
|
||||
\li
|
||||
\row
|
||||
\li Supports controlling the thread using signals
|
||||
\li Yes (received by QThread)
|
||||
\li
|
||||
\li Yes (received by QFutureWatcher)
|
||||
\row
|
||||
\li Supports thread reuse
|
||||
\li
|
||||
\li Yes
|
||||
\li Yes
|
||||
\row
|
||||
\li Task-oriented
|
||||
\li
|
||||
\li Yes
|
||||
\li Yes
|
||||
\row
|
||||
\li High level API
|
||||
\li
|
||||
\li
|
||||
\li Yes
|
||||
\row
|
||||
\li Supports pausing/resuming/canceling
|
||||
\li
|
||||
\li
|
||||
\li Yes
|
||||
\endtable
|
||||
\sup{\e{*Except QtConcurrent::run(), which is like QRunnable}}
|
||||
|
||||
|
||||
\section2 Example Use Cases
|
||||
|
||||
\table
|
||||
\header
|
||||
\li Lifetime of thread
|
||||
\li Operation
|
||||
\li Solution
|
||||
\row
|
||||
\li One call
|
||||
\li Run a linear function within another thread, optionally with progress
|
||||
updates during the run.
|
||||
\li Qt provides different solutions:
|
||||
\list
|
||||
\li Place the function in a reimplementation of QThread::run() and
|
||||
start the QThread. Emit signals to update progress. OR
|
||||
\li Place the function in a reimplementation of QRunnable::run() and
|
||||
add the QRunnable to a QThreadPool. Write to a \l{Synchronizing
|
||||
Threads}{thread-safe variable} to update progress. OR
|
||||
\li Run the function using QtConcurrent::run(). Write to a \l{Synchronizing
|
||||
Threads}{thread-safe variable} to update progress.
|
||||
\endlist
|
||||
\row
|
||||
\li One call
|
||||
\li Perform an operation on all items of a container, using all available
|
||||
cores. For example, producing thumbnails from a list of images.
|
||||
\li Use Qt Concurrent's \l{QtConcurrent::}{filter()} function to select
|
||||
container elements, and the \l{QtConcurrent::}{map()} function to apply
|
||||
an operation to each element. To fold the output into a single result,
|
||||
use \l{QtConcurrent::}{filterReduced()} and \l{QtConcurrent::}{mapReduced()}
|
||||
instead.
|
||||
\row
|
||||
\li Permanent
|
||||
\li Have an object living in another thread that can perform different
|
||||
tasks upon request and/or can receive new data to work with.
|
||||
\li Subclass a QObject to create a worker. Instantiate this worker object
|
||||
and a QThread. Move the worker to the new thread. Send commands or
|
||||
data to the worker object over queued signal-slot connections.
|
||||
\row
|
||||
\li Permanent
|
||||
\li Repeatedly perform an expensive operation in another thread, where the
|
||||
thread does not need to receive any signals or events.
|
||||
\li Write the infinite loop directly within a reimplementation of QThread::run().
|
||||
Start the thread without an event loop. Let the thread emit signals to
|
||||
send data back to the GUI thread.
|
||||
\endtable
|
||||
*/
|
||||
|
||||
/*!
|
||||
\page threads-synchronizing.html
|
||||
\title Synchronizing Threads
|
||||
|
||||
\previouspage Starting Threads with QThread
|
||||
\previouspage Multithreading Technologies in Qt
|
||||
\contentspage Thread Support in Qt
|
||||
\nextpage Reentrancy and Thread-Safety
|
||||
|
||||
|
@ -805,8 +805,7 @@ const QString::Null QString::null = { };
|
||||
|
||||
/*! \typedef QString::const_iterator
|
||||
|
||||
The QString::const_iterator typedef provides an STL-style const
|
||||
iterator for QString.
|
||||
This typedef provides an STL-style const iterator for QString.
|
||||
|
||||
\sa QString::iterator
|
||||
*/
|
||||
@ -834,13 +833,12 @@ const QString::Null QString::null = { };
|
||||
/*!
|
||||
\typedef QString::const_reference
|
||||
|
||||
The QString::const_reference typedef provides an STL-style
|
||||
const reference for a QString element (QChar).
|
||||
This typedef provides an STL-style const reference for a QString element (QChar).
|
||||
*/
|
||||
/*!
|
||||
\typedef QString::reference
|
||||
|
||||
The QString::reference typedef provides an STL-style
|
||||
This typedef provides an STL-style
|
||||
reference for a QString element (QChar).
|
||||
*/
|
||||
|
||||
@ -860,8 +858,7 @@ const QString::Null QString::null = { };
|
||||
/*!
|
||||
\typedef QString::value_type
|
||||
|
||||
The QString::const_reference typedef provides an STL-style
|
||||
value type for QString.
|
||||
This typedef provides an STL-style value type for QString.
|
||||
*/
|
||||
|
||||
/*! \fn QString::iterator QString::begin()
|
||||
|
@ -104,6 +104,10 @@ public: // typedefs
|
||||
{ return QLatin1String(interface) < other; }
|
||||
inline bool operator<(const QByteArray &other) const
|
||||
{ return interface < other; }
|
||||
#if defined(Q_CC_MSVC) && _MSC_VER < 1600
|
||||
friend inline bool operator<(const QString &str, const AdaptorData &obj)
|
||||
{ return str < QLatin1String(obj.interface); }
|
||||
#endif
|
||||
};
|
||||
typedef QVector<AdaptorData> AdaptorMap;
|
||||
|
||||
|
@ -804,7 +804,7 @@ bool QDBusConnection::registerObject(const QString &path, QObject *object, Regis
|
||||
return false;
|
||||
|
||||
if (options & QDBusConnectionPrivate::VirtualObject) {
|
||||
if (options & SubPath && node->activeChildren)
|
||||
if (options & SubPath && !node->children.isEmpty())
|
||||
return false;
|
||||
} else {
|
||||
if ((options & ExportChildObjects && !node->children.isEmpty()))
|
||||
@ -842,7 +842,6 @@ bool QDBusConnection::registerObject(const QString &path, QObject *object, Regis
|
||||
}
|
||||
} else {
|
||||
// add entry
|
||||
++node->activeChildren;
|
||||
node = node->children.insert(it, pathComponents.at(i));
|
||||
}
|
||||
|
||||
|
@ -140,16 +140,24 @@ public:
|
||||
{
|
||||
typedef QVector<ObjectTreeNode> DataList;
|
||||
|
||||
inline ObjectTreeNode() : obj(0), flags(0), activeChildren(0) { }
|
||||
inline ObjectTreeNode() : obj(0), flags(0) { }
|
||||
inline ObjectTreeNode(const QString &n) // intentionally implicit
|
||||
: name(n), obj(0), flags(0), activeChildren(0) { }
|
||||
: name(n), obj(0), flags(0) { }
|
||||
inline ~ObjectTreeNode() { }
|
||||
inline bool operator<(const QString &other) const
|
||||
{ return name < other; }
|
||||
inline bool operator<(const QStringRef &other) const
|
||||
{ return QStringRef(&name) < other; }
|
||||
#if defined(Q_CC_MSVC) && _MSC_VER < 1600
|
||||
inline bool operator<(const ObjectTreeNode &other) const
|
||||
{ return name < other.name; }
|
||||
friend inline bool operator<(const QString &str, const ObjectTreeNode &obj)
|
||||
{ return str < obj.name; }
|
||||
friend inline bool operator<(const QStringRef &str, const ObjectTreeNode &obj)
|
||||
{ return str < QStringRef(&obj.name); }
|
||||
#endif
|
||||
inline bool isActive() const
|
||||
{ return obj || activeChildren; }
|
||||
{ return obj || !children.isEmpty(); }
|
||||
|
||||
QString name;
|
||||
union {
|
||||
@ -157,7 +165,6 @@ public:
|
||||
QDBusVirtualObject *treeNode;
|
||||
};
|
||||
int flags;
|
||||
int activeChildren;
|
||||
|
||||
DataList children;
|
||||
};
|
||||
|
@ -587,46 +587,22 @@ bool QDBusConnectionPrivate::handleMessage(const QDBusMessage &amsg)
|
||||
return false;
|
||||
}
|
||||
|
||||
static void garbageCollectChildren(QDBusConnectionPrivate::ObjectTreeNode &node)
|
||||
{
|
||||
int size = node.children.count();
|
||||
if (node.activeChildren == 0) {
|
||||
// easy case
|
||||
node.children.clear();
|
||||
} else if (size > node.activeChildren * 3 || (size > 20 && size * 2 > node.activeChildren * 3)) {
|
||||
// rewrite the vector, keeping only the active children
|
||||
// if the vector is large (> 20 items) and has one third of inactives
|
||||
// or if the vector is small and has two thirds of inactives.
|
||||
QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator end = node.children.end();
|
||||
QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it = node.children.begin();
|
||||
QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator tgt = it;
|
||||
for ( ; it != end; ++it) {
|
||||
if (it->isActive())
|
||||
*tgt++ = qMove(*it);
|
||||
}
|
||||
++tgt;
|
||||
node.children.erase(tgt, end);
|
||||
}
|
||||
}
|
||||
|
||||
static void huntAndDestroy(QObject *needle, QDBusConnectionPrivate::ObjectTreeNode &haystack)
|
||||
{
|
||||
QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it = haystack.children.begin();
|
||||
QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator end = haystack.children.end();
|
||||
for ( ; it != end; ++it) {
|
||||
if (!it->isActive())
|
||||
continue;
|
||||
|
||||
while (it != haystack.children.end()) {
|
||||
huntAndDestroy(needle, *it);
|
||||
if (!it->isActive())
|
||||
--haystack.activeChildren;
|
||||
it = haystack.children.erase(it);
|
||||
else
|
||||
it++;
|
||||
}
|
||||
|
||||
if (needle == haystack.obj) {
|
||||
haystack.obj = 0;
|
||||
haystack.flags = 0;
|
||||
}
|
||||
|
||||
garbageCollectChildren(haystack);
|
||||
}
|
||||
|
||||
static void huntAndUnregister(const QStringList &pathComponents, int i, QDBusConnection::UnregisterMode mode,
|
||||
@ -639,7 +615,6 @@ static void huntAndUnregister(const QStringList &pathComponents, int i, QDBusCon
|
||||
|
||||
if (mode == QDBusConnection::UnregisterTree) {
|
||||
// clear the sub-tree as well
|
||||
node->activeChildren = 0;
|
||||
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
|
||||
}
|
||||
@ -648,14 +623,12 @@ static void huntAndUnregister(const QStringList &pathComponents, int i, QDBusCon
|
||||
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) || !it->isActive())
|
||||
if (it == end || it->name != pathComponents.at(i))
|
||||
return; // node not found
|
||||
|
||||
huntAndUnregister(pathComponents, i + 1, mode, it);
|
||||
if (!it->isActive())
|
||||
--node->activeChildren;
|
||||
|
||||
garbageCollectChildren(*node);
|
||||
node->children.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,6 @@ QT_END_NAMESPACE
|
||||
Qt::KeyboardModifiers currentWheelModifiers;
|
||||
bool m_subscribesForGlobalFrameNotifications;
|
||||
QCocoaGLContext *m_glContext;
|
||||
bool m_drawRectHasBeenCalled;
|
||||
bool m_shouldSetGLContextinDrawRect;
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,6 @@ static QTouchDevice *touchDevice = 0;
|
||||
m_sendKeyEvent = false;
|
||||
m_subscribesForGlobalFrameNotifications = false;
|
||||
m_glContext = 0;
|
||||
m_drawRectHasBeenCalled = false;
|
||||
m_shouldSetGLContextinDrawRect = false;
|
||||
currentCustomDragTypes = 0;
|
||||
m_sendUpAsRightButton = false;
|
||||
@ -154,9 +153,9 @@ static QTouchDevice *touchDevice = 0;
|
||||
- (void) setQCocoaGLContext:(QCocoaGLContext *)context
|
||||
{
|
||||
m_glContext = context;
|
||||
if (m_drawRectHasBeenCalled) {
|
||||
[m_glContext->nsOpenGLContext() setView:self];
|
||||
} else {
|
||||
[m_glContext->nsOpenGLContext() setView:self];
|
||||
if (![m_glContext->nsOpenGLContext() view]) {
|
||||
//was unable to set view
|
||||
m_shouldSetGLContextinDrawRect = true;
|
||||
}
|
||||
|
||||
@ -393,8 +392,6 @@ static QTouchDevice *touchDevice = 0;
|
||||
m_shouldSetGLContextinDrawRect = false;
|
||||
}
|
||||
|
||||
m_drawRectHasBeenCalled = true;
|
||||
|
||||
if (!m_backingStore)
|
||||
return;
|
||||
|
||||
|
@ -2467,7 +2467,7 @@ void tst_QSettings::testEscapes()
|
||||
QString s = QSettingsPrivate::variantToString(v); \
|
||||
QCOMPARE(s, escStr); \
|
||||
QCOMPARE(QVariant(QSettingsPrivate::stringToVariant(escStr)), v); \
|
||||
QVERIFY(val == v.func()); \
|
||||
QVERIFY((val) == v.func()); \
|
||||
}
|
||||
|
||||
#define testBadEscape(escStr, vStr) \
|
||||
|
@ -56,10 +56,11 @@
|
||||
#define STRINGPREP_BIDI_LEADTRAIL_NOT_RAL 5
|
||||
|
||||
struct ushortarray {
|
||||
ushortarray(unsigned short *array = 0)
|
||||
ushortarray() {}
|
||||
template <size_t N>
|
||||
ushortarray(unsigned short (&array)[N])
|
||||
{
|
||||
if (array)
|
||||
memcpy(points, array, sizeof(points));
|
||||
memcpy(points, array, N*sizeof(unsigned short));
|
||||
}
|
||||
|
||||
unsigned short points[100];
|
||||
|
Loading…
Reference in New Issue
Block a user