XCB: Implement native window dump for diaglib

Extract a helper function to determine the window title from QXcbConnection
and add an invokable function to the native interface that dumps the window
tree similar to existing functionality on Windows.

Change-Id: I5544d69ea2b801eb16d3b5b8d64021b3e567b0d8
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
Friedemann Kleint 2017-12-14 14:15:34 +01:00
parent b68dfa0348
commit cb142954c5
6 changed files with 91 additions and 11 deletions

View File

@ -673,4 +673,60 @@ void *QXcbNativeInterface::handlerNativeResourceForBackingStore(const QByteArray
return nullptr;
}
static void dumpNativeWindowsRecursion(const QXcbConnection *connection, xcb_window_t window,
int level, QTextStream &str)
{
if (level)
str << QByteArray(2 * level, ' ');
xcb_connection_t *conn = connection->xcb_connection();
auto geomReply = Q_XCB_REPLY(xcb_get_geometry, conn, window);
if (!geomReply)
return;
const QRect geom(geomReply->x, geomReply->y, geomReply->width, geomReply->height);
if (!geom.isValid() || (geom.width() <= 3 && geom.height() <= 3))
return; // Skip helper/dummy windows.
str << "0x";
const int oldFieldWidth = str.fieldWidth();
const QChar oldPadChar =str.padChar();
str.setFieldWidth(8);
str.setPadChar(QLatin1Char('0'));
str << hex << window;
str.setFieldWidth(oldFieldWidth);
str.setPadChar(oldPadChar);
str << dec << " \""
<< QXcbWindow::windowTitle(connection, window) << "\" "
<< geom.width() << 'x' << geom.height() << forcesign << geom.x() << geom.y()
<< noforcesign << '\n';
auto reply = Q_XCB_REPLY(xcb_query_tree, conn, window);
if (reply) {
const int count = xcb_query_tree_children_length(reply.get());
const xcb_window_t *children = xcb_query_tree_children(reply.get());
for (int i = 0; i < count; ++i)
dumpNativeWindowsRecursion(connection, children[i], level + 1, str);
}
}
QString QXcbNativeInterface::dumpConnectionNativeWindows(const QXcbConnection *connection, WId root) const
{
QString result;
QTextStream str(&result);
if (root) {
dumpNativeWindowsRecursion(connection, xcb_window_t(root), 0, str);
} else {
for (const QXcbScreen *screen : connection->screens()) {
str << "Screen: \"" << screen->name() << "\"\n";
dumpNativeWindowsRecursion(connection, screen->root(), 0, str);
str << '\n';
}
}
return result;
}
QString QXcbNativeInterface::dumpNativeWindows(WId root) const
{
return dumpConnectionNativeWindows(QXcbIntegration::instance()->defaultConnection(), root);
}
QT_END_NAMESPACE

View File

@ -127,6 +127,8 @@ public:
Q_INVOKABLE bool systrayVisualHasAlphaChannel();
Q_INVOKABLE bool requestSystemTrayWindowDock(const QWindow *window);
Q_INVOKABLE QRect systemTrayWindowGlobalGeometry(const QWindow *window);
Q_INVOKABLE QString dumpConnectionNativeWindows(const QXcbConnection *connection, WId root) const;
Q_INVOKABLE QString dumpNativeWindows(WId root = 0) const;
void addHandler(QXcbNativeInterfaceHandler *handler);
void removeHandler(QXcbNativeInterfaceHandler *handler);

View File

@ -91,16 +91,8 @@ QXcbVirtualDesktop::QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t
if (reply && reply->format == 32 && reply->type == XCB_ATOM_WINDOW) {
xcb_window_t windowManager = *((xcb_window_t *)xcb_get_property_value(reply.get()));
if (windowManager != XCB_WINDOW_NONE) {
auto windowManagerReply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(),
false, windowManager,
atom(QXcbAtom::_NET_WM_NAME),
atom(QXcbAtom::UTF8_STRING), 0, 1024);
if (windowManagerReply && windowManagerReply->format == 8 && windowManagerReply->type == atom(QXcbAtom::UTF8_STRING)) {
m_windowManagerName = QString::fromUtf8((const char *)xcb_get_property_value(windowManagerReply.get()),
xcb_get_property_value_length(windowManagerReply.get()));
}
}
if (windowManager != XCB_WINDOW_NONE)
m_windowManagerName = QXcbWindow::windowTitle(connection, windowManager);
}
const xcb_query_extension_reply_t *sync_reply = xcb_get_extension_data(xcb_connection(), &xcb_sync_id);

View File

@ -2835,5 +2835,18 @@ QXcbScreen *QXcbWindow::xcbScreen() const
return static_cast<QXcbScreen *>(screen());
}
QString QXcbWindow::windowTitle(const QXcbConnection *conn, xcb_window_t window)
{
const xcb_atom_t utf8Atom = conn->atom(QXcbAtom::UTF8_STRING);
auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, conn->xcb_connection(),
false, window, conn->atom(QXcbAtom::_NET_WM_NAME),
utf8Atom, 0, 1024);
if (reply && reply->format == 8 && reply->type == utf8Atom) {
const char *name = reinterpret_cast<const char *>(xcb_get_property_value(reply.get()));
return QString::fromUtf8(name);
}
return QString();
}
QT_END_NAMESPACE

View File

@ -182,6 +182,8 @@ public:
virtual void create();
virtual void destroy();
static QString windowTitle(const QXcbConnection *conn, xcb_window_t window);
public Q_SLOTS:
void updateSyncRequestCounter();

View File

@ -28,10 +28,25 @@
#include "nativewindowdump.h"
#if QT_VERSION >= 0x050000
# include <QtGui/QGuiApplication>
# include <qpa/qplatformnativeinterface.h>
#endif
#include <QtCore/QDebug>
namespace QtDiag {
void dumpNativeWindows(WId)
void dumpNativeWindows(WId wid)
{
#if QT_VERSION >= 0x050000
QPlatformNativeInterface *ni = QGuiApplication::platformNativeInterface();
QString result;
QMetaObject::invokeMethod(ni, "dumpNativeWindows", Qt::DirectConnection,
Q_RETURN_ARG(QString, result),
Q_ARG(WId, wid));
qDebug().noquote() << result;
#endif // Qt 5
}
void dumpNativeQtTopLevels()