From 5eef8717c9862befe8b6529cbb111c0b30529f48 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Tue, 5 May 2009 10:16:00 +0200 Subject: Fixed handling of XA_PIXMAP format type in QClipboard on X11. When requesting image/ppm type we didn't return the proper pixmap because type 'PIXMAP' is not a proper image format name, but a reserved atom, so the fix is to remove redundant check that was triggered before we entered the actual function that tries to convert the clipboard content. Task-number: 252501 Reviewed-by: Brad --- src/gui/kernel/qclipboard_x11.cpp | 2 +- src/gui/kernel/qdnd_x11.cpp | 23 +++++------------------ 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/src/gui/kernel/qclipboard_x11.cpp b/src/gui/kernel/qclipboard_x11.cpp index 089cc43..d7eb111 100644 --- a/src/gui/kernel/qclipboard_x11.cpp +++ b/src/gui/kernel/qclipboard_x11.cpp @@ -786,7 +786,7 @@ static Atom send_selection(QClipboardData *d, Atom target, Window window, Atom p QByteArray data; QByteArray fmt = X11->xdndAtomToString(target); - if (fmt.isEmpty() || !QInternalMimeData::hasFormatHelper(QString::fromAscii(fmt), d->source())) { // Not a MIME type we have + if (fmt.isEmpty()) { // Not a MIME type we have DEBUG("QClipboard: send_selection(): converting to type '%s' is not supported", fmt.data()); return XNone; } diff --git a/src/gui/kernel/qdnd_x11.cpp b/src/gui/kernel/qdnd_x11.cpp index 4c9c73c..ed93b34 100644 --- a/src/gui/kernel/qdnd_x11.cpp +++ b/src/gui/kernel/qdnd_x11.cpp @@ -542,6 +542,8 @@ bool QX11Data::xdndMimeDataForAtom(Atom a, QMimeData *mimeData, QByteArray *data dm->xdndMimeTransferedPixmapIndex = (dm->xdndMimeTransferedPixmapIndex + 1) % 2; } + } else { + DEBUG("QClipboard: xdndMimeDataForAtom(): converting to type '%s' is not supported", atomName); } } return data; @@ -623,27 +625,12 @@ QVariant QX11Data::xdndMimeConvertToFormat(Atom a, const QByteArray &data, const if (a == XA_PIXMAP && data.size() == sizeof(Pixmap)) { Pixmap xpm = *((Pixmap*)data.data()); Display *dpy = display; - Window r; - int x,y; - uint w,h,bw,d; if (!xpm) return QByteArray(); - XGetGeometry(dpy,xpm, &r,&x,&y,&w,&h,&bw,&d); + QPixmap qpm = QPixmap::fromX11Pixmap(xpm); QImageWriter imageWriter; - GC gc = XCreateGC(dpy, xpm, 0, 0); - QImage imageToWrite; - if (d == 1) { - QBitmap qbm(w,h); - XCopyArea(dpy,xpm,qbm.handle(),gc,0,0,w,h,0,0); - imageWriter.setFormat("PBMRAW"); - imageToWrite = qbm.toImage(); - } else { - QPixmap qpm(w,h); - XCopyArea(dpy,xpm,qpm.handle(),gc,0,0,w,h,0,0); - imageWriter.setFormat("PPMRAW"); - imageToWrite = qpm.toImage(); - } - XFreeGC(dpy,gc); + imageWriter.setFormat("PPMRAW"); + QImage imageToWrite = qpm.toImage(); QBuffer buf; buf.open(QIODevice::WriteOnly); imageWriter.setDevice(&buf); -- cgit v0.12 From 6cbbc22cb8493120ccd01b62028866995e9f5cd7 Mon Sep 17 00:00:00 2001 From: mae Date: Tue, 5 May 2009 14:22:21 +0200 Subject: Extend change 759338df758ad16cdfd9521b270f7e379bbfa57c to cover extra selections with different foreground but no background The main concern is to avoid double painting. With anti-aliasing turned on by default, we can not draw a piece of text on top of the same piece of text without artefacts. Task-number: 252310 --- src/gui/text/qtextlayout.cpp | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 3222237..fa624ef 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -1145,7 +1145,7 @@ void QTextLayout::draw(QPainter *p, const QPointF &pos, const QVectorsave(); - p->setClipPath(region, Qt::IntersectClip); - selection.format.setProperty(ObjectSelectionBrush, selection.format.property(QTextFormat::BackgroundBrush)); - // don't just clear the property, set an empty brush that overrides a potential - // background brush specified in the text - selection.format.setProperty(QTextFormat::BackgroundBrush, QBrush()); - selection.format.clearProperty(QTextFormat::OutlinePen); + bool hasText = (selection.format.foreground().style() != Qt::NoBrush); + bool hasBackground= (selection.format.background().style() != Qt::NoBrush); + + if (hasBackground) { + selection.format.setProperty(ObjectSelectionBrush, selection.format.property(QTextFormat::BackgroundBrush)); + // don't just clear the property, set an empty brush that overrides a potential + // background brush specified in the text + selection.format.setProperty(QTextFormat::BackgroundBrush, QBrush()); + selection.format.clearProperty(QTextFormat::OutlinePen); + } - bool noText = (selection.format.foreground().style() == Qt::NoBrush); + selection.format.setProperty(SuppressText, !hasText); + + if (hasText && !hasBackground && !(textDoneRegion & region).isEmpty()) + continue; - selection.format.setProperty(SuppressText, noText); + p->save(); + p->setClipPath(region, Qt::IntersectClip); for (int line = firstLine; line < lastLine; ++line) { QTextLine l(line, d); @@ -1224,13 +1231,17 @@ void QTextLayout::draw(QPainter *p, const QPointF &pos, const QVectorrestore(); - if (noText) - needsTextButNoBackground += region; - else - needsTextButNoBackground -= region; + if (hasText) { + textDoneRegion += region; + } else { + if (hasBackground) + textDoneRegion -= region; + } + excludedRegion += region; } + QPainterPath needsTextButNoBackground = excludedRegion - textDoneRegion; if (!needsTextButNoBackground.isEmpty()){ p->save(); p->setClipPath(needsTextButNoBackground, Qt::IntersectClip); -- cgit v0.12 From a5c9793ea6b5590f1033546856c34eaee6352d58 Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Tue, 5 May 2009 14:50:22 +0200 Subject: Show the BGR mode in the titlebar of the qvfb window. Slightly hacky, but isolated change. Reviewed-by: Tom --- tools/qvfb/qvfb.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/qvfb/qvfb.cpp b/tools/qvfb/qvfb.cpp index 8de638f..510f0eb 100644 --- a/tools/qvfb/qvfb.cpp +++ b/tools/qvfb/qvfb.cpp @@ -711,7 +711,16 @@ void QVFb::configure() } view->setViewFormat(displayFormat); view->setTouchscreenEmulation( config->touchScreen->isChecked() ); - view->setRgbSwapped(config->rgbSwapped->isChecked()); + if (view->rgbSwapped() != config->rgbSwapped->isChecked()) { + //### the windowTitle logic is inside init(), and init isn't always invoked + QString caption = windowTitle(); + if (!config->rgbSwapped->isChecked()) + caption.replace(QLatin1String(" BGR"), QString()); + else + caption.append(QLatin1String(" BGR")); + setWindowTitle(caption); + view->setRgbSwapped(config->rgbSwapped->isChecked()); + } bool lcdEmulation = config->lcdScreen->isChecked(); view->setLcdScreenEmulation( lcdEmulation ); if ( lcdEmulation ) -- cgit v0.12 From 2137f41ca0df3c83abce9dd386074e0fd09a33dc Mon Sep 17 00:00:00 2001 From: Bjoern Erik Nilsen Date: Tue, 5 May 2009 15:33:42 +0200 Subject: Partially revert 37c72476fc444d3089075473cb4e9aa42ed64694 The problem was that mouse move events were not forwarded to the scene when mouse tracking was explicitly enabled on the view. Mouse tracking is disabled by default unless the scene contains an item that accepts hover events or has a cursor set. A mouse move event can only occur if: 1) a mouse button is pressed while moving the mouse 2) mouse tracking is enabled That means the part I've reverted was only hitting when mouse tracking was explicitly enabled, which is wrong. We always have to forward mouse move events to the scene if the view is getting them in the first place. Auto test included. Reviewed-by: Andreas --- src/gui/graphicsview/qgraphicsview.cpp | 4 ---- tests/auto/qgraphicsview/tst_qgraphicsview.cpp | 27 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 7720a10..644e843 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -587,10 +587,6 @@ void QGraphicsViewPrivate::mouseMoveEventHandler(QMouseEvent *event) return; if (!scene) return; - if (scene->d_func()->allItemsIgnoreHoverEvents && scene->d_func()->allItemsUseDefaultCursor - && !event->buttons()) { // forward event to the scene if something is pressed. - return; // No need to process this event further. - } QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove); mouseEvent.setWidget(q->viewport()); diff --git a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp index ca88afc..bb61f90 100644 --- a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp @@ -190,6 +190,7 @@ private slots: void scrollAfterResize(); void centerOnDirtyItem(); void mouseTracking(); + void mouseTracking2(); // task specific tests below me void task172231_untransformableItems(); @@ -3173,5 +3174,31 @@ void tst_QGraphicsView::mouseTracking() } } +void tst_QGraphicsView::mouseTracking2() +{ + // Make sure mouse move events propagates to the scene when + // mouse tracking is explicitly enabled on the view, + // even when all items ignore hover events / use default cursor. + + QGraphicsScene scene; + scene.addRect(0, 0, 100, 100); + + QGraphicsView view(&scene); + view.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&view); +#endif + QTest::qWait(200); + + QVERIFY(!view.viewport()->hasMouseTracking()); + view.viewport()->setMouseTracking(true); // Explicitly enable mouse tracking. + QVERIFY(view.viewport()->hasMouseTracking()); + + EventSpy spy(&scene, QEvent::GraphicsSceneMouseMove); + QCOMPARE(spy.count(), 0); + sendMouseMove(view.viewport(), view.viewport()->rect().center()); + QCOMPARE(spy.count(), 1); +} + QTEST_MAIN(tst_QGraphicsView) #include "tst_qgraphicsview.moc" -- cgit v0.12 From 98d485b54d2da97b83b7ff2379b31039923f922e Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Tue, 5 May 2009 18:50:31 +0200 Subject: Fix behavior of QButtonGroup::addButton(QAbstractButton, int). The method did not adhere to the documented behavior nor according to its precedessor in Qt 3 times. Now, when being passed -1 as argument, it will automatically assign ids. They will all be negative, starting from -2. Reviewed-by: mae --- src/gui/widgets/qabstractbutton.cpp | 17 +++++++--- src/gui/widgets/qbuttongroup.cpp | 16 +++++++-- tests/auto/qbuttongroup/tst_qbuttongroup.cpp | 49 +++++++++++++++++++++++++--- 3 files changed, 70 insertions(+), 12 deletions(-) diff --git a/src/gui/widgets/qabstractbutton.cpp b/src/gui/widgets/qabstractbutton.cpp index f2a9ceb..1900016 100644 --- a/src/gui/widgets/qabstractbutton.cpp +++ b/src/gui/widgets/qabstractbutton.cpp @@ -215,11 +215,8 @@ void QButtonGroup::setExclusive(bool exclusive) d->exclusive = exclusive; } -/*! - Adds the given \a button to the end of the group's internal list of buttons. - \sa removeButton() -*/ +// TODO: Qt 5: Merge with addButton(QAbstractButton *button, int id) void QButtonGroup::addButton(QAbstractButton *button) { addButton(button, -1); @@ -232,8 +229,18 @@ void QButtonGroup::addButton(QAbstractButton *button, int id) previous->removeButton(button); button->d_func()->group = this; d->buttonList.append(button); - if (id != -1) + if (id == -1) { + QList ids = d->mapping.values(); + if (ids.isEmpty()) + d->mapping[button] = -2; + else { + qSort(ids); + d->mapping[button] = ids.first()-1; + } + } else { d->mapping[button] = id; + } + if (d->exclusive && button->isChecked()) button->d_func()->notifyChecked(); } diff --git a/src/gui/widgets/qbuttongroup.cpp b/src/gui/widgets/qbuttongroup.cpp index 06bcf1e..ebfafe3 100644 --- a/src/gui/widgets/qbuttongroup.cpp +++ b/src/gui/widgets/qbuttongroup.cpp @@ -176,11 +176,21 @@ */ /*! - \fn void QButtonGroup::addButton(QAbstractButton *button, int id = -1); + \fn void QButtonGroup::addButton(QAbstractButton *button); + + Adds the given \a button to the end of the group's internal list of buttons. + An \a id will be assigned to the button by this QButtonGroup. Automatically + assigned ids are guaranteed to be negative, starting with -2. If you are also + assigning your own ids, use positive values to avoid conflicts. + + \sa removeButton() buttons() +*/ + +/*! + \fn void QButtonGroup::addButton(QAbstractButton *button, int id); Adds the given \a button to the button group, with the given \a - id. If \a id is -1 (the default), an id will be assigned to the - button by this QButtonGroup. + id. It is recommended to assign only positive ids. \sa removeButton() buttons() */ diff --git a/tests/auto/qbuttongroup/tst_qbuttongroup.cpp b/tests/auto/qbuttongroup/tst_qbuttongroup.cpp index 15cca56..4bb414c 100644 --- a/tests/auto/qbuttongroup/tst_qbuttongroup.cpp +++ b/tests/auto/qbuttongroup/tst_qbuttongroup.cpp @@ -92,11 +92,15 @@ private slots: void exclusive(); void exclusiveWithActions(); void testSignals(); - void checkedButton(); void task106609(); + // fixed for Qt 4.6.0 +#if QT_VERSION >= 0x040600 + void autoIncrementId(); +#endif + void task209485_removeFromGroupInEventHandler_data(); void task209485_removeFromGroupInEventHandler(); }; @@ -329,13 +333,19 @@ void tst_QButtonGroup::testSignals() QCOMPARE(clickedSpy.count(), 1); QCOMPARE(clickedIdSpy.count(), 1); - QVERIFY(clickedIdSpy.takeFirst().at(0).toInt() == -1); + + int expectedId = -1; +#if QT_VERSION >= 0x040600 + expectedId = -2; +#endif + + QVERIFY(clickedIdSpy.takeFirst().at(0).toInt() == expectedId); QCOMPARE(pressedSpy.count(), 1); QCOMPARE(pressedIdSpy.count(), 1); - QVERIFY(pressedIdSpy.takeFirst().at(0).toInt() == -1); + QVERIFY(pressedIdSpy.takeFirst().at(0).toInt() == expectedId); QCOMPARE(releasedSpy.count(), 1); QCOMPARE(releasedIdSpy.count(), 1); - QVERIFY(releasedIdSpy.takeFirst().at(0).toInt() == -1); + QVERIFY(releasedIdSpy.takeFirst().at(0).toInt() == expectedId); clickedSpy.clear(); clickedIdSpy.clear(); @@ -483,5 +493,36 @@ void tst_QButtonGroup::task209485_removeFromGroupInEventHandler() QCOMPARE(spy1.count() + spy2.count(), signalCount); } +#if QT_VERSION >= 0x040600 +void tst_QButtonGroup::autoIncrementId() +{ + QDialog dlg(0); + QButtonGroup *buttons = new QButtonGroup(&dlg); + QVBoxLayout *vbox = new QVBoxLayout(&dlg); + + QRadioButton *radio1 = new QRadioButton(&dlg); + radio1->setText("radio1"); + QRadioButton *radio2 = new QRadioButton(&dlg); + radio2->setText("radio2"); + QRadioButton *radio3 = new QRadioButton(&dlg); + radio3->setText("radio3"); + + buttons->addButton(radio1); + vbox->addWidget(radio1); + buttons->addButton(radio2); + vbox->addWidget(radio2); + buttons->addButton(radio3); + vbox->addWidget(radio3); + + radio1->setChecked(true); + + QVERIFY(buttons->id(radio1) == -2); + QVERIFY(buttons->id(radio2) == -3); + QVERIFY(buttons->id(radio3) == -4); + + dlg.show(); +} +#endif + QTEST_MAIN(tst_QButtonGroup) #include "tst_qbuttongroup.moc" -- cgit v0.12 From 5443871a89e01c8d8a8440f7786a24ea87922106 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 5 May 2009 17:03:09 +0200 Subject: Accept the event when doing keyboard search on a itemview. This is required for KHTML Patch by David Faure (the test is not really related) Reviewed-by: Thierry Task-number: 252912 --- src/gui/itemviews/qabstractitemview.cpp | 9 +++++---- tests/auto/qlistview/tst_qlistview.cpp | 25 +++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp index 4e4392f..4c1f7fc 100644 --- a/src/gui/itemviews/qabstractitemview.cpp +++ b/src/gui/itemviews/qabstractitemview.cpp @@ -2165,11 +2165,12 @@ void QAbstractItemView::keyPressEvent(QKeyEvent *event) } #endif bool modified = (event->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier)); - if (!event->text().isEmpty() && !modified) { - if (!edit(currentIndex(), AnyKeyPressed, event)) - keyboardSearch(event->text()); + if (!event->text().isEmpty() && !modified && !edit(currentIndex(), AnyKeyPressed, event)) { + keyboardSearch(event->text()); + event->accept(); + } else { + event->ignore(); } - event->ignore(); break; } } } diff --git a/tests/auto/qlistview/tst_qlistview.cpp b/tests/auto/qlistview/tst_qlistview.cpp index c372475..791a472 100644 --- a/tests/auto/qlistview/tst_qlistview.cpp +++ b/tests/auto/qlistview/tst_qlistview.cpp @@ -106,6 +106,7 @@ private slots: void task228566_infiniteRelayout(); void task248430_crashWith0SizedItem(); void task250446_scrollChanged(); + void keyboardSearch(); }; // Testing get/set functions @@ -1555,6 +1556,30 @@ void tst_QListView::task250446_scrollChanged() QCOMPARE(view.currentIndex(), index); } +void tst_QListView::keyboardSearch() +{ + QStringList items; + items << "AB" << "AC" << "BA" << "BB" << "BD" << "KAFEINE" << "KONQUEROR" << "KOPETE" << "KOOKA" << "OKULAR"; + QStringListModel model(items); + + QListView view; + view.setModel(&model); + view.show(); + QTest::qWait(30); +// QCOMPARE(view.currentIndex() , model.index(0,0)); + + QTest::keyClick(&view, Qt::Key_K); + QTest::qWait(10); + QCOMPARE(view.currentIndex() , model.index(5,0)); //KAFEINE + + QTest::keyClick(&view, Qt::Key_O); + QTest::qWait(10); + QCOMPARE(view.currentIndex() , model.index(6,0)); //KONQUEROR + + QTest::keyClick(&view, Qt::Key_N); + QTest::qWait(10); + QCOMPARE(view.currentIndex() , model.index(6,0)); //KONQUEROR +} QTEST_MAIN(tst_QListView) #include "tst_qlistview.moc" -- cgit v0.12 From 5727fe3657ee311c7b00e174f662464a67ff59bb Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Mon, 4 May 2009 15:55:19 +0200 Subject: Add padding around the text in the QTabBar. This is only usefull when eliding text. We just make SE_TabBarTabText match to what's computed by QTabBar::tabSizeHint Reviewed-by: jbache --- src/gui/styles/qcommonstyle.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gui/styles/qcommonstyle.cpp b/src/gui/styles/qcommonstyle.cpp index f8ae1a6..e1535f8 100644 --- a/src/gui/styles/qcommonstyle.cpp +++ b/src/gui/styles/qcommonstyle.cpp @@ -2873,9 +2873,11 @@ QRect QCommonStyle::subElementRect(SubElement sr, const QStyleOption *opt, tr.setRect(0, 0, tr.height(), tr.width()); int verticalShift = pixelMetric(QStyle::PM_TabBarTabShiftVertical, tab, widget); int horizontalShift = pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, tab, widget); + int hpadding = pixelMetric(QStyle::PM_TabBarTabHSpace, opt, widget) / 2; + int vpadding = pixelMetric(QStyle::PM_TabBarTabVSpace, opt, widget) / 2; if (tabV2.shape == QTabBar::RoundedSouth || tabV2.shape == QTabBar::TriangularSouth) verticalShift = -verticalShift; - tr.adjust(0, 0, horizontalShift, verticalShift); + tr.adjust(hpadding, vpadding, horizontalShift - hpadding, verticalShift - vpadding); bool selected = tabV2.state & State_Selected; if (selected) { tr.setBottom(tr.bottom() - verticalShift); -- cgit v0.12 From d32782a91982c50c72aed170f3bab2024ff8b4f3 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 5 May 2009 20:24:54 +0200 Subject: Show text in tabs of a QTabBar while compileing with QT_NO_TABWIDGET Spotted by looking at the code Reviewed-by: bnilsen --- src/gui/widgets/qtabbar.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/gui/widgets/qtabbar.cpp b/src/gui/widgets/qtabbar.cpp index 49de8c1..ce1ac09 100644 --- a/src/gui/widgets/qtabbar.cpp +++ b/src/gui/widgets/qtabbar.cpp @@ -176,12 +176,11 @@ void QTabBar::initStyleOption(QStyleOptionTab *option, int tabIndex) const if (tw->cornerWidget(Qt::TopRightCorner) || tw->cornerWidget(Qt::BottomRightCorner)) option->cornerWidgets |= QStyleOptionTab::RightCornerWidget; } +#endif QRect textRect = style()->subElementRect(QStyle::SE_TabBarTabText, option, this); - option->text = fontMetrics().elidedText(option->text, d->elideMode, textRect.width(), Qt::TextShowMnemonic); -#endif } /*! -- cgit v0.12 From 2d194009379a4e199ec246ca053ee97ee733482f Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Wed, 6 May 2009 10:31:28 +1000 Subject: Made tst_Selftests::checkXML actually test the new (Qt 4.6) test logger. Previously `-flush' was always passed to the child process, meaning the old (Qt 4.5) test logger was used exclusively in this test, hiding bugs. --- tests/auto/selftests/badxml/tst_badxml.cpp | 7 ++++ tests/auto/selftests/tst_selftests.cpp | 63 +++++++++++++++++------------- 2 files changed, 42 insertions(+), 28 deletions(-) diff --git a/tests/auto/selftests/badxml/tst_badxml.cpp b/tests/auto/selftests/badxml/tst_badxml.cpp index 6b2e4c4..fa5b717 100644 --- a/tests/auto/selftests/badxml/tst_badxml.cpp +++ b/tests/auto/selftests/badxml/tst_badxml.cpp @@ -58,6 +58,8 @@ private slots: void badMessage() const; void badMessage_data() const; + void failWithNoFile() const; + public: static QList const& badStrings(); }; @@ -116,6 +118,11 @@ void tst_BadXml::badDataTag_data() const } } +void tst_BadXml::failWithNoFile() const +{ + QTest::qFail("failure message", 0, 0); +} + /* Outputs a message containing a bad string. */ diff --git a/tests/auto/selftests/tst_selftests.cpp b/tests/auto/selftests/tst_selftests.cpp index aa1048b..d4069b1 100644 --- a/tests/auto/selftests/tst_selftests.cpp +++ b/tests/auto/selftests/tst_selftests.cpp @@ -324,34 +324,41 @@ void tst_Selftests::checkXML() const if(m_checkXMLBlacklist.contains(subdir)) return; - arguments.prepend("-xml"); - arguments.prepend("-flush"); - - QProcess proc; - proc.setEnvironment(QStringList("")); - proc.start(subdir + "/" + subdir, arguments); - QVERIFY(proc.waitForFinished()); - - QByteArray out(proc.readAllStandardOutput()); - QByteArray err(proc.readAllStandardError()); - - /* Some platforms decides to output a message for uncaught exceptions. For instance, - * this is what windows platforms says: - * "This application has requested the Runtime to terminate it in an unusual way. - * Please contact the application's support team for more information." */ - if(subdir != QLatin1String("exception") && subdir != QLatin1String("fetchbogus")) - QVERIFY2(err.isEmpty(), err.constData()); - - QXmlStreamReader reader(out); - - while(!reader.atEnd()) - reader.readNext(); - - QVERIFY2(!reader.error(), qPrintable(QString("line %1, col %2: %3") - .arg(reader.lineNumber()) - .arg(reader.columnNumber()) - .arg(reader.errorString()) - )); + QStringList args; + /* Test both old (-flush) and new XML logger implementation */ + for (int i = 0; i < 2; ++i) { + bool flush = i; + args = arguments; + args.prepend("-xml"); + if (flush) args.prepend("-flush"); + + QProcess proc; + proc.setEnvironment(QStringList("")); + proc.start(subdir + "/" + subdir, args); + QVERIFY(proc.waitForFinished()); + + QByteArray out(proc.readAllStandardOutput()); + QByteArray err(proc.readAllStandardError()); + + /* Some platforms decides to output a message for uncaught exceptions. For instance, + * this is what windows platforms says: + * "This application has requested the Runtime to terminate it in an unusual way. + * Please contact the application's support team for more information." */ + if(subdir != QLatin1String("exception") && subdir != QLatin1String("fetchbogus")) + QVERIFY2(err.isEmpty(), err.constData()); + + QXmlStreamReader reader(out); + + while(!reader.atEnd()) + reader.readNext(); + + QVERIFY2(!reader.error(), qPrintable(QString("(flush %0) line %1, col %2: %3") + .arg(flush) + .arg(reader.lineNumber()) + .arg(reader.columnNumber()) + .arg(reader.errorString()) + )); + } } void tst_Selftests::checkXunitxml() const -- cgit v0.12 From 9a60df38330c8a37d48e4e3f8fbdfc067b320cb5 Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Wed, 6 May 2009 10:34:40 +1000 Subject: Fixed invalid XML from testlib. Obvious typo in format string: `', closing tag should be `DataTag'. Autotest: 2d194009379a4e199ec246ca053ee97ee733482f --- src/testlib/qtestxmlstreamer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/testlib/qtestxmlstreamer.cpp b/src/testlib/qtestxmlstreamer.cpp index cf99b96..055abe0 100644 --- a/src/testlib/qtestxmlstreamer.cpp +++ b/src/testlib/qtestxmlstreamer.cpp @@ -54,7 +54,7 @@ void QTestXmlStreamer::formatStart(const QTestElement *element, char *formatted) QXmlTestLogger::xmlCdata(cdataTag, element->attributeValue(QTest::AI_Tag), sizeof(cdataTag)); QTest::qt_snprintf(formatted, 1024, "\n" - " \n" + " \n" " \n" "\n", element->attributeValue(QTest::AI_Result), location, cdataTag, cdataDesc); -- cgit v0.12 From 826bc847e6601f834a3ece8c001a8dd2bfa2fe97 Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Wed, 6 May 2009 10:46:35 +1000 Subject: Fixed invalid XML from testlib: `addAttribute(QTest::AI_Result, typeBuf); - failureElement->addAttribute(QTest::AI_File, file); + if(file) + failureElement->addAttribute(QTest::AI_File, file); + else + failureElement->addAttribute(QTest::AI_File, ""); QTest::qt_snprintf(buf, sizeof(buf), "%i", line); failureElement->addAttribute(QTest::AI_Line, buf); failureElement->addAttribute(QTest::AI_Description, description); -- cgit v0.12 From 548da9a5434d615456a7a6efda3380b7138c6000 Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Wed, 6 May 2009 11:00:59 +1000 Subject: Fixed failure of tst_Selftests::checkXML. A few tests use printf, which means they interfere with the XML test logging. Blacklist them for the XML test. Note that these tests happened to pass under the old test logger implementation. That was because the test logger always printed XML tags on a single line, and the printf calls contained no special XML characters. The test logs generated were technically valid XML but contained extraneous text. --- tests/auto/selftests/tst_selftests.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/auto/selftests/tst_selftests.cpp b/tests/auto/selftests/tst_selftests.cpp index d4069b1..603e730 100644 --- a/tests/auto/selftests/tst_selftests.cpp +++ b/tests/auto/selftests/tst_selftests.cpp @@ -307,13 +307,12 @@ void tst_Selftests::initTestCase() m_checkXMLBlacklist.append("qexecstringlist"); m_checkXMLBlacklist.append("benchliboptions"); + /* These tests use printf and therefore corrupt the testlog */ + m_checkXMLBlacklist.append("subtest"); + m_checkXMLBlacklist.append("globaldata"); + m_checkXMLBlacklist.append("warnings"); + m_checkXunitBlacklist = m_checkXMLBlacklist; - m_checkXunitBlacklist.append("benchlibwalltime"); - m_checkXunitBlacklist.append("benchlibeventcounter"); - m_checkXunitBlacklist.append("benchlibcallgrind"); - m_checkXunitBlacklist.append("subtest"); - m_checkXunitBlacklist.append("globaldata"); - m_checkXunitBlacklist.append("warnings"); } void tst_Selftests::checkXML() const -- cgit v0.12 From 244f5ee9c2c34ddee200e4d5cdc1345762a5901b Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 29 Apr 2009 17:01:04 +0200 Subject: Fix QFormLayout which allowed fields to be smaller that their minimum size If the label's sizeHint is bigger than its minimumSizeHint, the field may be resized smaller than its minimum size. This also fix another problem where the field would 'jump' from one sizehint to the others. (This can happen if labels can word-wrap for example) Reviewed-by: Michael Goddard --- src/gui/kernel/qformlayout.cpp | 6 +++++- tests/auto/qformlayout/tst_qformlayout.cpp | 30 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/gui/kernel/qformlayout.cpp b/src/gui/kernel/qformlayout.cpp index e2d6108..a665c89 100644 --- a/src/gui/kernel/qformlayout.cpp +++ b/src/gui/kernel/qformlayout.cpp @@ -689,12 +689,16 @@ void QFormLayoutPrivate::setupVerticalLayoutData(int width) // are split. maxLabelWidth = 0; if (!wrapAllRows) { + int maxFieldMinWidth = 0; //the maximum minimum size of the field for (int i = 0; i < rr; ++i) { const QFormLayoutItem *label = m_matrix(i, 0); const QFormLayoutItem *field = m_matrix(i, 1); - if (label && (label->sizeHint.width() + (field ? field->minSize.width() : 0) <= width)) + if (label && field && label->sideBySide) maxLabelWidth = qMax(maxLabelWidth, label->sizeHint.width()); + if (field) + maxFieldMinWidth = qMax(maxFieldMinWidth, field->minSize.width() + field->sbsHSpace); } + maxLabelWidth = qMin(maxLabelWidth, width - maxFieldMinWidth); } else { maxLabelWidth = width; } diff --git a/tests/auto/qformlayout/tst_qformlayout.cpp b/tests/auto/qformlayout/tst_qformlayout.cpp index c4c6f70..242974d 100644 --- a/tests/auto/qformlayout/tst_qformlayout.cpp +++ b/tests/auto/qformlayout/tst_qformlayout.cpp @@ -125,6 +125,7 @@ private slots: Qt::Orientations expandingDirections() const; */ + void fieldMinimumSize(); }; tst_QFormLayout::tst_QFormLayout() @@ -905,6 +906,35 @@ void tst_QFormLayout::layoutAlone() QTest::qWait(500); } + +void tst_QFormLayout::fieldMinimumSize() +{ + //check that the field with is bigger than its minimumSizeHint for any size of the widget + // even if the label with is not fixed + QWidget w; + QFormLayout layout; + layout.setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); + w.setLayout(&layout); + QLabel label1("Here is a strange test case"); + label1.setWordWrap(true); + QLabel label2("Here is another label"); + label2.setWordWrap(true); + QLabel shortLabel("short"); + QLabel longLabel("Quite long label"); + layout.addRow(&label1, &shortLabel); + layout.addRow(&label2, &longLabel); + w.show(); + int width = w.size().width() + 9; + + do { + w.resize(width, w.size().height()); + layout.activate(); + QVERIFY(shortLabel.size().width() >= shortLabel.minimumSizeHint().width()); + QVERIFY(longLabel.size().width() >= longLabel.minimumSizeHint().width()); + width -= 3; + } while(width >= w.minimumSizeHint().width()); +} + QTEST_MAIN(tst_QFormLayout) #include "tst_qformlayout.moc" -- cgit v0.12 From a2a8773f8c226f79727b39d42c7796fc91c4d60e Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 23 Feb 2009 15:29:26 +0100 Subject: test for queueing up pending connections --- tests/auto/qlocalsocket/tst_qlocalsocket.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/auto/qlocalsocket/tst_qlocalsocket.cpp b/tests/auto/qlocalsocket/tst_qlocalsocket.cpp index deabda6..785eab0 100644 --- a/tests/auto/qlocalsocket/tst_qlocalsocket.cpp +++ b/tests/auto/qlocalsocket/tst_qlocalsocket.cpp @@ -101,6 +101,8 @@ private slots: void recycleServer(); + void multiConnect(); + void debug(); }; @@ -842,6 +844,31 @@ void tst_QLocalSocket::recycleServer() QVERIFY(server.nextPendingConnection() != 0); } +void tst_QLocalSocket::multiConnect() +{ + QLocalServer server; + QLocalSocket client1; + QLocalSocket client2; + QLocalSocket client3; + + QVERIFY(server.listen("multiconnect")); + + client1.connectToServer("multiconnect"); + client2.connectToServer("multiconnect"); + client3.connectToServer("multiconnect"); + + QVERIFY(client1.waitForConnected(201)); + QVERIFY(client2.waitForConnected(202)); + QVERIFY(client3.waitForConnected(203)); + + QVERIFY(server.waitForNewConnection(201)); + QVERIFY(server.nextPendingConnection() != 0); + QVERIFY(server.waitForNewConnection(202)); + QVERIFY(server.nextPendingConnection() != 0); + QVERIFY(server.waitForNewConnection(203)); + QVERIFY(server.nextPendingConnection() != 0); +} + void tst_QLocalSocket::debug() { // Make sure this compiles -- cgit v0.12 From 3e89f8d598a677f004cb273dd2c3cc03d68f32eb Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 24 Apr 2009 10:07:00 +0200 Subject: rewrite QLocalServer native Windows implementation. this makes it much less arcane and buggy, specifically it resolves the internal thread-unsafety. Reviewed-by: thiago --- src/network/socket/qlocalserver.cpp | 6 +- src/network/socket/qlocalserver.h | 4 +- src/network/socket/qlocalserver_p.h | 59 ++------- src/network/socket/qlocalserver_win.cpp | 221 ++++++++++++++------------------ 4 files changed, 112 insertions(+), 178 deletions(-) diff --git a/src/network/socket/qlocalserver.cpp b/src/network/socket/qlocalserver.cpp index d6b1507..1815d73 100644 --- a/src/network/socket/qlocalserver.cpp +++ b/src/network/socket/qlocalserver.cpp @@ -276,9 +276,11 @@ QLocalSocket *QLocalServer::nextPendingConnection() if (d->pendingConnections.isEmpty()) return 0; QLocalSocket *nextSocket = d->pendingConnections.dequeue(); + if (d->pendingConnections.size() <= d->maxPendingConnections) #ifndef Q_OS_WIN - d->socketNotifier->setEnabled(d->pendingConnections.size() - <= d->maxPendingConnections); + d->socketNotifier->setEnabled(true); +#else + d->connectionEventNotifier->setEnabled(true); #endif return nextSocket; } diff --git a/src/network/socket/qlocalserver.h b/src/network/socket/qlocalserver.h index 8e8babd..c745ccb 100644 --- a/src/network/socket/qlocalserver.h +++ b/src/network/socket/qlocalserver.h @@ -89,9 +89,7 @@ private: #if defined(QT_LOCALSOCKET_TCP) Q_PRIVATE_SLOT(d_func(), void _q_onNewConnection()) #elif defined(Q_OS_WIN) - Q_PRIVATE_SLOT(d_func(), void _q_openSocket(HANDLE handle)) - Q_PRIVATE_SLOT(d_func(), void _q_stoppedListening()) - Q_PRIVATE_SLOT(d_func(), void _q_setError(QAbstractSocket::SocketError error, const QString &errorString)) + Q_PRIVATE_SLOT(d_func(), void _q_onNewConnection()) #else Q_PRIVATE_SLOT(d_func(), void _q_socketActivated()) #endif diff --git a/src/network/socket/qlocalserver_p.h b/src/network/socket/qlocalserver_p.h index 8e96401..9af4a20 100644 --- a/src/network/socket/qlocalserver_p.h +++ b/src/network/socket/qlocalserver_p.h @@ -63,7 +63,7 @@ # include #elif defined(Q_OS_WIN) # include -# include +# include #else # include # include @@ -71,52 +71,13 @@ QT_BEGIN_NAMESPACE -#if defined(Q_OS_WIN) && !defined(QT_LOCALSOCKET_TCP) - -/*! - \internal - QLocalServerThread exists because Windows does not have a - way to provide notifications when there is a new connections to - the server. - */ -class QLocalServerThread : public QThread -{ - Q_OBJECT - -Q_SIGNALS: - void connected(HANDLE newSocket); - void error(QAbstractSocket::SocketError error, const QString &errorString); - -public: - QLocalServerThread(QObject *parent = 0); - ~QLocalServerThread(); - void closeServer(); - -public: - QString setName(const QString &name); - void run(); - void stop(); - bool makeHandle(); - - HANDLE gotConnectionEvent; - QQueue pendingHandles; - int maxPendingConnections; -private: - HANDLE stopEvent; - QString fullServerName; -}; - -#endif - class QLocalServerPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QLocalServer) public: QLocalServerPrivate() : -#if defined(Q_OS_WIN) && !defined(QT_LOCALSOCKET_TCP) - inWaitingFunction(false), -#elif !defined(QT_LOCALSOCKET_TCP) +#if !defined(QT_LOCALSOCKET_TCP) && !defined(Q_OS_WIN) listenSocket(-1), socketNotifier(0), #endif maxPendingConnections(30), error(QAbstractSocket::UnknownSocketError) @@ -135,12 +96,18 @@ public: QTcpServer tcpServer; QMap socketMap; #elif defined(Q_OS_WIN) - void _q_openSocket(HANDLE socket); - void _q_stoppedListening(); - void _q_setError(QAbstractSocket::SocketError error, const QString &errorString); + struct Listener { + HANDLE handle; + OVERLAPPED overlapped; + }; + + void setError(const QString &function); + bool addListener(); + void _q_onNewConnection(); - QLocalServerThread waitForConnection; - bool inWaitingFunction; + QList listeners; + HANDLE eventHandle; + QWinEventNotifier *connectionEventNotifier; #else void setError(const QString &function); void _q_socketActivated(); diff --git a/src/network/socket/qlocalserver_win.cpp b/src/network/socket/qlocalserver_win.cpp index 880cd7e..b14bbf7 100644 --- a/src/network/socket/qlocalserver_win.cpp +++ b/src/network/socket/qlocalserver_win.cpp @@ -44,68 +44,26 @@ #include "qlocalsocket.h" #include -#include -#include -#include // The buffer size need to be 0 otherwise data could be // lost if the socket that has written data closes the connection // before it is read. Pipewriter is used for write buffering. #define BUFSIZE 0 -QT_BEGIN_NAMESPACE - -QLocalServerThread::QLocalServerThread(QObject *parent) : QThread(parent), - maxPendingConnections(1) -{ - stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - gotConnectionEvent = CreateEvent(NULL, TRUE, FALSE, NULL); -} +// ###: This should be a property. Should replace the insane 50 on unix as well. +#define SYSTEM_MAX_PENDING_SOCKETS 8 -QLocalServerThread::~QLocalServerThread() -{ - stop(); - closeServer(); - CloseHandle(stopEvent); - CloseHandle(gotConnectionEvent); -} - -void QLocalServerThread::stop() -{ - if (isRunning()) { - SetEvent(stopEvent); - wait(); - ResetEvent(stopEvent); - } -} - -void QLocalServerThread::closeServer() -{ - while (!pendingHandles.isEmpty()) - CloseHandle(pendingHandles.dequeue()); -} - -QString QLocalServerThread::setName(const QString &name) -{ - QString pipePath = QLatin1String("\\\\.\\pipe\\"); - if (name.startsWith(pipePath)) - fullServerName = name; - else - fullServerName = pipePath + name; - for (int i = pendingHandles.count(); i < maxPendingConnections; ++i) - if (!makeHandle()) - break; - return fullServerName; -} +QT_BEGIN_NAMESPACE -bool QLocalServerThread::makeHandle() +bool QLocalServerPrivate::addListener() { - if (pendingHandles.count() >= maxPendingConnections) - return false; + // The object must not change its address once the + // contained OVERLAPPED struct is passed to Windows. + listeners << Listener(); + Listener &listener = listeners.last(); - HANDLE handle = INVALID_HANDLE_VALUE; QT_WA({ - handle = CreateNamedPipeW( + listener.handle = CreateNamedPipeW( (TCHAR*)fullServerName.utf16(), // pipe name PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access PIPE_TYPE_MESSAGE | // message type pipe @@ -117,7 +75,7 @@ bool QLocalServerThread::makeHandle() 3000, // client time-out NULL); }, { - handle = CreateNamedPipeA( + listener.handle = CreateNamedPipeA( fullServerName.toLocal8Bit().constData(), // pipe name PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access PIPE_TYPE_MESSAGE | // message type pipe @@ -129,68 +87,43 @@ bool QLocalServerThread::makeHandle() 3000, // client time-out NULL); }); - - if (INVALID_HANDLE_VALUE == handle) { + if (listener.handle == INVALID_HANDLE_VALUE) { + setError(QLatin1String("QLocalServerPrivate::addListener")); + listeners.removeLast(); return false; } - pendingHandles.enqueue(handle); + + memset(&listener.overlapped, 0, sizeof(listener.overlapped)); + listener.overlapped.hEvent = eventHandle; + if (!ConnectNamedPipe(listener.handle, &listener.overlapped)) { + switch (GetLastError()) { + case ERROR_IO_PENDING: + break; + case ERROR_PIPE_CONNECTED: + SetEvent(eventHandle); + break; + default: + CloseHandle(listener.handle); + setError(QLatin1String("QLocalServerPrivate::addListener")); + listeners.removeLast(); + return false; + } + } else { + Q_ASSERT_X(false, "QLocalServerPrivate::addListener", "The impossible happened"); + SetEvent(eventHandle); + } return true; } -void QLocalServerThread::run() +void QLocalServerPrivate::setError(const QString &function) { - OVERLAPPED op; - HANDLE handleArray[2]; - memset(&op, 0, sizeof(op)); - handleArray[0] = op.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - handleArray[1] = stopEvent; - HANDLE handle = INVALID_HANDLE_VALUE; - - forever { - if (INVALID_HANDLE_VALUE == handle) { - makeHandle(); - if (!pendingHandles.isEmpty()) - handle = pendingHandles.dequeue(); - } - if (INVALID_HANDLE_VALUE == handle) { - int windowsError = GetLastError(); - QString function = QLatin1String("QLocalServer::run"); - QString errorString = QLocalServer::tr("%1: Unknown error %2").arg(function).arg(windowsError); - emit error(QAbstractSocket::UnknownSocketError, errorString); - CloseHandle(handleArray[0]); - SetEvent(gotConnectionEvent); - return; - } - - BOOL isConnected = ConnectNamedPipe(handle, &op) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); - if (!isConnected) { - switch (WaitForMultipleObjects(2, handleArray, FALSE, INFINITE)) - { - case WAIT_OBJECT_0 + 1: - CloseHandle(handle); - CloseHandle(handleArray[0]); - return; - } - } - emit connected(handle); - handle = INVALID_HANDLE_VALUE; - ResetEvent(handleArray[0]); - SetEvent(gotConnectionEvent); - } + int windowsError = GetLastError(); + errorString = QString::fromLatin1("%1: %2").arg(function).arg(qt_error_string(windowsError)); + error = QAbstractSocket::UnknownSocketError; } void QLocalServerPrivate::init() { - Q_Q(QLocalServer); - qRegisterMetaType("HANDLE"); - q->connect(&waitForConnection, SIGNAL(connected(HANDLE)), - q, SLOT(_q_openSocket(HANDLE)), Qt::QueuedConnection); - q->connect(&waitForConnection, SIGNAL(finished()), - q, SLOT(_q_stoppedListening()), Qt::QueuedConnection); - q->connect(&waitForConnection, SIGNAL(terminated()), - q, SLOT(_q_stoppedListening()), Qt::QueuedConnection); - q->connect(&waitForConnection, SIGNAL(error(QAbstractSocket::SocketError, const QString &)), - q, SLOT(_q_setError(QAbstractSocket::SocketError, const QString &))); } bool QLocalServerPrivate::removeServer(const QString &name) @@ -201,35 +134,71 @@ bool QLocalServerPrivate::removeServer(const QString &name) bool QLocalServerPrivate::listen(const QString &name) { - fullServerName = waitForConnection.setName(name); - serverName = name; - waitForConnection.start(); - return true; -} + Q_Q(QLocalServer); -void QLocalServerPrivate::_q_setError(QAbstractSocket::SocketError e, const QString &eString) -{ - error = e; - errorString = eString; -} + QString pipePath = QLatin1String("\\\\.\\pipe\\"); + if (name.startsWith(pipePath)) + fullServerName = name; + else + fullServerName = pipePath + name; -void QLocalServerPrivate::_q_stoppedListening() -{ - Q_Q(QLocalServer); - if (!inWaitingFunction) - q->close(); + // Use only one event for all listeners of one socket. + // The idea is that listener events are rare, so polling all listeners once in a while is + // cheap compared to waiting for N additional events in each iteration of the main loop. + eventHandle = CreateEvent(NULL, TRUE, FALSE, NULL); + connectionEventNotifier = new QWinEventNotifier(eventHandle , q); + q->connect(connectionEventNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_onNewConnection())); + + for (int i = 0; i < SYSTEM_MAX_PENDING_SOCKETS; ++i) + if (!addListener()) + return false; + return true; } -void QLocalServerPrivate::_q_openSocket(HANDLE handle) +void QLocalServerPrivate::_q_onNewConnection() { Q_Q(QLocalServer); - q->incomingConnection((int)handle); + DWORD dummy; + + // Reset first, otherwise we could reset an event which was asserted + // immediately after we checked the conn status. + ResetEvent(eventHandle); + + // Testing shows that there is indeed absolutely no guarantee which listener gets + // a client connection first, so there is no way around polling all of them. + for (int i = 0; i < listeners.size(); ) { + HANDLE handle = listeners[i].handle; + if (GetOverlappedResult(handle, &listeners[i].overlapped, &dummy, FALSE)) { + listeners.removeAt(i); + + addListener(); + + if (pendingConnections.size() > maxPendingConnections) + connectionEventNotifier->setEnabled(false); + + // Make this the last thing so connected slots can wreak the least havoc + q->incomingConnection((quintptr)handle); + } else { + if (GetLastError() != ERROR_IO_INCOMPLETE) { + setError(QLatin1String("QLocalServerPrivate::_q_onNewConnection")); + closeServer(); + return; + } + + ++i; + } + } } void QLocalServerPrivate::closeServer() { - waitForConnection.stop(); - waitForConnection.closeServer(); + connectionEventNotifier->setEnabled(false); // Otherwise, closed handle is checked before deleter runs + connectionEventNotifier->deleteLater(); + connectionEventNotifier = 0; + CloseHandle(eventHandle); + for (int i = 0; i < listeners.size(); ++i) + CloseHandle(listeners[i].handle); + listeners.clear(); } void QLocalServerPrivate::waitForNewConnection(int msecs, bool *timedOut) @@ -238,14 +207,12 @@ void QLocalServerPrivate::waitForNewConnection(int msecs, bool *timedOut) if (!pendingConnections.isEmpty() || !q->isListening()) return; - DWORD result = WaitForSingleObject(waitForConnection.gotConnectionEvent, - (msecs == -1) ? INFINITE : msecs); + DWORD result = WaitForSingleObject(eventHandle, (msecs == -1) ? INFINITE : msecs); if (result == WAIT_TIMEOUT) { if (timedOut) *timedOut = true; } else { - ResetEvent(waitForConnection.gotConnectionEvent); - QCoreApplication::instance()->processEvents(); + _q_onNewConnection(); } } -- cgit v0.12 From e13aab33bc1aa68bcf5a18e2d77b2db7f9f44e1e Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 6 May 2009 12:51:46 +0200 Subject: standardize on one name for the socket connection slot --- src/network/socket/qlocalserver.h | 6 ------ src/network/socket/qlocalserver_p.h | 4 +--- src/network/socket/qlocalserver_unix.cpp | 6 +++--- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/network/socket/qlocalserver.h b/src/network/socket/qlocalserver.h index c745ccb..1488a75 100644 --- a/src/network/socket/qlocalserver.h +++ b/src/network/socket/qlocalserver.h @@ -86,13 +86,7 @@ protected: private: Q_DISABLE_COPY(QLocalServer) -#if defined(QT_LOCALSOCKET_TCP) Q_PRIVATE_SLOT(d_func(), void _q_onNewConnection()) -#elif defined(Q_OS_WIN) - Q_PRIVATE_SLOT(d_func(), void _q_onNewConnection()) -#else - Q_PRIVATE_SLOT(d_func(), void _q_socketActivated()) -#endif }; #endif // QT_NO_LOCALSERVER diff --git a/src/network/socket/qlocalserver_p.h b/src/network/socket/qlocalserver_p.h index 9af4a20..7b31082 100644 --- a/src/network/socket/qlocalserver_p.h +++ b/src/network/socket/qlocalserver_p.h @@ -89,9 +89,9 @@ public: static bool removeServer(const QString &name); void closeServer(); void waitForNewConnection(int msec, bool *timedOut); + void _q_onNewConnection(); #if defined(QT_LOCALSOCKET_TCP) - void _q_onNewConnection(); QTcpServer tcpServer; QMap socketMap; @@ -103,14 +103,12 @@ public: void setError(const QString &function); bool addListener(); - void _q_onNewConnection(); QList listeners; HANDLE eventHandle; QWinEventNotifier *connectionEventNotifier; #else void setError(const QString &function); - void _q_socketActivated(); int listenSocket; QSocketNotifier *socketNotifier; diff --git a/src/network/socket/qlocalserver_unix.cpp b/src/network/socket/qlocalserver_unix.cpp index e7d2252..53ee6b6 100644 --- a/src/network/socket/qlocalserver_unix.cpp +++ b/src/network/socket/qlocalserver_unix.cpp @@ -132,7 +132,7 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName) socketNotifier = new QSocketNotifier(listenSocket, QSocketNotifier::Read, q); q->connect(socketNotifier, SIGNAL(activated(int)), - q, SLOT(_q_socketActivated())); + q, SLOT(_q_onNewConnection())); socketNotifier->setEnabled(maxPendingConnections > 0); return true; } @@ -164,7 +164,7 @@ void QLocalServerPrivate::closeServer() We have received a notification that we can read on the listen socket. Accept the new socket. */ -void QLocalServerPrivate::_q_socketActivated() +void QLocalServerPrivate::_q_onNewConnection() { Q_Q(QLocalServer); if (-1 == listenSocket) @@ -209,7 +209,7 @@ void QLocalServerPrivate::waitForNewConnection(int msec, bool *timedOut) break; } if (result > 0) - _q_socketActivated(); + _q_onNewConnection(); } if (timedOut) *timedOut = (result == 0); -- cgit v0.12 From 8cd19116ae81c99fe28fbf91aa7f4c1c08163fe0 Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Wed, 6 May 2009 13:54:57 +0200 Subject: QTreeView could be not correctly updated when the 1st column is hidden. The problem was that we were not always storing the modelindex in column 0 for each QTreeViewItem. That was causing inconsistencies. Now it is always the case. It allowed to remove some calls to QModelIndex::sibling. Task-number: 239271 Reviewed-by: ogoffart --- src/gui/itemviews/qtreeview.cpp | 38 ++++++++++---------------------- tests/auto/qtreeview/tst_qtreeview.cpp | 40 ++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 26 deletions(-) diff --git a/src/gui/itemviews/qtreeview.cpp b/src/gui/itemviews/qtreeview.cpp index 61f1b5b..ab03fea 100644 --- a/src/gui/itemviews/qtreeview.cpp +++ b/src/gui/itemviews/qtreeview.cpp @@ -680,10 +680,9 @@ void QTreeView::dataChanged(const QModelIndex &topLeft, const QModelIndex &botto // refresh the height cache here; we don't really lose anything by getting the size hint, // since QAbstractItemView::dataChanged() will get the visualRect for the items anyway - QModelIndex top = topLeft.sibling(topLeft.row(), 0); - int topViewIndex = d->viewIndex(top); + int topViewIndex = d->viewIndex(topLeft); if (topViewIndex == 0) - d->defaultItemHeight = indexRowSizeHint(top); + d->defaultItemHeight = indexRowSizeHint(topLeft); bool sizeChanged = false; if (topViewIndex != -1) { if (topLeft == bottomRight) { @@ -691,8 +690,7 @@ void QTreeView::dataChanged(const QModelIndex &topLeft, const QModelIndex &botto d->invalidateHeightCache(topViewIndex); sizeChanged = (oldHeight != d->itemHeight(topViewIndex)); } else { - QModelIndex bottom = bottomRight.sibling(bottomRight.row(), 0); - int bottomViewIndex = d->viewIndex(bottom); + int bottomViewIndex = d->viewIndex(bottomRight); for (int i = topViewIndex; i <= bottomViewIndex; ++i) { int oldHeight = d->itemHeight(i); d->invalidateHeightCache(i); @@ -1815,10 +1813,10 @@ void QTreeView::mouseDoubleClickEvent(QMouseEvent *event) if (i == -1) return; // user clicked outside the items - const QModelIndex &index = d->viewItems.at(i).index; + const QPersistentModelIndex firstColumnIndex = d->viewItems.at(i).index; int column = d->header->logicalIndexAt(event->x()); - QPersistentModelIndex persistent = index.sibling(index.row(), column); + QPersistentModelIndex persistent = firstColumnIndex.sibling(firstColumnIndex.row(), column); if (d->pressedIndex != persistent) { mousePressEvent(event); @@ -1841,10 +1839,10 @@ void QTreeView::mouseDoubleClickEvent(QMouseEvent *event) if (d->itemsExpandable && d->expandsOnDoubleClick && d->hasVisibleChildren(persistent)) { - if (!((i < d->viewItems.count()) && (d->viewItems.at(i).index == persistent))) { + if (!((i < d->viewItems.count()) && (d->viewItems.at(i).index == firstColumnIndex))) { // find the new index of the item for (i = 0; i < d->viewItems.count(); ++i) { - if (d->viewItems.at(i).index == persistent) + if (d->viewItems.at(i).index == firstColumnIndex) break; } if (i == d->viewItems.count()) @@ -2422,14 +2420,10 @@ void QTreeView::rowsInserted(const QModelIndex &parent, int start, int end) ? d->viewItems.count() : d->viewItems.at(parentItem).total) - 1; - int firstColumn = 0; - while (isColumnHidden(firstColumn) && firstColumn < header()->count() - 1) - ++firstColumn; - const int delta = end - start + 1; QVector insertedItems(delta); for (int i = 0; i < delta; ++i) { - insertedItems[i].index = d->model->index(i + start, firstColumn, parent); + insertedItems[i].index = d->model->index(i + start, 0, parent); insertedItems[i].level = childLevel; } if (d->viewItems.isEmpty()) @@ -2612,7 +2606,7 @@ void QTreeView::expandAll() d->viewItems[i].expanded = true; d->layout(i); QModelIndex idx = d->viewItems.at(i).index; - d->expandedIndexes.insert(idx.sibling(idx.row(), 0)); + d->expandedIndexes.insert(idx); } updateGeometries(); d->viewport->update(); @@ -3130,13 +3124,9 @@ void QTreeViewPrivate::layout(int i) int last = 0; int children = 0; - int firstColumn = 0; - while (header->isSectionHidden(firstColumn) && firstColumn < header->count()) - ++firstColumn; - for (int j = first; j < first + count; ++j) { - current = model->index(j - first, firstColumn, parent); - if (isRowHidden(current.sibling(current.row(), 0))) { + current = model->index(j - first, 0, parent); + if (isRowHidden(current)) { ++hidden; last = j - hidden + children; } else { @@ -3319,15 +3309,11 @@ int QTreeViewPrivate::itemAtCoordinate(int coordinate) const int QTreeViewPrivate::viewIndex(const QModelIndex &_index) const { - Q_Q(const QTreeView); if (!_index.isValid() || viewItems.isEmpty()) return -1; const int totalCount = viewItems.count(); - int firstColumn = 0; - while (q->isColumnHidden(firstColumn) && firstColumn < header->count()) - ++firstColumn; - const QModelIndex index = _index.sibling(_index.row(), firstColumn); + const QModelIndex index = _index.sibling(_index.row(), 0); // A quick check near the last item to see if we are just incrementing diff --git a/tests/auto/qtreeview/tst_qtreeview.cpp b/tests/auto/qtreeview/tst_qtreeview.cpp index 37cb5b0..71d7b4d 100644 --- a/tests/auto/qtreeview/tst_qtreeview.cpp +++ b/tests/auto/qtreeview/tst_qtreeview.cpp @@ -226,6 +226,7 @@ private slots: void task244304_clickOnDecoration(); void task246536_scrollbarsNotWorking(); void task250683_wrongSectionSize(); + void task239271_addRowsWithFirstColumnHidden(); }; class QtTestModel: public QAbstractItemModel @@ -3289,6 +3290,45 @@ void tst_QTreeView::task250683_wrongSectionSize() QCOMPARE(treeView.header()->sectionSize(0) + treeView.header()->sectionSize(1), treeView.viewport()->width()); } +void tst_QTreeView::task239271_addRowsWithFirstColumnHidden() +{ + class MyDelegate : public QStyledItemDelegate + { + public: + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const + { + paintedIndexes << index; + QStyledItemDelegate::paint(painter, option, index); + } + + mutable QSet paintedIndexes; + }; + + QTreeView view; + QStandardItemModel model; + view.setModel(&model); + MyDelegate delegate; + view.setItemDelegate(&delegate); + QStandardItem root0("root0"), root1("root1"); + model.invisibleRootItem()->appendRow(QList() << &root0 << &root1); + QStandardItem sub0("sub0"), sub00("sub00"); + root0.appendRow(QList() << &sub0 << &sub00); + view.expand(root0.index()); + + view.hideColumn(0); + view.show(); + QTest::qWait(200); + delegate.paintedIndexes.clear(); + QStandardItem sub1("sub1"), sub11("sub11"); + root0.appendRow(QList() << &sub1 << &sub11); + + QTest::qWait(200); + //items in the 2nd column should have been painted + QVERIFY(delegate.paintedIndexes.contains(sub00.index())); + QVERIFY(delegate.paintedIndexes.contains(sub11.index())); +} + + QTEST_MAIN(tst_QTreeView) #include "tst_qtreeview.moc" -- cgit v0.12 From 2dc5bf5c17f5b07e1387796977c69d3354acfd06 Mon Sep 17 00:00:00 2001 From: Kenneth Rohde Christiansen Date: Thu, 30 Apr 2009 09:59:04 +0200 Subject: Fix focus issues in QX11EmbedContainer, affecting Flash plugin in QtWebKit. We are now moving focus to the XEmbed focus proxy when we accept a client and when we get window activation. Window activation did that before, but only when we were the active container, thus had focus in. Now we do it always. Due to race conditions with the window manager, the time stamt we used for XSetInputFocus was the same as that of the window manager. This broke it from time to time in Metacity and Xfce but always in KWin. With other tested window manager we didn't have this issue. Following Owen Tayler's advice (one of the authors of the XEmbed specification) we now use CurrentTime and not qt_x11Data->time when moving the input focus as there is no explicit user interaction involved. Reviewed-by: Denis Dzyubenko Reviewed-by: Bradley T. Hughes --- src/gui/kernel/qx11embed_x11.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/gui/kernel/qx11embed_x11.cpp b/src/gui/kernel/qx11embed_x11.cpp index 6329135..ae93efe 100644 --- a/src/gui/kernel/qx11embed_x11.cpp +++ b/src/gui/kernel/qx11embed_x11.cpp @@ -1297,9 +1297,6 @@ bool QX11EmbedContainer::eventFilter(QObject *o, QEvent *event) // focus is set to our focus proxy. We want to intercept all // keypresses. if (o == window() && d->client) { - if (!d->isEmbedded() && d->activeContainer == this) - d->moveInputToProxy(); - if (d->clientIsXEmbed) { sendXEmbedMessage(d->client, x11Info().display(), XEMBED_WINDOW_ACTIVATE); } else { @@ -1307,6 +1304,8 @@ bool QX11EmbedContainer::eventFilter(QObject *o, QEvent *event) if (hasFocus()) XSetInputFocus(x11Info().display(), d->client, XRevertToParent, x11Time()); } + if (!d->isEmbedded()) + d->moveInputToProxy(); } break; case QEvent::WindowDeactivate: @@ -1729,10 +1728,10 @@ void QX11EmbedContainerPrivate::acceptClient(WId window) checkGrab(); if (q->hasFocus()) { XSetInputFocus(q->x11Info().display(), client, XRevertToParent, x11Time()); - } else { - if (!isEmbedded()) - moveInputToProxy(); } + } else { + if (!isEmbedded()) + moveInputToProxy(); } emit q->clientIsEmbedded(); @@ -1749,11 +1748,9 @@ void QX11EmbedContainerPrivate::acceptClient(WId window) void QX11EmbedContainerPrivate::moveInputToProxy() { Q_Q(QX11EmbedContainer); - WId focus; - int revert_to; - XGetInputFocus(q->x11Info().display(), &focus, &revert_to); - if (focus != focusProxy->internalWinId()) - XSetInputFocus(q->x11Info().display(), focusProxy->internalWinId(), XRevertToParent, x11Time()); + // Following Owen Taylor's advice from the XEmbed specification to + // always use CurrentTime when no explicit user action is involved. + XSetInputFocus(q->x11Info().display(), focusProxy->internalWinId(), XRevertToParent, CurrentTime); } /*! \internal -- cgit v0.12 From bcf7c498f0bd29f1ee9c7f226b3a656f1c05e35e Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 6 May 2009 15:17:03 +0200 Subject: Reduced the number of files in the WebKit import Exclude chromium files from the import. Reviewed-by: Trust me --- util/webkit/mkdist-webkit | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/util/webkit/mkdist-webkit b/util/webkit/mkdist-webkit index a7ecbc6..a2ef05b 100755 --- a/util/webkit/mkdist-webkit +++ b/util/webkit/mkdist-webkit @@ -46,6 +46,7 @@ excluded_directories="$excluded_directories JavaScriptCore/wtf/wx" excluded_directories="$excluded_directories JavaScriptCore/wtf/gtk" excluded_directories="$excluded_directories JavaScriptCore/wtf/mac" excluded_directories="$excluded_directories JavaScriptCore/wtf/win" +excluded_directories="$excluded_directories JavaScriptCore/wtf/chromium" excluded_directories="$excluded_directories WebCore/WebCore.vcproj" excluded_directories="$excluded_directories WebCore/DerivedSources.make" @@ -70,6 +71,7 @@ excluded_directories="$excluded_directories WebCore/loader/win" excluded_directories="$excluded_directories WebCore/page/gtk" excluded_directories="$excluded_directories WebCore/page/mac" excluded_directories="$excluded_directories WebCore/page/wx" +excluded_directories="$excluded_directories WebCore/page/chromium" excluded_directories="$excluded_directories WebCore/history/mac" @@ -78,6 +80,7 @@ excluded_directories="$excluded_directories WebCore/editing/wx" excluded_directories="$excluded_directories WebCore/platform/text/wx" excluded_directories="$excluded_directories WebCore/platform/text/gtk" +excluded_directories="$excluded_directories WebCore/platform/text/chromium" excluded_directories="$excluded_directories WebCore/manual-tests" @@ -87,6 +90,7 @@ excluded_directories="$excluded_directories WebCore/platform/network/curl" excluded_directories="$excluded_directories WebCore/platform/network/mac" excluded_directories="$excluded_directories WebCore/platform/network/win" excluded_directories="$excluded_directories WebCore/platform/network/soup" +excluded_directories="$excluded_directories WebCore/platform/network/chromium" excluded_directories="$excluded_directories WebCore/platform/graphics/cg" excluded_directories="$excluded_directories WebCore/platform/graphics/cairo" @@ -95,6 +99,7 @@ excluded_directories="$excluded_directories WebCore/platform/graphics/wx" excluded_directories="$excluded_directories WebCore/platform/graphics/mac" excluded_directories="$excluded_directories WebCore/platform/graphics/win" excluded_directories="$excluded_directories WebCore/platform/graphics/skia" +excluded_directories="$excluded_directories WebCore/platform/graphics/chromium" excluded_directories="$excluded_directories WebCore/platform/image-decoders/bmp" excluded_directories="$excluded_directories WebCore/platform/image-decoders/gif" @@ -105,6 +110,7 @@ excluded_directories="$excluded_directories WebCore/platform/image-decoders/jpeg excluded_directories="$excluded_directories WebCore/platform/image-decoders/xbm" excluded_directories="$excluded_directories WebCore/plugins/gtk" +excluded_directories="$excluded_directories WebCore/plugins/chromium" excluded_directories="$excluded_directories WebCore/platform/symbian WebCore/platform/wx" excluded_directories="$excluded_directories WebKit/gtk" -- cgit v0.12 From 980256ac1012f236a600d2a613229c50258a1ed8 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 6 May 2009 15:58:27 +0200 Subject: fix compilation of QLocalServer when QT_LOCALSOCKET_TCP is defined When QT_LOCALSOCKET_TCP is defined we cannot call setEnabled on the socket notifier. Reviewed-by: ossi --- src/network/socket/qlocalserver.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/network/socket/qlocalserver.cpp b/src/network/socket/qlocalserver.cpp index 1815d73..77a999b 100644 --- a/src/network/socket/qlocalserver.cpp +++ b/src/network/socket/qlocalserver.cpp @@ -276,12 +276,14 @@ QLocalSocket *QLocalServer::nextPendingConnection() if (d->pendingConnections.isEmpty()) return 0; QLocalSocket *nextSocket = d->pendingConnections.dequeue(); +#ifndef QT_LOCALSOCKET_TCP if (d->pendingConnections.size() <= d->maxPendingConnections) #ifndef Q_OS_WIN d->socketNotifier->setEnabled(true); #else d->connectionEventNotifier->setEnabled(true); #endif +#endif return nextSocket; } -- cgit v0.12 From 2eb0312c96ab828809158802d4cb7e0980227389 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Mon, 4 May 2009 14:29:39 +0200 Subject: Fix crash in QWebView when application has a style sheet Task: 252796 Rev-By: Tor Arne --- src/gui/styles/qstylesheetstyle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/styles/qstylesheetstyle.cpp b/src/gui/styles/qstylesheetstyle.cpp index ebddfd5..dcc11b8 100644 --- a/src/gui/styles/qstylesheetstyle.cpp +++ b/src/gui/styles/qstylesheetstyle.cpp @@ -4758,7 +4758,7 @@ QSize QStyleSheetStyle::sizeFromContents(ContentsType ct, const QStyleOption *op case CT_LineEdit: #ifndef QT_NO_SPINBOX // ### hopelessly broken QAbstractSpinBox (part 2) - if (QAbstractSpinBox *spinBox = qobject_cast(w->parentWidget())) { + if (QAbstractSpinBox *spinBox = qobject_cast(w ? w->parentWidget() : 0)) { QRenderRule rule = renderRule(spinBox, opt); if (rule.hasBox() || !rule.hasNativeBorder()) return csz; -- cgit v0.12