Hyprland XWayland Integration: Architecture, Lifecycle, and Configuration
Hyprland XWayland integration bridges legacy X11 applications to the Wayland compositor via the CXWayland façade, CXWaylandServer process wrapper, and CHyprXWaylandManager geometry utilities, supporting both runtime toggling and compile-time exclusion.
Hyprland XWayland integration is implemented as an optional subsystem in the hyprwm/Hyprland repository that lets legacy X11 clients run seamlessly under the Wayland compositor. The architecture splits responsibilities across three core C++ classes that manage server lifecycle, socket communication, and surface translation. Understanding these internals helps developers debug X11 application behavior, customize cursor handling, and optimize startup performance according to the Hyprland source code.
Hyprland XWayland Architecture
The source code in hyprwm/Hyprland organizes XWayland support into three distinct layers that isolate process management, protocol translation, and utility helpers.
CXWayland: High-Level Facade
Defined in src/xwayland/XWayland.hpp and implemented in src/xwayland/XWayland.cpp, the CXWayland class serves as the primary entry point. It constructs CXWaylandServer, exposes enabled() to query subsystem state, and forwards cursor images through setCursor().
CXWaylandServer: Process and Socket Management
CXWaylandServer, declared in src/xwayland/Server.hpp and defined in src/xwayland/Server.cpp, wraps the Xwayland binary. It creates communication sockets, spawns the process via runXWayland, and tracks the client connection through m_xwaylandClient.
CHyprXWaylandManager: Geometry and Surface Translation
Declared in src/managers/XWaylandManager.hpp and used throughout the compositor, this utility class translates coordinate spaces and manipulates X11 window state. Key helpers include xwaylandToWaylandCoords and waylandToXWaylandCoords, along with window operations such as sendCloseWindow.
XWayland Lifecycle and Startup Sequence
The startup and shutdown sequence follows a strict order inside the compositor.
-
Construction. When Hyprland starts, it instantiates
CXWaylandwith thewantsEnabledflag read from configuration. Insrc/xwayland/XWayland.cpp, the constructor checks#ifndef NO_XWAYLANDand, if the flag is false, clears theDISPLAYenvironment variable and closes existing X windows.// src/xwayland/XWayland.cpp CXWayland::CXWayland(const bool wantsEnabled) { #ifndef NO_XWAYLAND if (!wantsEnabled) { ... } ... -
Executable Detection. Before spawning, Hyprland verifies that the
Xwaylandbinary exists in$PATHusingNFsUtils::executableExistsInPath. -
Server Creation.
CXWaylandServer::create()opens display sockets and launches the XWayland process. On success,CXWayland::m_enabledis set totrue. -
XWM Initialization. Once the server is ready, an X window manager (
CXWM) is instantiated fromsrc/xwayland/XWM.hpp. It handles ICCCM and EWMH atoms, window mapping, and cursor setting. -
Cursor Forwarding. Hyprland propagates cursor changes to X clients by calling
CXWayland::setCursor, which proxies the request toCXWM::setCursor. -
Coordinate Translation.
CHyprXWaylandManagerkeeps positioning consistent by converting between X11 and native Wayland geometries. -
Shutdown. On exit or runtime disable, the server and XWM are destroyed, sockets are closed, and
DISPLAYis unset.
Configuration and Build Options
Runtime Toggle
XWayland can be enabled or disabled at runtime through the Hyprland configuration file:
# Enable XWayland (default is enabled)
exec = "Hyprland"
# To disable:
# exec = "Hyprland --no-xwayland"
Compile-Time Exclusion
For minimal builds, defining NO_XWAYLAND at compile time strips out all XWayland code paths entirely. When this macro is present, CXWayland construction becomes a no-op and no X11 server is spawned.
Cursor Handling and Coordinate Translation
Hyprland forwards cursor images to the XWayland subsystem through the façade, while the manager class ensures that window geometry remains consistent across protocol boundaries.
CXWayland::setCursor– Accepts RGBA pixel data, stride, size, and hotspot, then delegates toCXWM::setCursoras implemented insrc/xwayland/XWayland.cpp.CHyprXWaylandManager::xwaylandToWaylandCoords– Converts X11 surface coordinates to the compositor’s native space.CHyprXWaylandManager::waylandToXWaylandCoords– Performs the inverse mapping for outgoing events.
Querying XWayland State via IPC
Hyprland exposes the XWayland state through its IPC interface. You can verify that XWayland is running and inspect X11 clients without reading source logs.
# Check if XWayland is running
hyprctl version | grep XWayland
# List X11 windows
hyprctl clients | grep X11
Practical Code Examples
Enabling XWayland at Runtime
#include <hyprland/src/xwayland/XWayland.hpp>
// Somewhere in your initialization code
bool wantXWayland = true; // or read from a config option
g_pXWayland = std::make_unique<CXWayland>(wantXWayland);
if (g_pXWayland->enabled()) {
std::cout << "XWayland is active on display " << getenv("DISPLAY") << "\n";
}
Setting a Custom Cursor for X Clients
#include <hyprland/src/xwayland/XWayland.hpp>
unsigned char* imgData = ...; // RGBA pixel data
uint32_t stride = width * 4;
Vector2D size = {width, height};
Vector2D hotspot = {width / 2, height / 2};
if (g_pXWayland && g_pXWayland->enabled())
g_pXWayland->setCursor(imgData, stride, size, hotspot);
Translating Coordinates
#include <hyprland/src/managers/XWaylandManager.hpp>
Vector2D wlPos = {100, 200};
Vector2D xPos = g_pXWaylandManager->waylandToXWaylandCoords(wlPos);
std::cout << "Wayland " << wlPos << " => XWayland " << xPos << "\n";
Closing an X11 Window Programmatically
#include <hyprland/src/managers/XWaylandManager.hpp>
PHLWINDOW xWindow = ...; // Obtained from hyprctl or internal lookup
g_pXWaylandManager->sendCloseWindow(xWindow);
Summary
- Three main classes compose the Hyprland XWayland integration:
CXWaylandinsrc/xwayland/XWayland.cpp,CXWaylandServerinsrc/xwayland/Server.cpp, andCHyprXWaylandManagerinsrc/managers/XWaylandManager.hpp. - Startup verification includes an executable check via
NFsUtils::executableExistsInPathbeforeCXWaylandServer::create()opens display sockets. - Cursor and geometry synchronization is handled by
CXWayland::setCursorand the coordinate conversion helpers inCHyprXWaylandManager. - Compile-time removal is controlled by the
NO_XWAYLANDmacro, while runtime state can be inspected withhyprctl.
Frequently Asked Questions
How does Hyprland start the XWayland server?
Hyprland constructs CXWayland with a wantsEnabled flag, verifies the Xwayland binary exists in $PATH, then invokes CXWaylandServer::create() to open sockets and spawn the process via runXWayland. After the server signals readiness, the CXWM window manager initializes in src/xwayland/XWM.hpp to handle ICCCM and EWMH protocols.
Can I disable XWayland in Hyprland?
Yes. Launch Hyprland with the --no-xwayland flag to disable it at runtime. For minimal builds, define NO_XWAYLAND at compile time to remove all XWayland code paths, including CXWayland, CXWaylandServer, and CXWM.
What does CHyprXWaylandManager do?
CHyprXWaylandManager, declared in src/managers/XWaylandManager.hpp, provides surface handling and geometry utilities such as xwaylandToWaylandCoords and waylandToXWaylandCoords. It also exposes X11-specific window operations like sendCloseWindow.
How are cursors shared between Wayland and XWayland?
The compositor forwards cursor images through CXWayland::setCursor, defined in src/xwayland/XWayland.cpp, which proxies the RGBA data directly to CXWM::setCursor. This ensures X11 clients render the same cursor shape as native Wayland applications.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →