# Hyprland XWayland Integration: Architecture, Lifecycle, and Configuration

> Explore Hyprland XWayland integration architecture. Learn about its lifecycle, configuration, and how it bridges X11 apps to Wayland for seamless compatibility. Optimize your setup now.

- Repository: [Hypr Development/Hyprland](https://github.com/hyprwm/Hyprland)
- Tags: architecture
- Published: 2026-07-26

---

**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`](https://github.com/hyprwm/Hyprland/blob/main/src/xwayland/XWayland.hpp) and implemented in [`src/xwayland/XWayland.cpp`](https://github.com/hyprwm/Hyprland/blob/main/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`](https://github.com/hyprwm/Hyprland/blob/main/src/xwayland/Server.hpp) and defined in [`src/xwayland/Server.cpp`](https://github.com/hyprwm/Hyprland/blob/main/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`](https://github.com/hyprwm/Hyprland/blob/main/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`](https://github.com/hyprwm/Hyprland/blob/main/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.

   ```cpp
   // 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`](https://github.com/hyprwm/Hyprland/blob/main/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:

```ini

# 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`](https://github.com/hyprwm/Hyprland/blob/main/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.

```bash

# Check if XWayland is running

hyprctl version | grep XWayland

# List X11 windows

hyprctl clients | grep X11

```

## Practical Code Examples

### Enabling XWayland at Runtime

```cpp
#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

```cpp
#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

```cpp
#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

```cpp
#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`](https://github.com/hyprwm/Hyprland/blob/main/src/xwayland/XWayland.cpp), `CXWaylandServer` in [`src/xwayland/Server.cpp`](https://github.com/hyprwm/Hyprland/blob/main/src/xwayland/Server.cpp), and `CHyprXWaylandManager` in [`src/managers/XWaylandManager.hpp`](https://github.com/hyprwm/Hyprland/blob/main/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`](https://github.com/hyprwm/Hyprland/blob/main/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`](https://github.com/hyprwm/Hyprland/blob/main/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`](https://github.com/hyprwm/Hyprland/blob/main/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.