Examples

Code Examples

Complete, working examples to get you started. From simple windows to GPU-accelerated rendering.

Building Examples

All examples can be compiled with a single command using pkg-config:

# Compile any example
gcc -o my_app my_app.c $(pkg-config --cflags --libs plexy)

# Or manually
gcc -o my_app my_app.c -I/usr/local/include -L/usr/local/lib -lplexy
Beginner

Minimal Window

The simplest possible PlexyDesk application. Creates a window, fills it with a solid color, and waits for close.

/*
 * hello_plexy.c - Minimal PlexyDesk window
 * Compile: gcc -o hello_plexy hello_plexy.c $(pkg-config --cflags --libs plexy)
 */
#include <plexy.h>
#include <stdio.h>
#include <string.h>

static bool running = true;

static void on_close(PlexyWindow* win, void* data) {
    running = false;
}

int main(void) {
    // Connect to compositor
    PlexyConnection* conn = plexy_connect(NULL);
    if (!conn) {
        fprintf(stderr, "Failed to connect to compositor\n");
        return 1;
    }
    
    // Create 400x300 window
    PlexyWindow* win = plexy_create_window(conn, -1, -1, 400, 300, "Hello PlexyDesk");
    if (!win) {
        fprintf(stderr, "Failed to create window\n");
        plexy_disconnect(conn);
        return 1;
    }
    
    // Set close callback
    PlexyWindowCallbacks callbacks = { .close = on_close };
    plexy_window_set_callbacks(win, &callbacks, NULL);
    
    // Create buffer and fill with blue
    PlexyBuffer* buf = plexy_create_buffer(conn, 400, 300, PLEXY_FORMAT_ARGB8888);
    uint32_t* pixels = (uint32_t*)plexy_buffer_get_data(buf);
    
    for (int i = 0; i < 400 * 300; i++) {
        pixels[i] = 0xFF3584E4;  // GNOME blue
    }
    
    // Display the buffer
    plexy_window_attach(win, buf);
    plexy_window_commit(win);
    plexy_flush(conn);
    
    // Event loop
    while (running) {
        if (plexy_dispatch(conn) < 0) {
            break;
        }
    }
    
    // Cleanup
    plexy_destroy_buffer(buf);
    plexy_destroy_window(win);
    plexy_disconnect(conn);
    
    return 0;
}

What this demonstrates

  • • Connection to the compositor
  • • Window creation with automatic positioning
  • • Creating and filling a shared memory buffer
  • • Basic event loop with close handling
Beginner

Drawing Shapes

Software rendering with basic shapes and transparency.

/*
 * shapes.c - Drawing basic shapes
 */
#include <plexy.h>
#include <string.h>
#include <math.h>

// Helper to pack ARGB color
static inline uint32_t rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
    return ((uint32_t)a << 24) | ((uint32_t)r << 16) | 
           ((uint32_t)g << 8) | b;
}

// Fill rectangle
static void fill_rect(uint32_t* pixels, int stride,
                      int x, int y, int w, int h, uint32_t color) {
    for (int row = y; row < y + h; row++) {
        for (int col = x; col < x + w; col++) {
            pixels[row * stride + col] = color;
        }
    }
}

// Draw filled circle
static void fill_circle(uint32_t* pixels, int stride, int width, int height,
                        int cx, int cy, int radius, uint32_t color) {
    int r2 = radius * radius;
    for (int y = cy - radius; y <= cy + radius; y++) {
        if (y < 0 || y >= height) continue;
        for (int x = cx - radius; x <= cx + radius; x++) {
            if (x < 0 || x >= width) continue;
            int dx = x - cx, dy = y - cy;
            if (dx*dx + dy*dy <= r2) {
                pixels[y * stride + x] = color;
            }
        }
    }
}

// Draw line (Bresenham's algorithm)
static void draw_line(uint32_t* pixels, int stride, int width, int height,
                      int x0, int y0, int x1, int y1, uint32_t color) {
    int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
    int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
    int err = dx + dy;
    
    while (1) {
        if (x0 >= 0 && x0 < width && y0 >= 0 && y0 < height)
            pixels[y0 * stride + x0] = color;
        if (x0 == x1 && y0 == y1) break;
        int e2 = 2 * err;
        if (e2 >= dy) { err += dy; x0 += sx; }
        if (e2 <= dx) { err += dx; y0 += sy; }
    }
}

int main(void) {
    PlexyConnection* conn = plexy_connect(NULL);
    PlexyWindow* win = plexy_create_window(conn, -1, -1, 640, 480, "Shapes");
    
    // Create buffer with alpha support
    PlexyBuffer* buf = plexy_create_buffer(conn, 640, 480, PLEXY_FORMAT_ARGB8888);
    uint32_t* pixels = (uint32_t*)plexy_buffer_get_data(buf);
    int stride = 640;
    
    // Clear to white
    for (int i = 0; i < 640 * 480; i++)
        pixels[i] = rgba(255, 255, 255, 255);
    
    // Draw shapes
    fill_rect(pixels, stride, 50, 50, 200, 150, rgba(53, 132, 228, 255));   // Blue rect
    fill_rect(pixels, stride, 100, 100, 200, 150, rgba(255, 120, 0, 180));  // Orange (translucent)
    fill_circle(pixels, stride, 640, 480, 400, 200, 80, rgba(143, 89, 2, 255));
    draw_line(pixels, stride, 640, 480, 10, 400, 630, 300, rgba(30, 30, 30, 255));
    
    plexy_window_attach(win, buf);
    plexy_window_commit(win);
    plexy_flush(conn);
    
    // Wait for events
    bool running = true;
    PlexyWindowCallbacks cbs = { .close = (void*)&(running = false) };
    plexy_window_set_callbacks(win, &cbs, &running);
    
    while (running && plexy_dispatch(conn) >= 0);
    
    plexy_destroy_buffer(buf);
    plexy_destroy_window(win);
    plexy_disconnect(conn);
    return 0;
}
Intermediate

Input Handling

Handle mouse and keyboard events with callbacks.

/*
 * input_demo.c - Mouse and keyboard handling
 */
#include <plexy.h>
#include <plexy_event_loop.h>
#include <stdio.h>

typedef struct {
    PlexyWindow* window;
    PlexyBuffer* buffer;
    PlexyEventLoop* loop;
    int32_t mouse_x, mouse_y;
    bool left_pressed;
    uint32_t modifiers;
} AppState;

static void on_pointer_motion(PlexyWindow* win, int32_t x, int32_t y, void* data) {
    AppState* app = (AppState*)data;
    app->mouse_x = x;
    app->mouse_y = y;
    
    // Draw at cursor position when button held
    if (app->left_pressed) {
        uint32_t* pixels = (uint32_t*)plexy_buffer_get_data(app->buffer);
        uint32_t w, h;
        plexy_window_get_size(win, &w, &h);
        
        // Draw small circle at cursor
        for (int dy = -3; dy <= 3; dy++) {
            for (int dx = -3; dx <= 3; dx++) {
                int px = x + dx, py = y + dy;
                if (px >= 0 && px < w && py >= 0 && py < h) {
                    if (dx*dx + dy*dy <= 9) {
                        pixels[py * w + px] = 0xFF1A5FB4;  // Blue
                    }
                }
            }
        }
        
        plexy_window_commit(win);
    }
}

static void on_pointer_button(PlexyWindow* win, uint32_t button, 
                              bool pressed, int32_t x, int32_t y, void* data) {
    AppState* app = (AppState*)data;
    
    if (button == PLEXY_BTN_LEFT) {
        app->left_pressed = pressed;
        printf("Left button %s at (%d, %d)\n", pressed ? "pressed" : "released", x, y);
    } else if (button == PLEXY_BTN_RIGHT && pressed) {
        // Clear canvas on right click
        uint32_t* pixels = (uint32_t*)plexy_buffer_get_data(app->buffer);
        for (int i = 0; i < 800 * 600; i++) {
            pixels[i] = 0xFFFFFFFF;  // White
        }
        plexy_window_commit(win);
        printf("Canvas cleared\n");
    }
}

static void on_key(PlexyWindow* win, uint32_t keycode, bool pressed,
                   uint32_t modifiers, void* data) {
    AppState* app = (AppState*)data;
    app->modifiers = modifiers;
    
    if (pressed) {
        printf("Key %u pressed", keycode);
        if (modifiers & PLEXY_MOD_CTRL) printf(" +Ctrl");
        if (modifiers & PLEXY_MOD_SHIFT) printf(" +Shift");
        if (modifiers & PLEXY_MOD_ALT) printf(" +Alt");
        printf("\n");
        
        // Escape to quit
        if (keycode == 1) {  // KEY_ESC
            plexy_event_loop_quit(app->loop);
        }
    }
}

