Jerky window resize animations with GTK on Linux

488 views
Skip to first unread message

Prasad Tammana

unread,
Jan 18, 2011, 9:02:29 PM1/18/11
to Chromium-dev
I'm prototyping some UI for implementing panels on Linux.  One of the things is to animate panel resizing.  I have a timer that fires every 20 milliseconds and the resize spans over 200 milliseconds.  Its getting really jerky once I'm past 3 or 4 windows.  Am I missing some tricks with regards to making the animation go smoother?

Thanks,
Prasad

Daniel Erat

unread,
Jan 18, 2011, 9:35:55 PM1/18/11
to pra...@chromium.org, Chromium-dev

(Apologies if you already know much/all of this.)

When an X client app attempts to move or resize one of its
(non-override-redirect / "popup" in GDK parlance) windows, the
ConfigureRequest message that it sends to the X server gets redirected
to the window manager. The window manager has the option of sending
the request back to the server (possibly with modifications) or
ignoring it. Once the X server receives the request from the window
manager, it resizes the window, which triggers ConfigureNotify and
(only if the window gets larger, I think) expose events to be sent to
the client. After all of this is done, the client can send additional
requests to the X server to repaint the window.

But things are actually more complicated than this, at least for many
common window managers.
http://standards.freedesktop.org/wm-spec/wm-spec-latest.html#id2552503
describes a scheme by which the window manager, upon resizing a
window, asks the client to notify it once it's done repainting the
resized window. This was initially done to rate-limit resizes so that
clients wouldn't fall behind, but in the case of compositing window
managers (Compiz, Mutter, KWin, etc.), it's also used to avoid drawing
the window onscreen again until it's been fully repainted.

So if you're trying to animate resizes while running under a
compositing window manager, I think that you're looking at:
- Chrome sends ConfigureRequest to server
- server sends ConfigureRequest to window manager
- window manager sends _NET_WM_SYNC_REQUEST ClientMessage to Chrome
and ConfigureRequest to server
- server sends ConfigureNotify to Chrome
- Chrome sends paint commands to server and increments sync request counter
- server sends damage event and notification that counter changed to
window manager
- window manager fetches updated window contents and paints them
onscreen using GL or whatever (avoiding additional copies, driver
willing)

If you're using override-redirect windows, the initial
ConfigureRequest redirection and the sync request stuff goes away (at
the expense of unpainted garbage probably being visible onscreen as
the window resizes itself).

