summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/kernel/qdnd_x11.cpp20
-rw-r--r--tests/auto/qdrag/dummy.pngbin0 -> 126 bytes
-rw-r--r--tests/auto/qdrag/tst_qdrag.cpp255
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
new file mode 100644
index 0000000..c4b5723
--- /dev/null
+++ b/tests/auto/qdrag/dummy.png
Binary files differ
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"