Compare commits

..

24 Commits

Author SHA1 Message Date
Alexander Larsson a0eac16cb8 gdkframeclock: Loop the layout phase if needed
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.
2013-04-24 23:10:05 +02:00
Alexander Larsson a0c95153f1 Change the way we draw (again)
We can't really just draw by walking down the widget hierarchy, as
this doesn't get the right clipping (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 expose event
although we still do it at the same base cairo_t that we get for the
toplevel native window.

We also collect all the windows of a widget so we can expose them inside
the same opacity group if needed.
2013-04-24 23:10:05 +02:00
Alexander Larsson 550175a99b gdkwindow: Change update_handler to invalidate_handler
The new name fits better, plus we also remove the return value, and
adds docs.
2013-04-24 23:10:05 +02:00
Alexander Larsson 26b93a8468 GtkViewport: Add offscreen surface based scrolling
Rather than scroll via XCopyArea (which we no longer do) we keep an
offscreen buffer of the scrolled area with some extra space outside
the visible area and when we expose the viewport we just blit the
offscreen to the right place.
2013-04-24 23:10:05 +02:00
Alexander Larsson b47f774b74 gtkcontainer: Don't propagate draws to non-drawable widgets
This short-circuits the propagation a bit earlier and fixes
a crash when looking for has_native_window on non-realized widgets.
2013-04-24 23:10:05 +02:00
Alexander Larsson cb98f90a38 Add gdk_window_set_update_handler
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.
2013-04-24 23:10:05 +02:00
Alexander Larsson 08c33ef953 gdkwindow: Simplify invalidation
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.
2013-04-24 23:10:04 +02:00
Alexander Larsson 2fa0536564 gdkwindow: Remove implicit paints
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.
2013-04-24 23:10:04 +02:00
Alexander Larsson a05fc8f5b9 Only handle exposes on native window, propagate to children via draw()
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.

NOTE: This change neuters gtk_widget_set_double_buffered for
widgets without native windows
2013-04-24 23:10:04 +02:00
Alexander Larsson 76615eba3a gdkwindow: Remove ancient USE_BACKING_STORE define
This is always set anyway.
2013-04-24 23:10:04 +02:00
Alexander Larsson b498ef1793 gdkwindow: Simplify clip region calculations
Since we no longer make overlapping siblings affect clip_region we
can further simplify the clip region calculation and updating.
2013-04-24 23:10:04 +02:00
Alexander Larsson 89dd7353fc gdkwindow: Simplify clip region handling
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.
2013-04-24 23:10:04 +02:00
Alexander Larsson bcf751d33f gdkwindow: Remove translate vfunc
This is not used anymore
2013-04-24 23:10:04 +02:00
Alexander Larsson 9f8e06265b gdkwindow: Remove outstanding_moves stuff
Since we now never move regions directly on the window we can
remove all the stuff that track outstanding moves and flushes then.
2013-04-24 23:10:04 +02:00
Alexander Larsson 2a0377017c gdk: Don't ever do copies from the window
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).
2013-04-24 23:10:03 +02:00
Cosimo Cecchi 06c8e8fa43 docs: fix some typos in newly introduced methods 2013-04-24 13:10:54 -04:00
Nik Kalach 95ce57443c [l10n] Update Interlingua translation 2013-04-24 16:03:15 +02:00
Yaron Shahrabani 9544ae08af Updated Hebrew translation. 2013-04-24 10:08:19 +03:00
Yaron Shahrabani 648ef7f7fa Updated Hebrew translation. 2013-04-24 09:45:26 +03:00
Matthias Clasen 661f24736b widget-factory: Add new widgets
Add GtkStack and GtkRevealer to the second page in
gtk3-widget-factory.
2013-04-23 17:39:46 -04:00
Benjamin Otte 174664b235 overlay: Silence gcc warnings 2013-04-23 14:13:51 -04:00
Owen W. Taylor 8c68050af8 tests/scrolling-performance: Add a new test for GtkViewport performance
Add a test that takes four copies of the widget-factory widgets and
scrolls them around to test how smoothly we can scroll and draw.
2013-04-23 14:04:40 -04:00
Owen W. Taylor b7063509f8 tests/animated-resizing: Split frame statistics out into a separate file
Split the code for computing frame rate and latency into a separate file
so we can use it from multiple tests.
2013-04-23 14:04:40 -04:00
Owen W. Taylor 0032b2dc5a GtkSpinButton: don't constantly recreate style contexts for buttons
Cache the style contexts for the up and down panels, instead of recreating
them each time they are drawn or size requested. GtkSpinButtons were
many times slower to draw than other widgets because of the constant
style matching.

