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.

  1. Construction. When Hyprland starts, it instantiates CXWayland with the wantsEnabled flag read from configuration. In src/xwayland/XWayland.cpp, the constructor checks #ifndef NO_XWAYLAND and, if the flag is false, clears the DISPLAY environment variable and closes existing X windows.

    // src/xwayland/XWayland.cpp
    CXWayland::CXWayland(const bool wantsEnabled) {
        #ifndef NO_XWAYLAND
        if (!wantsEnabled) { ... }
        ...
  2. Executable Detection. Before spawning, Hyprland verifies that the Xwayland binary exists in $PATH using NFsUtils::executableExistsInPath.

  3. Server Creation. CXWaylandServer::create() opens display sockets and launches the XWayland process. On success, CXWayland::m_enabled is set to true.

  4. XWM Initialization. Once the server is ready, an X window manager (CXWM) is instantiated from src/xwayland/XWM.hpp. It handles ICCCM and EWMH atoms, window mapping, and cursor setting.

  5. Cursor Forwarding. Hyprland propagates cursor changes to X clients by calling CXWayland::setCursor, which proxies the request to CXWM::setCursor.

  6. Coordinate Translation. CHyprXWaylandManager keeps positioning consistent by converting between X11 and native Wayland geometries.

  7. Shutdown. On exit or runtime disable, the server and XWM are destroyed, sockets are closed, and DISPLAY is 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 to CXWM::setCursor as implemented in src/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: CXWayland in src/xwayland/XWayland.cpp, CXWaylandServer in src/xwayland/Server.cpp, and CHyprXWaylandManager in src/managers/XWaylandManager.hpp.
  • Startup verification includes an executable check via NFsUtils::executableExistsInPath before CXWaylandServer::create() opens display sockets.
  • Cursor and geometry synchronization is handled by CXWayland::setCursor and the coordinate conversion helpers in CHyprXWaylandManager.
  • Compile-time removal is controlled by the NO_XWAYLAND macro, while runtime state can be inspected with hyprctl.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →