why do I get full window expose events always?

294 views Asked by At

In the test program:

/*
 * Study for Xwindow events.
 */
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//#define BACKGROUND_PAINT

void prtxevtt(int type)

{

    switch (type) {

        case 2:  fprintf(stderr, "KeyPress"); break;
        case 3:  fprintf(stderr, "KeyRelease"); break;
        case 4:  fprintf(stderr, "ButtonPress"); break;
        case 5:  fprintf(stderr, "ButtonRelease"); break;
        case 6:  fprintf(stderr, "MotionNotify"); break;
        case 7:  fprintf(stderr, "EnterNotify"); break;
        case 8:  fprintf(stderr, "LeaveNotify"); break;
        case 9:  fprintf(stderr, "FocusIn"); break;
        case 10: fprintf(stderr, "FocusOut"); break;
        case 11: fprintf(stderr, "KeymapNotify"); break;
        case 12: fprintf(stderr, "Expose"); break;
        case 13: fprintf(stderr, "GraphicsExpose"); break;
        case 14: fprintf(stderr, "NoExpose"); break;
        case 15: fprintf(stderr, "VisibilityNotify"); break;
        case 16: fprintf(stderr, "CreateNotify"); break;
        case 17: fprintf(stderr, "DestroyNotify"); break;
        case 18: fprintf(stderr, "UnmapNotify"); break;
        case 19: fprintf(stderr, "MapNotify"); break;
        case 20: fprintf(stderr, "MapRequest"); break;
        case 21: fprintf(stderr, "ReparentNotify"); break;
        case 22: fprintf(stderr, "ConfigureNotify"); break;
        case 23: fprintf(stderr, "ConfigureRequest"); break;
        case 24: fprintf(stderr, "GravityNotify"); break;
        case 25: fprintf(stderr, "ResizeRequest"); break;
        case 26: fprintf(stderr, "CirculateNotify"); break;
        case 27: fprintf(stderr, "CirculateRequest"); break;
        case 28: fprintf(stderr, "PropertyNotify"); break;
        case 29: fprintf(stderr, "SelectionClear"); break;
        case 30: fprintf(stderr, "SelectionRequest"); break;
        case 31: fprintf(stderr, "SelectionNotify"); break;
        case 32: fprintf(stderr, "ColormapNotify"); break;
        case 33: fprintf(stderr, "ClientMessage"); break;
        case 34: fprintf(stderr, "MappingNotify"); break;
        case 35: fprintf(stderr, "GenericEvent"); break;
        default: fprintf(stderr, "???"); break;

    }

}

void prtxevt(Display* d, XEvent* e)

{

    fprintf(stderr, "X Event: %5ld Window: %lx ", e->xany.serial,
            e->xany.window);
    prtxevtt(e->type);
    switch (e->type) {

        case Expose: fprintf(stderr, ": x: %d y: %d w: %d h: %d",
                             e->xexpose.x, e->xexpose.y,
                             e->xexpose.width, e->xexpose.height); break;
        case ConfigureNotify: fprintf(stderr, ": x: %d y: %d w: %d h: %d",
                             e->xconfigure.x, e->xconfigure.y,
                             e->xconfigure.width, e->xconfigure.height); break;
        case MotionNotify: fprintf(stderr, ": x: %d y: %d",
                                   e->xmotion.x, e->xmotion.y); break;
        case PropertyNotify: fprintf(stderr, ": atom: %s",
                                     XGetAtomName(d, e->xproperty.atom));

    }
    fprintf(stderr, "\n"); fflush(stderr);

}

int main(void) {

    Window         w;
    GC             gracxt;
    XEvent         e;
    const char*    msg = "Hello, window";
    int            s;
    Display*       d;
    XFontStruct*   font;
 
    d = XOpenDisplay(NULL);
    if (d == NULL) {

        fprintf(stderr, "Cannot open display\n");
        exit(1);

    }
 
    s = DefaultScreen(d);

    font = XLoadQueryFont(d,
        "-bitstream-courier 10 pitch-bold-r-normal--0-0-200-200-m-0-iso8859-1");
    if (!font) {

        fprintf(stderr, "*** No font ***\n");
        exit(1);

    }
    gracxt = XDefaultGC(d, s);
    XSetFont(d, gracxt, font->fid);

#ifdef BACKGROUND_PAINT
    w = XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 1000, 1000, 5,
                            BlackPixel(d, s), WhitePixel(d, s));
#else
    // no background draw
    w = XCreateWindow(d, RootWindow(d, s), 0, 0, 1000, 1000, 0, CopyFromParent,
                      InputOutput, CopyFromParent, 0, NULL);
#endif
    XSelectInput(d, w, ExposureMask|KeyPressMask|/*PointerMotionMask|*/
                       StructureNotifyMask/*|PropertyChangeMask*/);
    XMapWindow(d, w);

    while (1) {

        XNextEvent(d, &e);
        prtxevt(d, &e);
        if (e.type == Expose) {

            XSetForeground(d, gracxt, WhitePixel(d, s));
            XFillRectangle(d, e.xany.window, gracxt,
                           e.xexpose.x, e.xexpose.y,
                           e.xexpose.width, e.xexpose.height);
            XSetForeground(d, gracxt, BlackPixel(d, s));
            XDrawString(d, e.xany.window, gracxt, 10, 50, msg, strlen(msg));

        }

    }

    XCloseDisplay(d);

    return 0;

}

Its a fairly normal window with "hello, window" painted on it (the text was enlarged because I have a 4k monitor). The background paint was turned off, so we handle painting ourselves.

If I grab the lower right hand corner of the window and expand it slowly in both x and y, I get:

miam@samiam-h-pc-2:~/projects/petit_ami_tools/linux$ ./xmltwin
X Event:    13 Window: 4e00002 ReparentNotify
X Event:    13 Window: 4e00002 ConfigureNotify: x: 20 y: 90 w: 1000 h: 1000
X Event:    13 Window: 4e00002 MapNotify
X Event:    13 Window: 4e00002 Expose: x: 0 y: 0 w: 1000 h: 1000
X Event:    17 Window: 4e00002 ConfigureNotify: x: 20 y: 90 w: 1001 h: 1000
X Event:    17 Window: 4e00002 Expose: x: 0 y: 0 w: 1001 h: 1000
X Event:    21 Window: 4e00002 ConfigureNotify: x: 20 y: 90 w: 1005 h: 1002
X Event:    21 Window: 4e00002 Expose: x: 0 y: 0 w: 1005 h: 1002
X Event:    25 Window: 4e00002 ConfigureNotify: x: 20 y: 90 w: 1007 h: 1003
X Event:    25 Window: 4e00002 Expose: x: 0 y: 0 w: 1007 h: 1003
X Event:    29 Window: 4e00002 ConfigureNotify: x: 20 y: 90 w: 1008 h: 1004
X Event:    29 Window: 4e00002 Expose: x: 0 y: 0 w: 1008 h: 1004
X Event:    33 Window: 4e00002 ConfigureNotify: x: 20 y: 90 w: 1009 h: 1004
X Event:    33 Window: 4e00002 Expose: x: 0 y: 0 w: 1009 h: 1004
X Event:    37 Window: 4e00002 ConfigureNotify: x: 20 y: 90 w: 1010 h: 1005
X Event:    37 Window: 4e00002 Expose: x: 0 y: 0 w: 1010 h: 1005
X Event:    41 Window: 4e00002 ConfigureNotify: x: 20 y: 90 w: 1012 h: 1005
X Event:    41 Window: 4e00002 Expose: x: 0 y: 0 w: 1012 h: 1005
X Event:    45 Window: 4e00002 ConfigureNotify: x: 20 y: 90 w: 1013 h: 1006
X Event:    45 Window: 4e00002 Expose: x: 0 y: 0 w: 1013 h: 1006
X Event:    49 Window: 4e00002 ConfigureNotify: x: 20 y: 90 w: 1015 h: 1009
X Event:    49 Window: 4e00002 Expose: x: 0 y: 0 w: 1015 h: 1009
X Event:    53 Window: 4e00002 ConfigureNotify: x: 20 y: 90 w: 1016 h: 1010
X Event:    53 Window: 4e00002 Expose: x: 0 y: 0 w: 1016 h: 1010
X Event:    57 Window: 4e00002 ConfigureNotify: x: 20 y: 90 w: 1016 h: 1011
X Event:    57 Window: 4e00002 Expose: x: 0 y: 0 w: 1016 h: 1011
X Event:    61 Window: 4e00002 ConfigureNotify: x: 20 y: 90 w: 1017 h: 1011
X Event:    61 Window: 4e00002 Expose: x: 0 y: 0 w: 1017 h: 1011
X Event:    65 Window: 4e00002 ConfigureNotify: x: 20 y: 90 w: 1017 h: 1012
X Event:    65 Window: 4e00002 Expose: x: 0 y: 0 w: 1017 h: 1012
X Event:    69 Window: 4e00002 ConfigureNotify: x: 20 y: 90 w: 1018 h: 1013
X Event:    69 Window: 4e00002 Expose: x: 0 y: 0 w: 1018 h: 1013
X Event:    73 Window: 4e00002 ConfigureNotify: x: 20 y: 90 w: 1019 h: 1014
X Event:    73 Window: 4e00002 Expose: x: 0 y: 0 w: 1019 h: 1014

Notice I am getting full expose events, that is, the expose rectangle is telling me to repaint the entire window. This is technically correct, but very inefficient. I would expect the expose rectangle to only ask to paint the rightmost and bottom most parts of the window, which in the example above, were only single pixel slices.

I know if I specify a background pixel, Xwindow has to give me full expose events, because it is erasing the background for me. But that should have been turned off with the background. I turned off the fill (XFillRectangle) and verified that it does not paint the background, leaves it to the previous contents under the window. Did I specify not painting the background correctly?

I notice that the underlying code for Xwindows uses XCB, and that it does not generate uncover paints (put another window in front, blocking part of it, then move to uncover the window again). This (to me) means that it is buffering up the drawn surface and restoring it from memory. One theory is that XLIB/XCB does not feel the need to optimize expose events anymore.

Ubuntu 20.04 LTS with GDM3.

Thanks,

Scott Franco San Jose, CA

1

There are 1 answers

0
ISOPARIX On

I am sure this is a problem with the X window manager, and I have seen it on KDE. But I use Cygwin, and its X window manager seems to me to behave correctly. Instead of sending this torrent of ConfigureNotify/Expose events, it sends nothing until the left mouse button is released, and then sends just one ConfigureNotify/Expose pair. Torrents are OK, if highly inefficient, if you only need to refresh a few lines of background, but if you re-computing a scaled image, it is desperate. Try Cygwin X!

FYI: Running your test program, and making a large change to the width, I only get a single Expose event, without all the intermediates.

X Event: 14 Window: 800002 ReparentNotify

X Event: 14 Window: 800002 ConfigureNotify: x: 34 y: 57 w: 400 h: 300

X Event: 18 Window: 800002 ConfigureNotify: x: 34 y: 57 w: 1708 h: 300

X Event: 18 Window: 800002 Expose: x: 0 y: 0 w: 1708 h: 300