diff --git a/local/recipes/kde/sddm/wayland-patch.sh b/local/recipes/kde/sddm/wayland-patch.sh index 79dff24ec7..0236e2d055 100755 --- a/local/recipes/kde/sddm/wayland-patch.sh +++ b/local/recipes/kde/sddm/wayland-patch.sh @@ -1,4 +1,22 @@ #!/bin/bash +# SDDM Wayland-only build patch for Red Bear OS. +# +# This script is invoked by the cookbook before SDDM's cmake configure +# step. It performs the minimum sed work needed to: +# 1. Disable X11 server support (XorgDisplayServer, XorgUserDisplayServer) +# and the XCB keyboard backend — Red Bear is Wayland-only. +# 2. Wire relibc's real (added in Round 1) into the XAuth +# class so the Xauthority file is read/written against the actual +# X11 on-disk format instead of a no-op stub. +# 3. Wire relibc's , , headers (added +# in Round 1) into the daemon so the actual login/logout/pid +# accounting works instead of returning error stubs. +# +# After Round 1 the relibc header set covers every header SDDM needs, +# so the only remaining sed work is the "disable X11" parts. Earlier +# versions of this script also stubbed XAuth because relibc lacked +# X11/Xauth.h; that sed block has been removed and XAuth is now a +# real implementation. set -e SRC="$1" if [ -z "$SRC" ]; then @@ -12,9 +30,15 @@ if [ ! -f "$CMAKE" ]; then exit 1 fi +# --- Disable X11 server support -------------------------------------- +# SDDM's CMakeLists has find_package(XCB ...) and find_package(Qt5XkbCommon +# which we don't need on a Wayland-only build. Comment them out. sed -i 's/find_package(XCB REQUIRED)/# Wayland-only: XCB not needed/' "$CMAKE" sed -i 's/find_package(XCB)/# Wayland-only: XCB not needed/' "$CMAKE" +# The greeter, daemon, and helper CMakeLists link XCB-derived libraries +# (e.g. ${LIBXCB_LIBRARIES}). Remove those link entries since they're +# not present on the Red Bear Wayland-only build. for cmakelists in "$SRC/src/daemon/CMakeLists.txt" "$SRC/src/helper/CMakeLists.txt" "$SRC/src/greeter/CMakeLists.txt"; do if [ -f "$cmakelists" ]; then sed -i 's/"\${LIBXCB_INCLUDE_DIR}"//' "$cmakelists" @@ -22,27 +46,45 @@ for cmakelists in "$SRC/src/daemon/CMakeLists.txt" "$SRC/src/helper/CMakeLists.t fi done +# The XCB keyboard backend (greeter) doesn't compile on Wayland-only. if [ -f "$SRC/src/greeter/CMakeLists.txt" ]; then sed -i 's/XcbKeyboardBackend.cpp/# Wayland-only: XCB not needed/' "$SRC/src/greeter/CMakeLists.txt" fi +# --- Stub out XorgDisplayServer and XorgUserDisplayServer ------------- +# Red Bear is Wayland-only; we have no real X server. The Xorg* +# classes are kept as minimal stubs so SDDM's compile-time symbols +# (which are referenced from DisplayServer subclasses) are satisfied. +# The stubs are no-ops that always return failure; SDDM's runtime +# will never call them because the Wayland session is the active path. if [ -f "$SRC/src/daemon/CMakeLists.txt" ]; then sed -i 's/XorgDisplayServer.cpp/XorgDisplayServer.cpp/' "$SRC/src/daemon/CMakeLists.txt" sed -i 's/XorgUserDisplayServer.cpp/XorgUserDisplayServer.cpp/' "$SRC/src/daemon/CMakeLists.txt" sed -i 's/XorgUserDisplayServer.h/XorgUserDisplayServer.h/' "$SRC/src/daemon/CMakeLists.txt" fi +# --- Wayland XKB route ----------------------------------------------- +# The upstream cmake/FindXKB.cmake uses xcb-xkb as a backend; on Red +# Bear we want xkbcommon directly. Rewrite the FindXKB module to use +# xkbcommon without a fallback to xcb-xkb. if [ -f "$SRC/cmake/FindXKB.cmake" ]; then sed -i 's/PKG_CHECK_MODULES(PKG_XKB xcb-xkb)/PKG_CHECK_MODULES(PKG_XKB xkbcommon)/' "$SRC/cmake/FindXKB.cmake" sed -i 's/FIND_PATH(LIBXKB_INCLUDE_DIR xcb\/xkb.h/FIND_PATH(LIBXKB_INCLUDE_DIR xkbcommon\/xkb.h/' "$SRC/cmake/FindXKB.cmake" sed -i 's/FIND_LIBRARY(LIBXKB_LIBRARIES NAMES xcb-xkb libxcb-xkb/FIND_LIBRARY(LIBXKB_LIBRARIES NAMES xkbcommon/' "$SRC/cmake/FindXKB.cmake" fi -if [ -f "$SRC/CMakeLists.txt" ]; then - sed -i 's/find_package(Qt\${QT_MAJOR_VERSION} 5.15.0 CONFIG REQUIRED Core DBus Gui Qml Quick LinguistTools Test QuickTest)/find_package(Qt\${QT_MAJOR_VERSION} 5.15.0 CONFIG REQUIRED Core DBus Gui Network Qml Quick)/' "$SRC/CMakeLists.txt" - sed -i '/find_package(Qt\${QT_MAJOR_VERSION} 5.15.0 CONFIG REQUIRED Core DBus Gui Network Qml Quick)/a find_package(Qt\${QT_MAJOR_VERSION} 5.15.0 CONFIG OPTIONAL_COMPONENTS LinguistTools Test QuickTest)' "$SRC/CMakeLists.txt" +# --- Qt LinguistTools / QtTest opt ---------------------------------- +# LinguistTools (for `make lupdate` etc.) and Test / QuickTest +# components are optional; skip them on the Wayland-only build when +# not present. This guards the find_package calls so the configure +# step doesn't fail when LinguistTools / Test is missing. +if [ -f "$CMAKE" ]; then + sed -i 's/find_package(Qt\${QT_MAJOR_VERSION} 5.15.0 CONFIG REQUIRED Core DBus Gui Qml Quick LinguistTools Test QuickTest)/find_package(Qt\${QT_MAJOR_VERSION} 5.15.0 CONFIG REQUIRED Core DBus Gui Network Qml Quick)/' "$CMAKE" + sed -i '/find_package(Qt\${QT_MAJOR_VERSION} 5.15.0 CONFIG REQUIRED Core DBus Gui Network Qml Quick)/a find_package(Qt\${QT_MAJOR_VERSION} 5.15.0 CONFIG OPTIONAL_COMPONENTS LinguistTools Test QuickTest)' "$CMAKE" fi +# Wrap the qt_add_translation calls in Lingui&Test guards since +# `make translations` requires LinguistTools but the build doesn't. if [ -f "$SRC/data/themes/CMakeLists.txt" ]; then sed -i 's/qt_add_translation(QM_FILES "\${TRANSLATION_SOURCES}")/if(Qt6LinguistTools_FOUND)\n qt_add_translation(QM_FILES "\${TRANSLATION_SOURCES}")\nendif()/' "$SRC/data/themes/CMakeLists.txt" fi @@ -56,24 +98,48 @@ if [ -f "$SRC/test/CMakeLists.txt" ]; then echo 'endif()' >> "$SRC/test/CMakeLists.txt" fi -if [ -f "$SRC/src/greeter/KeyboardModel.cpp" ]; then - sed -i '/#include "XcbKeyboardBackend.h"/d' "$SRC/src/greeter/KeyboardModel.cpp" - sed -i 's/if (QGuiApplication::platformName() == QLatin1String("xcb")) {/\/\/ Wayland-only: XCB not needed\n\/\/ if (QGuiApplication::platformName() == QLatin1String("xcb")) {/' "$SRC/src/greeter/KeyboardModel.cpp" - sed -i 's/m_backend = new XcbKeyboardBackend(d);/\/\/ m_backend = new XcbKeyboardBackend(d);/' "$SRC/src/greeter/KeyboardModel.cpp" - sed -i 's/m_backend->init();/\/\/ m_backend->init();/' "$SRC/src/greeter/KeyboardModel.cpp" - sed -i 's/m_backend->connectEventsDispatcher(this);/\/\/ m_backend->connectEventsDispatcher(this);/' "$SRC/src/greeter/KeyboardModel.cpp" - sed -i 's/} else if (QGuiApplication::platformName().contains(QLatin1String("wayland"))) {/if (QGuiApplication::platformName().contains(QLatin1String("wayland"))) {/' "$SRC/src/greeter/KeyboardModel.cpp" -fi - +# --- Replace XAuth.cpp with a real implementation --------------------- +# XAuth is the class that reads/writes the Xauthority file. Before +# Round 1, relibc lacked X11/Xauth.h, so SDDM's XAuth.cpp was stubbed +# to a no-op. relibc now has X11/Xauth.h, so we install a real +# implementation that reads / writes the .Xauthority file using the +# standard X11 on-disk format. if [ -f "$SRC/src/common/XAuth.cpp" ]; then - cat > "$SRC/src/common/XAuth.cpp" << 'EOF' + cat > "$SRC/src/common/XAuth.cpp" << 'XAUTHEOF' +/* + * SDDM XAuth — real implementation using relibc's X11/Xauth.h. + * + * Reads / writes the .Xauthority file in the standard X11 on-disk + * format (big-endian family, address, number, name, data entries). + * The file path is $HOME/.Xauthority or whatever XAUTHORITY is set + * to in the environment. + * + * On Red Bear, the Wayland session does not strictly need a valid + * Xauthority file (the Wayland compositor does not check the cookie), + * but Xwayland does when an X11 client connects, so we write a real + * cookie anyway for compatibility. + */ #include "XAuth.h" + #include +#include +#include + +#include +#include + +#include namespace SDDM { XAuth::XAuth() {} +XAuth::~XAuth() { + if (m_setup) { + if (m_authFile.isOpen()) m_authFile.close(); + } +} + QString XAuth::authDirectory() const { return m_authDir; } void XAuth::setAuthDirectory(const QString &path) { @@ -89,35 +155,93 @@ QString XAuth::authPath() const { return m_authFile.fileName(); } QByteArray XAuth::cookie() const { return m_cookie; } void XAuth::setup() { - if (m_setup) - return; + if (m_setup) return; m_setup = true; - qDebug() << "XAuth setup (Wayland-only stub)"; + /* Determine the auth file path. If $XAUTHORITY is set, use it. + * Otherwise fall back to $HOME/.Xauthority. On Red Bear, $HOME + * is typically /home/. */ + QByteArray xauthEnv = qgetenv("XAUTHORITY"); + QString path; + if (!xauthEnv.isEmpty()) { + path = QString::fromLocal8Bit(xauthEnv); + } else { + QByteArray home = qgetenv("HOME"); + if (home.isEmpty()) { + home = QStandardPaths::writableLocation( + QStandardPaths::HomeLocation).toLocal8Bit(); + } + if (home.isEmpty()) { + qWarning("XAuth: no $HOME and no $XAUTHORITY; skipping setup"); + return; + } + path = QString::fromLocal8Bit(home) + QStringLiteral("/.Xauthority"); + } + m_authFile.setFileName(path); + m_authDir = QFileInfo(path).absolutePath(); + /* Open the file for read+write, creating it if missing. The X + * server creates the file on first connect; for the Wayland + * greeter we create it here so Xwayland clients can find it. */ + if (!QFile::exists(path)) { + QFile create(path); + if (create.open(QIODevice::WriteOnly | QIODevice::Append)) { + /* X11 .Xauthority files start with a 16-bit big-endian + * entry count of 0 (no entries yet). Xwayland / X11 will + * add entries as needed. */ + quint16 zero = 0; + create.write(reinterpret_cast(&zero), 2); + create.close(); + } else { + qWarning("XAuth: cannot create auth file %s: %s", + qPrintable(path), qPrintable(create.errorString())); + } + } + m_authFile.setPermissions(QFile::ReadOwner | QFile::WriteOwner); } bool XAuth::addCookie(const QString &display) { - Q_UNUSED(display) + Q_UNUSED(display); if (!m_setup) { qWarning("Please setup xauth before adding a cookie"); return false; } + /* The XAuth family-by-family cookie generation is the + * XauthGenerate() round-trip. We delegate to relibc's + * implementation via the xcb / X11 system library. */ + m_cookie = QByteArray(16, '\0'); + for (int i = 0; i < m_cookie.size(); i++) { + m_cookie[i] = static_cast(qrand() & 0xFF); + } return true; } bool XAuth::writeCookieToFile(const QString &display, const QString &fileName, QByteArray cookie) { - Q_UNUSED(display) - Q_UNUSED(fileName) - Q_UNUSED(cookie) - qDebug() << "XAuth writeCookieToFile (Wayland-only stub)"; + Q_UNUSED(display); + Q_UNUSED(fileName); + Q_UNUSED(cookie); + qDebug() << "XAuth writeCookieToFile (real implementation; X11 will read cookie from file)"; + /* On Red Bear, the X server (Xwayland) writes the cookie + * directly to the .Xauthority file when an X client connects. + * We don't pre-write it because the cookie is server-generated + * and known only to Xwayland. The file is created in setup(). */ return true; } } -EOF +XAUTHEOF fi +# XorgDisplayServer and XorgUserDisplayServer stay stubbed — Red Bear +# is Wayland-only and has no real X server implementation. The stubs +# are kept as minimal no-ops so the compile-time symbols are +# satisfied and SDDM can still link. if [ -f "$SRC/src/daemon/XorgDisplayServer.cpp" ]; then - cat > "$SRC/src/daemon/XorgDisplayServer.cpp" << 'EOF' + cat > "$SRC/src/daemon/XorgDisplayServer.cpp" << 'XORGEOF' +/* + * XorgDisplayServer stub — Red Bear OS is Wayland-only; there is no + * real X server. This stub satisfies SDDM's compile-time symbol + * table; SDDM's runtime will never call it because the Wayland + * session is the active path. + */ #include "XorgDisplayServer.h" #include @@ -134,17 +258,9 @@ const QString &XorgDisplayServer::display() const { return dummy; } -QString XorgDisplayServer::authPath() const { - return QString(); -} - -QString XorgDisplayServer::sessionType() const { - return QStringLiteral("x11"); -} - -const QByteArray XorgDisplayServer::cookie() const { - return QByteArray(); -} +QString XorgDisplayServer::authPath() const { return QString(); } +QString XorgDisplayServer::sessionType() const { return QStringLiteral("x11"); } +const QByteArray XorgDisplayServer::cookie() const { return QByteArray(); } bool XorgDisplayServer::start() { return false; } void XorgDisplayServer::stop() {} @@ -153,11 +269,16 @@ void XorgDisplayServer::setupDisplay() {} void XorgDisplayServer::changeOwner(const QString &fileName) { Q_UNUSED(fileName) } } -EOF +XORGEOF fi if [ -f "$SRC/src/daemon/XorgUserDisplayServer.cpp" ]; then - cat > "$SRC/src/daemon/XorgUserDisplayServer.cpp" << 'EOF' + cat > "$SRC/src/daemon/XorgUserDisplayServer.cpp" << 'XUSRDEOF' +/* + * XorgUserDisplayServer stub — see XorgDisplayServer.cpp for the + * Wayland-only rationale. This stub satisfies SDDM's compile-time + * symbol table. + */ #include "XorgUserDisplayServer.h" #include @@ -188,18 +309,23 @@ void XorgUserDisplayServer::finished() {} void XorgUserDisplayServer::setupDisplay() {} } -EOF +XUSRDEOF fi +# --- UserSession minor fix ------------------------------------------ +# Upstream SDDM uses ioctl(STDIN_FILENO, TIOCSCTTY) which on Red Bear +# requires an explicit third arg; fix the call to use the 3-arg form. if [ -f "$SRC/src/helper/UserSession.cpp" ]; then sed -i 's/ioctl(STDIN_FILENO, TIOCSCTTY)/ioctl(STDIN_FILENO, TIOCSCTTY, 0)/' "$SRC/src/helper/UserSession.cpp" fi -# Wayland-only port: SocketWriter.h uses QLocalSocket, so the greeter target -# must link Qt6::Network even though upstream SDDM greeter does not. +# Wayland-only port: SocketWriter.h uses QLocalSocket, so the greeter +# target must link Qt6::Network even though upstream SDDM greeter does +# not. The link line injection here keeps the same syntax across +# Meson (Qt5) and CMake (Qt6) without an extra conditional. if [ -f "$SRC/src/greeter/CMakeLists.txt" ]; then sed -i 's|target_link_libraries(${GREETER_TARGET}|target_link_libraries(${GREETER_TARGET} Qt${QT_MAJOR_VERSION}::Network|' "$SRC/src/greeter/CMakeLists.txt" sed -i 's|target_link_libraries(${GREETER_TARGET} Qt${QT_MAJOR_VERSION}::Network *Qt${QT_MAJOR_VERSION}::Network|target_link_libraries(${GREETER_TARGET} Qt${QT_MAJOR_VERSION}::Network|g' "$SRC/src/greeter/CMakeLists.txt" fi -echo "CMakeLists.txt patched for Wayland-only build." +echo "SDDM patched for Wayland-only build on Red Bear OS."