static void on_close(PlexyWindow* win, void* data) {
    AppState* app = (AppState*)data;
    plexy_event_loop_quit(app->loop);
}

int main(void) {
    AppState app = {0};
    
    PlexyConnection* conn = plexy_connect(NULL);
    app.window = plexy_create_window(conn, -1, -1, 800, 600, "Drawing Canvas");
    app.buffer = plexy_create_buffer(conn, 800, 600, PLEXY_FORMAT_ARGB8888);
    app.loop = plexy_event_loop_create(conn);
    
    // Clear to white
    uint32_t* pixels = (uint32_t*)plexy_buffer_get_data(app.buffer);
    for (int i = 0; i < 800 * 600; i++) pixels[i] = 0xFFFFFFFF;
    
    plexy_window_attach(app.window, app.buffer);
    plexy_window_commit(app.window);
    
    // Set all callbacks
    PlexyWindowCallbacks callbacks = {
        .pointer_motion = on_pointer_motion,
        .pointer_button = on_pointer_button,
        .key = on_key,
        .close = on_close,
    };
    plexy_window_set_callbacks(app.window, &callbacks, &app);
    
    printf("Draw with left mouse button. Right-click to clear. ESC to quit.\n");
    
    // Run event loop
    plexy_event_loop_run(app.loop);
    
    // Cleanup
    plexy_event_loop_destroy(app.loop);
    plexy_destroy_buffer(app.buffer);
    plexy_destroy_window(app.window);
    plexy_disconnect(conn);
    
    return 0;
}

Key concepts

  • • Callbacks receive the user_data pointer for state access
  • • Button events include the position at press/release time
  • • Key events include current modifier state
  • • Using the event loop for clean event handling
Intermediate

Dock Panel

Create a dock panel using layer surfaces. Demonstrates anchoring, exclusive zones, and hover effects.

/*
 * dock.c - Bottom dock panel with layer surface
 */
#include <plexy.h>
#include <plexy_event_loop.h>
#include <string.h>

#define DOCK_HEIGHT 64
#define ICON_SIZE 48
#define ICON_COUNT 5

typedef struct {
    PlexyConnection* conn;
    PlexyLayerSurface* dock;
    PlexyBuffer* buffer;
    PlexyEventLoop* loop;
    uint32_t width;
    int hovered_icon;
} DockState;

static uint32_t icon_colors[ICON_COUNT] = {
    0xFF3584E4,  // Blue (Files)
    0xFFFF7800,  // Orange (Firefox)
    0xFF33D17A,  // Green (Terminal)
    0xFF9141AC,  // Purple (Settings)
    0xFFC01C28,  // Red (Power)
};

static void draw_dock(DockState* dock) {
    uint32_t* pixels = (uint32_t*)plexy_buffer_get_data(dock->buffer);
    uint32_t stride = dock->width;
    
    // Semi-transparent dark background
    for (uint32_t y = 0; y < DOCK_HEIGHT; y++) {
        for (uint32_t x = 0; x < dock->width; x++) {
            pixels[y * stride + x] = 0xE0303030;
        }
    }
    
    // Draw icons centered
    int total_width = ICON_COUNT * (ICON_SIZE + 16) - 16;
    int start_x = (dock->width - total_width) / 2;
    int icon_y = (DOCK_HEIGHT - ICON_SIZE) / 2;
    
    for (int i = 0; i < ICON_COUNT; i++) {
        int icon_x = start_x + i * (ICON_SIZE + 16);
        uint32_t color = icon_colors[i];
        
        // Hover effect: brighten
        if (i == dock->hovered_icon) {
            uint8_t r = ((color >> 16) & 0xFF) + 30;
            uint8_t g = ((color >> 8) & 0xFF) + 30;
            uint8_t b = (color & 0xFF) + 30;
            color = 0xFF000000 | (r << 16) | (g << 8) | b;
        }
        
        // Draw rounded rectangle (simplified as filled rect)
        for (int y = icon_y; y < icon_y + ICON_SIZE; y++) {
            for (int x = icon_x; x < icon_x + ICON_SIZE; x++) {
                pixels[y * stride + x] = color;
            }
        }
    }
    
    plexy_layer_surface_commit(dock->dock);
}

