[Qt-interest] Problem: X Error: BadWindow (invalid Window parameter) 3 ...
Bjoern Erik Nilsen
bnilsen at trolltech.com
Wed Feb 4 14:39:54 CET 2009
> I've investigated a little bit and seem that QApplication::widgetAt() (or
> even topLevelAt() inside qapplication_x11.cpp) is problem (seem that it
> stays in loop somehow). I'm calling it many times and when problem starts,
> its always after call to QApplication::widgetAt().
Thank you for pinpointing the problem. I will dig into that function and
see what I can find out.
> I've seen in docs that widgetAt() can be slow. So what to use instead of
> widgetAt() to find out which window is under mouse cursor (if any) ?
> What's the exact diff between widgetAt() and topLevelAt() ?
widgetAt() Returns the widget at global screen position point, or 0 if
there is no Qt widget there.
topLevelAt() Returns the top-level widget at the given point; returns 0
if there is no such widget.
So the difference is that widgetAt() also returns child widgets whereas
topLevelAt() only returns top-levels.
These functions can be expensive because they potentially have to check
all windows on the desktop (depends on the windowing system in use).
However, since you are only interested in the widget under the cursor,
things are a lot more easier. Something like this should do the trick:
#include <QtGui>
#include <QDebug>
class Dummy : public QObject
{
Q_OBJECT
public:
Dummy() { QTimer::singleShot(300, this, SLOT(printInfo())); }
private slots:
void printInfo()
{
qDebug() << widgetUnderCursor();
QTimer::singleShot(300, this, SLOT(printInfo()));
}
private:
QWidget *widgetUnderCursor() const
{
const QWidgetList topLevelWidgets = qApp->topLevelWidgets();
if (topLevelWidgets.isEmpty())
return 0;
// Loop through all top-levels and see if the cursor is inside.
QWidget *topLevelUnderCursor= 0;
foreach (QWidget *topLevel, topLevelWidgets) {
if (topLevel->testAttribute(Qt::WA_UnderMouse))
topLevelUnderCursor = topLevel;
break;
}
}
if (!topLevelUnderCursor)
return 0; // Not inside any top-level widget.
const QPoint localCursorPos =
topLevelUnderCursor->mapFromGlobal(QCursor::pos());
QWidget *childUnderCursor =
topLevelUnderCursor->childAt(localCursorPos);
if (childUnderCursor)
return childUnderCursor;
return topLevelUnderCursor;
}
};
#include "main.moc"
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QWidget topLevel;
topLevel.setMask(QRegion(0, 0, 200, 200, QRegion::Ellipse));
topLevel.show();
QWidget anotherTopLevel;
anotherTopLevel.show();
Dummy dummy;
return app.exec();
}
The algorithm can easily be improved further, but I will leave that as
an exercise for the reader :-)
Hope this helps,
--
Bjørn Erik Nilsen
Software Engineer
Nokia, Qt Software
More information about the Qt-interest-old
mailing list