Skip to content

Instantly share code, notes, and snippets.

@robertkirkman
Last active November 21, 2025 19:19
Show Gist options
  • Select an option

  • Save robertkirkman/8cf5020ccbfe2118cc0972e0691d8903 to your computer and use it in GitHub Desktop.

Select an option

Save robertkirkman/8cf5020ccbfe2118cc0972e0691d8903 to your computer and use it in GitHub Desktop.
Gentoo Mod: wayland-free Gentoo.

Warning

This is a downstream solution to https://bugs.gentoo.org/923305. Upstream should continue to focus on supporting systems where wayland is unmasked because this masked-wayland configuration is NOT necessary for normal users. Do not ask for support with this in Gentoo channels, instead use the comments section here.

How to use Gentoo without installing Wayland - period.

  1. Add the package.mask and package.use lines below to their respective locations in /etc/portage/
  2. Save each X-Y.patch file in a new folder in /etc/portage/patches/ following the pattern /etc/portage/patches/X/Y/ - you can reference Gentoo Package Search and Gentoo Wiki if you are unsure how to use /etc/portage/patches/
  3. Save emerge-sync-purge-wayland.sh anywhere with any filename and from now on, run it instead of emerge --sync
  4. Run emerge-sync-purge-wayland.sh, then perform a world upgrade with emerge -avuDU world followed (after the first completely successful world upgrade) by emerge -c