static void on_motion(PlexyWindow* w, int32_t x, int32_t y, void* data) {
    DockState* dock = (DockState*)data;
    
    int total_width = ICON_COUNT * (ICON_SIZE + 16) - 16;
    int start_x = (dock->width - total_width) / 2;
    
    int old_hover = dock->hovered_icon;
    dock->hovered_icon = -1;
    
    for (int i = 0; i < ICON_COUNT; i++) {
        int icon_x = start_x + i * (ICON_SIZE + 16);
        if (x >= icon_x && x < icon_x + ICON_SIZE) {
            dock->hovered_icon = i;
            break;
        }
    }
    
    if (dock->hovered_icon != old_hover) {
        draw_dock(dock);
    }
}

static void on_leave(PlexyWindow* w, void* data) {
    DockState* dock = (DockState*)data;
    dock->hovered_icon = -1;
    draw_dock(dock);
}

int main(void) {
    DockState dock = { .hovered_icon = -1 };
    
    dock.conn = plexy_connect(NULL);
    
    // Get screen width
    plexy_get_screen_size(dock.conn, &dock.width, NULL);
    
    // Create layer surface anchored to bottom edge
    dock.dock = plexy_create_layer_surface(
        dock.conn,
        PLEXY_LAYER_TOP,
        PLEXY_ANCHOR_BOTTOM | PLEXY_ANCHOR_LEFT | PLEXY_ANCHOR_RIGHT,
        0,              // width: stretch to anchors
        DOCK_HEIGHT,
        DOCK_HEIGHT,    // exclusive zone: reserve this space
        0, 0            // margins
    );
    
    // Create buffer for dock
    dock.buffer = plexy_create_buffer(dock.conn, dock.width, DOCK_HEIGHT, 
                                      PLEXY_FORMAT_ARGB8888);
    plexy_layer_surface_attach(dock.dock, dock.buffer);
    
    // Set callbacks for hover effects
    PlexyLayerSurfaceCallbacks callbacks = {
        .pointer_motion = on_motion,
        .pointer_leave = on_leave,
    };
    plexy_layer_surface_set_callbacks(dock.dock, &callbacks, &dock);
    
    // Initial draw
    draw_dock(&dock);
    plexy_flush(dock.conn);
    
    // Run
    dock.loop = plexy_event_loop_create(dock.conn);
    plexy_event_loop_run(dock.loop);
    
    // Cleanup
    plexy_event_loop_destroy(dock.loop);
    plexy_destroy_buffer(dock.buffer);
    plexy_destroy_layer_surface(dock.dock);
    plexy_disconnect(dock.conn);
    
    return 0;
}

Layer Types

  • BACKGROUND — Desktop wallpaper
  • BOTTOM — Below windows
  • TOP — Panels, docks
  • OVERLAY — Lock screens, notifications

Anchor Flags

  • TOP | LEFT | RIGHT — Top bar
  • BOTTOM | LEFT | RIGHT — Bottom dock
  • LEFT | TOP | BOTTOM — Left sidebar
Intermediate

Smooth Animation

Use the event loop with timers for smooth 60fps animation.

/*
 * animation.c - Smooth 60fps animation with event loop timers
 */
#include <plexy.h>
#include <plexy_event_loop.h>
#include <math.h>

#define WIDTH 640
#define HEIGHT 480
#define FPS 60

typedef struct {
    PlexyWindow* window;
    PlexyBuffer* buffer;
    PlexyEventLoop* loop;
    double time;
} AnimState;

