Merge pull request #15 from fuddlesworth/qt-drop-x11

qt: drop X11/xcb support (Wayland-only frontend)
pull/12846/head
Nathan 2026-05-23 16:20:35 -05:00 committed by GitHub
commit d523efd22c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 26 additions and 59 deletions

View File

@ -32,9 +32,9 @@ include(GNUInstallDirs)
find_package(Qt6 REQUIRED COMPONENTS Gui Widgets OpenGL DBus
Multimedia Svg)
# WindowBlur + XkbTracker use qpa/qplatformnativeinterface.h to reach
# the wl_display / wl_surface / xcb_connection_t / wl_seat for native
# compositor calls (blur, layer-shell screen pinning, raw wl_keyboard
# listeners). The Qt-internal GuiPrivate module is tied to a specific
# the wl_display / wl_surface / wl_seat for native compositor calls
# (blur, layer-shell screen pinning, raw wl_keyboard listeners). The
# Qt-internal GuiPrivate module is tied to a specific
# Qt build, but every consumer of these headers ends up here there
# is no public alternative. Suppress the cosmetic
# `_qt_internal_show_private_module_warning` so the build is silent
@ -48,12 +48,11 @@ find_package(Qt6 QUIET OPTIONAL_COMPONENTS GuiPrivate)
# LayerShellQt: the quick terminal is a wlr-layer-shell dropdown window.
find_package(LayerShellQt REQUIRED)
# KWin background-blur is applied through the native compositor: the
# org_kde_kwin_blur Wayland protocol and the _KDE_NET_WM_BLUR atom on
# X11. Qt6::GuiPrivate gives the QPA native-handle accessors.
# KWin background-blur is applied through the native compositor via
# the org_kde_kwin_blur Wayland protocol. Qt6::GuiPrivate gives the
# QPA native-handle accessors.
find_package(PkgConfig REQUIRED)
pkg_check_modules(WAYLAND_CLIENT REQUIRED IMPORTED_TARGET wayland-client)
pkg_check_modules(XCB REQUIRED IMPORTED_TARGET xcb)
# libxkbcommon: derive the unshifted Unicode codepoint for a key event
# from its XKB keycode, so libghostty's kitty encoder finds an entry for
# punctuation keys (Qt's ev->key() reports the SHIFTED symbol, e.g.
@ -147,7 +146,6 @@ target_link_libraries(ghastty PRIVATE
Qt6::Multimedia
Qt6::Svg
PkgConfig::WAYLAND_CLIENT
PkgConfig::XCB
PkgConfig::XKBCOMMON
LayerShellQt::Interface
"${GHOSTTY_LINK_SO}"

View File

@ -712,8 +712,8 @@ void GhosttySurface::sendKey(QKeyEvent *ev, ghostty_input_action_e action) {
static_cast<unsigned char>(text.front()) >= 0x20 &&
static_cast<unsigned char>(text.front()) != 0x7f;
// On xcb nativeScanCode() is the X11/XKB keycode; the Wayland plugin
// likewise reports the XKB keycode, which is libghostty's Linux native.
// The Wayland plugin reports the XKB keycode via nativeScanCode(),
// which is libghostty's Linux-native input format.
const uint32_t keycode = ev->nativeScanCode();
// OR in any right-side bit for this keycode (e.g. Right-Shift sets

View File

@ -310,8 +310,8 @@ void MainWindow::showEvent(QShowEvent *event) {
if (m_firstTabPending)
QTimer::singleShot(250, this, [this] { createFirstTab(); });
// Apply background blur once the native (Wayland/X11) surface exists;
// a zero-delay timer defers past the platform-window creation.
// Apply background blur once the native Wayland surface exists; a
// zero-delay timer defers past the platform-window creation.
QTimer::singleShot(0, this, [this] { applyBlur(); });
}
@ -1257,13 +1257,11 @@ void MainWindow::setSizeLimits(uint32_t minW, uint32_t minH, uint32_t maxW,
}
// CELL_SIZE: store the value and apply window-step-resize. The
// `window-step-resize` config asks Qt to resize in cell increments;
// QWidget::setSizeIncrement is honored on X11 by most WMs but is
// usually ignored by Wayland compositors (the protocol has no
// equivalent of WM_NORMAL_HINTS step). Best-effort: it works where
// it works, no-op otherwise. Config docs explicitly say "currently
// only supported on macOS / has no effect on Linux," so this is
// strictly a bonus.
// `window-step-resize` config asks Qt to resize in cell increments
// via QWidget::setSizeIncrement, but Wayland has no equivalent of
// WM_NORMAL_HINTS step so compositors typically ignore it. Config
// docs explicitly say "currently only supported on macOS / has no
// effect on Linux," so this is strictly a bonus.
void MainWindow::setCellSize(uint32_t w, uint32_t h) {
m_cellSize = QSize(int(w), int(h));
if (config::boolean("window-step-resize", false))

View File

@ -1,6 +1,5 @@
#include "WindowBlur.h"
#include <cstdlib>
#include <cstring>
#include <QGuiApplication>
@ -12,8 +11,6 @@
#include <wayland-client.h>
#include <xcb/xcb.h>
#include "blur-client-protocol.h"
namespace {
@ -112,32 +109,6 @@ void applyWayland(QWindow *window, bool enabled) {
wl_display_flush(display);
}
// --- X11 (_KDE_NET_WM_BLUR_BEHIND_REGION) ----------------------------
void applyX11(QWindow *window, bool enabled) {
QPlatformNativeInterface *native = QGuiApplication::platformNativeInterface();
if (!native) return;
auto *conn = static_cast<xcb_connection_t *>(
native->nativeResourceForIntegration("connection"));
if (!conn) return;
const auto xid = static_cast<xcb_window_t>(window->winId());
static const char kName[] = "_KDE_NET_WM_BLUR_BEHIND_REGION";
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(
conn, xcb_intern_atom(conn, 0, std::strlen(kName), kName), nullptr);
if (!reply) return;
const xcb_atom_t atom = reply->atom;
std::free(reply);
if (enabled)
// An empty region property blurs the whole window.
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, xid, atom,
XCB_ATOM_CARDINAL, 32, 0, nullptr);
else
xcb_delete_property(conn, xid, atom);
xcb_flush(conn);
}
} // namespace
void applyWindowBlur(QWidget *window, bool enabled) {
@ -145,9 +116,10 @@ void applyWindowBlur(QWidget *window, bool enabled) {
QWindow *handle = window->windowHandle();
if (!handle) return; // not a native window yet
const QString platform = QGuiApplication::platformName();
if (platform.startsWith(QLatin1String("wayland")))
// The Qt frontend is Wayland-only (LayerShellQt + XkbTracker both
// require it). On any other QPA, blur is a no-op rather than a
// platform-specific port — the rest of the app would not function
// there in the first place.
if (QGuiApplication::platformName().startsWith(QLatin1String("wayland")))
applyWayland(handle, enabled);
else if (platform == QLatin1String("xcb"))
applyX11(handle, enabled);
}

View File

@ -3,10 +3,9 @@
class QWidget;
// Enable or disable KWin's "blur behind" effect for `window`, honoring
// the `background-blur` config. Works on KDE/KWin via the native
// compositor protocols — `org_kde_kwin_blur` on Wayland and the
// `_KDE_NET_WM_BLUR_BEHIND_REGION` property on X11 — and is a harmless
// no-op on compositors that do not advertise blur support.
// the `background-blur` config. Works on KDE/KWin via the
// `org_kde_kwin_blur` Wayland protocol; a harmless no-op on
// compositors that do not advertise blur support.
//
// The whole window is blurred; only the terminal's translucent pixels
// actually show the effect, so no per-region calculation is needed.

View File

@ -13,7 +13,7 @@
// True when any argv entry starts with `+` — i.e. the user invoked a
// libghostty CLI action (`+show-config`, `+list-fonts`, `+version`, …).
// We detect early so the CLI path can run without paying the cost of
// constructing a QApplication (which opens a Wayland/X11 connection
// constructing a QApplication (which opens a Wayland connection
// only to exit).
static bool isCliActionInvocation(int argc, char **argv) {
for (int i = 1; i < argc; ++i) {
@ -77,8 +77,8 @@ int main(int argc, char **argv) {
QCoreApplication::setOrganizationName(QStringLiteral("ghastty"));
// Match the installed ghastty.desktop: this becomes the Wayland app-id
// (and X11 WM_CLASS), so the compositor associates the window with the
// desktop entry — taskbar icon, launcher identity.
// so the compositor associates the window with the desktop entry —
// taskbar icon, launcher identity.
QGuiApplication::setDesktopFileName(QStringLiteral("ghastty"));
// The window icon, embedded so it works even running from the build