GtkPixelCache is a helper utility that lets you implement
faster scrolling of a viewport of a canvas by using an
offscreen pixmap cache.
You call _gtk_pixel_cache_draw with a callback function that
does the drawing, and additionally you specify the size and the
position of the viewport in the widget, and the position and size
of the canvas wrt the viewport. The callback will be called to
draw on an offscreen surface, and the surface will be drawn
on the window. The next time you do the same, any already drawn
pieces of the surface are re-used from the offscreen and need
not be rendered again.
If things inside the canvas change you need to call
_gtk_pixel_cache_invalidate to tell the cache about this.
Some other details:
* The offscreen surface is generally a bit larger than
the viewport, so scrolling a small amount can often
be done without redrawing children.
* If the canvas is not larger than the viewport no
offscreen surface is used.
GtkPixelCache: Make sure we always copy using SOURCE
We were using OVER for the first copy (from source to group surface.
GtkPixelCache: Fix x/y typos
GtkPixelCache: Allow NULL for invalidate region
gtkpixelcache: Use CONTENT_COLOR for solid bg windows
Since widgets now cache drawn state we allow them to override
queue_draw_region to detect when some region of the widget
should be redrawn. For instance, if a widget draws the
background color in a pixel cache we will need to invalidate
that when the style context changes which queues a repaint.
This lets you register callbacks for when child widgets invalidate
areas of the window read it and/or change it.
For instance, this lets you do rendering effects and keeping offscreen
caches uptodate.
If we got the release event for the last buffer then we're
fine with writing directly to the window surface, as wayland
will not be looing at it. This saves us from allocating
and copying more data.
First of all, we now only do paints on native windows, as there is
really no reason anymore to do it for subwindows. Secondly, we
keep track of the paints even for GtkPaintable windows, but for
that case we don't create the offscreen surface, but rather
assume the windowing system does the backing store.
We do the save/restore when emitting ::draw rather than in a custom
marshaller, as this saves an extra stack frame, which is helpfull now
that we do painting fully recursive. This is also likely to save a few
cycles.
In the case where the layout phase queued a layout we don't
want to progress to the paint phase with invalid allocations, so
we loop the layout. This shouldn't normally happen, but it may
happen in some edge cases like if user/wm resizes clash with
natural window size changes from a gtk widget. This should not
generally loop though, so we detect this after 4 cycles and
print a warning.
This was detected because of an issue in GtkWindow where it
seems to incorrectly handle the case of a user interactive resize.
It seems gtk_window_move_resize() believes that configure_request_size_changed
changed due to hitting some corner case so it calls
gtk_widget_queue_resize_no_redraw(), marking the window as need_alloc
after the layout phase. This commit fixes the issue, but we should
also look into if we can fix that.
Now that all windows are non-opaque we can simplify the invalidation
a lot. There is no need to clip the invalidate area to child regions,
because we will always redraw everything under all the children.
We only have to handle native childen specially.
We now only do one expose event per native window, so there will
only be one begin/end_paint() call. This means all the work with
implicit paints to combine the paints on a single double buffer
surface is unnecessary, so we can just delete it.
We now consider non-native windows non-opaque, which means any invalid
area in a subwindow will also be invalid all the way up to the nearest
native windows. We take advantage of this by ignoring all expose events
on non-native windows (which typically means just the toplevel) and instead
propagating down the draw() calls to children directly via
gtk_container_propagate_draw.
This is nice as it means we always draw widgets the same way, and it
will let us do some interesting ways in the future.
We also clean up the GtkWidget opacity handling as we can now always
rely on the draing happening via cairo.
We can't really just draw by walking down the widget hierarchy, as
this doesn't get the clipping right (so e.g. widgets doing cairo_paint
may draw outside the expected gdkwindow subarea) nor does it let
us paint window backgrounds.
So, we now do multiple draws for each widget, once for each GdkWindow,
although we still do it on the same base cairo_t that we get for the
toplevel native window. The difference is only the clipping, the rendering
order, and which other widgets we propagate into.
We also collect all the windows of a widget so we can expose them inside
the same opacity group if needed.
NOTE: This change neuters gtk_widget_set_double_buffered for
widgets without native windows. Its impossible to disable
the double buffering in this model.
Since we dropped the move region optimization there is really no need
to try carefully keep track of opaque non-overlapped regions, as we
don't use this information to trigger the optimization anymore.
So, by assuming that all windows are non-opaque we can vastly simplify
the clip region stuff. First of all, we don't need clip_region_with_children,
as each window will need to draw under all children anyway. Secondly, we
don't remove overlapping sibling areas from clip_region, as these are
all non-opaque anyway and we need to draw under them
Finally, we don't need to track the layered region anymore as its
essentially unused. The few times something like it is needed we can
compute it explicitly.
For the case of native children of widgets we may cause a repaint
under native windows that are guaranteed to be opaque, but these
will be clipped by the native child anyway.
This basically neuters gdk_window_move_region, gdk_window_scroll
and gdk_window_move_resize, in that they now never copy any bits but
just invalidate the source and destination regions. This is a performance
loss, but the hope is that the simplifications it later allows will let
us recover this performance loss (which mainly affects scrolling).
Turns out our blurring function isn't very nice, it has a lot
of energy past the blur radius, so clipping at exactly the
blur radius causes ugly gradient stops. This just adds 4
extra pixels of slop, which makes this better in most cases.
We split up the rendering of blurred shadows into 9 parts, the
corners, the sides and the rest. This lets us only blur the "blurry"
part, and it lets us completely skip blurry parts that are fully
clipped.
As per css3-background 7.2. Drop Shadows: the ‘box-shadow’ property:
An outer box-shadow casts a shadow as if the border-box of the element
were opaque. The shadow is drawn outside the border edge only: it
is clipped inside the border-box of the element.
Also verified vs firefox behaviour.
Change the visibility handling to be the same way we do it in
GLib now. We pass -fvisibility=hidden to gcc and decorate public
functions with __attribute__((visibility("default"))).
This commit just does this for GDK, GTK+ will follow later.
glib-mkenums is not currently clever enough to know which version an
enum type was added in, so just mark all the _get_type() functions as
available in all versions.
Make all GDK_DEPRECATED and GDK_AVAILABLE macros use a
new _GDK_EXTERN macro. _GDK_EXTERN defaults to just 'extern'
but a subsequent commit will add visibility handling to it
while building GTK+.
glib-mkenums is not currently clever enough to know which version an
enum type was added in, so just mark all the _get_type() functions as
available in all versions.
Add a macro to declare that a particular symbol is available in all
versions of GTK+.
All newly-added symbols should have proper version macros (like
GDK_AVAILABLE_IN_3_4).