material-decoration icon indicating copy to clipboard operation
material-decoration copied to clipboard

Qt6 Removes X11Info from Qt5::X11Extras

Open Zren opened this issue 3 years ago • 8 comments

Changes to Qt X11 Extras

The QX11Info class has been removed.

Clients that still rely on the functionality can include the private header <QtGui/private/qtx11extras_p.h> as a stopgap solution. To enable private headers use QT += gui-private with qmake, or add a project dependency to Qt::GuiPrivate with CMake.

  • https://doc.qt.io/qt-6/extras-changes-qt6.html#changes-to-qt-x11-extras
  • https://doc.qt.io/qt-5/qtx11extras-index.html
  • https://doc.qt.io/qt-5/qx11info.html

We use this class in:

  • Decoration::sendMoveEvent() and Decoration::windowPos() to get the global cursor pos for a drag
  • AppMenuModel::onWinIdChanged() to get the x11 window properties to know the dbus interface
  • Some unused commented out code in AppMenuButtonGroup

Zren avatar Jan 11 '22 19:01 Zren

I think I can help answer how to fix this the "correct" way without having to access private headers that could go away at any time.

These places you mention all need access to the xcb_connection_t * for the Display. QX11Info had an accessor to get that directly, but in Qt 6, the only thing that is provided is access to the Display *. However the means to access the Display * is substantially different from Qt 5:

QNativeInterface::QX11Application *x11App = qApp->nativeInterface<QNativeInterface::QX11Application>();
Display *displayID = x11App->display();

To get the xcb_connection_t *, I think you follow https://xcb.freedesktop.org/MixingCalls/ like so (this is untested - I'm just going from the aforementioned page:

#include <X11/Xlib-xcb.h>
[...]
QNativeInterface::QX11Application *x11App = qApp->nativeInterface<QNativeInterface::QX11Application>();
Display *displayID = x11App->display();
xcb_connection_t *c;
c = XGetXCBConnection(dpy);
[do your stuff that needs xcb_connection_t]

keithel avatar May 26 '22 05:05 keithel

  • https://doc.qt.io/qt-6/qguiapplication.html#nativeInterface
  • https://doc.qt.io/qt-6/qnativeinterface-qx11application.html

There's a connection() function. Do I need display() => Display then XGetXCBConnection(Display) => xcb_connection_t? There shouldn't be multiple connections for each display right?


Here's how QX11Info::connection() works:

  • Qt 6.0 dev https://github.com/qt/qtbase/blame/dev/src/gui/platform/unix/qtx11extras.cpp#L327
  • Qt 5.15 https://github.com/qt/qtx11extras/blame/5.15/src/x11extras/qx11info_x11.cpp#L374-L384
xcb_connection_t *QX11Info::connection()
{
    if (!qApp)
        return nullptr;
    QPlatformNativeInterface *native = qApp->platformNativeInterface();
    if (!native)
        return nullptr;

    void *connection = native->nativeResourceForIntegration(QByteArray("connection"));
    return reinterpret_cast<xcb_connection_t *>(connection);
}

The new Qt6 API:

Note, this is not backwards compatible, as QGuiApplication::nativeInterface() is not in Qt5? In Qt5 there is QGuiApplication::platformNativeInterface() but it's even less documented.

  • https://doc.qt.io/qt-5/qguiapplication.html#platformNativeInterface

Looks like I'll need to have separate logic for Qt5 + Qt6.

  • https://github.com/qt/qtbase/blame/dev/src/gui/kernel/qguiapplication_platform.h#L36
  • https://github.com/qt/qtbase/blame/dev/src/plugins/platforms/xcb/qxcbnativeinterface.cpp#L342-L346
  • https://github.com/qt/qtbase/blame/dev/src/plugins/platforms/xcb/qxcbintegration.h#L85
  • https://github.com/qt/qtbase/blame/dev/src/plugins/platforms/xcb/qxcbconnection_basic.h#L35
  • https://github.com/qt/qtbase/blame/dev/src/plugins/platforms/xcb/qxcbconnection_basic.cpp#L87
QXcbBasicConnection::QXcbBasicConnection(const char *displayName)
    : m_displayName(displayName ? QByteArray(displayName) : qgetenv("DISPLAY"))
{
#if QT_CONFIG(xcb_xlib)
    Display *dpy = XOpenDisplay(m_displayName.constData());
    if (dpy) {
        m_primaryScreenNumber = DefaultScreen(dpy);
        m_xcbConnection = XGetXCBConnection(dpy);
        XSetEventQueueOwner(dpy, XCBOwnsEventQueue);
        XSetErrorHandler(nullErrorHandler);
        XSetIOErrorHandler(ioErrorHandler);
        m_xlibDisplay = dpy;
    }
#else
    m_xcbConnection = xcb_connect(m_displayName.constData(), &m_primaryScreenNumber);
#endif

Zren avatar May 29 '22 21:05 Zren

Hmm Not sure where I had in my head that there was no connection method... I see now that it's there...

You're definitely right that in Qt5 QGuiApplication::platformNativeInterface() is severely undocumented (but at least they show it exists in the docs!).

Here is the header for it: https://github.com/qt/qtbase/blob/v5.15.5-lts-lgpl/src/gui/kernel/qplatformnativeinterface.h

And here's the XCB implementation. https://github.com/qt/qtbase/blob/v5.15.5-lts-lgpl/src/plugins/platforms/xcb/qxcbnativeinterface.h

in a #if Q_OS_LINUX block, you can use qobject_cast<QXcbNativeInterface *> and then access the methods there.

You'll need to have separate Qt5 and Qt6 implementations for this to work, as far as I understand - but it'll be using stable APIs that won't change on you. I think there's a good chance that the QX11Info private APIs will be removed at some point in the near future.

keithel avatar Jul 12 '22 19:07 keithel

TODO: I need to add #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) check to use #include <private/qtx11extras_p.h>.

https://invent.kde.org/plasma/breeze/-/commit/59142d5b800703986c1f4f71ab150bf4b4b23f3a#0f8721806070aa2f5fd1a8c2d4f6c865f35f96ab_27_27

#if BREEZE_HAVE_QTX11EXTRAS
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include <private/qtx11extras_p.h>
#else
#include <QX11Info>
#endif
#endif

Zren avatar Jan 15 '23 07:01 Zren

You can do this, but it is kicking the can down the road. In Qt 7, qtx11extras_p.h won't exist.

keithel avatar Jan 17 '23 14:01 keithel

https://doc.qt.io/qt-6/extras-changes-qt6.html#changes-to-qt-x11-extras

Zren avatar Aug 29 '23 01:08 Zren

Are there any instructions for compiling it with Qt6?

guiodic avatar Feb 29 '24 12:02 guiodic

i tried to build with Qt6 but i receive this error:

CMake Error at CMakeLists.txt:24 (find_package):
  Found package configuration file:

    /usr/lib/cmake/Qt6/Qt6Config.cmake

  but it set Qt6_FOUND to FALSE so package "Qt6" is considered to be NOT
  FOUND.  Reason given by package:

  Failed to find required Qt component "GuiPrivate".

  Expected Config file at
  "/usr/lib/cmake/Qt6GuiPrivate/Qt6GuiPrivateConfig.cmake" does NOT exist



  Configuring with --debug-find-pkg=Qt6GuiPrivate might reveal details why
  the package was not found.

  Configuring with -DQT_DEBUG_FIND_PACKAGE=ON will print the values of some
  of the path variables that find_package uses to try and find the package.

guiodic avatar Mar 07 '24 20:03 guiodic