Merge "Merge branch 'stable' into dev" into refs/staging/dev

This commit is contained in:
Sergio Ahumada 2013-09-21 17:34:59 +02:00 committed by The Qt Project
commit 4cebef621b
31 changed files with 429 additions and 169 deletions

View File

@ -32,7 +32,7 @@
# manifestmeta.global.names = *
# manifestmeta.global.tags = qt5
manifestmeta.filters = highlighted webkit1 webkit2 android
manifestmeta.filters = highlighted webkit1 webkit2 android thumbnail
manifestmeta.highlighted.names = "QtQuick/Qt Quick Demo - Same Game" \
"QtQuick/Qt Quick Demo - Photo Surface" \
@ -168,3 +168,28 @@ manifestmeta.android.names = "QtQuick/Qt Quick Demo - Maroon*" \
"QtWidgets/Address Book Example"
manifestmeta.android.tags = android
# add a generic thumbnail image to examples that do not have any images in their documentation
manifestmeta.thumbnail.attributes = "imageUrl:qthelp\://org.qt-project.qtdoc.$QT_VERSION_TAG/qtdoc/images/qt-codesample.png"
manifestmeta.thumbnail.names = "QtConcurrent/Map Example" \
"QtConcurrent/QtConcurrent Word Count Example" \
"QtConcurrent/Run Function Example" \
"QtGui/Raster Window Example" \
"QtNetwork/Network Download*" \
"QtWidgets/Dynamic Layouts Example" \
"QtWidgets/Event Transitions Example" \
"QtWidgets/Plug & Paint Basic Tools Example" \
"QtWidgets/Plug & Paint Extra Filters Example" \
"QtWidgets/Two-way Button Example" \
"QtWidgets/Validators Example" \
"ActiveQt/*" \
"QtDbus/*" \
"QtHelp/*" \
"QtMultimedia/AudioEngine Example" \
"QtMultimedia/Declarative Radio Example" \
"QtMultimedia/Media Player Example" \
"QtQml/Extending QML*" \
"QtQuick/Qt Quick Examples - Accessibility" \
"QtSensors/Qt Sensors - SensorGesture QML Type example" \
"QtWinExtras/Icon Extractor"

View File

@ -26,6 +26,7 @@ Cpp.ignoretokens += \
Q_CORE_EXPORT_INLINE \
Q_DBUS_EXPORT \
Q_DECL_CONSTEXPR \
Q_DECL_DEPRECATED \
Q_DECL_NOEXCEPT \
Q_DECL_NOTHROW \
Q_DECLARATIVE_EXPORT \

View File

@ -39,7 +39,7 @@
****************************************************************************/
#ifndef GRAPHICSVIEW_H
#define GRAPHICSVIEW
#define GRAPHICSVIEW_H
#include <QtWidgets/QGraphicsView>

View File

@ -117,8 +117,8 @@
Random access iterators can be faster in cases where Qt Concurrent is iterating
over a large number of lightweight items, since they allow skipping to any point
in the container. In addition, using random access iterators allows Qt Concurrent
to provide progress information trough QFuture::progressValue() and QFutureWatcher::
progressValueChanged().
to provide progress information trough QFuture::progressValue() and
QFutureWatcher::progressValueChanged().
The non in-place modifying functions such as mapped() and filtered() makes a
copy of the container when called. If you are using STL containers this copy operation

View File

@ -47,7 +47,7 @@
\brief The <QtConcurrentFilter> header provides concurrent Filter and
Filter-Reduce.
These functions are a part of the \l {Concurrent Programming}{Qt Concurrent} framework.
These functions are a part of the \l {Qt Concurrent} framework.
The QtConcurrent::filter(), QtConcurrent::filtered() and
QtConcurrent::filteredReduced() functions filter items in a sequence such

View File

@ -47,8 +47,8 @@
possible to write multi-threaded programs without using low-level
threading primitives.
See the \l {Concurrent Programming}{Qt Concurrent} chapter in
the \l{threads.html}{threading} documentation.
See the \l {Qt Concurrent} module documentation for an overview of available
functions, or see below for detailed information on each function.
\inheaderfile QtConcurrent
\ingroup thread
@ -74,7 +74,7 @@
\brief The <QtConcurrentMap> header provides concurrent Map and MapReduce.
These functions are a part of the \l {Concurrent Programming}{Qt Concurrent} framework.
These functions are a part of the \l {Qt Concurrent} framework.
The QtConcurrent::map(), QtConcurrent::mapped() and
QtConcurrent::mappedReduced() functions run computations in parallel on

View File

@ -48,7 +48,7 @@
\ingroup thread
This function is a part of the \l {Concurrent Programming}{Qt Concurrent} framework.
This function is a part of the \l {Qt Concurrent} framework.
The QtConcurrent::run() function runs a function in a separate thread.
The return value of the function is made available through the QFuture API.

