# How to Create Custom Window Decorations Using the Hyprland Plugin API

> Learn how to create custom window decorations in Hyprland using the Plugin API. Implement IHyprWindowDecoration and register your plugin to enhance your window management experience.

- Repository: [Hypr Development/Hyprland](https://github.com/hyprwm/Hyprland)
- Tags: how-to-guide
- Published: 2026-07-23

---

**Yes, you can add custom window decorations by implementing the `IHyprWindowDecoration` interface in a C++ plugin and registering it via `hyprland::addWindowDecoration()`.**

Hyprland’s modular architecture extends beyond static configuration into native plugin development. The compositor exposes a **window decoration interface** in [`src/render/decorations/IHyprWindowDecoration.hpp`](https://github.com/hyprwm/Hyprland/blob/main/src/render/decorations/IHyprWindowDecoration.hpp) that allows developers to draw custom visual elements—ranging from drop shadows to entirely novel window chrome—around client windows using the Hyprland Plugin API.

## Understanding the IHyprWindowDecoration Interface

The abstract base class `IHyprWindowDecoration` defines the contract between the compositor and your custom code. Located in [`src/render/decorations/IHyprWindowDecoration.hpp`](https://github.com/hyprwm/Hyprland/blob/main/src/render/decorations/IHyprWindowDecoration.hpp), this interface requires you to implement virtual methods that govern lifecycle, layering, and spatial positioning.

### Core Lifecycle and Layering Methods

Every decoration must declare its type and render layer to Hyprland’s rendering engine. The `getDecorationType()` method returns an `eDecorationType` (such as `DECORATION_TYPE_CUSTOM`), while `getDecorationLayer()` selects whether your content draws in the background, normal, or overlay layer. The `getDecorationFlags()` method returns bitflags—such as `DECORATION_ALLOWS_MOUSE_INPUT`—that control interaction and compositing behavior.

### Positioning and Geometry Negotiation

The positioning system uses a request-reply pattern. Your implementation of `getPositioningInfo()` returns an `SDecorationPositioningInfo` struct specifying policy (absolute coordinates or sticky to window edges). After Hyprland calculates the final geometry via [`src/render/decorations/DecorationPositioner.hpp`](https://github.com/hyprwm/Hyprland/blob/main/src/render/decorations/DecorationPositioner.hpp), it communicates the result through `onPositioningReply()`, passing an `SDecorationPositioningReply` containing the assigned `SBoxExtents` rectangle.

## Implementing the Decoration Class

Create a concrete subclass of `IHyprWindowDecoration` in your plugin source. The constructor receives a `PHLWINDOW` pointer representing the target window. Override the virtual methods to define behavior, and implement a `render()` method—invoked by the GLRenderer during the compositing loop—to execute OpenGL commands within your allocated rectangle.

```cpp
/* MyDecoration.hpp */
#pragma once
#include "src/render/decorations/IHyprWindowDecoration.hpp"

class MyDecoration : public IHyprWindowDecoration {
public:
    MyDecoration(PHLWINDOW pWindow) : IHyprWindowDecoration(pWindow) {}
    virtual ~MyDecoration() = default;

    eDecorationType getDecorationType() override { 
        return DECORATION_TYPE_CUSTOM; 
    }

    eDecorationLayer getDecorationLayer() override { 
        return DECORATION_LAYER_OVER; 
    }

    uint64_t getDecorationFlags() override { 
        return DECORATION_ALLOWS_MOUSE_INPUT; 
    }

    SDecorationPositioningInfo getPositioningInfo() override {
        SDecorationPositioningInfo info;
        info.policy = DECORATION_POSITION_ABSOLUTE;
        return info;
    }

    void onPositioningReply(const SDecorationPositioningReply& reply) override {
        m_box = reply.box;
    }

    void render() {
        // OpenGL rendering within m_box
        glBegin(GL_QUADS);
        glColor4f(0.2f, 0.6f, 0.9f, 0.8f);
        glVertex2f(m_box.x, m_box.y);
        glVertex2f(m_box.x + m_box.w, m_box.y);
        glVertex2f(m_box.x + m_box.w, m_box.y + m_box.h);
        glVertex2f(m_box.x, m_box.y + m_box.h);
        glEnd();
    }

private:
    SBoxExtents m_box{};
};

```

## Registering the Plugin with Hyprland

Registration occurs in the plugin entry point defined in [`hyprpm/src/core/Plugin.hpp`](https://github.com/hyprwm/Hyprland/blob/main/hyprpm/src/core/Plugin.hpp). Use the templated function `hyprland::addWindowDecoration()` to bind your class to a configuration identifier.

```cpp
/* plugin.cpp */
#include <hyprpm/src/core/Plugin.hpp>
#include "MyDecoration.hpp"

extern "C" PLUGIN_EXPORT void plugin_init() {
    hyprland::addWindowDecoration<MyDecoration>("my_custom_deco");
}

```

## Activating the Decoration via Configuration

Once loaded, enable the decoration using Hyprland’s configuration syntax. Add the registration name to your [`hyprland.conf`](https://github.com/hyprwm/Hyprland/blob/main/hyprland.conf):

```ini

# ~/.config/hpr/hyprland.conf

decoration:my_custom_deco

```

You can apply this globally or target specific applications using window rules.

## Key Source Files and Reference Implementations

Study built-in decorators to understand texture handling and geometry calculations. The drop-shadow implementation demonstrates opacity management and multi-pass rendering.

- **`[`src/render/decorations/IHyprWindowDecoration.hpp`](https://github.com/hyprwm/Hyprland/blob/main/src/render/decorations/IHyprWindowDecoration.hpp)`** – Abstract interface defining `getDecorationType()`, `getPositioningInfo()`, and rendering callbacks.
- **`[`src/render/decorations/DecorationPositioner.hpp`](https://github.com/hyprwm/Hyprland/blob/main/src/render/decorations/DecorationPositioner.hpp)`** – Positioning engine handling `SDecorationPositioningInfo` and `SDecorationPositioningReply`.
- **`[`src/render/decorations/CHyprDropShadowDecoration.hpp`](https://github.com/hyprwm/Hyprland/blob/main/src/render/decorations/CHyprDropShadowDecoration.hpp)`** – Reference implementation showing texture-based decoration techniques.
- **`[`hyprpm/src/core/Plugin.hpp`](https://github.com/hyprwm/Hyprland/blob/main/hyprpm/src/core/Plugin.hpp)`** – Plugin API header containing `addWindowDecoration()` and the `PLUGIN_EXPORT` macro.

## Summary

- Inherit from `IHyprWindowDecoration` in [`src/render/decorations/IHyprWindowDecoration.hpp`](https://github.com/hyprwm/Hyprland/blob/main/src/render/decorations/IHyprWindowDecoration.hpp) to create custom visual elements.
- Override `getPositioningInfo()` and `onPositioningReply()` to negotiate screen real estate with the compositor.
- Register your class using `hyprland::addWindowDecoration<T>()` inside the `plugin_init()` entry point.
- Activate via `decoration:<name>` syntax in [`hyprland.conf`](https://github.com/hyprwm/Hyprland/blob/main/hyprland.conf).
- Reference `CHyprDropShadowDecoration` for implementation patterns involving textures and blending.

## Frequently Asked Questions

### What programming language are Hyprland plugins written in?

Plugins are written in **C++** and compiled as shared libraries. The API headers utilize C++17/20 features, and the decoration interface relies on virtual inheritance, STL containers, and direct OpenGL context access.

### Can I use custom decorations without writing a plugin?

No. Novel window decoration types require implementing the `IHyprWindowDecoration` interface through a native plugin. While built-in decorations like drop shadows are configurable via [`hyprland.conf`](https://github.com/hyprwm/Hyprland/blob/main/hyprland.conf), custom rendering logic must reside in compiled code loaded through the Plugin API.

### How do I debug a custom window decoration plugin?

Load your plugin using `hyprpm` or manually via `hyprctl plugin load /path/to/your.so`, then monitor output with `hyprctl logs`. For breakpoint debugging, attach GDB to the running Hyprland process and set breakpoints in your `render()` or `onPositioningReply()` implementations.

### Are custom decorations compatible with all rendering backends?

Yes. The `IHyprWindowDecoration` interface is backend-agnostic. While your `render()` method typically executes OpenGL commands within the current context managed by Hyprland’s GLRenderer, the interface contracts—geometry via `SBoxExtents` and callbacks—remain consistent regardless of the underlying graphics API.