#!/bin/bash
emerge --sync || exit 1
unnecessarily_wayland_depending_packages=(
'guru/gnome-extra/yad'
'gentoo/media-video/obs-studio'
'gentoo/games-util/heroic-bin'
'gentoo/kde-frameworks/kauth'
'gentoo/x11-misc/pcmanfm-qt'
'gentoo/x11-misc/screengrab'
'gentoo/kde-plasma/polkit-kde-agent'
'gentoo/app-office/libreoffice'
'gentoo/dev-util/android-studio'
)
ebuild_repo_path=/var/db/repos
for package in "${unnecessarily_wayland_depending_packages[@]}"
do
for ebuild in $(find $ebuild_repo_path/$package -type f)
do
echo "purging wayland from: $ebuild"
sed -i -e '/dev-libs\/wayland/d' \
-e '/dev-qt\/qtwayland/d' \
-e 's/\[wayland\]//' \
-e 's/\[wayland,X\]/\[X\]/g' \
-e '/kde-plasma\/layer-shell-qt/d' \
-e '/kde-plasma\/libplasma/d' \
$ebuild
done
done
--- a/src/backends/polkit-1/Polkit1Backend.cpp
+++ b/src/backends/polkit-1/Polkit1Backend.cpp
@@ -11,7 +11,6 @@
#include "Polkit1Backend.h"
#include "kauthdebug.h"
-#include <KWaylandExtras>
#include <KWindowSystem>
#include <QCoreApplication>
@@ -66,22 +65,6 @@ void Polkit1Backend::preAuthAction(const QString &action, QWindow *parentWindow)
// Are we running our KDE auth agent?
if (QDBusConnection::sessionBus().interface()->isServiceRegistered(QLatin1String("org.kde.polkit-kde-authentication-agent-1"))) {
- if (KWindowSystem::isPlatformWayland()) {
- KWaylandExtras::exportWindow(parentWindow);
- connect(
- KWaylandExtras::self(),
- &KWaylandExtras::windowExported,
- this,
- [this, action, parentWindow](QWindow *window, const QString &handle) {
- if (window == parentWindow) {
- sendWindowHandle(action, handle);
- }
- },
- Qt::SingleShotConnection);
-
- // Generate and send an XDG Activation token.
- sendActivationToken(action, parentWindow);
- } else {
// Retrieve the dialog root window Id
const qulonglong wId = parentWindow->winId();
@@ -97,7 +80,6 @@ void Polkit1Backend::preAuthAction(const QString &action, QWindow *parentWindow)
if (reply.type() != QDBusMessage::ReplyMessage) {
qWarning() << "Failed to set window id" << wId << "for" << action << reply.errorMessage();
}
- }
} else {
qCDebug(KAUTH) << "KDE polkit agent appears too old or not registered on the bus";
}
@@ -124,33 +106,6 @@ void Polkit1Backend::sendWindowHandle(const QString &action, const QString &hand
void Polkit1Backend::sendActivationToken(const QString &action, QWindow *window)
{
- const auto requestedSerial = KWaylandExtras::lastInputSerial(window);
- connect(
- KWaylandExtras::self(),
- &KWaylandExtras::xdgActivationTokenArrived,
- this,
- [this, requestedSerial, action](quint32 serial, const QString &token) {
- if (serial != requestedSerial || token.isEmpty()) {
- return;
- }
- QDBusMessage methodCall =
- QDBusMessage::createMethodCall(c_kdeAgentService, c_kdeAgentPath, c_kdeAgentInterface, QLatin1String("setActivationTokenForAction"));
- methodCall << action;
- methodCall << token;
-
- const auto reply = QDBusConnection::sessionBus().asyncCall(methodCall);
- auto *watcher = new QDBusPendingCallWatcher(reply, this);
- connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, watcher, token, action] {
- watcher->deleteLater();
-
- QDBusPendingReply<> reply = *watcher;
- if (reply.isError()) {
- qCWarning(KAUTH) << "Failed to set activation token" << token << "for" << action << reply.error().message();
- }
- });
- },
- Qt::SingleShotConnection);
- KWaylandExtras::requestXdgActivationToken(window, requestedSerial, {});
}
Action::AuthStatus Polkit1Backend::authorizeAction(const QString &action)
diff --git a/modules/gui/qt/util/csdmenu.cpp b/modules/gui/qt/util/csdmenu.cpp
index b9d2cc7c85..09601bfa94 100644
--- a/modules/gui/qt/util/csdmenu.cpp
+++ b/modules/gui/qt/util/csdmenu.cpp
@@ -156,16 +156,6 @@ public:
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
- if (m_plateform == QT_CSD_PLATFORM_WAYLAND)
- {
- info.platform = QT_CSD_PLATFORM_WAYLAND;
-
- auto appNative = qApp->nativeInterface<QNativeInterface::QWaylandApplication>();
- auto windowNative = window->nativeInterface<QNativeInterface::Private::QWaylandWindow>();
-
- info.data.wayland.display = appNative->display();
- info.data.wayland.toplevel = windowNative->surfaceRole<xdg_toplevel>();
- }
#endif // QT 6.5
#endif // QT_GUI_PRIVATE
#endif // _WIN32
@@ -301,14 +291,6 @@ void CSDMenu::popup(const QPoint &pos)
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
- if (d->m_plateform == QT_CSD_PLATFORM_WAYLAND)
- {
- event.platform = QT_CSD_PLATFORM_WAYLAND;
- auto appNative = qApp->nativeInterface<QNativeInterface::QWaylandApplication>();
- assert(appNative);
- event.data.wayland.seat = appNative->lastInputSeat();
- event.data.wayland.serial = appNative->lastInputSerial();
- }
#endif // Qt 6.5
#endif // QT_GUI_PRIVATE
#endif // _WIN32
dev-libs/wayland
x11-base/xwayland
dev-util/wayland-scanner
dev-libs/wayland-protocols
kde-plasma/layer-shell-qt
*/* -wayland
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -26,7 +26,6 @@ find_package(Qt6LinguistTools ${QT_MINIMUM_VERSION} REQUIRED)
find_package(Qt6Widgets ${QT_MINIMUM_VERSION} REQUIRED)
find_package(fm-qt6 ${LIBFMQT_MINIMUM_VERSION} REQUIRED)
find_package(lxqt2-build-tools ${LXQTBT_MINIMUM_VERSION} REQUIRED)
-find_package(LayerShellQt ${SHELLQT_MINIMUM_VERSION} REQUIRED)
message(STATUS "Building ${PROJECT_NAME} with Qt ${Qt6Core_VERSION}")
diff --git a/pcmanfm/CMakeLists.txt b/pcmanfm/CMakeLists.txt
index c670d2d..dd98b1e 100644
--- a/pcmanfm/CMakeLists.txt
+++ b/pcmanfm/CMakeLists.txt
@@ -90,7 +90,6 @@ target_include_directories(pcmanfm-qt
target_link_libraries(pcmanfm-qt
Qt6::Widgets
Qt6::DBus
- LayerShellQtInterface
fm-qt6
)
diff --git a/pcmanfm/desktopwindow.cpp b/pcmanfm/desktopwindow.cpp
index 8b5d774..c28b32c 100644
--- a/pcmanfm/desktopwindow.cpp
+++ b/pcmanfm/desktopwindow.cpp
@@ -43,9 +43,6 @@
#include <QRandomGenerator>
#include <QToolTip>
-#include <LayerShellQt/shell.h>
-#include <LayerShellQt/window.h>
-
#include "./application.h"
#include "mainwindow.h"
#include <libfm-qt6/foldermenu.h>
@@ -193,25 +190,6 @@ DesktopWindow::DesktopWindow(int screenNum):
shortcut = new QShortcut(QKeySequence(Qt::SHIFT | Qt::Key_Delete), this); // force delete
connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onDeleteActivated);
-
- // under Wayland, set the layer and anchors as well as window transparency
- if(static_cast<Application*>(qApp)->underWayland()) {
- setAttribute(Qt::WA_TranslucentBackground);
- winId();
- if(QWindow* win = windowHandle()) {
- if(LayerShellQt::Window* layershell = LayerShellQt::Window::get(win)) {
- layershell->setLayer(LayerShellQt::Window::Layer::LayerBackground);
- LayerShellQt::Window::Anchors anchors = {LayerShellQt::Window::AnchorTop
- | LayerShellQt::Window::AnchorBottom
- | LayerShellQt::Window::AnchorLeft
- | LayerShellQt::Window::AnchorRight};
- layershell->setAnchors(anchors);
- layershell->setKeyboardInteractivity(LayerShellQt::Window::KeyboardInteractivityOnDemand);
- layershell->setExclusiveZone(-1); // not moved to accommodate for other surfaces
- layershell->setScope(QStringLiteral("desktop")); // just for distinguishing it
- }
- }
- }
}
DesktopWindow::~DesktopWindow() {
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 52b3766..cbd7f4d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -22,9 +22,7 @@ set(LXQTBT_MINIMUM_VERSION "2.2.0")
find_package(Qt6Network ${QT_MINIMUM_VERSION} REQUIRED)
find_package(Qt6Widgets ${QT_MINIMUM_VERSION} REQUIRED)
-find_package(Qt6WaylandClient ${QT_MINIMUM_VERSION} REQUIRED)
find_package(Qt6LinguistTools ${QT_MINIMUM_VERSION} REQUIRED)
-find_package(LayerShellQt ${SHELLQT_MINIMUM_VERSION} REQUIRED)
find_package(KF6WindowSystem ${KF6_MINIMUM_VERSION} REQUIRED)
find_package(lxqt2-build-tools ${LXQTBT_MINIMUM_VERSION} REQUIRED)
@@ -115,8 +113,6 @@ set(SCREENGRAB_SRC
src/core/ui/configwidget.cpp
src/core/ui/about.cpp
src/core/ui/mainwindow.cpp
- src/core/wayland/ScreenCopy.cpp
- src/core/wayland/ScreenShot.cpp
)
if(SG_DBUS_NOTIFY)
@@ -208,12 +204,7 @@ if (XCB_XFIXES_FOUND)
endif()
# Link with Network. See pull#86. TODO: Should be optional when upload module is needed.
-target_link_libraries(screengrab qkeysequencewidget Qt6::Widgets KF6::WindowSystem Qt6::Network ${X11_LIBRARIES}
-LayerShellQtInterface Qt6::GuiPrivate Qt6::WaylandClient Qt6::WaylandClientPrivate Qt6::WaylandGlobalPrivate)
-
-qt6_generate_wayland_protocol_client_sources(screengrab FILES
- ${CMAKE_CURRENT_SOURCE_DIR}/src/core/wayland/wlr-screencopy-unstable-v1.xml
-)
+target_link_libraries(screengrab qkeysequencewidget Qt6::Widgets KF6::WindowSystem Qt6::Network ${X11_LIBRARIES})
# installing
install(TARGETS screengrab RUNTIME DESTINATION bin)
diff --git a/src/core/core.cpp b/src/core/core.cpp
index aa8ac50..80e53b8 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -47,7 +47,6 @@
#include "dbusnotifier.h"
#endif
-#include "wayland/ScreenShot.h"
Core* Core::corePtr = nullptr;
@@ -308,21 +307,6 @@ void Core::waylandScreenShot(bool delayed)
}
default: // for now, we can take only a fullscreen shot
{
- auto ws = new LXQt::Wayland::ScreenShot(_conf->getIncludeCursor(),
- _wnd->selectedScreen(),
- QRect(),
- this);
- connect(ws, &LXQt::Wayland::ScreenShot::screenShotReady, this,
- [this, ws] (const QPixmap& pixmap) {
- if (!pixmap.isNull())
- {
- *_pixelMap = pixmap;
- checkAutoSave();
- _wnd->updatePixmap(_pixelMap);
- }
- showScreenshot();
- ws->deleteLater();
- });
break;
}
}
@@ -330,26 +314,6 @@ void Core::waylandScreenShot(bool delayed)
void Core::takeWaylandAreaScreenshot(bool checkCursor)
{
- if (_selector == nullptr)
- return;
- auto ws = new LXQt::Wayland::ScreenShot(checkCursor ? _conf->getIncludeCursor() : false,
- _wnd->selectedScreen(),
- _selector->getSelectionRect(),
- this);
- connect(ws, &LXQt::Wayland::ScreenShot::screenShotReady, this,
- [this, ws] (const QPixmap& pixmap) {
- if (!pixmap.isNull())
- {
- *_pixelMap = pixmap;
- checkAutoSave();
- _wnd->updatePixmap(_pixelMap);
- }
- showScreenshot();
- _lastSelectedArea = _selector->getSelectionRect();
- _selector->deleteLater();
- _selector = nullptr;
- ws->deleteLater();
- });
}
void Core::showScreenshot()
diff --git a/src/core/regionselect.cpp b/src/core/regionselect.cpp
index 3cfd85e..89c0da2 100644
--- a/src/core/regionselect.cpp
+++ b/src/core/regionselect.cpp
@@ -20,8 +20,6 @@
#include <QApplication>
-#include <LayerShellQt/shell.h>
-#include <LayerShellQt/window.h>
RegionSelect::RegionSelect(Config *mainconf, QScreen *screen, QWidget *parent)
:QWidget(parent)
@@ -113,26 +111,6 @@ void RegionSelect::sharedInit()
void RegionSelect::showEvent(QShowEvent *event)
{
- if (QGuiApplication::platformName() == QStringLiteral("wayland"))
- {
- winId();
- if (QWindow* win = windowHandle())
- {
- if (LayerShellQt::Window* layershell = LayerShellQt::Window::get(win))
- {
- layershell->setLayer(LayerShellQt::Window::Layer::LayerOverlay);
- LayerShellQt::Window::Anchors anchors = {LayerShellQt::Window::AnchorTop
- | LayerShellQt::Window::AnchorBottom
- | LayerShellQt::Window::AnchorLeft
- | LayerShellQt::Window::AnchorRight};
- layershell->setAnchors(anchors);
- layershell->setKeyboardInteractivity(LayerShellQt::Window::KeyboardInteractivityExclusive);
- layershell->setExclusiveZone(-1); // not moved to accommodate for other surfaces
- win->setScreen(_selectedScreen == nullptr ? qApp->primaryScreen() : _selectedScreen);
- layershell->setScreenConfiguration(LayerShellQt::Window::ScreenConfiguration::ScreenFromQWindow);
- }
- }
- }
QWidget::showEvent(event);
}
@robertkirkman
Copy link
Author

If you use a VLC version at this commit or newer, the VLC patch is no longer required.

Reportedly, the edge case that resulted in upstream accepting a change to support building without having Wayland installed, was a MacOS build, so this is an example of a fix for a popular closed-source use-case having a beneficial side effect for an obscure fully-open-source use-case (pure Xorg).

In the future, maybe continued popular use of MacOS alongside Wayland like that will preserve the ecosystem diversity sufficiently to make backporting software to pure Xorg a little bit easier from time to time, as pure Xorg gradually loses more popularity.

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