static int render_frame(void* data) {
    AnimState* anim = (AnimState*)data;
    uint32_t* pixels = (uint32_t*)plexy_buffer_get_data(anim->buffer);
    
    anim->time += 1.0 / FPS;
    
    // Clear
    for (int i = 0; i < WIDTH * HEIGHT; i++) {
        pixels[i] = 0xFF1E1E1E;  // Dark gray
    }
    
    // Animated circle
    double cx = WIDTH / 2 + cos(anim->time * 2.0) * 150;
    double cy = HEIGHT / 2 + sin(anim->time * 3.0) * 100;
    int radius = 40 + sin(anim->time * 5.0) * 15;
    
    // Hue cycling
    double hue = fmod(anim->time * 60, 360);
    uint8_t r, g, b;
    // HSV to RGB (simplified)
    int hi = (int)(hue / 60) % 6;
    double f = hue / 60 - hi;
    uint8_t v = 230, p = 50, q = v * (1 - f), t = v * f;
    switch (hi) {
        case 0: r = v; g = t; b = p; break;
        case 1: r = q; g = v; b = p; break;
        case 2: r = p; g = v; b = t; break;
        case 3: r = p; g = q; b = v; break;
        case 4: r = t; g = p; b = v; break;
        default: r = v; g = p; b = q; break;
    }
    uint32_t color = 0xFF000000 | (r << 16) | (g << 8) | b;
    
    // Draw filled circle
    for (int y = (int)cy - radius; y <= (int)cy + radius; y++) {
        if (y < 0 || y >= HEIGHT) continue;
        for (int x = (int)cx - radius; x <= (int)cx + radius; x++) {
            if (x < 0 || x >= WIDTH) continue;
            double dx = x - cx, dy = y - cy;
            if (dx*dx + dy*dy <= radius*radius) {
                pixels[y * WIDTH + x] = color;
            }
        }
    }
    
    plexy_window_commit(anim->window);
    
    return 0;  // Keep timer running
}

static void on_close(PlexyWindow* win, void* data) {
    AnimState* anim = (AnimState*)data;
    plexy_event_loop_quit(anim->loop);
}

int main(void) {
    AnimState anim = {0};
    
    PlexyConnection* conn = plexy_connect(NULL);
    anim.window = plexy_create_window(conn, -1, -1, WIDTH, HEIGHT, "Animation");
    anim.buffer = plexy_create_buffer(conn, WIDTH, HEIGHT, PLEXY_FORMAT_ARGB8888);
    anim.loop = plexy_event_loop_create(conn);
    
    plexy_window_attach(anim.window, anim.buffer);
    
    PlexyWindowCallbacks callbacks = { .close = on_close };
    plexy_window_set_callbacks(anim.window, &callbacks, &anim);
    
    // Add 60fps timer (~16ms interval)
    plexy_event_loop_add_timer(anim.loop, 1000 / FPS, render_frame, &anim);
    
    // Initial frame
    render_frame(&anim);
    
    // Run
    plexy_event_loop_run(anim.loop);
    
    plexy_event_loop_destroy(anim.loop);
    plexy_destroy_buffer(anim.buffer);
    plexy_destroy_window(anim.window);
    plexy_disconnect(conn);
    
    return 0;
}

Timer callback return values

  • return 0; — Keep timer running
  • return 1; — Remove timer (one-shot)
Advanced

GPU Rendering with DMA-BUF

Zero-copy GPU sharing using DMA-BUF for maximum performance. This example uses GBM for buffer allocation and OpenGL ES for rendering.

/*
 * gpu_render.c - OpenGL ES rendering with DMA-BUF
 * Compile: gcc -o gpu_render gpu_render.c $(pkg-config --cflags --libs plexy gbm egl glesv2)
 */
#include <plexy.h>
#include <gbm.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <drm_fourcc.h>
#include <fcntl.h>
#include <unistd.h>

#define WIDTH 800
#define HEIGHT 600

typedef struct {
    int drm_fd;
    struct gbm_device* gbm;
    struct gbm_bo* bo;
    EGLDisplay egl_display;
    EGLContext egl_context;
    EGLImageKHR egl_image;
    GLuint fbo, texture;
} GPUState;

