diff options
-rw-r--r-- | src/gui/kernel/qdnd_x11.cpp | 20 | ||||
-rw-r--r-- | tests/auto/qdrag/dummy.png | bin | 0 -> 126 bytes | |||
-rw-r--r-- | tests/auto/qdrag/tst_qdrag.cpp | 255 |
3 files changed, 267 insertions, 8 deletions
diff --git a/src/gui/kernel/qdnd_x11.cpp b/src/gui/kernel/qdnd_x11.cpp index b312d7e..e3d5391 100644 --- a/src/gui/kernel/qdnd_x11.cpp +++ b/src/gui/kernel/qdnd_x11.cpp @@ -1427,9 +1427,8 @@ bool windowInteractsWithPosition(const QPoint & pos, Window w, int shapeType) { int nrectanglesRet, dummyOrdering; XRectangle *rectangles = XShapeGetRectangles(QX11Info::display(), w, shapeType, &nrectanglesRet, &dummyOrdering); - bool interacts = true; + bool interacts = false; if (rectangles) { - interacts = false; for (int i = 0; !interacts && i < nrectanglesRet; ++i) interacts = QRect(rectangles[i].x, rectangles[i].y, rectangles[i].width, rectangles[i].height).contains(pos); XFree(rectangles); @@ -1438,7 +1437,7 @@ bool windowInteractsWithPosition(const QPoint & pos, Window w, int shapeType) } static -Window findRealWindow(const QPoint & pos, Window w, int md) +Window findRealWindow(const QPoint & pos, Window w, int md, bool ignoreNonXdndAwareWindows) { if (xdnd_data.deco && w == xdnd_data.deco->effectiveWinId()) return 0; @@ -1452,7 +1451,7 @@ Window findRealWindow(const QPoint & pos, Window w, int md) if (attr.map_state == IsViewable && QRect(attr.x,attr.y,attr.width,attr.height).contains(pos)) { - bool windowContainsMouse = true; + bool windowContainsMouse = !ignoreNonXdndAwareWindows; { Atom type = XNone; int f; @@ -1463,12 +1462,15 @@ Window findRealWindow(const QPoint & pos, Window w, int md) AnyPropertyType, &type, &f,&n,&a,&data); if (data) XFree(data); if (type) { + const QPoint relPos = pos - QPoint(attr.x,attr.y); // When ShapeInput and ShapeBounding are not set they return a single rectangle with the geometry of the window, this is why we // need an && here so that in the case one is set and the other is not we still get the correct result. #if defined(ShapeInput) && defined(ShapeBounding) - windowContainsMouse = windowInteractsWithPosition(pos, w, ShapeInput) && windowInteractsWithPosition(pos, w, ShapeBounding); + windowContainsMouse = windowInteractsWithPosition(relPos, w, ShapeInput) && windowInteractsWithPosition(relPos, w, ShapeBounding); #elif defined(ShapeBounding) - windowContainsMouse = windowInteractsWithPosition(pos, w, ShapeBounding); + windowContainsMouse = windowInteractsWithPosition(relPos, w, ShapeBounding); +#else + windowContainsMouse = true; #endif if (windowContainsMouse) return w; @@ -1482,7 +1484,7 @@ Window findRealWindow(const QPoint & pos, Window w, int md) r=0; for (uint i=nc; !r && i--;) { r = findRealWindow(pos-QPoint(attr.x,attr.y), - c[i], md-1); + c[i], md-1, ignoreNonXdndAwareWindows); } XFree(c); if (r) @@ -1579,7 +1581,9 @@ void QDragManager::move(const QPoint & globalPos) } if (xdnd_data.deco && (!target || target == xdnd_data.deco->effectiveWinId())) { DNDDEBUG << "need to find real window"; - target = findRealWindow(globalPos, rootwin, 6); + target = findRealWindow(globalPos, rootwin, 6, true); + if (target == 0) + target = findRealWindow(globalPos, rootwin, 6, false); DNDDEBUG << "real window found" << QWidget::find(target) << target; } } diff --git a/tests/auto/qdrag/dummy.png b/tests/auto/qdrag/dummy.png Binary files differnew file mode 100644 index 0000000..c4b5723 --- /dev/null +++ b/tests/auto/qdrag/dummy.png diff --git a/tests/auto/qdrag/tst_qdrag.cpp b/tests/auto/qdrag/tst_qdrag.cpp index 07d82b3..3aac909 100644 --- a/tests/auto/qdrag/tst_qdrag.cpp +++ b/tests/auto/qdrag/tst_qdrag.cpp @@ -46,9 +46,132 @@ #include <qdebug.h> #include <qdrag.h> +#ifdef Q_WS_X11 +#include <QBitmap> +#include <QPainter> +#include <QX11Info> + +#include <X11/extensions/shape.h> +#endif + //TESTED_CLASS= //TESTED_FILES= +class DragEnterCounterWidget : public QWidget +{ +public: + DragEnterCounterWidget(); + + void dragEnterEvent(QDragEnterEvent * event); + + int enterEvents; +}; + +class DragCounterAndCreatorWidget : public DragEnterCounterWidget +{ +public: + DragCounterAndCreatorWidget(); + + void mousePressEvent(QMouseEvent * event); + + int startedDrags; +}; + +class BiggerDragCounterWidget : public DragEnterCounterWidget +{ +public: + BiggerDragCounterWidget(); +}; + +DragEnterCounterWidget::DragEnterCounterWidget() : QWidget(0), enterEvents(0) +{ + setAcceptDrops(true); + setWindowFlags(Qt::FramelessWindowHint); + show(); +} + +void DragEnterCounterWidget::dragEnterEvent(QDragEnterEvent * event) +{ + event->acceptProposedAction(); + ++enterEvents; +} + +DragCounterAndCreatorWidget::DragCounterAndCreatorWidget() : startedDrags(0) +{ + resize(80, 80); + move(300, 300); +} + +void DragCounterAndCreatorWidget::mousePressEvent(QMouseEvent * /*event*/) +{ + ++startedDrags; + QDrag *drag = new QDrag(this); + drag->setMimeData(new QMimeData); + QPixmap p("dummy.png"); + drag->setHotSpot(QPoint( p.width() / 2, p.height() / 2 )); + drag->setPixmap(p); + drag->exec(); +} + +BiggerDragCounterWidget::BiggerDragCounterWidget() +{ + resize(180, 180); + move(250, 250); +} + +class DoMouseReleaseHelper : public QTimer +{ +Q_OBJECT + +public: + DoMouseReleaseHelper(QWidget *w, int timeout = 0); + +private slots: + void doMouseRelease(); + +private: + QWidget *m_w; +}; + +DoMouseReleaseHelper::DoMouseReleaseHelper(QWidget *w, int timeout) : m_w(w) +{ + setSingleShot(true); + start(timeout); + connect(this, SIGNAL(timeout()), this, SLOT(doMouseRelease())); +} + +void DoMouseReleaseHelper::doMouseRelease() +{ + QTest::mouseRelease(m_w, Qt::LeftButton); +} + +class DoMouseMoveHelper : public QTimer +{ +Q_OBJECT + +public: + DoMouseMoveHelper(QWidget *w, const QPoint &p, int timeout = 0); + +private slots: + void doMouseMove(); + +private: + QWidget *m_w; + QPoint m_p; +}; + +DoMouseMoveHelper::DoMouseMoveHelper(QWidget *w, const QPoint &p, int timeout) : m_w(w), m_p(p) +{ + setSingleShot(true); + start(timeout); + connect(this, SIGNAL(timeout()), this, SLOT(doMouseMove())); +} + +void DoMouseMoveHelper::doMouseMove() +{ + QTest::mouseMove(m_w, m_p); +} + class tst_QDrag : public QObject { Q_OBJECT @@ -59,6 +182,10 @@ public: private slots: void getSetCheck(); + void testDragEnterSelf(); + void testDragEnterNoShaping(); + void testDragEnterSomeShaping(); + void testDragEnterAllShaping(); }; tst_QDrag::tst_QDrag() @@ -90,5 +217,133 @@ void tst_QDrag::getSetCheck() QCOMPARE(result, Qt::IgnoreAction); } +void tst_QDrag::testDragEnterSelf() +{ +#ifdef Q_WS_X11 + // Widget of 80x80 at 300, 300 + DragCounterAndCreatorWidget dw; + QTest::qWaitForWindowShown(&dw); + + // Press mouse to create a drag in dw + QTest::qWait(100); + QTest::mouseMove(&dw); + DoMouseReleaseHelper aux(&dw); + QTest::mousePress(&dw, Qt::LeftButton); + + // Verify that without a window in the middle the drag goes to dw itself + QCOMPARE(dw.startedDrags, 1); + QCOMPARE(dw.enterEvents, 1); +#endif +} + +void tst_QDrag::testDragEnterNoShaping() +{ +#ifdef Q_WS_X11 + // Widget of 80x80 at 300, 300 + DragCounterAndCreatorWidget dw; + QTest::qWaitForWindowShown(&dw); + + // Widget of 180x180 at 250, 250 + BiggerDragCounterWidget widgetOnTop; + QTest::qWaitForWindowShown(&widgetOnTop); + + // Press mouse to create a drag in dw + QTest::qWait(100); + QTest::mouseMove(&dw); + DoMouseReleaseHelper aux(&dw); + QTest::mousePress(&dw, Qt::LeftButton); + + // Verify that with widgetOnTop in the middle the drag, the drag event does not go to dw + // and goes to widgetOnTop + QCOMPARE(dw.startedDrags, 1); + QCOMPARE(dw.enterEvents, 0); + QCOMPARE(widgetOnTop.enterEvents, 1); +#endif +} + +void tst_QDrag::testDragEnterSomeShaping() +{ +#ifdef Q_WS_X11 + // Widget of 80x80 at 300, 300 + DragCounterAndCreatorWidget dw; + QTest::qWaitForWindowShown(&dw); + + // Widget of 180x180 at 250, 250 + BiggerDragCounterWidget widgetOnTop; + QTest::qWaitForWindowShown(&widgetOnTop); + + // Punch a hole in widgetOnTop to let the mouse go through the widget + // in the center of dw + QBitmap inputShape(180, 180); + inputShape.fill(Qt::color1); + QPainter painter(&inputShape); + painter.fillRect(80, 80, 50, 50, Qt::color0); + painter.end(); + XShapeCombineRegion(QX11Info::display(), widgetOnTop.effectiveWinId(), ShapeInput, 0, 0, QRegion(inputShape).handle(), ShapeSet); + + // Press mouse to create a drag in dw + QTest::qWait(100); + QTest::mouseMove(&dw); + DoMouseReleaseHelper aux(&dw); + QTest::mousePress(&dw, Qt::LeftButton); + + // Verify that with a input shaped widgetOnTop in the middle the drag, the drag event goes to dw + // and does not go to widgetOnTop + QCOMPARE(dw.startedDrags, 1); + QCOMPARE(dw.enterEvents, 1); + QCOMPARE(widgetOnTop.enterEvents, 0); + + // Press mouse to create a drag in dw and move it to the corner of the dw where widgetOnTop is not shaped anymore + DoMouseMoveHelper aux2(&dw, QPoint(1, 1), 100); + DoMouseReleaseHelper aux3(&dw, 200); + QTest::mousePress(&dw, Qt::LeftButton); + + // Verify once we get out of the shaped area the drag event also goes to widgetOnTop + QCOMPARE(dw.startedDrags, 2); + QCOMPARE(dw.enterEvents, 2); + QCOMPARE(widgetOnTop.enterEvents, 1); +#endif +} + +void tst_QDrag::testDragEnterAllShaping() +{ +#ifdef Q_WS_X11 + // Widget of 80x80 at 300, 300 + DragCounterAndCreatorWidget dw; + QTest::qWaitForWindowShown(&dw); + + // Widget of 180x180 at 250, 250 + BiggerDragCounterWidget widgetOnTop; + QTest::qWaitForWindowShown(&widgetOnTop); + + // Make widgetOnTop totally a hole regarding input + QBitmap inputShape(180, 180); + inputShape.fill(Qt::color0); + XShapeCombineRegion(QX11Info::display(), widgetOnTop.effectiveWinId(), ShapeInput, 0, 0, QRegion(inputShape).handle(), ShapeSet); + + // Press mouse to create a drag in dw + QTest::qWait(100); + QTest::mouseMove(&dw); + DoMouseReleaseHelper aux(&dw); + QTest::mousePress(&dw, Qt::LeftButton); + + // Verify that with a input shaped widgetOnTop in the middle the drag, the drag event goes to dw + // and does not go to widgetOnTop + QCOMPARE(dw.startedDrags, 1); + QCOMPARE(dw.enterEvents, 1); + QCOMPARE(widgetOnTop.enterEvents, 0); + + // Press mouse to create a drag in dw and move it to the corner of the dw + DoMouseMoveHelper aux2(&widgetOnTop, QPoint(1, 1)); + DoMouseReleaseHelper aux3(&dw, 200); + QTest::mousePress(&dw, Qt::LeftButton); + + // Verify the event also went to dw + QCOMPARE(dw.startedDrags, 2); + QCOMPARE(dw.enterEvents, 2); + QCOMPARE(widgetOnTop.enterEvents, 0); +#endif +} + QTEST_MAIN(tst_QDrag) #include "tst_qdrag.moc" |