summaryrefslogtreecommitdiff
path: root/gtk
diff options
context:
space:
mode:
authorFederico Mena Quintero <federico@gnome.org>2013-02-27 10:29:35 -0600
committerFederico Mena Quintero <federico@gnome.org>2013-02-27 10:29:35 -0600
commita46976fb79dac40288727bdaa4a5a231d9edddf3 (patch)
treefc98b941229179c12561efeeb14ff7e528e8c929 /gtk
parent936045e82bc9a3f2b09612e3c22799c45b101c5e (diff)
parentbbfc8f9a9b84cc019dff0c23d52aac83beb6be64 (diff)
downloadgtk+-a46976fb79dac40288727bdaa4a5a231d9edddf3.tar.gz
Merge branch 'origin/master' into places-sidebar
Diffstat (limited to 'gtk')
-rw-r--r--gtk/a11y/Makefile.am32
-rw-r--r--gtk/a11y/gtkcellaccessible.c2
-rw-r--r--gtk/a11y/gtktextviewaccessible.c10
-rw-r--r--gtk/a11y/gtktreeviewaccessible.c95
-rw-r--r--gtk/gtk.symbols11
-rw-r--r--gtk/gtkaccellabel.c8
-rw-r--r--gtk/gtkapplication.c14
-rw-r--r--gtk/gtkbox.c25
-rw-r--r--gtk/gtkcellrenderer.c10
-rw-r--r--gtk/gtkcellrenderer.h2
-rw-r--r--gtk/gtkcellrendererpixbuf.c2
-rw-r--r--gtk/gtkcellrenderertext.c2
-rw-r--r--gtk/gtkcellrenderertoggle.c2
-rw-r--r--gtk/gtkcolorswatch.c2
-rw-r--r--gtk/gtkcombobox.c27
-rw-r--r--gtk/gtkcontainer.c92
-rw-r--r--gtk/gtkcontainerprivate.h2
-rw-r--r--gtk/gtkentry.c49
-rw-r--r--gtk/gtkfilechooserbutton.c39
-rw-r--r--gtk/gtkfilechooserdefault.c21
-rw-r--r--gtk/gtkfilesystem.c2
-rw-r--r--gtk/gtkiconfactory.c2
-rw-r--r--gtk/gtkiconhelper.c2
-rw-r--r--gtk/gtkicontheme.c634
-rw-r--r--gtk/gtkicontheme.h42
-rw-r--r--gtk/gtkimmodule.c14
-rw-r--r--gtk/gtknumerableicon.c2
-rw-r--r--gtk/gtkplug.c2
-rw-r--r--gtk/gtkradiomenuitem.c42
-rw-r--r--gtk/gtkrecentmanager.c2
-rw-r--r--gtk/gtkscrolledwindow.c36
-rw-r--r--gtk/gtkstylecontext.c173
-rw-r--r--gtk/gtkstylecontext.h7
-rw-r--r--gtk/gtktexthandle.c16
-rw-r--r--gtk/gtktoolbar.c23
-rw-r--r--gtk/gtktreeview.c1
-rw-r--r--gtk/gtkuimanager.c1
-rw-r--r--gtk/gtkviewport.c7
-rw-r--r--gtk/gtkwidget.c350
-rw-r--r--gtk/gtkwidget.h32
-rw-r--r--gtk/gtkwindow.c13
-rw-r--r--gtk/tests/filechooser.c271
-rw-r--r--gtk/tests/treeview-scrolling.c32
-rw-r--r--gtk/updateiconcache.c23
44 files changed, 1771 insertions, 405 deletions
diff --git a/gtk/a11y/Makefile.am b/gtk/a11y/Makefile.am
index 5eec7d42fd..ee9b0ce01c 100644
--- a/gtk/a11y/Makefile.am
+++ b/gtk/a11y/Makefile.am
@@ -137,37 +137,37 @@ libgtka11y_la_LIBADD = \
libgtka11y_la_LDFLAGS = \
$(LDFLAGS)
-dist-hook: ../../build/win32/vs9/libgail.vcproj ../../build/win32/vs10/libgail.vcxproj ../../build/win32/vs10/libgail.vcxproj.filters
+dist-hook: $(top_builddir)/build/win32/vs9/gtka11y.vcproj $(top_builddir)/build/win32/vs10/gtka11y.vcxproj $(top_builddir)/build/win32/vs10/gtka11y.vcxproj.filters
-../../build/win32/vs9/libgail.vcproj: ../../build/win32/vs9/libgail.vcprojin
- for F in $(libgail_la_SOURCES); do \
+$(top_builddir)/build/win32/vs9/gtka11y.vcproj: $(top_srcdir)/build/win32/vs9/gtka11y.vcprojin
+ for F in $(gtka11y_c_sources); do \
case $$F in \
*.c) echo ' <File RelativePath="..\..\..\gtk\a11y\'$$F'" />' \
;; \
esac; \
- done >libgail.sourcefiles
- $(CPP) -P - <$(top_srcdir)/build/win32/vs9/libgail.vcprojin >$@
- rm libgail.sourcefiles
+ done >gtka11y.sourcefiles
+ $(CPP) -P - <$(top_srcdir)/build/win32/vs9/gtka11y.vcprojin >$@
+ rm gtka11y.sourcefiles
-../../build/win32/vs10/libgail.vcxproj: ../../build/win32/vs10/libgail.vcxprojin
- for F in $(libgail_la_SOURCES); do \
+$(top_builddir)/build/win32/vs10/gtka11y.vcxproj: $(top_srcdir)/build/win32/vs10/gtka11y.vcxprojin
+ for F in $(gtka11y_c_sources); do \
case $$F in \
*.c) echo ' <ClCompile Include="..\..\..\gtk\a11y\'$$F'" />' \
;; \
esac; \
- done >libgail.vs10.sourcefiles
- $(CPP) -P - <$(top_srcdir)/build/win32/vs10/libgail.vcxprojin >$@
- rm libgail.vs10.sourcefiles
+ done >gtka11y.vs10.sourcefiles
+ $(CPP) -P - <$(top_srcdir)/build/win32/vs10/gtka11y.vcxprojin >$@
+ rm gtka11y.vs10.sourcefiles
-../../build/win32/vs10/libgail.vcxproj.filters: ../../build/win32/vs10/libgail.vcxproj.filtersin
- for F in $(libgail_la_SOURCES); do \
+$(top_builddir)/build/win32/vs10/gtka11y.vcxproj.filters: $(top_srcdir)/build/win32/vs10/gtka11y.vcxproj.filtersin
+ for F in $(gtka11y_c_sources); do \
case $$F in \
*.c) echo ' <ClCompile Include="..\..\..\gtk\a11y\'$$F'"><Filter>Source Files</Filter></ClCompile>' \
;; \
esac; \
- done >libgail.vs10.sourcefiles.filters
- $(CPP) -P - <$(top_srcdir)/build/win32/vs10/libgail.vcxproj.filtersin >$@
- rm libgail.vs10.sourcefiles.filters
+ done >gtka11y.vs10.sourcefiles.filters
+ $(CPP) -P - <$(top_srcdir)/build/win32/vs10/gtka11y.vcxproj.filtersin >$@
+ rm gtka11y.vs10.sourcefiles.filters
-include $(top_srcdir)/git.mk
diff --git a/gtk/a11y/gtkcellaccessible.c b/gtk/a11y/gtkcellaccessible.c
index e03496b85a..b5846e8c21 100644
--- a/gtk/a11y/gtkcellaccessible.c
+++ b/gtk/a11y/gtkcellaccessible.c
@@ -412,7 +412,7 @@ _gtk_cell_accessible_state_changed (GtkCellAccessible *cell,
atk_object_notify_state_change (object,
state_map[i].atk_state,
!state_map[i].invert);
- if (added & state_map[i].renderer_state)
+ if (removed & state_map[i].renderer_state)
atk_object_notify_state_change (object,
state_map[i].atk_state,
state_map[i].invert);
diff --git a/gtk/a11y/gtktextviewaccessible.c b/gtk/a11y/gtktextviewaccessible.c
index 9e59b8f1a1..ca07161d22 100644
--- a/gtk/a11y/gtktextviewaccessible.c
+++ b/gtk/a11y/gtktextviewaccessible.c
@@ -117,6 +117,11 @@ gtk_text_view_accessible_change_buffer (GtkTextViewAccessible *accessible,
if (old_buffer)
{
g_signal_handlers_disconnect_matched (old_buffer, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, accessible);
+
+ g_signal_emit_by_name (accessible,
+ "text-changed::delete",
+ 0,
+ gtk_text_buffer_get_char_count (old_buffer));
}
if (new_buffer)
@@ -124,6 +129,11 @@ gtk_text_view_accessible_change_buffer (GtkTextViewAccessible *accessible,
g_signal_connect_after (new_buffer, "insert-text", G_CALLBACK (insert_text_cb), accessible);
g_signal_connect (new_buffer, "delete-range", G_CALLBACK (delete_range_cb), accessible);
g_signal_connect_after (new_buffer, "mark-set", G_CALLBACK (mark_set_cb), accessible);
+
+ g_signal_emit_by_name (accessible,
+ "text-changed::insert",
+ 0,
+ gtk_text_buffer_get_char_count (new_buffer));
}
}
diff --git a/gtk/a11y/gtktreeviewaccessible.c b/gtk/a11y/gtktreeviewaccessible.c
index a25fba5d04..09bb72fde7 100644
--- a/gtk/a11y/gtktreeviewaccessible.c
+++ b/gtk/a11y/gtktreeviewaccessible.c
@@ -1896,6 +1896,7 @@ _gtk_tree_view_accessible_add_state (GtkTreeView *treeview,
GtkCellRendererState state)
{
GtkTreeViewAccessible *accessible;
+ GtkTreeViewColumn *single_column;
AtkObject *obj;
guint i;
@@ -1907,36 +1908,38 @@ _gtk_tree_view_accessible_add_state (GtkTreeView *treeview,
if (state == GTK_CELL_RENDERER_FOCUSED)
{
- GtkTreeViewColumn *focus_column;
-
- focus_column = get_effective_focus_column (treeview, _gtk_tree_view_get_focus_column (treeview));
-
- if (focus_column)
- {
- GtkCellAccessible *cell;
-
- cell = peek_cell (accessible, tree, node, focus_column);
- if (cell != NULL)
- _gtk_cell_accessible_state_changed (cell, 0, state);
- else
- cell = create_cell (treeview, accessible, tree, node, focus_column);
-
- g_signal_emit_by_name (accessible, "active-descendant-changed", cell);
- }
-
- return;
+ single_column = get_effective_focus_column (treeview, _gtk_tree_view_get_focus_column (treeview));
+ }
+ else if (state == GTK_CELL_RENDERER_EXPANDED ||
+ state == GTK_CELL_RENDERER_EXPANDABLE)
+ {
+ single_column = gtk_tree_view_get_expander_column (treeview);
}
+ else
+ single_column = NULL;
- for (i = 0; i < gtk_tree_view_get_n_columns (treeview); i++)
+ if (single_column)
{
GtkCellAccessible *cell = peek_cell (accessible,
tree, node,
- gtk_tree_view_get_column (treeview, i));
+ single_column);
- if (cell == NULL)
- continue;
+ if (cell != NULL)
+ _gtk_cell_accessible_state_changed (cell, state, 0);
+ }
+ else
+ {
+ for (i = 0; i < gtk_tree_view_get_n_columns (treeview); i++)
+ {
+ GtkCellAccessible *cell = peek_cell (accessible,
+ tree, node,
+ gtk_tree_view_get_column (treeview, i));
+
+ if (cell == NULL)
+ continue;
- _gtk_cell_accessible_state_changed (cell, state, 0);
+ _gtk_cell_accessible_state_changed (cell, state, 0);
+ }
}
if (state == GTK_CELL_RENDERER_SELECTED)
@@ -1950,6 +1953,7 @@ _gtk_tree_view_accessible_remove_state (GtkTreeView *treeview,
GtkCellRendererState state)
{
GtkTreeViewAccessible *accessible;
+ GtkTreeViewColumn *single_column;
AtkObject *obj;
guint i;
@@ -1961,33 +1965,38 @@ _gtk_tree_view_accessible_remove_state (GtkTreeView *treeview,
if (state == GTK_CELL_RENDERER_FOCUSED)
{
- GtkTreeViewColumn *focus_column;
-
- focus_column = get_effective_focus_column (treeview, _gtk_tree_view_get_focus_column (treeview));
-
- if (focus_column)
- {
- GtkCellAccessible *cell = peek_cell (accessible,
- tree, node,
- focus_column);
-
- if (cell != NULL)
- _gtk_cell_accessible_state_changed (cell, 0, state);
- }
-
- return;
+ single_column = get_effective_focus_column (treeview, _gtk_tree_view_get_focus_column (treeview));
+ }
+ else if (state == GTK_CELL_RENDERER_EXPANDED ||
+ state == GTK_CELL_RENDERER_EXPANDABLE)
+ {
+ single_column = gtk_tree_view_get_expander_column (treeview);
}
+ else
+ single_column = NULL;
- for (i = 0; i < gtk_tree_view_get_n_columns (treeview); i++)
+ if (single_column)
{
GtkCellAccessible *cell = peek_cell (accessible,
tree, node,
- gtk_tree_view_get_column (treeview, i));
+ single_column);
- if (cell == NULL)
- continue;
+ if (cell != NULL)
+ _gtk_cell_accessible_state_changed (cell, 0, state);
+ }
+ else
+ {
+ for (i = 0; i < gtk_tree_view_get_n_columns (treeview); i++)
+ {
+ GtkCellAccessible *cell = peek_cell (accessible,
+ tree, node,
+ gtk_tree_view_get_column (treeview, i));
+
+ if (cell == NULL)
+ continue;
- _gtk_cell_accessible_state_changed (cell, 0, state);
+ _gtk_cell_accessible_state_changed (cell, 0, state);
+ }
}
if (state == GTK_CELL_RENDERER_SELECTED)
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index d0e219c643..fe927d62c5 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -1255,8 +1255,14 @@ gtk_icon_info_get_embedded_rect
gtk_icon_info_get_filename
gtk_icon_info_get_type
gtk_icon_info_load_icon
+gtk_icon_info_load_icon_async
+gtk_icon_info_load_icon_finish
gtk_icon_info_load_symbolic
+gtk_icon_info_load_symbolic_async
+gtk_icon_info_load_symbolic_finish
gtk_icon_info_load_symbolic_for_context
+gtk_icon_info_load_symbolic_for_context_async
+gtk_icon_info_load_symbolic_for_context_finish
gtk_icon_info_load_symbolic_for_style
gtk_icon_info_new_for_pixbuf
gtk_icon_info_set_raw_coordinates
@@ -2665,6 +2671,7 @@ gtk_style_context_get_border_color
gtk_style_context_get_color
gtk_style_context_get_direction
gtk_style_context_get_font
+gtk_style_context_get_frame_clock
gtk_style_context_get_junction_sides
gtk_style_context_get_margin
gtk_style_context_get_padding
@@ -2700,6 +2707,7 @@ gtk_style_context_save
gtk_style_context_scroll_animations
gtk_style_context_set_background
gtk_style_context_set_direction
+gtk_style_context_set_frame_clock
gtk_style_context_set_junction_sides
gtk_style_context_set_parent
gtk_style_context_set_path
@@ -3664,6 +3672,7 @@ gtk_widget_add_accelerator
gtk_widget_add_device_events
gtk_widget_add_events
gtk_widget_add_mnemonic_label
+gtk_widget_add_tick_callback
gtk_widget_can_activate_accel
gtk_widget_child_focus
gtk_widget_child_notify
@@ -3705,6 +3714,7 @@ gtk_widget_get_direction
gtk_widget_get_display
gtk_widget_get_double_buffered
gtk_widget_get_events
+gtk_widget_get_frame_clock
gtk_widget_get_halign
gtk_widget_get_has_tooltip
gtk_widget_get_has_window
@@ -3843,6 +3853,7 @@ gtk_widget_region_intersect
gtk_widget_register_window
gtk_widget_remove_accelerator
gtk_widget_remove_mnemonic_label
+gtk_widget_remove_tick_callback
gtk_widget_render_icon
gtk_widget_render_icon_pixbuf
gtk_widget_reparent
diff --git a/gtk/gtkaccellabel.c b/gtk/gtkaccellabel.c
index 311b4a4d7f..d8bb7e96fa 100644
--- a/gtk/gtkaccellabel.c
+++ b/gtk/gtkaccellabel.c
@@ -836,12 +836,13 @@ _gtk_accel_label_class_get_accelerator_label (GtkAccelLabelClass *klass,
#endif
seen_mod = TRUE;
}
- if (seen_mod)
- g_string_append (gstring, klass->mod_separator);
ch = gdk_keyval_to_unicode (accelerator_key);
if (ch && ch < 0x80 && (g_unichar_isgraph (ch) || ch == ' '))
{
+ if (seen_mod)
+ g_string_append (gstring, klass->mod_separator);
+
switch (ch)
{
case ' ':
@@ -862,6 +863,9 @@ _gtk_accel_label_class_get_accelerator_label (GtkAccelLabelClass *klass,
tmp = gdk_keyval_name (gdk_keyval_to_lower (accelerator_key));
if (tmp != NULL)
{
+ if (seen_mod)
+ g_string_append (gstring, klass->mod_separator);
+
if (tmp[0] != 0 && tmp[1] == 0)
g_string_append_c (gstring, g_ascii_toupper (tmp[0]));
else
diff --git a/gtk/gtkapplication.c b/gtk/gtkapplication.c
index bbb65b847e..9072907513 100644
--- a/gtk/gtkapplication.c
+++ b/gtk/gtkapplication.c
@@ -1418,16 +1418,22 @@ gtk_application_inhibit (GtkApplication *application,
GVariant *res;
GError *error = NULL;
guint cookie;
- guint xid;
+ guint xid = 0;
g_return_val_if_fail (GTK_IS_APPLICATION (application), 0);
g_return_val_if_fail (!g_application_get_is_remote (G_APPLICATION (application)), 0);
g_return_val_if_fail (application->priv->sm_proxy != NULL, 0);
if (window != NULL)
- xid = GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (window)));
- else
- xid = 0;
+ {
+ GdkWindow *gdkwindow;
+
+ gdkwindow = gtk_widget_get_window (GTK_WIDGET (window));
+ if (gdkwindow == NULL)
+ g_warning ("Inhibit called with an unrealized window");
+ else
+ xid = GDK_WINDOW_XID (gdkwindow);
+ }
res = g_dbus_proxy_call_sync (application->priv->sm_proxy,
"Inhibit",
diff --git a/gtk/gtkbox.c b/gtk/gtkbox.c
index efd4936657..5c8e6e3ff8 100644
--- a/gtk/gtkbox.c
+++ b/gtk/gtkbox.c
@@ -151,6 +151,8 @@ static void gtk_box_size_allocate (GtkWidget *widget,
static void gtk_box_compute_expand (GtkWidget *widget,
gboolean *hexpand,
gboolean *vexpand);
+static void gtk_box_direction_changed (GtkWidget *widget,
+ GtkTextDirection previous_direction);
static void gtk_box_set_property (GObject *object,
guint prop_id,
@@ -220,6 +222,7 @@ gtk_box_class_init (GtkBoxClass *class)
widget_class->get_preferred_height_for_width = gtk_box_get_preferred_height_for_width;
widget_class->get_preferred_width_for_height = gtk_box_get_preferred_width_for_height;
widget_class->compute_expand = gtk_box_compute_expand;
+ widget_class->direction_changed = gtk_box_direction_changed;
container_class->add = gtk_box_add;
container_class->remove = gtk_box_remove;
@@ -855,7 +858,9 @@ count_widget_position (GtkWidget *widget,
if (count->widget == widget)
count->found = TRUE;
- else if (!count->found)
+ else if (count->found)
+ count->after++;
+ else
count->before++;
}
@@ -877,7 +882,11 @@ gtk_box_get_visible_position (GtkBox *box,
if (!count.found)
return -1;
- return count.before;
+ if (box->priv->orientation == GTK_ORIENTATION_HORIZONTAL &&
+ gtk_widget_get_direction (GTK_WIDGET (box)) == GTK_TEXT_DIR_RTL)
+ return count.after;
+ else
+ return count.before;
}
static GtkWidgetPath *
@@ -886,9 +895,11 @@ gtk_box_get_path_for_child (GtkContainer *container,
{
GtkWidgetPath *path, *sibling_path;
GtkBox *box;
+ GtkBoxPrivate *private;
GList *list, *children;
box = GTK_BOX (container);
+ private = box->priv;
path = _gtk_widget_create_path (GTK_WIDGET (container));
@@ -900,6 +911,9 @@ gtk_box_get_path_for_child (GtkContainer *container,
/* get_children works in visible order */
children = gtk_container_get_children (container);
+ if (private->orientation == GTK_ORIENTATION_HORIZONTAL &&
+ gtk_widget_get_direction (GTK_WIDGET (box)) == GTK_TEXT_DIR_RTL)
+ children = g_list_reverse (children);
for (list = children; list; list = list->next)
{
@@ -941,6 +955,13 @@ gtk_box_invalidate_order (GtkBox *box)
}
static void
+gtk_box_direction_changed (GtkWidget *widget,
+ GtkTextDirection previous_direction)
+{
+ gtk_box_invalidate_order (GTK_BOX (widget));
+}
+
+static void
box_child_visibility_notify_cb (GObject *obj,
GParamSpec *pspec,
gpointer user_data)
diff --git a/gtk/gtkcellrenderer.c b/gtk/gtkcellrenderer.c
index c941190d0b..78fb31c863 100644
--- a/gtk/gtkcellrenderer.c
+++ b/gtk/gtkcellrenderer.c
@@ -429,7 +429,7 @@ gtk_cell_renderer_class_init (GtkCellRendererClass *class)
g_type_class_add_private (class, sizeof (GtkCellRendererPrivate));
- _gtk_cell_renderer_class_set_accessible_type (class, GTK_TYPE_RENDERER_CELL_ACCESSIBLE);
+ gtk_cell_renderer_class_set_accessible_type (class, GTK_TYPE_RENDERER_CELL_ACCESSIBLE);
}
static void
@@ -1781,8 +1781,8 @@ gtk_cell_renderer_get_state (GtkCellRenderer *cell,
return state;
}
-/*
- * _gtk_cell_renderer_class_set_accessible_type:
+/**
+ * gtk_cell_renderer_class_set_accessible_type:
* @renderer_class: class to set the accessible type for
* @type: The object type that implements the accessible for @widget_class.
* The type must be a subtype of #GtkRendererCellAccessible
@@ -1795,8 +1795,8 @@ gtk_cell_renderer_get_state (GtkCellRenderer *cell,
* renderers.
**/
void
-_gtk_cell_renderer_class_set_accessible_type (GtkCellRendererClass *renderer_class,
- GType type)
+gtk_cell_renderer_class_set_accessible_type (GtkCellRendererClass *renderer_class,
+ GType type)
{
GtkCellRendererClassPrivate *priv;
diff --git a/gtk/gtkcellrenderer.h b/gtk/gtkcellrenderer.h
index 3eee3088ca..8948e64c56 100644
--- a/gtk/gtkcellrenderer.h
+++ b/gtk/gtkcellrenderer.h
@@ -269,7 +269,7 @@ GtkStateFlags gtk_cell_renderer_get_state (GtkCellRenderer *cell,
GtkWidget *widget,
GtkCellRendererState cell_state);
-void _gtk_cell_renderer_class_set_accessible_type
+void gtk_cell_renderer_class_set_accessible_type
(GtkCellRendererClass *renderer_class,
GType type);
GType _gtk_cell_renderer_get_accessible_type
diff --git a/gtk/gtkcellrendererpixbuf.c b/gtk/gtkcellrendererpixbuf.c
index 2e36915585..90fc9fece0 100644
--- a/gtk/gtkcellrendererpixbuf.c
+++ b/gtk/gtkcellrendererpixbuf.c
@@ -251,7 +251,7 @@ gtk_cell_renderer_pixbuf_class_init (GtkCellRendererPixbufClass *class)
g_type_class_add_private (object_class, sizeof (GtkCellRendererPixbufPrivate));
- _gtk_cell_renderer_class_set_accessible_type (cell_class, GTK_TYPE_IMAGE_CELL_ACCESSIBLE);
+ gtk_cell_renderer_class_set_accessible_type (cell_class, GTK_TYPE_IMAGE_CELL_ACCESSIBLE);
}
static void
diff --git a/gtk/gtkcellrenderertext.c b/gtk/gtkcellrenderertext.c
index 31b0413b1a..3399bb2be0 100644
--- a/gtk/gtkcellrenderertext.c
+++ b/gtk/gtkcellrenderertext.c
@@ -731,7 +731,7 @@ gtk_cell_renderer_text_class_init (GtkCellRendererTextClass *class)
g_type_class_add_private (object_class, sizeof (GtkCellRendererTextPrivate));
- _gtk_cell_renderer_class_set_accessible_type (cell_class, GTK_TYPE_TEXT_CELL_ACCESSIBLE);
+ gtk_cell_renderer_class_set_accessible_type (cell_class, GTK_TYPE_TEXT_CELL_ACCESSIBLE);
}
static void
diff --git a/gtk/gtkcellrenderertoggle.c b/gtk/gtkcellrenderertoggle.c
index c83f6003b7..f94ff2a71a 100644
--- a/gtk/gtkcellrenderertoggle.c
+++ b/gtk/gtkcellrenderertoggle.c
@@ -196,7 +196,7 @@ gtk_cell_renderer_toggle_class_init (GtkCellRendererToggleClass *class)
g_type_class_add_private (object_class, sizeof (GtkCellRendererTogglePrivate));
- _gtk_cell_renderer_class_set_accessible_type (cell_class, GTK_TYPE_BOOLEAN_CELL_ACCESSIBLE);
+ gtk_cell_renderer_class_set_accessible_type (cell_class, GTK_TYPE_BOOLEAN_CELL_ACCESSIBLE);
}
static void
diff --git a/gtk/gtkcolorswatch.c b/gtk/gtkcolorswatch.c
index e33a3f601f..c6081d7907 100644
--- a/gtk/gtkcolorswatch.c
+++ b/gtk/gtkcolorswatch.c
@@ -228,7 +228,7 @@ swatch_draw (GtkWidget *widget,
g_object_unref (pixbuf);
}
- gtk_icon_info_free (icon_info);
+ g_object_unref (icon_info);
}
cairo_restore (cr);
diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c
index 246516fe6e..e7ef489f61 100644
--- a/gtk/gtkcombobox.c
+++ b/gtk/gtkcombobox.c
@@ -468,6 +468,8 @@ static void gtk_combo_box_get_preferred_height_for_width (GtkWidget *widg
gint *natural_size);
static GtkWidgetPath *gtk_combo_box_get_path_for_child (GtkContainer *container,
GtkWidget *child);
+static void gtk_combo_box_direction_changed (GtkWidget *widget,
+ GtkTextDirection previous_direction);
G_DEFINE_TYPE_WITH_CODE (GtkComboBox, gtk_combo_box, GTK_TYPE_BIN,
G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
@@ -508,6 +510,7 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass)
widget_class->get_preferred_height_for_width = gtk_combo_box_get_preferred_height_for_width;
widget_class->get_preferred_width_for_height = gtk_combo_box_get_preferred_width_for_height;
widget_class->destroy = gtk_combo_box_destroy;
+ widget_class->direction_changed = gtk_combo_box_direction_changed;
object_class = (GObjectClass *)klass;
object_class->constructor = gtk_combo_box_constructor;
@@ -1379,6 +1382,27 @@ gtk_combo_box_button_state_flags_changed (GtkWidget *widget,
gtk_widget_queue_draw (widget);
}
+static void
+gtk_combo_box_invalidate_order_foreach (GtkWidget *widget)
+{
+ _gtk_widget_invalidate_style_context (widget, GTK_CSS_CHANGE_POSITION | GTK_CSS_CHANGE_SIBLING_POSITION);
+}
+
+static void
+gtk_combo_box_invalidate_order (GtkComboBox *combo_box)
+{
+ gtk_container_forall (GTK_CONTAINER (combo_box),
+ (GtkCallback) gtk_combo_box_invalidate_order_foreach,
+ NULL);
+}
+
+static void
+gtk_combo_box_direction_changed (GtkWidget *widget,
+ GtkTextDirection previous_direction)
+{
+ gtk_combo_box_invalidate_order (GTK_COMBO_BOX (widget));
+}
+
static GtkWidgetPath *
gtk_combo_box_get_path_for_child (GtkContainer *container,
GtkWidget *child)
@@ -1407,6 +1431,9 @@ gtk_combo_box_get_path_for_child (GtkContainer *container,
if (widget && gtk_widget_get_visible (widget))
visible_children = g_list_prepend (visible_children, widget);
+ if (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL)
+ visible_children = g_list_reverse (visible_children);
+
pos = 0;
for (l = visible_children; l; l = l->next)
diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c
index 4377a5f683..ce16fe4df4 100644
--- a/gtk/gtkcontainer.c
+++ b/gtk/gtkcontainer.c
@@ -236,6 +236,9 @@ struct _GtkContainerPrivate
{
GtkWidget *focus_child;
+ guint resize_handler;
+ GdkFrameClock *resize_clock;
+
guint border_width : 16;
guint has_focus_chain : 1;
@@ -344,8 +347,6 @@ static const gchar vadjustment_key[] = "gtk-vadjustment";
static guint vadjustment_key_id = 0;
static const gchar hadjustment_key[] = "gtk-hadjustment";
static guint hadjustment_key_id = 0;
-static GSList *container_resize_queue = NULL;
-static GSList *container_restyle_queue = NULL;
static guint container_signals[LAST_SIGNAL] = { 0 };
static GtkWidgetClass *parent_class = NULL;
extern GParamSpecPool *_gtk_widget_child_property_pool;
@@ -1357,11 +1358,9 @@ gtk_container_destroy (GtkWidget *widget)
if (priv->resize_pending)
_gtk_container_dequeue_resize_handler (container);
+
if (priv->restyle_pending)
- {
- container_restyle_queue = g_slist_remove (container_restyle_queue, container);
- priv->restyle_pending = FALSE;
- }
+ priv->restyle_pending = FALSE;
if (priv->focus_child)
{
@@ -1553,7 +1552,6 @@ _gtk_container_dequeue_resize_handler (GtkContainer *container)
g_return_if_fail (GTK_IS_CONTAINER (container));
g_return_if_fail (container->priv->resize_pending);
- container_resize_queue = g_slist_remove (container_resize_queue, container);
container->priv->resize_pending = FALSE;
}
@@ -1630,12 +1628,10 @@ gtk_container_set_reallocate_redraws (GtkContainer *container,
container->priv->reallocate_redraws = needs_redraws ? TRUE : FALSE;
}
-static gboolean
-gtk_container_idle_sizer (gpointer data)
+static void
+gtk_container_idle_sizer (GdkFrameClock *clock,
+ GtkContainer *container)
{
- GSList *slist;
- gint64 current_time;
-
/* We validate the style contexts in a single loop before even trying
* to handle resizes instead of doing validations inline.
* This is mostly necessary for compatibility reasons with old code,
@@ -1646,16 +1642,13 @@ gtk_container_idle_sizer (gpointer data)
* sane values. So the result of an invalid style context will never be
* a program crash, but only a wrong layout or rendering.
*/
- current_time = g_get_monotonic_time ();
- slist = container_restyle_queue;
- container_restyle_queue = NULL;
- while (slist)
+ if (container->priv->restyle_pending)
{
- GSList *next = slist->next;
- GtkContainer *container = slist->data;
GtkBitmask *empty;
+ gint64 current_time;
empty = _gtk_bitmask_new ();
+ current_time = g_get_monotonic_time ();
container->priv->restyle_pending = FALSE;
_gtk_style_context_validate (gtk_widget_get_style_context (GTK_WIDGET (container)),
@@ -1663,8 +1656,6 @@ gtk_container_idle_sizer (gpointer data)
0,
empty);
- g_slist_free_1 (slist);
- slist = next;
_gtk_bitmask_free (empty);
}
@@ -1674,35 +1665,52 @@ gtk_container_idle_sizer (gpointer data)
* than trying to explicitely work around them with some extra flags,
* since it doesn't cause any actual harm.
*/
- while (container_resize_queue)
+ if (container->priv->resize_pending)
{
- GtkContainer *container;
-
- slist = container_resize_queue;
- container_resize_queue = slist->next;
- container = slist->data;
- g_slist_free_1 (slist);
-
container->priv->resize_pending = FALSE;
gtk_container_check_resize (container);
}
- gdk_window_process_all_updates ();
-
- return container_resize_queue != NULL || container_restyle_queue != NULL;
+ if (!container->priv->restyle_pending && !container->priv->resize_pending)
+ {
+ _gtk_container_stop_idle_sizer (container);
+ }
+ else
+ {
+ gdk_frame_clock_request_phase (clock,
+ GDK_FRAME_CLOCK_PHASE_LAYOUT);
+ }
}
static void
gtk_container_start_idle_sizer (GtkContainer *container)
{
- /* already started */
- if (container_resize_queue != NULL ||
- container_restyle_queue != NULL)
+ GdkFrameClock *clock;
+
+ if (container->priv->resize_handler != 0)
+ return;
+
+ clock = gtk_widget_get_frame_clock (GTK_WIDGET (container));
+ if (clock == NULL)
+ return;
+
+ container->priv->resize_clock = clock;
+ container->priv->resize_handler = g_signal_connect (clock, "layout",
+ G_CALLBACK (gtk_container_idle_sizer), container);
+ gdk_frame_clock_request_phase (clock,
+ GDK_FRAME_CLOCK_PHASE_LAYOUT);
+}
+
+void
+_gtk_container_stop_idle_sizer (GtkContainer *container)
+{
+ if (container->priv->resize_handler == 0)
return;
- gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE,
- gtk_container_idle_sizer,
- NULL, NULL);
+ g_signal_handler_disconnect (container->priv->resize_clock,
+ container->priv->resize_handler);
+ container->priv->resize_handler = 0;
+ container->priv->resize_clock = NULL;
}
static void
@@ -1725,7 +1733,6 @@ gtk_container_queue_resize_handler (GtkContainer *container)
{
container->priv->resize_pending = TRUE;
gtk_container_start_idle_sizer (container);
- container_resize_queue = g_slist_prepend (container_resize_queue, container);
}
break;
@@ -1780,8 +1787,6 @@ _gtk_container_queue_restyle (GtkContainer *container)
return;
gtk_container_start_idle_sizer (container);
-
- container_restyle_queue = g_slist_prepend (container_restyle_queue, container);
priv->restyle_pending = TRUE;
}
@@ -1816,6 +1821,13 @@ _gtk_container_resize_invalidate (GtkContainer *container)
}
void
+_gtk_container_maybe_start_idle_sizer (GtkContainer *container)
+{
+ if (container->priv->restyle_pending || container->priv->resize_pending)
+ gtk_container_start_idle_sizer (container);
+}
+
+void
gtk_container_check_resize (GtkContainer *container)
{
g_return_if_fail (GTK_IS_CONTAINER (container));
diff --git a/gtk/gtkcontainerprivate.h b/gtk/gtkcontainerprivate.h
index f12148bb4f..dd989d2dc7 100644
--- a/gtk/gtkcontainerprivate.h
+++ b/gtk/gtkcontainerprivate.h
@@ -39,6 +39,8 @@ GList * _gtk_container_focus_sort (GtkContainer *container,
GtkWidget *old_focus);
gboolean _gtk_container_get_reallocate_redraws (GtkContainer *container);
+void _gtk_container_stop_idle_sizer (GtkContainer *container);
+void _gtk_container_maybe_start_idle_sizer (GtkContainer *container);
G_END_DECLS
diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c
index d6a3804261..6e34ab5be2 100644
--- a/gtk/gtkentry.c
+++ b/gtk/gtkentry.c
@@ -3164,6 +3164,7 @@ gtk_entry_unrealize (GtkWidget *widget)
{
if (icon_info->window != NULL)
{
+ gtk_widget_unregister_window (widget, icon_info->window);
gdk_window_destroy (icon_info->window);
icon_info->window = NULL;
}
@@ -3743,36 +3744,40 @@ gtk_entry_draw (GtkWidget *widget,
GtkEntryPrivate *priv = entry->priv;
int i;
- context = gtk_widget_get_style_context (widget);
+ if (gtk_cairo_should_draw_window (cr,
+ gtk_widget_get_window (widget)))
+ {
+ context = gtk_widget_get_style_context (widget);
- /* Draw entry_bg, shadow, progress and focus */
- gtk_entry_draw_frame (widget, context, cr);
+ /* Draw entry_bg, shadow, progress and focus */
+ gtk_entry_draw_frame (widget, context, cr);
- /* Draw text and cursor */
- cairo_save (cr);
+ /* Draw text and cursor */
+ cairo_save (cr);
- gtk_cairo_transform_to_window (cr, widget, priv->text_area);
+ gtk_cairo_transform_to_window (cr, widget, priv->text_area);
- if (priv->dnd_position != -1)
- gtk_entry_draw_cursor (GTK_ENTRY (widget), cr, CURSOR_DND);
-
- gtk_entry_draw_text (GTK_ENTRY (widget), cr);
+ if (priv->dnd_position != -1)
+ gtk_entry_draw_cursor (GTK_ENTRY (widget), cr, CURSOR_DND);
- /* When no text is being displayed at all, don't show the cursor */
- if (gtk_entry_get_display_mode (entry) != DISPLAY_BLANK &&
- gtk_widget_has_focus (widget) &&
- priv->selection_bound == priv->current_pos && priv->cursor_visible)
- gtk_entry_draw_cursor (GTK_ENTRY (widget), cr, CURSOR_STANDARD);
+ gtk_entry_draw_text (GTK_ENTRY (widget), cr);
- cairo_restore (cr);
+ /* When no text is being displayed at all, don't show the cursor */
+ if (gtk_entry_get_display_mode (entry) != DISPLAY_BLANK &&
+ gtk_widget_has_focus (widget) &&
+ priv->selection_bound == priv->current_pos && priv->cursor_visible)
+ gtk_entry_draw_cursor (GTK_ENTRY (widget), cr, CURSOR_STANDARD);
- /* Draw icons */
- for (i = 0; i < MAX_ICONS; i++)
- {
- EntryIconInfo *icon_info = priv->icons[i];
+ cairo_restore (cr);
- if (icon_info != NULL)
- draw_icon (widget, cr, i);
+ /* Draw icons */
+ for (i = 0; i < MAX_ICONS; i++)
+ {
+ EntryIconInfo *icon_info = priv->icons[i];
+
+ if (icon_info != NULL)
+ draw_icon (widget, cr, i);
+ }
}
return FALSE;
diff --git a/gtk/gtkfilechooserbutton.c b/gtk/gtkfilechooserbutton.c
index d91ab62c08..c38bae69ef 100644
--- a/gtk/gtkfilechooserbutton.c
+++ b/gtk/gtkfilechooserbutton.c
@@ -655,8 +655,6 @@ gtk_file_chooser_button_select_file (GtkFileChooser *chooser,
priv->selection_while_inactive = g_object_ref (file);
- g_signal_emit (button, file_chooser_button_signals[FILE_SET], 0);
-
return TRUE;
}
}
@@ -683,8 +681,6 @@ gtk_file_chooser_button_unselect_file (GtkFileChooser *chooser,
g_object_unref (priv->selection_while_inactive);
priv->selection_while_inactive = NULL;
}
-
- g_signal_emit (button, file_chooser_button_signals[FILE_SET], 0);
}
}
}
@@ -708,8 +704,6 @@ gtk_file_chooser_button_unselect_all (GtkFileChooser *chooser)
g_object_unref (priv->selection_while_inactive);
priv->selection_while_inactive = NULL;
}
-
- g_signal_emit (button, file_chooser_button_signals[FILE_SET], 0);
}
}
@@ -2357,13 +2351,13 @@ static void
update_combo_box (GtkFileChooserButton *button)
{
GtkFileChooserButtonPrivate *priv = button->priv;
- GSList *files;
+ GFile *file;
GtkTreeIter iter;
gboolean row_found;
gtk_tree_model_get_iter_first (priv->filter_model, &iter);
- files = gtk_file_chooser_get_files (GTK_FILE_CHOOSER (priv->dialog));
+ file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (priv->dialog));
row_found = FALSE;
@@ -2386,9 +2380,7 @@ update_combo_box (GtkFileChooserButton *button)
case ROW_TYPE_SHORTCUT:
case ROW_TYPE_BOOKMARK:
case ROW_TYPE_CURRENT_FOLDER:
- row_found = (files &&
- files->data &&
- g_file_equal (data, files->data));
+ row_found = (file && g_file_equal (data, file));
break;
case ROW_TYPE_VOLUME:
{
@@ -2397,9 +2389,7 @@ update_combo_box (GtkFileChooserButton *button)
base_file = _gtk_file_system_volume_get_root (data);
if (base_file)
{
- row_found = (files &&
- files->data &&
- g_file_equal (base_file, files->data));
+ row_found = (file && g_file_equal (base_file, file));
g_object_unref (base_file);
}
}
@@ -2421,12 +2411,12 @@ update_combo_box (GtkFileChooserButton *button)
while (!row_found && gtk_tree_model_iter_next (priv->filter_model, &iter));
/* If it hasn't been found already, update & select the current-folder row. */
- if (!row_found && files && files->data)
+ if (!row_found && file)
{
GtkTreeIter filter_iter;
gint pos;
- model_update_current_folder (button, files->data);
+ model_update_current_folder (button, file);
gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter_model));
pos = model_get_type_position (button, ROW_TYPE_CURRENT_FOLDER);
@@ -2440,8 +2430,8 @@ update_combo_box (GtkFileChooserButton *button)
g_signal_handler_unblock (priv->combo_box, priv->combo_box_changed_id);
}
- g_slist_foreach (files, (GFunc) g_object_unref, NULL);
- g_slist_free (files);
+ if (file)
+ g_object_unref (file);
}
/* Button */
@@ -2487,9 +2477,9 @@ update_label_and_image (GtkFileChooserButton *button)
{
GtkFileChooserButtonPrivate *priv = button->priv;
gchar *label_text;
- GSList *files;
+ GFile *file;
- files = gtk_file_chooser_get_files (GTK_FILE_CHOOSER (priv->dialog));
+ file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (priv->dialog));
label_text = NULL;
if (priv->update_button_cancellable)
@@ -2498,13 +2488,10 @@ update_label_and_image (GtkFileChooserButton *button)
priv->update_button_cancellable = NULL;
}
- if (files && files->data)
+ if (file)
{
- GFile *file;
GtkFileSystemVolume *volume = NULL;
- file = files->data;
-
volume = _gtk_file_system_get_volume_for_file (priv->fs, file);
if (volume)
{
@@ -2554,10 +2541,10 @@ update_label_and_image (GtkFileChooserButton *button)
if (pixbuf)
g_object_unref (pixbuf);
}
+
+ g_object_unref (file);
}
out:
- g_slist_foreach (files, (GFunc) g_object_unref, NULL);
- g_slist_free (files);
if (label_text)
{
diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c
index d97bf1a738..996c7fc01e 100644
--- a/gtk/gtkfilechooserdefault.c
+++ b/gtk/gtkfilechooserdefault.c
@@ -340,7 +340,7 @@ static void path_bar_clicked (GtkPathBar *path_bar,
static void update_cell_renderer_attributes (GtkFileChooserDefault *impl);
-static void load_remove_timer (GtkFileChooserDefault *impl);
+static void load_remove_timer (GtkFileChooserDefault *impl, LoadState new_load_state);
static void browse_files_center_selected_row (GtkFileChooserDefault *impl);
static void location_button_toggled_cb (GtkToggleButton *toggle,
@@ -4001,9 +4001,9 @@ load_setup_timer (GtkFileChooserDefault *impl)
impl->load_state = LOAD_PRELOAD;
}
-/* Removes the load timeout and switches to the LOAD_FINISHED state */
+/* Removes the load timeout; changes the impl->load_state to the specified value. */
static void
-load_remove_timer (GtkFileChooserDefault *impl)
+load_remove_timer (GtkFileChooserDefault *impl, LoadState new_load_state)
{
if (impl->load_timeout_id != 0)
{
@@ -4011,12 +4011,16 @@ load_remove_timer (GtkFileChooserDefault *impl)
g_source_remove (impl->load_timeout_id);
impl->load_timeout_id = 0;
- impl->load_state = LOAD_EMPTY;
}
else
g_assert (impl->load_state == LOAD_EMPTY ||
impl->load_state == LOAD_LOADING ||
impl->load_state == LOAD_FINISHED);
+
+ g_assert (new_load_state == LOAD_EMPTY ||
+ new_load_state == LOAD_LOADING ||
+ new_load_state == LOAD_FINISHED);
+ impl->load_state = new_load_state;
}
/* Selects the first row in the file list */
@@ -4089,9 +4093,14 @@ show_and_select_files (GtkFileChooserDefault *impl,
gboolean selected_a_file;
GSList *walk;
+ g_assert (impl->load_state == LOAD_FINISHED);
+ g_assert (impl->browse_files_model != NULL);
+
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
fsmodel = GTK_FILE_SYSTEM_MODEL (gtk_tree_view_get_model (GTK_TREE_VIEW (impl->browse_files_tree_view)));
+ g_assert (fsmodel == impl->browse_files_model);
+
enabled_hidden = impl->show_hidden;
removed_filters = (impl->current_filter == NULL);
@@ -4226,7 +4235,7 @@ browse_files_model_finished_loading_cb (GtkFileSystemModel *model,
if (impl->load_state == LOAD_PRELOAD)
{
- load_remove_timer (impl);
+ load_remove_timer (impl, LOAD_FINISHED);
load_set_model (impl);
}
else if (impl->load_state == LOAD_LOADING)
@@ -4259,7 +4268,7 @@ static void
stop_loading_and_clear_list_model (GtkFileChooserDefault *impl,
gboolean remove_from_treeview)
{
- load_remove_timer (impl); /* This changes the state to LOAD_EMPTY */
+ load_remove_timer (impl, LOAD_EMPTY);
if (impl->browse_files_model)
{
diff --git a/gtk/gtkfilesystem.c b/gtk/gtkfilesystem.c
index 8679bd232d..df2e1d62db 100644
--- a/gtk/gtkfilesystem.c
+++ b/gtk/gtkfilesystem.c
@@ -732,7 +732,7 @@ get_pixbuf_from_gicon (GIcon *icon,
return NULL;
pixbuf = gtk_icon_info_load_icon (icon_info, error);
- gtk_icon_info_free (icon_info);
+ g_object_unref (icon_info);
return pixbuf;
}
diff --git a/gtk/gtkiconfactory.c b/gtk/gtkiconfactory.c
index a3bfea78b7..b40267335b 100644
--- a/gtk/gtkiconfactory.c
+++ b/gtk/gtkiconfactory.c
@@ -1569,7 +1569,7 @@ render_icon_name_pixbuf (GtkIconSource *icon_source,
if (info)
{
tmp_pixbuf = gtk_icon_info_load_icon (info, &error);
- gtk_icon_info_free (info);
+ g_object_unref (info);
}
else
tmp_pixbuf = NULL;
diff --git a/gtk/gtkiconhelper.c b/gtk/gtkiconhelper.c
index 37ba5811c8..58ae8a15db 100644
--- a/gtk/gtkiconhelper.c
+++ b/gtk/gtkiconhelper.c
@@ -263,7 +263,7 @@ ensure_pixbuf_for_icon_name_or_gicon (GtkIconHelper *self,
self->priv->rendered_pixbuf = ensure_stated_icon_from_info (self, context, info);
if (info)
- gtk_icon_info_free (info);
+ g_object_unref (info);
}
static void
diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c
index 0520686206..73d8ba7d0f 100644
--- a/gtk/gtkicontheme.c
+++ b/gtk/gtkicontheme.c
@@ -225,8 +225,15 @@ struct _SymbolicPixbufCache {
SymbolicPixbufCache *next;
};
+struct _GtkIconInfoClass
+{
+ GObjectClass parent_class;
+};
+
struct _GtkIconInfo
{
+ GObject parent_instance;
+
/* Information about the source
*/
IconInfoKey key;
@@ -256,8 +263,6 @@ struct _GtkIconInfo
guint forced_size : 1;
guint emblems_applied : 1;
- guint ref_count;
-
/* Cached information if we go ahead and try to load
* the icon.
*/
@@ -345,6 +350,7 @@ static void do_theme_change (GtkIconTheme *icon_theme);
static void blow_themes (GtkIconTheme *icon_themes);
static gboolean rescan_themes (GtkIconTheme *icon_themes);
+static GtkIconData *icon_data_dup (GtkIconData *icon_data);
static void icon_data_free (GtkIconData *icon_data);
static void load_icon_data (IconThemeDir *dir,
const char *path,
@@ -1438,7 +1444,7 @@ ensure_lru_cache_space (GtkIconTheme *icon_theme)
g_list_length (priv->info_cache_lru)));
priv->info_cache_lru = g_list_delete_link (priv->info_cache_lru, l);
- gtk_icon_info_free (icon_info);
+ g_object_unref (icon_info);
}
}
@@ -1459,7 +1465,7 @@ add_to_lru_cache (GtkIconTheme *icon_theme,
ensure_lru_cache_space (icon_theme);
/* prepend new info to LRU */
priv->info_cache_lru = g_list_prepend (priv->info_cache_lru,
- gtk_icon_info_copy (icon_info));
+ g_object_ref (icon_info));
}
static void
@@ -1494,7 +1500,7 @@ remove_from_lru_cache (GtkIconTheme *icon_theme,
g_list_length (priv->info_cache_lru)));
priv->info_cache_lru = g_list_remove (priv->info_cache_lru, icon_info);
- gtk_icon_info_free (icon_info);
+ g_object_unref (icon_info);
}
}
@@ -1608,7 +1614,7 @@ choose_icon (GtkIconTheme *icon_theme,
icon_info->key.size, icon_info->key.flags,
g_hash_table_size (priv->info_cache)));
- icon_info = gtk_icon_info_copy (icon_info);
+ icon_info = g_object_ref (icon_info);
remove_from_lru_cache (icon_theme, icon_info);
return icon_info;
@@ -1772,9 +1778,8 @@ choose_icon (GtkIconTheme *icon_theme,
* gtk_icon_info_load_icon(). (gtk_icon_theme_load_icon()
* combines these two steps if all you need is the pixbuf.)
*
- * Return value: a #GtkIconInfo structure containing information
- * about the icon, or %NULL if the icon wasn't found. Free with
- * gtk_icon_info_free()
+ * Return value: (transfer full): a #GtkIconInfo object containing information
+ * about the icon, or %NULL if the icon wasn't found.
*
* Since: 2.4
*/
@@ -1850,9 +1855,8 @@ gtk_icon_theme_lookup_icon (GtkIconTheme *icon_theme,
* tries them all in the given order before falling back to
* inherited icon themes.
*
- * Return value: a #GtkIconInfo structure containing information
- * about the icon, or %NULL if the icon wasn't found. Free with
- * gtk_icon_info_free()
+ * Return value: (transfer full): a #GtkIconInfo object containing information
+ * about the icon, or %NULL if the icon wasn't found.
*
* Since: 2.12
*/
@@ -1933,7 +1937,7 @@ gtk_icon_theme_load_icon (GtkIconTheme *icon_theme,
}
pixbuf = gtk_icon_info_load_icon (icon_info, error);
- gtk_icon_info_free (icon_info);
+ g_object_unref (icon_info);
return pixbuf;
}
@@ -2967,23 +2971,83 @@ icon_data_free (GtkIconData *icon_data)
g_slice_free (GtkIconData, icon_data);
}
+static GtkIconData *
+icon_data_dup (GtkIconData *icon_data)
+{
+ GtkIconData *dup = NULL;
+ if (icon_data)
+ {
+ dup = g_slice_new0 (GtkIconData);
+ *dup = *icon_data;
+ if (dup->n_attach_points > 0)
+ {
+ dup->attach_points = g_memdup (dup->attach_points,
+ sizeof (GdkPoint) * dup->n_attach_points);
+ }
+ dup->display_name = g_strdup (dup->display_name);
+ }
+
+ return dup;
+}
+
+
/*
* GtkIconInfo
*/
-G_DEFINE_BOXED_TYPE (GtkIconInfo, gtk_icon_info,
- gtk_icon_info_copy,
- gtk_icon_info_free)
+static void gtk_icon_info_class_init (GtkIconInfoClass *klass);
+
+G_DEFINE_TYPE (GtkIconInfo, gtk_icon_info, G_TYPE_OBJECT)
+
+static void
+gtk_icon_info_init (GtkIconInfo *icon_info)
+{
+ icon_info->scale = -1.;
+}
static GtkIconInfo *
icon_info_new (void)
{
- GtkIconInfo *icon_info = g_slice_new0 (GtkIconInfo);
+ return g_object_new (GTK_TYPE_ICON_INFO, NULL);
+}
- icon_info->scale = -1.;
- icon_info->ref_count = 1;
+/* This only copies whatever is needed to load the pixbuf, so that we can do
+ * a load in a thread without affecting the original IconInfo from the thread.
+ */
+static GtkIconInfo *
+icon_info_dup (GtkIconInfo *icon_info)
+{
+ GtkIconInfo *dup;
+ GSList *l;
- return icon_info;
+ dup = icon_info_new ();
+
+ dup->filename = g_strdup (icon_info->filename);
+ if (icon_info->icon_file)
+ dup->icon_file = g_object_ref (icon_info->icon_file);
+ if (icon_info->loadable)
+ dup->loadable = g_object_ref (icon_info->loadable);
+
+ for (l = icon_info->emblem_infos; l != NULL; l = l->next)
+ {
+ dup->emblem_infos =
+ g_slist_append (dup->emblem_infos,
+ icon_info_dup (l->data));
+ }
+
+ if (icon_info->cache_pixbuf)
+ dup->cache_pixbuf = g_object_ref (icon_info->cache_pixbuf);
+
+ dup->data = icon_data_dup (icon_info->data);
+ dup->dir_type = icon_info->dir_type;
+ dup->dir_size = icon_info->dir_size;
+ dup->threshold = icon_info->threshold;
+ dup->desired_size = icon_info->desired_size;
+ dup->raw_coordinates = icon_info->raw_coordinates;
+ dup->forced_size = icon_info->forced_size;
+ dup->emblems_applied = icon_info->emblems_applied;
+
+ return dup;
}
static GtkIconInfo *
@@ -3000,7 +3064,7 @@ icon_info_new_builtin (BuiltinIcon *icon)
}
/**
- * gtk_icon_info_copy:
+ * gtk_icon_info_copy: (skip)
* @icon_info: a #GtkIconInfo
*
* Make a copy of a #GtkIconInfo.
@@ -3008,6 +3072,8 @@ icon_info_new_builtin (BuiltinIcon *icon)
* Return value: the new GtkIconInfo
*
* Since: 2.4
+ *
+ * Deprecated: 3.8: Use g_object_ref()
**/
GtkIconInfo *
gtk_icon_info_copy (GtkIconInfo *icon_info)
@@ -3015,27 +3081,31 @@ gtk_icon_info_copy (GtkIconInfo *icon_info)
g_return_val_if_fail (icon_info != NULL, NULL);
- icon_info->ref_count++;
-
- return icon_info;
+ return g_object_ref (icon_info);
}
/**
- * gtk_icon_info_free:
+ * gtk_icon_info_free: (skip)
* @icon_info: a #GtkIconInfo
*
* Free a #GtkIconInfo and associated information
*
* Since: 2.4
+ *
+ * Deprecated: 3.8: Use g_object_unref()
**/
void
gtk_icon_info_free (GtkIconInfo *icon_info)
{
g_return_if_fail (icon_info != NULL);
- icon_info->ref_count--;
- if (icon_info->ref_count > 0)
- return;
+ g_object_unref (icon_info);
+}
+
+static void
+gtk_icon_info_finalize (GObject *object)
+{
+ GtkIconInfo *icon_info = (GtkIconInfo *) object;
if (icon_info->in_cache)
g_hash_table_remove (icon_info->in_cache->priv->info_cache, &icon_info->key);
@@ -3047,7 +3117,7 @@ gtk_icon_info_free (GtkIconInfo *icon_info)
if (icon_info->loadable)
g_object_unref (icon_info->loadable);
- g_slist_free_full (icon_info->emblem_infos, (GDestroyNotify) gtk_icon_info_free);
+ g_slist_free_full (icon_info->emblem_infos, (GDestroyNotify) g_object_unref);
if (icon_info->pixbuf)
g_object_unref (icon_info->pixbuf);
if (icon_info->cache_pixbuf)
@@ -3057,7 +3127,15 @@ gtk_icon_info_free (GtkIconInfo *icon_info)
symbolic_pixbuf_cache_free (icon_info->symbolic_pixbuf_cache);
- g_slice_free (GtkIconInfo, icon_info);
+ G_OBJECT_CLASS (gtk_icon_info_parent_class)->finalize (object);
+}
+
+static void
+gtk_icon_info_class_init (GtkIconInfoClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = gtk_icon_info_finalize;
}
/**
@@ -3222,6 +3300,21 @@ apply_emblems (GtkIconInfo *info)
info->emblems_applied = TRUE;
}
+/* If this returns TRUE, its safe to call
+ icon_info_ensure_scale_and_pixbuf without blocking */
+static gboolean
+icon_info_get_pixbuf_ready (GtkIconInfo *icon_info)
+{
+ if (icon_info->pixbuf &&
+ (icon_info->emblem_infos == NULL || icon_info->emblems_applied))
+ return TRUE;
+
+ if (icon_info->load_error)
+ return TRUE;
+
+ return FALSE;
+}
+
/* This function contains the complicated logic for deciding
* on the size at which to load the icon and loading it at
* that size.
@@ -3416,7 +3509,7 @@ proxy_pixbuf_destroy (guchar *pixels, gpointer data)
if (icon_theme != NULL)
ensure_in_lru_cache (icon_theme, icon_info);
- gtk_icon_info_free (icon_info);
+ g_object_unref (icon_info);
}
/**
@@ -3483,11 +3576,124 @@ gtk_icon_info_load_icon (GtkIconInfo *icon_info,
gdk_pixbuf_get_height (icon_info->pixbuf),
gdk_pixbuf_get_rowstride (icon_info->pixbuf),
proxy_pixbuf_destroy,
- gtk_icon_info_copy (icon_info));
+ g_object_ref (icon_info));
return icon_info->proxy_pixbuf;
}
+static void
+load_icon_thread (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ GtkIconInfo *dup = task_data;
+
+ icon_info_ensure_scale_and_pixbuf (dup, FALSE);
+ g_task_return_pointer (task, NULL, NULL);
+}
+
+/**
+ * gtk_icon_info_load_icon_async:
+ * @icon_info: a #GtkIconInfo structure from gtk_icon_theme_lookup_icon()
+ * @cancellable: (allow-none): optional #GCancellable object,
+ * %NULL to ignore
+ * @callback: (scope async): a #GAsyncReadyCallback to call when the
+ * request is satisfied
+ * @user_data: (closure): the data to pass to callback function
+ *
+ * Asynchronously load, render and scale an icon previously looked up
+ * from the icon theme using gtk_icon_theme_lookup_icon().
+ *
+ * For more details, see gtk_icon_info_load_icon() which is the synchronous
+ * version of this call.
+ *
+ * Since: 3.8
+ **/
+void
+gtk_icon_info_load_icon_async (GtkIconInfo *icon_info,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ GdkPixbuf *pixbuf;
+ GtkIconInfo *dup;
+ GError *error = NULL;
+
+ task = g_task_new (icon_info, cancellable, callback, user_data);
+
+ if (icon_info_get_pixbuf_ready (icon_info))
+ {
+ pixbuf = gtk_icon_info_load_icon (icon_info, &error);
+ if (pixbuf == NULL)
+ g_task_return_error (task, error);
+ else
+ g_task_return_pointer (task, pixbuf, g_object_unref);
+ g_object_unref (task);
+ }
+ else
+ {
+ dup = icon_info_dup (icon_info);
+ g_task_set_task_data (task, dup, g_object_unref);
+ g_task_run_in_thread (task, load_icon_thread);
+ g_object_unref (task);
+ }
+}
+
+/**
+ * gtk_icon_info_load_icon_finish:
+ * @icon_info: a #GtkIconInfo structure from gtk_icon_theme_lookup_icon()
+ * @res: a #GAsyncResult
+ * @error: (allow-none): location to store error information on failure,
+ * or %NULL.
+ *
+ * Finishes an async icon load, see gtk_icon_info_load_icon_async().
+ *
+ * Return value: (transfer full): the rendered icon; this may be a newly
+ * created icon or a new reference to an internal icon, so you must
+ * not modify the icon. Use g_object_unref() to release your reference
+ * to the icon.
+ *
+ * Since: 3.8
+ **/
+GdkPixbuf *
+gtk_icon_info_load_icon_finish (GtkIconInfo *icon_info,
+ GAsyncResult *result,
+ GError **error)
+{
+ GTask *task = G_TASK (result);
+ GtkIconInfo *dup;
+
+ g_return_val_if_fail (g_task_is_valid (result, icon_info), NULL);
+
+ dup = g_task_get_task_data (task);
+ if (dup == NULL || g_task_had_error (task))
+ return g_task_propagate_pointer (task, error);
+
+ /* We ran the thread and it was not cancelled */
+
+ /* Check if someone else updated the icon_info in between */
+ if (!icon_info_get_pixbuf_ready (icon_info))
+ {
+ /* If not, copy results from dup back to icon_info */
+
+ icon_info->emblems_applied = dup->emblems_applied;
+ icon_info->scale = dup->scale;
+ g_clear_object (&icon_info->pixbuf);
+ if (dup->pixbuf)
+ icon_info->pixbuf = g_object_ref (dup->pixbuf);
+ g_clear_error (&icon_info->load_error);
+ if (dup->load_error)
+ icon_info->load_error = g_error_copy (dup->load_error);
+ }
+
+ g_assert (icon_info_get_pixbuf_ready (icon_info));
+
+ /* This is now guaranteed to not block */
+ return gtk_icon_info_load_icon (icon_info, error);
+}
+
static gchar *
gdk_color_to_css (GdkColor *color)
{
@@ -3532,7 +3738,7 @@ proxy_symbolic_pixbuf_destroy (guchar *pixels, gpointer data)
if (icon_theme != NULL)
ensure_in_lru_cache (icon_theme, icon_info);
- gtk_icon_info_free (icon_info);
+ g_object_unref (icon_info);
}
static GdkPixbuf *
@@ -3551,7 +3757,7 @@ symbolic_cache_get_proxy (SymbolicPixbufCache *symbolic_cache,
gdk_pixbuf_get_height (symbolic_cache->pixbuf),
gdk_pixbuf_get_rowstride (symbolic_cache->pixbuf),
proxy_symbolic_pixbuf_destroy,
- gtk_icon_info_copy (icon_info));
+ g_object_ref (icon_info));
return symbolic_cache->proxy_pixbuf;
}
@@ -3562,7 +3768,8 @@ _gtk_icon_info_load_symbolic_internal (GtkIconInfo *icon_info,
const GdkRGBA *success_color,
const GdkRGBA *warning_color,
const GdkRGBA *error_color,
- GError **error)
+ gboolean use_cache,
+ GError **error)
{
GInputStream *stream;
GdkPixbuf *pixbuf;
@@ -3574,10 +3781,13 @@ _gtk_icon_info_load_symbolic_internal (GtkIconInfo *icon_info,
gchar *width, *height, *uri;
SymbolicPixbufCache *symbolic_cache;
- symbolic_cache = symbolic_pixbuf_cache_matches (icon_info->symbolic_pixbuf_cache,
- fg, success_color, warning_color, error_color);
- if (symbolic_cache)
- return symbolic_cache_get_proxy (symbolic_cache, icon_info);
+ if (use_cache)
+ {
+ symbolic_cache = symbolic_pixbuf_cache_matches (icon_info->symbolic_pixbuf_cache,
+ fg, success_color, warning_color, error_color);
+ if (symbolic_cache)
+ return symbolic_cache_get_proxy (symbolic_cache, icon_info);
+ }
/* css_fg can't possibly have failed, otherwise
* that would mean we have a broken style */
@@ -3678,11 +3888,16 @@ _gtk_icon_info_load_symbolic_internal (GtkIconInfo *icon_info,
if (pixbuf != NULL)
{
- icon_info->symbolic_pixbuf_cache =
- symbolic_pixbuf_cache_new (pixbuf, fg, success_color, warning_color, error_color,
- icon_info->symbolic_pixbuf_cache);
-
- return symbolic_cache_get_proxy (icon_info->symbolic_pixbuf_cache, icon_info);
+ if (use_cache)
+ {
+ icon_info->symbolic_pixbuf_cache =
+ symbolic_pixbuf_cache_new (pixbuf, fg, success_color, warning_color, error_color,
+ icon_info->symbolic_pixbuf_cache);
+ g_object_unref (pixbuf);
+ return symbolic_cache_get_proxy (icon_info->symbolic_pixbuf_cache, icon_info);
+ }
+ else
+ return pixbuf;
}
return NULL;
@@ -3756,6 +3971,7 @@ gtk_icon_info_load_symbolic (GtkIconInfo *icon_info,
return _gtk_icon_info_load_symbolic_internal (icon_info,
fg, success_color,
warning_color, error_color,
+ TRUE,
error);
}
@@ -3842,9 +4058,332 @@ gtk_icon_info_load_symbolic_for_context (GtkIconInfo *icon_info,
return _gtk_icon_info_load_symbolic_internal (icon_info,
fgp, success_colorp,
warning_colorp, error_colorp,
+ TRUE,
error);
}
+typedef struct {
+ gboolean is_symbolic;
+ GtkIconInfo *dup;
+ GdkRGBA fg;
+ gboolean fg_set;
+ GdkRGBA success_color;
+ gboolean success_color_set;
+ GdkRGBA warning_color;
+ gboolean warning_color_set;
+ GdkRGBA error_color;
+ gboolean error_color_set;
+} AsyncSymbolicData;
+
+static void
+async_symbolic_data_free (AsyncSymbolicData *data)
+{
+ if (data->dup)
+ g_object_unref (data->dup);
+ g_slice_free (AsyncSymbolicData, data);
+}
+
+static void
+async_load_no_symbolic_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GtkIconInfo *icon_info = GTK_ICON_INFO (source_object);
+ GTask *task = user_data;
+ GError *error = NULL;
+ GdkPixbuf *pixbuf;
+
+ pixbuf = gtk_icon_info_load_icon_finish (icon_info, res, &error);
+ if (pixbuf == NULL)
+ g_task_return_error (task, error);
+ else
+ g_task_return_pointer (task, pixbuf, g_object_unref);
+ g_object_unref (task);
+}
+
+static void
+load_symbolic_icon_thread (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ AsyncSymbolicData *data = task_data;
+ GError *error;
+ GdkPixbuf *pixbuf;
+
+ error = NULL;
+ pixbuf =
+ _gtk_icon_info_load_symbolic_internal (data->dup,
+ data->fg_set ? &data->fg : NULL,
+ data->success_color_set ? &data->success_color : NULL,
+ data->warning_color_set ? &data->warning_color : NULL,
+ data->error_color_set ? &data->error_color : NULL,
+ FALSE,
+ &error);
+ if (pixbuf == NULL)
+ g_task_return_error (task, error);
+ else
+ g_task_return_pointer (task, pixbuf, g_object_unref);
+}
+
+/**
+ * gtk_icon_info_load_symbolic_async:
+ * @icon_info: a #GtkIconInfo structure from gtk_icon_theme_lookup_icon()
+ * @fg: a #GdkRGBA representing the foreground color of the icon
+ * @success_color: (allow-none): a #GdkRGBA representing the warning color
+ * of the icon or %NULL to use the default color
+ * @warning_color: (allow-none): a #GdkRGBA representing the warning color
+ * of the icon or %NULL to use the default color
+ * @error_color: (allow-none): a #GdkRGBA representing the error color
+ * of the icon or %NULL to use the default color (allow-none)
+ * @cancellable: (allow-none): optional #GCancellable object,
+ * %NULL to ignore
+ * @callback: (scope async): a #GAsyncReadyCallback to call when the
+ * request is satisfied
+ * @user_data: (closure): the data to pass to callback function
+ *
+ * Asynchronously load, render and scale a symbolic icon previously looked up
+ * from the icon theme using gtk_icon_theme_lookup_icon().
+ *
+ * For more details, see gtk_icon_info_load_symbolic() which is the synchronous
+ * version of this call.
+ *
+ * Since: 3.8
+ **/
+void
+gtk_icon_info_load_symbolic_async (GtkIconInfo *icon_info,
+ const GdkRGBA *fg,
+ const GdkRGBA *success_color,
+ const GdkRGBA *warning_color,
+ const GdkRGBA *error_color,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ AsyncSymbolicData *data;
+ gchar *icon_uri;
+ SymbolicPixbufCache *symbolic_cache;
+ GdkPixbuf *pixbuf;
+
+ g_return_if_fail (icon_info != NULL);
+ g_return_if_fail (fg != NULL);
+
+ task = g_task_new (icon_info, cancellable, callback, user_data);
+
+ data = g_slice_new0 (AsyncSymbolicData);
+ g_task_set_task_data (task, data, (GDestroyNotify) async_symbolic_data_free);
+
+ icon_uri = NULL;
+ if (icon_info->icon_file)
+ icon_uri = g_file_get_uri (icon_info->icon_file);
+
+ data->is_symbolic = (icon_uri != NULL) && (g_str_has_suffix (icon_uri, "-symbolic.svg"));
+ g_free (icon_uri);
+
+ if (!data->is_symbolic)
+ {
+ gtk_icon_info_load_icon_async (icon_info, cancellable, async_load_no_symbolic_cb, g_object_ref (task));
+ }
+ else
+ {
+ symbolic_cache = symbolic_pixbuf_cache_matches (icon_info->symbolic_pixbuf_cache,
+ fg, success_color, warning_color, error_color);
+ if (symbolic_cache)
+ {
+ pixbuf = symbolic_cache_get_proxy (symbolic_cache, icon_info);
+ g_task_return_pointer (task, pixbuf, g_object_unref);
+ }
+ else
+ {
+ if (fg)
+ {
+ data->fg = *fg;
+ data->fg_set = TRUE;
+ }
+
+ if (success_color)
+ {
+ data->success_color = *success_color;
+ data->success_color_set = TRUE;
+ }
+
+ if (warning_color)
+ {
+ data->warning_color = *warning_color;
+ data->warning_color_set = TRUE;
+ }
+
+ if (error_color)
+ {
+ data->error_color = *error_color;
+ data->error_color_set = TRUE;
+ }
+
+ data->dup = icon_info_dup (icon_info);
+ g_task_run_in_thread (task, load_symbolic_icon_thread);
+ }
+ }
+ g_object_unref (task);
+}
+
+/**
+ * gtk_icon_info_load_symbolic_finish:
+ * @icon_info: a #GtkIconInfo structure from gtk_icon_theme_lookup_icon()
+ * @res: a #GAsyncResult
+ * @was_symbolic: (out) (allow-none): a #gboolean, returns whether the
+ * loaded icon was a symbolic one and whether the @fg color was
+ * applied to it.
+ * @error: (allow-none): location to store error information on failure,
+ * or %NULL.
+ *
+ * Finishes an async icon load, see gtk_icon_info_load_symbolic_async().
+ *
+ * Return value: (transfer full): the rendered icon; this may be a newly
+ * created icon or a new reference to an internal icon, so you must
+ * not modify the icon. Use g_object_unref() to release your reference
+ * to the icon.
+ *
+ * Since: 3.8
+ **/
+GdkPixbuf *
+gtk_icon_info_load_symbolic_finish (GtkIconInfo *icon_info,
+ GAsyncResult *result,
+ gboolean *was_symbolic,
+ GError **error)
+{
+ GTask *task = G_TASK (result);
+ AsyncSymbolicData *data = g_task_get_task_data (task);
+ SymbolicPixbufCache *symbolic_cache;
+ GdkPixbuf *pixbuf;
+
+ if (was_symbolic)
+ *was_symbolic = data->is_symbolic;
+
+ if (data->dup && !g_task_had_error (task))
+ {
+ pixbuf = g_task_propagate_pointer (task, NULL);
+
+ g_assert (pixbuf != NULL); /* we checked for !had_error above */
+
+ symbolic_cache = symbolic_pixbuf_cache_matches (icon_info->symbolic_pixbuf_cache,
+ data->fg_set ? &data->fg : NULL,
+ data->success_color_set ? &data->success_color : NULL,
+ data->warning_color_set ? &data->warning_color : NULL,
+ data->error_color_set ? &data->error_color : NULL);
+
+ if (symbolic_cache == NULL)
+ {
+ symbolic_cache = icon_info->symbolic_pixbuf_cache =
+ symbolic_pixbuf_cache_new (pixbuf,
+ data->fg_set ? &data->fg : NULL,
+ data->success_color_set ? &data->success_color : NULL,
+ data->warning_color_set ? &data->warning_color : NULL,
+ data->error_color_set ? &data->error_color : NULL,
+ icon_info->symbolic_pixbuf_cache);
+ }
+
+ g_object_unref (pixbuf);
+
+ return symbolic_cache_get_proxy (symbolic_cache, icon_info);
+ }
+
+ return g_task_propagate_pointer (task, error);
+}
+
+/**
+ * gtk_icon_info_load_symbolic_for_context_async:
+ * @icon_info: a #GtkIconInfo structure from gtk_icon_theme_lookup_icon()
+ * @context: a #GtkStyleContext
+ * @cancellable: (allow-none): optional #GCancellable object,
+ * %NULL to ignore
+ * @callback: (scope async): a #GAsyncReadyCallback to call when the
+ * request is satisfied
+ * @user_data: (closure): the data to pass to callback function
+ *
+ * Asynchronously load, render and scale a symbolic icon previously looked up
+ * from the icon theme using gtk_icon_theme_lookup_icon().
+ *
+ * For more details, see gtk_icon_info_load_symbolic_for_context() which is the synchronous
+ * version of this call.
+ *
+ * Since: 3.8
+ **/
+void
+gtk_icon_info_load_symbolic_for_context_async (GtkIconInfo *icon_info,
+ GtkStyleContext *context,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GdkRGBA *color = NULL;
+ GdkRGBA fg;
+ GdkRGBA *fgp;
+ GdkRGBA success_color;
+ GdkRGBA *success_colorp;
+ GdkRGBA warning_color;
+ GdkRGBA *warning_colorp;
+ GdkRGBA error_color;
+ GdkRGBA *error_colorp;
+ GtkStateFlags state;
+
+ g_return_if_fail (icon_info != NULL);
+ g_return_if_fail (context != NULL);
+
+ fgp = success_colorp = warning_colorp = error_colorp = NULL;
+
+ state = gtk_style_context_get_state (context);
+ gtk_style_context_get (context, state, "color", &color, NULL);
+ if (color)
+ {
+ fg = *color;
+ fgp = &fg;
+ gdk_rgba_free (color);
+ }
+
+ if (gtk_style_context_lookup_color (context, "success_color", &success_color))
+ success_colorp = &success_color;
+
+ if (gtk_style_context_lookup_color (context, "warning_color", &warning_color))
+ warning_colorp = &warning_color;
+
+ if (gtk_style_context_lookup_color (context, "error_color", &error_color))
+ error_colorp = &error_color;
+
+ gtk_icon_info_load_symbolic_async (icon_info,
+ fgp, success_colorp,
+ warning_colorp, error_colorp,
+ cancellable, callback, user_data);
+}
+
+/**
+ * gtk_icon_info_load_symbolic_for_context_finish:
+ * @icon_info: a #GtkIconInfo structure from gtk_icon_theme_lookup_icon()
+ * @res: a #GAsyncResult
+ * @was_symbolic: (out) (allow-none): a #gboolean, returns whether the
+ * loaded icon was a symbolic one and whether the @fg color was
+ * applied to it.
+ * @error: (allow-none): location to store error information on failure,
+ * or %NULL.
+ *
+ * Finishes an async icon load, see gtk_icon_info_load_symbolic_for_context_async().
+ *
+ * Return value: (transfer full): the rendered icon; this may be a newly
+ * created icon or a new reference to an internal icon, so you must
+ * not modify the icon. Use g_object_unref() to release your reference
+ * to the icon.
+ *
+ * Since: 3.8
+ **/
+GdkPixbuf *
+gtk_icon_info_load_symbolic_for_context_finish (GtkIconInfo *icon_info,
+ GAsyncResult *result,
+ gboolean *was_symbolic,
+ GError **error)
+{
+ return gtk_icon_info_load_symbolic_finish (icon_info, result, was_symbolic, error);
+}
+
static GdkRGBA *
color_to_rgba (GdkColor *color, GdkRGBA *rgba)
{
@@ -3930,6 +4469,7 @@ gtk_icon_info_load_symbolic_for_style (GtkIconInfo *icon_info,
return _gtk_icon_info_load_symbolic_internal (icon_info,
&fg, success_colorp,
warning_colorp, error_colorp,
+ TRUE,
error);
}
@@ -4292,9 +4832,9 @@ _gtk_icon_theme_check_reload (GdkDisplay *display)
* The icon can then be rendered into a pixbuf using
* gtk_icon_info_load_icon().
*
- * Return value: a #GtkIconInfo structure containing
+ * Return value: (transfer full): a #GtkIconInfo structure containing
* information about the icon, or %NULL if the icon
- * wasn't found. Free with gtk_icon_info_free()
+ * wasn't found. Unref with g_object_unref()
*
* Since: 2.14
*/
@@ -4411,7 +4951,7 @@ gtk_icon_theme_lookup_by_gicon (GtkIconTheme *icon_theme,
*
* Creates a #GtkIconInfo for a #GdkPixbuf.
*
- * Returns: a #GtkIconInfo
+ * Return value: (transfer full): a #GtkIconInfo
*
* Since: 2.14
*/
diff --git a/gtk/gtkicontheme.h b/gtk/gtkicontheme.h
index 8852110cdb..0b4ee405f6 100644
--- a/gtk/gtkicontheme.h
+++ b/gtk/gtkicontheme.h
@@ -29,6 +29,11 @@
G_BEGIN_DECLS
#define GTK_TYPE_ICON_INFO (gtk_icon_info_get_type ())
+#define GTK_ICON_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_INFO, GtkIconInfo))
+#define GTK_ICON_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_ICON_INFO, GtkIconInfoClass))
+#define GTK_IS_ICON_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ICON_INFO))
+#define GTK_IS_ICON_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_ICON_INFO))
+#define GTK_ICON_INFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_ICON_INFO, GtkIconInfoClass))
#define GTK_TYPE_ICON_THEME (gtk_icon_theme_get_type ())
#define GTK_ICON_THEME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ICON_THEME, GtkIconTheme))
@@ -44,6 +49,7 @@ G_BEGIN_DECLS
* an icon theme.
*/
typedef struct _GtkIconInfo GtkIconInfo;
+typedef struct _GtkIconInfoClass GtkIconInfoClass;
typedef struct _GtkIconTheme GtkIconTheme;
typedef struct _GtkIconThemeClass GtkIconThemeClass;
typedef struct _GtkIconThemePrivate GtkIconThemePrivate;
@@ -186,7 +192,9 @@ void gtk_icon_theme_add_builtin_icon (const gchar *icon_name,
GdkPixbuf *pixbuf);
GType gtk_icon_info_get_type (void) G_GNUC_CONST;
+GDK_DEPRECATED_IN_3_8_FOR(g_object_ref)
GtkIconInfo * gtk_icon_info_copy (GtkIconInfo *icon_info);
+GDK_DEPRECATED_IN_3_8_FOR(g_object_unref)
void gtk_icon_info_free (GtkIconInfo *icon_info);
GtkIconInfo * gtk_icon_info_new_for_pixbuf (GtkIconTheme *icon_theme,
@@ -197,6 +205,15 @@ const gchar * gtk_icon_info_get_filename (GtkIconInfo *icon_info
GdkPixbuf * gtk_icon_info_get_builtin_pixbuf (GtkIconInfo *icon_info);
GdkPixbuf * gtk_icon_info_load_icon (GtkIconInfo *icon_info,
GError **error);
+GDK_AVAILABLE_IN_3_8
+void gtk_icon_info_load_icon_async (GtkIconInfo *icon_info,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GDK_AVAILABLE_IN_3_8
+GdkPixbuf * gtk_icon_info_load_icon_finish (GtkIconInfo *icon_info,
+ GAsyncResult *res,
+ GError **error);
GdkPixbuf * gtk_icon_info_load_symbolic (GtkIconInfo *icon_info,
const GdkRGBA *fg,
const GdkRGBA *success_color,
@@ -204,10 +221,35 @@ GdkPixbuf * gtk_icon_info_load_symbolic (GtkIconInfo *icon_info
const GdkRGBA *error_color,
gboolean *was_symbolic,
GError **error);
+GDK_AVAILABLE_IN_3_8
+void gtk_icon_info_load_symbolic_async (GtkIconInfo *icon_info,
+ const GdkRGBA *fg,
+ const GdkRGBA *success_color,
+ const GdkRGBA *warning_color,
+ const GdkRGBA *error_color,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GDK_AVAILABLE_IN_3_8
+GdkPixbuf * gtk_icon_info_load_symbolic_finish (GtkIconInfo *icon_info,
+ GAsyncResult *res,
+ gboolean *was_symbolic,
+ GError **error);
GdkPixbuf * gtk_icon_info_load_symbolic_for_context (GtkIconInfo *icon_info,
GtkStyleContext *context,
gboolean *was_symbolic,
GError **error);
+GDK_AVAILABLE_IN_3_8
+void gtk_icon_info_load_symbolic_for_context_async (GtkIconInfo *icon_info,
+ GtkStyleContext *context,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GDK_AVAILABLE_IN_3_8
+GdkPixbuf * gtk_icon_info_load_symbolic_for_context_finish (GtkIconInfo *icon_info,
+ GAsyncResult *res,
+ gboolean *was_symbolic,
+ GError **error);
GDK_DEPRECATED_IN_3_0_FOR(gtk_icon_info_load_symbol_for_context)
GdkPixbuf * gtk_icon_info_load_symbolic_for_style (GtkIconInfo *icon_info,
GtkStyle *style,
diff --git a/gtk/gtkimmodule.c b/gtk/gtkimmodule.c
index 0f45847c61..e6372f2edb 100644
--- a/gtk/gtkimmodule.c
+++ b/gtk/gtkimmodule.c
@@ -646,12 +646,14 @@ lookup_immodule (gchar **immodules_list)
if (g_strcmp0 (*immodules_list, SIMPLE_ID) == 0)
return SIMPLE_ID;
else
- {
- GtkIMModule *module;
- module = g_hash_table_lookup (contexts_hash, *immodules_list);
- if (module)
- return module->contexts[0]->context_id;
- }
+ {
+ gboolean found;
+ gchar *context_id;
+ found = g_hash_table_lookup_extended (contexts_hash, *immodules_list,
+ (gpointer *) &context_id, NULL);
+ if (found)
+ return context_id;
+ }
immodules_list++;
}
diff --git a/gtk/gtknumerableicon.c b/gtk/gtknumerableicon.c
index a1131f576e..e46547174a 100644
--- a/gtk/gtknumerableicon.c
+++ b/gtk/gtknumerableicon.c
@@ -215,7 +215,7 @@ draw_from_gicon (GtkNumerableIcon *self)
return NULL;
pixbuf = gtk_icon_info_load_icon (info, NULL);
- gtk_icon_info_free (info);
+ g_object_unref (info);
if (pixbuf == NULL)
return NULL;
diff --git a/gtk/gtkplug.c b/gtk/gtkplug.c
index 65df93699b..01fc9799e5 100644
--- a/gtk/gtkplug.c
+++ b/gtk/gtkplug.c
@@ -1092,8 +1092,6 @@ gtk_plug_realize (GtkWidget *widget)
gtk_style_context_set_background (gtk_widget_get_style_context (widget),
gdk_window);
-
- gdk_window_enable_synchronized_configure (gdk_window);
}
static void
diff --git a/gtk/gtkradiomenuitem.c b/gtk/gtkradiomenuitem.c
index 0413328eee..29011caa13 100644
--- a/gtk/gtkradiomenuitem.c
+++ b/gtk/gtkradiomenuitem.c
@@ -127,10 +127,9 @@ gtk_radio_menu_item_set_property (GObject *object,
GSList *slist;
case PROP_GROUP:
- if (G_VALUE_HOLDS_OBJECT (value))
- slist = gtk_radio_menu_item_get_group ((GtkRadioMenuItem*) g_value_get_object (value));
- else
- slist = NULL;
+ slist = g_value_get_object (value);
+ if (slist)
+ slist = gtk_radio_menu_item_get_group ((GtkRadioMenuItem*) g_value_get_object (value));
gtk_radio_menu_item_set_group (radio_menu_item, slist);
break;
default:
@@ -249,18 +248,10 @@ GtkWidget*
gtk_radio_menu_item_new_with_label (GSList *group,
const gchar *label)
{
- GtkWidget *radio_menu_item;
- GtkWidget *accel_label;
-
- radio_menu_item = gtk_radio_menu_item_new (group);
- accel_label = gtk_accel_label_new (label);
- gtk_widget_set_halign (accel_label, GTK_ALIGN_START);
- gtk_widget_set_valign (accel_label, GTK_ALIGN_CENTER);
- gtk_container_add (GTK_CONTAINER (radio_menu_item), accel_label);
- gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label), radio_menu_item);
- gtk_widget_show (accel_label);
-
- return radio_menu_item;
+ return g_object_new (GTK_TYPE_RADIO_MENU_ITEM,
+ "group", (group) ? group->data : NULL,
+ "label", label,
+ NULL);
}
@@ -280,20 +271,11 @@ GtkWidget*
gtk_radio_menu_item_new_with_mnemonic (GSList *group,
const gchar *label)
{
- GtkWidget *radio_menu_item;
- GtkWidget *accel_label;
-
- radio_menu_item = gtk_radio_menu_item_new (group);
- accel_label = g_object_new (GTK_TYPE_ACCEL_LABEL, NULL);
- gtk_label_set_text_with_mnemonic (GTK_LABEL (accel_label), label);
- gtk_widget_set_halign (accel_label, GTK_ALIGN_START);
- gtk_widget_set_valign (accel_label, GTK_ALIGN_CENTER);
-
- gtk_container_add (GTK_CONTAINER (radio_menu_item), accel_label);
- gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label), radio_menu_item);
- gtk_widget_show (accel_label);
-
- return radio_menu_item;
+ return g_object_new (GTK_TYPE_RADIO_MENU_ITEM,
+ "group", (group) ? group->data : NULL,
+ "label", label,
+ "use-underline", TRUE,
+ NULL);
}
/**
diff --git a/gtk/gtkrecentmanager.c b/gtk/gtkrecentmanager.c
index 1c5a188232..310efe0771 100644
--- a/gtk/gtkrecentmanager.c
+++ b/gtk/gtkrecentmanager.c
@@ -1944,7 +1944,7 @@ get_icon_for_mime_type (const char *mime_type,
return NULL;
pixbuf = gtk_icon_info_load_icon (info, NULL);
- gtk_icon_info_free (info);
+ g_object_unref (info);
return pixbuf;
}
diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
index 0095072ea6..99dab9ee94 100644
--- a/gtk/gtkscrolledwindow.c
+++ b/gtk/gtkscrolledwindow.c
@@ -126,7 +126,6 @@
#define TOUCH_BYPASS_CAPTURED_THRESHOLD 30
/* Kinetic scrolling */
-#define FRAME_INTERVAL (1000 / 60)
#define MAX_OVERSHOOT_DISTANCE 50
#define FRICTION_DECELERATION 0.003
#define OVERSHOOT_INVERSE_ACCELERATION 0.003
@@ -284,6 +283,8 @@ static gboolean _gtk_scrolled_window_set_adjustment_value (GtkScrolledWindo
gboolean allow_overshooting,
gboolean snap_to_border);
+static void gtk_scrolled_window_cancel_deceleration (GtkScrolledWindow *scrolled_window);
+
static guint signals[LAST_SIGNAL] = {0};
G_DEFINE_TYPE (GtkScrolledWindow, gtk_scrolled_window, GTK_TYPE_BIN)
@@ -2384,7 +2385,9 @@ _gtk_scrolled_window_set_adjustment_value (GtkScrolledWindow *scrolled_window,
}
static gboolean
-scrolled_window_deceleration_cb (gpointer user_data)
+scrolled_window_deceleration_cb (GtkWidget *widdget,
+ GdkFrameClock *frame_clock,
+ gpointer user_data)
{
KineticScrollData *data = user_data;
GtkScrolledWindow *scrolled_window = data->scrolled_window;
@@ -2401,7 +2404,7 @@ scrolled_window_deceleration_cb (gpointer user_data)
_gtk_scrolled_window_get_overshoot (scrolled_window,
&old_overshoot_x, &old_overshoot_y);
- current_time = g_get_monotonic_time ();
+ current_time = gdk_frame_clock_get_frame_time (frame_clock);
elapsed = (current_time - data->last_deceleration_time) / 1000;
data->last_deceleration_time = current_time;
@@ -2493,14 +2496,11 @@ scrolled_window_deceleration_cb (gpointer user_data)
_gtk_scrolled_window_allocate_overshoot_window (scrolled_window);
}
- if (overshoot_x != 0 || overshoot_y != 0 ||
- data->x_velocity != 0 || data->y_velocity != 0)
- return TRUE;
- else
- {
- priv->deceleration_id = 0;
- return FALSE;
- }
+ if (overshoot_x == 0 && overshoot_y == 0 &&
+ data->x_velocity == 0 && data->y_velocity == 0)
+ gtk_scrolled_window_cancel_deceleration (scrolled_window);
+
+ return G_SOURCE_CONTINUE;
}
static void
@@ -2510,7 +2510,8 @@ gtk_scrolled_window_cancel_deceleration (GtkScrolledWindow *scrolled_window)
if (priv->deceleration_id)
{
- g_source_remove (priv->deceleration_id);
+ gtk_widget_remove_tick_callback (GTK_WIDGET (scrolled_window),
+ priv->deceleration_id);
priv->deceleration_id = 0;
}
}
@@ -2519,12 +2520,15 @@ static void
gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
{
GtkScrolledWindowPrivate *priv = scrolled_window->priv;
+ GdkFrameClock *frame_clock;
KineticScrollData *data;
gdouble angle;
+ frame_clock = gtk_widget_get_frame_clock (GTK_WIDGET (scrolled_window));
+
data = g_new0 (KineticScrollData, 1);
data->scrolled_window = scrolled_window;
- data->last_deceleration_time = g_get_monotonic_time ();
+ data->last_deceleration_time = gdk_frame_clock_get_frame_time (frame_clock);
data->x_velocity = priv->x_velocity;
data->y_velocity = priv->y_velocity;
@@ -2536,10 +2540,10 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
data->vel_sine = sin (angle);
scrolled_window->priv->deceleration_id =
- gdk_threads_add_timeout_full (G_PRIORITY_DEFAULT,
- FRAME_INTERVAL,
+ gtk_widget_add_tick_callback (GTK_WIDGET (scrolled_window),
scrolled_window_deceleration_cb,
- data, (GDestroyNotify) g_free);
+ data,
+ (GDestroyNotify) g_free);
}
static gboolean
diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c
index 876105cf54..f5d1e86ea5 100644
--- a/gtk/gtkstylecontext.c
+++ b/gtk/gtkstylecontext.c
@@ -358,20 +358,21 @@ struct _GtkStyleContextPrivate
GtkStyleCascade *cascade;
- GtkStyleContext *animation_list_prev;
- GtkStyleContext *animation_list_next;
-
GtkStyleContext *parent;
GSList *children;
- GtkWidget *widget;
+ GtkWidget *widget;
GtkWidgetPath *widget_path;
GHashTable *style_data;
GtkStyleInfo *info;
+ GdkFrameClock *frame_clock;
+ guint frame_clock_update_id;
+
GtkCssChange relevant_changes;
GtkCssChange pending_changes;
const GtkBitmask *invalidating_context;
+ guint animating : 1;
guint invalid : 1;
};
@@ -379,6 +380,7 @@ enum {
PROP_0,
PROP_SCREEN,
PROP_DIRECTION,
+ PROP_FRAME_CLOCK,
PROP_PARENT
};
@@ -388,8 +390,6 @@ enum {
};
static guint signals[LAST_SIGNAL] = { 0 };
-static GtkStyleContext *_running_animations = NULL;
-guint _running_animations_timer_id = 0;
static void gtk_style_context_finalize (GObject *object);
@@ -404,6 +404,9 @@ static void gtk_style_context_impl_get_property (GObject *object,
static StyleData *style_data_lookup (GtkStyleContext *context);
+static void gtk_style_context_disconnect_update (GtkStyleContext *context);
+static void gtk_style_context_connect_update (GtkStyleContext *context);
+
G_DEFINE_TYPE (GtkStyleContext, gtk_style_context, G_TYPE_OBJECT)
static void
@@ -443,6 +446,13 @@ gtk_style_context_class_init (GtkStyleContextClass *klass)
GDK_TYPE_SCREEN,
GTK_PARAM_READWRITE));
g_object_class_install_property (object_class,
+ PROP_FRAME_CLOCK,
+ g_param_spec_object ("paint-clock",
+ P_("FrameClock"),
+ P_("The associated GdkFrameClock"),
+ GDK_TYPE_FRAME_CLOCK,
+ GTK_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
PROP_DIRECTION,
g_param_spec_enum ("direction",
P_("Direction"),
@@ -724,28 +734,48 @@ gtk_style_context_init (GtkStyleContext *style_context)
_gtk_style_cascade_get_for_screen (priv->screen));
}
+static void
+gtk_style_context_update (GdkFrameClock *clock,
+ GtkStyleContext *context)
+{
+ _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANIMATE);
+}
+
static gboolean
-gtk_style_context_do_animations (gpointer unused)
+gtk_style_context_is_animating (GtkStyleContext *context)
{
- GtkStyleContext *context;
+ GtkStyleContextPrivate *priv = context->priv;
- for (context = _running_animations;
- context != NULL;
- context = context->priv->animation_list_next)
+ return priv->animating;
+}
+
+static void
+gtk_style_context_disconnect_update (GtkStyleContext *context)
+{
+ GtkStyleContextPrivate *priv = context->priv;
+
+ if (priv->frame_clock && priv->frame_clock_update_id)
{
- _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANIMATE);
+ g_signal_handler_disconnect (priv->frame_clock,
+ priv->frame_clock_update_id);
+ priv->frame_clock_update_id = 0;
+ gdk_frame_clock_end_updating (priv->frame_clock);
}
-
- return TRUE;
}
-static gboolean
-gtk_style_context_is_animating (GtkStyleContext *context)
+static void
+gtk_style_context_connect_update (GtkStyleContext *context)
{
GtkStyleContextPrivate *priv = context->priv;
- return priv->animation_list_prev != NULL
- || _running_animations == context;
+ if (priv->frame_clock && priv->frame_clock_update_id == 0)
+ {
+ priv->frame_clock_update_id = g_signal_connect (priv->frame_clock,
+ "update",
+ G_CALLBACK (gtk_style_context_update),
+ context);
+ gdk_frame_clock_begin_updating (priv->frame_clock);
+ }
}
static void
@@ -756,25 +786,9 @@ gtk_style_context_stop_animating (GtkStyleContext *context)
if (!gtk_style_context_is_animating (context))
return;
- if (priv->animation_list_prev == NULL)
- {
- _running_animations = priv->animation_list_next;
+ priv->animating = FALSE;
- if (_running_animations == NULL)
- {
- /* we were the last animation */
- g_source_remove (_running_animations_timer_id);
- _running_animations_timer_id = 0;
- }
- }
- else
- priv->animation_list_prev->priv->animation_list_next = priv->animation_list_next;
-
- if (priv->animation_list_next)
- priv->animation_list_next->priv->animation_list_prev = priv->animation_list_prev;
-
- priv->animation_list_next = NULL;
- priv->animation_list_prev = NULL;
+ gtk_style_context_disconnect_update (context);
}
static void
@@ -785,19 +799,9 @@ gtk_style_context_start_animating (GtkStyleContext *context)
if (gtk_style_context_is_animating (context))
return;
- if (_running_animations == NULL)
- {
- _running_animations_timer_id = gdk_threads_add_timeout (25,
- gtk_style_context_do_animations,
- NULL);
- _running_animations = context;
- }
- else
- {
- priv->animation_list_next = _running_animations;
- _running_animations->priv->animation_list_prev = context;
- _running_animations = context;
- }
+ priv->animating = TRUE;
+
+ gtk_style_context_connect_update (context);
}
static gboolean
@@ -886,6 +890,10 @@ gtk_style_context_impl_set_property (GObject *object,
g_value_get_enum (value));
G_GNUC_END_IGNORE_DEPRECATIONS;
break;
+ case PROP_FRAME_CLOCK:
+ gtk_style_context_set_frame_clock (style_context,
+ g_value_get_object (value));
+ break;
case PROP_PARENT:
gtk_style_context_set_parent (style_context,
g_value_get_object (value));
@@ -918,6 +926,9 @@ gtk_style_context_impl_get_property (GObject *object,
g_value_set_enum (value, gtk_style_context_get_direction (style_context));
G_GNUC_END_IGNORE_DEPRECATIONS;
break;
+ case PROP_FRAME_CLOCK:
+ g_value_set_object (value, priv->frame_clock);
+ break;
case PROP_PARENT:
g_value_set_object (value, priv->parent);
break;
@@ -2615,6 +2626,70 @@ gtk_style_context_get_screen (GtkStyleContext *context)
}
/**
+ * gtk_style_context_set_frame_clock:
+ * @context: a #GdkFrameClock
+ * @frame_clock: a #GdkFrameClock
+ *
+ * Attaches @context to the given frame clock.
+ *
+ * The frame clock is used for the timing of animations.
+ *
+ * If you are using a #GtkStyleContext returned from
+ * gtk_widget_get_style_context(), you do not need to
+ * call this yourself.
+ *
+ * Since: 3.8
+ **/
+void
+gtk_style_context_set_frame_clock (GtkStyleContext *context,
+ GdkFrameClock *frame_clock)
+{
+ GtkStyleContextPrivate *priv;
+
+ g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
+ g_return_if_fail (frame_clock == NULL || GDK_IS_FRAME_CLOCK (frame_clock));
+
+ priv = context->priv;
+ if (priv->frame_clock == frame_clock)
+ return;
+
+ if (priv->animating)
+ gtk_style_context_disconnect_update (context);
+
+ if (priv->frame_clock)
+ g_object_unref (priv->frame_clock);
+ priv->frame_clock = frame_clock;
+ if (priv->frame_clock)
+ g_object_ref (priv->frame_clock);
+
+ if (priv->animating)
+ gtk_style_context_connect_update (context);
+
+ g_object_notify (G_OBJECT (context), "paint-clock");
+}
+
+/**
+ * gtk_style_context_get_frame_clock:
+ * @context: a #GtkStyleContext
+ *
+ * Returns the #GdkFrameClock to which @context is attached.
+ *
+ * Returns: (transfer none): a #GdkFrameClock, or %NULL
+ * if @context does not have an attached frame clock.
+ * Since: 3.8
+ **/
+GdkFrameClock *
+gtk_style_context_get_frame_clock (GtkStyleContext *context)
+{
+ GtkStyleContextPrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
+
+ priv = context->priv;
+ return priv->frame_clock;
+}
+
+/**
* gtk_style_context_set_direction:
* @context: a #GtkStyleContext
* @direction: the new direction.
diff --git a/gtk/gtkstylecontext.h b/gtk/gtkstylecontext.h
index dab758a5fb..35655f28d6 100644
--- a/gtk/gtkstylecontext.h
+++ b/gtk/gtkstylecontext.h
@@ -836,6 +836,13 @@ void gtk_style_context_set_screen (GtkStyleContext *context,
GdkScreen *screen);
GdkScreen * gtk_style_context_get_screen (GtkStyleContext *context);
+GDK_AVAILABLE_IN_3_8
+void gtk_style_context_set_frame_clock (GtkStyleContext *context,
+ GdkFrameClock *frame_clock);
+GDK_AVAILABLE_IN_3_8
+GdkFrameClock *gtk_style_context_get_frame_clock (GtkStyleContext *context);
+
+
GDK_DEPRECATED_IN_3_8_FOR(gtk_style_context_set_state)
void gtk_style_context_set_direction (GtkStyleContext *context,
GtkTextDirection direction);
diff --git a/gtk/gtktexthandle.c b/gtk/gtktexthandle.c
index 97449b485b..8298cdf941 100644
--- a/gtk/gtktexthandle.c
+++ b/gtk/gtktexthandle.c
@@ -369,10 +369,18 @@ gtk_text_handle_finalize (GObject *object)
g_object_unref (priv->relative_to);
if (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window)
- gdk_window_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window);
+ {
+ gtk_widget_unregister_window (priv->parent,
+ priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window);
+ gdk_window_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window);
+ }
if (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window)
- gdk_window_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window);
+ {
+ gtk_widget_unregister_window (priv->parent,
+ priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window);
+ gdk_window_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window);
+ }
if (g_signal_handler_is_connected (priv->parent, priv->draw_signal_id))
g_signal_handler_disconnect (priv->parent, priv->draw_signal_id);
@@ -527,7 +535,11 @@ _gtk_text_handle_set_relative_to (GtkTextHandle *handle,
if (priv->relative_to)
{
+ gtk_widget_unregister_window (priv->parent,
+ priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window);
gdk_window_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_START].window);
+ gtk_widget_unregister_window (priv->parent,
+ priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window);
gdk_window_destroy (priv->windows[GTK_TEXT_HANDLE_POSITION_SELECTION_END].window);
g_object_unref (priv->relative_to);
}
diff --git a/gtk/gtktoolbar.c b/gtk/gtktoolbar.c
index 0ca1b7eea4..e4dbfa45eb 100644
--- a/gtk/gtktoolbar.c
+++ b/gtk/gtktoolbar.c
@@ -231,6 +231,8 @@ static GtkWidgetPath * gtk_toolbar_get_path_for_child
GtkWidget *child);
static void gtk_toolbar_invalidate_order (GtkToolbar *toolbar);
+static void gtk_toolbar_direction_changed (GtkWidget *widget,
+ GtkTextDirection previous_direction);
static void gtk_toolbar_orientation_changed (GtkToolbar *toolbar,
GtkOrientation orientation);
static void gtk_toolbar_real_style_changed (GtkToolbar *toolbar,
@@ -394,6 +396,7 @@ gtk_toolbar_class_init (GtkToolbarClass *klass)
widget_class->unmap = gtk_toolbar_unmap;
widget_class->popup_menu = gtk_toolbar_popup_menu;
widget_class->show_all = gtk_toolbar_show_all;
+ widget_class->direction_changed = gtk_toolbar_direction_changed;
container_class->add = gtk_toolbar_add;
container_class->remove = gtk_toolbar_remove;
@@ -3855,6 +3858,10 @@ gtk_toolbar_get_visible_position (GtkToolbar *toolbar,
g_assert (count.found);
+ if (toolbar->priv->orientation == GTK_ORIENTATION_HORIZONTAL &&
+ gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL)
+ return count.after;
+
return count.before;
}
@@ -3875,18 +3882,23 @@ gtk_toolbar_get_path_for_child (GtkContainer *container,
{
GtkWidgetPath *path;
GtkToolbar *toolbar;
+ GtkToolbarPrivate *priv;
GtkWidgetPath *sibling_path;
gint vis_index;
GList *children;
toolbar = GTK_TOOLBAR (container);
+ priv = toolbar->priv;
/* build a path for all the visible children;
* get_children works in visible order
*/
sibling_path = gtk_widget_path_new ();
children = _gtk_container_get_all_children (container);
- children = g_list_reverse (children);
+
+ if (priv->orientation != GTK_ORIENTATION_HORIZONTAL ||
+ gtk_widget_get_direction (GTK_WIDGET (toolbar)) != GTK_TEXT_DIR_RTL)
+ children = g_list_reverse (children);
g_list_foreach (children, add_widget_to_path, sibling_path);
g_list_free (children);
@@ -3924,3 +3936,12 @@ gtk_toolbar_invalidate_order (GtkToolbar *toolbar)
NULL);
}
+static void
+gtk_toolbar_direction_changed (GtkWidget *widget,
+ GtkTextDirection previous_direction)
+{
+ GTK_WIDGET_CLASS (gtk_toolbar_parent_class)->direction_changed (widget, previous_direction);
+
+ gtk_toolbar_invalidate_order (GTK_TOOLBAR (widget));
+}
+
diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
index 34898aba62..af7b8a0888 100644
--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@ -3347,6 +3347,7 @@ gtk_tree_view_button_release_drag_column (GtkWidget *widget,
tree_view->priv->cur_reorder->left_column);
}
tree_view->priv->drag_column = NULL;
+ gtk_widget_unregister_window (widget, tree_view->priv->drag_window);
gdk_window_destroy (tree_view->priv->drag_window);
tree_view->priv->drag_window = NULL;
diff --git a/gtk/gtkuimanager.c b/gtk/gtkuimanager.c
index 9d93046bcd..75189aac3e 100644
--- a/gtk/gtkuimanager.c
+++ b/gtk/gtkuimanager.c
@@ -714,7 +714,6 @@ gtk_ui_manager_buildable_add_child (GtkBuildable *buildable,
pos = g_list_length (manager->private_data->action_groups);
- g_object_ref (child);
gtk_ui_manager_insert_action_group (manager,
GTK_ACTION_GROUP (child),
pos);
diff --git a/gtk/gtkviewport.c b/gtk/gtkviewport.c
index 935bda7b9e..0469c5bce4 100644
--- a/gtk/gtkviewport.c
+++ b/gtk/gtkviewport.c
@@ -255,10 +255,11 @@ gtk_viewport_init (GtkViewport *viewport)
/**
* gtk_viewport_new:
- * @hadjustment: horizontal adjustment
- * @vadjustment: vertical adjustment
+ * @hadjustment: (allow-none): horizontal adjustment
+ * @vadjustment: (allow-none): vertical adjustment
*
- * Creates a new #GtkViewport with the given adjustments.
+ * Creates a new #GtkViewport with the given adjustments, or with default
+ * adjustments if none are given.
*
* Returns: a new #GtkViewport
*/
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index d161ee9194..eefaddeef6 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -409,6 +409,9 @@ struct _GtkWidgetPrivate
/* The widget's parent */
GtkWidget *parent;
+ /* Animations and other things to update on clock ticks */
+ GList *tick_callbacks;
+
#ifdef G_ENABLE_DEBUG
/* Number of gtk_widget_push_verify_invariants () */
guint verifying_invariants_count;
@@ -710,6 +713,10 @@ static void gtk_widget_set_device_enabled_internal (GtkWidget *widget,
GdkDevice *device,
gboolean recurse,
gboolean enabled);
+
+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 (cairo_t *cr,
GdkEventExpose *event);
@@ -1798,6 +1805,13 @@ gtk_widget_class_init (GtkWidgetClass *klass)
* restore it. The signal emission takes care of calling cairo_save()
* before and cairo_restore() after invoking the handler.
*
+ * The signal handler will get a @cr with a clip region already set to the
+ * widget's dirty region, i.e. to the area that needs repainting. Complicated
+ * widgets that want to avoid redrawing themselves completely can get the full
+ * extents of the clip region with gdk_cairo_get_clip_rectangle(), or they can
+ * get a finer-grained representation of the dirty region with
+ * cairo_copy_clip_rectangle_list().
+ *
* Returns: %TRUE to stop other handlers from being invoked for the event.
% %FALSE to propagate the event further.
*
@@ -4505,6 +4519,239 @@ gtk_widget_update_devices_mask (GtkWidget *widget,
gtk_widget_set_device_enabled_internal (widget, GDK_DEVICE (l->data), recurse, TRUE);
}
+typedef struct _GtkTickCallbackInfo GtkTickCallbackInfo;
+
+struct _GtkTickCallbackInfo
+{
+ guint refcount;
+
+ guint id;
+ GtkTickCallback callback;
+ gpointer user_data;
+ GDestroyNotify notify;
+
+ guint destroyed : 1;
+};
+
+static void
+ref_tick_callback_info (GtkTickCallbackInfo *info)
+{
+ info->refcount++;
+}
+
+static void
+unref_tick_callback_info (GtkWidget *widget,
+ GtkTickCallbackInfo *info,
+ GList *link)
+{
+ GtkWidgetPrivate *priv = widget->priv;
+
+ info->refcount--;
+ if (info->refcount == 0)
+ {
+ priv->tick_callbacks = g_list_delete_link (priv->tick_callbacks, link);
+ if (info->notify)
+ info->notify (info->user_data);
+ g_slice_free (GtkTickCallbackInfo, info);
+ }
+
+ if (priv->tick_callbacks == NULL && priv->realized)
+ {
+ GdkFrameClock *frame_clock = gtk_widget_get_frame_clock (widget);
+ g_signal_handlers_disconnect_by_func (frame_clock,
+ (gpointer) gtk_widget_on_frame_clock_update,
+ widget);
+ gdk_frame_clock_end_updating (frame_clock);
+ }
+}
+
+static void
+destroy_tick_callback_info (GtkWidget *widget,
+ GtkTickCallbackInfo *info,
+ GList *link)
+{
+ if (!info->destroyed)
+ {
+ info->destroyed = TRUE;
+ unref_tick_callback_info (widget, info, link);
+ }
+}
+
+static void
+gtk_widget_on_frame_clock_update (GdkFrameClock *frame_clock,
+ GtkWidget *widget)
+{
+ GtkWidgetPrivate *priv = widget->priv;
+ GList *l;
+
+ g_object_ref (widget);
+
+ for (l = priv->tick_callbacks; l;)
+ {
+ GtkTickCallbackInfo *info = l->data;
+ GList *next;
+
+ ref_tick_callback_info (info);
+ if (!info->destroyed)
+ {
+ if (info->callback (widget,
+ frame_clock,
+ info->user_data) == G_SOURCE_REMOVE)
+ {
+ destroy_tick_callback_info (widget, info, l);
+ }
+ }
+
+ next = l->next;
+ unref_tick_callback_info (widget, info, l);
+ l = next;
+ }
+
+ g_object_unref (widget);
+}
+
+static guint tick_callback_id;
+
+/**
+ * gtk_widget_add_tick_callback:
+ * @widget: a #GtkWidget
+ * @callback: function to call for updating animations
+ * @user_data: data to pass to @callback
+ * @notify: function to call to free @user_data when the callback is removed.
+ *
+ * Queues a animation frame update and adds a callback to be called
+ * before each frame. Until the tick callback is removed, it will be
+ * called frequently (usually at the frame rate of the output device
+ * or as quickly as the application an be repainted, whichever is
+ * slower). For this reason, is most suitable for handling graphics
+ * that change every frame or every few frames. The tick callback does
+ * not automatically imply a relayout or repaint. If you want a
+ * repaint or relayout, and aren't changing widget properties that
+ * would trigger that (for example, changing the text of a #GtkLabel),
+ * then you will have to call gtk_widget_queue_resize() or
+ * gtk_widget_queue_draw_area() yourself.
+ *
+ * gdk_frame_clock_get_frame_time() should generally be used for timing
+ * continuous animations and
+ * gdk_frame_timings_get_predicted_presentation_time() if you are
+ * trying to display isolated frames at particular times.
+ *
+ * This is a more convenient alternative to connecting directly to the
+ * #GdkFrameClock::update signal of #GdkFrameClock, since you don't
+ * have to worry about when a #GdkFrameClock is assigned to a widget.
+ *
+ * Returns: an id for the connection of this callback. Remove the callback
+ * by passing it to gtk_widget_remove_tick_callback()
+ *
+ * Since: 3.8
+ */
+guint
+gtk_widget_add_tick_callback (GtkWidget *widget,
+ GtkTickCallback callback,
+ gpointer user_data,
+ GDestroyNotify notify)
+{
+ GtkWidgetPrivate *priv;
+ GtkTickCallbackInfo *info;
+
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
+
+ priv = widget->priv;
+
+ if (priv->tick_callbacks == NULL && priv->realized)
+ {
+ GdkFrameClock *frame_clock = gtk_widget_get_frame_clock (widget);
+ g_signal_connect (frame_clock, "update",
+ G_CALLBACK (gtk_widget_on_frame_clock_update),
+ widget);
+ gdk_frame_clock_begin_updating (frame_clock);
+ }
+
+ info = g_slice_new0 (GtkTickCallbackInfo);
+
+ info->refcount = 1;
+ info->id = ++tick_callback_id;
+ info->callback = callback;
+ info->user_data = user_data;
+ info->notify = notify;
+
+ priv->tick_callbacks = g_list_prepend (priv->tick_callbacks,
+ info);
+
+ return info->id;
+}
+
+/**
+ * gtk_widget_remove_tick_callback:
+ * @widget: a #GtkWidget
+ * @id: an id returned by gtk_widget_add_tick_callback()
+ *
+ * Removes a tick callback previously registered with
+ * gtk_widget_add_tick_callback().
+ *
+ * Since: 3.8
+ */
+void
+gtk_widget_remove_tick_callback (GtkWidget *widget,
+ guint id)
+{
+ GtkWidgetPrivate *priv;
+ GList *l;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ priv = widget->priv;
+
+ for (l = priv->tick_callbacks; l; l = l->next)
+ {
+ GtkTickCallbackInfo *info = l->data;
+ if (info->id == id)
+ destroy_tick_callback_info (widget, info, l);
+ }
+}
+
+static void
+gtk_widget_connect_frame_clock (GtkWidget *widget,
+ GdkFrameClock *frame_clock)
+{
+ GtkWidgetPrivate *priv = widget->priv;
+
+ if (GTK_IS_CONTAINER (widget))
+ _gtk_container_maybe_start_idle_sizer (GTK_CONTAINER (widget));
+
+ if (priv->tick_callbacks != NULL)
+ {
+ g_signal_connect (frame_clock, "update",
+ G_CALLBACK (gtk_widget_on_frame_clock_update),
+ widget);
+ gdk_frame_clock_begin_updating (frame_clock);
+ }
+
+ if (priv->context)
+ gtk_style_context_set_frame_clock (priv->context, frame_clock);
+}
+
+static void
+gtk_widget_disconnect_frame_clock (GtkWidget *widget,
+ GdkFrameClock *frame_clock)
+{
+ GtkWidgetPrivate *priv = widget->priv;
+
+ if (GTK_IS_CONTAINER (widget))
+ _gtk_container_stop_idle_sizer (GTK_CONTAINER (widget));
+
+ if (priv->tick_callbacks)
+ {
+ g_signal_handlers_disconnect_by_func (frame_clock,
+ (gpointer) gtk_widget_on_frame_clock_update,
+ widget);
+ gdk_frame_clock_end_updating (frame_clock);
+ }
+
+ if (priv->context)
+ gtk_style_context_set_frame_clock (priv->context, NULL);
+}
+
/**
* gtk_widget_realize:
* @widget: a #GtkWidget
@@ -4585,6 +4832,9 @@ gtk_widget_realize (GtkWidget *widget)
_gtk_widget_enable_device_events (widget);
gtk_widget_update_devices_mask (widget, TRUE);
+ gtk_widget_connect_frame_clock (widget,
+ gtk_widget_get_frame_clock (widget));
+
gtk_widget_pop_verify_invariants (widget);
}
}
@@ -4617,6 +4867,9 @@ gtk_widget_unrealize (GtkWidget *widget)
if (widget->priv->mapped)
gtk_widget_unmap (widget);
+ gtk_widget_disconnect_frame_clock (widget,
+ gtk_widget_get_frame_clock (widget));
+
g_signal_emit (widget, widget_signals[UNREALIZE], 0);
g_assert (!widget->priv->mapped);
gtk_widget_set_realized (widget, FALSE);
@@ -4778,6 +5031,61 @@ gtk_widget_queue_resize_no_redraw (GtkWidget *widget)
}
/**
+ * gtk_widget_get_frame_clock:
+ * @widget: a #GtkWidget
+ *
+ * Obtains the frame clock for a widget. The frame clock is a global
+ * "ticker" that can be used to drive animations and repaints. The
+ * most common reason to get the frame clock is to call
+ * gdk_frame_clock_get_frame_time(), in order to get a time to use for
+ * animating. For example you might record the start of the animation
+ * with an initial value from gdk_frame_clock_get_frame_time(), and
+ * then update the animation by calling
+ * gdk_frame_clock_get_frame_time() again during each repaint.
+ *
+ * gdk_frame_clock_request_phase() will result in a new frame on the
+ * clock, but won't necessarily repaint any widgets. To repaint a
+ * widget, you have to use gtk_widget_queue_draw() which invalidates
+ * the widget (thus scheduling it to receive a draw on the next
+ * frame). gtk_widget_queue_draw() will also end up requesting a frame
+ * on the appropriate frame clock.
+ *
+ * A widget's frame clock will not change while the widget is
+ * mapped. Reparenting a widget (which implies a temporary unmap) can
+ * change the widget's frame clock.
+ *
+ * Unrealized widgets do not have a frame clock.
+ *
+ * Return value: (transfer none): a #GdkFrameClock (or #NULL if widget is unrealized)
+ *
+ * Since: 3.0
+ */
+GdkFrameClock*
+gtk_widget_get_frame_clock (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
+
+ if (widget->priv->realized)
+ {
+ /* We use gtk_widget_get_toplevel() here to make it explicit that
+ * the frame clock is a property of the toplevel that a widget
+ * is anchored to; gdk_window_get_toplevel() will go up the
+ * hierarchy anyways, but should squash any funny business with
+ * reparenting windows and widgets.
+ */
+ GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
+ GdkWindow *window = gtk_widget_get_window (toplevel);
+ g_assert (window != NULL);
+
+ return gdk_window_get_frame_clock (window);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+/**
* gtk_widget_size_request:
* @widget: a #GtkWidget
* @requisition: (out): a #GtkRequisition to be filled in
@@ -8453,6 +8761,17 @@ gtk_widget_propagate_hierarchy_changed_recurse (GtkWidget *widget,
priv->anchored = new_anchored;
+ /* This can only happen with gtk_widget_reparent() */
+ if (priv->realized)
+ {
+ if (new_anchored)
+ gtk_widget_connect_frame_clock (widget,
+ gtk_widget_get_frame_clock (widget));
+ else
+ gtk_widget_disconnect_frame_clock (widget,
+ gtk_widget_get_frame_clock (info->previous_toplevel));
+ }
+
g_signal_emit (widget, widget_signals[HIERARCHY_CHANGED], 0, info->previous_toplevel);
do_screen_change (widget, info->previous_screen, info->new_screen);
@@ -10461,6 +10780,7 @@ gtk_widget_real_destroy (GtkWidget *object)
/* gtk_object_destroy() will already hold a refcount on object */
GtkWidget *widget = GTK_WIDGET (object);
GtkWidgetPrivate *priv = widget->priv;
+ GList *l;
if (GTK_WIDGET_GET_CLASS (widget)->priv->accessible_type != GTK_TYPE_ACCESSIBLE)
{
@@ -10482,6 +10802,13 @@ gtk_widget_real_destroy (GtkWidget *object)
gtk_grab_remove (widget);
+ for (l = priv->tick_callbacks; l;)
+ {
+ GList *next = l->next;
+ destroy_tick_callback_info (widget, l->data, l);
+ l = next;
+ }
+
if (priv->style)
g_object_unref (priv->style);
priv->style = gtk_widget_get_default_style ();
@@ -13771,7 +14098,7 @@ gtk_widget_register_window (GtkWidget *widget,
gdk_window_set_user_data (window, widget);
priv->registered_windows = g_list_prepend (priv->registered_windows, window);
- if (!gtk_widget_get_has_window (widget) && !gdk_window_has_native (window))
+ if (priv->window != window && !gdk_window_has_native (window))
gdk_window_set_opacity (window,
priv->norender_children ? 0.0 : 1.0);
}
@@ -13904,8 +14231,8 @@ gtk_widget_propagate_alpha (GtkWidget *widget)
parent = priv->parent;
norender =
- /* If this widget has an opacity group, never render it */
- priv->opacity_group ||
+ /* If this widget has an opacity group and no window don't render it */
+ (priv->opacity_group && !gtk_widget_get_has_window (widget)) ||
/* If the parent has norender_children, propagate that here */
(parent != NULL && parent->priv->norender_children);
@@ -13925,14 +14252,12 @@ gtk_widget_propagate_alpha (GtkWidget *widget)
gdk_window_set_opacity (priv->window,
norender ? 0 : priv->alpha / 255.0);
}
- else /* !has_window */
+
+ for (l = priv->registered_windows; l != NULL; l = l->next)
{
- for (l = priv->registered_windows; l != NULL; l = l->next)
- {
- GdkWindow *w = l->data;
- if (!gdk_window_has_native (w))
- gdk_window_set_opacity (w, norender_children ? 0.0 : 1.0);
- }
+ 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;
@@ -14396,6 +14721,7 @@ gtk_widget_get_style_context (GtkWidget *widget)
if (G_UNLIKELY (priv->context == NULL))
{
GdkScreen *screen;
+ GdkFrameClock *frame_clock;
priv->context = gtk_style_context_new ();
@@ -14405,6 +14731,10 @@ gtk_widget_get_style_context (GtkWidget *widget)
if (screen)
gtk_style_context_set_screen (priv->context, screen);
+ frame_clock = gtk_widget_get_frame_clock (widget);
+ if (frame_clock)
+ gtk_style_context_set_frame_clock (priv->context, frame_clock);
+
if (priv->parent)
gtk_style_context_set_parent (priv->context,
gtk_widget_get_style_context (priv->parent));
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index a4c20e86c2..bdf8e5e607 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -87,6 +87,23 @@ typedef void (*GtkCallback) (GtkWidget *widget,
gpointer data);
/**
+ * GtkTickCallback:
+ * @widget: the widget
+ * @frame_clock: the frame clock for the widget (same as calling gtk_widget_get_frame_clock())
+ * @user_data: user data passed to gtk_widget_add_tick_callback().
+ *
+ * Callback type for adding a function to update animations. See gtk_widget_add_tick_callback().
+ *
+ * Returns: %G_SOURCE_CONTINUE if the tick callback should continue to be called,
+ * %G_SOURCE_REMOVE if the tick callback should be removed.
+ *
+ * Since: 3.8
+ */
+typedef gboolean (*GtkTickCallback) (GtkWidget *widget,
+ GdkFrameClock *frame_clock,
+ gpointer user_data);
+
+/**
* GtkRequisition:
* @width: the widget's desired width
* @height: the widget's desired height
@@ -473,6 +490,9 @@ void gtk_widget_queue_draw_region (GtkWidget *widget,
const cairo_region_t*region);
void gtk_widget_queue_resize (GtkWidget *widget);
void gtk_widget_queue_resize_no_redraw (GtkWidget *widget);
+GDK_AVAILABLE_IN_3_8
+GdkFrameClock* gtk_widget_get_frame_clock (GtkWidget *widget);
+
GDK_DEPRECATED_IN_3_0_FOR(gtk_widget_get_preferred_size)
void gtk_widget_size_request (GtkWidget *widget,
GtkRequisition *requisition);
@@ -903,6 +923,18 @@ void gtk_widget_insert_action_group (GtkWidg
const gchar *name,
GActionGroup *group);
+
+
+GDK_AVAILABLE_IN_3_8
+guint gtk_widget_add_tick_callback (GtkWidget *widget,
+ GtkTickCallback callback,
+ gpointer user_data,
+ GDestroyNotify notify);
+
+GDK_AVAILABLE_IN_3_8
+void gtk_widget_remove_tick_callback (GtkWidget *widget,
+ guint id);
+
G_END_DECLS
#endif /* __GTK_WIDGET_H__ */
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index a2f9b18e0d..fe24363fd1 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -422,9 +422,11 @@ static GtkKeyHash *gtk_window_get_key_hash (GtkWindow *window);
static void gtk_window_free_key_hash (GtkWindow *window);
static void gtk_window_on_composited_changed (GdkScreen *screen,
GtkWindow *window);
+#ifdef GDK_WINDOWING_X11
static void gtk_window_on_theme_variant_changed (GtkSettings *settings,
GParamSpec *pspec,
GtkWindow *window);
+#endif
static void gtk_window_set_theme_variant (GtkWindow *window);
static GSList *toplevel_list = NULL;
@@ -5164,7 +5166,6 @@ gtk_window_realize (GtkWidget *widget)
gtk_style_context_set_background (gtk_widget_get_style_context (widget), gdk_window);
- gdk_window_enable_synchronized_configure (gdk_window);
return;
}
@@ -5238,8 +5239,6 @@ gtk_window_realize (GtkWidget *widget)
gdk_window = gdk_window_new (parent_window, &attributes, attributes_mask);
gtk_widget_set_window (widget, gdk_window);
- gdk_window_enable_synchronized_configure (gdk_window);
-
gtk_widget_register_window (widget, gdk_window);
context = gtk_widget_get_style_context (widget);
@@ -5580,7 +5579,6 @@ gtk_window_configure_event (GtkWidget *widget,
if (GTK_WIDGET_CLASS (gtk_window_parent_class)->configure_event)
return GTK_WIDGET_CLASS (gtk_window_parent_class)->configure_event (widget, event);
- gdk_window_configure_finished (gtk_widget_get_window (widget));
return FALSE;
}
@@ -5614,7 +5612,6 @@ gtk_window_configure_event (GtkWidget *widget,
(allocation.width == event->width &&
allocation.height == event->height))
{
- gdk_window_configure_finished (gtk_widget_get_window (widget));
return TRUE;
}
@@ -7153,10 +7150,6 @@ gtk_window_move_resize (GtkWindow *window)
set_grip_position (window);
update_grip_visibility (window);
- gdk_window_process_updates (gdk_window, TRUE);
-
- gdk_window_configure_finished (gdk_window);
-
/* If the configure request changed, it means that
* we either:
* 1) coincidentally changed hints or widget properties
@@ -8345,6 +8338,7 @@ gtk_window_set_theme_variant (GtkWindow *window)
#endif
}
+#ifdef GDK_WINDOWING_X11
static void
gtk_window_on_theme_variant_changed (GtkSettings *settings,
GParamSpec *pspec,
@@ -8353,6 +8347,7 @@ gtk_window_on_theme_variant_changed (GtkSettings *settings,
if (window->priv->type == GTK_WINDOW_TOPLEVEL)
gtk_window_set_theme_variant (window);
}
+#endif
static void
gtk_window_on_composited_changed (GdkScreen *screen,
diff --git a/gtk/tests/filechooser.c b/gtk/tests/filechooser.c
index 92b7f96844..8aa5993793 100644
--- a/gtk/tests/filechooser.c
+++ b/gtk/tests/filechooser.c
@@ -37,6 +37,7 @@
#include "gtk/gtkfilechooserdefault.h"
#include "gtk/gtkfilechooserentry.h"
+#ifdef BROKEN_TESTS
static void
log_test (gboolean passed, const char *test_name, ...)
{
@@ -77,6 +78,7 @@ set_filename_timeout_cb (gpointer data)
return FALSE;
}
+#endif
static guint wait_for_idle_id = 0;
@@ -100,6 +102,7 @@ wait_for_idle (void)
gtk_main_iteration ();
}
+#ifdef BROKEN_TESTS
static void
test_set_filename (GtkFileChooserAction action,
gboolean focus_button,
@@ -230,6 +233,7 @@ test_black_box_set_current_name (gconstpointer data)
g_free (cwd);
}
+#endif
/* FIXME: fails in CREATE_FOLDER mode when FOLDER_NAME == "/" */
@@ -253,6 +257,7 @@ test_black_box_set_current_name (gconstpointer data)
* http://bugzilla.gnome.org/show_bug.cgi?id=346058
*/
+#ifdef BROKEN_TESTS
static void
setup_set_filename_tests (void)
{
@@ -288,6 +293,7 @@ setup_set_current_name_tests (void)
for (i = 0; i < G_N_ELEMENTS (tests); i++)
g_test_add_data_func (tests[i].test_name, &tests[i], test_black_box_set_current_name);
}
+#endif
typedef struct
{
@@ -376,6 +382,8 @@ test_file_chooser_button (gconstpointer data)
GtkWidget *window;
GtkWidget *fc_button;
GtkWidget *fc_dialog;
+ int iterations;
+ int i;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
@@ -392,54 +400,66 @@ test_file_chooser_button (gconstpointer data)
gtk_widget_show_all (window);
wait_for_idle ();
+ /* If there is a dialog to be opened, we actually test going through it a
+ * couple of times. This ensures that any state that the button frobs for
+ * each appearance of the dialog will make sense.
+ */
if (setup->open_dialog)
+ iterations = 2;
+ else
+ iterations = 1;
+
+ for (i = 0; i < iterations; i++)
{
- GList *children;
+ if (setup->open_dialog)
+ {
+ GList *children;
- /* Hack our way into the file chooser button; get its GtkButton child and click it */
- children = gtk_container_get_children (GTK_CONTAINER (fc_button));
- g_assert (children && GTK_IS_BUTTON (children->data));
- gtk_button_clicked (GTK_BUTTON (children->data));
- g_list_free (children);
+ /* Hack our way into the file chooser button; get its GtkButton child and click it */
+ children = gtk_container_get_children (GTK_CONTAINER (fc_button));
+ g_assert (children && GTK_IS_BUTTON (children->data));
+ gtk_button_clicked (GTK_BUTTON (children->data));
+ g_list_free (children);
- wait_for_idle ();
+ sleep_in_main_loop ();
- /* Give me the internal dialog, damnit */
- fc_dialog = g_object_get_qdata (G_OBJECT (fc_button), delegate_get_quark ());
- g_assert (GTK_IS_FILE_CHOOSER (fc_dialog));
- g_assert (GTK_IS_DIALOG (fc_dialog));
- }
+ /* Give me the internal dialog, damnit */
+ fc_dialog = g_object_get_qdata (G_OBJECT (fc_button), delegate_get_quark ());
+ g_assert (GTK_IS_FILE_CHOOSER (fc_dialog));
+ g_assert (GTK_IS_DIALOG (fc_dialog));
+ }
- /* Okay, now frob the button and its optional dialog */
+ /* Okay, now frob the button and its optional dialog */
- if (setup->tweak_current_folder)
- gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (fc_button), setup->tweak_current_folder);
+ if (setup->tweak_current_folder)
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (fc_button), setup->tweak_current_folder);
- if (setup->tweak_filename)
- gtk_file_chooser_select_filename (GTK_FILE_CHOOSER (fc_button), setup->tweak_filename);
+ if (setup->tweak_filename)
+ gtk_file_chooser_select_filename (GTK_FILE_CHOOSER (fc_button), setup->tweak_filename);
- sleep_in_main_loop ();
+ sleep_in_main_loop ();
- if (setup->open_dialog)
- {
- gtk_dialog_response (GTK_DIALOG (fc_dialog), setup->dialog_response);
- wait_for_idle ();
- }
+ if (setup->open_dialog)
+ {
+ gtk_dialog_response (GTK_DIALOG (fc_dialog), setup->dialog_response);
+ wait_for_idle ();
+ }
- if (setup->final_current_folder)
- {
- char *folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (fc_button));
+ if (setup->final_current_folder)
+ {
+ char *folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (fc_button));
- g_assert_cmpstr (folder, ==, setup->final_current_folder);
- g_free (folder);
- }
+ g_assert_cmpstr (folder, ==, setup->final_current_folder);
+ g_free (folder);
+ }
- if (setup->final_filename)
- {
- char *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (fc_button));
+ if (setup->final_filename)
+ {
+ char *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (fc_button));
- g_assert_cmpstr (filename, ==, setup->final_filename);
- g_free (filename);
+ g_assert_cmpstr (filename, ==, setup->final_filename);
+ g_free (filename);
+ }
}
gtk_widget_destroy (window);
@@ -696,6 +716,81 @@ static FileChooserButtonTest button_tests[] =
NULL /* final_filename */
},
+ /* OPEN tests with dialog, cancelled via closing the dialog (not by selecting the Cancel button) */
+
+ {
+ "open-dialog-close-1",
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ NULL, /* initial_current_folder */
+ NULL, /* initial_filename */
+ TRUE, /* open_dialog */
+ NULL, /* tweak_current_folder */
+ NULL, /* tweak_filename */
+ GTK_RESPONSE_DELETE_EVENT,/* dialog_response */
+ NULL, /* final_current_folder */
+ NULL /* final_filename */
+ },
+ {
+ "open-dialog-close-2",
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ NULL, /* initial_current_folder */
+ FILE_NAME, /* initial_filename */
+ TRUE, /* open_dialog */
+ NULL, /* tweak_current_folder */
+ NULL, /* tweak_filename */
+ GTK_RESPONSE_DELETE_EVENT,/* dialog_response */
+ NULL, /* final_current_folder */
+ FILE_NAME /* final_filename */
+ },
+ {
+ "open-dialog-close-3",
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ FOLDER_NAME, /* initial_current_folder */
+ NULL, /* initial_filename */
+ TRUE, /* open_dialog */
+ NULL, /* tweak_current_folder */
+ NULL, /* tweak_filename */
+ GTK_RESPONSE_DELETE_EVENT,/* dialog_response */
+ FOLDER_NAME, /* final_current_folder */
+ NULL /* final_filename */
+ },
+ {
+ "open-dialog-close-4",
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ NULL, /* initial_current_folder */
+ NULL, /* initial_filename */
+ TRUE, /* open_dialog */
+ NULL, /* tweak_current_folder */
+ FILE_NAME, /* tweak_filename */
+ GTK_RESPONSE_DELETE_EVENT,/* dialog_response */
+ NULL, /* final_current_folder */
+ NULL /* final_filename */
+ },
+ {
+ "open-dialog-close-5",
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ NULL, /* initial_current_folder */
+ FILE_NAME, /* initial_filename */
+ TRUE, /* open_dialog */
+ NULL, /* tweak_current_folder */
+ FILE_NAME_2, /* tweak_filename */
+ GTK_RESPONSE_DELETE_EVENT,/* dialog_response */
+ NULL, /* final_current_folder */
+ FILE_NAME /* final_filename */
+ },
+ {
+ "open-dialog-close-6",
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ FOLDER_NAME, /* initial_current_folder */
+ NULL, /* initial_filename */
+ TRUE, /* open_dialog */
+ NULL, /* tweak_current_folder */
+ FILE_NAME_2, /* tweak_filename */
+ GTK_RESPONSE_DELETE_EVENT,/* dialog_response */
+ FOLDER_NAME, /* final_current_folder */
+ NULL /* final_filename */
+ },
+
/* SELECT_FOLDER tests with dialog, cancelled */
{
@@ -768,7 +863,7 @@ static FileChooserButtonTest button_tests[] =
FOLDER_NAME_2, /* tweak_filename */
GTK_RESPONSE_CANCEL, /* dialog_response */
NULL, /* final_current_folder */
- FOLDER_NAME /* final_filename */
+ FOLDER_NAME /* final_filename */
},
{
"select-folder-dialog-cancel-7",
@@ -795,6 +890,105 @@ static FileChooserButtonTest button_tests[] =
FOLDER_NAME /* final_filename */
},
+ /* SELECT_FOLDER tests with dialog, cancelled via closing the dialog (not selecting the Cancel button) */
+
+ {
+ "select-folder-dialog-close-1",
+ GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+ NULL, /* initial_current_folder */
+ NULL, /* initial_filename */
+ TRUE, /* open_dialog */
+ NULL, /* tweak_current_folder */
+ NULL, /* tweak_filename */
+ GTK_RESPONSE_DELETE_EVENT,/* dialog_response */
+ NULL, /* final_current_folder */
+ NULL /* final_filename */
+ },
+ {
+ "select-folder-dialog-close-2",
+ GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+ NULL, /* initial_current_folder */
+ FOLDER_NAME, /* initial_filename */
+ TRUE, /* open_dialog */
+ NULL, /* tweak_current_folder */
+ NULL, /* tweak_filename */
+ GTK_RESPONSE_DELETE_EVENT,/* dialog_response */
+ NULL, /* final_current_folder */
+ FOLDER_NAME /* final_filename */
+ },
+ {
+ "select-folder-dialog-close-3",
+ GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+ FOLDER_NAME, /* initial_current_folder */
+ NULL, /* initial_filename */
+ TRUE, /* open_dialog */
+ NULL, /* tweak_current_folder */
+ NULL, /* tweak_filename */
+ GTK_RESPONSE_DELETE_EVENT,/* dialog_response */
+ FOLDER_NAME, /* final_current_folder */
+ NULL /* final_filename */
+ },
+ {
+ "select-folder-dialog-close-4",
+ GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+ FOLDER_NAME, /* initial_current_folder */
+ NULL, /* initial_filename */
+ TRUE, /* open_dialog */
+ NULL, /* tweak_current_folder */
+ NULL, /* tweak_filename */
+ GTK_RESPONSE_DELETE_EVENT,/* dialog_response */
+ NULL, /* final_current_folder */
+ FOLDER_NAME /* final_filename */
+ },
+ {
+ "select-folder-dialog-close-5",
+ GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+ NULL, /* initial_current_folder */
+ NULL, /* initial_filename */
+ TRUE, /* open_dialog */
+ NULL, /* tweak_current_folder */
+ FOLDER_NAME, /* tweak_filename */
+ GTK_RESPONSE_DELETE_EVENT,/* dialog_response */
+ NULL, /* final_current_folder */
+ NULL /* final_filename */
+ },
+ {
+ "select-folder-dialog-close-6",
+ GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+ NULL, /* initial_current_folder */
+ FOLDER_NAME, /* initial_filename */
+ TRUE, /* open_dialog */
+ NULL, /* tweak_current_folder */
+ FOLDER_NAME_2, /* tweak_filename */
+ GTK_RESPONSE_DELETE_EVENT,/* dialog_response */
+ NULL, /* final_current_folder */
+ FOLDER_NAME /* final_filename */
+ },
+ {
+ "select-folder-dialog-close-7",
+ GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+ FOLDER_NAME, /* initial_current_folder */
+ NULL, /* initial_filename */
+ TRUE, /* open_dialog */
+ NULL, /* tweak_current_folder */
+ FOLDER_NAME_2, /* tweak_filename */
+ GTK_RESPONSE_DELETE_EVENT,/* dialog_response */
+ FOLDER_NAME, /* final_current_folder */
+ NULL /* final_filename */
+ },
+ {
+ "select-folder-dialog-close-8",
+ GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+ FOLDER_NAME, /* initial_current_folder */
+ NULL, /* initial_filename */
+ TRUE, /* open_dialog */
+ NULL, /* tweak_current_folder */
+ FOLDER_NAME_2, /* tweak_filename */
+ GTK_RESPONSE_DELETE_EVENT,/* dialog_response */
+ NULL, /* final_current_folder */
+ FOLDER_NAME /* final_filename */
+ },
+
/* OPEN tests with dialog */
{
@@ -914,6 +1108,7 @@ setup_file_chooser_button_tests (void)
}
}
+#ifdef BROKEN_TESTS
struct confirm_overwrite_closure {
GtkWidget *chooser;
GtkWidget *accept_button;
@@ -1052,6 +1247,7 @@ test_confirm_overwrite (void)
passed = passed && test_confirm_overwrite_for_path ("/etc/resolv.conf", TRUE);
g_assert (passed);
}
+#endif
static const GtkFileChooserAction open_actions[] = {
GTK_FILE_CHOOSER_ACTION_OPEN,
@@ -1064,6 +1260,7 @@ static const GtkFileChooserAction save_actions[] = {
};
+#ifdef BROKEN_TESTS
static gboolean
has_action (const GtkFileChooserAction *actions,
int n_actions,
@@ -1116,7 +1313,7 @@ get_impl_from_dialog (GtkWidget *dialog)
return impl;
}
-#ifdef BROKEN_TESTS
+
static gboolean
test_widgets_for_current_action (GtkFileChooserDialog *dialog,
GtkFileChooserAction expected_action)
@@ -1439,7 +1636,6 @@ test_reload (void)
log_test (passed, "test_reload(): set a folder explicitly before mapping");
g_assert (passed);
}
-#endif
static gboolean
test_button_folder_states_for_action (GtkFileChooserAction action, gboolean use_dialog, gboolean set_folder_on_dialog)
@@ -1668,6 +1864,7 @@ test_folder_switch_and_filters (void)
log_test (passed, "test_folder_switch_and_filters(): all filter tests");
}
+#endif
int
main (int argc,
diff --git a/gtk/tests/treeview-scrolling.c b/gtk/tests/treeview-scrolling.c
index e18174d2a9..77dca9abc4 100644
--- a/gtk/tests/treeview-scrolling.c
+++ b/gtk/tests/treeview-scrolling.c
@@ -479,6 +479,17 @@ test_position (GtkTreeView *tree_view,
/* Testing scrolling to various positions with various alignments */
static void
+ensure_layout (void)
+{
+ /* HACK: sleep for more than one frame, to give the paint clock
+ * time to prepare the new layout */
+ g_usleep (100 * 1000);
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+}
+
+static void
scroll (ScrollFixture *fixture,
GtkTreePath *path,
gboolean use_align,
@@ -492,9 +503,7 @@ scroll (ScrollFixture *fixture,
gtk_widget_show_all (fixture->window);
- while (gtk_events_pending ())
- gtk_main_iteration ();
-
+ ensure_layout ();
test_position (GTK_TREE_VIEW (fixture->tree_view), path,
use_align, row_align);
}
@@ -561,9 +570,7 @@ scroll_after_realize (ScrollFixture *fixture,
path, NULL,
use_align, row_align, 0.0);
- while (gtk_events_pending ())
- gtk_main_iteration ();
-
+ ensure_layout ();
test_position (GTK_TREE_VIEW (fixture->tree_view), path,
use_align, row_align);
}
@@ -643,9 +650,7 @@ scroll_both_realize (ScrollFixture *fixture,
path, NULL,
use_align, row_align, 0.0);
- while (gtk_events_pending ())
- gtk_main_iteration ();
-
+ ensure_layout ();
test_position (GTK_TREE_VIEW (fixture->tree_view), path,
use_align, row_align);
}
@@ -812,8 +817,7 @@ scroll_new_row (ScrollFixture *fixture,
column,
TRUE);
- while (gtk_events_pending ())
- gtk_main_iteration ();
+ ensure_layout ();
/* Test position */
test_position (GTK_TREE_VIEW (fixture->tree_view), scroll_path,
@@ -865,8 +869,7 @@ scroll_new_row_tree (ScrollFixture *fixture,
scroll_path, NULL, FALSE, 0.0, 0.0);
gtk_tree_path_free (scroll_path);
- while (gtk_events_pending ())
- gtk_main_iteration ();
+ ensure_layout ();
/* Test position, the scroll bar must be at the end */
g_assert (gtk_adjustment_get_value (vadjustment) == gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment));
@@ -1013,6 +1016,9 @@ test_bug93584 (ScrollFixture *fixture,
row = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL);
row -= 20;
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
path = gtk_tree_path_new_from_indices (row, -1);
scroll (fixture, path, TRUE, 0.5);
gtk_tree_path_free (path);
diff --git a/gtk/updateiconcache.c b/gtk/updateiconcache.c
index d3ebd2c117..effea7c6c6 100644
--- a/gtk/updateiconcache.c
+++ b/gtk/updateiconcache.c
@@ -574,6 +574,23 @@ maybe_cache_icon_data (Image *image,
}
}
+/**
+ * Finds all dir separators and replaces them with '/'.
+ * This makes sure that only /-separated paths are written in cache files,
+ * maintaining compatibility with theme index files that use slashes as
+ * directory separators on all platforms.
+ */
+static void
+replace_backslashes_with_slashes (gchar *path)
+{
+ size_t i;
+ if (path == NULL)
+ return;
+ for (i = 0; path[i]; i++)
+ if (G_IS_DIR_SEPARATOR (path[i]))
+ path[i] = '/';
+}
+
static GList *
scan_directory (const gchar *base_path,
const gchar *subdir,
@@ -588,7 +605,7 @@ scan_directory (const gchar *base_path,
gboolean dir_added = FALSE;
guint dir_index = 0xffff;
- dir_path = g_build_filename (base_path, subdir, NULL);
+ dir_path = g_build_path ("/", base_path, subdir, NULL);
/* FIXME: Use the gerror */
dir = g_dir_open (dir_path, 0, NULL);
@@ -607,13 +624,14 @@ scan_directory (const gchar *base_path,
gchar *basename, *dot;
path = g_build_filename (dir_path, name, NULL);
+
retval = g_file_test (path, G_FILE_TEST_IS_DIR);
if (retval)
{
gchar *subsubdir;
if (subdir)
- subsubdir = g_build_filename (subdir, name, NULL);
+ subsubdir = g_build_path ("/", subdir, name, NULL);
else
subsubdir = g_strdup (name);
directories = scan_directory (base_path, subsubdir, files,
@@ -1736,6 +1754,7 @@ main (int argc, char **argv)
if (!force_update && is_cache_up_to_date (path))
return 0;
+ replace_backslashes_with_slashes (path);
build_cache (path);
if (strcmp (var_name, "-") != 0)