Search code examples
cx11xlib

Draw border (frame) using xlib


Is it possible to draw transparent window without title bar, close button, responses on mouse buttons using xlib. So just border with specific color and width? Something like enter image description here

this orange rectangle is what I need to create. Also I'd like to have possibility to move, resize, close and make it flicking (change border's color on timer) programatically.

I managed to create transparent window without titlebar and draw rectangles on each side of the window to make border-effect:

#define W_WIDTH 640
#define W_HEIGHT 480

#define X_POS 100
#define Y_POS 120
#define BORDER_WIDTH 2

Display *dpy;
Window w;

XRectangle rectangles[4] =
    {
    { X_POS, Y_POS, W_WIDTH, BORDER_WIDTH },
    { X_POS, Y_POS, BORDER_WIDTH, W_HEIGHT },
    { X_POS, W_HEIGHT - BORDER_WIDTH, W_WIDTH, BORDER_WIDTH },
    { W_WIDTH - BORDER_WIDTH, Y_POS, BORDER_WIDTH, W_HEIGHT }
    };

int main(int argc, char *argv[])
{
    GC gc;
    XGCValues gcv;
    int run = 1;

    dpy = XOpenDisplay(NULL);

    XVisualInfo vinfo;
    XMatchVisualInfo(dpy, DefaultScreen(dpy), 32, TrueColor, &vinfo);
    XSetWindowAttributes attr;
    attr.colormap = XCreateColormap(dpy, DefaultRootWindow(dpy), vinfo.visual, AllocNone);

    w = XCreateWindow(dpy, DefaultRootWindow(dpy), X_POS, Y_POS,
                      W_WIDTH, W_HEIGHT, BORDER_WIDTH, vinfo.depth,
                      InputOutput, vinfo.visual, CWColormap | CWBorderPixel | CWBackPixel, &attr);
    XColor color;
    Colormap colormap;
    char orangeDark[] = "#FF8000";
    colormap = DefaultColormap(dpy, 0);
    XParseColor(dpy, colormap, orangeDark, &color);
    XAllocColor(dpy, colormap, &color);

    gcv.line_width = BORDER_WIDTH;
    gc = XCreateGC(dpy, w, GCLineWidth, &gcv);

    XSelectInput(dpy, w, ExposureMask);
    Atom window_type = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
    long value = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False);
    XChangeProperty(dpy, w, window_type, XA_ATOM, 32, PropModeReplace, (unsigned char *) &value, 1);
    XMapWindow(dpy, w);
    XSync(dpy, False);

    while(run)
    {
        XEvent xe;
        XNextEvent(dpy, &xe);
        switch (xe.type)
        {
            case Expose:
                XSetForeground(dpy, gc, color.pixel);
                XDrawRectangles(dpy, w, gc, rectangles, 4);
                XFillRectangles(dpy, w, gc, rectangles, 4);
                XSync(dpy, False);
                break;
            default:
                break;
        }
    }

    XDestroyWindow(dpy, w);
    XCloseDisplay(dpy);

    return 0;
}

This code works almost fine except the thing, that my orange border is semitransparent and is almost invisible on light windows: enter image description here Could you please tell how I need change my code to draw solid orange rectangles? Another variant I have is to draw transparent rectangle inside of orange window. But I didn't find any info in the Internet about how to do that.


Solution

  • Two main mistakes.

    1. Not initializing attr and gcv to 0
    2. Not using attr.colormap for color allocation

    That should help:

    #include <X11/Xlib.h>
    #include <X11/Xutil.h>
    #include <X11/Xatom.h>
    
    #define W_WIDTH 640
    #define W_HEIGHT 480
    
    #define X_POS 100
    #define Y_POS 120
    #define BORDER_WIDTH 2
    
    int main(int argc, char *argv[]) {
        XRectangle rectangles[4] = {
            { X_POS, Y_POS, W_WIDTH, BORDER_WIDTH },
            { X_POS, Y_POS, BORDER_WIDTH, W_HEIGHT },
            { X_POS, W_HEIGHT - BORDER_WIDTH, W_WIDTH, BORDER_WIDTH },
            { W_WIDTH - BORDER_WIDTH, Y_POS, BORDER_WIDTH, W_HEIGHT }
        };
        Display *dpy = XOpenDisplay(NULL);
        XSetWindowAttributes attr = {0};
        XGCValues gcv = {0};
        XVisualInfo vinfo;
        GC gc;
    
        Window w;
    
        int run = 1;
    
        XMatchVisualInfo(dpy, DefaultScreen(dpy), 32, TrueColor, &vinfo);
        attr.colormap = XCreateColormap(dpy, DefaultRootWindow(dpy), vinfo.visual, AllocNone);
    
        XColor color;
        char orangeDark[] = "#FF8000";
        XParseColor(dpy, attr.colormap, orangeDark, &color);
        XAllocColor(dpy, attr.colormap, &color);
    
        w = XCreateWindow(dpy, DefaultRootWindow(dpy), X_POS, Y_POS,
                          W_WIDTH, W_HEIGHT, BORDER_WIDTH, vinfo.depth,
                          InputOutput, vinfo.visual, CWColormap | CWBorderPixel | CWBackPixel, &attr);
    
        gcv.line_width = BORDER_WIDTH;
        gc = XCreateGC(dpy, w, GCLineWidth, &gcv);
    
        XSelectInput(dpy, w, ExposureMask);
        long value = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False);
        XChangeProperty(dpy, w, XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False),
                        XA_ATOM, 32, PropModeReplace, (unsigned char *) &value, 1);
        XMapWindow(dpy, w);
        XSync(dpy, False);
    
        while(run) {
            XEvent xe;
            XNextEvent(dpy, &xe);
            switch (xe.type) {
                case Expose:
                    XSetForeground(dpy, gc, color.pixel);
                    XDrawRectangles(dpy, w, gc, rectangles, 4);
                    XFillRectangles(dpy, w, gc, rectangles, 4);
                    XSync(dpy, False);
                    break;
    
                default:
                    break;
            }
        }
    
        XDestroyWindow(dpy, w);
        XCloseDisplay(dpy);
    
        return 0;
    }
    

    Result:

    enter image description here