Mike
Mike

Reputation: 814

Xlib doesn't draw

This was a much larger program that I reduced to the minimal that causes the problem. The calls to XDrawRectangle() and XFillRectangle(), which are near the bottom of the code, don't draw anything. The original code has a fuller event loop that does draw things as expected, but the calls to XDrawRectangle() and XFillRectangle() are in the same location as the old event loop so I don't understand why they don't work.

EDIT: I do get a white window, but no rectangle drawn within the window.

The compile command is: gcc -o paint paint.c -lX11

#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>

static Display *dpy;
static int scr;
static Window root;
static Visual *vis;

static Window create_win(int x, int y, int w, int h, int b)
{
    Window win;
    XSetWindowAttributes xwa = 
    {
        .background_pixel = WhitePixel(dpy, scr),
        .border_pixel = BlackPixel(dpy, scr),
    };

    win = XCreateWindow(dpy, root, x, y, w, h, b, DefaultDepth(dpy, scr), InputOutput, vis, CWBackPixel | CWBorderPixel | CWEventMask, &xwa);
    return win;
}

static GC create_gc()
{
    GC gc;
    XGCValues xgcv;
    unsigned long valuemask;

    xgcv.line_width = 4;
    xgcv.fill_style = FillSolid;
    xgcv.foreground = BlackPixel(dpy, scr);
    xgcv.background = WhitePixel(dpy, scr);

    valuemask = GCForeground | GCBackground | GCFillStyle | GCLineStyle | GCLineWidth | GCCapStyle | GCJoinStyle;
    gc = XCreateGC(dpy, root, valuemask, &xgcv);

    return gc;
}

int main()
{
    Window main_win;
    GC gc;
    
    dpy = XOpenDisplay(NULL);

    scr = DefaultScreen(dpy);
    root = RootWindow(dpy, scr);
    vis = DefaultVisual(dpy, scr);
    main_win = create_win(0, 0, 200, 200, 5);
    
    gc = create_gc();
    
    XMapWindow(dpy, main_win);
    
    XDrawRectangle(dpy, main_win, gc, 0, 0, 100, 100);
    XFillRectangle(dpy, main_win, gc, 0, 0, 100, 100);
    
    XEvent ev;
    while (!(XNextEvent(dpy, &ev)))
        ;

    XUnmapWindow(dpy, main_win);
    XDestroyWindow(dpy, main_win);
    XFreeGC(dpy, gc);
    XCloseDisplay(dpy);
    
    return 0;
}

Upvotes: 2

Views: 104

Answers (2)

dash-o
dash-o

Reputation: 14493

OP did not specify the desktop environment (Linux version, X version, window manager, etc.) - making some assumption, which can be incorrect.

In general, the most likely reason of for no visible output when you call the XDraw functions is the way that X11 window works. While technically possible to call drawing function anytime (including immediately after window creation) - you are not guaranteed that it will actually be displayed.

One common reason is that you window is not at the top - it may be covered by other windows. Another reason may be that your request to create/map the window was not completed yet, and you are drawing into non-visible area.

The "proper" way is to draw in response to "redraw" events, when the display tells you application that an area on the screen was "damaged", and need to be redraw to make it "correct". This will guarantee that the content is sent to a window when the window is visible, mapped, etc.

Depending on how you display is configured, direct drawing into windows may work - especially if the display is configured for "backing store", or other configuration that will allocate memory to the windows in advance, and may even refresh the screen from memory - without having to request you application to redraw" - however - this is not guaranteed.

You did not mention which toolkit (if any) you are using - many libraries/toolkit (Motif, Athena, GTK) will provide callbacks where you can "Draw" on the screen. I assume that you code is using no such framework, for whatever reason. In this case, you want to change your program to trigger the redraw - when you get the "Expose" events.

    gc = create_gc()
    XMapWindow(dpy, main_win) ;

    while ( !XNextEvent(dpy, &ev) ) {
        if ( ev.type == Expose ) {
             XDraw(...)
             XFill(...)
        } ;
    } ;

Emphasizing: this is based on assumption - I'm not able to replicate your problem on my display (Centos 8) - most likely of differences in display configuration. I could get similar results (no drawing) when I resized the window, which led me to believe that the problem is with lack of handling for "Expose" events.

Upvotes: 1

gsm
gsm

Reputation: 77

You should call follow function before XMapWindow:

XSelectInput(dsp, main_win, ExposureMask);

Upvotes: -1

Related Questions