Zren / material-decoration

Material-ish window decoration theme for KWin, with LIM, based on zzag's original design.
GNU General Public License v2.0
197 stars 17 forks source link

Qt6 Removes X11Info from Qt5::X11Extras #60

Open Zren opened 2 years ago

Zren commented 2 years ago

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.

We use this class in:

keithel commented 2 years ago

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]
Zren commented 2 years ago

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:

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.

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

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
keithel commented 1 year ago

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.

Zren commented 1 year ago

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
keithel commented 1 year ago

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

Zren commented 10 months ago

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

guiodic commented 4 months ago

Are there any instructions for compiling it with Qt6?

guiodic commented 3 months ago

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.