static bool init_gpu(GPUState* gpu) {
    // Open render node
    gpu->drm_fd = open("/dev/dri/renderD128", O_RDWR);
    if (gpu->drm_fd < 0) return false;
    
    // Create GBM device
    gpu->gbm = gbm_create_device(gpu->drm_fd);
    if (!gpu->gbm) return false;
    
    // Create buffer object
    gpu->bo = gbm_bo_create(gpu->gbm, WIDTH, HEIGHT,
                            GBM_FORMAT_ARGB8888,
                            GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR);
    if (!gpu->bo) return false;
    
    // Initialize EGL
    gpu->egl_display = eglGetPlatformDisplay(EGL_PLATFORM_GBM_KHR, gpu->gbm, NULL);
    eglInitialize(gpu->egl_display, NULL, NULL);
    eglBindAPI(EGL_OPENGL_ES_API);
    
    static const EGLint ctx_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
    static const EGLint cfg_attribs[] = {
        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
        EGL_NONE
    };
    EGLConfig config;
    EGLint num_configs;
    eglChooseConfig(gpu->egl_display, cfg_attribs, &config, 1, &num_configs);
    
    gpu->egl_context = eglCreateContext(gpu->egl_display, config, 
                                        EGL_NO_CONTEXT, ctx_attribs);
    eglMakeCurrent(gpu->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, 
                   gpu->egl_context);
    
    // Create EGL image from GBM buffer
    static const EGLAttrib image_attribs[] = {
        EGL_WIDTH, WIDTH,
        EGL_HEIGHT, HEIGHT,
        EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_ARGB8888,
        EGL_DMA_BUF_PLANE0_FD_EXT, gbm_bo_get_fd(gpu->bo),
        EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
        EGL_DMA_BUF_PLANE0_PITCH_EXT, gbm_bo_get_stride(gpu->bo),
        EGL_NONE
    };
    
    PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = 
        (void*)eglGetProcAddress("eglCreateImageKHR");
    gpu->egl_image = eglCreateImageKHR(gpu->egl_display, EGL_NO_CONTEXT,
                                       EGL_LINUX_DMA_BUF_EXT, NULL, image_attribs);
    
    // Create texture and FBO
    glGenTextures(1, &gpu->texture);
    glBindTexture(GL_TEXTURE_2D, gpu->texture);
    
    PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES =
        (void*)eglGetProcAddress("glEGLImageTargetTexture2DOES");
    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, gpu->egl_image);
    
    glGenFramebuffers(1, &gpu->fbo);
    glBindFramebuffer(GL_FRAMEBUFFER, gpu->fbo);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 
                           GL_TEXTURE_2D, gpu->texture, 0);
    
    glViewport(0, 0, WIDTH, HEIGHT);
    
    return true;
}

int main(void) {
    GPUState gpu = {0};
    if (!init_gpu(&gpu)) {
        fprintf(stderr, "Failed to initialize GPU\n");
        return 1;
    }
    
    PlexyConnection* conn = plexy_connect(NULL);
    PlexyWindow* window = plexy_create_window(conn, -1, -1, WIDTH, HEIGHT, 
                                              "GPU Rendering");
    
    // Create PlexyBuffer from DMA-BUF
    int dmabuf_fd = gbm_bo_get_fd(gpu.bo);
    PlexyBuffer* buffer = plexy_create_buffer_from_dmabuf(
        conn, dmabuf_fd,
        WIDTH, HEIGHT,
        gbm_bo_get_stride(gpu.bo),
        DRM_FORMAT_ARGB8888,
        DRM_FORMAT_MOD_LINEAR
    );
    
    plexy_window_attach(window, buffer);
    
    // Render with OpenGL
    glClearColor(0.1f, 0.1f, 0.2f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    
    // ... your OpenGL rendering here ...
    
    glFinish();  // Ensure GPU completes before commit
    
    plexy_window_commit(window);
    plexy_flush(conn);
    
    // Event loop...
    bool running = true;
    while (running && plexy_dispatch(conn) >= 0);
    
    // Cleanup
    plexy_destroy_buffer(buffer);
    plexy_destroy_window(window);
    plexy_disconnect(conn);
    
    glDeleteFramebuffers(1, &gpu.fbo);
    glDeleteTextures(1, &gpu.texture);
    eglDestroyImageKHR(gpu.egl_display, gpu.egl_image);
    eglDestroyContext(gpu.egl_display, gpu.egl_context);
    eglTerminate(gpu.egl_display);
    gbm_bo_destroy(gpu.bo);
    gbm_device_destroy(gpu.gbm);
    close(gpu.drm_fd);
    
    return 0;
}

Requirements

DMA-BUF requires a GPU with proper DRM/KMS drivers. Most modern Intel, AMD, and NVIDIA GPUs are supported.

Dependencies: libgbm, libegl, libglesv2, libdrm

More Examples

HiDPI Support

Handle display scaling for crisp rendering on high-density displays.

View on GitHub →

Text Rendering

Render text using a simple bitmap font renderer.

View on GitHub →

Clock Widget

Desktop clock using layer surfaces and timer callbacks.

View on GitHub →

Glass Bar

Transparent overlay bar with blur effect (compositor-dependent).

View on GitHub →
Menu