| Unix Content | Register | FAQ | Calendar | Search | Today's Posts | Mark Forums Read |
|
#1
|
| 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 ) away 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
|
| 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
|
| 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
|
| On Nov 9, 8:37*am, Tony > 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 |