diff options
author | Federico Mena Quintero <federico@gnome.org> | 2013-02-27 10:29:35 -0600 |
---|---|---|
committer | Federico Mena Quintero <federico@gnome.org> | 2013-02-27 10:29:35 -0600 |
commit | a46976fb79dac40288727bdaa4a5a231d9edddf3 (patch) | |
tree | fc98b941229179c12561efeeb14ff7e528e8c929 /gtk | |
parent | 936045e82bc9a3f2b09612e3c22799c45b101c5e (diff) | |
parent | bbfc8f9a9b84cc019dff0c23d52aac83beb6be64 (diff) | |
download | gtk+-a46976fb79dac40288727bdaa4a5a231d9edddf3.tar.gz |
Merge branch 'origin/master' into places-sidebar
Diffstat (limited to 'gtk')
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) |