If you only care about making the animation work for compositing
window managers, a better approach might be just using an RGBA window
for your panel (if you aren't already), and then resizing the window
just once to the final size and only animating its _appearance_
changing between the two sizes. That way, the resizing-related bits
only happen once and you can do your animation without any round trips
to the server.

I've found xtrace (http://xtrace.alioth.debian.org/) to be useful in
debugging performance issues in X clients. You could also try running
your code without a window manager to see if that improves things.

Prasad Tammana

unread,
Jan 18, 2011, 10:45:18 PM1/18/11
to Daniel Erat, Chromium-dev
Wow!  That's a lot of information.

I'm creating the panels with - gtk_window_new(GTK_WINDOW_POPUP).  My code is not in Chrome, this is a stand-alone Gtk app that I'm writing to prototype the UI.  While the resize animations are jerky, I don't see that jerkiness with move animations and it seems to work smoothly with even 8 windows and they involve an equivalent number of move operations as there are resize operations in case of resize animation.  I'm not sure if that tells you something.

> If you only care about making the animation work for compositing
> window managers, a better approach might be just using an RGBA window
> for your panel (if you aren't already), and then resizing the window
> just once to the final size and only animating its _appearance_
> changing between the two sizes.  That way, the resizing-related bits
> only happen once and you can do your animation without any round trips
> to the server.

At the moment, I don't know if this only needs to work for compositing window mangers.  Is there a policy in Chrome with regards to what window managers we work well with?  Can you send me some pointers to info/API for RGBA windows?  A quick search didn't turn up much.  And lastly, what does animating appearance mean?  My specific scenario is that I'm sizing the window from a height of say, 400 pixels, down to 5 pixels and trying to animate this by resizing a few pixels every 20 seconds.

Thanks for the detailed mail, I'll work through it and also check out xtrace.

Prasad

Daniel Erat

unread,
Jan 18, 2011, 11:04:36 PM1/18/11
to Prasad Tammana, Chromium-dev
On Tue, Jan 18, 2011 at 7:45 PM, Prasad Tammana <pra...@chromium.org> wrote:
> I'm creating the panels with - gtk_window_new(GTK_WINDOW_POPUP).  My code is
> not in Chrome, this is a stand-alone Gtk app that I'm writing to prototype
> the UI.  While the resize animations are jerky, I don't see that jerkiness
> with move animations and it seems to work smoothly with even 8 windows and
> they involve an equivalent number of move operations as there are resize
> operations in case of resize animation.  I'm not sure if that tells you
> something.

You're probably not seeing any performance issues with move animations
since your client doesn't need to redraw its windows' contents for
each frame of animation. In the resize case, I think that there's a
round trip between your client and the X server for each frame (as you
might not redraw until you receive notification from the server that
the window has been resized). It's possible that GDK avoids this
delay for popup windows since it knows that its resize request will be
honored. Things will still look janky since resizing and redrawing
happen non-atomically, though.

> At the moment, I don't know if this only needs to work for compositing
> window mangers.  Is there a policy in Chrome with regards to what window
> managers we work well with?  Can you send me some pointers to info/API for
> RGBA windows?  A quick search didn't turn up much.  And lastly, what does
> animating appearance mean?  My specific scenario is that I'm sizing the
> window from a height of say, 400 pixels, down to 5 pixels and trying to
> animate this by resizing a few pixels every 20 seconds.

I meant that in the case of making a panel resize from 100x100 to
400x400, you could resize the window once to 400x400 and paint the
contents within the 110x110 region while leaving the rest of the
window transparent, then within 120x120, and so on. The window's
alpha channel will only be honored if there's a compositor running,
but if you don't need partial transparency, you could use the shape
extension to mask out portions of the window without using RGBA
windows (using the shape extension may have worse performance in
compositing window managers, though). I don't know of any good
resources about RGBA windows in X. :-/

It's a bit off-topic, but what's your plan for the actual
implementation of this with regard to using normal vs. popup windows?
If you use normal windows, you'll have compatibility problems with
various window managers ignoring or misinterpreting your requests to
move and resize your panels. If you use popup windows, input won't
work (the window manager will never focus your panels). To get around
this in Chrome OS, we just wrote our own window manager that knows how
to handle our panels. :-P

Prasad Tammana

unread,
Jan 19, 2011, 11:02:05 PM1/19/11
to Daniel Erat, Chromium-dev
Comments in-line:

On Tue, Jan 18, 2011 at 8:04 PM, Daniel Erat <de...@chromium.org> wrote:
On Tue, Jan 18, 2011 at 7:45 PM, Prasad Tammana <pra...@chromium.org> wrote:

You're probably not seeing any performance issues with move animations
since your client doesn't need to redraw its windows' contents for
each frame of animation.  In the resize case, I think that there's a
round trip between your client and the X server for each frame (as you
might not redraw until you receive notification from the server that
the window has been resized).  It's possible that GDK avoids this
delay for popup windows since it knows that its resize request will be
honored.  Things will still look janky since resizing and redrawing
happen non-atomically, though.

That's a useful insight.  I'll use the tool pointed out to look at the X traffic.  Is there some way to suppress redraws?  In my demo, there is no content on the windows, I'd have thought there would be no redraws.  I see the same behavior when I switch from popup to toplevel windows.
 
I meant that in the case of making a panel resize from 100x100 to
400x400, you could resize the window once to 400x400 and paint the
contents within the 110x110 region while leaving the rest of the
window transparent, then within 120x120, and so on.  The window's
alpha channel will only be honored if there's a compositor running,
but if you don't need partial transparency, you could use the shape
extension to mask out portions of the window without using RGBA
windows (using the shape extension may have worse performance in
compositing window managers, though).  I don't know of any good
resources about RGBA windows in X. :-/

That's interesting.  I'll experiment with that and see what I figure.
 
It's a bit off-topic, but what's your plan for the actual
implementation of this with regard to using normal vs. popup windows?
If you use normal windows, you'll have compatibility problems with
various window managers ignoring or misinterpreting your requests to
move and resize your panels.  If you use popup windows, input won't
work (the window manager will never focus your panels).  To get around
this in Chrome OS, we just wrote our own window manager that knows how
to handle our panels. :-P

I didn't realize popup windows can't take keyboard input and I verified that.  I changed my code to use top level windows.  After a handful of tweaks to keep the window on top, not show up in task bar, not re-sizable and a few others, I got the panels to have the same visual look and feel as the popup windows.  But now, as you pointed out might happen, the positioning of the window is not pixel perfect anymore, especially when I minimize it.  Looks like I have to solve one of two problems:

1) Make popup windows take keyboard focus or
2) Figure a way to convince the window manager to honor the size and position requests precisely.

I don't think we'll be writing a new window manager for chrome on Linux :-)  Looking at the documentation option 1) doesn't seem like a good idea as I might run into other problems(?).  I'd appreciate any ideas/thoughts in this regard.

Thanks,
Prasad

Daniel Erat

unread,
Jan 21, 2011, 3:41:52 PM1/21/11
to Prasad Tammana, Chromium-dev
On Wed, Jan 19, 2011 at 8:02 PM, Prasad Tammana <pra...@chromium.org> wrote:
[snip]

> traffic.  Is there some way to suppress redraws?  In my demo, there is no
> content on the windows, I'd have thought there would be no redraws.  I see
> the same behavior when I switch from popup to toplevel windows.

Whether to redraw or not is up to the toolkit, as far as I'm aware.
It could maybe be avoided in some cases where the window is getting
smaller, assuming that its bit gravity is set correctly (see
http://tronche.com/gui/x/xlib/window/attributes/gravity.html).

If you only need to animate panels sliding down off the bottom of the
screen, you may also be able to just animate them moving offscreen
instead of resizing them.

[snip]


> minimize it.  Looks like I have to solve one of two problems:
> 1) Make popup windows take keyboard focus or
> 2) Figure a way to convince the window manager to honor the size and
> position requests precisely.
> I don't think we'll be writing a new window manager for chrome on Linux :-)
>  Looking at the documentation option 1) doesn't seem like a good idea as I
> might run into other problems(?).  I'd appreciate any ideas/thoughts in this
> regard.

Yeah, 1) isn't a great choice. It's what the Linux version of Chrome
uses for infobubbles (such as the bookmark bubble) since we ran into
issues with some window managers when using normal windows with
_NET_WM_WINDOW_TYPE_UTILITY (the window manager isn't under any
obligation to honor move or resize requests), but there are problems
with various GTK widgets' behavior when the window grabs the focus
instead of getting it assigned by the window manager, and grabbing the
keyboard is user-unfriendly (window manager shortcuts like Alt-Tab
won't work, for instance).

Reply all
Reply to author
Forward
0 new messages