I've just pushed the wip/simple-draw4 branch which is the latest version of my work trying to simplify and modernize the Gtk drawing machinery. Its now in a state where I think its time to discuss the merging of this.
The very first commit in the branch makes gdk_window_move() and gdk_window_scroll() very dumb. Previously it tried to copy as much as possible of the existing pixels and only invalidate the areas that were previously not visible. Now it just invalidates the entire scrolled area and redraws it. This may seem a bit crazy and slow, but in fact its just the first step in making the gdk drawing model more modern. Doing scrolling by same-surface copying is an old technology has some problems in the modern world. First of all, on modern hardware a same-surface copy doesn't work very well (for technical reasons). In fact, the operation is a no-op in the wayland backend atm. Secondly, in a more "modern" scene graph like in recent gtk3 most windows have alpha pixels and render over the window background rather than each window rendering its own opaque background, so scrolling via copy doesn't work. So, the branch continues with deleting lots of very tricky code inside gdk where does things like figuring out the cases where we can apply the copy optimization, and handling async exposes from the xserver racing with copy-area of the same region from the app. A more modern way to do scrolling is to keep an offscreen buffer for the content inside the scrolling region, covering what is currently visible in the viewport plus a bit more. Then when we draw the window we just draw the buffer in the right place, making scrolling very fast. Although if you scroll to far we have to render a new piece of the offscreen buffer. To do this kind of scrolling a container needs two things, a way to get told when a child needs redrawing so that we can make our cache dirty, and a way to retarget rendering the children to the offscreen buffer. We add some gdk API (gdk_window_set_invalidate_handler) for the first, but the second is a bit more complex. Right now rendering is done in many separate phases, one per GdkWindow where for each GdkWindow there may be several non-window widgets (and each widget may have several windows too). The branch completely redoes this so that Gtk+ only ever handles expose events on native windows (i.e. generally toplevels only) and then renders everything inside the ::draw signal handler of the toplevel widget. In order to maximize backwards compatibility we still call draw() multiple times on multi-window widgets, with the right clipping set up and the right window backgrounds rendered, however, there are still some minor differences. For instance, we expose primarily in widget order whereas we previously exposed in window order (although for windows in the same widget we respect the window order), but this is rarely a problem because intra-widget window order in gdk is hard to control anyway due to realize being called in unexpected places. With this in place the branch then does some further simplifications and then adds fast scrolling support to GtkViewport and GtkTreeView via the new GtkPixelCache helper object. I've tried a bunch of apps and most things seem to work. Currently I know of two problems: The control-center background panel calls gdk_cairo_create() inside the draw() handler, which draws directly to the window rather than the passed in cairo_t. This "works" in a sense, but the rendering is then unaffected by the cairo_push()/pop() that the stack uses for crossfading, so the crossfade effect breaks. This could possibly happen in other cases, but it seems like it is pretty uncommon (I didn't find any other problematic use in all of Gnome). The control-center display panel does this weird thing where it "draws" areas using cairo, and then reads it back to use as input regions. This code assumes that the coordinates on the cairo_t when converted via cairo_user_to_device() is in the coordinate space of the widgets windows, whereas it is now in the coordinate space of the toplevel. This makes the input regions offset by the position of the widget making it hard to click/drag them. This is a pretty weird thing to do, and i don't expect we'll run into other apps doing the same thing. IMHO we can just land the branch and fix these issues inside the control-center. Its a minor incompatibility change, but I think its still worth it. There is still some further work we may want to work on after the branch lands, in case someone wants to help out: * Port GtkIconView to GtkPixelCache * Port GtkTextView to GtkPixelCache * Have some way to hint a GtkPixelCache so that we e.g. always render an entire treeview row or textview paragraph when painting, to avoid multiple setups for drawing it when scrolling. * Try a tile-based approach for GtkPixelCache to avoid having to do a same-surface copy (usign an intermediate surface) when scrolling the cache. _______________________________________________ gtk-devel-list mailing list gtk-devel-list@gnome.org https://mail.gnome.org/mailman/listinfo/gtk-devel-list