View File

@ -63,7 +63,6 @@
\li \l{Synchronizing Threads}
\li \l{Reentrancy and Thread-Safety}
\li \l{Threads and QObjects}
\li \l{Concurrent Programming}
\li \l{Thread-Support in Qt Modules}
\endlist
@ -449,7 +448,7 @@
\previouspage Reentrancy and Thread Safety
\contentspage Thread Support in Qt
\nextpage Concurrent Programming
\nextpage Thread-Support in Qt Modules
QThread inherits QObject. It emits signals to indicate that the
thread started or finished executing, and provides a few slots as
@ -645,114 +644,11 @@
a TCP server asynchronously.
*/
/*!
\page threads-qtconcurrent.html
\title Concurrent Programming
\previouspage Threads and QObjects
\contentspage Thread Support in Qt
\nextpage Thread-Support in Qt Modules
\target qtconcurrent intro
The QtConcurrent namespace provides high-level APIs that make it
possible to write multi-threaded programs without using low-level
threading primitives such as mutexes, read-write locks, wait
conditions, or semaphores. Programs written with QtConcurrent
automatically adjust the number of threads used according to the
number of processor cores available. This means that applications
written today will continue to scale when deployed on multi-core
systems in the future.
QtConcurrent includes functional programming style APIs for
parallel list processing, including a MapReduce and FilterReduce
implementation for shared-memory (non-distributed) systems, and
classes for managing asynchronous computations in GUI
applications:
\list
\li QtConcurrent::map() applies a function to every item in a container,
modifying the items in-place.
\li QtConcurrent::mapped() is like map(), except that it returns a new
container with the modifications.
\li QtConcurrent::mappedReduced() is like mapped(), except that the
modified results are reduced or folded into a single result.
\li QtConcurrent::filter() removes all items from a container based on the
result of a filter function.
\li QtConcurrent::filtered() is like filter(), except that it returns a new
container with the filtered results.
\li QtConcurrent::filteredReduced() is like filtered(), except that the
filtered results are reduced or folded into a single result.
\li QtConcurrent::run() runs a function in another thread.
\li QFuture represents the result of an asynchronous computation.
\li QFutureIterator allows iterating through results available via QFuture.
\li QFutureWatcher allows monitoring a QFuture using signals-and-slots.
\li QFutureSynchronizer is a convenience class that automatically
synchronizes several QFutures.
\endlist
Qt Concurrent supports several STL-compatible container and iterator types,
but works best with Qt containers that have random-access iterators, such as
QList or QVector. The map and filter functions accept both containers and begin/end iterators.
STL Iterator support overview:
\table
\header
\li Iterator Type
\li Example classes
\li Support status
\row
\li Input Iterator
\li
\li Not Supported
\row
\li Output Iterator
\li
\li Not Supported
\row
\li Forward Iterator
\li std::slist
\li Supported
\row
\li Bidirectional Iterator
\li QLinkedList, std::list
\li Supported
\row
\li Random Access Iterator
\li QList, QVector, std::vector
\li Supported and Recommended
\endtable
Random access iterators can be faster in cases where Qt Concurrent is iterating
over a large number of lightweight items, since they allow skipping to any point
in the container. In addition, using random access iterators allows Qt Concurrent
to provide progress information trough QFuture::progressValue() and QFutureWatcher::
progressValueChanged().
The non in-place modifying functions such as mapped() and filtered() makes a
copy of the container when called. If you are using STL containers this copy operation
might take some time, in this case we recommend specifying the begin and end iterators
for the container instead.
*/
/*!
\page threads-modules.html
\title Thread-Support in Qt Modules
\previouspage Concurrent Programming
\previouspage Threads and QObjects
\contentspage Thread Support in Qt
\section1 Threads and the SQL Module

View File

@ -365,11 +365,11 @@ void QInotifyFileSystemWatcherEngine::readFromInotify()
// qDebug() << "inotify event, wd" << event.wd << "mask" << hex << event.mask;
int id = event.wd;
QString path = idToPath.value(id);
QString path = getPathFromID(id);
if (path.isEmpty()) {
// perhaps a directory?
id = -id;
path = idToPath.value(id);
path = getPathFromID(id);
if (path.isEmpty())
continue;
}
@ -378,8 +378,9 @@ void QInotifyFileSystemWatcherEngine::readFromInotify()
if ((event.mask & (IN_DELETE_SELF | IN_MOVE_SELF | IN_UNMOUNT)) != 0) {
pathToID.remove(path);
idToPath.remove(id);
inotify_rm_watch(inotifyFd, event.wd);
idToPath.remove(id, getPathFromID(id));
if (!idToPath.contains(id))
inotify_rm_watch(inotifyFd, event.wd);
if (id < 0)
emit directoryChanged(path, true);
@ -394,6 +395,18 @@ void QInotifyFileSystemWatcherEngine::readFromInotify()
}
}
QString QInotifyFileSystemWatcherEngine::getPathFromID(int id) const
{
QHash<int, QString>::const_iterator i = idToPath.find(id);
while (i != idToPath.constEnd() && i.key() == id) {
if ((i + 1) == idToPath.constEnd() || (i + 1).key() != id) {
return i.value();
}
++i;
}
return QString();
}
QT_END_NAMESPACE
#endif // QT_NO_FILESYSTEMWATCHER

View File

@ -78,11 +78,14 @@ public:
private Q_SLOTS:
void readFromInotify();
private:
QString getPathFromID(int id) const;
private:
QInotifyFileSystemWatcherEngine(int fd, QObject *parent);
int inotifyFd;
QHash<QString, int> pathToID;
QHash<int, QString> idToPath;
QMultiHash<int, QString> idToPath;
QSocketNotifier notifier;
};

View File

@ -121,17 +121,33 @@ static const int errorBufferMax = 512;
static int qt_qprocess_deadChild_pipe[2];
static struct sigaction qt_sa_old_sigchld_handler;
static void qt_sa_sigchld_handler(int signum)
static void qt_sa_sigchld_sigaction(int signum, siginfo_t *info, void *context)
{
// *Never* use the info or contect variables in this function
// (except for passing them to the next signal in the chain).
// We cannot be sure if another library or if the application
// installed a signal handler for SIGCHLD without SA_SIGINFO
// and fails to pass the arguments to us. If they do that,
// these arguments contain garbage and we'd most likely crash.
qt_safe_write(qt_qprocess_deadChild_pipe[1], "", 1);
#if defined (QPROCESS_DEBUG)
fprintf(stderr, "*** SIGCHLD\n");
#endif
// load it as volatile
void (*oldAction)(int) = ((volatile struct sigaction *)&qt_sa_old_sigchld_handler)->sa_handler;
if (oldAction && oldAction != SIG_IGN)
oldAction(signum);
// load as volatile
volatile struct sigaction *vsa = &qt_sa_old_sigchld_handler;
if (qt_sa_old_sigchld_handler.sa_flags & SA_SIGINFO) {
void (*oldAction)(int, siginfo_t *, void *) = vsa->sa_sigaction;
oldAction(signum, info, context);
} else {
void (*oldAction)(int) = vsa->sa_handler;
if (oldAction && oldAction != SIG_IGN)
oldAction(signum);
}
}
static inline void add_fd(int &nfds, int fd, fd_set *fdset)
@ -197,10 +213,16 @@ QProcessManager::QProcessManager()
// set up the SIGCHLD handler, which writes a single byte to the dead
// child pipe every time a child dies.
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_handler = qt_sa_sigchld_handler;
action.sa_flags = SA_NOCLDSTOP;
// use the old handler as template, i.e., preserve the signal mask
// otherwise the original signal handler might be interrupted although it
// was marked to never be interrupted
::sigaction(SIGCHLD, NULL, &action);
action.sa_sigaction = qt_sa_sigchld_sigaction;
// set the SA_SIGINFO flag such that we can use the three argument handler
// function
action.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
::sigaction(SIGCHLD, &action, &qt_sa_old_sigchld_handler);
processManagerInstance = this;
@ -225,7 +247,7 @@ QProcessManager::~QProcessManager()
struct sigaction currentAction;
::sigaction(SIGCHLD, 0, &currentAction);
if (currentAction.sa_handler == qt_sa_sigchld_handler) {
if (currentAction.sa_sigaction == qt_sa_sigchld_sigaction) {
::sigaction(SIGCHLD, &qt_sa_old_sigchld_handler, 0);
}

View File

@ -47,8 +47,7 @@
\ingroup thread
To start a computation, use one of the APIs in the
\l {Concurrent Programming}{Qt Concurrent} framework.
To start a computation, use one of the APIs in the \l {Qt Concurrent} framework.
QFuture allows threads to be synchronized against one or more results
which will be ready at a later point in time. The result can be of any type
@ -93,7 +92,7 @@
To interact with running tasks using signals and slots, use QFutureWatcher.
\sa QFutureWatcher, {Concurrent Programming}{Qt Concurrent}
\sa QFutureWatcher, {Qt Concurrent}
*/
/*! \fn QFuture::QFuture()

View File

@ -66,7 +66,7 @@
You can query the status of the cancel-on-wait feature using the
cancelOnWait() function.
\sa QFuture, QFutureWatcher, {Concurrent Programming}{Qt Concurrent}
\sa QFuture, QFutureWatcher, {Qt Concurrent}
*/
/*!

View File

@ -98,7 +98,7 @@ QT_BEGIN_NAMESPACE
QFutureWatcher<void> as well. This is useful if only status or progress
information is needed; not the actual result data.
\sa QFuture, {Concurrent Programming}{Qt Concurrent}
\sa QFuture, {Qt Concurrent}
*/
/*! \fn QFutureWatcher::QFutureWatcher(QObject *parent)

View File

@ -1,5 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
@ -280,6 +281,15 @@ void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scal
image.setColorCount(2);
image.setColor(1, qRgb(0,0,0));
image.setColor(0, qRgb(255,255,255));
if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_color_p) {
const int g = trans_color_p->gray;
// the image has white in the first position of the color table,
// black in the second. g is 0 for black, 1 for white.
if (g == 0)
image.setColor(1, qRgba(0, 0, 0, 0));
else if (g == 1)
image.setColor(0, qRgba(255, 255, 255, 0));
}
} else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
png_set_expand(png_ptr);
png_set_strip_16(png_ptr);
@ -406,14 +416,14 @@ static void read_image_scaled(QImage *outImage, png_structp png_ptr, png_infop i
QPngHandlerPrivate::AllocatedMemoryPointers &amp, QSize scaledSize)
{
png_uint_32 width;
png_uint_32 height;
png_int_32 offset_x;
png_int_32 offset_y;
png_uint_32 width = 0;
png_uint_32 height = 0;
png_int_32 offset_x = 0;
png_int_32 offset_y = 0;
int bit_depth;
int color_type;
int unit_type;
int bit_depth = 0;
int color_type = 0;
int unit_type = PNG_OFFSET_PIXEL;
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, &unit_type);
uchar *data = outImage->bits();

View File

@ -2293,13 +2293,30 @@ bool qt_scaleForTransform(const QTransform &transform, qreal *scale)
return qFuzzyCompare(xScale, yScale);
}
const qreal xScale = transform.m11() * transform.m11()
// rotate then scale: compare columns
const qreal xScale1 = transform.m11() * transform.m11()
+ transform.m21() * transform.m21();
const qreal yScale = transform.m12() * transform.m12()
const qreal yScale1 = transform.m12() * transform.m12()
+ transform.m22() * transform.m22();
if (scale)
*scale = qSqrt(qMax(xScale, yScale));
return type == QTransform::TxRotate && qFuzzyCompare(xScale, yScale);
// scale then rotate: compare rows
const qreal xScale2 = transform.m11() * transform.m11()
+ transform.m12() * transform.m12();
const qreal yScale2 = transform.m21() * transform.m21()
+ transform.m22() * transform.m22();
// decide the order of rotate and scale operations
if (qAbs(xScale1 - yScale1) > qAbs(xScale2 - yScale2)) {
if (scale)
*scale = qSqrt(qMax(xScale1, yScale1));
return type == QTransform::TxRotate && qFuzzyCompare(xScale1, yScale1);
} else {
if (scale)
*scale = qSqrt(qMax(xScale2, yScale2));
return type == QTransform::TxRotate && qFuzzyCompare(xScale2, yScale2);
}
}
QT_END_NAMESPACE

View File

@ -509,7 +509,7 @@ void QHttpNetworkConnectionPrivate::createAuthorization(QAbstractSocket *socket,
// Send "Authorization" header, but not if it's NTLM and the socket is already authenticated.
if (channels[i].authMethod != QAuthenticatorPrivate::None) {
if (!(channels[i].authMethod == QAuthenticatorPrivate::Ntlm && channels[i].lastStatus != 401)) {
if ((channels[i].authMethod != QAuthenticatorPrivate::Ntlm && request.headerField("Authorization").isEmpty()) || channels[i].lastStatus == 401) {
QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(channels[i].authenticator);
if (priv && priv->method != QAuthenticatorPrivate::None) {
QByteArray response = priv->calculateResponse(request.d->methodName(), request.d->uri(false));

View File

@ -236,8 +236,8 @@ bool QHttpNetworkConnectionChannel::sendRequest()
QAuthenticator &auth = authenticator;
if (url.userName() != auth.user()
|| (!url.password().isEmpty() && url.password() != auth.password())) {
auth.setUser(url.userName());
auth.setPassword(url.password());
auth.setUser(url.userName(QUrl::FullyDecoded));
auth.setPassword(url.password(QUrl::FullyDecoded));
connection->d_func()->copyCredentials(connection->d_func()->indexOf(socket), &auth, false);
}
// clear the userinfo, since we use the same request for resending

View File

@ -1358,8 +1358,8 @@ void QNetworkAccessManagerPrivate::authenticationRequired(QAuthenticator *authen
// if credentials are included in the url, then use them
if (!url.userName().isEmpty()
&& !url.password().isEmpty()) {
authenticator->setUser(url.userName());
authenticator->setPassword(url.password());
authenticator->setUser(url.userName(QUrl::FullyDecoded));
authenticator->setPassword(url.password(QUrl::FullyDecoded));
*urlForLastAuthentication = url;
authenticationManager->cacheCredentials(url, authenticator);
return;

View File

@ -115,7 +115,7 @@ QAccessibleInterface *AccessibleFactory::create(const QString &classname, QObjec
QToolButton *tb = qobject_cast<QToolButton*>(widget);
if (!tb->menu())
role = tb->isCheckable() ? QAccessible::CheckBox : QAccessible::PushButton;
else if (!tb->popupMode() != QToolButton::DelayedPopup)
else if (tb->popupMode() == QToolButton::DelayedPopup)
role = QAccessible::ButtonDropDown;
else
#endif

View File

@ -125,7 +125,7 @@ public:
QList<int> possibleKeys(const QKeyEvent *event) const;
void updateScreens();
QCocoaScreen *screenAtIndex(int index) const { return mScreens.at(index); }
QCocoaScreen *screenAtIndex(int index);
private:

View File

@ -343,6 +343,14 @@ void QCocoaIntegration::updateScreens()
screen->setVirtualSiblings(siblings);
}
QCocoaScreen *QCocoaIntegration::screenAtIndex(int index)
{
if (index >= mScreens.count())
updateScreens();
return mScreens.at(index);
}
bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
switch (cap) {

View File

@ -157,12 +157,122 @@ private:
QByteArray format_atoms;
};
class INCRTransaction;
typedef QMap<xcb_window_t,INCRTransaction*> TransactionMap;
static TransactionMap *transactions = 0;
//#define INCR_DEBUG
class INCRTransaction : public QObject
{
Q_OBJECT
public:
INCRTransaction(QXcbConnection *c, xcb_window_t w, xcb_atom_t p,
QByteArray d, uint i, xcb_atom_t t, int f, int to) :
conn(c), win(w), property(p), data(d), increment(i),
target(t), format(f), timeout(to), offset(0)
{
const quint32 values[] = { XCB_EVENT_MASK_PROPERTY_CHANGE };
xcb_change_window_attributes(conn->xcb_connection(), win,
XCB_CW_EVENT_MASK, values);
if (!transactions) {
#ifdef INCR_DEBUG
qDebug("INCRTransaction: creating the TransactionMap");
#endif
transactions = new TransactionMap;
conn->clipboard()->setProcessIncr(true);
}
transactions->insert(win, this);
abort_timer = startTimer(timeout);
}
~INCRTransaction()
{
if (abort_timer)
killTimer(abort_timer);
abort_timer = 0;
transactions->remove(win);
if (transactions->isEmpty()) {
#ifdef INCR_DEBUG
qDebug("INCRTransaction: no more INCR transactions left in the TransactionMap");
#endif
delete transactions;
transactions = 0;
conn->clipboard()->setProcessIncr(false);
}
}
void updateIncrProperty(xcb_property_notify_event_t *event, bool &accepted)
{
xcb_connection_t *c = conn->xcb_connection();
if (event->atom == property && event->state == XCB_PROPERTY_DELETE) {
accepted = true;
// restart the timer
if (abort_timer)
killTimer(abort_timer);
abort_timer = startTimer(timeout);
unsigned int bytes_left = data.size() - offset;
if (bytes_left > 0) {
unsigned int bytes_to_send = qMin(increment, bytes_left);
#ifdef INCR_DEBUG
qDebug("INCRTransaction: sending %d bytes, %d remaining (INCR transaction %p)",
bytes_to_send, bytes_left - bytes_to_send, this);
#endif
int dataSize = bytes_to_send / (format / 8);
xcb_change_property(c, XCB_PROP_MODE_REPLACE, win, property,
target, format, dataSize, data.constData() + offset);
offset += bytes_to_send;
} else {
#ifdef INCR_DEBUG
qDebug("INCRTransaction: INCR transaction %p completed", this);
#endif
xcb_change_property(c, XCB_PROP_MODE_REPLACE, win, property,
target, format, 0, (const void *)0);
const quint32 values[] = { XCB_EVENT_MASK_NO_EVENT };
xcb_change_window_attributes(conn->xcb_connection(), win,
XCB_CW_EVENT_MASK, values);
// self destroy
delete this;
}
}
}
protected:
void timerEvent(QTimerEvent *ev)
{
if (ev->timerId() == abort_timer) {
// this can happen when the X client we are sending data
// to decides to exit (normally or abnormally)
#ifdef INCR_DEBUG
qDebug("INCRTransaction: Timed out while sending data to %p", this);
#endif
delete this;
}
}
private:
QXcbConnection *conn;
xcb_window_t win;
xcb_atom_t property;
QByteArray data;
uint increment;
xcb_atom_t target;
int format;
int timeout;
uint offset;
int abort_timer;
};
const int QXcbClipboard::clipboard_timeout = 5000;
QXcbClipboard::QXcbClipboard(QXcbConnection *c)
: QXcbObject(c), QPlatformClipboard()
, m_requestor(XCB_NONE)
, m_owner(XCB_NONE)
, m_incr_active(false)
, m_clipboard_closing(false)
, m_incr_receive_time(0)
{
Q_ASSERT(QClipboard::Clipboard == 0);
Q_ASSERT(QClipboard::Selection == 1);
@ -200,6 +310,7 @@ QXcbClipboard::QXcbClipboard(QXcbConnection *c)
QXcbClipboard::~QXcbClipboard()
{
m_clipboard_closing = true;
// Transfer the clipboard content to the clipboard manager if we own a selection
if (m_timestamp[QClipboard::Clipboard] != XCB_CURRENT_TIME ||
m_timestamp[QClipboard::Selection] != XCB_CURRENT_TIME) {
@ -224,6 +335,17 @@ QXcbClipboard::~QXcbClipboard()
}
}
void QXcbClipboard::incrTransactionPeeker(xcb_generic_event_t *ge, bool &accepted)
{
uint response_type = ge->response_type & ~0x80;
if (response_type == XCB_PROPERTY_NOTIFY) {
xcb_property_notify_event_t *event = (xcb_property_notify_event_t *)ge;
TransactionMap::Iterator it = transactions->find(event->window);
if (it != transactions->end()) {
(*it)->updateIncrProperty(event, accepted);
}
}
}
xcb_window_t QXcbClipboard::getSelectionOwner(xcb_atom_t atom) const
{
@ -415,16 +537,17 @@ xcb_atom_t QXcbClipboard::sendSelection(QMimeData *d, xcb_atom_t target, xcb_win
// Motif clients (since Motif doesn't support INCR)
static xcb_atom_t motif_clip_temporary = atom(QXcbAtom::CLIP_TEMPORARY);
bool allow_incr = property != motif_clip_temporary;
// This 'bool' can be removed once there is a proper fix for QTBUG-32853
if (m_clipboard_closing)
allow_incr = false;
// X_ChangeProperty protocol request is 24 bytes
const int increment = (xcb_get_maximum_request_length(xcb_connection()) * 4) - 24;
if (data.size() > increment && allow_incr) {
long bytes = data.size();
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, property,
atom(QXcbAtom::INCR), 32, 1, (const void *)&bytes);
// (void)new QClipboardINCRTransaction(window, property, atomFormat, dataFormat, data, increment);
qWarning("QXcbClipboard: INCR is unimplemented");
new INCRTransaction(connection(), window, property, data, increment,
atomFormat, dataFormat, clipboard_timeout);
return property;
}
@ -611,7 +734,7 @@ static inline int maxSelectionIncr(xcb_connection_t *c)
return (l > 65536 ? 65536*4 : l*4) - 100;
}
bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property, bool deleteProperty, QByteArray *buffer, int *size, xcb_atom_t *type, int *format) const
bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property, bool deleteProperty, QByteArray *buffer, int *size, xcb_atom_t *type, int *format)
{
int maxsize = maxSelectionIncr(xcb_connection());
ulong bytes_left; // bytes_after
@ -687,7 +810,8 @@ bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property,
// correct size, not 0-term.
if (size)
*size = buffer_offset;
if (*type == atom(QXcbAtom::INCR))
m_incr_receive_time = connection()->getTimestamp();
if (deleteProperty)
xcb_delete_property(xcb_connection(), win, property);
@ -791,6 +915,7 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb
bool alloc_error = false;
int length;
int offset = 0;
xcb_timestamp_t prev_time = m_incr_receive_time;
if (nbytes > 0) {
// Reserve buffer + zero-terminator (for text data)
@ -805,10 +930,14 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb
xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_PROPERTY_NOTIFY, clipboard_timeout);
if (!ge)
break;
xcb_property_notify_event_t *event = (xcb_property_notify_event_t *)ge;
if (event->atom != property || event->state != XCB_PROPERTY_NEW_VALUE)
if (event->atom != property
|| event->state != XCB_PROPERTY_NEW_VALUE
|| event->time < prev_time)
continue;
prev_time = event->time;
if (clipboardReadProperty(win, property, true, &tmp_buf, &length, 0, 0)) {
if (length == 0) { // no more data, we're done
if (nullterm) {

View File

@ -78,11 +78,15 @@ public:
void handleSelectionClearRequest(xcb_selection_clear_event_t *event);
void handleXFixesSelectionRequest(xcb_xfixes_selection_notify_event_t *event);
bool clipboardReadProperty(xcb_window_t win, xcb_atom_t property, bool deleteProperty, QByteArray *buffer, int *size, xcb_atom_t *type, int *format) const;
bool clipboardReadProperty(xcb_window_t win, xcb_atom_t property, bool deleteProperty, QByteArray *buffer, int *size, xcb_atom_t *type, int *format);
QByteArray clipboardReadIncrementalProperty(xcb_window_t win, xcb_atom_t property, int nbytes, bool nullterm);
QByteArray getDataInFormat(xcb_atom_t modeAtom, xcb_atom_t fmtatom);
void setProcessIncr(bool process) { m_incr_active = process; }
bool processIncr() { return m_incr_active; }
void incrTransactionPeeker(xcb_generic_event_t *ge, bool &accepted);
xcb_window_t getSelectionOwner(xcb_atom_t atom) const;
QByteArray getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property, xcb_timestamp_t t = 0);
@ -107,6 +111,9 @@ private:
static const int clipboard_timeout;
bool m_incr_active;
bool m_clipboard_closing;
xcb_timestamp_t m_incr_receive_time;
};
#endif // QT_NO_CLIPBOARD

View File

@ -1164,6 +1164,12 @@ void QXcbConnection::processXcbEvents()
continue;
}
bool accepted = false;
if (clipboard()->processIncr())
clipboard()->incrTransactionPeeker(event, accepted);
if (accepted)
continue;
QVector<PeekFunc>::iterator it = m_peekFuncs.begin();
while (it != m_peekFuncs.end()) {
// These callbacks return true if the event is what they were

View File

@ -648,7 +648,6 @@ void QXcbWindow::show()
if (!transientXcbParent)
transientXcbParent = static_cast<QXcbScreen *>(screen())->clientLeader();
if (transientXcbParent) { // ICCCM 4.1.2.6
m_gravity = XCB_GRAVITY_CENTER;
Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32,
1, &transientXcbParent));
@ -1304,9 +1303,6 @@ QRect QXcbWindow::windowToWmGeometry(QRect r) const
r.translate(m_frameMargins.left(), m_frameMargins.top());
} else if (!frameInclusive && m_gravity == XCB_GRAVITY_NORTH_WEST) {
r.translate(-m_frameMargins.left(), -m_frameMargins.top());
} else if (!frameInclusive && m_gravity == XCB_GRAVITY_CENTER) {
r.translate(-(m_frameMargins.left() - m_frameMargins.right())/2,
-(m_frameMargins.top() - m_frameMargins.bottom())/2);
}
return r;
}

View File

@ -197,7 +197,7 @@ void QPrintDialogPrivate::openCocoaPrintPanel(Qt::WindowModality modality)
// close down during the cleanup (QTBUG-17913):
qApp->processEvents(QEventLoop::ExcludeUserInputEvents, QEventLoop::ExcludeSocketNotifiers);
QT_MANGLE_NAMESPACE(QCocoaPrintPanelDelegate) *delegate = [[QT_MANGLE_NAMESPACE(QCocoaPrintPanelDelegate) alloc] init];
QT_MANGLE_NAMESPACE(QCocoaPrintPanelDelegate) *delegate = [[QT_MANGLE_NAMESPACE(QCocoaPrintPanelDelegate) alloc] initWithNSPrintInfo:printInfo];
if (modality == Qt::ApplicationModal || !q->parentWidget()) {
if (modality == Qt::NonModal)
qWarning("QPrintDialog is required to be modal on OS X");

View File

@ -52,12 +52,12 @@ if (v.isValid() && qstrcmp(v.typeName(), "sqlite3*")==0) {
//! [1]
if (v.typeName() == "PGconn*") {
if (qstrcmp(v.typeName(), "PGconn*")) {
PGconn *handle = *static_cast<PGconn **>(v.data());
if (handle != 0) ...
}
if (v.typeName() == "MYSQL*") {
if (qstrcmp(v.typeName(), "MYSQL*")) {
MYSQL *handle = *static_cast<MYSQL **>(v.data());
if (handle != 0) ...
}

View File

@ -79,6 +79,8 @@ private slots:
void QTBUG2331();
void QTBUG2331_data() { basicTest_data(); }
void signalsEmittedAfterFileMoved();
private:
QString m_tempDirPattern;
};
@ -596,5 +598,84 @@ void tst_QFileSystemWatcher::QTBUG2331()
QCOMPARE(watcher.directories(), QStringList());
}
class SignalReceiver : public QObject
{
Q_OBJECT
public:
SignalReceiver(const QDir &moveSrcDir,
const QString &moveDestination,
QFileSystemWatcher *watcher,
QObject *parent = 0)
: QObject(parent),
added(false),
moveSrcDir(moveSrcDir),
moveDestination(QDir(moveDestination)),
watcher(watcher)
{}
public slots:
void fileChanged(const QString &path)
{
QFileInfo finfo(path);
QCOMPARE(finfo.absolutePath(), moveSrcDir.absolutePath());
if (!added) {
foreach (const QFileInfo &fi, moveDestination.entryInfoList(QDir::Files | QDir::NoSymLinks))
watcher->addPath(fi.absoluteFilePath());
added = true;
}
}
private:
bool added;
QDir moveSrcDir;
QDir moveDestination;
QFileSystemWatcher *watcher;
};
// regression test for QTBUG-33211.
// using inotify backend if a file is moved and then added to the watcher
// before all the fileChanged signals are emitted the remaining signals are
// emitted with the destination path instead of the starting path
void tst_QFileSystemWatcher::signalsEmittedAfterFileMoved()
{
QTemporaryDir temporaryDirectory(m_tempDirPattern);
QVERIFY(temporaryDirectory.isValid());
QDir testDir(temporaryDirectory.path());
QVERIFY(testDir.mkdir("movehere"));
QString movePath = testDir.filePath("movehere");
for (int i = 0; i < 10; i++) {
QFile f(testDir.filePath(QString("test%1.txt").arg(i)));
QVERIFY(f.open(QIODevice::WriteOnly));
f.write(QByteArray("i am " + i));
f.close();
}
QFileSystemWatcher watcher;
QVERIFY(watcher.addPath(testDir.path()));
QVERIFY(watcher.addPath(movePath));
// add files to watcher
QFileInfoList files = testDir.entryInfoList(QDir::Files | QDir::NoSymLinks);
foreach (const QFileInfo &finfo, files)
QVERIFY(watcher.addPath(finfo.absoluteFilePath()));
// create the signal receiver
SignalReceiver signalReceiver(testDir, movePath, &watcher);
connect(&watcher, SIGNAL(fileChanged(QString)), &signalReceiver, SLOT(fileChanged(QString)));
// watch signals
QSignalSpy changedSpy(&watcher, SIGNAL(fileChanged(QString)));
QVERIFY(changedSpy.isValid());
// move files to second directory
foreach (const QFileInfo &finfo, files)
QVERIFY(testDir.rename(finfo.fileName(), QString("movehere/%2").arg(finfo.fileName())));
QTRY_COMPARE(changedSpy.count(), 10);
}
QTEST_MAIN(tst_QFileSystemWatcher)
#include "tst_qfilesystemwatcher.moc"

View File

@ -1587,6 +1587,8 @@ void tst_QTextLayout::testTabDPIScale()
case QPaintDevice::PdmPhysicalDpiX:
case QPaintDevice::PdmPhysicalDpiY:
return 72;
case QPaintDevice::PdmDevicePixelRatio:
; // fall through
}
return 0;
}

View File

@ -114,6 +114,7 @@ private slots:
void about();
void detailsText();
void detailsButtonText();
void expandDetails_QTBUG_32473();
#ifndef Q_OS_MAC
void shortcut();
@ -137,6 +138,19 @@ private:
QTimer keySendTimer;
};
class tst_ResizingMessageBox : public QMessageBox
{
public:
tst_ResizingMessageBox() : QMessageBox(), resized(false) { }
bool resized;
protected:
void resizeEvent ( QResizeEvent * event ) {
resized = true;
QMessageBox::resizeEvent(event);
}
};
tst_QMessageBox::tst_QMessageBox() : keyToSend(-1)
{
}
@ -603,6 +617,37 @@ void tst_QMessageBox::detailsButtonText()
}
}
void tst_QMessageBox::expandDetails_QTBUG_32473()
{
tst_ResizingMessageBox box;
box.setDetailedText("bla");
box.show();
QApplication::postEvent(&box, new QEvent(QEvent::LanguageChange));
QApplication::processEvents();
QDialogButtonBox* bb = box.findChild<QDialogButtonBox*>("qt_msgbox_buttonbox");
QVERIFY(bb);
QList<QAbstractButton *> list = bb->buttons();
QAbstractButton* moreButton = NULL;
foreach (QAbstractButton* btn, list)
if (btn && bb->buttonRole(btn) == QDialogButtonBox::ActionRole)
moreButton = btn;
QVERIFY(moreButton);
QVERIFY(QTest::qWaitForWindowExposed(&box));
QRect geom = box.geometry();
box.resized = false;
moreButton->click();
QTRY_VERIFY(box.resized);
// After we receive the expose event for a second widget, it's likely
// that the window manager is also done manipulating the first QMessageBox.
QWidget fleece;
fleece.show();
QTest::qWaitForWindowExposed(&fleece);
if (geom.topLeft() == box.geometry().topLeft())
QTest::qWait(500);
QCOMPARE(geom.topLeft(), box.geometry().topLeft());
}
void tst_QMessageBox::incorrectDefaultButton()
{
keyToSend = Qt::Key_Escape;