https://bugzilla.gnome.org/show_bug.cgi?id=698682
2013-04-23 14:04:39 -04:00
39 changed files with 3079 additions and 4532 deletions
+38
View File
@@ -78,6 +78,35 @@ on_page_toggled (GtkToggleButton *button,
gtk_notebook_set_current_page (pages, page);
}
static void
spin_value_changed (GtkAdjustment *adjustment, GtkWidget *label)
{
GtkWidget *w;
gint v;
gchar *text;
v = (int)gtk_adjustment_get_value (adjustment);
if ((v % 3) == 0)
{
text = g_strdup_printf ("%d is a multiple of 3", v);
gtk_label_set_label (GTK_LABEL (label), text);
g_free (text);
}
w = gtk_widget_get_ancestor (label, GTK_TYPE_REVEALER);
gtk_revealer_set_reveal_child (GTK_REVEALER (w), (v % 3) == 0);
}
static void
dismiss (GtkWidget *button)
{
GtkWidget *w;
w = gtk_widget_get_ancestor (button, GTK_TYPE_REVEALER);
gtk_revealer_set_reveal_child (GTK_REVEALER (w), FALSE);
}
int
main (int argc, char *argv[])
{
@@ -86,6 +115,7 @@ main (int argc, char *argv[])
GtkWidget *widget;
GtkWidget *notebook;
gboolean dark = FALSE;
GtkAdjustment *adj;
gtk_init (&argc, &argv);
@@ -114,6 +144,14 @@ main (int argc, char *argv[])
widget = (GtkWidget*) gtk_builder_get_object (builder, "aboutmenuitem");
g_signal_connect (widget, "activate", G_CALLBACK (show_about), window);
widget = (GtkWidget*) gtk_builder_get_object (builder, "page2dismiss");
g_signal_connect (widget, "clicked", G_CALLBACK (dismiss), NULL);
widget = (GtkWidget*) gtk_builder_get_object (builder, "page2note");
adj = (GtkAdjustment *) gtk_builder_get_object (builder, "adjustment2");
g_signal_connect (adj, "value-changed",
G_CALLBACK (spin_value_changed), widget);
g_object_unref (G_OBJECT (builder));
gtk_widget_show (window);
+160 -15
View File
@@ -54,6 +54,23 @@ Vestibulum in tortor diam, quis aliquet quam. Praesent ut justo neque, tempus ru
Duis eu lectus quam. Vivamus eget metus a mauris molestie venenatis pulvinar eleifend nisi.
Nulla facilisi. Pellentesque at dolor sit amet purus dapibus pulvinar molestie quis neque.
Suspendisse feugiat quam quis dolor accumsan cursus. </property>
</object>
<object class="GtkTextBuffer" id="textbuffer2">
<property name="text">* Translation updates:
Aragonese
Assamese
Basque
Brazilian Portuguese
Dutch
German
Hebrew
Hungarian
Polish
Portuguese
Serbian
Slovenian
Spanish
Uyghur</property>
</object>
<object class="GtkAccelGroup" id="accelgroup1"/>
<object class="GtkWindow" id="window">
@@ -2146,30 +2163,158 @@ Suspendisse feugiat quam quis dolor accumsan cursus. </property>
</object>
</child>
<child>
<object class="GtkBox" id="page2">
<object class="GtkOverlay" id="page2">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<property name="border-width">6</property>
<child>
<object class="GtkBox" id="page2box1">
<child type="overlay">
<object class="GtkRevealer" id="page2revealer">
<property name="visible">True</property>
<property name="orientation">horizontal</property>
<property name="spacing">4</property>
<property name="halign">center</property>
<property name="valign">start</property>
<child>
<object class="GtkSpinButton" id="verticalspin1">
<object class="GtkFrame" id="page2frame">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="adjustment">adjustment2</property>
<property name="margin-top">2</property>
<child>
<object class="GtkBox" id="page2box">
<property name="visible">True</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin-left">10</property>
<property name="margin-right">10</property>
<property name="spacing">20</property>
<child>
<object class="GtkLabel" id="page2note">
<property name="visible">True</property>
<property name="hexpand">True</property>
<property name="halign">start</property>
<property name="label">NEWS!</property>
</object>
</child>
<child>
<object class="GtkButton" id="page2dismiss">
<property name="visible">True</property>
<child>
<object class="GtkImage" id="page2dismissi">
<property name="visible">True</property>
<property name="icon-name">window-close-symbolic</property>
<property name="icon-size">0</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkGrid" id="page2grid">
<property name="visible">True</property>
<property name="column-homogeneous">True</property>
<property name="row-spacing">6</property>
<property name="column-spacing">6</property>
<property name="border-width">6</property>
<child>
<object class="GtkSpinButton" id="verticalspin2">
<object class="GtkBox" id="page2box1">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="orientation">vertical</property>
<property name="adjustment">adjustment1</property>
<property name="orientation">horizontal</property>
<property name="spacing">4</property>
<child>
<object class="GtkSpinButton" id="verticalspin1">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="adjustment">adjustment2</property>
</object>
</child>
<child>
<object class="GtkSpinButton" id="verticalspin2">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="orientation">vertical</property>
<property name="adjustment">adjustment1</property>
</object>
</child>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="filler1">
<property name="visible">True</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="filler2">
<property name="visible">True</property>
</object>
<packing>
<property name="left-attach">2</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkStackSwitcher" id="switcher">
<property name="visible">True</property>
<property name="stack">stack</property>
<property name="halign">center</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame">
<property name="visible">True</property>
<property name="hexpand">False</property>
<child>
<object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="transition-type">crossfade</property>
<property name="transition-duration">1000</property>
<child>
<object class="GtkScrolledWindow" id="swo">
<property name="visible">True</property>
<property name="shadow-type">none</property>
<child>
<object class="GtkTextView" id="tvo">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="buffer">textbuffer2</property>
</object>
</child>
</object>
<packing>
<property name="name">page1</property>
<property name="icon-name">document-open-recent-symbolic</property>
<property name="title">News</property>
</packing>
</child>
<child>
<object class="GtkImage" id="imageo">
<property name="visible">True</property>
<property name="resource">/logos/gtk-logo-256.png</property>
</object>
<packing>
<property name="name">page2</property>
<property name="icon-name">system-shutdown-symbolic</property>
<property name="title">Logo</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
</packing>
</child>
</object>
</child>
-51
View File
@@ -1470,56 +1470,6 @@ _gdk_broadway_window_queue_antiexpose (GdkWindow *window,
return TRUE;
}
static void
copy_region (cairo_surface_t *surface,
cairo_region_t *area,
gint dx,
gint dy)
{
cairo_t *cr;
cr = cairo_create (surface);
gdk_cairo_region (cr, area);
cairo_clip (cr);
/* NB: This is a self-copy and Cairo doesn't support that yet.
* So we do a litle trick.
*/
cairo_push_group (cr);
cairo_set_source_surface (cr, surface, dx, dy);
cairo_paint (cr);
cairo_pop_group_to_source (cr);
cairo_paint (cr);
cairo_destroy (cr);
}
void
_gdk_broadway_window_translate (GdkWindow *window,
cairo_region_t *area,
gint dx,
gint dy)
{
GdkWindowImplBroadway *impl;
GdkBroadwayDisplay *broadway_display;
impl = GDK_WINDOW_IMPL_BROADWAY (window->impl);
if (impl->surface)
{
copy_region (impl->surface, area, dx, dy);
broadway_display = GDK_BROADWAY_DISPLAY (gdk_window_get_display (window));
if (_gdk_broadway_server_window_translate (broadway_display->server,
impl->id,
area, dx, dy))
queue_flush (window);
}
}
guint32
gdk_broadway_get_last_seen_time (GdkWindow *window)
{
@@ -1558,7 +1508,6 @@ gdk_window_impl_broadway_class_init (GdkWindowImplBroadwayClass *klass)
impl_class->input_shape_combine_region = gdk_window_broadway_input_shape_combine_region;
impl_class->set_static_gravities = gdk_window_broadway_set_static_gravities;
impl_class->queue_antiexpose = _gdk_broadway_window_queue_antiexpose;
impl_class->translate = _gdk_broadway_window_translate;
impl_class->destroy = _gdk_broadway_window_destroy;
impl_class->destroy_foreign = gdk_broadway_window_destroy_foreign;
impl_class->resize_cairo_surface = gdk_window_broadway_resize_cairo_surface;
+11 -1
View File
@@ -384,6 +384,7 @@ gdk_frame_clock_paint_idle (void *data)
case GDK_FRAME_CLOCK_PHASE_LAYOUT:
if (priv->freeze_count == 0)
{
int iter;
#ifdef G_ENABLE_DEBUG
if ((_gdk_debug_flags & GDK_DEBUG_FRAMES) != 0)
{
@@ -394,11 +395,20 @@ gdk_frame_clock_paint_idle (void *data)
#endif /* G_ENABLE_DEBUG */
priv->phase = GDK_FRAME_CLOCK_PHASE_LAYOUT;
if (priv->requested & GDK_FRAME_CLOCK_PHASE_LAYOUT)
/* We loop in the layout phase, because we don't want to progress
* into the paint phase with invalid size allocations. This may
* happen in some situation like races between user window
* resizes and natural size changes.
*/
iter = 0;
while ((priv->requested & GDK_FRAME_CLOCK_PHASE_LAYOUT) &&
priv->freeze_count == 0 && iter++ < 4)
{
priv->requested &= ~GDK_FRAME_CLOCK_PHASE_LAYOUT;
g_signal_emit_by_name (G_OBJECT (clock), "layout");
}
if (iter == 4)
g_warning ("gdk-frame-clock: layout continuously requested, giving up after 4 tries");
}
case GDK_FRAME_CLOCK_PHASE_PAINT:
if (priv->freeze_count == 0)
+2 -4
View File
@@ -224,6 +224,7 @@ struct _GdkWindow
guint native_visibility : 2; /* the native visibility of a impl windows */
guint viewable : 1; /* mapped and all parents mapped */
guint applied_shape : 1;
guint in_update : 1;
GdkFullscreenMode fullscreen_mode;
/* The GdkWindow that has the impl, ref:ed if another window.
@@ -250,10 +251,6 @@ struct _GdkWindow
GdkCursor *cursor;
GHashTable *device_cursor;
GSList *implicit_paint;
GList *outstanding_moves;
cairo_region_t *shape;
cairo_region_t *input_shape;
@@ -269,6 +266,7 @@ struct _GdkWindow
guint num_offscreen_children;
GdkFrameClock *frame_clock; /* NULL to use from parent or default */
GdkWindowInvalidateHandlerFunc invalidate_handler;
};
#define GDK_WINDOW_TYPE(d) (((GDK_WINDOW (d)))->window_type)
-37
View File
@@ -555,42 +555,6 @@ gdk_offscreen_window_queue_antiexpose (GdkWindow *window,
return FALSE;
}
static void
gdk_offscreen_window_translate (GdkWindow *window,
cairo_region_t *area,
gint dx,
gint dy)
{
GdkOffscreenWindow *offscreen = GDK_OFFSCREEN_WINDOW (window->impl);
if (offscreen->surface)
{
cairo_t *cr;
cr = cairo_create (offscreen->surface);
area = cairo_region_copy (area);
gdk_cairo_region (cr, area);
cairo_clip (cr);
/* NB: This is a self-copy and Cairo doesn't support that yet.
* So we do a litle trick.
*/
cairo_push_group (cr);
cairo_set_source_surface (cr, offscreen->surface, dx, dy);
cairo_paint (cr);
cairo_pop_group_to_source (cr);
cairo_paint (cr);
cairo_destroy (cr);
}
_gdk_window_add_damage (window, area);
}
static cairo_surface_t *
gdk_offscreen_window_resize_cairo_surface (GdkWindow *window,
cairo_surface_t *surface,
@@ -752,7 +716,6 @@ gdk_offscreen_window_class_init (GdkOffscreenWindowClass *klass)
impl_class->input_shape_combine_region = gdk_offscreen_window_input_shape_combine_region;
impl_class->set_static_gravities = gdk_offscreen_window_set_static_gravities;
impl_class->queue_antiexpose = gdk_offscreen_window_queue_antiexpose;
impl_class->translate = gdk_offscreen_window_translate;
impl_class->destroy = gdk_offscreen_window_destroy;
impl_class->destroy_foreign = NULL;
impl_class->resize_cairo_surface = gdk_offscreen_window_resize_cairo_surface;
+242 -1431
View File
File diff suppressed because it is too large Load Diff
+20
View File
@@ -634,6 +634,26 @@ gboolean gdk_window_set_static_gravities (GdkWindow *window,
/* GdkWindow */
/**
* GdkWindowInvalidateHandlerFunc:
* @window: a #GdkWindow
* @region: a #cairo_region_t
*
* Whenever some area of the window is invalidated (directly in the
* window or in a child window) this gets called with @region in
* the coordinate space of @window. You can use @region to just
* keep track of the dirty region, or you can actually change
* @region in case you are doing display tricks like showing
* a child in multiple places.
*
* Since: 3.10
*/
typedef void (*GdkWindowInvalidateHandlerFunc) (GdkWindow *window,
cairo_region_t *region);
GDK_AVAILABLE_IN_3_10
void gdk_window_set_invalidate_handler (GdkWindow *window,
GdkWindowInvalidateHandlerFunc handler);
gboolean gdk_window_has_native (GdkWindow *window);
void gdk_window_set_type_hint (GdkWindow *window,
GdkWindowTypeHint hint);
-10
View File
@@ -125,16 +125,6 @@ struct _GdkWindowImplClass
gboolean (* queue_antiexpose) (GdkWindow *window,
cairo_region_t *update_area);
/* Called to move @area inside @window by @dx x @dy pixels. @area is
* guaranteed to be inside @window. If part of @area is not invisible or
* invalid, it is this function's job to queue expose events in those
* areas.
*/
void (* translate) (GdkWindow *window,
cairo_region_t *area,
gint dx,
gint dy);
/* Called to do the windowing system specific part of gdk_window_destroy(),
*
* window: The window being destroyed
-44
View File
@@ -2237,49 +2237,6 @@ gdk_quartz_window_queue_antiexpose (GdkWindow *window,
return FALSE;
}
static void
gdk_quartz_window_translate (GdkWindow *window,
cairo_region_t *area,
gint dx,
gint dy)
{
cairo_region_t *invalidate, *scrolled;
GdkWindowImplQuartz *impl = (GdkWindowImplQuartz *)window->impl;
GdkRectangle extents;
cairo_region_get_extents (area, &extents);
[impl->view scrollRect:NSMakeRect (extents.x - dx, extents.y - dy,
extents.width, extents.height)
by:NSMakeSize (dx, dy)];
if (impl->needs_display_region)
{
cairo_region_t *intersection;
/* Invalidate already invalidated area that was moved at new
* location.
*/
intersection = cairo_region_copy (impl->needs_display_region);
cairo_region_intersect (intersection, area);
cairo_region_translate (intersection, dx, dy);
gdk_quartz_window_set_needs_display_in_region (window, intersection);
cairo_region_destroy (intersection);
}
/* Calculate newly exposed area that needs invalidation */
scrolled = cairo_region_copy (area);
cairo_region_translate (scrolled, dx, dy);
invalidate = cairo_region_copy (area);
cairo_region_subtract (invalidate, scrolled);
cairo_region_destroy (scrolled);
gdk_quartz_window_set_needs_display_in_region (window, invalidate);
cairo_region_destroy (invalidate);
}
static void
gdk_quartz_window_set_focus_on_map (GdkWindow *window,
gboolean focus_on_map)
@@ -3078,7 +3035,6 @@ gdk_window_impl_quartz_class_init (GdkWindowImplQuartzClass *klass)
impl_class->input_shape_combine_region = gdk_window_quartz_input_shape_combine_region;
impl_class->set_static_gravities = gdk_window_quartz_set_static_gravities;
impl_class->queue_antiexpose = gdk_quartz_window_queue_antiexpose;
impl_class->translate = gdk_quartz_window_translate;
impl_class->destroy = gdk_quartz_window_destroy;
impl_class->destroy_foreign = gdk_quartz_window_destroy_foreign;
impl_class->resize_cairo_surface = gdk_window_quartz_resize_cairo_surface;
-10
View File
@@ -1009,15 +1009,6 @@ gdk_wayland_window_queue_antiexpose (GdkWindow *window,
return FALSE;
}
static void
gdk_wayland_window_translate (GdkWindow *window,
cairo_region_t *area,
gint dx,
gint dy)
{
_gdk_window_invalidate_for_expose (window, area);
}
static void
gdk_wayland_window_destroy (GdkWindow *window,
gboolean recursing,
@@ -1726,7 +1717,6 @@ _gdk_window_impl_wayland_class_init (GdkWindowImplWaylandClass *klass)
impl_class->input_shape_combine_region = gdk_window_wayland_input_shape_combine_region;
impl_class->set_static_gravities = gdk_window_wayland_set_static_gravities;
impl_class->queue_antiexpose = gdk_wayland_window_queue_antiexpose;
impl_class->translate = gdk_wayland_window_translate;
impl_class->destroy = gdk_wayland_window_destroy;
impl_class->destroy_foreign = gdk_window_wayland_destroy_foreign;
impl_class->resize_cairo_surface = gdk_window_wayland_resize_cairo_surface;
-72
View File
@@ -3319,77 +3319,6 @@ _gdk_win32_window_queue_antiexpose (GdkWindow *window,
return FALSE;
}
/* Gets called from gdwindow.c(do_move_region_bits_on_impl)
* and got tested with testgtk::big_window. Given the previous,
* untested implementation this one looks much too simple ;)
*/
static void
_gdk_win32_window_translate (GdkWindow *window,
cairo_region_t *area, /* In impl window coords */
gint dx,
gint dy)
{
GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
HRGN hrgn, area_hrgn;
cairo_region_t *update_region;
HDC hdc;
int ret;
/* Note: This is the destination area, not the source, and
it has been moved by dx, dy from the source area */
area_hrgn = cairo_region_to_hrgn (area, 0, 0);
/* First we copy any outstanding invalid areas in the
source area to the new position in the destination area */
hrgn = CreateRectRgn (0, 0, 0, 0);
ret = GetUpdateRgn (GDK_WINDOW_HWND (window), hrgn, FALSE);
if (ret == ERROR)
WIN32_API_FAILED ("GetUpdateRgn");
else if (ret != NULLREGION)
{
/* Convert the source invalid region as it would be copied */
OffsetRgn (hrgn, dx, dy);
/* Keep what intersects the copy destination area */
ret = CombineRgn (hrgn, hrgn, area_hrgn, RGN_AND);
/* And invalidate it */
if (ret == ERROR)
WIN32_API_FAILED ("CombineRgn");
else if (ret != NULLREGION)
API_CALL (InvalidateRgn, (GDK_WINDOW_HWND (window), hrgn, TRUE));
}
/* Then we copy the bits, invalidating whatever is copied from
otherwise invisible areas */
hdc = _gdk_win32_impl_acquire_dc (impl);
/* Clip hdc to target region */
API_CALL (SelectClipRgn, (hdc, area_hrgn));
SetRectRgn (hrgn, 0, 0, 0, 0);
if (!ScrollDC (hdc, dx, dy, NULL, NULL, hrgn, NULL))
WIN32_GDI_FAILED ("ScrollDC");
else
{
update_region = _gdk_win32_hrgn_to_region (hrgn);
if (!cairo_region_is_empty (update_region))
_gdk_window_invalidate_for_expose (window, update_region);
cairo_region_destroy (update_region);
}
/* Unset hdc clip region */
API_CALL (SelectClipRgn, (hdc, NULL));
_gdk_win32_impl_release_dc (impl);
if (!DeleteObject (hrgn))
WIN32_GDI_FAILED ("DeleteObject");
if (!DeleteObject (area_hrgn))
WIN32_GDI_FAILED ("DeleteObject");
}
static void
gdk_win32_input_shape_combine_region (GdkWindow *window,
const cairo_region_t *shape_region,
@@ -3556,7 +3485,6 @@ gdk_window_impl_win32_class_init (GdkWindowImplWin32Class *klass)
impl_class->input_shape_combine_region = gdk_win32_input_shape_combine_region;
impl_class->set_static_gravities = gdk_win32_window_set_static_gravities;
impl_class->queue_antiexpose = _gdk_win32_window_queue_antiexpose;
impl_class->translate = _gdk_win32_window_translate;
impl_class->destroy = gdk_win32_window_destroy;
impl_class->destroy_foreign = gdk_win32_window_destroy_foreign;
impl_class->resize_cairo_surface = gdk_win32_window_resize_cairo_surface;
+6 -126
View File
@@ -28,26 +28,11 @@
typedef struct _GdkWindowQueueItem GdkWindowQueueItem;
typedef struct _GdkWindowParentPos GdkWindowParentPos;
typedef enum {
GDK_WINDOW_QUEUE_TRANSLATE,
GDK_WINDOW_QUEUE_ANTIEXPOSE
} GdkWindowQueueType;
struct _GdkWindowQueueItem
{
GdkWindow *window;
gulong serial;
GdkWindowQueueType type;
union {
struct {
cairo_region_t *area;
gint dx;
gint dy;
} translate;
struct {
cairo_region_t *area;
} antiexpose;
} u;
cairo_region_t *antiexpose_area;
};
void
@@ -140,14 +125,7 @@ queue_item_free (GdkWindowQueueItem *item)
(gpointer *)&(item->window));
}
if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
cairo_region_destroy (item->u.antiexpose.area);
else
{
if (item->u.translate.area)
cairo_region_destroy (item->u.translate.area);
}
cairo_region_destroy (item->antiexpose_area);
g_free (item);
}
@@ -213,11 +191,8 @@ gdk_window_queue (GdkWindow *window,
GdkWindowQueueItem *item = tmp_list->data;
GList *next = tmp_list->next;
if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
{
queue_delete_link (display_x11->translate_queue, tmp_list);
queue_item_free (item);
}
queue_delete_link (display_x11->translate_queue, tmp_list);
queue_item_free (item);
tmp_list = next;
}
@@ -232,86 +207,12 @@ gdk_window_queue (GdkWindow *window,
g_queue_push_tail (display_x11->translate_queue, item);
}
static GC
_get_scratch_gc (GdkWindow *window, cairo_region_t *clip_region)
{
GdkX11Screen *screen;
XRectangle *rectangles;
gint n_rects;
gint depth;
screen = GDK_X11_SCREEN (gdk_window_get_screen (window));
depth = gdk_visual_get_depth (gdk_window_get_visual (window)) - 1;
if (!screen->subwindow_gcs[depth])
{
XGCValues values;
values.graphics_exposures = True;
values.subwindow_mode = IncludeInferiors;
screen->subwindow_gcs[depth] = XCreateGC (screen->xdisplay,
GDK_WINDOW_XID (window),
GCSubwindowMode | GCGraphicsExposures,
&values);
}
_gdk_x11_region_get_xrectangles (clip_region,
0, 0,
&rectangles,
&n_rects);
XSetClipRectangles (screen->xdisplay,
screen->subwindow_gcs[depth],
0, 0,
rectangles, n_rects,
YXBanded);
g_free (rectangles);
return screen->subwindow_gcs[depth];
}
void
_gdk_x11_window_translate (GdkWindow *window,
cairo_region_t *area,
gint dx,
gint dy)
{
GdkWindowQueueItem *item;
GC xgc;
GdkRectangle extents;
cairo_region_get_extents (area, &extents);
xgc = _get_scratch_gc (window, area);
cairo_region_translate (area, -dx, -dy); /* Move to source region */
item = g_new (GdkWindowQueueItem, 1);
item->type = GDK_WINDOW_QUEUE_TRANSLATE;
item->u.translate.area = cairo_region_copy (area);
item->u.translate.dx = dx;
item->u.translate.dy = dy;
gdk_window_queue (window, item);
XCopyArea (GDK_WINDOW_XDISPLAY (window),
GDK_WINDOW_XID (window),
GDK_WINDOW_XID (window),
xgc,
extents.x - dx, extents.y - dy,
extents.width, extents.height,
extents.x, extents.y);
}
gboolean
_gdk_x11_window_queue_antiexpose (GdkWindow *window,
cairo_region_t *area)
{
GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
item->type = GDK_WINDOW_QUEUE_ANTIEXPOSE;
item->u.antiexpose.area = area;
item->antiexpose_area = area;
gdk_window_queue (window, item);
@@ -339,28 +240,7 @@ _gdk_x11_window_process_expose (GdkWindow *window,
if (serial - item->serial > (gulong) G_MAXLONG)
{
if (item->window == window)
{
if (item->type == GDK_WINDOW_QUEUE_TRANSLATE)
{
if (item->u.translate.area)
{
cairo_region_t *intersection;
intersection = cairo_region_copy (invalidate_region);
cairo_region_intersect (intersection, item->u.translate.area);
cairo_region_subtract (invalidate_region, intersection);
cairo_region_translate (intersection, item->u.translate.dx, item->u.translate.dy);
cairo_region_union (invalidate_region, intersection);
cairo_region_destroy (intersection);
}
else
cairo_region_translate (invalidate_region, item->u.translate.dx, item->u.translate.dy);
}
else /* anti-expose */
{
cairo_region_subtract (invalidate_region, item->u.antiexpose.area);
}
}
cairo_region_subtract (invalidate_region, item->antiexpose_area);
}
else
{
-1
View File
@@ -5334,7 +5334,6 @@ gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass)
impl_class->input_shape_combine_region = gdk_window_x11_input_shape_combine_region;
impl_class->set_static_gravities = gdk_window_x11_set_static_gravities;
impl_class->queue_antiexpose = _gdk_x11_window_queue_antiexpose;
impl_class->translate = _gdk_x11_window_translate;
impl_class->destroy = gdk_x11_window_destroy;
impl_class->destroy_foreign = gdk_x11_window_destroy_foreign;
impl_class->resize_cairo_surface = gdk_window_x11_resize_cairo_surface;
+1 -1
View File
@@ -295,7 +295,6 @@ gtk_public_h_sources = \
gtkpagesetup.h \
gtkpaned.h \
gtkpapersize.h \
gtkpathbar.h \
gtkplacessidebar.h \
gtkplug.h \
gtkprintcontext.h \
@@ -515,6 +514,7 @@ gtk_private_h_sources = \
gtknumerableiconprivate.h \
gtkorientableprivate.h \
gtkpango.h \
gtkpathbar.h \
gtkpressandholdprivate.h \
gtkprintoperation-private.h \
gtkprintutils.h \
-1
View File
@@ -145,7 +145,6 @@
#include <gtk/gtkpagesetup.h>
#include <gtk/gtkpapersize.h>
#include <gtk/gtkpaned.h>
#include <gtk/gtkpathbar.h>
#include <gtk/gtkplacessidebar.h>
#include <gtk/gtkprintcontext.h>
#include <gtk/gtkprintoperation.h>
+21 -8
View File
@@ -3365,7 +3365,7 @@ gtk_container_propagate_draw (GtkContainer *container,
{
GdkEventExpose *event;
GtkAllocation allocation;
GdkWindow *window, *w;
GdkWindow *window, *w, *event_window, *child_in_window;
int x, y;
g_return_if_fail (GTK_IS_CONTAINER (container));
@@ -3374,13 +3374,26 @@ gtk_container_propagate_draw (GtkContainer *container,
g_assert (gtk_widget_get_parent (child) == GTK_WIDGET (container));
if (!gtk_widget_is_drawable (child))
return;
/* Only propagate to native child window if we're not handling
an expose (i.e. in a pure gtk_widget_draw() call */
event = _gtk_cairo_get_event (cr);
if (event)
{
if (gtk_widget_get_has_window (child) ||
gtk_widget_get_window (child) != event->window)
return;
}
if (event &&
(gtk_widget_get_has_window (child) &&
gdk_window_has_native (gtk_widget_get_window (child))))
return;
/* Never propagate to a child window when exposing a window
that is not the one the child widget is in. */
event_window = _gtk_cairo_get_event_window (cr);
if (gtk_widget_get_has_window (child))
child_in_window = gdk_window_get_parent (gtk_widget_get_window (child));
else
child_in_window = gtk_widget_get_window (child);
if (child_in_window != event_window)
return;
cairo_save (cr);
@@ -3422,7 +3435,7 @@ gtk_container_propagate_draw (GtkContainer *container,
cairo_translate (cr, x, y);
_gtk_widget_draw_internal (child, cr, TRUE);
gtk_widget_draw (child, cr);
cairo_restore (cr);
}
+13 -13
View File
@@ -504,11 +504,11 @@ static void list_row_activated (GtkTreeView *tree_view,
GtkTreeViewColumn *column,
GtkFileChooserDefault *impl);
static void path_bar_open_location_cb (GtkPathBar *path_bar,
GFile *file,
GFile *child,
gboolean child_is_hidden,
GtkFileChooserDefault *impl);
static void path_bar_clicked (GtkPathBar *path_bar,
GFile *file,
GFile *child,
gboolean child_is_hidden,
GtkFileChooserDefault *impl);
static void update_cell_renderer_attributes (GtkFileChooserDefault *impl);
@@ -2522,7 +2522,7 @@ put_recent_folder_in_pathbar (GtkFileChooserDefault *impl, GtkTreeIter *iter)
gtk_tree_model_get (GTK_TREE_MODEL (priv->recent_model), iter,
MODEL_COL_FILE, &file,
-1);
gtk_path_bar_set_location (GTK_PATH_BAR (priv->browse_path_bar), file, FALSE);
_gtk_path_bar_set_file (GTK_PATH_BAR (priv->browse_path_bar), file, FALSE);
g_object_unref (file);
}
@@ -4615,7 +4615,7 @@ update_current_folder_get_info_cb (GCancellable *cancellable,
if (! _gtk_file_info_consider_as_directory (info))
goto out;
gtk_path_bar_set_location (GTK_PATH_BAR (priv->browse_path_bar), data->file, data->keep_trail);
_gtk_path_bar_set_file (GTK_PATH_BAR (priv->browse_path_bar), data->file, data->keep_trail);
if (priv->current_folder != data->file)
{
@@ -7014,11 +7014,11 @@ list_row_activated (GtkTreeView *tree_view,
}
static void
path_bar_open_location_cb (GtkPathBar *path_bar,
GFile *file,
GFile *child_file,
gboolean child_is_hidden,
GtkFileChooserDefault *impl)
path_bar_clicked (GtkPathBar *path_bar,
GFile *file,
GFile *child_file,
gboolean child_is_hidden,
GtkFileChooserDefault *impl)
{
if (child_file)
pending_select_files_add (impl, child_file);
@@ -7507,7 +7507,7 @@ _gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
gtk_widget_class_bind_callback (widget_class, filter_combo_changed);
gtk_widget_class_bind_callback (widget_class, location_button_toggled_cb);
gtk_widget_class_bind_callback (widget_class, new_folder_button_clicked);
gtk_widget_class_bind_callback (widget_class, path_bar_open_location_cb);
gtk_widget_class_bind_callback (widget_class, path_bar_clicked);
gtk_widget_class_bind_callback (widget_class, places_sidebar_open_location_cb);
gtk_widget_class_bind_callback (widget_class, places_sidebar_show_error_message_cb);
}
+1 -1
View File
@@ -79,7 +79,7 @@
<object class="GtkPathBar" id="browse_path_bar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<signal name="open-location" handler="path_bar_open_location_cb" after="yes" swapped="no"/>
<signal name="path-clicked" handler="path_bar_clicked" after="yes" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
+1 -1
View File
@@ -2552,7 +2552,7 @@ gtk_grid_set_baseline_row (GtkGrid *grid,
}
/**
* gtk_grid_set_baseline_row:
* gtk_grid_get_baseline_row:
* @grid: a #GtkGrid
*
* Returns which row defines the global baseline of @grid.
+11 -3
View File
@@ -1615,9 +1615,17 @@ gtk_main_do_event (GdkEvent *event)
case GDK_EXPOSE:
if (event->any.window && gtk_widget_get_double_buffered (event_widget))
{
gdk_window_begin_paint_region (event->any.window, event->expose.region);
gtk_widget_send_expose (event_widget, event);
gdk_window_end_paint (event->any.window);
/* We handle exposes only on native windows, relying on the
* draw() handler to propagate down to non-native windows.
* This is ok now that we child windows always are considered
* (semi)transparent.
*/
if (gdk_window_has_native (event->expose.window))
{
gdk_window_begin_paint_region (event->any.window, event->expose.region);
gtk_widget_send_expose (event_widget, event);
gdk_window_end_paint (event->any.window);
}
}
else
{
+8
View File
@@ -399,6 +399,10 @@ gtk_overlay_get_child_position (GtkOverlay *overlay,
case GTK_ALIGN_END:
alloc->x += main_alloc.width - req.width;
break;
case GTK_ALIGN_BASELINE:
default:
g_assert_not_reached ();
break;
}
alloc->y = main_alloc.y;
@@ -418,6 +422,10 @@ gtk_overlay_get_child_position (GtkOverlay *overlay,
case GTK_ALIGN_END:
alloc->y += main_alloc.height - req.height;
break;
case GTK_ALIGN_BASELINE:
default:
g_assert_not_reached ();
break;
}
return TRUE;
+344 -721
View File
File diff suppressed because it is too large Load Diff
+9 -22
View File
@@ -18,13 +18,8 @@
#ifndef __GTK_PATH_BAR_H__
#define __GTK_PATH_BAR_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkcontainer.h>
#include <gtk/gtkfilesystem.h>
#include <gtk/gtkplacessidebar.h>
#include "gtkcontainer.h"
#include "gtkfilesystem.h"
G_BEGIN_DECLS
@@ -51,26 +46,18 @@ struct _GtkPathBarClass
{
GtkContainerClass parent_class;
void (* open_location) (GtkPathBar *path_bar,
GFile *file,
GFile *child_file,
gboolean child_is_hidden);
void (* path_clicked) (GtkPathBar *path_bar,
GFile *file,
GFile *child_file,
gboolean child_is_hidden);
};
GType gtk_path_bar_get_type (void) G_GNUC_CONST;
GtkWidget *gtk_path_bar_new (void);
GtkPlacesOpenFlags gtk_path_bar_get_open_flags (GtkPathBar *path_bar);
void gtk_path_bar_set_open_flags (GtkPathBar *path_bar, GtkPlacesOpenFlags flags);
void gtk_path_bar_set_location (GtkPathBar *path_bar,
GFile *location,
gboolean keep_trail);
GFile *gtk_path_bar_get_location (GtkPathBar *path_bar);
void _gtk_path_bar_set_file_system (GtkPathBar *path_bar,
GtkFileSystem *file_system);
void _gtk_path_bar_set_file (GtkPathBar *path_bar,
GFile *file,
gboolean keep_trail);
void _gtk_path_bar_up (GtkPathBar *path_bar);
void _gtk_path_bar_down (GtkPathBar *path_bar);
+2 -2
View File
@@ -874,8 +874,8 @@ gtk_revealer_get_transition_type (GtkRevealer *revealer)
}
/**
* gtk_stack_set_transition_type:
* @stack: a #GtkStack
* gtk_revealer_set_transition_type:
* @revealer: a #GtkRevealer
* @transition: the new transition type
*
* Sets the type of animation that will be used for
+48 -10
View File
@@ -156,6 +156,9 @@ struct _GtkSpinButtonPrivate
GdkWindow *down_panel;
GdkWindow *up_panel;
GtkStyleContext *down_panel_context;
GtkStyleContext *up_panel_context;
GdkWindow *click_child;
GdkWindow *in_child;
@@ -248,6 +251,7 @@ static void gtk_spin_button_grab_notify (GtkWidget *widget,
gboolean was_grabbed);
static void gtk_spin_button_state_flags_changed (GtkWidget *widget,
GtkStateFlags previous_state);
static void gtk_spin_button_style_updated (GtkWidget *widget);
static gboolean gtk_spin_button_timer (GtkSpinButton *spin_button);
static gboolean gtk_spin_button_stop_spinning (GtkSpinButton *spin);
static void gtk_spin_button_value_changed (GtkAdjustment *adjustment,
@@ -328,6 +332,7 @@ gtk_spin_button_class_init (GtkSpinButtonClass *class)
widget_class->focus_out_event = gtk_spin_button_focus_out;
widget_class->grab_notify = gtk_spin_button_grab_notify;
widget_class->state_flags_changed = gtk_spin_button_state_flags_changed;
widget_class->style_updated = gtk_spin_button_style_updated;
entry_class->activate = gtk_spin_button_activate;
entry_class->get_text_area_size = gtk_spin_button_get_text_area_size;
@@ -684,7 +689,16 @@ gtk_spin_button_init (GtkSpinButton *spin_button)
static void
gtk_spin_button_finalize (GObject *object)
{
gtk_spin_button_set_adjustment (GTK_SPIN_BUTTON (object), NULL);
GtkSpinButton *spin_button = GTK_SPIN_BUTTON (object);
GtkSpinButtonPrivate *priv = spin_button->priv;
gtk_spin_button_set_adjustment (spin_button, NULL);
if (priv->down_panel_context)
g_object_unref (priv->down_panel_context);
if (priv->up_panel_context)
g_object_unref (priv->up_panel_context);
G_OBJECT_CLASS (gtk_spin_button_parent_class)->finalize (object);
}
@@ -730,7 +744,7 @@ gtk_spin_button_unmap (GtkWidget *widget)
static void
gtk_spin_button_panel_nthchildize_context (GtkSpinButton *spin_button,
GtkStyleContext *context,
GdkWindow *panel)
gboolean is_down_panel)
{
GtkSpinButtonPrivate *priv = spin_button->priv;
GtkWidget *widget = GTK_WIDGET (spin_button);
@@ -777,7 +791,7 @@ gtk_spin_button_panel_nthchildize_context (GtkSpinButton *spin_button,
gtk_widget_path_iter_add_class (siblings_path, up_pos, GTK_STYLE_CLASS_SPINBUTTON);
gtk_widget_path_iter_add_class (siblings_path, down_pos, GTK_STYLE_CLASS_SPINBUTTON);
if (panel == priv->down_panel)
if (is_down_panel)
gtk_widget_path_append_with_siblings (path, siblings_path, down_pos);
else
gtk_widget_path_append_with_siblings (path, siblings_path, up_pos);
@@ -846,12 +860,20 @@ static GtkStyleContext *
gtk_spin_button_panel_get_context (GtkSpinButton *spin_button,
GdkWindow *panel)
{
GtkStyleContext *context;
GtkSpinButtonPrivate *priv = spin_button->priv;
GtkStyleContext **contextp;
context = gtk_style_context_new ();
gtk_spin_button_panel_nthchildize_context (spin_button, context, panel);
contextp = (panel == priv->down_panel) ?
&priv->down_panel_context : &priv->up_panel_context;
return context;
if (*contextp == NULL)
{
*contextp = gtk_style_context_new ();
gtk_spin_button_panel_nthchildize_context (spin_button, *contextp,
panel == priv->down_panel);
}
return *contextp;
}
static void
@@ -874,8 +896,6 @@ gtk_spin_button_panel_get_size (GtkSpinButton *spin_button,
gtk_style_context_get_padding (context, state, &button_padding);
gtk_style_context_get_border (context, state, &button_border);
g_object_unref (context);
if (width)
*width = icon_size + button_padding.left + button_padding.right +
button_border.left + button_border.right;
@@ -1004,7 +1024,6 @@ gtk_spin_button_panel_draw (GtkSpinButton *spin_button,
cairo_restore (cr);
g_object_unref (icon_helper);
g_object_unref (context);
}
static void
@@ -1361,6 +1380,25 @@ gtk_spin_button_state_flags_changed (GtkWidget *widget,
}
}
static void
gtk_spin_button_style_updated (GtkWidget *widget)
{
GtkSpinButton *spin = GTK_SPIN_BUTTON (widget);
GtkSpinButtonPrivate *priv = spin->priv;
if (priv->down_panel_context)
gtk_spin_button_panel_nthchildize_context (spin,
priv->down_panel_context,
TRUE);
if (priv->up_panel_context)
gtk_spin_button_panel_nthchildize_context (spin,
priv->up_panel_context,
FALSE);
GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->style_updated (widget);
}
static gint
gtk_spin_button_scroll (GtkWidget *widget,
GdkEventScroll *event)
+231 -23
View File
@@ -66,6 +66,13 @@ struct _GtkViewportPrivate
GdkWindow *bin_window;
GdkWindow *view_window;
int backing_surface_x;
int backing_surface_y;
int backing_surface_w;
int backing_surface_h;
cairo_surface_t *backing_surface;
cairo_region_t *backing_surface_dirty;
/* GtkScrollablePolicy needs to be checked when
* driving the scrollable adjustment values */
guint hscroll_policy : 1;
@@ -649,6 +656,37 @@ gtk_viewport_get_view_window (GtkViewport *viewport)
return viewport->priv->view_window;
}
static void
gtk_viewport_bin_window_invalidate_handler (GdkWindow *window,
cairo_region_t *region)
{
gpointer widget;
GtkViewport *viewport;
GtkViewportPrivate *priv;
cairo_rectangle_int_t r;
gdk_window_get_user_data (window, &widget);
viewport = GTK_VIEWPORT (widget);
priv = viewport->priv;
if (priv->backing_surface_dirty == NULL)
priv->backing_surface_dirty = cairo_region_create ();
cairo_region_translate (region,
-priv->backing_surface_x,
-priv->backing_surface_y);
cairo_region_union (priv->backing_surface_dirty, region);
cairo_region_translate (region,
priv->backing_surface_x,
priv->backing_surface_y);
r.x = 0;
r.y = 0;
r.width = priv->backing_surface_w;
r.height = priv->backing_surface_h;
cairo_region_intersect_rectangle (priv->backing_surface_dirty, &r);
}
static void
gtk_viewport_realize (GtkWidget *widget)
{
@@ -713,6 +751,8 @@ gtk_viewport_realize (GtkWidget *widget)
priv->bin_window = gdk_window_new (priv->view_window, &attributes, attributes_mask);
gtk_widget_register_window (widget, priv->bin_window);
gdk_window_set_invalidate_handler (priv->bin_window,
gtk_viewport_bin_window_invalidate_handler);
child = gtk_bin_get_child (bin);
if (child)
@@ -750,7 +790,10 @@ gtk_viewport_draw (GtkWidget *widget,
GtkViewport *viewport = GTK_VIEWPORT (widget);
GtkViewportPrivate *priv = viewport->priv;
GtkStyleContext *context;
int x, y;
cairo_t *backing_cr;
GtkWidget *child;
int x, y, bin_x, bin_y, new_surf_x, new_surf_y;
cairo_rectangle_int_t view_pos;
context = gtk_widget_get_style_context (widget);
@@ -766,30 +809,151 @@ gtk_viewport_draw (GtkWidget *widget,
gtk_style_context_restore (context);
}
if (gtk_cairo_should_draw_window (cr, priv->view_window))
if (priv->backing_surface &&
/* Don't use backing surface if rendering elsewhere */
cairo_surface_get_type (priv->backing_surface) == cairo_surface_get_type (cairo_get_target (cr)))
{
/* This is a cute hack to ensure the contents of bin_window are
* restricted to where they are visible. We only need to do this
* clipping when called via gtk_widget_draw() and not in expose
* events. And when that happens every window (including this one)
* should be drawn.
*/
gdk_window_get_position (priv->view_window, &x, &y);
cairo_rectangle (cr, x, y,
gdk_window_get_width (priv->view_window),
gdk_window_get_height (priv->view_window));
cairo_clip (cr);
gdk_window_get_position (priv->bin_window, &bin_x, &bin_y);
view_pos.x = -bin_x;
view_pos.y = -bin_y;
view_pos.width = gdk_window_get_width (priv->view_window);
view_pos.height = gdk_window_get_height (priv->view_window);
/* Reposition so all is visible visible */
if (priv->backing_surface)
{
cairo_rectangle_int_t r;
cairo_region_t *copy_region;
if (view_pos.x < priv->backing_surface_x ||
view_pos.x + view_pos.width >
priv->backing_surface_x + priv->backing_surface_w ||
view_pos.y < priv->backing_surface_y ||
view_pos.y + view_pos.height >
priv->backing_surface_y + priv->backing_surface_h)
{
new_surf_x = priv->backing_surface_x;
if (view_pos.x < priv->backing_surface_x)
new_surf_x = view_pos.x - (priv->backing_surface_w - view_pos.width);
else if (view_pos.x + view_pos.width >
priv->backing_surface_x + priv->backing_surface_w)
new_surf_x = view_pos.x;
new_surf_y = priv->backing_surface_y;
if (view_pos.y < priv->backing_surface_y)
new_surf_y = view_pos.y - (priv->backing_surface_h - view_pos.height);
else if (view_pos.y + view_pos.height >
priv->backing_surface_y + priv->backing_surface_h)
new_surf_y = view_pos.y;
r.x = 0;
r.y = 0;
r.width = priv->backing_surface_w;
r.height = priv->backing_surface_h;
copy_region = cairo_region_create_rectangle (&r);
if (priv->backing_surface_dirty)
{
cairo_region_subtract (copy_region, priv->backing_surface_dirty);
cairo_region_destroy (priv->backing_surface_dirty);
priv->backing_surface_dirty = NULL;
}
cairo_region_translate (copy_region,
priv->backing_surface_x - new_surf_x,
priv->backing_surface_y - new_surf_y);
cairo_region_intersect_rectangle (copy_region, &r);
backing_cr = cairo_create (priv->backing_surface);
gdk_cairo_region (backing_cr, copy_region);
cairo_clip (backing_cr);
cairo_push_group (backing_cr);
cairo_set_source_surface (backing_cr, priv->backing_surface,
priv->backing_surface_x - new_surf_x,
priv->backing_surface_y - new_surf_y);
cairo_paint (backing_cr);
cairo_pop_group_to_source (backing_cr);
cairo_set_operator (backing_cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (backing_cr);
cairo_destroy (backing_cr);
priv->backing_surface_x = new_surf_x;
priv->backing_surface_y = new_surf_y;
cairo_region_xor_rectangle (copy_region, &r);
priv->backing_surface_dirty = copy_region;
}
}
if (priv->backing_surface_dirty &&
!cairo_region_is_empty (priv->backing_surface_dirty))
{
backing_cr = cairo_create (priv->backing_surface);
gdk_cairo_region (backing_cr, priv->backing_surface_dirty);
cairo_clip (backing_cr);
cairo_translate (backing_cr,
-priv->backing_surface_x,
-priv->backing_surface_y);
cairo_set_source_rgba (backing_cr,
0, 0, 0, 0);
cairo_set_operator (backing_cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (backing_cr);
cairo_set_operator (backing_cr, CAIRO_OPERATOR_OVER);
gtk_render_background (context, backing_cr,
0,0,
gdk_window_get_width (priv->bin_window),
gdk_window_get_height (priv->bin_window));
child = gtk_bin_get_child (GTK_BIN (widget));
if (child && gtk_widget_get_visible (child)) {
if (!gtk_widget_get_has_window (child))
{
GtkAllocation child_allocation;
gtk_widget_get_allocation (child, &child_allocation);
cairo_translate (backing_cr,
child_allocation.x,
child_allocation.y);
}
gtk_widget_draw (child, backing_cr);
}
cairo_destroy (backing_cr);
}
if (priv->backing_surface_dirty)
{
cairo_region_destroy (priv->backing_surface_dirty);
priv->backing_surface_dirty = NULL;
}
if (gtk_cairo_should_draw_window (cr, priv->bin_window))
{
gdk_window_get_position (priv->view_window, &x, &y);
cairo_set_source_surface (cr, priv->backing_surface,
priv->backing_surface_x + bin_x + x,
priv->backing_surface_y + bin_y + y);
cairo_rectangle (cr, x, y,
gdk_window_get_width (priv->view_window),
gdk_window_get_height (priv->view_window));
cairo_fill (cr);
}
}
if (gtk_cairo_should_draw_window (cr, priv->bin_window))
else
{
gdk_window_get_position (priv->bin_window, &x, &y);
gtk_render_background (context, cr, x, y,
gdk_window_get_width (priv->bin_window),
gdk_window_get_height (priv->bin_window));
GTK_WIDGET_CLASS (gtk_viewport_parent_class)->draw (widget, cr);
/* Don't use backing_surface */
if (gtk_cairo_should_draw_window (cr, priv->bin_window))
{
gdk_window_get_position (priv->view_window, &x, &y);
cairo_rectangle (cr, x, y,
gdk_window_get_width (priv->view_window),
gdk_window_get_height (priv->view_window));
cairo_clip (cr);
gdk_window_get_position (priv->bin_window, &x, &y);
gtk_render_background (context, cr, x, y,
gdk_window_get_width (priv->bin_window),
gdk_window_get_height (priv->bin_window));
GTK_WIDGET_CLASS (gtk_viewport_parent_class)->draw (widget, cr);
}
}
return FALSE;
@@ -823,6 +987,7 @@ gtk_viewport_size_allocate (GtkWidget *widget,
GtkAdjustment *vadjustment = priv->vadjustment;
GtkAllocation child_allocation;
GtkWidget *child;
int surface_w, surface_h;
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
@@ -843,7 +1008,7 @@ gtk_viewport_size_allocate (GtkWidget *widget,
viewport_set_hadjustment_values (viewport);
viewport_set_vadjustment_values (viewport);
child_allocation.x = 0;
child_allocation.y = 0;
child_allocation.width = gtk_adjustment_get_upper (hadjustment);
@@ -851,6 +1016,7 @@ gtk_viewport_size_allocate (GtkWidget *widget,
if (gtk_widget_get_realized (widget))
{
GtkAllocation view_allocation;
cairo_rectangle_int_t rect;
gdk_window_move_resize (gtk_widget_get_window (widget),
allocation->x + border_width,
@@ -869,6 +1035,48 @@ gtk_viewport_size_allocate (GtkWidget *widget,
- gtk_adjustment_get_value (vadjustment),
child_allocation.width,
child_allocation.height);
surface_w = view_allocation.width;
if (child_allocation.width > view_allocation.width)
surface_w = MIN (surface_w + 64, child_allocation.width);
surface_h = view_allocation.height;
if (child_allocation.height > view_allocation.height)
surface_h = MIN (surface_h + 64, child_allocation.height);
if (priv->backing_surface != NULL &&
(priv->backing_surface_w < view_allocation.width ||
priv->backing_surface_w > surface_w + 32 ||
priv->backing_surface_h < view_allocation.height ||
priv->backing_surface_h > surface_h + 32))
{
cairo_surface_destroy (priv->backing_surface);
priv->backing_surface = NULL;
if (priv->backing_surface_dirty)
cairo_region_destroy (priv->backing_surface_dirty);
priv->backing_surface_dirty = NULL;
}
if (priv->backing_surface == NULL &&
(view_allocation.width < child_allocation.width ||
view_allocation.height < child_allocation.height))
{
priv->backing_surface_x = gtk_adjustment_get_value (hadjustment);
priv->backing_surface_y = gtk_adjustment_get_value (vadjustment);
priv->backing_surface_w = surface_w;
priv->backing_surface_h = surface_h;
priv->backing_surface_dirty = cairo_region_create ();
priv->backing_surface =
gdk_window_create_similar_surface (priv->bin_window,
CAIRO_CONTENT_COLOR_ALPHA,
surface_w, surface_h);
rect.x = 0;
rect.y = 0;
rect.width = surface_w;
rect.height = surface_h;
cairo_region_union_rectangle (priv->backing_surface_dirty,
&rect);
}
}
child = gtk_bin_get_child (bin);
+195 -166
View File
@@ -854,9 +854,10 @@ static void gtk_widget_on_frame_clock_update (GdkFrameClock *frame_clock,
GtkWidget *widget);
static gboolean event_window_is_still_viewable (GdkEvent *event);
static void gtk_cairo_set_event_window (cairo_t *cr,
GdkWindow *window);
static void gtk_cairo_set_event (cairo_t *cr,
GdkEventExpose *event);
static void gtk_widget_propagate_alpha (GtkWidget *widget);
/* --- variables --- */
static gpointer gtk_widget_parent_class = NULL;
@@ -967,24 +968,9 @@ gtk_widget_draw_marshaller (GClosure *closure,
gpointer invocation_hint,
gpointer marshal_data)
{
GtkWidget *widget = g_value_get_object (&param_values[0]);
GdkEventExpose *tmp_event;
gboolean push_group;
cairo_t *cr = g_value_get_boxed (&param_values[1]);
cairo_save (cr);
tmp_event = _gtk_cairo_get_event (cr);
push_group =
widget->priv->opacity_group ||
(widget->priv->alpha != 255 &&
(!gtk_widget_get_has_window (widget) || tmp_event == NULL));
if (push_group)
{
cairo_push_group (cr);
gtk_cairo_set_event (cr, NULL);
}
_gtk_marshal_BOOLEAN__BOXED (closure,
return_value,
@@ -994,14 +980,6 @@ gtk_widget_draw_marshaller (GClosure *closure,
marshal_data);
if (push_group)
{
cairo_pop_group_to_source (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_paint_with_alpha (cr, widget->priv->alpha / 255.0);
}
gtk_cairo_set_event (cr, tmp_event);
cairo_restore (cr);
}
@@ -1014,9 +992,6 @@ gtk_widget_draw_marshallerv (GClosure *closure,
int n_params,
GType *param_types)
{
GtkWidget *widget = GTK_WIDGET (instance);
GdkEventExpose *tmp_event;
gboolean push_group;
cairo_t *cr;
va_list args_copy;
@@ -1024,18 +999,6 @@ gtk_widget_draw_marshallerv (GClosure *closure,
cr = va_arg (args_copy, gpointer);
cairo_save (cr);
tmp_event = _gtk_cairo_get_event (cr);
push_group =
widget->priv->opacity_group ||
(widget->priv->alpha != 255 &&
(!gtk_widget_get_has_window (widget) || tmp_event == NULL));
if (push_group)
{
cairo_push_group (cr);
gtk_cairo_set_event (cr, NULL);
}
_gtk_marshal_BOOLEAN__BOXEDv (closure,
return_value,
@@ -1046,14 +1009,6 @@ gtk_widget_draw_marshallerv (GClosure *closure,
param_types);
if (push_group)
{
cairo_pop_group_to_source (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_paint_with_alpha (cr, widget->priv->alpha / 255.0);
}
gtk_cairo_set_event (cr, tmp_event);
cairo_restore (cr);
va_end (args_copy);
@@ -4203,8 +4158,6 @@ gtk_widget_unparent (GtkWidget *widget)
g_object_notify_queue_clear (G_OBJECT (widget), nqueue);
g_object_notify_queue_thaw (G_OBJECT (widget), nqueue);
gtk_widget_propagate_alpha (widget);
gtk_widget_pop_verify_invariants (widget);
g_object_unref (widget);
}
@@ -6282,6 +6235,23 @@ gtk_widget_real_mnemonic_activate (GtkWidget *widget,
return TRUE;
}
static const cairo_user_data_key_t event_window_key;
GdkWindow *
_gtk_cairo_get_event_window (cairo_t *cr)
{
g_return_val_if_fail (cr != NULL, NULL);
return cairo_get_user_data (cr, &event_window_key);
}
static void
gtk_cairo_set_event_window (cairo_t *cr,
GdkWindow *event_window)
{
cairo_set_user_data (cr, &event_window_key, event_window, NULL);
}
static const cairo_user_data_key_t event_key;
GdkEventExpose *
@@ -6294,7 +6264,7 @@ _gtk_cairo_get_event (cairo_t *cr)
static void
gtk_cairo_set_event (cairo_t *cr,
GdkEventExpose *event)
GdkEventExpose *event)
{
cairo_set_user_data (cr, &event_key, event, NULL);
}
@@ -6323,15 +6293,15 @@ gboolean
gtk_cairo_should_draw_window (cairo_t *cr,
GdkWindow *window)
{
GdkEventExpose *event;
GdkWindow *event_window;
g_return_val_if_fail (cr != NULL, FALSE);
g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);
event = _gtk_cairo_get_event (cr);
event_window = _gtk_cairo_get_event_window (cr);
return event == NULL ||
event->window == window;
return event_window == NULL ||
event_window == window;
}
static gboolean
@@ -6348,17 +6318,20 @@ gtk_widget_get_clip_draw (GtkWidget *widget)
return TRUE;
}
/* code shared by gtk_container_propagate_draw() and
* gtk_widget_draw()
*/
void
static void
_gtk_widget_draw_internal (GtkWidget *widget,
cairo_t *cr,
gboolean clip_to_size)
gboolean clip_to_size,
GdkWindow *window)
{
GdkWindow *tmp_event_window;
if (!gtk_widget_is_drawable (widget))
return;
tmp_event_window = _gtk_cairo_get_event_window (cr);
gtk_cairo_set_event_window (cr, window);
clip_to_size &= gtk_widget_get_clip_draw (widget);
if (clip_to_size)
@@ -6399,7 +6372,7 @@ _gtk_widget_draw_internal (GtkWidget *widget,
#endif
if (cairo_status (cr) &&
_gtk_cairo_get_event (cr))
_gtk_cairo_get_event_window (cr))
{
/* We check the event so we only warn about internal GTK calls.
* Errors might come from PDF streams having write failures and
@@ -6411,6 +6384,77 @@ _gtk_widget_draw_internal (GtkWidget *widget,
cairo_status_to_string (cairo_status (cr)));
}
}
gtk_cairo_set_event_window (cr, tmp_event_window);
}
/* Emit draw() on the widget that owns window,
and on any child windows that also belong
to the widget. */
static void
_gtk_widget_draw_windows (GdkWindow *window,
cairo_t *cr,
int window_x,
int window_y)
{
cairo_pattern_t *pattern;
gboolean do_clip;
GtkWidget *widget = NULL;
GList *l;
int x, y;
if (!gdk_window_is_viewable (window))
return;
cairo_save (cr);
cairo_translate (cr, window_x, window_y);
cairo_rectangle (cr, 0, 0,
gdk_window_get_width (window),
gdk_window_get_height (window));
cairo_clip (cr);
if (gdk_cairo_get_clip_rectangle (cr, NULL))
{
cairo_save (cr);
pattern = gdk_window_get_background_pattern (window);
cairo_set_source (cr, pattern);
cairo_paint (cr);
cairo_restore (cr);
gdk_window_get_user_data (window, (gpointer *) &widget);
do_clip = _gtk_widget_get_translation_to_window (widget, window,
&x, &y);
cairo_save (cr);
cairo_translate (cr, -x, -y);
_gtk_widget_draw_internal (widget, cr, do_clip, window);
cairo_restore (cr);
for (l = g_list_last (gdk_window_peek_children (window));
l != NULL;
l = l->prev)
{
GdkWindow *child_window = l->data;
gpointer child_data;
GdkWindowType type;
int wx, wy;
type = gdk_window_get_window_type (child_window);
if (!gdk_window_is_visible (child_window) ||
gdk_window_is_input_only (child_window) ||
type == GDK_WINDOW_OFFSCREEN ||
type == GDK_WINDOW_FOREIGN)
continue;
gdk_window_get_user_data (child_window, &child_data);
if (child_data == (gpointer)widget)
{
gdk_window_get_position (child_window, &wx, &wy);
_gtk_widget_draw_windows (child_window, cr, wx,wy);
}
}
}
cairo_restore (cr);
}
/**
@@ -6443,23 +6487,89 @@ void
gtk_widget_draw (GtkWidget *widget,
cairo_t *cr)
{
GdkEventExpose *tmp_event;
GdkWindow *window, *child_window;
gpointer child_data;
GList *l;
int wx, wy;
gboolean push_group;
GdkWindowType type;
/* We get expose events only on native windows, so the draw
* implementation has to walk the entire widget hierarchy, except
* that it stops at native subwindows while we're in an expose
* event (_gtk_cairo_get_event () != NULL).
*
* However, we need to properly clip drawing into child windows
* to avoid drawing outside if widgets use e.g. cairo_paint(), so
* we traverse over GdkWindows as well as GtkWidgets.
*
* In order to be able to have opacity groups for entire widgets
* that consists of multiple windows we collect all the windows
* that belongs to a widget and draw them in one go. This means
* we may somewhat reorder GdkWindows when we paint them, but
* thats not generally a problem, as if you want a guaranteed
* order you generally use a windowed widget where you control
* the window hierarchy.
*/
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (!widget->priv->alloc_needed);
g_return_if_fail (cr != NULL);
cairo_save (cr);
/* We have to reset the event here so that draw functions can call
* gtk_widget_draw() on random other widgets and get the desired
* effect: Drawing all contents, not just the current window.
*/
tmp_event = _gtk_cairo_get_event (cr);
gtk_cairo_set_event (cr, NULL);
_gtk_widget_draw_internal (widget, cr, TRUE);
push_group =
widget->priv->opacity_group ||
(widget->priv->alpha != 255 &&
!gtk_widget_is_toplevel (widget));
if (push_group)
cairo_push_group (cr);
window = gtk_widget_get_window (widget);
if (gtk_widget_get_has_window (widget))
{
/* The widget will be completely contained in its window, so just
* expose that (and any child window belonging to the widget) */
_gtk_widget_draw_windows (window, cr, 0, 0);
}
else
{
/* The widget draws in its parent window, so we send a draw() for
* that. */
_gtk_widget_draw_internal (widget, cr, TRUE, window);
/* But, it may also have child windows in the parent which we should
* draw (after having drawn on the parent) */
for (l = g_list_last (gdk_window_peek_children (window));
l != NULL;
l = l->prev)
{
child_window = l->data;
type = gdk_window_get_window_type (child_window);
if (!gdk_window_is_visible (child_window) ||
gdk_window_is_input_only (child_window) ||
type == GDK_WINDOW_OFFSCREEN ||
type == GDK_WINDOW_FOREIGN)
continue;
gdk_window_get_user_data (child_window, &child_data);
if (child_data == (gpointer)widget)
{
gdk_window_get_position (child_window, &wx, &wy);
_gtk_widget_draw_windows (child_window, cr,
wx - widget->priv->allocation.x,
wy - widget->priv->allocation.y);
}
}
}
if (push_group)
{
cairo_pop_group_to_source (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_paint_with_alpha (cr, widget->priv->alpha / 255.0);
}
gtk_cairo_set_event (cr, tmp_event);
cairo_restore (cr);
}
@@ -6755,8 +6865,6 @@ gtk_widget_send_expose (GtkWidget *widget,
{
gboolean result = FALSE;
cairo_t *cr;
int x, y;
gboolean do_clip;
g_return_val_if_fail (GTK_IS_WIDGET (widget), TRUE);
g_return_val_if_fail (gtk_widget_get_realized (widget), TRUE);
@@ -6764,21 +6872,18 @@ gtk_widget_send_expose (GtkWidget *widget,
g_return_val_if_fail (event->type == GDK_EXPOSE, TRUE);
cr = gdk_cairo_create (event->expose.window);
gtk_cairo_set_event (cr, &event->expose);
gdk_cairo_region (cr, event->expose.region);
cairo_clip (cr);
do_clip = _gtk_widget_get_translation_to_window (widget,
event->expose.window,
&x, &y);
cairo_translate (cr, -x, -y);
gtk_cairo_set_event (cr, &event->expose);
_gtk_widget_draw_internal (widget, cr, do_clip);
if (event->expose.window == widget->priv->window)
gtk_widget_draw (widget, cr);
else
_gtk_widget_draw_windows (event->expose.window, cr, 0, 0);
/* unset here, so if someone keeps a reference to cr we
* don't leak the window. */
gtk_cairo_set_event (cr, NULL);
cairo_destroy (cr);
return result;
@@ -8460,6 +8565,9 @@ gtk_widget_get_app_paintable (GtkWidget *widget)
* expose events, since even the clearing to the background color or
* pixmap will not happen automatically (as it is done in
* gdk_window_begin_paint_region()).
*
* Since 3.10 this function only works for widgets with native
* windows.
**/
void
gtk_widget_set_double_buffered (GtkWidget *widget,
@@ -8718,8 +8826,6 @@ gtk_widget_set_parent (GtkWidget *widget,
gtk_widget_queue_compute_expand (parent);
}
gtk_widget_propagate_alpha (widget);
gtk_widget_pop_verify_invariants (widget);
}
@@ -14556,10 +14662,6 @@ gtk_widget_set_window (GtkWidget *widget,
{
priv->window = window;
if (gtk_widget_get_has_window (widget) && window != NULL && !gdk_window_has_native (window))
gdk_window_set_opacity (window,
priv->norender ? 0 : priv->alpha / 255.0);
g_object_notify (G_OBJECT (widget), "window");
}
}
@@ -14698,86 +14800,8 @@ gtk_widget_set_support_multidevice (GtkWidget *widget,
* in gtk_widget_set_opacity, secondly we can get it from the css opacity. These two
* are multiplied together to form the total alpha. Secondly, the user can specify
* an opacity group for a widget, which means we must essentially handle it as having alpha.
*
* We handle opacity in two ways. For a windowed widget, with opacity set but no opacity
* group we directly set the opacity of widget->window. This will cause gdk to properly
* redirect drawing inside the window to a buffer and do OVER paint_with_alpha.
*
* However, if the widget is not windowed, or the user specified an opacity group for the
* widget we do the opacity handling in the ::draw marshaller for the widget. A naive
* implementation of this would break for windowed widgets or descendant widgets with
* windows, as these would not be handled by the ::draw signal. To handle this we set
* all such gdkwindows as fully transparent and then override gtk_cairo_should_draw_window()
* to make the draw signal propagate to *all* child widgets/windows.
*
* Note: We don't make all child windows fully transparent, we stop at the first one
* in each branch when propagating down the hierarchy.
*/
/* This is called when priv->alpha or priv->opacity_group group changes, and should
* update priv->norender and GdkWindow opacity for this widget and any children that
* needs changing. It is also called whenver the parent changes, the parents
* norender_children state changes, or the has_window state of the widget changes.
*/
static void
gtk_widget_propagate_alpha (GtkWidget *widget)
{
GtkWidgetPrivate *priv = widget->priv;
GtkWidget *parent;
gboolean norender, norender_children;
GList *l;
parent = priv->parent;
/* Norender affects only windowed widget and means don't render widget->window in the
normal fashion.
We only set this if the parent has norender_children, because:
a) For an opacity group (that does not have a norender_children parent) we still
need to render the window or we will never get an expose event.
b) For alpha we set the opacity of window->widget directly, so no other
work is needed.
*/
norender = (parent != NULL && parent->priv->norender_children);
/* windows under this widget should not render if:
a) This widget has an opacity group
b) This widget has alpha and is no-windowed (otherwise we'd set alpha on widget->window)
c) This widget has norender but is no-windowed (a windowed widget would "swallow" the norender)
*/
norender_children =
priv->opacity_group ||
(!gtk_widget_get_has_window (widget) &&
( norender || priv->alpha != 255));
if (gtk_widget_get_has_window (widget))
{
if (priv->window != NULL &&
(!gdk_window_has_native (priv->window) || gtk_widget_is_toplevel (widget)))
gdk_window_set_opacity (priv->window,
norender ? 0 : priv->alpha / 255.0);
}
for (l = priv->registered_windows; l != NULL; l = l->next)
{
GdkWindow *w = l->data;
if (w != priv->window && !gdk_window_has_native (w))
gdk_window_set_opacity (w, norender_children ? 0.0 : 1.0);
}
priv->norender = norender;
if (priv->norender_children != norender_children)
{
priv->norender_children = norender_children;
if (GTK_IS_CONTAINER (widget))
gtk_container_forall (GTK_CONTAINER (widget), (GtkCallback)gtk_widget_propagate_alpha, NULL);
}
if (gtk_widget_get_realized (widget))
gtk_widget_queue_draw (widget);
}
static void
gtk_widget_update_alpha (GtkWidget *widget)
{
@@ -14804,8 +14828,12 @@ gtk_widget_update_alpha (GtkWidget *widget)
priv->alpha = alpha;
gtk_widget_propagate_alpha (widget);
if (gtk_widget_is_toplevel (widget))
gdk_window_set_opacity (priv->window,
priv->alpha / 255.0);
if (gtk_widget_get_realized (widget))
gtk_widget_queue_draw (widget);
}
static void
@@ -14825,7 +14853,8 @@ gtk_widget_set_has_opacity_group (GtkWidget *widget,
priv->opacity_group = has_opacity_group;
gtk_widget_propagate_alpha (widget);
if (gtk_widget_get_realized (widget))
gtk_widget_queue_draw (widget);
}
/**
+1 -3
View File
@@ -89,11 +89,9 @@ const gchar* _gtk_widget_get_accel_path (GtkWidget *widget,
AtkObject * _gtk_widget_peek_accessible (GtkWidget *widget);
GdkWindow * _gtk_cairo_get_event_window (cairo_t *cr);
GdkEventExpose * _gtk_cairo_get_event (cairo_t *cr);
void _gtk_widget_draw_internal (GtkWidget *widget,
cairo_t *cr,
gboolean clip_to_size);
void _gtk_widget_set_has_default (GtkWidget *widget,
gboolean has_default);
void _gtk_widget_set_has_grab (GtkWidget *widget,
+1016 -1157
View File
File diff suppressed because it is too large Load Diff
+345 -468
View File
File diff suppressed because it is too large Load Diff
+11
View File
@@ -27,6 +27,7 @@ endif
noinst_PROGRAMS = $(TEST_PROGS) \
animated-resizing \
motion-compression \
scrolling-performance \
simple \
flicker \
print-editor \
@@ -158,6 +159,7 @@ endif
animated_resizing_DEPENDENCIES = $(TEST_DEPS)
flicker_DEPENDENCIES = $(TEST_DEPS)
motion_compression_DEPENDENCIES = $(TEST_DEPS)
scrolling_performance_DEPENDENCIES = $(TEST_DEPS)
simple_DEPENDENCIES = $(TEST_DEPS)
print_editor_DEPENDENCIES = $(TEST_DEPS)
video_timer_DEPENDENCIES = $(TEST_DEPS)
@@ -263,6 +265,15 @@ testrevealer_DEPENDENCIES = $(TEST_DEPS)
animated_resizing_SOURCES = \
animated-resizing.c \
frame-stats.c \
frame-stats.h \
variable.c \
variable.h
scrolling_performance_SOURCES = \
scrolling-performance.c \
frame-stats.c \
frame-stats.h \
variable.c \
variable.h
+12 -117
View File
@@ -4,7 +4,7 @@
#include <math.h>
#include <string.h>
#include "variable.h"
#include "frame-stats.h"
#define RADIUS 64
#define DIAMETER (2*RADIUS)
@@ -19,11 +19,8 @@ static int window_width = WIDTH, window_height = HEIGHT;
gint64 start_frame_time;
static double angle;
static int max_stats = -1;
static double statistics_time = 5.;
static double load_factor = 1.0;
static double cb_no_resize = FALSE;
static gboolean machine_readable = FALSE;
static cairo_surface_t *source_surface;
@@ -113,115 +110,11 @@ on_window_draw (GtkWidget *widget,
g_rand_free(rand);
}
static void
print_double (const char *description,
double value)
{
if (machine_readable)
g_print ("%g\t", value);
else
g_print ("%s: %g\n", description, value);
}
static void
print_variable (const char *description,
Variable *variable)
{
if (variable->weight != 0)
{
if (machine_readable)
g_print ("%g\t%g\t",
variable_mean (variable),
variable_standard_deviation (variable));
else
g_print ("%s: %g +/- %g\n", description,
variable_mean (variable),
variable_standard_deviation (variable));
}
else
{
if (machine_readable)
g_print ("-\t-\t");
else
g_print ("%s: <n/a>\n", description);
}
}
static void
handle_frame_stats (GdkFrameClock *frame_clock)
{
static int num_stats = 0;
static double last_print_time = 0;
static int frames_since_last_print = 0;
static gint64 frame_counter;
static gint64 last_handled_frame = -1;
static Variable latency = VARIABLE_INIT;
double current_time;
current_time = g_get_monotonic_time ();
if (current_time >= last_print_time + 1000000 * statistics_time)
{
if (frames_since_last_print)
{
if (num_stats == 0 && machine_readable)
{
g_print ("# load_factor frame_rate latency\n");
}
num_stats++;
if (machine_readable)
g_print ("%g ", load_factor);
print_double ("Frame rate ",
frames_since_last_print / ((current_time - last_print_time) / 1000000.));
print_variable ("Latency", &latency);
g_print ("\n");
}
last_print_time = current_time;
frames_since_last_print = 0;
variable_reset (&latency);
if (num_stats == max_stats)
gtk_main_quit ();
}
frames_since_last_print++;
for (frame_counter = last_handled_frame;
frame_counter < gdk_frame_clock_get_frame_counter (frame_clock);
frame_counter++)
{
GdkFrameTimings *timings = gdk_frame_clock_get_timings (frame_clock, frame_counter);
GdkFrameTimings *previous_timings = gdk_frame_clock_get_timings (frame_clock, frame_counter - 1);
if (!timings || gdk_frame_timings_get_complete (timings))
last_handled_frame = frame_counter;
if (timings && gdk_frame_timings_get_complete (timings) && previous_timings &&
gdk_frame_timings_get_presentation_time (timings) != 0 &&
gdk_frame_timings_get_presentation_time (previous_timings) != 0)
{
double display_time = (gdk_frame_timings_get_presentation_time (timings) - gdk_frame_timings_get_presentation_time (previous_timings)) / 1000.;
double frame_latency = (gdk_frame_timings_get_presentation_time (previous_timings) - gdk_frame_timings_get_frame_time (previous_timings)) / 1000. + display_time / 2;
variable_add_weighted (&latency, frame_latency, display_time);
}
}
}
static void
on_frame (double progress)
{
GdkFrameClock *frame_clock = gtk_widget_get_frame_clock (window);
int jitter;
if (frame_clock)
handle_frame_stats (frame_clock);
angle = 2 * M_PI * progress;
jitter = WINDOW_SIZE_JITTER * sin(angle);
@@ -265,10 +158,7 @@ on_map_event (GtkWidget *widget,
static GOptionEntry options[] = {
{ "factor", 'f', 0, G_OPTION_ARG_DOUBLE, &load_factor, "Load factor", "FACTOR" },
{ "max-statistics", 'm', 0, G_OPTION_ARG_INT, &max_stats, "Maximum statistics printed", NULL },
{ "machine-readable", 0, 0, G_OPTION_ARG_NONE, &machine_readable, "Print statistics in columns", NULL },
{ "no-resize", 'n', 0, G_OPTION_ARG_NONE, &cb_no_resize, "No Resize", NULL },
{ "statistics-time", 's', 0, G_OPTION_ARG_DOUBLE, &statistics_time, "Statistics accumulation time", "TIME" },
{ NULL }
};
@@ -279,21 +169,26 @@ main(int argc, char **argv)
GdkScreen *screen;
GdkRectangle monitor_bounds;
if (!gtk_init_with_args (&argc, &argv, "",
options, NULL, &error))
GOptionContext *context = g_option_context_new (NULL);
g_option_context_add_main_entries (context, options, NULL);
frame_stats_add_options (g_option_context_get_main_group (context));
g_option_context_add_group (context,
gtk_get_option_group (TRUE));
if (!g_option_context_parse (context, &argc, &argv, &error))
{
g_printerr ("Option parsing failed: %s\n", error->message);
return 1;
}
g_print ("%sLoad factor: %g\n",
machine_readable ? "# " : "",
g_print ("# Load factor: %g\n",
load_factor);
g_print ("%sResizing?: %s\n",
machine_readable ? "# " : "",
g_print ("# Resizing?: %s\n",
cb_no_resize ? "no" : "yes");
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
frame_stats_ensure (GTK_WINDOW (window));
gtk_window_set_keep_above (GTK_WINDOW (window), TRUE);
gtk_window_set_gravity (GTK_WINDOW (window), GDK_GRAVITY_CENTER);
gtk_widget_set_app_paintable (window, TRUE);
+182
View File
@@ -0,0 +1,182 @@
/* -*- mode: C; c-basic-offset: 2; indent-tabs-mode: nil; -*- */
#include <gtk/gtk.h>
#include "frame-stats.h"
#include "variable.h"
typedef struct FrameStats FrameStats;
struct FrameStats
{
GdkFrameClock *frame_clock;
int num_stats;
double last_print_time;
int frames_since_last_print;
gint64 last_handled_frame;
Variable latency;
};
static int max_stats = -1;
static double statistics_time = 5.;
static gboolean machine_readable = FALSE;
static GOptionEntry frame_sync_options[] = {
{ "max-statistics", 'm', 0, G_OPTION_ARG_INT, &max_stats, "Maximum statistics printed", NULL },
{ "machine-readable", 0, 0, G_OPTION_ARG_NONE, &machine_readable, "Print statistics in columns", NULL },
{ "statistics-time", 's', 0, G_OPTION_ARG_DOUBLE, &statistics_time, "Statistics accumulation time", "TIME" },
{ NULL }
};
void
frame_stats_add_options (GOptionGroup *group)
{
g_option_group_add_entries (group, frame_sync_options);
}
static void
print_double (const char *description,
double value)
{
if (machine_readable)
g_print ("%g\t", value);
else
g_print ("%s: %g\n", description, value);
}
static void
print_variable (const char *description,
Variable *variable)
{
if (variable->weight != 0)
{
if (machine_readable)
g_print ("%g\t%g\t",
variable_mean (variable),
variable_standard_deviation (variable));
else
g_print ("%s: %g +/- %g\n", description,
variable_mean (variable),
variable_standard_deviation (variable));
}
else
{
if (machine_readable)
g_print ("-\t-\t");
else
g_print ("%s: <n/a>\n", description);
}
}
static void
on_frame_clock_after_paint (GdkFrameClock *frame_clock,
FrameStats *frame_stats)
{
gint64 frame_counter;
gint64 current_time;
current_time = g_get_monotonic_time ();
if (current_time >= frame_stats->last_print_time + 1000000 * statistics_time)
{
if (frame_stats->frames_since_last_print)
{
if (frame_stats->num_stats == 0 && machine_readable)
{
g_print ("# load_factor frame_rate latency\n");
}
frame_stats->num_stats++;
print_double ("Frame rate ",
frame_stats->frames_since_last_print /
((current_time - frame_stats->last_print_time) / 1000000.));
print_variable ("Latency", &frame_stats->latency);
g_print ("\n");
}
frame_stats->last_print_time = current_time;
frame_stats->frames_since_last_print = 0;
variable_init (&frame_stats->latency);
if (frame_stats->num_stats == max_stats)
gtk_main_quit ();
}
frame_stats->frames_since_last_print++;
for (frame_counter = frame_stats->last_handled_frame;
frame_counter < gdk_frame_clock_get_frame_counter (frame_clock);
frame_counter++)
{
GdkFrameTimings *timings = gdk_frame_clock_get_timings (frame_clock, frame_counter);
GdkFrameTimings *previous_timings = gdk_frame_clock_get_timings (frame_clock, frame_counter - 1);
if (!timings || gdk_frame_timings_get_complete (timings))
frame_stats->last_handled_frame = frame_counter;
if (timings && gdk_frame_timings_get_complete (timings) && previous_timings &&
gdk_frame_timings_get_presentation_time (timings) != 0 &&
gdk_frame_timings_get_presentation_time (previous_timings) != 0)
{
double display_time = (gdk_frame_timings_get_presentation_time (timings) - gdk_frame_timings_get_presentation_time (previous_timings)) / 1000.;
double frame_latency = (gdk_frame_timings_get_presentation_time (previous_timings) - gdk_frame_timings_get_frame_time (previous_timings)) / 1000. + display_time / 2;
variable_add_weighted (&frame_stats->latency, frame_latency, display_time);
}
}
}
void
on_window_realize (GtkWidget *window,
FrameStats *frame_stats)
{
frame_stats->frame_clock = gtk_widget_get_frame_clock (GTK_WIDGET (window));
g_signal_connect (frame_stats->frame_clock, "after-paint",
G_CALLBACK (on_frame_clock_after_paint), frame_stats);
}
void
on_window_unrealize (GtkWidget *window,
FrameStats *frame_stats)
{
g_signal_handlers_disconnect_by_func (frame_stats->frame_clock,
(gpointer) on_frame_clock_after_paint,
frame_stats);
frame_stats->frame_clock = NULL;
}
void
on_window_destroy (GtkWidget *window,
FrameStats *stats)
{
g_free (stats);
}
void
frame_stats_ensure (GtkWindow *window)
{
FrameStats *frame_stats;
frame_stats = g_object_get_data (G_OBJECT (window), "frame-stats");
if (frame_stats != NULL)
return;
frame_stats = g_new0 (FrameStats, 1);
g_object_set_data (G_OBJECT (window), "frame-stats", frame_stats);
variable_init (&frame_stats->latency);
frame_stats->last_handled_frame = -1;
g_signal_connect (window, "realize",
G_CALLBACK (on_window_realize), frame_stats);
g_signal_connect (window, "unrealize",
G_CALLBACK (on_window_unrealize), frame_stats);
g_signal_connect (window, "destroy",
G_CALLBACK (on_window_destroy), frame_stats);
if (gtk_widget_get_realized (GTK_WIDGET (window)))
on_window_realize (GTK_WIDGET (window), frame_stats);
}
+9
View File
@@ -0,0 +1,9 @@
#ifndef __FRAME_STATS_H__
#define __FRAME_STATS_H__
#include <gtk/gtk.h>
void frame_stats_add_options (GOptionGroup *group);
void frame_stats_ensure (GtkWindow *window);
#endif /* __FRAME_STATS_H__ */
+126
View File
@@ -0,0 +1,126 @@
/* -*- mode: C; c-basic-offset: 2; indent-tabs-mode: nil; -*- */
#include <gtk/gtk.h>
#include <math.h>
#include "frame-stats.h"
GtkWidget *
create_widget_factory_content (void)
{
GError *error = NULL;
GtkBuilder *builder;
GtkWidget *result;
builder = gtk_builder_new ();
gtk_builder_add_from_file (builder,
"../demos/widget-factory/widget-factory.ui",
&error);
if (error != NULL)
g_error ("Failed to create widgets: %s\n", error->message);
result = GTK_WIDGET (gtk_builder_get_object (builder, "box1"));
g_object_ref (result);
gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (result)),
result);
g_object_unref (builder);
return result;
}
static void
set_adjustment_to_fraction (GtkAdjustment *adjustment,
gdouble fraction)
{
gdouble upper = gtk_adjustment_get_upper (adjustment);
gdouble lower = gtk_adjustment_get_lower (adjustment);
gdouble page_size = gtk_adjustment_get_page_size (adjustment);
gtk_adjustment_set_value (adjustment,
(1 - fraction) * lower +
fraction * (upper - page_size));
}
gboolean
scroll_viewport (GtkWidget *viewport,
GdkFrameClock *frame_clock,
gpointer user_data)
{
static gint64 start_time;
gint64 now = gdk_frame_clock_get_frame_time (frame_clock);
gdouble elapsed;
GtkAdjustment *hadjustment, *vadjustment;
if (start_time == 0)
start_time = now;
elapsed = (now - start_time) / 1000000.;
hadjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (viewport));
vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (viewport));
set_adjustment_to_fraction (hadjustment, 0.5 + 0.5 * sin (elapsed));
set_adjustment_to_fraction (vadjustment, 0.5 + 0.5 * cos (elapsed));
return TRUE;
}
static GOptionEntry options[] = {
{ NULL }
};
int
main (int argc, char **argv)
{
GtkWidget *window;
GtkWidget *scrolled_window;
GtkWidget *viewport;
GtkWidget *grid;
GError *error = NULL;
int i;
GOptionContext *context = g_option_context_new (NULL);
g_option_context_add_main_entries (context, options, NULL);
frame_stats_add_options (g_option_context_get_main_group (context));
g_option_context_add_group (context,
gtk_get_option_group (TRUE));
if (!g_option_context_parse (context, &argc, &argv, &error))
{
g_printerr ("Option parsing failed: %s\n", error->message);
return 1;
}
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
frame_stats_ensure (GTK_WINDOW (window));
gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (window), scrolled_window);
viewport = gtk_viewport_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (scrolled_window), viewport);
grid = gtk_grid_new ();
gtk_container_add (GTK_CONTAINER (viewport), grid);
for (i = 0; i < 4; i++)
{
GtkWidget *content = create_widget_factory_content ();
gtk_grid_attach (GTK_GRID (grid), content,
i % 2, i / 2, 1, 1);
g_object_unref (content);
}
gtk_widget_add_tick_callback (viewport,
scroll_viewport,
NULL,
NULL);
gtk_widget_show_all (window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_main_quit), NULL);
gtk_main ();
return 0;
}
+8 -9
View File
@@ -3,6 +3,14 @@
#include <math.h>
#include "variable.h"
void
variable_init (Variable *variable)
{
variable->weight = 0.0;
variable->sum = 0.0;
variable->sum2 = 0.0;
}
void
variable_add_weighted (Variable *variable,
double value,
@@ -32,12 +40,3 @@ variable_standard_deviation (Variable *variable)
double mean = variable_mean (variable);
return sqrt (variable->sum2 / variable->weight - mean * mean);
}
void
variable_reset (Variable *variable)
{
variable->weight = 0;
variable->sum = 0;
variable->sum2 = 0;
}
+3 -2
View File
@@ -8,8 +8,9 @@ typedef struct
double sum2;
} Variable;
#define VARIABLE_INIT { 0, 0.0, 0.0 }
#define VARIABLE_INIT { 0.0, 0.0, 0.0 }
void variable_init (Variable *variable);
void variable_add_weighted (Variable *variable,
double value,
double weight);
@@ -19,5 +20,5 @@ double variable_mean (Variable *variable);
double variable_standard_deviation (Variable *variable);
void variable_reset (Variable *variable);
#endif /* __VARAIBLE_H__ */
#endif /* __VARIABLE_H__ */
+2 -2
View File
@@ -291,8 +291,8 @@ print_statistics (void)
g_print ("playback rate adjustment: %g +/- %g %%\n",
(variable_mean (&time_factor_stats) - 1) * 100,
variable_standard_deviation (&time_factor_stats) * 100);
variable_reset (&latency_error);
variable_reset (&time_factor_stats);
variable_init (&latency_error);
variable_init (&time_factor_stats);
dropped_frames = 0;
n_frames = 0;
last_print_time = now;