X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtktreeviewcolumn.c;h=af2317cab7250bf3d0be3599a948e339ffad828c;hb=d97861bd8b338c3d25d7ffb5496edee9eee9bfbb;hp=7f75f2c8c3275ab4d47b23158a99fba3031d0457;hpb=5f1b5d24067468fc86b28dccc504c71abdaf68b8;p=~andy%2Fgtk diff --git a/gtk/gtktreeviewcolumn.c b/gtk/gtktreeviewcolumn.c index 7f75f2c8c..af2317cab 100644 --- a/gtk/gtktreeviewcolumn.c +++ b/gtk/gtktreeviewcolumn.c @@ -12,70 +12,49 @@ * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ #include "config.h" -#include + #include "gtktreeviewcolumn.h" + +#include + #include "gtktreeview.h" #include "gtktreeprivate.h" #include "gtkcelllayout.h" #include "gtkbutton.h" #include "gtkalignment.h" #include "gtklabel.h" -#include "gtkhbox.h" +#include "gtkbox.h" #include "gtkmarshalers.h" #include "gtkarrow.h" +#include "gtkcellareacontext.h" +#include "gtkcellareabox.h" #include "gtkprivate.h" #include "gtkintl.h" +#include "gtktypebuiltins.h" +#include "a11y/gtktreeviewaccessibleprivate.h" -enum -{ - PROP_0, - PROP_VISIBLE, - PROP_RESIZABLE, - PROP_WIDTH, - PROP_SPACING, - PROP_SIZING, - PROP_FIXED_WIDTH, - PROP_MIN_WIDTH, - PROP_MAX_WIDTH, - PROP_TITLE, - PROP_EXPAND, - PROP_CLICKABLE, - PROP_WIDGET, - PROP_ALIGNMENT, - PROP_REORDERABLE, - PROP_SORT_INDICATOR, - PROP_SORT_ORDER, - PROP_SORT_COLUMN_ID -}; - -enum -{ - CLICKED, - LAST_SIGNAL -}; +/** + * SECTION:gtktreeviewcolumn + * @Short_description: A visible column in a GtkTreeView widget + * @Title: GtkTreeViewColumn + * @See_also: #GtkTreeView, #GtkTreeSelection, #GtkTreeDnd, #GtkTreeMode, #GtkTreeSortable, + * #GtkTreeModelSort, #GtkListStore, #GtkTreeStore, #GtkCellRenderer, #GtkCellEditable, + * #GtkCellRendererPixbuf, #GtkCellRendererText, #GtkCellRendererToggle + * + * The GtkTreeViewColumn object represents a visible column in a #GtkTreeView widget. + * It allows to set properties of the column header, and functions as a holding pen for + * the cell renderers which determine how the data in the column is displayed. + * + * Please refer to the tree widget conceptual overview + * for an overview of all the objects and data types related to the tree widget and how + * they work together. + */ -typedef struct _GtkTreeViewColumnCellInfo GtkTreeViewColumnCellInfo; -struct _GtkTreeViewColumnCellInfo -{ - GtkCellRenderer *cell; - GSList *attributes; - GtkTreeCellDataFunc func; - gpointer func_data; - GDestroyNotify destroy; - gint requested_width; - gint real_width; - guint expand : 1; - guint pack : 1; - guint has_focus : 1; - guint in_editing_mode : 1; -}; /* Type methods */ static void gtk_tree_view_column_cell_layout_init (GtkCellLayoutIface *iface); @@ -90,30 +69,16 @@ static void gtk_tree_view_column_get_property (GObject GValue *value, GParamSpec *pspec); static void gtk_tree_view_column_finalize (GObject *object); +static void gtk_tree_view_column_dispose (GObject *object); +static GObject *gtk_tree_view_column_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties); /* GtkCellLayout implementation */ -static void gtk_tree_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout, - GtkCellRenderer *cell, - gboolean expand); -static void gtk_tree_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout, - GtkCellRenderer *cell, - gboolean expand); -static void gtk_tree_view_column_cell_layout_clear (GtkCellLayout *cell_layout); -static void gtk_tree_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout, - GtkCellRenderer *cell, - const gchar *attribute, - gint column); -static void gtk_tree_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout, - GtkCellRenderer *cell, - GtkCellLayoutDataFunc func, - gpointer func_data, - GDestroyNotify destroy); -static void gtk_tree_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout, - GtkCellRenderer *cell); -static void gtk_tree_view_column_cell_layout_reorder (GtkCellLayout *cell_layout, - GtkCellRenderer *cell, - gint position); -static GList *gtk_tree_view_column_cell_layout_get_cells (GtkCellLayout *cell_layout); +static void gtk_tree_view_column_ensure_cell_area (GtkTreeViewColumn *column, + GtkCellArea *cell_area); + +static GtkCellArea *gtk_tree_view_column_cell_layout_get_area (GtkCellLayout *cell_layout); /* Button handling code */ static void gtk_tree_view_column_create_button (GtkTreeViewColumn *tree_column); @@ -133,6 +98,21 @@ static gboolean gtk_tree_view_column_mnemonic_activate (GtkWidget *widge static void gtk_tree_view_model_sort_column_changed (GtkTreeSortable *sortable, GtkTreeViewColumn *tree_column); +/* GtkCellArea/GtkCellAreaContext callbacks */ +static void gtk_tree_view_column_context_changed (GtkCellAreaContext *context, + GParamSpec *pspec, + GtkTreeViewColumn *tree_column); +static void gtk_tree_view_column_add_editable_callback (GtkCellArea *area, + GtkCellRenderer *renderer, + GtkCellEditable *edit_widget, + GdkRectangle *cell_area, + const gchar *path_string, + gpointer user_data); +static void gtk_tree_view_column_remove_editable_callback (GtkCellArea *area, + GtkCellRenderer *renderer, + GtkCellEditable *edit_widget, + gpointer user_data); + /* Internal functions */ static void gtk_tree_view_column_sort (GtkTreeViewColumn *tree_column, gpointer data); @@ -140,24 +120,95 @@ static void gtk_tree_view_column_setup_sort_column_id_callback (GtkTreeViewColum static void gtk_tree_view_column_set_attributesv (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell_renderer, va_list args); -static GtkTreeViewColumnCellInfo *gtk_tree_view_column_get_cell_info (GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell_renderer); - -/* cell list manipulation */ -static GList *gtk_tree_view_column_cell_first (GtkTreeViewColumn *tree_column); -static GList *gtk_tree_view_column_cell_last (GtkTreeViewColumn *tree_column); -static GList *gtk_tree_view_column_cell_next (GtkTreeViewColumn *tree_column, - GList *current); -static GList *gtk_tree_view_column_cell_prev (GtkTreeViewColumn *tree_column, - GList *current); -static void gtk_tree_view_column_clear_attributes_by_info (GtkTreeViewColumn *tree_column, - GtkTreeViewColumnCellInfo *info); + /* GtkBuildable implementation */ static void gtk_tree_view_column_buildable_init (GtkBuildableIface *iface); + +struct _GtkTreeViewColumnPrivate +{ + GtkWidget *tree_view; + GtkWidget *button; + GtkWidget *child; + GtkWidget *arrow; + GtkWidget *alignment; + GdkWindow *window; + gfloat xalign; + gulong property_changed_signal; + + /* Sizing fields */ + /* see gtk+/doc/tree-column-sizing.txt for more information on them */ + GtkTreeViewColumnSizing column_type; + gint padding; + gint x_offset; + gint width; + gint fixed_width; + gint min_width; + gint max_width; + + /* dragging columns */ + gint drag_x; + gint drag_y; + + gchar *title; + + /* Sorting */ + gulong sort_clicked_signal; + gulong sort_column_changed_signal; + gint sort_column_id; + GtkSortType sort_order; + + /* Cell area */ + GtkCellArea *cell_area; + GtkCellAreaContext *cell_area_context; + gulong add_editable_signal; + gulong remove_editable_signal; + gulong context_changed_signal; + + /* Flags */ + guint visible : 1; + guint resizable : 1; + guint clickable : 1; + guint dirty : 1; + guint show_sort_indicator : 1; + guint maybe_reordered : 1; + guint reorderable : 1; + guint expand : 1; +}; + +enum +{ + PROP_0, + PROP_VISIBLE, + PROP_RESIZABLE, + PROP_X_OFFSET, + PROP_WIDTH, + PROP_SPACING, + PROP_SIZING, + PROP_FIXED_WIDTH, + PROP_MIN_WIDTH, + PROP_MAX_WIDTH, + PROP_TITLE, + PROP_EXPAND, + PROP_CLICKABLE, + PROP_WIDGET, + PROP_ALIGNMENT, + PROP_REORDERABLE, + PROP_SORT_INDICATOR, + PROP_SORT_ORDER, + PROP_SORT_COLUMN_ID, + PROP_CELL_AREA +}; + +enum +{ + CLICKED, + LAST_SIGNAL +}; + static guint tree_column_signals[LAST_SIGNAL] = { 0 }; -G_DEFINE_TYPE_WITH_CODE (GtkTreeViewColumn, gtk_tree_view_column, GTK_TYPE_OBJECT, +G_DEFINE_TYPE_WITH_CODE (GtkTreeViewColumn, gtk_tree_view_column, G_TYPE_INITIALLY_UNOWNED, G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT, gtk_tree_view_column_cell_layout_init) G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, @@ -173,7 +224,9 @@ gtk_tree_view_column_class_init (GtkTreeViewColumnClass *class) class->clicked = NULL; + object_class->constructor = gtk_tree_view_column_constructor; object_class->finalize = gtk_tree_view_column_finalize; + object_class->dispose = gtk_tree_view_column_dispose; object_class->set_property = gtk_tree_view_column_set_property; object_class->get_property = gtk_tree_view_column_get_property; @@ -202,6 +255,16 @@ gtk_tree_view_column_class_init (GtkTreeViewColumnClass *class) FALSE, GTK_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_X_OFFSET, + g_param_spec_int ("x-offset", + P_("X position"), + P_("Current X position of the column"), + -G_MAXINT, + G_MAXINT, + 0, + GTK_PARAM_READABLE)); + g_object_class_install_property (object_class, PROP_WIDTH, g_param_spec_int ("width", @@ -234,9 +297,9 @@ gtk_tree_view_column_class_init (GtkTreeViewColumnClass *class) g_param_spec_int ("fixed-width", P_("Fixed Width"), P_("Current fixed width of the column"), - 1, + -1, G_MAXINT, - 1, /* not useful */ + -1, GTK_PARAM_READWRITE)); g_object_class_install_property (object_class, @@ -331,7 +394,7 @@ gtk_tree_view_column_class_init (GtkTreeViewColumnClass *class) * GtkTreeViewColumn:sort-column-id: * * Logical sort column ID this column sorts on when selected for sorting. Setting the sort column ID makes the column header - * clickable. Set to %-1 to make the column unsortable. + * clickable. Set to -1 to make the column unsortable. * * Since: 2.18 **/ @@ -344,6 +407,37 @@ gtk_tree_view_column_class_init (GtkTreeViewColumnClass *class) G_MAXINT, -1, GTK_PARAM_READWRITE)); + + /** + * GtkTreeViewColumn:cell-area: + * + * The #GtkCellArea used to layout cell renderers for this column. + * + * If no area is specified when creating the tree view column with gtk_tree_view_column_new_with_area() + * a horizontally oriented #GtkCellAreaBox will be used. + * + * Since: 3.0 + */ + g_object_class_install_property (object_class, + PROP_CELL_AREA, + g_param_spec_object ("cell-area", + P_("Cell Area"), + P_("The GtkCellArea used to layout cells"), + GTK_TYPE_CELL_AREA, + GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_type_class_add_private (class, sizeof (GtkTreeViewColumnPrivate)); +} + +static void +gtk_tree_view_column_custom_tag_end (GtkBuildable *buildable, + GtkBuilder *builder, + GObject *child, + const gchar *tagname, + gpointer *data) +{ + /* Just ignore the boolean return from here */ + _gtk_cell_layout_buildable_custom_tag_end (buildable, builder, child, tagname, data); } static void @@ -351,79 +445,119 @@ gtk_tree_view_column_buildable_init (GtkBuildableIface *iface) { iface->add_child = _gtk_cell_layout_buildable_add_child; iface->custom_tag_start = _gtk_cell_layout_buildable_custom_tag_start; - iface->custom_tag_end = _gtk_cell_layout_buildable_custom_tag_end; + iface->custom_tag_end = gtk_tree_view_column_custom_tag_end; } static void gtk_tree_view_column_cell_layout_init (GtkCellLayoutIface *iface) { - iface->pack_start = gtk_tree_view_column_cell_layout_pack_start; - iface->pack_end = gtk_tree_view_column_cell_layout_pack_end; - iface->clear = gtk_tree_view_column_cell_layout_clear; - iface->add_attribute = gtk_tree_view_column_cell_layout_add_attribute; - iface->set_cell_data_func = gtk_tree_view_column_cell_layout_set_cell_data_func; - iface->clear_attributes = gtk_tree_view_column_cell_layout_clear_attributes; - iface->reorder = gtk_tree_view_column_cell_layout_reorder; - iface->get_cells = gtk_tree_view_column_cell_layout_get_cells; + iface->get_area = gtk_tree_view_column_cell_layout_get_area; } static void gtk_tree_view_column_init (GtkTreeViewColumn *tree_column) { - tree_column->button = NULL; - tree_column->xalign = 0.0; - tree_column->width = 0; - tree_column->spacing = 0; - tree_column->requested_width = -1; - tree_column->min_width = -1; - tree_column->max_width = -1; - tree_column->resized_width = 0; - tree_column->column_type = GTK_TREE_VIEW_COLUMN_GROW_ONLY; - tree_column->visible = TRUE; - tree_column->resizable = FALSE; - tree_column->expand = FALSE; - tree_column->clickable = FALSE; - tree_column->dirty = TRUE; - tree_column->sort_order = GTK_SORT_ASCENDING; - tree_column->show_sort_indicator = FALSE; - tree_column->property_changed_signal = 0; - tree_column->sort_clicked_signal = 0; - tree_column->sort_column_changed_signal = 0; - tree_column->sort_column_id = -1; - tree_column->reorderable = FALSE; - tree_column->maybe_reordered = FALSE; - tree_column->fixed_width = 1; - tree_column->use_resized_width = FALSE; - tree_column->title = g_strdup (""); + GtkTreeViewColumnPrivate *priv; + + tree_column->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_column, + GTK_TYPE_TREE_VIEW_COLUMN, + GtkTreeViewColumnPrivate); + priv = tree_column->priv; + + priv->button = NULL; + priv->xalign = 0.0; + priv->width = 0; + priv->padding = -1; + priv->min_width = -1; + priv->max_width = -1; + priv->column_type = GTK_TREE_VIEW_COLUMN_GROW_ONLY; + priv->visible = TRUE; + priv->resizable = FALSE; + priv->expand = FALSE; + priv->clickable = FALSE; + priv->dirty = TRUE; + priv->sort_order = GTK_SORT_ASCENDING; + priv->show_sort_indicator = FALSE; + priv->property_changed_signal = 0; + priv->sort_clicked_signal = 0; + priv->sort_column_changed_signal = 0; + priv->sort_column_id = -1; + priv->reorderable = FALSE; + priv->maybe_reordered = FALSE; + priv->fixed_width = -1; + priv->title = g_strdup (""); +} + +static GObject * +gtk_tree_view_column_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GtkTreeViewColumn *tree_column; + GObject *object; + + object = G_OBJECT_CLASS (gtk_tree_view_column_parent_class)->constructor + (type, n_construct_properties, construct_properties); + + tree_column = (GtkTreeViewColumn *) object; + + gtk_tree_view_column_ensure_cell_area (tree_column, NULL); + + return object; } static void -gtk_tree_view_column_finalize (GObject *object) +gtk_tree_view_column_dispose (GObject *object) { - GtkTreeViewColumn *tree_column = (GtkTreeViewColumn *) object; - GList *list; + GtkTreeViewColumn *tree_column = (GtkTreeViewColumn *) object; + GtkTreeViewColumnPrivate *priv = tree_column->priv; - for (list = tree_column->cell_list; list; list = list->next) + /* Remove this column from its treeview, + * in case this column is destroyed before its treeview. + */ + if (priv->tree_view) + gtk_tree_view_remove_column (GTK_TREE_VIEW (priv->tree_view), tree_column); + + if (priv->cell_area_context) + { + g_signal_handler_disconnect (priv->cell_area_context, + priv->context_changed_signal); + + g_object_unref (priv->cell_area_context); + + priv->cell_area_context = NULL; + priv->context_changed_signal = 0; + } + + if (priv->cell_area) { - GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data; + g_signal_handler_disconnect (priv->cell_area, + priv->add_editable_signal); + g_signal_handler_disconnect (priv->cell_area, + priv->remove_editable_signal); - if (info->destroy) - { - GDestroyNotify d = info->destroy; + g_object_unref (priv->cell_area); + priv->cell_area = NULL; + priv->add_editable_signal = 0; + priv->remove_editable_signal = 0; + } - info->destroy = NULL; - d (info->func_data); - } - gtk_tree_view_column_clear_attributes_by_info (tree_column, info); - g_object_unref (info->cell); - g_free (info); + if (priv->child) + { + g_object_unref (priv->child); + priv->child = NULL; } - g_free (tree_column->title); - g_list_free (tree_column->cell_list); + G_OBJECT_CLASS (gtk_tree_view_column_parent_class)->dispose (object); +} + +static void +gtk_tree_view_column_finalize (GObject *object) +{ + GtkTreeViewColumn *tree_column = (GtkTreeViewColumn *) object; + GtkTreeViewColumnPrivate *priv = tree_column->priv; - if (tree_column->child) - g_object_unref (tree_column->child); + g_free (priv->title); G_OBJECT_CLASS (gtk_tree_view_column_parent_class)->finalize (object); } @@ -435,6 +569,7 @@ gtk_tree_view_column_set_property (GObject *object, GParamSpec *pspec) { GtkTreeViewColumn *tree_column; + GtkCellArea *area; tree_column = GTK_TREE_VIEW_COLUMN (object); @@ -519,7 +654,24 @@ gtk_tree_view_column_set_property (GObject *object, gtk_tree_view_column_set_sort_column_id (tree_column, g_value_get_int (value)); break; - + + case PROP_CELL_AREA: + /* Construct-only, can only be assigned once */ + area = g_value_get_object (value); + + if (area) + { + if (tree_column->priv->cell_area != NULL) + { + g_warning ("cell-area has already been set, ignoring construct property"); + g_object_ref_sink (area); + g_object_unref (area); + } + else + gtk_tree_view_column_ensure_cell_area (tree_column, area); + } + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -548,6 +700,11 @@ gtk_tree_view_column_get_property (GObject *object, gtk_tree_view_column_get_resizable (tree_column)); break; + case PROP_X_OFFSET: + g_value_set_int (value, + gtk_tree_view_column_get_x_offset (tree_column)); + break; + case PROP_WIDTH: g_value_set_int (value, gtk_tree_view_column_get_width (tree_column)); @@ -622,6 +779,10 @@ gtk_tree_view_column_get_property (GObject *object, g_value_set_int (value, gtk_tree_view_column_get_sort_column_id (tree_column)); break; + + case PROP_CELL_AREA: + g_value_set_object (value, tree_column->priv->cell_area); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -633,234 +794,95 @@ gtk_tree_view_column_get_property (GObject *object, */ static void -gtk_tree_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout, - GtkCellRenderer *cell, - gboolean expand) -{ - GtkTreeViewColumn *column; - GtkTreeViewColumnCellInfo *cell_info; - - g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (cell_layout)); - column = GTK_TREE_VIEW_COLUMN (cell_layout); - g_return_if_fail (! gtk_tree_view_column_get_cell_info (column, cell)); - - g_object_ref_sink (cell); - - cell_info = g_new0 (GtkTreeViewColumnCellInfo, 1); - cell_info->cell = cell; - cell_info->expand = expand ? TRUE : FALSE; - cell_info->pack = GTK_PACK_START; - cell_info->has_focus = 0; - cell_info->attributes = NULL; - - column->cell_list = g_list_append (column->cell_list, cell_info); -} - -static void -gtk_tree_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout, - GtkCellRenderer *cell, - gboolean expand) -{ - GtkTreeViewColumn *column; - GtkTreeViewColumnCellInfo *cell_info; - - g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (cell_layout)); - column = GTK_TREE_VIEW_COLUMN (cell_layout); - g_return_if_fail (! gtk_tree_view_column_get_cell_info (column, cell)); - - g_object_ref_sink (cell); - - cell_info = g_new0 (GtkTreeViewColumnCellInfo, 1); - cell_info->cell = cell; - cell_info->expand = expand ? TRUE : FALSE; - cell_info->pack = GTK_PACK_END; - cell_info->has_focus = 0; - cell_info->attributes = NULL; - - column->cell_list = g_list_append (column->cell_list, cell_info); -} - -static void -gtk_tree_view_column_cell_layout_clear (GtkCellLayout *cell_layout) -{ - GtkTreeViewColumn *column; - - g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (cell_layout)); - column = GTK_TREE_VIEW_COLUMN (cell_layout); - - while (column->cell_list) - { - GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *)column->cell_list->data; - - gtk_tree_view_column_cell_layout_clear_attributes (cell_layout, info->cell); - g_object_unref (info->cell); - g_free (info); - column->cell_list = g_list_delete_link (column->cell_list, - column->cell_list); - } -} - -static void -gtk_tree_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout, - GtkCellRenderer *cell, - const gchar *attribute, - gint column) -{ - GtkTreeViewColumn *tree_column; - GtkTreeViewColumnCellInfo *info; - - g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (cell_layout)); - tree_column = GTK_TREE_VIEW_COLUMN (cell_layout); - - info = gtk_tree_view_column_get_cell_info (tree_column, cell); - g_return_if_fail (info != NULL); - - info->attributes = g_slist_prepend (info->attributes, GINT_TO_POINTER (column)); - info->attributes = g_slist_prepend (info->attributes, g_strdup (attribute)); - - if (tree_column->tree_view) - _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE); -} - -static void -gtk_tree_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout, - GtkCellRenderer *cell, - GtkCellLayoutDataFunc func, - gpointer func_data, - GDestroyNotify destroy) -{ - GtkTreeViewColumn *column; - GtkTreeViewColumnCellInfo *info; - - g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (cell_layout)); - column = GTK_TREE_VIEW_COLUMN (cell_layout); - - info = gtk_tree_view_column_get_cell_info (column, cell); - g_return_if_fail (info != NULL); - - if (info->destroy) - { - GDestroyNotify d = info->destroy; - - info->destroy = NULL; - d (info->func_data); - } - - info->func = (GtkTreeCellDataFunc)func; - info->func_data = func_data; - info->destroy = destroy; - - if (column->tree_view) - _gtk_tree_view_column_cell_set_dirty (column, TRUE); -} - -static void -gtk_tree_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout, - GtkCellRenderer *cell_renderer) +gtk_tree_view_column_ensure_cell_area (GtkTreeViewColumn *column, + GtkCellArea *cell_area) { - GtkTreeViewColumn *column; - GtkTreeViewColumnCellInfo *info; + GtkTreeViewColumnPrivate *priv = column->priv; - g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (cell_layout)); - column = GTK_TREE_VIEW_COLUMN (cell_layout); - - info = gtk_tree_view_column_get_cell_info (column, cell_renderer); - if (info) - gtk_tree_view_column_clear_attributes_by_info (column, info); -} - -static void -gtk_tree_view_column_cell_layout_reorder (GtkCellLayout *cell_layout, - GtkCellRenderer *cell, - gint position) -{ - GList *link; - GtkTreeViewColumn *column; - GtkTreeViewColumnCellInfo *info; - - g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (cell_layout)); - column = GTK_TREE_VIEW_COLUMN (cell_layout); - - info = gtk_tree_view_column_get_cell_info (column, cell); + if (priv->cell_area) + return; - g_return_if_fail (info != NULL); - g_return_if_fail (position >= 0); + if (cell_area) + priv->cell_area = cell_area; + else + priv->cell_area = gtk_cell_area_box_new (); - link = g_list_find (column->cell_list, info); + g_object_ref_sink (priv->cell_area); - g_return_if_fail (link != NULL); + priv->add_editable_signal = + g_signal_connect (priv->cell_area, "add-editable", + G_CALLBACK (gtk_tree_view_column_add_editable_callback), + column); + priv->remove_editable_signal = + g_signal_connect (priv->cell_area, "remove-editable", + G_CALLBACK (gtk_tree_view_column_remove_editable_callback), + column); - column->cell_list = g_list_delete_link (column->cell_list, link); - column->cell_list = g_list_insert (column->cell_list, info, position); + priv->cell_area_context = gtk_cell_area_create_context (priv->cell_area); - if (column->tree_view) - gtk_widget_queue_draw (column->tree_view); + priv->context_changed_signal = + g_signal_connect (priv->cell_area_context, "notify", + G_CALLBACK (gtk_tree_view_column_context_changed), + column); } -static void -gtk_tree_view_column_clear_attributes_by_info (GtkTreeViewColumn *tree_column, - GtkTreeViewColumnCellInfo *info) +static GtkCellArea * +gtk_tree_view_column_cell_layout_get_area (GtkCellLayout *cell_layout) { - GSList *list; + GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (cell_layout); + GtkTreeViewColumnPrivate *priv = column->priv; - list = info->attributes; - - while (list && list->next) - { - g_free (list->data); - list = list->next->next; - } - g_slist_free (info->attributes); - info->attributes = NULL; + if (G_UNLIKELY (!priv->cell_area)) + gtk_tree_view_column_ensure_cell_area (column, NULL); - if (tree_column->tree_view) - _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE); + return priv->cell_area; } -/* Helper functions - */ - /* Button handling code */ static void gtk_tree_view_column_create_button (GtkTreeViewColumn *tree_column) { + GtkTreeViewColumnPrivate *priv = tree_column->priv; GtkTreeView *tree_view; GtkWidget *child; GtkWidget *hbox; - tree_view = (GtkTreeView *) tree_column->tree_view; + tree_view = (GtkTreeView *) priv->tree_view; g_return_if_fail (GTK_IS_TREE_VIEW (tree_view)); - g_return_if_fail (tree_column->button == NULL); + g_return_if_fail (priv->button == NULL); gtk_widget_push_composite_child (); - tree_column->button = gtk_button_new (); - gtk_widget_add_events (tree_column->button, GDK_POINTER_MOTION_MASK); + priv->button = gtk_button_new (); + if (priv->visible) + gtk_widget_show (priv->button); + gtk_widget_add_events (priv->button, GDK_POINTER_MOTION_MASK); gtk_widget_pop_composite_child (); /* make sure we own a reference to it as well. */ - if (tree_view->priv->header_window) - gtk_widget_set_parent_window (tree_column->button, tree_view->priv->header_window); - gtk_widget_set_parent (tree_column->button, GTK_WIDGET (tree_view)); + if (_gtk_tree_view_get_header_window (tree_view)) + gtk_widget_set_parent_window (priv->button, _gtk_tree_view_get_header_window (tree_view)); - g_signal_connect (tree_column->button, "event", + gtk_widget_set_parent (priv->button, GTK_WIDGET (tree_view)); + + g_signal_connect (priv->button, "event", G_CALLBACK (gtk_tree_view_column_button_event), tree_column); - g_signal_connect (tree_column->button, "clicked", + g_signal_connect (priv->button, "clicked", G_CALLBACK (gtk_tree_view_column_button_clicked), tree_column); - tree_column->alignment = gtk_alignment_new (tree_column->xalign, 0.5, 0.0, 0.0); + priv->alignment = gtk_alignment_new (priv->xalign, 0.5, 0.0, 0.0); - hbox = gtk_hbox_new (FALSE, 2); - tree_column->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN); + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2); + priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN); - if (tree_column->child) - child = tree_column->child; + if (priv->child) + child = priv->child; else { - child = gtk_label_new (tree_column->title); + child = gtk_label_new (priv->title); gtk_widget_show (child); } @@ -868,24 +890,25 @@ gtk_tree_view_column_create_button (GtkTreeViewColumn *tree_column) G_CALLBACK (gtk_tree_view_column_mnemonic_activate), tree_column); - if (tree_column->xalign <= 0.5) - gtk_box_pack_end (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0); + if (priv->xalign <= 0.5) + gtk_box_pack_end (GTK_BOX (hbox), priv->arrow, FALSE, FALSE, 0); else - gtk_box_pack_start (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (hbox), priv->arrow, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX (hbox), tree_column->alignment, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (hbox), priv->alignment, TRUE, TRUE, 0); - gtk_container_add (GTK_CONTAINER (tree_column->alignment), child); - gtk_container_add (GTK_CONTAINER (tree_column->button), hbox); + gtk_container_add (GTK_CONTAINER (priv->alignment), child); + gtk_container_add (GTK_CONTAINER (priv->button), hbox); gtk_widget_show (hbox); - gtk_widget_show (tree_column->alignment); + gtk_widget_show (priv->alignment); gtk_tree_view_column_update_button (tree_column); } static void gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column) { + GtkTreeViewColumnPrivate *priv = tree_column->priv; gint sort_column_id = -1; GtkWidget *hbox; GtkWidget *alignment; @@ -894,38 +917,38 @@ gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column) GtkArrowType arrow_type = GTK_ARROW_NONE; GtkTreeModel *model; - if (tree_column->tree_view) - model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_column->tree_view)); + if (priv->tree_view) + model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree_view)); else model = NULL; /* Create a button if necessary */ - if (tree_column->visible && - tree_column->button == NULL && - tree_column->tree_view && - gtk_widget_get_realized (tree_column->tree_view)) + if (priv->visible && + priv->button == NULL && + priv->tree_view && + gtk_widget_get_realized (priv->tree_view)) gtk_tree_view_column_create_button (tree_column); - if (! tree_column->button) + if (! priv->button) return; - hbox = gtk_bin_get_child (GTK_BIN (tree_column->button)); - alignment = tree_column->alignment; - arrow = tree_column->arrow; + hbox = gtk_bin_get_child (GTK_BIN (priv->button)); + alignment = priv->alignment; + arrow = priv->arrow; current_child = gtk_bin_get_child (GTK_BIN (alignment)); /* Set up the actual button */ - gtk_alignment_set (GTK_ALIGNMENT (alignment), tree_column->xalign, + gtk_alignment_set (GTK_ALIGNMENT (alignment), priv->xalign, 0.5, 0.0, 0.0); - if (tree_column->child) + if (priv->child) { - if (current_child != tree_column->child) + if (current_child != priv->child) { gtk_container_remove (GTK_CONTAINER (alignment), current_child); gtk_container_add (GTK_CONTAINER (alignment), - tree_column->child); + priv->child); } } else @@ -940,9 +963,9 @@ gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column) g_return_if_fail (GTK_IS_LABEL (current_child)); - if (tree_column->title) + if (priv->title) gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child), - tree_column->title); + priv->title); else gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child), ""); @@ -953,15 +976,15 @@ gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column) &sort_column_id, NULL); - if (tree_column->show_sort_indicator) + if (priv->show_sort_indicator) { gboolean alternative; - g_object_get (gtk_widget_get_settings (tree_column->tree_view), + g_object_get (gtk_widget_get_settings (priv->tree_view), "gtk-alternative-sort-arrows", &alternative, NULL); - switch (tree_column->sort_order) + switch (priv->sort_order) { case GTK_SORT_ASCENDING: arrow_type = alternative ? GTK_ARROW_UP : GTK_ARROW_DOWN; @@ -988,7 +1011,7 @@ gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column) g_object_ref (arrow); gtk_container_remove (GTK_CONTAINER (hbox), arrow); - if (tree_column->xalign <= 0.5) + if (priv->xalign <= 0.5) { gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, FALSE, 0); } @@ -1000,52 +1023,54 @@ gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column) } g_object_unref (arrow); - if (tree_column->show_sort_indicator - || (GTK_IS_TREE_SORTABLE (model) && tree_column->sort_column_id >= 0)) + if (priv->show_sort_indicator + || (GTK_IS_TREE_SORTABLE (model) && priv->sort_column_id >= 0)) gtk_widget_show (arrow); else gtk_widget_hide (arrow); /* It's always safe to hide the button. It isn't always safe to show it, as * if you show it before it's realized, it'll get the wrong window. */ - if (tree_column->button && - tree_column->tree_view != NULL && - gtk_widget_get_realized (tree_column->tree_view)) + if (priv->button && + priv->tree_view != NULL && + gtk_widget_get_realized (priv->tree_view)) { - if (tree_column->visible) + if (priv->visible && + gdk_window_is_visible (_gtk_tree_view_get_header_window (GTK_TREE_VIEW (priv->tree_view)))) { - gtk_widget_show_now (tree_column->button); - if (tree_column->window) + gtk_widget_show (priv->button); + + if (priv->window) { - if (tree_column->resizable) + if (priv->resizable) { - gdk_window_show (tree_column->window); - gdk_window_raise (tree_column->window); + gdk_window_show (priv->window); + gdk_window_raise (priv->window); } else { - gdk_window_hide (tree_column->window); + gdk_window_hide (priv->window); } } } else { - gtk_widget_hide (tree_column->button); - if (tree_column->window) - gdk_window_hide (tree_column->window); + gtk_widget_hide (priv->button); + if (priv->window) + gdk_window_hide (priv->window); } } - if (tree_column->reorderable || tree_column->clickable) + if (priv->reorderable || priv->clickable) { - gtk_widget_set_can_focus (tree_column->button, TRUE); + gtk_widget_set_can_focus (priv->button, TRUE); } else { - gtk_widget_set_can_focus (tree_column->button, FALSE); - if (gtk_widget_has_focus (tree_column->button)) + gtk_widget_set_can_focus (priv->button, FALSE); + if (gtk_widget_has_focus (priv->button)) { - GtkWidget *toplevel = gtk_widget_get_toplevel (tree_column->tree_view); + GtkWidget *toplevel = gtk_widget_get_toplevel (priv->tree_view); if (gtk_widget_is_toplevel (toplevel)) { gtk_window_set_focus (GTK_WINDOW (toplevel), NULL); @@ -1055,8 +1080,8 @@ gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column) /* Queue a resize on the assumption that we always want to catch all changes * and columns don't change all that often. */ - if (gtk_widget_get_realized (tree_column->tree_view)) - gtk_widget_queue_resize (tree_column->tree_view); + if (gtk_widget_get_realized (priv->tree_view)) + gtk_widget_queue_resize (priv->tree_view); } @@ -1068,40 +1093,43 @@ gtk_tree_view_column_button_event (GtkWidget *widget, GdkEvent *event, gpointer data) { - GtkTreeViewColumn *column = (GtkTreeViewColumn *) data; + GtkTreeViewColumn *column = (GtkTreeViewColumn *) data; + GtkTreeViewColumnPrivate *priv = column->priv; g_return_val_if_fail (event != NULL, FALSE); if (event->type == GDK_BUTTON_PRESS && - column->reorderable && - ((GdkEventButton *)event)->button == 1) - { - column->maybe_reordered = TRUE; - gdk_window_get_pointer (GTK_BUTTON (widget)->event_window, - &column->drag_x, - &column->drag_y, - NULL); + priv->reorderable && + ((GdkEventButton *)event)->button == GDK_BUTTON_PRIMARY) + { + priv->maybe_reordered = TRUE; + gdk_window_get_device_position (gtk_button_get_event_window (GTK_BUTTON (widget)), + gdk_event_get_device (event), + &priv->drag_x, + &priv->drag_y, + NULL); gtk_widget_grab_focus (widget); } if (event->type == GDK_BUTTON_RELEASE || event->type == GDK_LEAVE_NOTIFY) - column->maybe_reordered = FALSE; + priv->maybe_reordered = FALSE; if (event->type == GDK_MOTION_NOTIFY && - column->maybe_reordered && + priv->maybe_reordered && (gtk_drag_check_threshold (widget, - column->drag_x, - column->drag_y, + priv->drag_x, + priv->drag_y, (gint) ((GdkEventMotion *)event)->x, (gint) ((GdkEventMotion *)event)->y))) { - column->maybe_reordered = FALSE; - _gtk_tree_view_column_start_drag (GTK_TREE_VIEW (column->tree_view), column, + priv->maybe_reordered = FALSE; + _gtk_tree_view_column_start_drag (GTK_TREE_VIEW (priv->tree_view), column, event->motion.device); return TRUE; } - if (column->clickable == FALSE) + + if (priv->clickable == FALSE) { switch (event->type) { @@ -1132,17 +1160,19 @@ gtk_tree_view_column_mnemonic_activate (GtkWidget *widget, gboolean group_cycling, gpointer data) { - GtkTreeViewColumn *column = (GtkTreeViewColumn *)data; + GtkTreeViewColumn *column = (GtkTreeViewColumn *)data; + GtkTreeViewColumnPrivate *priv = column->priv; g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), FALSE); - GTK_TREE_VIEW (column->tree_view)->priv->focus_column = column; - if (column->clickable) - gtk_button_clicked (GTK_BUTTON (column->button)); - else if (gtk_widget_get_can_focus (column->button)) - gtk_widget_grab_focus (column->button); + _gtk_tree_view_set_focus_column (GTK_TREE_VIEW (priv->tree_view), column); + + if (priv->clickable) + gtk_button_clicked (GTK_BUTTON (priv->button)); + else if (gtk_widget_get_can_focus (priv->button)) + gtk_widget_grab_focus (priv->button); else - gtk_widget_grab_focus (column->tree_view); + gtk_widget_grab_focus (priv->tree_view); return TRUE; } @@ -1151,6 +1181,7 @@ static void gtk_tree_view_model_sort_column_changed (GtkTreeSortable *sortable, GtkTreeViewColumn *column) { + GtkTreeViewColumnPrivate *priv = column->priv; gint sort_column_id; GtkSortType order; @@ -1158,7 +1189,7 @@ gtk_tree_view_model_sort_column_changed (GtkTreeSortable *sortable, &sort_column_id, &order)) { - if (sort_column_id == column->sort_column_id) + if (sort_column_id == priv->sort_column_id) { gtk_tree_view_column_set_sort_indicator (column, TRUE); gtk_tree_view_column_set_sort_order (column, order); @@ -1178,74 +1209,80 @@ static void gtk_tree_view_column_sort (GtkTreeViewColumn *tree_column, gpointer data) { + GtkTreeViewColumnPrivate *priv = tree_column->priv; + GtkTreeModel *model; + GtkTreeSortable *sortable; gint sort_column_id; GtkSortType order; gboolean has_sort_column; gboolean has_default_sort_func; - g_return_if_fail (tree_column->tree_view != NULL); + g_return_if_fail (priv->tree_view != NULL); + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree_view)); + sortable = GTK_TREE_SORTABLE (model); has_sort_column = - gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model), + gtk_tree_sortable_get_sort_column_id (sortable, &sort_column_id, &order); has_default_sort_func = - gtk_tree_sortable_has_default_sort_func (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model)); + gtk_tree_sortable_has_default_sort_func (sortable); if (has_sort_column && - sort_column_id == tree_column->sort_column_id) + sort_column_id == priv->sort_column_id) { if (order == GTK_SORT_ASCENDING) - gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model), - tree_column->sort_column_id, + gtk_tree_sortable_set_sort_column_id (sortable, + priv->sort_column_id, GTK_SORT_DESCENDING); else if (order == GTK_SORT_DESCENDING && has_default_sort_func) - gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model), + gtk_tree_sortable_set_sort_column_id (sortable, GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING); else - gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model), - tree_column->sort_column_id, + gtk_tree_sortable_set_sort_column_id (sortable, + priv->sort_column_id, GTK_SORT_ASCENDING); } else { - gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model), - tree_column->sort_column_id, + gtk_tree_sortable_set_sort_column_id (sortable, + priv->sort_column_id, GTK_SORT_ASCENDING); } } - static void gtk_tree_view_column_setup_sort_column_id_callback (GtkTreeViewColumn *tree_column) { + GtkTreeViewColumnPrivate *priv = tree_column->priv; GtkTreeModel *model; - if (tree_column->tree_view == NULL) + if (priv->tree_view == NULL) return; - model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_column->tree_view)); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree_view)); if (model == NULL) return; if (GTK_IS_TREE_SORTABLE (model) && - tree_column->sort_column_id != -1) + priv->sort_column_id != -1) { gint real_sort_column_id; GtkSortType real_order; - if (tree_column->sort_column_changed_signal == 0) - tree_column->sort_column_changed_signal = + if (priv->sort_column_changed_signal == 0) + priv->sort_column_changed_signal = g_signal_connect (model, "sort-column-changed", G_CALLBACK (gtk_tree_view_model_sort_column_changed), tree_column); - + if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model), &real_sort_column_id, &real_order) && - (real_sort_column_id == tree_column->sort_column_id)) + (real_sort_column_id == priv->sort_column_id)) { gtk_tree_view_column_set_sort_indicator (tree_column, TRUE); gtk_tree_view_column_set_sort_order (tree_column, real_order); @@ -1257,36 +1294,95 @@ gtk_tree_view_column_setup_sort_column_id_callback (GtkTreeViewColumn *tree_colu } } +static void +gtk_tree_view_column_context_changed (GtkCellAreaContext *context, + GParamSpec *pspec, + GtkTreeViewColumn *tree_column) +{ + /* Here we want the column re-requested if the underlying context was + * actually reset for any reason, this can happen if the underlying + * area/cell configuration changes (i.e. cell packing properties + * or cell spacing and the like) + * + * Note that we block this handler while requesting for sizes + * so there is no need to check for the new context size being -1, + * we also block the handler when explicitly resetting the context + * so as to avoid some infinite stack recursion. + */ + if (!strcmp (pspec->name, "minimum-width") || + !strcmp (pspec->name, "natural-width") || + !strcmp (pspec->name, "minimum-height") || + !strcmp (pspec->name, "natural-height")) + _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE); +} + +static void +gtk_tree_view_column_add_editable_callback (GtkCellArea *area, + GtkCellRenderer *renderer, + GtkCellEditable *edit_widget, + GdkRectangle *cell_area, + const gchar *path_string, + gpointer user_data) +{ + GtkTreeViewColumn *column = user_data; + GtkTreeViewColumnPrivate *priv = column->priv; + GtkTreePath *path; + + if (priv->tree_view) + { + path = gtk_tree_path_new_from_string (path_string); + + _gtk_tree_view_add_editable (GTK_TREE_VIEW (priv->tree_view), + column, + path, + edit_widget, + cell_area); + + gtk_tree_path_free (path); + } +} + +static void +gtk_tree_view_column_remove_editable_callback (GtkCellArea *area, + GtkCellRenderer *renderer, + GtkCellEditable *edit_widget, + gpointer user_data) +{ + GtkTreeViewColumn *column = user_data; + GtkTreeViewColumnPrivate *priv = column->priv; + + if (priv->tree_view) + _gtk_tree_view_remove_editable (GTK_TREE_VIEW (priv->tree_view), + column, + edit_widget); +} /* Exported Private Functions. * These should only be called by gtktreeview.c or gtktreeviewcolumn.c */ - void _gtk_tree_view_column_realize_button (GtkTreeViewColumn *column) { + GtkTreeViewColumnPrivate *priv = column->priv; + GtkAllocation allocation; GtkTreeView *tree_view; GdkWindowAttr attr; guint attributes_mask; gboolean rtl; - tree_view = (GtkTreeView *)column->tree_view; - rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL); + tree_view = (GtkTreeView *)priv->tree_view; + rtl = (gtk_widget_get_direction (priv->tree_view) == GTK_TEXT_DIR_RTL); g_return_if_fail (GTK_IS_TREE_VIEW (tree_view)); - g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view))); - g_return_if_fail (tree_view->priv->header_window != NULL); - g_return_if_fail (column->button != NULL); + g_return_if_fail (gtk_widget_get_realized (priv->tree_view)); + g_return_if_fail (priv->button != NULL); - gtk_widget_set_parent_window (column->button, tree_view->priv->header_window); - - if (column->visible) - gtk_widget_show (column->button); + g_return_if_fail (_gtk_tree_view_get_header_window (tree_view) != NULL); + gtk_widget_set_parent_window (priv->button, _gtk_tree_view_get_header_window (tree_view)); attr.window_type = GDK_WINDOW_CHILD; attr.wclass = GDK_INPUT_ONLY; attr.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view)); - attr.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view)); attr.event_mask = gtk_widget_get_events (GTK_WIDGET (tree_view)) | (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | @@ -1294,42 +1390,49 @@ _gtk_tree_view_column_realize_button (GtkTreeViewColumn *column) GDK_POINTER_MOTION_HINT_MASK | GDK_KEY_PRESS_MASK); attributes_mask = GDK_WA_CURSOR | GDK_WA_X | GDK_WA_Y; - attr.cursor = gdk_cursor_new_for_display (gdk_drawable_get_display (tree_view->priv->header_window), - GDK_SB_H_DOUBLE_ARROW); + attr.cursor = gdk_cursor_new_for_display + (gdk_window_get_display (_gtk_tree_view_get_header_window (tree_view)), GDK_SB_H_DOUBLE_ARROW); attr.y = 0; attr.width = TREE_VIEW_DRAG_WIDTH; - attr.height = tree_view->priv->header_height; + attr.height = _gtk_tree_view_get_header_height (tree_view); - attr.x = (column->button->allocation.x + (rtl ? 0 : column->button->allocation.width)) - TREE_VIEW_DRAG_WIDTH / 2; - column->window = gdk_window_new (tree_view->priv->header_window, - &attr, attributes_mask); - gdk_window_set_user_data (column->window, tree_view); + gtk_widget_get_allocation (priv->button, &allocation); + attr.x = (allocation.x + (rtl ? 0 : allocation.width)) - TREE_VIEW_DRAG_WIDTH / 2; + priv->window = gdk_window_new (_gtk_tree_view_get_header_window (tree_view), + &attr, attributes_mask); + gtk_widget_register_window (GTK_WIDGET (tree_view), priv->window); gtk_tree_view_column_update_button (column); - gdk_cursor_unref (attr.cursor); + g_object_unref (attr.cursor); } void _gtk_tree_view_column_unrealize_button (GtkTreeViewColumn *column) { + GtkTreeViewColumnPrivate *priv; + g_return_if_fail (column != NULL); - g_return_if_fail (column->window != NULL); - gdk_window_set_user_data (column->window, NULL); - gdk_window_destroy (column->window); - column->window = NULL; + priv = column->priv; + g_return_if_fail (priv->window != NULL); + + gtk_widget_unregister_window (GTK_WIDGET (priv->tree_view), priv->window); + gdk_window_destroy (priv->window); + priv->window = NULL; } void _gtk_tree_view_column_unset_model (GtkTreeViewColumn *column, GtkTreeModel *old_model) { - if (column->sort_column_changed_signal) + GtkTreeViewColumnPrivate *priv = column->priv; + + if (priv->sort_column_changed_signal) { g_signal_handler_disconnect (old_model, - column->sort_column_changed_signal); - column->sort_column_changed_signal = 0; + priv->sort_column_changed_signal); + priv->sort_column_changed_signal = 0; } gtk_tree_view_column_set_sort_indicator (column, FALSE); } @@ -1338,16 +1441,18 @@ void _gtk_tree_view_column_set_tree_view (GtkTreeViewColumn *column, GtkTreeView *tree_view) { - g_assert (column->tree_view == NULL); + GtkTreeViewColumnPrivate *priv = column->priv; - column->tree_view = GTK_WIDGET (tree_view); + g_assert (priv->tree_view == NULL); + + priv->tree_view = GTK_WIDGET (tree_view); gtk_tree_view_column_create_button (column); - column->property_changed_signal = - g_signal_connect_swapped (tree_view, - "notify::model", - G_CALLBACK (gtk_tree_view_column_setup_sort_column_id_callback), - column); + priv->property_changed_signal = + g_signal_connect_swapped (tree_view, + "notify::model", + G_CALLBACK (gtk_tree_view_column_setup_sort_column_id_callback), + column); gtk_tree_view_column_setup_sort_column_id_callback (column); } @@ -1355,96 +1460,148 @@ _gtk_tree_view_column_set_tree_view (GtkTreeViewColumn *column, void _gtk_tree_view_column_unset_tree_view (GtkTreeViewColumn *column) { - if (column->tree_view && column->button) + GtkTreeViewColumnPrivate *priv = column->priv; + + if (priv->tree_view && priv->button) { - gtk_container_remove (GTK_CONTAINER (column->tree_view), column->button); + gtk_container_remove (GTK_CONTAINER (priv->tree_view), priv->button); } - if (column->property_changed_signal) + if (priv->property_changed_signal) { - g_signal_handler_disconnect (column->tree_view, column->property_changed_signal); - column->property_changed_signal = 0; + g_signal_handler_disconnect (priv->tree_view, priv->property_changed_signal); + priv->property_changed_signal = 0; } - if (column->sort_column_changed_signal) + if (priv->sort_column_changed_signal) { - g_signal_handler_disconnect (gtk_tree_view_get_model (GTK_TREE_VIEW (column->tree_view)), - column->sort_column_changed_signal); - column->sort_column_changed_signal = 0; + g_signal_handler_disconnect (gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree_view)), + priv->sort_column_changed_signal); + priv->sort_column_changed_signal = 0; } - column->tree_view = NULL; - column->button = NULL; + priv->tree_view = NULL; + priv->button = NULL; } gboolean _gtk_tree_view_column_has_editable_cell (GtkTreeViewColumn *column) { - GtkCellRenderer *cell; - GtkCellRendererMode mode; - GList *list; + GtkTreeViewColumnPrivate *priv = column->priv; + gboolean ret = FALSE; + GList *list, *cells; + + cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (priv->cell_area)); - for (list = column->cell_list; list; list = list->next) + for (list = cells; list; list = list->next) { - cell = ((GtkTreeViewColumnCellInfo *)list->data)->cell; + GtkCellRenderer *cell = list->data; + GtkCellRendererMode mode; + g_object_get (cell, "mode", &mode, NULL); + if (mode == GTK_CELL_RENDERER_MODE_EDITABLE) - return TRUE; + { + ret = TRUE; + break; + } } - return FALSE; + g_list_free (cells); + + return ret; } /* gets cell being edited */ GtkCellRenderer * _gtk_tree_view_column_get_edited_cell (GtkTreeViewColumn *column) { - GList *list; - - for (list = column->cell_list; list; list = list->next) - if (((GtkTreeViewColumnCellInfo *)list->data)->in_editing_mode) - return ((GtkTreeViewColumnCellInfo *)list->data)->cell; + GtkTreeViewColumnPrivate *priv = column->priv; - return NULL; + return gtk_cell_area_get_edited_cell (priv->cell_area); } -gint -_gtk_tree_view_column_count_special_cells (GtkTreeViewColumn *column) -{ - gint i = 0; - GList *list; +GtkCellRenderer * +_gtk_tree_view_column_get_cell_at_pos (GtkTreeViewColumn *column, + GdkRectangle *cell_area, + GdkRectangle *background_area, + gint x, + gint y) +{ + GtkCellRenderer *match = NULL; + GtkTreeViewColumnPrivate *priv = column->priv; + + /* If (x, y) is outside of the background area, immediately return */ + if (x < background_area->x || + x > background_area->x + background_area->width || + y < background_area->y || + y > background_area->y + background_area->height) + return NULL; + + /* If (x, y) is inside the background area, clamp it to the cell_area + * so that a cell is still returned. The main reason for doing this + * (on the x axis) is for handling clicks in the indentation area + * (either at the left or right depending on RTL setting). Another + * reason is for handling clicks on the area where the focus rectangle + * is drawn (this is outside of cell area), this manifests itself + * mainly when a large setting is used for focus-line-width. + */ + if (x < cell_area->x) + x = cell_area->x; + else if (x > cell_area->x + cell_area->width) + x = cell_area->x + cell_area->width; - for (list = column->cell_list; list; list = list->next) - { - GtkCellRendererMode mode; - GtkTreeViewColumnCellInfo *cellinfo = list->data; + if (y < cell_area->y) + y = cell_area->y; + else if (y > cell_area->y + cell_area->height) + y = cell_area->y + cell_area->height; - g_object_get (cellinfo->cell, "mode", &mode, NULL); - if ((mode == GTK_CELL_RENDERER_MODE_EDITABLE || - mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE) && - gtk_cell_renderer_get_visible (cellinfo->cell)) - i++; - } + match = gtk_cell_area_get_cell_at_position (priv->cell_area, + priv->cell_area_context, + priv->tree_view, + cell_area, + x, y, + NULL); - return i; + return match; } -GtkCellRenderer * -_gtk_tree_view_column_get_cell_at_pos (GtkTreeViewColumn *column, - gint x) -{ - GList *list; - gint current_x = 0; - - list = gtk_tree_view_column_cell_first (column); - for (; list; list = gtk_tree_view_column_cell_next (column, list)) - { - GtkTreeViewColumnCellInfo *cellinfo = list->data; - if (current_x <= x && x <= current_x + cellinfo->real_width) - return cellinfo->cell; - current_x += cellinfo->real_width; - } +gboolean +_gtk_tree_view_column_is_blank_at_pos (GtkTreeViewColumn *column, + GdkRectangle *cell_area, + GdkRectangle *background_area, + gint x, + gint y) +{ + GtkCellRenderer *match; + GdkRectangle cell_alloc, aligned_area, inner_area; + GtkTreeViewColumnPrivate *priv = column->priv; + + match = _gtk_tree_view_column_get_cell_at_pos (column, + cell_area, + background_area, + x, y); + if (!match) + return FALSE; + + gtk_cell_area_get_cell_allocation (priv->cell_area, + priv->cell_area_context, + priv->tree_view, + match, + cell_area, + &cell_alloc); + + gtk_cell_area_inner_cell_area (priv->cell_area, priv->tree_view, + &cell_alloc, &inner_area); + gtk_cell_renderer_get_aligned_area (match, priv->tree_view, 0, + &inner_area, &aligned_area); + + if (x < aligned_area.x || + x > aligned_area.x + aligned_area.width || + y < aligned_area.y || + y > aligned_area.y + aligned_area.height) + return TRUE; - return NULL; + return FALSE; } /* Public Functions */ @@ -1468,13 +1625,34 @@ gtk_tree_view_column_new (void) } /** - * gtk_tree_view_column_new_with_attributes: - * @title: The title to set the header to. - * @cell: The #GtkCellRenderer. - * @Varargs: A %NULL-terminated list of attributes. + * gtk_tree_view_column_new_with_area: + * @area: the #GtkCellArea that the newly created column should use to layout cells. + * + * Creates a new #GtkTreeViewColumn using @area to render its cells. * - * Creates a new #GtkTreeViewColumn with a number of default values. This is - * equivalent to calling gtk_tree_view_column_set_title(), + * Return value: A newly created #GtkTreeViewColumn. + * + * Since: 3.0 + */ +GtkTreeViewColumn * +gtk_tree_view_column_new_with_area (GtkCellArea *area) +{ + GtkTreeViewColumn *tree_column; + + tree_column = g_object_new (GTK_TYPE_TREE_VIEW_COLUMN, "cell-area", area, NULL); + + return tree_column; +} + + +/** + * gtk_tree_view_column_new_with_attributes: + * @title: The title to set the header to + * @cell: The #GtkCellRenderer + * @...: A %NULL-terminated list of attributes + * + * Creates a new #GtkTreeViewColumn with a number of default values. + * This is equivalent to calling gtk_tree_view_column_set_title(), * gtk_tree_view_column_pack_start(), and * gtk_tree_view_column_set_attributes() on the newly created #GtkTreeViewColumn. * @@ -1516,18 +1694,6 @@ gtk_tree_view_column_new_with_attributes (const gchar *title, return retval; } -static GtkTreeViewColumnCellInfo * -gtk_tree_view_column_get_cell_info (GtkTreeViewColumn *tree_column, - GtkCellRenderer *cell_renderer) -{ - GList *list; - for (list = tree_column->cell_list; list; list = list->next) - if (((GtkTreeViewColumnCellInfo *)list->data)->cell == cell_renderer) - return (GtkTreeViewColumnCellInfo *) list->data; - return NULL; -} - - /** * gtk_tree_view_column_pack_start: * @tree_column: A #GtkTreeViewColumn. @@ -1576,24 +1742,6 @@ gtk_tree_view_column_clear (GtkTreeViewColumn *tree_column) gtk_cell_layout_clear (GTK_CELL_LAYOUT (tree_column)); } -static GList * -gtk_tree_view_column_cell_layout_get_cells (GtkCellLayout *layout) -{ - GtkTreeViewColumn *tree_column = GTK_TREE_VIEW_COLUMN (layout); - GList *retval = NULL, *list; - - g_return_val_if_fail (tree_column != NULL, NULL); - - for (list = tree_column->cell_list; list; list = list->next) - { - GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *)list->data; - - retval = g_list_append (retval, info->cell); - } - - return retval; -} - /** * gtk_tree_view_column_add_attribute: * @tree_column: A #GtkTreeViewColumn. @@ -1623,32 +1771,35 @@ gtk_tree_view_column_set_attributesv (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell_renderer, va_list args) { + GtkTreeViewColumnPrivate *priv = tree_column->priv; gchar *attribute; gint column; attribute = va_arg (args, gchar *); - gtk_tree_view_column_clear_attributes (tree_column, cell_renderer); + gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (priv->cell_area), + cell_renderer); while (attribute != NULL) { column = va_arg (args, gint); - gtk_tree_view_column_add_attribute (tree_column, cell_renderer, attribute, column); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (priv->cell_area), + cell_renderer, attribute, column); attribute = va_arg (args, gchar *); } } /** * gtk_tree_view_column_set_attributes: - * @tree_column: A #GtkTreeViewColumn. + * @tree_column: A #GtkTreeViewColumn * @cell_renderer: the #GtkCellRenderer we're setting the attributes of - * @Varargs: A %NULL-terminated list of attributes. - * + * @...: A %NULL-terminated list of attributes + * * Sets the attributes in the list as the attributes of @tree_column. * The attributes should be in attribute/column order, as in * gtk_tree_view_column_add_attribute(). All existing attributes * are removed, and replaced with the new attributes. - **/ + */ void gtk_tree_view_column_set_attributes (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell_renderer, @@ -1658,7 +1809,6 @@ gtk_tree_view_column_set_attributes (GtkTreeViewColumn *tree_column, g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer)); - g_return_if_fail (gtk_tree_view_column_get_cell_info (tree_column, cell_renderer)); va_start (args, cell_renderer); gtk_tree_view_column_set_attributesv (tree_column, cell_renderer, args); @@ -1670,11 +1820,11 @@ gtk_tree_view_column_set_attributes (GtkTreeViewColumn *tree_column, * gtk_tree_view_column_set_cell_data_func: * @tree_column: A #GtkTreeViewColumn * @cell_renderer: A #GtkCellRenderer - * @func: The #GtkTreeViewColumnFunc to use. + * @func: (allow-none): The #GtkTreeCellDataFunc to use. * @func_data: The user data for @func. * @destroy: The destroy notification for @func_data * - * Sets the #GtkTreeViewColumnFunc to use for the column. This + * Sets the #GtkTreeCellDataFunc to use for the column. This * function is used instead of the standard attributes mapping for * setting the column value, and should set the value of @tree_column's * cell renderer as appropriate. @func may be %NULL to remove an @@ -1722,14 +1872,16 @@ void gtk_tree_view_column_set_spacing (GtkTreeViewColumn *tree_column, gint spacing) { + GtkTreeViewColumnPrivate *priv; + g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); g_return_if_fail (spacing >= 0); - if (tree_column->spacing == spacing) - return; + priv = tree_column->priv; - tree_column->spacing = spacing; - if (tree_column->tree_view) + gtk_cell_area_box_set_spacing (GTK_CELL_AREA_BOX (priv->cell_area), + spacing); + if (priv->tree_view) _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE); } @@ -1744,9 +1896,13 @@ gtk_tree_view_column_set_spacing (GtkTreeViewColumn *tree_column, gint gtk_tree_view_column_get_spacing (GtkTreeViewColumn *tree_column) { + GtkTreeViewColumnPrivate *priv; + g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0); - return tree_column->spacing; + priv = tree_column->priv; + + return gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (priv->cell_area)); } /* Options for manipulating the columns */ @@ -1757,23 +1913,33 @@ gtk_tree_view_column_get_spacing (GtkTreeViewColumn *tree_column) * @visible: %TRUE if the @tree_column is visible. * * Sets the visibility of @tree_column. - **/ + */ void gtk_tree_view_column_set_visible (GtkTreeViewColumn *tree_column, - gboolean visible) + gboolean visible) { + GtkTreeViewColumnPrivate *priv; + g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); + priv = tree_column->priv; visible = !! visible; - - if (tree_column->visible == visible) + + if (priv->visible == visible) return; - tree_column->visible = visible; + priv->visible = visible; - if (tree_column->visible) + if (priv->visible) _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE); + if (priv->tree_view) + { + _gtk_tree_view_reset_header_styles (GTK_TREE_VIEW (priv->tree_view)); + _gtk_tree_view_accessible_toggle_visibility (GTK_TREE_VIEW (priv->tree_view), + tree_column); + } + gtk_tree_view_column_update_button (tree_column); g_object_notify (G_OBJECT (tree_column), "visible"); } @@ -1792,7 +1958,7 @@ gtk_tree_view_column_get_visible (GtkTreeViewColumn *tree_column) { g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE); - return tree_column->visible; + return tree_column->priv->visible; } /** @@ -1809,16 +1975,19 @@ void gtk_tree_view_column_set_resizable (GtkTreeViewColumn *tree_column, gboolean resizable) { + GtkTreeViewColumnPrivate *priv; + g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); + priv = tree_column->priv; resizable = !! resizable; - if (tree_column->resizable == resizable) + if (priv->resizable == resizable) return; - tree_column->resizable = resizable; + priv->resizable = resizable; - if (resizable && tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE) + if (resizable && priv->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE) gtk_tree_view_column_set_sizing (tree_column, GTK_TREE_VIEW_COLUMN_GROW_ONLY); gtk_tree_view_column_update_button (tree_column); @@ -1839,7 +2008,7 @@ gtk_tree_view_column_get_resizable (GtkTreeViewColumn *tree_column) { g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE); - return tree_column->resizable; + return tree_column->priv->resizable; } @@ -1854,25 +2023,19 @@ void gtk_tree_view_column_set_sizing (GtkTreeViewColumn *tree_column, GtkTreeViewColumnSizing type) { + GtkTreeViewColumnPrivate *priv; + g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); - if (type == tree_column->column_type) + priv = tree_column->priv; + + if (type == priv->column_type) return; if (type == GTK_TREE_VIEW_COLUMN_AUTOSIZE) gtk_tree_view_column_set_resizable (tree_column, FALSE); -#if 0 - /* I was clearly on crack when I wrote this. I'm not sure what's supposed to - * be below so I'll leave it until I figure it out. - */ - if (tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE && - tree_column->requested_width != -1) - { - gtk_tree_view_column_set_sizing (tree_column, tree_column->requested_width); - } -#endif - tree_column->column_type = type; + priv->column_type = type; gtk_tree_view_column_update_button (tree_column); @@ -1892,7 +2055,7 @@ gtk_tree_view_column_get_sizing (GtkTreeViewColumn *tree_column) { g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0); - return tree_column->column_type; + return tree_column->priv->column_type; } /** @@ -1908,35 +2071,150 @@ gtk_tree_view_column_get_width (GtkTreeViewColumn *tree_column) { g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0); - return tree_column->width; + return tree_column->priv->width; } /** - * gtk_tree_view_column_set_fixed_width: + * gtk_tree_view_column_get_x_offset: * @tree_column: A #GtkTreeViewColumn. - * @fixed_width: The size to set @tree_column to. Must be greater than 0. * - * Sets the size of the column in pixels. This is meaningful only if the sizing - * type is #GTK_TREE_VIEW_COLUMN_FIXED. The size of the column is clamped to - * the min/max width for the column. Please note that the min/max width of the - * column doesn't actually affect the "fixed_width" property of the widget, just - * the actual size when displayed. + * Returns the current X offset of @tree_column in pixels. + * + * Return value: The current X offset of @tree_column. + * + * Since: 3.2 + */ +gint +gtk_tree_view_column_get_x_offset (GtkTreeViewColumn *tree_column) +{ + g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0); + + return tree_column->priv->x_offset; +} + +void +_gtk_tree_view_column_request_width (GtkTreeViewColumn *tree_column, + gint *minimum, + gint *natural) +{ + GtkTreeViewColumnPrivate *priv = tree_column->priv; + gint minimum_width = 1, natural_width = 1; + gint button_minimum, button_natural; + + if (priv->column_type != GTK_TREE_VIEW_COLUMN_FIXED) + { + gtk_cell_area_context_get_preferred_width (priv->cell_area_context, &minimum_width, &natural_width); + minimum_width += priv->padding; + natural_width += priv->padding; + + if (gtk_tree_view_get_headers_visible (GTK_TREE_VIEW (priv->tree_view))) + { + gtk_widget_get_preferred_width (priv->button, &button_minimum, &button_natural); + minimum_width = MAX (minimum_width, button_minimum); + natural_width = MAX (natural_width, button_natural); + } + } + + if (priv->fixed_width != -1) + natural_width = MAX (priv->fixed_width, minimum_width); + + if (priv->min_width != -1) + { + minimum_width = MAX (minimum_width, priv->min_width); + natural_width = MAX (natural_width, priv->min_width); + } + + if (priv->max_width != -1) + { + minimum_width = MIN (minimum_width, priv->max_width); + natural_width = MIN (natural_width, priv->max_width); + } + + if (minimum != NULL) + *minimum = minimum_width; + if (natural != NULL) + *natural = natural_width; +} + +void +_gtk_tree_view_column_allocate (GtkTreeViewColumn *tree_column, + int x_offset, + int width) +{ + GtkTreeViewColumnPrivate *priv; + gboolean rtl; + GtkAllocation allocation = { 0, 0, 0, 0 }; + + g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); + + priv = tree_column->priv; + + if (priv->width != width) + gtk_widget_queue_draw (priv->tree_view); + + priv->x_offset = x_offset; + priv->width = width; + + gtk_cell_area_context_allocate (priv->cell_area_context, priv->width - priv->padding, -1); + + if (gtk_tree_view_get_headers_visible (GTK_TREE_VIEW (priv->tree_view))) + { + allocation.x = x_offset; + allocation.y = 0; + allocation.width = width; + allocation.height = _gtk_tree_view_get_header_height (GTK_TREE_VIEW (priv->tree_view)); + + gtk_widget_size_allocate (priv->button, &allocation); + } + + if (priv->window) + { + rtl = (gtk_widget_get_direction (priv->tree_view) == GTK_TEXT_DIR_RTL); + gdk_window_move_resize (priv->window, + allocation.x + (rtl ? 0 : allocation.width) - TREE_VIEW_DRAG_WIDTH/2, + allocation.y, + TREE_VIEW_DRAG_WIDTH, allocation.height); + } + + g_object_notify (G_OBJECT (tree_column), "x-offset"); + g_object_notify (G_OBJECT (tree_column), "width"); +} + +/** + * gtk_tree_view_column_set_fixed_width: + * @tree_column: A #GtkTreeViewColumn. + * @fixed_width: The new fixed width, in pixels, or -1. + * + * If @fixed_width is not -1, sets the fixed width of @tree_column; otherwise + * unsets it. The effective value of @fixed_width is clamped between the + * minumum and maximum width of the column; however, the value stored in the + * "fixed-width" property is not clamped. If the column sizing is + * #GTK_TREE_VIEW_COLUMN_GROW_ONLY or #GTK_TREE_VIEW_COLUMN_AUTOSIZE, setting a + * fixed width overrides the automatically calculated width. Note that + * @fixed_width is only a hint to GTK+; the width actually allocated to the + * column may be greater or less than requested. + * + * Along with "expand", the "fixed-width" property changes when the column is + * resized by the user. **/ void gtk_tree_view_column_set_fixed_width (GtkTreeViewColumn *tree_column, gint fixed_width) { + GtkTreeViewColumnPrivate *priv; + g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); - g_return_if_fail (fixed_width > 0); + g_return_if_fail (fixed_width >= -1); + + priv = tree_column->priv; - tree_column->fixed_width = fixed_width; - tree_column->use_resized_width = FALSE; + priv->fixed_width = fixed_width; - if (tree_column->tree_view && - gtk_widget_get_realized (tree_column->tree_view) && - tree_column->column_type == GTK_TREE_VIEW_COLUMN_FIXED) + if (priv->visible && + priv->tree_view != NULL && + gtk_widget_get_realized (priv->tree_view)) { - gtk_widget_queue_resize (tree_column->tree_view); + gtk_widget_queue_resize (priv->tree_view); } g_object_notify (G_OBJECT (tree_column), "fixed-width"); @@ -1944,19 +2222,19 @@ gtk_tree_view_column_set_fixed_width (GtkTreeViewColumn *tree_column, /** * gtk_tree_view_column_get_fixed_width: - * @tree_column: a #GtkTreeViewColumn - * - * Gets the fixed width of the column. This value is only meaning may not be - * the actual width of the column on the screen, just what is requested. - * - * Return value: the fixed width of the column + * @tree_column: A #GtkTreeViewColumn. + * + * Gets the fixed width of the column. This may not be the actual displayed + * width of the column; for that, use gtk_tree_view_column_get_width(). + * + * Return value: The fixed width of the column. **/ gint gtk_tree_view_column_get_fixed_width (GtkTreeViewColumn *tree_column) { g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0); - return tree_column->fixed_width; + return tree_column->priv->fixed_width; } /** @@ -1971,32 +2249,36 @@ void gtk_tree_view_column_set_min_width (GtkTreeViewColumn *tree_column, gint min_width) { + GtkTreeViewColumnPrivate *priv; + g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); g_return_if_fail (min_width >= -1); - if (min_width == tree_column->min_width) + priv = tree_column->priv; + + if (min_width == priv->min_width) return; - if (tree_column->visible && - tree_column->tree_view != NULL && - gtk_widget_get_realized (tree_column->tree_view)) + if (priv->visible && + priv->tree_view != NULL && + gtk_widget_get_realized (priv->tree_view)) { - if (min_width > tree_column->width) - gtk_widget_queue_resize (tree_column->tree_view); + if (min_width > priv->width) + gtk_widget_queue_resize (priv->tree_view); } - tree_column->min_width = min_width; + priv->min_width = min_width; g_object_freeze_notify (G_OBJECT (tree_column)); - if (tree_column->max_width != -1 && tree_column->max_width < min_width) + if (priv->max_width != -1 && priv->max_width < min_width) { - tree_column->max_width = min_width; + priv->max_width = min_width; g_object_notify (G_OBJECT (tree_column), "max-width"); } g_object_notify (G_OBJECT (tree_column), "min-width"); g_object_thaw_notify (G_OBJECT (tree_column)); - if (tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE) - _gtk_tree_view_column_autosize (GTK_TREE_VIEW (tree_column->tree_view), + if (priv->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE) + _gtk_tree_view_column_autosize (GTK_TREE_VIEW (priv->tree_view), tree_column); } @@ -2014,7 +2296,7 @@ gtk_tree_view_column_get_min_width (GtkTreeViewColumn *tree_column) { g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), -1); - return tree_column->min_width; + return tree_column->priv->min_width; } /** @@ -2031,32 +2313,36 @@ void gtk_tree_view_column_set_max_width (GtkTreeViewColumn *tree_column, gint max_width) { + GtkTreeViewColumnPrivate *priv; + g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); g_return_if_fail (max_width >= -1); - if (max_width == tree_column->max_width) + priv = tree_column->priv; + + if (max_width == priv->max_width) return; - if (tree_column->visible && - tree_column->tree_view != NULL && - gtk_widget_get_realized (tree_column->tree_view)) + if (priv->visible && + priv->tree_view != NULL && + gtk_widget_get_realized (priv->tree_view)) { - if (max_width != -1 && max_width < tree_column->width) - gtk_widget_queue_resize (tree_column->tree_view); + if (max_width != -1 && max_width < priv->width) + gtk_widget_queue_resize (priv->tree_view); } - tree_column->max_width = max_width; + priv->max_width = max_width; g_object_freeze_notify (G_OBJECT (tree_column)); - if (max_width != -1 && max_width < tree_column->min_width) + if (max_width != -1 && max_width < priv->min_width) { - tree_column->min_width = max_width; + priv->min_width = max_width; g_object_notify (G_OBJECT (tree_column), "min-width"); } g_object_notify (G_OBJECT (tree_column), "max-width"); g_object_thaw_notify (G_OBJECT (tree_column)); - if (tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE) - _gtk_tree_view_column_autosize (GTK_TREE_VIEW (tree_column->tree_view), + if (priv->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE) + _gtk_tree_view_column_autosize (GTK_TREE_VIEW (priv->tree_view), tree_column); } @@ -2074,7 +2360,7 @@ gtk_tree_view_column_get_max_width (GtkTreeViewColumn *tree_column) { g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), -1); - return tree_column->max_width; + return tree_column->priv->max_width; } /** @@ -2087,12 +2373,16 @@ gtk_tree_view_column_get_max_width (GtkTreeViewColumn *tree_column) void gtk_tree_view_column_clicked (GtkTreeViewColumn *tree_column) { + GtkTreeViewColumnPrivate *priv; + g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); - if (tree_column->visible && - tree_column->button && - tree_column->clickable) - gtk_button_clicked (GTK_BUTTON (tree_column->button)); + priv = tree_column->priv; + + if (priv->visible && + priv->button && + priv->clickable) + gtk_button_clicked (GTK_BUTTON (priv->button)); } /** @@ -2107,13 +2397,16 @@ void gtk_tree_view_column_set_title (GtkTreeViewColumn *tree_column, const gchar *title) { - gchar *new_title; - + GtkTreeViewColumnPrivate *priv; + gchar *new_title; + g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); + priv = tree_column->priv; + new_title = g_strdup (title); - g_free (tree_column->title); - tree_column->title = new_title; + g_free (priv->title); + priv->title = new_title; gtk_tree_view_column_update_button (tree_column); g_object_notify (G_OBJECT (tree_column), "title"); @@ -2128,49 +2421,49 @@ gtk_tree_view_column_set_title (GtkTreeViewColumn *tree_column, * Return value: the title of the column. This string should not be * modified or freed. **/ -G_CONST_RETURN gchar * +const gchar * gtk_tree_view_column_get_title (GtkTreeViewColumn *tree_column) { g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), NULL); - return tree_column->title; + return tree_column->priv->title; } /** * gtk_tree_view_column_set_expand: - * @tree_column: A #GtkTreeViewColumn - * @expand: %TRUE if the column should take available extra space, %FALSE if not - * + * @tree_column: A #GtkTreeViewColumn. + * @expand: %TRUE if the column should expand to fill available space. + * * Sets the column to take available extra space. This space is shared equally * amongst all columns that have the expand set to %TRUE. If no column has this * option set, then the last column gets all extra space. By default, every * column is created with this %FALSE. * + * Along with "fixed-width", the "expand" property changes when the column is + * resized by the user. + * * Since: 2.4 **/ void gtk_tree_view_column_set_expand (GtkTreeViewColumn *tree_column, gboolean expand) { + GtkTreeViewColumnPrivate *priv; + g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); + priv = tree_column->priv; + expand = expand?TRUE:FALSE; - if (tree_column->expand == expand) + if (priv->expand == expand) return; - tree_column->expand = expand; + priv->expand = expand; - if (tree_column->visible && - tree_column->tree_view != NULL && - gtk_widget_get_realized (tree_column->tree_view)) + if (priv->visible && + priv->tree_view != NULL && + gtk_widget_get_realized (priv->tree_view)) { - /* We want to continue using the original width of the - * column that includes additional space added by the user - * resizing the columns and possibly extra (expanded) space, which - * are not included in the resized width. - */ - tree_column->use_resized_width = FALSE; - - gtk_widget_queue_resize (tree_column->tree_view); + gtk_widget_queue_resize (priv->tree_view); } g_object_notify (G_OBJECT (tree_column), "expand"); @@ -2178,11 +2471,11 @@ gtk_tree_view_column_set_expand (GtkTreeViewColumn *tree_column, /** * gtk_tree_view_column_get_expand: - * @tree_column: a #GtkTreeViewColumn - * - * Return %TRUE if the column expands to take any available space. - * - * Return value: %TRUE, if the column expands + * @tree_column: A #GtkTreeViewColumn. + * + * Returns %TRUE if the column expands to fill available space. + * + * Return value: %TRUE if the column expands to fill available space. * * Since: 2.4 **/ @@ -2191,7 +2484,7 @@ gtk_tree_view_column_get_expand (GtkTreeViewColumn *tree_column) { g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE); - return tree_column->expand; + return tree_column->priv->expand; } /** @@ -2199,20 +2492,24 @@ gtk_tree_view_column_get_expand (GtkTreeViewColumn *tree_column) * @tree_column: A #GtkTreeViewColumn. * @clickable: %TRUE if the header is active. * - * Sets the header to be active if @active is %TRUE. When the header is active, - * then it can take keyboard focus, and can be clicked. + * Sets the header to be active if @clickable is %TRUE. When the header is + * active, then it can take keyboard focus, and can be clicked. **/ void gtk_tree_view_column_set_clickable (GtkTreeViewColumn *tree_column, gboolean clickable) { + GtkTreeViewColumnPrivate *priv; + g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); + priv = tree_column->priv; + clickable = !! clickable; - if (tree_column->clickable == clickable) + if (priv->clickable == clickable) return; - tree_column->clickable = clickable; + priv->clickable = clickable; gtk_tree_view_column_update_button (tree_column); g_object_notify (G_OBJECT (tree_column), "clickable"); } @@ -2230,7 +2527,7 @@ gtk_tree_view_column_get_clickable (GtkTreeViewColumn *tree_column) { g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE); - return tree_column->clickable; + return tree_column->priv->clickable; } /** @@ -2245,16 +2542,20 @@ void gtk_tree_view_column_set_widget (GtkTreeViewColumn *tree_column, GtkWidget *widget) { + GtkTreeViewColumnPrivate *priv; + g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget)); + priv = tree_column->priv; + if (widget) g_object_ref_sink (widget); - if (tree_column->child) - g_object_unref (tree_column->child); + if (priv->child) + g_object_unref (priv->child); - tree_column->child = widget; + priv->child = widget; gtk_tree_view_column_update_button (tree_column); g_object_notify (G_OBJECT (tree_column), "widget"); } @@ -2262,18 +2563,19 @@ gtk_tree_view_column_set_widget (GtkTreeViewColumn *tree_column, /** * gtk_tree_view_column_get_widget: * @tree_column: A #GtkTreeViewColumn. - * - * Returns the #GtkWidget in the button on the column header. If a custom - * widget has not been set then %NULL is returned. - * - * Return value: The #GtkWidget in the column header, or %NULL + * + * Returns the #GtkWidget in the button on the column header. + * If a custom widget has not been set then %NULL is returned. + * + * Return value: (transfer none): The #GtkWidget in the column + * header, or %NULL **/ GtkWidget * gtk_tree_view_column_get_widget (GtkTreeViewColumn *tree_column) { g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), NULL); - return tree_column->child; + return tree_column->priv->child; } /** @@ -2289,14 +2591,18 @@ void gtk_tree_view_column_set_alignment (GtkTreeViewColumn *tree_column, gfloat xalign) { + GtkTreeViewColumnPrivate *priv; + g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); + priv = tree_column->priv; + xalign = CLAMP (xalign, 0.0, 1.0); - if (tree_column->xalign == xalign) + if (priv->xalign == xalign) return; - tree_column->xalign = xalign; + priv->xalign = xalign; gtk_tree_view_column_update_button (tree_column); g_object_notify (G_OBJECT (tree_column), "alignment"); } @@ -2315,7 +2621,7 @@ gtk_tree_view_column_get_alignment (GtkTreeViewColumn *tree_column) { g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0.5); - return tree_column->xalign; + return tree_column->priv->xalign; } /** @@ -2330,15 +2636,19 @@ void gtk_tree_view_column_set_reorderable (GtkTreeViewColumn *tree_column, gboolean reorderable) { + GtkTreeViewColumnPrivate *priv; + g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); + priv = tree_column->priv; + /* if (reorderable) gtk_tree_view_column_set_clickable (tree_column, TRUE);*/ - if (tree_column->reorderable == (reorderable?TRUE:FALSE)) + if (priv->reorderable == (reorderable?TRUE:FALSE)) return; - tree_column->reorderable = (reorderable?TRUE:FALSE); + priv->reorderable = (reorderable?TRUE:FALSE); gtk_tree_view_column_update_button (tree_column); g_object_notify (G_OBJECT (tree_column), "reorderable"); } @@ -2356,7 +2666,7 @@ gtk_tree_view_column_get_reorderable (GtkTreeViewColumn *tree_column) { g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE); - return tree_column->reorderable; + return tree_column->priv->reorderable; } @@ -2372,29 +2682,33 @@ void gtk_tree_view_column_set_sort_column_id (GtkTreeViewColumn *tree_column, gint sort_column_id) { + GtkTreeViewColumnPrivate *priv; + g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); g_return_if_fail (sort_column_id >= -1); - if (tree_column->sort_column_id == sort_column_id) + priv = tree_column->priv; + + if (priv->sort_column_id == sort_column_id) return; - tree_column->sort_column_id = sort_column_id; + priv->sort_column_id = sort_column_id; /* Handle unsetting the id */ if (sort_column_id == -1) { - GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_column->tree_view)); + GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree_view)); - if (tree_column->sort_clicked_signal) + if (priv->sort_clicked_signal) { - g_signal_handler_disconnect (tree_column, tree_column->sort_clicked_signal); - tree_column->sort_clicked_signal = 0; + g_signal_handler_disconnect (tree_column, priv->sort_clicked_signal); + priv->sort_clicked_signal = 0; } - if (tree_column->sort_column_changed_signal) + if (priv->sort_column_changed_signal) { - g_signal_handler_disconnect (model, tree_column->sort_column_changed_signal); - tree_column->sort_column_changed_signal = 0; + g_signal_handler_disconnect (model, priv->sort_column_changed_signal); + priv->sort_column_changed_signal = 0; } gtk_tree_view_column_set_sort_order (tree_column, GTK_SORT_ASCENDING); @@ -2406,11 +2720,11 @@ gtk_tree_view_column_set_sort_column_id (GtkTreeViewColumn *tree_column, gtk_tree_view_column_set_clickable (tree_column, TRUE); - if (! tree_column->sort_clicked_signal) - tree_column->sort_clicked_signal = g_signal_connect (tree_column, - "clicked", - G_CALLBACK (gtk_tree_view_column_sort), - NULL); + if (! priv->sort_clicked_signal) + priv->sort_clicked_signal = g_signal_connect (tree_column, + "clicked", + G_CALLBACK (gtk_tree_view_column_sort), + NULL); gtk_tree_view_column_setup_sort_column_id_callback (tree_column); g_object_notify (G_OBJECT (tree_column), "sort-column-id"); @@ -2432,7 +2746,7 @@ gtk_tree_view_column_get_sort_column_id (GtkTreeViewColumn *tree_column) { g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0); - return tree_column->sort_column_id; + return tree_column->priv->sort_column_id; } /** @@ -2454,10 +2768,10 @@ gtk_tree_view_column_set_sort_indicator (GtkTreeViewColumn *tree_column, setting = setting != FALSE; - if (setting == tree_column->show_sort_indicator) + if (setting == tree_column->priv->show_sort_indicator) return; - tree_column->show_sort_indicator = setting; + tree_column->priv->show_sort_indicator = setting; gtk_tree_view_column_update_button (tree_column); g_object_notify (G_OBJECT (tree_column), "sort-indicator"); } @@ -2475,7 +2789,7 @@ gtk_tree_view_column_get_sort_indicator (GtkTreeViewColumn *tree_column) { g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE); - return tree_column->show_sort_indicator; + return tree_column->priv->show_sort_indicator; } /** @@ -2488,7 +2802,7 @@ gtk_tree_view_column_get_sort_indicator (GtkTreeViewColumn *tree_column) * This does not actually sort the model. Use * gtk_tree_view_column_set_sort_column_id() if you want automatic sorting * support. This function is primarily for custom sorting behavior, and should - * be used in conjunction with gtk_tree_sortable_set_sort_column() to do + * be used in conjunction with gtk_tree_sortable_set_sort_column_id() to do * that. For custom models, the mechanism will vary. * * The sort indicator changes direction to indicate normal sort or reverse sort. @@ -2501,10 +2815,10 @@ gtk_tree_view_column_set_sort_order (GtkTreeViewColumn *tree_column, { g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); - if (order == tree_column->sort_order) + if (order == tree_column->priv->sort_order) return; - tree_column->sort_order = order; + tree_column->priv->sort_order = order; gtk_tree_view_column_update_button (tree_column); g_object_notify (G_OBJECT (tree_column), "sort-order"); } @@ -2522,7 +2836,7 @@ gtk_tree_view_column_get_sort_order (GtkTreeViewColumn *tree_column) { g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0); - return tree_column->sort_order; + return tree_column->priv->sort_order; } /** @@ -2545,58 +2859,23 @@ gtk_tree_view_column_cell_set_cell_data (GtkTreeViewColumn *tree_column, gboolean is_expander, gboolean is_expanded) { - GSList *list; - GValue value = { 0, }; - GList *cell_list; - gboolean cell_is_expander, cell_is_expanded; - g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); if (tree_model == NULL) return; - for (cell_list = tree_column->cell_list; cell_list; cell_list = cell_list->next) - { - GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) cell_list->data; - GObject *cell = (GObject *) info->cell; - - list = info->attributes; - - g_object_freeze_notify (cell); - - g_object_get (cell, "is-expander", &cell_is_expander, NULL); - if (cell_is_expander != is_expander) - g_object_set (cell, "is-expander", is_expander, NULL); - - g_object_get (cell, "is-expanded", &cell_is_expanded, NULL); - if (cell_is_expanded != is_expanded) - g_object_set (cell, "is-expanded", is_expanded, NULL); - - while (list && list->next) - { - gtk_tree_model_get_value (tree_model, iter, - GPOINTER_TO_INT (list->next->data), - &value); - g_object_set_property (cell, (gchar *) list->data, &value); - g_value_unset (&value); - list = list->next->next; - } - - if (info->func) - (* info->func) (tree_column, info->cell, tree_model, iter, info->func_data); - g_object_thaw_notify (G_OBJECT (info->cell)); - } - + gtk_cell_area_apply_attributes (tree_column->priv->cell_area, tree_model, iter, + is_expander, is_expanded); } /** * gtk_tree_view_column_cell_get_size: * @tree_column: A #GtkTreeViewColumn. * @cell_area: (allow-none): The area a cell in the column will be allocated, or %NULL - * @x_offset: (allow-none): location to return x offset of a cell relative to @cell_area, or %NULL - * @y_offset: (allow-none): location to return y offset of a cell relative to @cell_area, or %NULL - * @width: (allow-none): location to return width needed to render a cell, or %NULL - * @height: (allow-none): location to return height needed to render a cell, or %NULL + * @x_offset: (out) (allow-none): location to return x offset of a cell relative to @cell_area, or %NULL + * @y_offset: (out) (allow-none): location to return y offset of a cell relative to @cell_area, or %NULL + * @width: (out) (allow-none): location to return width needed to render a cell, or %NULL + * @height: (out) (allow-none): location to return height needed to render a cell, or %NULL * * Obtains the width and height needed to render the column. This is used * primarily by the #GtkTreeView. @@ -2609,942 +2888,134 @@ gtk_tree_view_column_cell_get_size (GtkTreeViewColumn *tree_column, gint *width, gint *height) { - GList *list; - gboolean first_cell = TRUE; - gint focus_line_width; + GtkTreeViewColumnPrivate *priv; + gint min_width = 0, min_height = 0; g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); - if (height) - * height = 0; - if (width) - * width = 0; - - gtk_widget_style_get (tree_column->tree_view, "focus-line-width", &focus_line_width, NULL); - - for (list = tree_column->cell_list; list; list = list->next) - { - GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data; - gboolean visible; - gint new_height = 0; - gint new_width = 0; - g_object_get (info->cell, "visible", &visible, NULL); - - if (visible == FALSE) - continue; - - if (first_cell == FALSE && width) - *width += tree_column->spacing; - - gtk_cell_renderer_get_size (info->cell, - tree_column->tree_view, - cell_area, - x_offset, - y_offset, - &new_width, - &new_height); - - if (height) - * height = MAX (*height, new_height + focus_line_width * 2); - info->requested_width = MAX (info->requested_width, new_width + focus_line_width * 2); - if (width) - * width += info->requested_width; - first_cell = FALSE; - } -} - -/* rendering, event handling and rendering focus are somewhat complicated, and - * quite a bit of code. Rather than duplicate them, we put them together to - * keep the code in one place. - * - * To better understand what's going on, check out - * docs/tree-column-sizing.png - */ -enum { - CELL_ACTION_RENDER, - CELL_ACTION_FOCUS, - CELL_ACTION_EVENT -}; - -static gboolean -gtk_tree_view_column_cell_process_action (GtkTreeViewColumn *tree_column, - GdkWindow *window, - const GdkRectangle *background_area, - const GdkRectangle *cell_area, - guint flags, - gint action, - const GdkRectangle *expose_area, /* RENDER */ - GdkRectangle *focus_rectangle, /* FOCUS */ - GtkCellEditable **editable_widget, /* EVENT */ - GdkEvent *event, /* EVENT */ - gchar *path_string) /* EVENT */ -{ - GList *list; - GdkRectangle real_cell_area; - GdkRectangle real_background_area; - GdkRectangle real_expose_area = *cell_area; - gint depth = 0; - gint expand_cell_count = 0; - gint full_requested_width = 0; - gint extra_space; - gint min_x, min_y, max_x, max_y; - gint focus_line_width; - gint special_cells; - gint horizontal_separator; - gboolean cursor_row = FALSE; - gboolean first_cell = TRUE; - gboolean rtl; - /* If we have rtl text, we need to transform our areas */ - GdkRectangle rtl_cell_area; - GdkRectangle rtl_background_area; - - min_x = G_MAXINT; - min_y = G_MAXINT; - max_x = 0; - max_y = 0; + priv = tree_column->priv; - rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL); - special_cells = _gtk_tree_view_column_count_special_cells (tree_column); - - if (special_cells > 1 && action == CELL_ACTION_FOCUS) - { - GtkTreeViewColumnCellInfo *info = NULL; - gboolean found_has_focus = FALSE; + g_signal_handler_block (priv->cell_area_context, + priv->context_changed_signal); - /* one should have focus */ - for (list = tree_column->cell_list; list; list = list->next) - { - info = list->data; - if (info && info->has_focus) - { - found_has_focus = TRUE; - break; - } - } + gtk_cell_area_get_preferred_width (priv->cell_area, + priv->cell_area_context, + priv->tree_view, + NULL, NULL); - if (!found_has_focus) - { - /* give the first one focus */ - info = gtk_tree_view_column_cell_first (tree_column)->data; - info->has_focus = TRUE; - } - } + gtk_cell_area_context_get_preferred_width (priv->cell_area_context, &min_width, NULL); - cursor_row = flags & GTK_CELL_RENDERER_FOCUSED; + gtk_cell_area_get_preferred_height_for_width (priv->cell_area, + priv->cell_area_context, + priv->tree_view, + min_width, + &min_height, + NULL); - gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view), - "focus-line-width", &focus_line_width, - "horizontal-separator", &horizontal_separator, - NULL); + g_signal_handler_unblock (priv->cell_area_context, + priv->context_changed_signal); - real_cell_area = *cell_area; - real_background_area = *background_area; + if (height) + * height = min_height; + if (width) + * width = min_width; - real_cell_area.x += focus_line_width; - real_cell_area.y += focus_line_width; - real_cell_area.height -= 2 * focus_line_width; +} - if (rtl) - depth = real_background_area.width - real_cell_area.width; - else - depth = real_cell_area.x - real_background_area.x; +/** + * gtk_tree_view_column_cell_render: + * @tree_column: A #GtkTreeViewColumn. + * @cr: cairo context to draw to + * @background_area: entire cell area (including tree expanders and maybe padding on the sides) + * @cell_area: area normally rendered by a cell renderer + * @flags: flags that affect rendering + * + * Renders the cell contained by #tree_column. This is used primarily by the + * #GtkTreeView. + **/ +void +_gtk_tree_view_column_cell_render (GtkTreeViewColumn *tree_column, + cairo_t *cr, + const GdkRectangle *background_area, + const GdkRectangle *cell_area, + guint flags, + gboolean draw_focus) +{ + GtkTreeViewColumnPrivate *priv; - /* Find out how much extra space we have to allocate */ - for (list = tree_column->cell_list; list; list = list->next) - { - GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *)list->data; + g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); + g_return_if_fail (cr != NULL); + g_return_if_fail (background_area != NULL); + g_return_if_fail (cell_area != NULL); - if (!gtk_cell_renderer_get_visible (info->cell)) - continue; + priv = tree_column->priv; - if (info->expand == TRUE) - expand_cell_count ++; - full_requested_width += info->requested_width; + cairo_save (cr); - if (!first_cell) - full_requested_width += tree_column->spacing; + gtk_cell_area_render (priv->cell_area, priv->cell_area_context, + priv->tree_view, cr, + background_area, cell_area, flags, + draw_focus); - first_cell = FALSE; - } + cairo_restore (cr); +} - extra_space = cell_area->width - full_requested_width; - if (extra_space < 0) - extra_space = 0; - else if (extra_space > 0 && expand_cell_count > 0) - extra_space /= expand_cell_count; +gboolean +_gtk_tree_view_column_cell_event (GtkTreeViewColumn *tree_column, + GdkEvent *event, + const GdkRectangle *cell_area, + guint flags) +{ + GtkTreeViewColumnPrivate *priv; - /* iterate list for GTK_PACK_START cells */ - for (list = tree_column->cell_list; list; list = list->next) - { - GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data; + g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE); - if (info->pack == GTK_PACK_END) - continue; + priv = tree_column->priv; - if (!gtk_cell_renderer_get_visible (info->cell)) - continue; + return gtk_cell_area_event (priv->cell_area, + priv->cell_area_context, + priv->tree_view, + event, + cell_area, + flags); +} - if ((info->has_focus || special_cells == 1) && cursor_row) - flags |= GTK_CELL_RENDERER_FOCUSED; - else - flags &= ~GTK_CELL_RENDERER_FOCUSED; +/** + * gtk_tree_view_column_cell_is_visible: + * @tree_column: A #GtkTreeViewColumn + * + * Returns %TRUE if any of the cells packed into the @tree_column are visible. + * For this to be meaningful, you must first initialize the cells with + * gtk_tree_view_column_cell_set_cell_data() + * + * Return value: %TRUE, if any of the cells packed into the @tree_column are currently visible + **/ +gboolean +gtk_tree_view_column_cell_is_visible (GtkTreeViewColumn *tree_column) +{ + GList *list; + GList *cells; + GtkTreeViewColumnPrivate *priv; - info->real_width = info->requested_width + (info->expand?extra_space:0); + g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE); - /* We constrain ourselves to only the width available */ - if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width) - { - info->real_width = cell_area->x + cell_area->width - real_cell_area.x; - } + priv = tree_column->priv; - if (real_cell_area.x > cell_area->x + cell_area->width) - break; + cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (priv->cell_area)); + for (list = cells; list; list = list->next) + { + if (gtk_cell_renderer_get_visible (list->data)) + { + g_list_free (cells); + return TRUE; + } + } - real_cell_area.width = info->real_width; - real_cell_area.width -= 2 * focus_line_width; + g_list_free (cells); - if (list->next) - { - real_background_area.width = info->real_width + depth; - } - else - { - /* fill the rest of background for the last cell */ - real_background_area.width = background_area->x + background_area->width - real_background_area.x; - } - - rtl_cell_area = real_cell_area; - rtl_background_area = real_background_area; - - if (rtl) - { - rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width; - rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width; - } - - /* RENDER */ - if (action == CELL_ACTION_RENDER) - { - gtk_cell_renderer_render (info->cell, - window, - tree_column->tree_view, - &rtl_background_area, - &rtl_cell_area, - &real_expose_area, - flags); - } - /* FOCUS */ - else if (action == CELL_ACTION_FOCUS) - { - gint x_offset, y_offset, width, height; - - gtk_cell_renderer_get_size (info->cell, - tree_column->tree_view, - &rtl_cell_area, - &x_offset, &y_offset, - &width, &height); - - if (special_cells > 1) - { - if (info->has_focus) - { - min_x = rtl_cell_area.x + x_offset; - max_x = min_x + width; - min_y = rtl_cell_area.y + y_offset; - max_y = min_y + height; - } - } - else - { - if (min_x > (rtl_cell_area.x + x_offset)) - min_x = rtl_cell_area.x + x_offset; - if (max_x < rtl_cell_area.x + x_offset + width) - max_x = rtl_cell_area.x + x_offset + width; - if (min_y > (rtl_cell_area.y + y_offset)) - min_y = rtl_cell_area.y + y_offset; - if (max_y < rtl_cell_area.y + y_offset + height) - max_y = rtl_cell_area.y + y_offset + height; - } - } - /* EVENT */ - else if (action == CELL_ACTION_EVENT) - { - gboolean try_event = FALSE; - - if (event) - { - if (special_cells == 1) - { - /* only 1 activatable cell -> whole column can activate */ - if (cell_area->x <= ((GdkEventButton *)event)->x && - cell_area->x + cell_area->width > ((GdkEventButton *)event)->x) - try_event = TRUE; - } - else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x && - rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x) - /* only activate cell if the user clicked on an individual - * cell - */ - try_event = TRUE; - } - else if (special_cells > 1 && info->has_focus) - try_event = TRUE; - else if (special_cells == 1) - try_event = TRUE; - - if (try_event) - { - gboolean visible, mode; - - g_object_get (info->cell, - "visible", &visible, - "mode", &mode, - NULL); - if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE) - { - if (gtk_cell_renderer_activate (info->cell, - event, - tree_column->tree_view, - path_string, - &rtl_background_area, - &rtl_cell_area, - flags)) - { - flags &= ~GTK_CELL_RENDERER_FOCUSED; - return TRUE; - } - } - else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE) - { - *editable_widget = - gtk_cell_renderer_start_editing (info->cell, - event, - tree_column->tree_view, - path_string, - &rtl_background_area, - &rtl_cell_area, - flags); - - if (*editable_widget != NULL) - { - g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE); - info->in_editing_mode = TRUE; - gtk_tree_view_column_focus_cell (tree_column, info->cell); - - flags &= ~GTK_CELL_RENDERER_FOCUSED; - - return TRUE; - } - } - } - } - - flags &= ~GTK_CELL_RENDERER_FOCUSED; - - real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing); - real_background_area.x += real_background_area.width + tree_column->spacing; - - /* Only needed for first cell */ - depth = 0; - } - - /* iterate list for PACK_END cells */ - for (list = g_list_last (tree_column->cell_list); list; list = list->prev) - { - GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data; - - if (info->pack == GTK_PACK_START) - continue; - - if (!gtk_cell_renderer_get_visible(info->cell)) - continue; - - if ((info->has_focus || special_cells == 1) && cursor_row) - flags |= GTK_CELL_RENDERER_FOCUSED; - else - flags &= ~GTK_CELL_RENDERER_FOCUSED; - - info->real_width = info->requested_width + (info->expand?extra_space:0); - - /* We constrain ourselves to only the width available */ - if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width) - { - info->real_width = cell_area->x + cell_area->width - real_cell_area.x; - } - - if (real_cell_area.x > cell_area->x + cell_area->width) - break; - - real_cell_area.width = info->real_width; - real_cell_area.width -= 2 * focus_line_width; - real_background_area.width = info->real_width + depth; - - rtl_cell_area = real_cell_area; - rtl_background_area = real_background_area; - if (rtl) - { - rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width; - rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width; - } - - /* RENDER */ - if (action == CELL_ACTION_RENDER) - { - gtk_cell_renderer_render (info->cell, - window, - tree_column->tree_view, - &rtl_background_area, - &rtl_cell_area, - &real_expose_area, - flags); - } - /* FOCUS */ - else if (action == CELL_ACTION_FOCUS) - { - gint x_offset, y_offset, width, height; - - gtk_cell_renderer_get_size (info->cell, - tree_column->tree_view, - &rtl_cell_area, - &x_offset, &y_offset, - &width, &height); - - if (special_cells > 1) - { - if (info->has_focus) - { - min_x = rtl_cell_area.x + x_offset; - max_x = min_x + width; - min_y = rtl_cell_area.y + y_offset; - max_y = min_y + height; - } - } - else - { - if (min_x > (rtl_cell_area.x + x_offset)) - min_x = rtl_cell_area.x + x_offset; - if (max_x < rtl_cell_area.x + x_offset + width) - max_x = rtl_cell_area.x + x_offset + width; - if (min_y > (rtl_cell_area.y + y_offset)) - min_y = rtl_cell_area.y + y_offset; - if (max_y < rtl_cell_area.y + y_offset + height) - max_y = rtl_cell_area.y + y_offset + height; - } - } - /* EVENT */ - else if (action == CELL_ACTION_EVENT) - { - gboolean try_event = FALSE; - - if (event) - { - if (special_cells == 1) - { - /* only 1 activatable cell -> whole column can activate */ - if (cell_area->x <= ((GdkEventButton *)event)->x && - cell_area->x + cell_area->width > ((GdkEventButton *)event)->x) - try_event = TRUE; - } - else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x && - rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x) - /* only activate cell if the user clicked on an individual - * cell - */ - try_event = TRUE; - } - else if (special_cells > 1 && info->has_focus) - try_event = TRUE; - else if (special_cells == 1) - try_event = TRUE; - - if (try_event) - { - gboolean visible, mode; - - g_object_get (info->cell, - "visible", &visible, - "mode", &mode, - NULL); - if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE) - { - if (gtk_cell_renderer_activate (info->cell, - event, - tree_column->tree_view, - path_string, - &rtl_background_area, - &rtl_cell_area, - flags)) - { - flags &= ~GTK_CELL_RENDERER_FOCUSED; - return TRUE; - } - } - else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE) - { - *editable_widget = - gtk_cell_renderer_start_editing (info->cell, - event, - tree_column->tree_view, - path_string, - &rtl_background_area, - &rtl_cell_area, - flags); - - if (*editable_widget != NULL) - { - g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE); - info->in_editing_mode = TRUE; - gtk_tree_view_column_focus_cell (tree_column, info->cell); - - flags &= ~GTK_CELL_RENDERER_FOCUSED; - return TRUE; - } - } - } - } - - flags &= ~GTK_CELL_RENDERER_FOCUSED; - - real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing); - real_background_area.x += (real_background_area.width + tree_column->spacing); - - /* Only needed for first cell */ - depth = 0; - } - - /* fill focus_rectangle when required */ - if (action == CELL_ACTION_FOCUS) - { - if (min_x >= max_x || min_y >= max_y) - { - *focus_rectangle = *cell_area; - /* don't change the focus_rectangle, just draw it nicely inside - * the cell area */ - } - else - { - focus_rectangle->x = min_x - focus_line_width; - focus_rectangle->y = min_y - focus_line_width; - focus_rectangle->width = (max_x - min_x) + 2 * focus_line_width; - focus_rectangle->height = (max_y - min_y) + 2 * focus_line_width; - } - } - - return FALSE; -} - -/** - * gtk_tree_view_column_cell_render: - * @tree_column: A #GtkTreeViewColumn. - * @window: a #GdkDrawable to draw to - * @background_area: entire cell area (including tree expanders and maybe padding on the sides) - * @cell_area: area normally rendered by a cell renderer - * @expose_area: area that actually needs updating - * @flags: flags that affect rendering - * - * Renders the cell contained by #tree_column. This is used primarily by the - * #GtkTreeView. - **/ -void -_gtk_tree_view_column_cell_render (GtkTreeViewColumn *tree_column, - GdkWindow *window, - const GdkRectangle *background_area, - const GdkRectangle *cell_area, - const GdkRectangle *expose_area, - guint flags) -{ - g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); - g_return_if_fail (background_area != NULL); - g_return_if_fail (cell_area != NULL); - g_return_if_fail (expose_area != NULL); - - gtk_tree_view_column_cell_process_action (tree_column, - window, - background_area, - cell_area, - flags, - CELL_ACTION_RENDER, - expose_area, - NULL, NULL, NULL, NULL); -} - -gboolean -_gtk_tree_view_column_cell_event (GtkTreeViewColumn *tree_column, - GtkCellEditable **editable_widget, - GdkEvent *event, - gchar *path_string, - const GdkRectangle *background_area, - const GdkRectangle *cell_area, - guint flags) -{ - g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE); - - return gtk_tree_view_column_cell_process_action (tree_column, - NULL, - background_area, - cell_area, - flags, - CELL_ACTION_EVENT, - NULL, NULL, - editable_widget, - event, - path_string); -} - -void -_gtk_tree_view_column_get_focus_area (GtkTreeViewColumn *tree_column, - const GdkRectangle *background_area, - const GdkRectangle *cell_area, - GdkRectangle *focus_area) -{ - gtk_tree_view_column_cell_process_action (tree_column, - NULL, - background_area, - cell_area, - 0, - CELL_ACTION_FOCUS, - NULL, - focus_area, - NULL, NULL, NULL); -} - - -/* cell list manipulation */ -static GList * -gtk_tree_view_column_cell_first (GtkTreeViewColumn *tree_column) -{ - GList *list = tree_column->cell_list; - - /* first GTK_PACK_START cell we find */ - for ( ; list; list = list->next) - { - GtkTreeViewColumnCellInfo *info = list->data; - if (info->pack == GTK_PACK_START) - return list; - } - - /* hmm, else the *last* GTK_PACK_END cell */ - list = g_list_last (tree_column->cell_list); - - for ( ; list; list = list->prev) - { - GtkTreeViewColumnCellInfo *info = list->data; - if (info->pack == GTK_PACK_END) - return list; - } - - return NULL; -} - -static GList * -gtk_tree_view_column_cell_last (GtkTreeViewColumn *tree_column) -{ - GList *list = tree_column->cell_list; - - /* *first* GTK_PACK_END cell we find */ - for ( ; list ; list = list->next) - { - GtkTreeViewColumnCellInfo *info = list->data; - if (info->pack == GTK_PACK_END) - return list; - } - - /* hmm, else the last GTK_PACK_START cell */ - list = g_list_last (tree_column->cell_list); - - for ( ; list; list = list->prev) - { - GtkTreeViewColumnCellInfo *info = list->data; - if (info->pack == GTK_PACK_START) - return list; - } - - return NULL; -} - -static GList * -gtk_tree_view_column_cell_next (GtkTreeViewColumn *tree_column, - GList *current) -{ - GList *list; - GtkTreeViewColumnCellInfo *info = current->data; - - if (info->pack == GTK_PACK_START) - { - for (list = current->next; list; list = list->next) - { - GtkTreeViewColumnCellInfo *inf = list->data; - if (inf->pack == GTK_PACK_START) - return list; - } - - /* out of GTK_PACK_START cells, get *last* GTK_PACK_END one */ - list = g_list_last (tree_column->cell_list); - for (; list; list = list->prev) - { - GtkTreeViewColumnCellInfo *inf = list->data; - if (inf->pack == GTK_PACK_END) - return list; - } - } - - for (list = current->prev; list; list = list->prev) - { - GtkTreeViewColumnCellInfo *inf = list->data; - if (inf->pack == GTK_PACK_END) - return list; - } - - return NULL; -} - -static GList * -gtk_tree_view_column_cell_prev (GtkTreeViewColumn *tree_column, - GList *current) -{ - GList *list; - GtkTreeViewColumnCellInfo *info = current->data; - - if (info->pack == GTK_PACK_END) - { - for (list = current->next; list; list = list->next) - { - GtkTreeViewColumnCellInfo *inf = list->data; - if (inf->pack == GTK_PACK_END) - return list; - } - - /* out of GTK_PACK_END, get last GTK_PACK_START one */ - list = g_list_last (tree_column->cell_list); - for ( ; list; list = list->prev) - { - GtkTreeViewColumnCellInfo *inf = list->data; - if (inf->pack == GTK_PACK_START) - return list; - } - } - - for (list = current->prev; list; list = list->prev) - { - GtkTreeViewColumnCellInfo *inf = list->data; - if (inf->pack == GTK_PACK_START) - return list; - } - - return NULL; -} - -gboolean -_gtk_tree_view_column_cell_focus (GtkTreeViewColumn *tree_column, - gint direction, - gboolean left, - gboolean right) -{ - gint count; - gboolean rtl; - - count = _gtk_tree_view_column_count_special_cells (tree_column); - rtl = gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL; - - /* if we are the current focus column and have multiple editable cells, - * try to select the next one, else move the focus to the next column - */ - if (GTK_TREE_VIEW (tree_column->tree_view)->priv->focus_column == tree_column) - { - if (count > 1) - { - GList *next, *prev; - GList *list = tree_column->cell_list; - GtkTreeViewColumnCellInfo *info = NULL; - - /* find current focussed cell */ - for ( ; list; list = list->next) - { - info = list->data; - if (info->has_focus) - break; - } - - /* not a focussed cell in the focus column? */ - if (!list || !info || !info->has_focus) - return FALSE; - - if (rtl) - { - prev = gtk_tree_view_column_cell_next (tree_column, list); - next = gtk_tree_view_column_cell_prev (tree_column, list); - } - else - { - next = gtk_tree_view_column_cell_next (tree_column, list); - prev = gtk_tree_view_column_cell_prev (tree_column, list); - } - - info->has_focus = FALSE; - if (direction > 0 && next) - { - info = next->data; - info->has_focus = TRUE; - return TRUE; - } - else if (direction > 0 && !next && !right) - { - /* keep focus on last cell */ - if (rtl) - info = gtk_tree_view_column_cell_first (tree_column)->data; - else - info = gtk_tree_view_column_cell_last (tree_column)->data; - - info->has_focus = TRUE; - return TRUE; - } - else if (direction < 0 && prev) - { - info = prev->data; - info->has_focus = TRUE; - return TRUE; - } - else if (direction < 0 && !prev && !left) - { - /* keep focus on first cell */ - if (rtl) - info = gtk_tree_view_column_cell_last (tree_column)->data; - else - info = gtk_tree_view_column_cell_first (tree_column)->data; - - info->has_focus = TRUE; - return TRUE; - } - } - return FALSE; - } - - /* we get focus, if we have multiple editable cells, give the correct one - * focus - */ - if (count > 1) - { - GList *list = tree_column->cell_list; - - /* clear focus first */ - for ( ; list ; list = list->next) - { - GtkTreeViewColumnCellInfo *info = list->data; - if (info->has_focus) - info->has_focus = FALSE; - } - - list = NULL; - if (rtl) - { - if (direction > 0) - list = gtk_tree_view_column_cell_last (tree_column); - else if (direction < 0) - list = gtk_tree_view_column_cell_first (tree_column); - } - else - { - if (direction > 0) - list = gtk_tree_view_column_cell_first (tree_column); - else if (direction < 0) - list = gtk_tree_view_column_cell_last (tree_column); - } - - if (list) - ((GtkTreeViewColumnCellInfo *) list->data)->has_focus = TRUE; - } - - return TRUE; -} - -void -_gtk_tree_view_column_cell_draw_focus (GtkTreeViewColumn *tree_column, - GdkWindow *window, - const GdkRectangle *background_area, - const GdkRectangle *cell_area, - const GdkRectangle *expose_area, - guint flags) -{ - gint focus_line_width; - GtkStateType cell_state; - - g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); - gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view), - "focus-line-width", &focus_line_width, NULL); - if (tree_column->editable_widget) - { - /* This function is only called on the editable row when editing. - */ -#if 0 - gtk_paint_focus (tree_column->tree_view->style, - window, - gtk_widget_get_state (tree_column->tree_view), - NULL, - tree_column->tree_view, - "treeview", - cell_area->x - focus_line_width, - cell_area->y - focus_line_width, - cell_area->width + 2 * focus_line_width, - cell_area->height + 2 * focus_line_width); -#endif - } - else - { - GdkRectangle focus_rectangle; - gtk_tree_view_column_cell_process_action (tree_column, - window, - background_area, - cell_area, - flags, - CELL_ACTION_FOCUS, - expose_area, - &focus_rectangle, - NULL, NULL, NULL); - - cell_state = flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED : - (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT : - (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL)); - gtk_paint_focus (tree_column->tree_view->style, - window, - cell_state, - cell_area, - tree_column->tree_view, - "treeview", - focus_rectangle.x, - focus_rectangle.y, - focus_rectangle.width, - focus_rectangle.height); - } -} - -/** - * gtk_tree_view_column_cell_is_visible: - * @tree_column: A #GtkTreeViewColumn - * - * Returns %TRUE if any of the cells packed into the @tree_column are visible. - * For this to be meaningful, you must first initialize the cells with - * gtk_tree_view_column_cell_set_cell_data() - * - * Return value: %TRUE, if any of the cells packed into the @tree_column are currently visible - **/ -gboolean -gtk_tree_view_column_cell_is_visible (GtkTreeViewColumn *tree_column) -{ - GList *list; - - g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE); - - for (list = tree_column->cell_list; list; list = list->next) - { - GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data; - - if (gtk_cell_renderer_get_visible (info->cell)) - return TRUE; - } - - return FALSE; -} + return FALSE; +} /** * gtk_tree_view_column_focus_cell: @@ -3560,142 +3031,53 @@ void gtk_tree_view_column_focus_cell (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell) { - GList *list; - gboolean found_cell = FALSE; - g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); g_return_if_fail (GTK_IS_CELL_RENDERER (cell)); - if (_gtk_tree_view_column_count_special_cells (tree_column) < 2) - return; - - for (list = tree_column->cell_list; list; list = list->next) - { - GtkTreeViewColumnCellInfo *info = list->data; - - if (info->cell == cell) - { - info->has_focus = TRUE; - found_cell = TRUE; - break; - } - } - - if (found_cell) - { - for (list = tree_column->cell_list; list; list = list->next) - { - GtkTreeViewColumnCellInfo *info = list->data; - - if (info->cell != cell) - info->has_focus = FALSE; - } - - /* FIXME: redraw? */ - } + gtk_cell_area_set_focus_cell (tree_column->priv->cell_area, cell); } void _gtk_tree_view_column_cell_set_dirty (GtkTreeViewColumn *tree_column, gboolean install_handler) { - GList *list; + GtkTreeViewColumnPrivate *priv = tree_column->priv; - for (list = tree_column->cell_list; list; list = list->next) - { - GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data; + priv->dirty = TRUE; + priv->padding = 0; + priv->width = 0; - info->requested_width = 0; - } - tree_column->dirty = TRUE; - tree_column->requested_width = -1; - tree_column->width = 0; + /* Issue a manual reset on the context to have all + * sizes re-requested for the context. + */ + g_signal_handler_block (priv->cell_area_context, + priv->context_changed_signal); + gtk_cell_area_context_reset (priv->cell_area_context); + g_signal_handler_unblock (priv->cell_area_context, + priv->context_changed_signal); - if (tree_column->tree_view && - gtk_widget_get_realized (tree_column->tree_view)) + if (priv->tree_view && + gtk_widget_get_realized (priv->tree_view)) { - if (install_handler) - _gtk_tree_view_install_mark_rows_col_dirty (GTK_TREE_VIEW (tree_column->tree_view)); - else - GTK_TREE_VIEW (tree_column->tree_view)->priv->mark_rows_col_dirty = TRUE; - gtk_widget_queue_resize (tree_column->tree_view); + _gtk_tree_view_install_mark_rows_col_dirty (GTK_TREE_VIEW (priv->tree_view), install_handler); + gtk_widget_queue_resize (priv->tree_view); } } -void -_gtk_tree_view_column_start_editing (GtkTreeViewColumn *tree_column, - GtkCellEditable *cell_editable) -{ - g_return_if_fail (tree_column->editable_widget == NULL); - - tree_column->editable_widget = cell_editable; -} - -void -_gtk_tree_view_column_stop_editing (GtkTreeViewColumn *tree_column) -{ - GList *list; - - g_return_if_fail (tree_column->editable_widget != NULL); - - tree_column->editable_widget = NULL; - for (list = tree_column->cell_list; list; list = list->next) - ((GtkTreeViewColumnCellInfo *)list->data)->in_editing_mode = FALSE; -} - -void -_gtk_tree_view_column_get_neighbor_sizes (GtkTreeViewColumn *column, - GtkCellRenderer *cell, - gint *left, - gint *right) +gboolean +_gtk_tree_view_column_cell_get_dirty (GtkTreeViewColumn *tree_column) { - GList *list; - GtkTreeViewColumnCellInfo *info; - gint l, r; - gboolean rtl; - - l = r = 0; - - list = gtk_tree_view_column_cell_first (column); - - while (list) - { - info = (GtkTreeViewColumnCellInfo *)list->data; - - list = gtk_tree_view_column_cell_next (column, list); - - if (info->cell == cell) - break; - - if (gtk_cell_renderer_get_visible (info->cell)) - l += info->real_width + column->spacing; - } - - while (list) - { - info = (GtkTreeViewColumnCellInfo *)list->data; - - list = gtk_tree_view_column_cell_next (column, list); - - if (gtk_cell_renderer_get_visible (info->cell)) - r += info->real_width + column->spacing; - } - - rtl = (gtk_widget_get_direction (GTK_WIDGET (column->tree_view)) == GTK_TEXT_DIR_RTL); - if (left) - *left = rtl ? r : l; - - if (right) - *right = rtl ? l : r; + return tree_column->priv->dirty; } /** * gtk_tree_view_column_cell_get_position: * @tree_column: a #GtkTreeViewColumn * @cell_renderer: a #GtkCellRenderer - * @start_pos: return location for the horizontal position of @cell within - * @tree_column, may be %NULL - * @width: return location for the width of @cell, may be %NULL + * @x_offset: (out) (allow-none): return location for the horizontal + * position of @cell within @tree_column, may be %NULL + * @width: (out) (allow-none): return location for the width of @cell, + * may be %NULL * * Obtains the horizontal position and size of a cell in a column. If the * cell is not found in the column, @start_pos and @width are not changed and @@ -3706,37 +3088,38 @@ _gtk_tree_view_column_get_neighbor_sizes (GtkTreeViewColumn *column, gboolean gtk_tree_view_column_cell_get_position (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell_renderer, - gint *start_pos, + gint *x_offset, gint *width) { - GList *list; - gint current_x = 0; - gboolean found_cell = FALSE; - GtkTreeViewColumnCellInfo *cellinfo = NULL; + GtkTreeViewColumnPrivate *priv; + GdkRectangle cell_area; + GdkRectangle allocation; - list = gtk_tree_view_column_cell_first (tree_column); - for (; list; list = gtk_tree_view_column_cell_next (tree_column, list)) - { - cellinfo = list->data; - if (cellinfo->cell == cell_renderer) - { - found_cell = TRUE; - break; - } + g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE); + g_return_val_if_fail (GTK_IS_CELL_RENDERER (cell_renderer), FALSE); - if (gtk_cell_renderer_get_visible (cellinfo->cell)) - current_x += cellinfo->real_width; - } + priv = tree_column->priv; - if (found_cell) - { - if (start_pos) - *start_pos = current_x; - if (width) - *width = cellinfo->real_width; - } + if (! gtk_cell_area_has_renderer (priv->cell_area, cell_renderer)) + return FALSE; + + gtk_tree_view_get_background_area (GTK_TREE_VIEW (priv->tree_view), + NULL, tree_column, &cell_area); - return found_cell; + gtk_cell_area_get_cell_allocation (priv->cell_area, + priv->cell_area_context, + priv->tree_view, + cell_renderer, + &cell_area, + &allocation); + + if (x_offset) + *x_offset = allocation.x - cell_area.x; + + if (width) + *width = allocation.width; + + return TRUE; } /** @@ -3753,7 +3136,7 @@ gtk_tree_view_column_queue_resize (GtkTreeViewColumn *tree_column) { g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column)); - if (tree_column->tree_view) + if (tree_column->priv->tree_view) _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE); } @@ -3761,12 +3144,12 @@ gtk_tree_view_column_queue_resize (GtkTreeViewColumn *tree_column) * gtk_tree_view_column_get_tree_view: * @tree_column: A #GtkTreeViewColumn * - * Returns the #GtkTreeView wherein @tree_column has been inserted. If - * @column is currently not inserted in any tree view, %NULL is + * Returns the #GtkTreeView wherein @tree_column has been inserted. + * If @column is currently not inserted in any tree view, %NULL is * returned. * - * Return value: The tree view wherein @column has been inserted if any, - * %NULL otherwise. + * Return value: (transfer none): The tree view wherein @column has + * been inserted if any, %NULL otherwise. * * Since: 2.12 */ @@ -3775,5 +3158,58 @@ gtk_tree_view_column_get_tree_view (GtkTreeViewColumn *tree_column) { g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), NULL); - return tree_column->tree_view; + return tree_column->priv->tree_view; +} + +/** + * gtk_tree_view_column_get_button: + * @tree_column: A #GtkTreeViewColumn + * + * Returns the button used in the treeview column header + * + * Return value: (transfer none): The button for the column header. + * + * Since: 3.0 + */ +GtkWidget * +gtk_tree_view_column_get_button (GtkTreeViewColumn *tree_column) +{ + g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), NULL); + + return tree_column->priv->button; +} + +GdkWindow * +_gtk_tree_view_column_get_window (GtkTreeViewColumn *column) +{ + return column->priv->window; +} + +void +_gtk_tree_view_column_push_padding (GtkTreeViewColumn *column, + gint padding) +{ + column->priv->padding = MAX (column->priv->padding, padding); +} + +gint +_gtk_tree_view_column_get_requested_width (GtkTreeViewColumn *column) +{ + gint requested_width; + + gtk_cell_area_context_get_preferred_width (column->priv->cell_area_context, &requested_width, NULL); + + return requested_width + column->priv->padding; +} + +gint +_gtk_tree_view_column_get_drag_x (GtkTreeViewColumn *column) +{ + return column->priv->drag_x; +} + +GtkCellAreaContext * +_gtk_tree_view_column_get_context (GtkTreeViewColumn *column) +{ + return column->priv->cell_area_context; }