Skip to content

Instantly share code, notes, and snippets.

@probonopd
Last active February 8, 2025 16:45
Show Gist options
  • Save probonopd/1c02750baf1bb161aac7e42941b6ed0a to your computer and use it in GitHub Desktop.
Save probonopd/1c02750baf1bb161aac7e42941b6ed0a to your computer and use it in GitHub Desktop.

PyQt6 application without X11 as of 2025

On RPi OS (Bookworm) as of 2025. Configured with raspi-config to boot into a terminal rather than the desktop.

Trying to run PyQt6 application on the bare minimum software stack. This is the application, hello.py:

#!/usr/bin/env python3

import sys
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QApplication, QLabel, QWidget, QVBoxLayout

class HelloWorldApp(QWidget):
    def __init__(self):
        super().__init__()

        self.init_ui()

    def init_ui(self):
        self.setWindowTitle("Hello, World!")

        layout = QVBoxLayout()
        label = QLabel("Hello, World!")
        label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        layout.addWidget(label)

        self.setLayout(layout)

def main():
    app = QApplication(sys.argv)
    window = HelloWorldApp()
    window.show()
    sys.exit(app.exec())

if __name__ == "__main__":
    main()

linuxfb and eglfs yay, wayland not so much. Any help appreciated.

linuxfb

QT_QPA_PLATFORM=linuxfb python3 hello.py

works and is practically INSTANT. Yay!

eglfs

cat << EOF > eglfs.json
{
  "device": "/dev/dri/card1",
  "outputs": [
    {
      "name": "HDMI1",
      "mode": "1920x1080"
    }
  ]
}
EOF

QT_QPA_EGLFS_KMS_CONFIG=eglfs.json QT_QPA_PLATFORM=eglfs python3 hello.py

also works.

But neither has window decorations. Qt no longer has QWT which used to have a windowing system.

So we nowadays probably need to use Wayland.

And here the trouble begins. Every time I touch anything Wayland, it's usually an undocumented broken mess that never "just works".

But here we go...

labwc

labwc # Need to run this command on physical terminal, not over ssh?

WAYLAND_DISPLAY=wayland-0 QTQT_QPA_PLATFORM=wayland python3 hello.py

$  WAYLAND_DISPLAY=wayland-0 QTQT_QPA_PLATFORM=wayland python3 hello.py
QStandardPaths: wrong permissions on runtime directory /run/user/1000, 0770 instead of 0700
qt.qpa.wayland: Loading shell integration failed.
qt.qpa.wayland: Attempted to load the following shells QList("xdg-shell", "wl-shell", "ivi-shell")

wayfire

wayfire # Need to run this command on physical terminal, not over ssh?

Has some warnings about "seatd" - probably yet another something complicated from Red Hat?

$ QT_WAYLAND_SHELL_INTEGRATION=xdg-shell WAYLAND_DISPLAY=wayland-1 QTQT_QPA_PLATFORM=wayland python3 hello.py
QStandardPaths: wrong permissions on runtime directory /run/user/1000, 0770 instead of 0700
qt.qpa.wayland: Loading shell integration failed.
qt.qpa.wayland: Attempted to load the following shells QList("xdg-shell")

qt-shell

qt6/plugins/wayland-shell-integration/libqt-shell.so seems to be a Qt specidic "shell" other than XDG which may be more liberal and support move(). So can we use it?

sudo apt install -y qt6-wayland-dev qml6-module-qtwayland-compositor qml6-module-qtqml

# qtwayland5-examples exists, but no qt6 version?

git clone https://github.com/qt/qtwayland/
cd qtwayland
git checkout 6.4.2
cd examples/wayland/qtshell/
cmake .
make -j4


cat << EOF > eglfs.json
{
  "device": "/dev/dri/card1",
  "outputs": [
    {
      "name": "HDMI1",
      "mode": "1920x1080"
    }
  ]
}
EOF

QT_DEBUG_PLUGINS=1 QT_WAYLAND_SHELL_INTEGRATION=qt-shell QT_QPA_EGLFS_KMS_CONFIG=eglfs.json QT_QPA_PLATFORM=eglfs ./qtshell
QQmlApplicationEngine failed to load component
qrc:/qml/main.qml:11:5: Type CompositorScreen unavailable
qrc:/qml/CompositorScreen.qml:55:21: Type Chrome unavailable
qrc:/qml/Chrome.qml:180:9: Cannot assign to non-existent property "staysOnTop"

When we comment out these two lines

        //staysOnBottom: shellSurface.windowFlags & Qt.WindowStaysOnBottomHint
        //staysOnTop: !staysOnBottom && shellSurface.windowFlags & Qt.WindowStaysOnTopHint

in `qml/Chrome.qml` and recompile, we get a desktop background!


QT_DEBUG_PLUGINS=1 QT_WAYLAND_SHELL_INTEGRATION=qt-shell QT_QPA_EGLFS_KMS_CONFIG=eglfs.json QT_QPA_PLATFORM=eglfs ./qtshell
error in client communication (pid 731)
error in client communication (pid 731)
error in client communication (pid 731)
...

In another terminal:

QT_DEBUG_PLUGINS=1 QT_WAYLAND_SHELL_INTEGRATION=qt-shell WAYLAND_DISPLAY=wayland-0 QT_QPA_PLATFORM=wayland python hello.py
QStandardPaths: wrong permissions on runtime directory /run/user/1000, 0770 instead of 0700
qt.qpa.wayland: Loading shell integration failed.
qt.qpa.wayland: Attempted to load the following shells QList("qt-shell")

Does not run...

wayland-egl

QT_DEBUG_PLUGINS=1 QT_WAYLAND_SHELL_INTEGRATION=qt-shell WAYLAND_DISPLAY=wayland-0 QT_QPA_PLATFORM=wayland-egl python hello.py

qt.core.plugin.factoryloader: checking directory path "/usr/bin/platforms" ...
qt.core.library: "/usr/lib/aarch64-linux-gnu/qt6/plugins/platforms/libqwayland-egl.so" cannot load: Cannot load library /usr/lib/aarch64-linux-gnu/qt6/plugins/platforms/libqwayland-egl.so: (/usr/lib/aarch64-linux-gnu/qt6/plugins/platforms/libqwayland-egl.so: undefined symbol: _ZNK15QtWaylandClient19QWaylandIntegration22queryKeyboardModifiersEv)
qt.core.plugin.loader: QLibraryPrivate::loadPlugin failed on "/usr/lib/aarch64-linux-gnu/qt6/plugins/platforms/libqwayland-egl.so" : "Cannot load library /usr/lib/aarch64-linux-gnu/qt6/plugins/platforms/libqwayland-egl.so: (/usr/lib/aarch64-linux-gnu/qt6/plugins/platforms/libqwayland-egl.so: undefined symbol: _ZNK15QtWaylandClient19QWaylandIntegration22queryKeyboardModifiersEv)"
qt.qpa.plugin: Could not load the Qt platform plugin "wayland-egl" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

Available platform plugins are: xcb, wayland-egl, eglfs, linuxfb, minimalegl, wayland, minimal, offscreen, vkkhrdisplay, vnc.

Aborted
@Consolatis
Copy link

labwc -s "python3 hello.py" ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment