Resizing Motif/Xaw/Xlib apps vs. resizing GTK/Qt apps, and how tospeed up an Xlib app - Xwindows

This is a discussion on Resizing Motif/Xaw/Xlib apps vs. resizing GTK/Qt apps, and how tospeed up an Xlib app - Xwindows ; I'm toying with Xlib at the moment (for the experience mostly) and am experiencing difficulties with resize events. From what I've heard on IRC and the Web, it appears that my application is currently processing and acting upon every ConfigureNotify ...

+ Reply to Thread
Results 1 to 4 of 4

Thread: Resizing Motif/Xaw/Xlib apps vs. resizing GTK/Qt apps, and how tospeed up an Xlib app

  1. Resizing Motif/Xaw/Xlib apps vs. resizing GTK/Qt apps, and how tospeed up an Xlib app

    I'm toying with Xlib at the moment (for the experience mostly) and am
    experiencing difficulties with resize events. From what I've heard on IRC
    and the Web, it appears that my application is currently processing and
    acting upon every ConfigureNotify event I'm recieving (basically a few
    XResizeWindow calls), causing /something/ inside X to get majorly
    spammed, lag to bits, and in turn cause my application to lag really
    badly. And the contents of my window are lagging up really badly because
    of this too.

    The biggest difference/discrepancy in resizing I've found with something
    written in Xlib, Xaw or Motif is that these typically don't seem to have
    control of the window they're in and will allow the WM to freely resize
    the window while they try to (almost comically) catch up to the WM's
    movements and lag majorly. elinks -g also exhibits this issue, and was
    the first app I found the problem in, and I was even on Win32, heh. Okay,
    so conversely, GTK or Qt seem to "grab" the window they're in, so the
    window resizes rather jerkily/jumpily in small increments, but the window
    contents "keep up" on each resize jump.

    I've also found that my code and assumedly code of the same type (Xaw/
    Motif/etc) uses 100% CPU while it resizes, but GTK/Qt code doesn't. :/

    So I just wanted advice on (and possibly example code implementing ) a
    way to go about fixing this up. I'm not very experienced with C or X so
    while I do my best to learn quickly I'm not all that fast at times with
    new concepts so do bear with me. :P Also, I #1 might have something
    wrong, and #2 am learning the right and wrong way to do things. If
    there's absolutely anything you think I could/should do differently,
    please do say. :P

    Below is a barebones X/Xlib app that, when compiled, creates a little
    child window inside a top-level window. When you resize the window the
    inner window (which I've set to black so you can actually see it) should
    update its size as well, and hopefully lag so you can see what I'm
    talking about. Note that I color the child window black when I
    XCreateWindow it, so I don't need to use Expose events to manage its
    color upon resize. This proves that this problem isn't Expose-event-
    related.

    Sorry the code looks cramped, I wanted to be sure no servers or clients
    would incorrectly wrap it wrongly causing it to fail to compile. I set it
    to use double-space tabbing so converting ' ' back to '\t' shouldn't be
    a problem if you like "real" tabbing.

    -dav7

    -----

    // gcc -lX11 xdrawsquare.c -o xdrawsquare

    #include
    #include

    int main() {

    int windowwidth = 300, windowheight = 300, run = 1;
    XEvent event;

    Display *display = XOpenDisplay(NULL);
    int screen = DefaultScreen(display);

    XSizeHints hints;
    hints.flags = PSize;

    Window window = XCreateSimpleWindow(display, RootWindow(display,
    screen), 100, 100, windowwidth, windowheight, 1, 10,
    WhitePixel(display, screen));

    Atom wmDeleteMessage = XInternAtom(display, "WM_DELETE_WINDOW",
    False);
    XSetWMProtocols(display, window, &wmDeleteMessage, 1);

    XSetStandardProperties(display, window, "X draw/resize demo",
    "xdrawsquare", None, (char **)"", 0, &hints);

    Window square = XCreateSimpleWindow(display, window, 10, 10,
    windowwidth - 20, windowheight - 20, 0, 0,
    BlackPixel(display, screen));

    XSelectInput(display, window, ExposureMask | KeyPressMask |\
    KeyReleaseMask | StructureNotifyMask);

    XMapWindow(display, square);
    XMapWindow(display, window);

    while (run == 1) {

    XNextEvent(display, &event);

    switch (event.type) {

    case DestroyNotify:
    case ClientMessage:
    if (event.xclient.data.l[0] ==
    wmDeleteMessage) run = 0;
    break;

    case ConfigureNotify:

    if (event.xconfigure.window == window) {

    windowwidth =
    event.xconfigure.width;
    windowheight =
    event.xconfigure.height;

    XResizeWindow(display, square,
    windowwidth - 20,
    windowheight - 20);

    }

    break;

    default:
    break;

    }

    }

    XDestroyWindow(display, square);
    XDestroyWindow(display, window);

    XCloseDisplay(display);

    }

  2. Re: Resizing Motif/Xaw/Xlib apps vs. resizing GTK/Qt apps, and how to speed up an Xlib app

    David Lindsay wrote:

    > I'm toying with Xlib at the moment (for the experience mostly) and am
    > experiencing difficulties with resize events. From what I've heard on IRC
    > and the Web, it appears that my application is currently processing and
    > acting upon every ConfigureNotify event I'm recieving (basically a few
    > XResizeWindow calls), causing /something/ inside X to get majorly
    > spammed, lag to bits, and in turn cause my application to lag really
    > badly. And the contents of my window are lagging up really badly because
    > of this too.
    >
    > The biggest difference/discrepancy in resizing I've found with something
    > written in Xlib, Xaw or Motif is that these typically don't seem to have
    > control of the window they're in and will allow the WM to freely resize
    > the window while they try to (almost comically) catch up to the WM's
    > movements and lag majorly. elinks -g also exhibits this issue, and was
    > the first app I found the problem in, and I was even on Win32, heh. Okay,
    > so conversely, GTK or Qt seem to "grab" the window they're in, so the
    > window resizes rather jerkily/jumpily in small increments, but the window
    > contents "keep up" on each resize jump.


    There are several things causing redraw performance issues in X11, and
    there's not much you can do about some of it. I know, because I wrote a
    window system that wasn't based on X11, and I've worked with X11 for years.

    X11 uses a mostly asynchronous drawing model, so flicker is one result of
    that on resize.

    Here's how a resize typically works.

    1. user triggers an event that causes a button press event to be sent to a
    particular app, such as the WM.
    2. the WM responds by setting some state variable to dragging
    3. the WM processes pointer motion events and calculates a delta that fits
    the current hints, and thereby produces a new size for the application
    window.
    4. the WM calls XResizeWindow or XConfigureWindow
    5. the application receives a ConfigureNotify due to step 4 and at some
    point redraws, perhaps then, or perhaps when its event loop is idle.
    6. graphics get drawn via X requests.
    7. repeat steps 3 through 6 until a button release triggers the !dragging
    state.

    There are various positions in between where graphics may be
    drawn/composited to the display memory before step 6, while the window
    being resized hasn't fully drawn its contents, because X is serving drawing
    requests from multiple clients. The asynchronous model can't really solve
    this, unless we assume that the new window contents are transparent, and
    even then the titlebar width wouldn't match the content width, for a few
    frames potentially.

    The way it worked in my window system was different. The WM was builtin to
    the server via an API, and would actually smoothly resize, and provide a
    more synchronous redraw system. If you don't actually resize the parent
    window until the client has responded, say with an update message, then the
    contents never get out of sync with reality, and you wouldn't see flicker.

    Resizing can often be costly, because it usually means reallocating a fairly
    large RGB or RGBA buffer, and thus the old buffer may be unmapped with a
    new buffer being mmaped in. This means TLB updates, and cache misses, and
    well, resizing is not a simple chore to optimize in the general case. A
    somewhat high-water-mark allocation scheme can help a little.

    It works differently of course with a WM that uses the sort of "rubberband"
    resize approach, which relies on grabbing the pointer until the user has
    clicked, such as TWM. Such a scheme doesn't generate nearly as many
    events.

    The flicker is not generally a serious problem for most people, but it's
    sometimes annoying.

    > I've also found that my code and assumedly code of the same type (Xaw/
    > Motif/etc) uses 100% CPU while it resizes, but GTK/Qt code doesn't. :/


    The lag/CPU usage could be from a variety of causes. The geometry managers
    may not be ideal, or as well optimized as Gtk+ and Qt. Geometry managers
    are difficult to write, at least for me. Gtk+/Gdk and Qt use shared memory
    for some of their graphics, Motif and Xaw generally do not.

    >
    > So I just wanted advice on (and possibly example code implementing ) a
    > way to go about fixing this up. I'm not very experienced with C or X so
    > while I do my best to learn quickly I'm not all that fast at times with
    > new concepts so do bear with me. :P Also, I #1 might have something
    > wrong, and #2 am learning the right and wrong way to do things. If
    > there's absolutely anything you think I could/should do differently,
    > please do say. :P
    >
    > Below is a barebones X/Xlib app that, when compiled, creates a little
    > child window inside a top-level window. When you resize the window the
    > inner window (which I've set to black so you can actually see it) should
    > update its size as well, and hopefully lag so you can see what I'm
    > talking about. Note that I color the child window black when I
    > XCreateWindow it, so I don't need to use Expose events to manage its
    > color upon resize. This proves that this problem isn't Expose-event-
    > related.


    Generally you will probably want to redraw after a ConfigureNotify too,
    IIRC.

    > Sorry the code looks cramped, I wanted to be sure no servers or clients
    > would incorrectly wrap it wrongly causing it to fail to compile. I set it
    > to use double-space tabbing so converting ' ' back to '\t' shouldn't be
    > a problem if you like "real" tabbing.
    >
    > -dav7
    >
    > -----
    >
    > // gcc -lX11 xdrawsquare.c -o xdrawsquare
    >
    > #include
    > #include
    >
    > int main() {
    >
    > int windowwidth = 300, windowheight = 300, run = 1;
    > XEvent event;
    >
    > Display *display = XOpenDisplay(NULL);
    > int screen = DefaultScreen(display);
    >
    > XSizeHints hints;
    > hints.flags = PSize;
    >
    > Window window = XCreateSimpleWindow(display, RootWindow(display,
    > screen), 100, 100, windowwidth, windowheight, 1, 10,
    > WhitePixel(display, screen));
    >
    > Atom wmDeleteMessage = XInternAtom(display, "WM_DELETE_WINDOW",
    > False);
    > XSetWMProtocols(display, window, &wmDeleteMessage, 1);
    >
    > XSetStandardProperties(display, window, "X draw/resize demo",
    > "xdrawsquare", None, (char **)"", 0, &hints);
    >
    > Window square = XCreateSimpleWindow(display, window, 10, 10,
    > windowwidth - 20, windowheight - 20, 0, 0,
    > BlackPixel(display, screen));
    >
    > XSelectInput(display, window, ExposureMask | KeyPressMask |\
    > KeyReleaseMask | StructureNotifyMask);
    >
    > XMapWindow(display, square);
    > XMapWindow(display, window);
    >
    > while (run == 1) {
    >
    > XNextEvent(display, &event);
    >
    > switch (event.type) {
    >
    > case DestroyNotify:
    > case ClientMessage:
    > if (event.xclient.data.l[0] ==
    > wmDeleteMessage) run = 0;
    > break;
    >
    > case ConfigureNotify:
    >
    > if (event.xconfigure.window == window) {
    >
    > windowwidth =
    > event.xconfigure.width;
    > windowheight =
    > event.xconfigure.height;
    >
    > XResizeWindow(display, square,
    > windowwidth - 20,
    > windowheight - 20);
    >
    > }


    This strikes me as odd. Something else, such as the window manager (WM) has
    notified you of the size it chose, and thus you get a ConfigureNotify. By
    doing another ConfigureRequest you can create a lot of unnecessary events.
    The XResizeWindow when a WM is redirecting Configure requests ends up
    causing the WM to respond in some way. Just accept what the WM tells you
    the toplevel size is.

    With regard to subwindows, you can choose any size you want, unless you have
    redirection enabled for the parent.

    --George

  3. Re: Resizing Motif/Xaw/Xlib apps vs. resizing GTK/Qt apps, and how to speed up an Xlib app

    David Lindsay wrote:

    > ...causing /something/ inside X to get majorly
    > spammed, lag to bits, and in turn cause my application to lag really
    > badly. And the contents of my window are lagging up really badly because
    > of this too.


    Qt handles this by processing only the final ConfigureNotify event in any
    given series of events. X11 generates a ConfigureNotify event for *every*
    change in window size. Fully processing all of the events is going to
    cause major display lag.


  4. Re: Resizing Motif/Xaw/Xlib apps vs. resizing GTK/Qt apps, and how tospeed up an Xlib app

    On Nov 9, 8:37*am, Tony wrote:
    > David Lindsay wrote:
    > > ...causing /something/ inside X to get majorly
    > > spammed, lag to bits, and in turn cause my application to lag really
    > > badly. And the contents of my window are lagging up really badly because
    > > of this too.

    >
    > Qt handles this by processing only the final ConfigureNotify event in any
    > given series of events. *X11 generates a ConfigureNotify event for *every*
    > change in window size. *Fully processing all of the events is going to
    > cause major display lag.


    Tony hinted at the correct way to handle this. In your event loop,
    whenever you find a ConfigureNotify for your window, you should check
    the
    rest of the event queue to see if it contains other ConfigureNotify
    events
    on your window.; Discard all but the last one, and process that one.
    See XCheckTypedWindowEvent.

    This same technique should be used for MotionNotify, Expose, Enter,
    and Leave events.

    Most Motif widgets do this automatically, by setting their
    compress_motion,
    compress_exposure, and compress_enterleave fields to TRUE.
    --
    Fred Kleinschmidt

+ Reply to Thread