How to Create Custom Window Decorations Using the Hyprland Plugin API

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 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, 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, 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.

/* 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. Use the templated function hyprland::addWindowDecoration() to bind your class to a configuration identifier.

/* 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:


# ~/.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 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.
  • 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, 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.

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 →