1 /* gtktreeviewcolumn.c
2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include "gtktreeviewcolumn.h"
21 
22 #include "gtkbox.h"
23 #include "gtkbutton.h"
24 #include "gtkcellareabox.h"
25 #include "gtkcellareacontext.h"
26 #include "gtkcelllayout.h"
27 #include "gtkdragsourceprivate.h"
28 #include "gtkframe.h"
29 #include "gtkimage.h"
30 #include "gtkintl.h"
31 #include "gtklabel.h"
32 #include "gtkmarshalers.h"
33 #include "gtkprivate.h"
34 #include "gtktreeprivate.h"
35 #include "gtktreeview.h"
36 #include "gtktypebuiltins.h"
37 #include "gtkwidgetprivate.h"
38 #include "gtkgesturedrag.h"
39 #include "gtkeventcontrollerfocus.h"
40 #include "gtkeventcontrollerkey.h"
41 #include "gtkbuiltiniconprivate.h"
42 
43 #include <string.h>
44 
45 
46 /**
47  * GtkTreeViewColumn:
48  *
49  * A visible column in a GtkTreeView widget
50  *
51  * The GtkTreeViewColumn object represents a visible column in a `GtkTreeView` widget.
52  * It allows to set properties of the column header, and functions as a holding pen
53  * for the cell renderers which determine how the data in the column is displayed.
54  *
55  * Please refer to the [tree widget conceptual overview][TreeWidget]
56  * for an overview of all the objects and data types related to the tree widget and
57  * how they work together, and to the `GtkTreeView` documentation for specifics about
58  * the CSS node structure for treeviews and their headers.
59  */
60 
61 
62 /* Type methods */
63 static void gtk_tree_view_column_cell_layout_init              (GtkCellLayoutIface      *iface);
64 
65 /* GObject methods */
66 static void gtk_tree_view_column_set_property                  (GObject                 *object,
67 								guint                    prop_id,
68 								const GValue            *value,
69 								GParamSpec              *pspec);
70 static void gtk_tree_view_column_get_property                  (GObject                 *object,
71 								guint                    prop_id,
72 								GValue                  *value,
73 								GParamSpec              *pspec);
74 static void gtk_tree_view_column_finalize                      (GObject                 *object);
75 static void gtk_tree_view_column_dispose                       (GObject                 *object);
76 static void gtk_tree_view_column_constructed                   (GObject                 *object);
77 
78 /* GtkCellLayout implementation */
79 static void       gtk_tree_view_column_ensure_cell_area        (GtkTreeViewColumn      *column,
80                                                                 GtkCellArea            *cell_area);
81 
82 static GtkCellArea *gtk_tree_view_column_cell_layout_get_area  (GtkCellLayout           *cell_layout);
83 
84 /* Button handling code */
85 static void gtk_tree_view_column_create_button                 (GtkTreeViewColumn       *tree_column);
86 static void gtk_tree_view_column_update_button                 (GtkTreeViewColumn       *tree_column);
87 
88 /* Button signal handlers */
89 static void column_button_drag_begin  (GtkGestureDrag    *gesture,
90                                        double             x,
91                                        double             y,
92                                        GtkTreeViewColumn *column);
93 static void column_button_drag_update (GtkGestureDrag    *gesture,
94                                        double             offset_x,
95                                        double             offset_y,
96                                        GtkTreeViewColumn *column);
97 
98 static void gtk_tree_view_column_button_clicked                (GtkWidget               *widget,
99 								gpointer                 data);
100 static gboolean gtk_tree_view_column_mnemonic_activate         (GtkWidget *widget,
101 					                        gboolean   group_cycling,
102 								gpointer   data);
103 
104 /* Property handlers */
105 static void gtk_tree_view_model_sort_column_changed            (GtkTreeSortable         *sortable,
106 								GtkTreeViewColumn       *tree_column);
107 
108 /* GtkCellArea/GtkCellAreaContext callbacks */
109 static void gtk_tree_view_column_context_changed               (GtkCellAreaContext      *context,
110 								GParamSpec              *pspec,
111 								GtkTreeViewColumn       *tree_column);
112 static void gtk_tree_view_column_add_editable_callback         (GtkCellArea             *area,
113 								GtkCellRenderer         *renderer,
114 								GtkCellEditable         *edit_widget,
115 								GdkRectangle            *cell_area,
116 								const char              *path_string,
117 								gpointer                 user_data);
118 static void gtk_tree_view_column_remove_editable_callback      (GtkCellArea             *area,
119 								GtkCellRenderer         *renderer,
120 								GtkCellEditable         *edit_widget,
121 								gpointer                 user_data);
122 
123 /* Internal functions */
124 static void gtk_tree_view_column_sort                          (GtkTreeViewColumn       *tree_column,
125 								gpointer                 data);
126 static void gtk_tree_view_column_setup_sort_column_id_callback (GtkTreeViewColumn       *tree_column);
127 static void gtk_tree_view_column_set_attributesv               (GtkTreeViewColumn       *tree_column,
128 								GtkCellRenderer         *cell_renderer,
129 								va_list                  args);
130 
131 /* GtkBuildable implementation */
132 static void gtk_tree_view_column_buildable_init                 (GtkBuildableIface     *iface);
133 
134 typedef struct _GtkTreeViewColumnClass   GtkTreeViewColumnClass;
135 typedef struct _GtkTreeViewColumnPrivate GtkTreeViewColumnPrivate;
136 
137 struct _GtkTreeViewColumn
138 {
139   GInitiallyUnowned parent_instance;
140 
141   GtkTreeViewColumnPrivate *priv;
142 };
143 
144 struct _GtkTreeViewColumnClass
145 {
146   GInitiallyUnownedClass parent_class;
147 
148   void (*clicked) (GtkTreeViewColumn *tree_column);
149 };
150 
151 
152 struct _GtkTreeViewColumnPrivate
153 {
154   GtkWidget *tree_view;
155   GtkWidget *button;
156   GtkWidget *child;
157   GtkWidget *arrow;
158   GtkWidget *frame;
159   gulong property_changed_signal;
160   float xalign;
161 
162   /* Sizing fields */
163   /* see gtk+/doc/tree-column-sizing.txt for more information on them */
164   GtkTreeViewColumnSizing column_type;
165   int padding;
166   int x_offset;
167   int width;
168   int fixed_width;
169   int min_width;
170   int max_width;
171 
172   /* dragging columns */
173   int drag_x;
174   int drag_y;
175 
176   char *title;
177 
178   /* Sorting */
179   gulong      sort_clicked_signal;
180   gulong      sort_column_changed_signal;
181   int         sort_column_id;
182   GtkSortType sort_order;
183 
184   /* Cell area */
185   GtkCellArea        *cell_area;
186   GtkCellAreaContext *cell_area_context;
187   gulong              add_editable_signal;
188   gulong              remove_editable_signal;
189   gulong              context_changed_signal;
190 
191   /* Flags */
192   guint visible             : 1;
193   guint resizable           : 1;
194   guint clickable           : 1;
195   guint dirty               : 1;
196   guint show_sort_indicator : 1;
197   guint maybe_reordered     : 1;
198   guint reorderable         : 1;
199   guint expand              : 1;
200 };
201 
202 enum
203 {
204   PROP_0,
205   PROP_VISIBLE,
206   PROP_RESIZABLE,
207   PROP_X_OFFSET,
208   PROP_WIDTH,
209   PROP_SPACING,
210   PROP_SIZING,
211   PROP_FIXED_WIDTH,
212   PROP_MIN_WIDTH,
213   PROP_MAX_WIDTH,
214   PROP_TITLE,
215   PROP_EXPAND,
216   PROP_CLICKABLE,
217   PROP_WIDGET,
218   PROP_ALIGNMENT,
219   PROP_REORDERABLE,
220   PROP_SORT_INDICATOR,
221   PROP_SORT_ORDER,
222   PROP_SORT_COLUMN_ID,
223   PROP_CELL_AREA,
224   LAST_PROP
225 };
226 
227 enum
228 {
229   CLICKED,
230   LAST_SIGNAL
231 };
232 
233 static guint tree_column_signals[LAST_SIGNAL] = { 0 };
234 static GParamSpec *tree_column_props[LAST_PROP] = { NULL, };
235 
G_DEFINE_TYPE_WITH_CODE(GtkTreeViewColumn,gtk_tree_view_column,G_TYPE_INITIALLY_UNOWNED,G_ADD_PRIVATE (GtkTreeViewColumn)G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,gtk_tree_view_column_cell_layout_init)G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,gtk_tree_view_column_buildable_init))236 G_DEFINE_TYPE_WITH_CODE (GtkTreeViewColumn, gtk_tree_view_column, G_TYPE_INITIALLY_UNOWNED,
237                          G_ADD_PRIVATE (GtkTreeViewColumn)
238 			 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
239 						gtk_tree_view_column_cell_layout_init)
240 			 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
241 						gtk_tree_view_column_buildable_init))
242 
243 
244 static void
245 gtk_tree_view_column_class_init (GtkTreeViewColumnClass *class)
246 {
247   GObjectClass *object_class;
248 
249   object_class = (GObjectClass*) class;
250 
251   class->clicked = NULL;
252 
253   object_class->constructed = gtk_tree_view_column_constructed;
254   object_class->finalize = gtk_tree_view_column_finalize;
255   object_class->dispose = gtk_tree_view_column_dispose;
256   object_class->set_property = gtk_tree_view_column_set_property;
257   object_class->get_property = gtk_tree_view_column_get_property;
258 
259   /**
260    * GtkTreeViewColumn::clicked:
261    * @column: the `GtkTreeViewColumn` that emitted the signal
262    *
263    * Emitted when the column's header has been clicked.
264    */
265   tree_column_signals[CLICKED] =
266     g_signal_new (I_("clicked"),
267                   G_OBJECT_CLASS_TYPE (object_class),
268                   G_SIGNAL_RUN_LAST,
269                   G_STRUCT_OFFSET (GtkTreeViewColumnClass, clicked),
270                   NULL, NULL,
271                   NULL,
272                   G_TYPE_NONE, 0);
273 
274   tree_column_props[PROP_VISIBLE] =
275       g_param_spec_boolean ("visible",
276                             P_("Visible"),
277                             P_("Whether to display the column"),
278                             TRUE,
279                             GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
280 
281   tree_column_props[PROP_RESIZABLE] =
282       g_param_spec_boolean ("resizable",
283                             P_("Resizable"),
284                             P_("Column is user-resizable"),
285                             FALSE,
286                             GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
287 
288   tree_column_props[PROP_X_OFFSET] =
289       g_param_spec_int ("x-offset",
290                         P_("X position"),
291                         P_("Current X position of the column"),
292                         -G_MAXINT, G_MAXINT,
293                         0,
294                         GTK_PARAM_READABLE);
295 
296   tree_column_props[PROP_WIDTH] =
297       g_param_spec_int ("width",
298                         P_("Width"),
299                         P_("Current width of the column"),
300                         0, G_MAXINT,
301                         0,
302                         GTK_PARAM_READABLE);
303 
304   tree_column_props[PROP_SPACING] =
305       g_param_spec_int ("spacing",
306                         P_("Spacing"),
307                         P_("Space which is inserted between cells"),
308                         0, G_MAXINT,
309                         0,
310                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
311 
312   tree_column_props[PROP_SIZING] =
313       g_param_spec_enum ("sizing",
314                          P_("Sizing"),
315                          P_("Resize mode of the column"),
316                          GTK_TYPE_TREE_VIEW_COLUMN_SIZING,
317                          GTK_TREE_VIEW_COLUMN_GROW_ONLY,
318                          GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
319 
320   tree_column_props[PROP_FIXED_WIDTH] =
321       g_param_spec_int ("fixed-width",
322                          P_("Fixed Width"),
323                          P_("Current fixed width of the column"),
324                          -1, G_MAXINT,
325                          -1,
326                          GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
327 
328   tree_column_props[PROP_MIN_WIDTH] =
329       g_param_spec_int ("min-width",
330                         P_("Minimum Width"),
331                         P_("Minimum allowed width of the column"),
332                         -1, G_MAXINT,
333                         -1,
334                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
335 
336   tree_column_props[PROP_MAX_WIDTH] =
337       g_param_spec_int ("max-width",
338                         P_("Maximum Width"),
339                         P_("Maximum allowed width of the column"),
340                         -1, G_MAXINT,
341                         -1,
342                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
343 
344   tree_column_props[PROP_TITLE] =
345       g_param_spec_string ("title",
346                            P_("Title"),
347                            P_("Title to appear in column header"),
348                            "",
349                            GTK_PARAM_READWRITE);
350 
351   tree_column_props[PROP_EXPAND] =
352       g_param_spec_boolean ("expand",
353                             P_("Expand"),
354                             P_("Column gets share of extra width allocated to the widget"),
355                             FALSE,
356                             GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
357 
358   tree_column_props[PROP_CLICKABLE] =
359       g_param_spec_boolean ("clickable",
360                             P_("Clickable"),
361                             P_("Whether the header can be clicked"),
362                             FALSE,
363                             GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
364 
365   tree_column_props[PROP_WIDGET] =
366       g_param_spec_object ("widget",
367                            P_("Widget"),
368                            P_("Widget to put in column header button instead of column title"),
369                            GTK_TYPE_WIDGET,
370                            GTK_PARAM_READWRITE);
371 
372   tree_column_props[PROP_ALIGNMENT] =
373       g_param_spec_float ("alignment",
374                           P_("Alignment"),
375                           P_("X Alignment of the column header text or widget"),
376                           0.0, 1.0, 0.0,
377                           GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
378 
379   tree_column_props[PROP_REORDERABLE] =
380       g_param_spec_boolean ("reorderable",
381                             P_("Reorderable"),
382                             P_("Whether the column can be reordered around the headers"),
383                             FALSE,
384                             GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
385 
386   tree_column_props[PROP_SORT_INDICATOR] =
387       g_param_spec_boolean ("sort-indicator",
388                             P_("Sort indicator"),
389                             P_("Whether to show a sort indicator"),
390                             FALSE,
391                             GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
392 
393   tree_column_props[PROP_SORT_ORDER] =
394       g_param_spec_enum ("sort-order",
395                          P_("Sort order"),
396                          P_("Sort direction the sort indicator should indicate"),
397                          GTK_TYPE_SORT_TYPE,
398                          GTK_SORT_ASCENDING,
399                          GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
400 
401   /**
402    * GtkTreeViewColumn:sort-column-id:
403    *
404    * Logical sort column ID this column sorts on when selected for sorting. Setting the sort column ID makes the column header
405    * clickable. Set to -1 to make the column unsortable.
406    **/
407   tree_column_props[PROP_SORT_COLUMN_ID] =
408       g_param_spec_int ("sort-column-id",
409                         P_("Sort column ID"),
410                         P_("Logical sort column ID this column sorts on when selected for sorting"),
411                         -1, G_MAXINT,
412                         -1,
413                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
414 
415   /**
416    * GtkTreeViewColumn:cell-area:
417    *
418    * The `GtkCellArea` used to layout cell renderers for this column.
419    *
420    * If no area is specified when creating the tree view column with gtk_tree_view_column_new_with_area()
421    * a horizontally oriented `GtkCellAreaBox` will be used.
422    */
423   tree_column_props[PROP_CELL_AREA] =
424       g_param_spec_object ("cell-area",
425                            P_("Cell Area"),
426                            P_("The GtkCellArea used to layout cells"),
427                            GTK_TYPE_CELL_AREA,
428                            GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
429 
430   g_object_class_install_properties (object_class, LAST_PROP, tree_column_props);
431 }
432 
433 static void
gtk_tree_view_column_custom_tag_end(GtkBuildable * buildable,GtkBuilder * builder,GObject * child,const char * tagname,gpointer data)434 gtk_tree_view_column_custom_tag_end (GtkBuildable *buildable,
435 				     GtkBuilder   *builder,
436 				     GObject      *child,
437 				     const char   *tagname,
438 				     gpointer      data)
439 {
440   /* Just ignore the boolean return from here */
441   _gtk_cell_layout_buildable_custom_tag_end (buildable, builder, child, tagname, data);
442 }
443 
444 static void
gtk_tree_view_column_buildable_init(GtkBuildableIface * iface)445 gtk_tree_view_column_buildable_init (GtkBuildableIface *iface)
446 {
447   iface->add_child = _gtk_cell_layout_buildable_add_child;
448   iface->custom_tag_start = _gtk_cell_layout_buildable_custom_tag_start;
449   iface->custom_tag_end = gtk_tree_view_column_custom_tag_end;
450 }
451 
452 static void
gtk_tree_view_column_cell_layout_init(GtkCellLayoutIface * iface)453 gtk_tree_view_column_cell_layout_init (GtkCellLayoutIface *iface)
454 {
455   iface->get_area = gtk_tree_view_column_cell_layout_get_area;
456 }
457 
458 static void
gtk_tree_view_column_init(GtkTreeViewColumn * tree_column)459 gtk_tree_view_column_init (GtkTreeViewColumn *tree_column)
460 {
461   GtkTreeViewColumnPrivate *priv;
462 
463   tree_column->priv = gtk_tree_view_column_get_instance_private (tree_column);
464   priv = tree_column->priv;
465 
466   priv->button = NULL;
467   priv->xalign = 0.0;
468   priv->width = 0;
469   priv->padding = 0;
470   priv->min_width = -1;
471   priv->max_width = -1;
472   priv->column_type = GTK_TREE_VIEW_COLUMN_GROW_ONLY;
473   priv->visible = TRUE;
474   priv->resizable = FALSE;
475   priv->expand = FALSE;
476   priv->clickable = FALSE;
477   priv->dirty = TRUE;
478   priv->sort_order = GTK_SORT_ASCENDING;
479   priv->show_sort_indicator = FALSE;
480   priv->property_changed_signal = 0;
481   priv->sort_clicked_signal = 0;
482   priv->sort_column_changed_signal = 0;
483   priv->sort_column_id = -1;
484   priv->reorderable = FALSE;
485   priv->maybe_reordered = FALSE;
486   priv->fixed_width = -1;
487   priv->title = g_strdup ("");
488 
489   gtk_tree_view_column_create_button (tree_column);
490 }
491 
492 static void
gtk_tree_view_column_constructed(GObject * object)493 gtk_tree_view_column_constructed (GObject *object)
494 {
495   GtkTreeViewColumn *tree_column = GTK_TREE_VIEW_COLUMN (object);
496 
497   G_OBJECT_CLASS (gtk_tree_view_column_parent_class)->constructed (object);
498 
499   gtk_tree_view_column_ensure_cell_area (tree_column, NULL);
500 }
501 
502 static void
gtk_tree_view_column_dispose(GObject * object)503 gtk_tree_view_column_dispose (GObject *object)
504 {
505   GtkTreeViewColumn        *tree_column = (GtkTreeViewColumn *) object;
506   GtkTreeViewColumnPrivate *priv        = tree_column->priv;
507 
508   /* Remove this column from its treeview,
509    * in case this column is destroyed before its treeview.
510    */
511   if (priv->tree_view)
512     gtk_tree_view_remove_column (GTK_TREE_VIEW (priv->tree_view), tree_column);
513 
514   if (priv->cell_area_context)
515     {
516       g_signal_handler_disconnect (priv->cell_area_context,
517 				   priv->context_changed_signal);
518 
519       g_object_unref (priv->cell_area_context);
520 
521       priv->cell_area_context = NULL;
522       priv->context_changed_signal = 0;
523     }
524 
525   if (priv->cell_area)
526     {
527       g_signal_handler_disconnect (priv->cell_area,
528 				   priv->add_editable_signal);
529       g_signal_handler_disconnect (priv->cell_area,
530 				   priv->remove_editable_signal);
531 
532       g_object_unref (priv->cell_area);
533       priv->cell_area = NULL;
534       priv->add_editable_signal = 0;
535       priv->remove_editable_signal = 0;
536     }
537 
538   if (priv->child)
539     {
540       g_object_unref (priv->child);
541       priv->child = NULL;
542     }
543 
544   g_clear_object (&priv->button);
545 
546   G_OBJECT_CLASS (gtk_tree_view_column_parent_class)->dispose (object);
547 }
548 
549 static void
gtk_tree_view_column_finalize(GObject * object)550 gtk_tree_view_column_finalize (GObject *object)
551 {
552   GtkTreeViewColumn        *tree_column = (GtkTreeViewColumn *) object;
553   GtkTreeViewColumnPrivate *priv        = tree_column->priv;
554 
555   g_free (priv->title);
556 
557   G_OBJECT_CLASS (gtk_tree_view_column_parent_class)->finalize (object);
558 }
559 
560 static void
gtk_tree_view_column_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)561 gtk_tree_view_column_set_property (GObject         *object,
562                                    guint            prop_id,
563                                    const GValue    *value,
564                                    GParamSpec      *pspec)
565 {
566   GtkTreeViewColumn *tree_column;
567   GtkCellArea       *area;
568 
569   tree_column = GTK_TREE_VIEW_COLUMN (object);
570 
571   switch (prop_id)
572     {
573     case PROP_VISIBLE:
574       gtk_tree_view_column_set_visible (tree_column,
575                                         g_value_get_boolean (value));
576       break;
577 
578     case PROP_RESIZABLE:
579       gtk_tree_view_column_set_resizable (tree_column,
580 					  g_value_get_boolean (value));
581       break;
582 
583     case PROP_SIZING:
584       gtk_tree_view_column_set_sizing (tree_column,
585                                        g_value_get_enum (value));
586       break;
587 
588     case PROP_FIXED_WIDTH:
589       gtk_tree_view_column_set_fixed_width (tree_column,
590 					    g_value_get_int (value));
591       break;
592 
593     case PROP_MIN_WIDTH:
594       gtk_tree_view_column_set_min_width (tree_column,
595                                           g_value_get_int (value));
596       break;
597 
598     case PROP_MAX_WIDTH:
599       gtk_tree_view_column_set_max_width (tree_column,
600                                           g_value_get_int (value));
601       break;
602 
603     case PROP_SPACING:
604       gtk_tree_view_column_set_spacing (tree_column,
605 					g_value_get_int (value));
606       break;
607 
608     case PROP_TITLE:
609       gtk_tree_view_column_set_title (tree_column,
610                                       g_value_get_string (value));
611       break;
612 
613     case PROP_EXPAND:
614       gtk_tree_view_column_set_expand (tree_column,
615 				       g_value_get_boolean (value));
616       break;
617 
618     case PROP_CLICKABLE:
619       gtk_tree_view_column_set_clickable (tree_column,
620                                           g_value_get_boolean (value));
621       break;
622 
623     case PROP_WIDGET:
624       gtk_tree_view_column_set_widget (tree_column,
625                                        (GtkWidget*) g_value_get_object (value));
626       break;
627 
628     case PROP_ALIGNMENT:
629       gtk_tree_view_column_set_alignment (tree_column,
630                                           g_value_get_float (value));
631       break;
632 
633     case PROP_REORDERABLE:
634       gtk_tree_view_column_set_reorderable (tree_column,
635 					    g_value_get_boolean (value));
636       break;
637 
638     case PROP_SORT_INDICATOR:
639       gtk_tree_view_column_set_sort_indicator (tree_column,
640                                                g_value_get_boolean (value));
641       break;
642 
643     case PROP_SORT_ORDER:
644       gtk_tree_view_column_set_sort_order (tree_column,
645                                            g_value_get_enum (value));
646       break;
647 
648     case PROP_SORT_COLUMN_ID:
649       gtk_tree_view_column_set_sort_column_id (tree_column,
650                                                g_value_get_int (value));
651       break;
652 
653     case PROP_CELL_AREA:
654       /* Construct-only, can only be assigned once */
655       area = g_value_get_object (value);
656 
657       if (area)
658         {
659           if (tree_column->priv->cell_area != NULL)
660             {
661               g_warning ("cell-area has already been set, ignoring construct property");
662               g_object_ref_sink (area);
663               g_object_unref (area);
664             }
665           else
666             gtk_tree_view_column_ensure_cell_area (tree_column, area);
667         }
668       break;
669 
670     default:
671       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
672       break;
673     }
674 }
675 
676 static void
gtk_tree_view_column_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)677 gtk_tree_view_column_get_property (GObject         *object,
678                                    guint            prop_id,
679                                    GValue          *value,
680                                    GParamSpec      *pspec)
681 {
682   GtkTreeViewColumn *tree_column;
683 
684   tree_column = GTK_TREE_VIEW_COLUMN (object);
685 
686   switch (prop_id)
687     {
688     case PROP_VISIBLE:
689       g_value_set_boolean (value,
690                            gtk_tree_view_column_get_visible (tree_column));
691       break;
692 
693     case PROP_RESIZABLE:
694       g_value_set_boolean (value,
695                            gtk_tree_view_column_get_resizable (tree_column));
696       break;
697 
698     case PROP_X_OFFSET:
699       g_value_set_int (value,
700                        gtk_tree_view_column_get_x_offset (tree_column));
701       break;
702 
703     case PROP_WIDTH:
704       g_value_set_int (value,
705                        gtk_tree_view_column_get_width (tree_column));
706       break;
707 
708     case PROP_SPACING:
709       g_value_set_int (value,
710                        gtk_tree_view_column_get_spacing (tree_column));
711       break;
712 
713     case PROP_SIZING:
714       g_value_set_enum (value,
715                         gtk_tree_view_column_get_sizing (tree_column));
716       break;
717 
718     case PROP_FIXED_WIDTH:
719       g_value_set_int (value,
720                        gtk_tree_view_column_get_fixed_width (tree_column));
721       break;
722 
723     case PROP_MIN_WIDTH:
724       g_value_set_int (value,
725                        gtk_tree_view_column_get_min_width (tree_column));
726       break;
727 
728     case PROP_MAX_WIDTH:
729       g_value_set_int (value,
730                        gtk_tree_view_column_get_max_width (tree_column));
731       break;
732 
733     case PROP_TITLE:
734       g_value_set_string (value,
735                           gtk_tree_view_column_get_title (tree_column));
736       break;
737 
738     case PROP_EXPAND:
739       g_value_set_boolean (value,
740                           gtk_tree_view_column_get_expand (tree_column));
741       break;
742 
743     case PROP_CLICKABLE:
744       g_value_set_boolean (value,
745                            gtk_tree_view_column_get_clickable (tree_column));
746       break;
747 
748     case PROP_WIDGET:
749       g_value_set_object (value,
750                           (GObject*) gtk_tree_view_column_get_widget (tree_column));
751       break;
752 
753     case PROP_ALIGNMENT:
754       g_value_set_float (value,
755                          gtk_tree_view_column_get_alignment (tree_column));
756       break;
757 
758     case PROP_REORDERABLE:
759       g_value_set_boolean (value,
760 			   gtk_tree_view_column_get_reorderable (tree_column));
761       break;
762 
763     case PROP_SORT_INDICATOR:
764       g_value_set_boolean (value,
765                            gtk_tree_view_column_get_sort_indicator (tree_column));
766       break;
767 
768     case PROP_SORT_ORDER:
769       g_value_set_enum (value,
770                         gtk_tree_view_column_get_sort_order (tree_column));
771       break;
772 
773     case PROP_SORT_COLUMN_ID:
774       g_value_set_int (value,
775                        gtk_tree_view_column_get_sort_column_id (tree_column));
776       break;
777 
778     case PROP_CELL_AREA:
779       g_value_set_object (value, tree_column->priv->cell_area);
780       break;
781 
782     default:
783       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
784       break;
785     }
786 }
787 
788 /* Implementation of GtkCellLayout interface
789  */
790 
791 static void
gtk_tree_view_column_ensure_cell_area(GtkTreeViewColumn * column,GtkCellArea * cell_area)792 gtk_tree_view_column_ensure_cell_area (GtkTreeViewColumn *column,
793                                        GtkCellArea       *cell_area)
794 {
795   GtkTreeViewColumnPrivate *priv = column->priv;
796 
797   if (priv->cell_area)
798     return;
799 
800   if (cell_area)
801     priv->cell_area = cell_area;
802   else
803     priv->cell_area = gtk_cell_area_box_new ();
804 
805   g_object_ref_sink (priv->cell_area);
806 
807   priv->add_editable_signal =
808     g_signal_connect (priv->cell_area, "add-editable",
809                       G_CALLBACK (gtk_tree_view_column_add_editable_callback),
810                       column);
811   priv->remove_editable_signal =
812     g_signal_connect (priv->cell_area, "remove-editable",
813                       G_CALLBACK (gtk_tree_view_column_remove_editable_callback),
814                       column);
815 
816   priv->cell_area_context = gtk_cell_area_create_context (priv->cell_area);
817 
818   priv->context_changed_signal =
819     g_signal_connect (priv->cell_area_context, "notify",
820                       G_CALLBACK (gtk_tree_view_column_context_changed),
821                       column);
822 }
823 
824 static GtkCellArea *
gtk_tree_view_column_cell_layout_get_area(GtkCellLayout * cell_layout)825 gtk_tree_view_column_cell_layout_get_area (GtkCellLayout   *cell_layout)
826 {
827   GtkTreeViewColumn        *column = GTK_TREE_VIEW_COLUMN (cell_layout);
828   GtkTreeViewColumnPrivate *priv   = column->priv;
829 
830   if (G_UNLIKELY (!priv->cell_area))
831     gtk_tree_view_column_ensure_cell_area (column, NULL);
832 
833   return priv->cell_area;
834 }
835 
836 static void
focus_in(GtkEventControllerKey * controller,GtkTreeViewColumn * column)837 focus_in (GtkEventControllerKey *controller,
838           GtkTreeViewColumn     *column)
839 {
840   _gtk_tree_view_set_focus_column (GTK_TREE_VIEW (column->priv->tree_view), column);
841 }
842 
843 /* Button handling code
844  */
845 static void
gtk_tree_view_column_create_button(GtkTreeViewColumn * tree_column)846 gtk_tree_view_column_create_button (GtkTreeViewColumn *tree_column)
847 {
848   GtkTreeViewColumnPrivate *priv = tree_column->priv;
849   GtkEventController *controller;
850   GtkWidget *child;
851   GtkWidget *hbox;
852 
853   g_return_if_fail (priv->button == NULL);
854 
855   priv->button = gtk_button_new ();
856   g_object_ref_sink (priv->button);
857   gtk_widget_set_focus_on_click (priv->button, FALSE);
858   gtk_widget_set_overflow (priv->button, GTK_OVERFLOW_HIDDEN);
859 
860   g_signal_connect (priv->button, "clicked",
861 		    G_CALLBACK (gtk_tree_view_column_button_clicked),
862 		    tree_column);
863 
864   controller = GTK_EVENT_CONTROLLER (gtk_gesture_drag_new ());
865   g_signal_connect (controller, "drag-begin",
866                     G_CALLBACK (column_button_drag_begin), tree_column);
867   g_signal_connect (controller, "drag-update",
868                     G_CALLBACK (column_button_drag_update), tree_column);
869   gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_CAPTURE);
870   gtk_widget_add_controller (priv->button, controller);
871 
872   controller = gtk_event_controller_focus_new ();
873   g_signal_connect (controller, "enter", G_CALLBACK (focus_in), tree_column);
874   gtk_widget_add_controller (priv->button, controller);
875 
876   priv->frame = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
877   gtk_widget_set_hexpand (priv->frame, TRUE);
878   gtk_widget_set_halign (priv->frame, GTK_ALIGN_START);
879 
880   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
881   priv->arrow = gtk_builtin_icon_new ("sort-indicator");
882 
883   if (priv->child)
884     child = priv->child;
885   else
886     child = gtk_label_new (priv->title);
887 
888   g_signal_connect (child, "mnemonic-activate",
889 		    G_CALLBACK (gtk_tree_view_column_mnemonic_activate),
890 		    tree_column);
891 
892   if (priv->xalign <= 0.5)
893     {
894       gtk_box_append (GTK_BOX (hbox), priv->frame);
895       gtk_box_append (GTK_BOX (hbox), priv->arrow);
896     }
897   else
898     {
899       gtk_box_append (GTK_BOX (hbox), priv->arrow);
900       gtk_box_append (GTK_BOX (hbox), priv->frame);
901     }
902 
903   gtk_box_append (GTK_BOX (priv->frame), child);
904   gtk_button_set_child (GTK_BUTTON (priv->button), hbox);
905 }
906 
907 static void
gtk_tree_view_column_update_button(GtkTreeViewColumn * tree_column)908 gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column)
909 {
910   GtkTreeViewColumnPrivate *priv = tree_column->priv;
911   int sort_column_id = -1;
912   GtkWidget *hbox;
913   GtkWidget *frame;
914   GtkWidget *arrow;
915   GtkWidget *current_child;
916   GtkTreeModel *model;
917 
918   if (priv->tree_view)
919     model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree_view));
920   else
921     model = NULL;
922 
923   hbox = gtk_button_get_child (GTK_BUTTON (priv->button));
924   frame = priv->frame;
925   arrow = priv->arrow;
926   current_child = gtk_widget_get_first_child (frame);
927 
928   /* Set up the actual button */
929   if (priv->child)
930     {
931       if (current_child != priv->child)
932         {
933           gtk_box_remove (GTK_BOX (frame), current_child);
934           gtk_box_append (GTK_BOX (frame), priv->child);
935         }
936     }
937   else
938     {
939       if (current_child == NULL)
940         {
941           current_child = gtk_label_new (NULL);
942           gtk_widget_show (current_child);
943           gtk_box_append (GTK_BOX (frame), current_child);
944         }
945 
946       g_return_if_fail (GTK_IS_LABEL (current_child));
947 
948       if (priv->title)
949         gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
950                                           priv->title);
951       else
952         gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
953                                           "");
954     }
955 
956   if (GTK_IS_TREE_SORTABLE (model))
957     gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
958                                           &sort_column_id,
959                                           NULL);
960 
961   if (priv->show_sort_indicator)
962     {
963       gboolean alternative;
964 
965       if (priv->tree_view)
966         g_object_get (gtk_widget_get_settings (priv->tree_view),
967                       "gtk-alternative-sort-arrows", &alternative,
968                       NULL);
969       else
970         alternative = FALSE;
971 
972       if ((!alternative && priv->sort_order == GTK_SORT_ASCENDING) ||
973           (alternative && priv->sort_order == GTK_SORT_DESCENDING))
974         {
975           gtk_widget_remove_css_class (arrow, "descending");
976           gtk_widget_add_css_class (arrow, "ascending");
977         }
978       else
979         {
980           gtk_widget_remove_css_class (arrow, "ascending");
981           gtk_widget_add_css_class (arrow, "descending");
982         }
983     }
984 
985   /* Put arrow on the right if the text is left-or-center justified, and on the
986    * left otherwise; do this by packing boxes, so flipping text direction will
987    * reverse things
988    */
989   if (priv->xalign <= 0.5)
990     gtk_box_reorder_child_after (GTK_BOX (hbox), arrow, gtk_widget_get_last_child (hbox));
991   else
992     gtk_box_reorder_child_after (GTK_BOX (hbox), arrow, NULL);
993 
994   if (priv->show_sort_indicator
995       || (GTK_IS_TREE_SORTABLE (model) && priv->sort_column_id >= 0))
996     gtk_widget_show (arrow);
997   else
998     gtk_widget_hide (arrow);
999 
1000   if (priv->show_sort_indicator)
1001     gtk_widget_set_opacity (arrow, 1.0);
1002   else
1003     gtk_widget_set_opacity (arrow, 0.0);
1004 
1005   /* It's always safe to hide the button.  It isn't always safe to show it, as
1006    * if you show it before it's realized, it'll get the wrong window. */
1007   if (priv->tree_view != NULL &&
1008       gtk_widget_get_realized (priv->tree_view))
1009     {
1010       if (priv->visible &&
1011           gtk_tree_view_get_headers_visible (GTK_TREE_VIEW (priv->tree_view)))
1012 	{
1013           gtk_widget_show (priv->button);
1014 	}
1015       else
1016 	{
1017 	  gtk_widget_hide (priv->button);
1018 	}
1019     }
1020 
1021   if (priv->reorderable || priv->clickable)
1022     {
1023       gtk_widget_set_focusable (priv->button, TRUE);
1024     }
1025   else
1026     {
1027       gtk_widget_set_focusable (priv->button, FALSE);
1028       if (gtk_widget_has_focus (priv->button))
1029 	{
1030           GtkRoot *root = gtk_widget_get_root (priv->tree_view);
1031 	  gtk_root_set_focus (root, NULL);
1032 	}
1033     }
1034   /* Queue a resize on the assumption that we always want to catch all changes
1035    * and columns don't change all that often.
1036    */
1037   if (priv->tree_view && gtk_widget_get_realized (priv->tree_view))
1038      gtk_widget_queue_resize (priv->tree_view);
1039 }
1040 
1041 /* Button signal handlers
1042  */
1043 
1044 static void
column_button_drag_begin(GtkGestureDrag * gesture,double x,double y,GtkTreeViewColumn * column)1045 column_button_drag_begin (GtkGestureDrag    *gesture,
1046                           double             x,
1047                           double             y,
1048                           GtkTreeViewColumn *column)
1049 {
1050   GtkTreeViewColumnPrivate *priv = column->priv;
1051 
1052   if (!priv->reorderable)
1053     {
1054       gtk_gesture_set_state (GTK_GESTURE (gesture),
1055                              GTK_EVENT_SEQUENCE_DENIED);
1056       return;
1057     }
1058 
1059   priv->drag_x = x;
1060   priv->drag_y = y;
1061   gtk_widget_grab_focus (priv->button);
1062 }
1063 
1064 static void
column_button_drag_update(GtkGestureDrag * gesture,double offset_x,double offset_y,GtkTreeViewColumn * column)1065 column_button_drag_update (GtkGestureDrag    *gesture,
1066                            double             offset_x,
1067                            double             offset_y,
1068                            GtkTreeViewColumn *column)
1069 {
1070   GtkTreeViewColumnPrivate *priv = column->priv;
1071 
1072   if (gtk_drag_check_threshold_double (priv->button, 0, 0, offset_x, offset_y))
1073     {
1074       gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
1075       _gtk_tree_view_column_start_drag (GTK_TREE_VIEW (priv->tree_view), column,
1076                                         gtk_gesture_get_device (GTK_GESTURE (gesture)));
1077     }
1078 }
1079 
1080 static void
gtk_tree_view_column_button_clicked(GtkWidget * widget,gpointer data)1081 gtk_tree_view_column_button_clicked (GtkWidget *widget, gpointer data)
1082 {
1083   g_signal_emit_by_name (data, "clicked");
1084 }
1085 
1086 static gboolean
gtk_tree_view_column_mnemonic_activate(GtkWidget * widget,gboolean group_cycling,gpointer data)1087 gtk_tree_view_column_mnemonic_activate (GtkWidget *widget,
1088 					gboolean   group_cycling,
1089 					gpointer   data)
1090 {
1091   GtkTreeViewColumn        *column = (GtkTreeViewColumn *)data;
1092   GtkTreeViewColumnPrivate *priv   = column->priv;
1093 
1094   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), FALSE);
1095 
1096   _gtk_tree_view_set_focus_column (GTK_TREE_VIEW (priv->tree_view), column);
1097 
1098   if (priv->clickable)
1099      g_signal_emit_by_name (priv->button, "clicked");
1100   else if (gtk_widget_get_focusable (priv->button))
1101     gtk_widget_grab_focus (priv->button);
1102   else
1103     gtk_widget_grab_focus (priv->tree_view);
1104 
1105   return TRUE;
1106 }
1107 
1108 static void
gtk_tree_view_model_sort_column_changed(GtkTreeSortable * sortable,GtkTreeViewColumn * column)1109 gtk_tree_view_model_sort_column_changed (GtkTreeSortable   *sortable,
1110 					 GtkTreeViewColumn *column)
1111 {
1112   GtkTreeViewColumnPrivate *priv = column->priv;
1113   int sort_column_id;
1114   GtkSortType order;
1115 
1116   if (gtk_tree_sortable_get_sort_column_id (sortable,
1117 					    &sort_column_id,
1118 					    &order))
1119     {
1120       if (sort_column_id == priv->sort_column_id)
1121 	{
1122 	  gtk_tree_view_column_set_sort_indicator (column, TRUE);
1123 	  gtk_tree_view_column_set_sort_order (column, order);
1124 	}
1125       else
1126 	{
1127 	  gtk_tree_view_column_set_sort_indicator (column, FALSE);
1128 	}
1129     }
1130   else
1131     {
1132       gtk_tree_view_column_set_sort_indicator (column, FALSE);
1133     }
1134 }
1135 
1136 static void
gtk_tree_view_column_sort(GtkTreeViewColumn * tree_column,gpointer data)1137 gtk_tree_view_column_sort (GtkTreeViewColumn *tree_column,
1138 			   gpointer           data)
1139 {
1140   GtkTreeViewColumnPrivate *priv = tree_column->priv;
1141   GtkTreeModel *model;
1142   GtkTreeSortable *sortable;
1143   int sort_column_id;
1144   GtkSortType order;
1145   gboolean has_sort_column;
1146   gboolean has_default_sort_func;
1147 
1148   g_return_if_fail (priv->tree_view != NULL);
1149 
1150   model    = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree_view));
1151   sortable = GTK_TREE_SORTABLE (model);
1152 
1153   has_sort_column =
1154     gtk_tree_sortable_get_sort_column_id (sortable,
1155 					  &sort_column_id,
1156 					  &order);
1157   has_default_sort_func =
1158     gtk_tree_sortable_has_default_sort_func (sortable);
1159 
1160   if (has_sort_column &&
1161       sort_column_id == priv->sort_column_id)
1162     {
1163       if (order == GTK_SORT_ASCENDING)
1164 	gtk_tree_sortable_set_sort_column_id (sortable,
1165 					      priv->sort_column_id,
1166 					      GTK_SORT_DESCENDING);
1167       else if (order == GTK_SORT_DESCENDING && has_default_sort_func)
1168 	gtk_tree_sortable_set_sort_column_id (sortable,
1169 					      GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
1170 					      GTK_SORT_ASCENDING);
1171       else
1172 	gtk_tree_sortable_set_sort_column_id (sortable,
1173 					      priv->sort_column_id,
1174 					      GTK_SORT_ASCENDING);
1175     }
1176   else
1177     {
1178       gtk_tree_sortable_set_sort_column_id (sortable,
1179 					    priv->sort_column_id,
1180 					    GTK_SORT_ASCENDING);
1181     }
1182 }
1183 
1184 static void
gtk_tree_view_column_setup_sort_column_id_callback(GtkTreeViewColumn * tree_column)1185 gtk_tree_view_column_setup_sort_column_id_callback (GtkTreeViewColumn *tree_column)
1186 {
1187   GtkTreeViewColumnPrivate *priv = tree_column->priv;
1188   GtkTreeModel *model;
1189 
1190   if (priv->tree_view == NULL)
1191     return;
1192 
1193   model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree_view));
1194 
1195   if (model == NULL)
1196     return;
1197 
1198   if (GTK_IS_TREE_SORTABLE (model) &&
1199       priv->sort_column_id != -1)
1200     {
1201       int real_sort_column_id;
1202       GtkSortType real_order;
1203 
1204       if (priv->sort_column_changed_signal == 0)
1205         priv->sort_column_changed_signal =
1206 	  g_signal_connect (model, "sort-column-changed",
1207 			    G_CALLBACK (gtk_tree_view_model_sort_column_changed),
1208 			    tree_column);
1209 
1210       if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
1211 						&real_sort_column_id,
1212 						&real_order) &&
1213 	  (real_sort_column_id == priv->sort_column_id))
1214 	{
1215 	  gtk_tree_view_column_set_sort_indicator (tree_column, TRUE);
1216 	  gtk_tree_view_column_set_sort_order (tree_column, real_order);
1217  	}
1218       else
1219 	{
1220 	  gtk_tree_view_column_set_sort_indicator (tree_column, FALSE);
1221 	}
1222    }
1223 }
1224 
1225 static void
gtk_tree_view_column_context_changed(GtkCellAreaContext * context,GParamSpec * pspec,GtkTreeViewColumn * tree_column)1226 gtk_tree_view_column_context_changed  (GtkCellAreaContext      *context,
1227 				       GParamSpec              *pspec,
1228 				       GtkTreeViewColumn       *tree_column)
1229 {
1230   /* Here we want the column re-requested if the underlying context was
1231    * actually reset for any reason, this can happen if the underlying
1232    * area/cell configuration changes (i.e. cell packing properties
1233    * or cell spacing and the like)
1234    *
1235    * Note that we block this handler while requesting for sizes
1236    * so there is no need to check for the new context size being -1,
1237    * we also block the handler when explicitly resetting the context
1238    * so as to avoid some infinite stack recursion.
1239    */
1240   if (!strcmp (pspec->name, "minimum-width") ||
1241       !strcmp (pspec->name, "natural-width") ||
1242       !strcmp (pspec->name, "minimum-height") ||
1243       !strcmp (pspec->name, "natural-height"))
1244     _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
1245 }
1246 
1247 static void
gtk_tree_view_column_add_editable_callback(GtkCellArea * area,GtkCellRenderer * renderer,GtkCellEditable * edit_widget,GdkRectangle * cell_area,const char * path_string,gpointer user_data)1248 gtk_tree_view_column_add_editable_callback (GtkCellArea       *area,
1249                                             GtkCellRenderer   *renderer,
1250                                             GtkCellEditable   *edit_widget,
1251                                             GdkRectangle      *cell_area,
1252                                             const char        *path_string,
1253                                             gpointer           user_data)
1254 {
1255   GtkTreeViewColumn        *column = user_data;
1256   GtkTreeViewColumnPrivate *priv   = column->priv;
1257   GtkTreePath              *path;
1258 
1259   if (priv->tree_view)
1260     {
1261       path = gtk_tree_path_new_from_string (path_string);
1262 
1263       _gtk_tree_view_add_editable (GTK_TREE_VIEW (priv->tree_view),
1264 				   column,
1265 				   path,
1266 				   edit_widget,
1267 				   cell_area);
1268 
1269       gtk_tree_path_free (path);
1270     }
1271 }
1272 
1273 static void
gtk_tree_view_column_remove_editable_callback(GtkCellArea * area,GtkCellRenderer * renderer,GtkCellEditable * edit_widget,gpointer user_data)1274 gtk_tree_view_column_remove_editable_callback (GtkCellArea     *area,
1275                                                GtkCellRenderer *renderer,
1276                                                GtkCellEditable *edit_widget,
1277                                                gpointer         user_data)
1278 {
1279   GtkTreeViewColumn        *column = user_data;
1280   GtkTreeViewColumnPrivate *priv   = column->priv;
1281 
1282   if (priv->tree_view)
1283     _gtk_tree_view_remove_editable (GTK_TREE_VIEW (priv->tree_view),
1284 				    column,
1285 				    edit_widget);
1286 }
1287 
1288 /* Exported Private Functions.
1289  * These should only be called by gtktreeview.c or gtktreeviewcolumn.c
1290  */
1291 void
_gtk_tree_view_column_realize_button(GtkTreeViewColumn * column)1292 _gtk_tree_view_column_realize_button (GtkTreeViewColumn *column)
1293 {
1294   g_return_if_fail (GTK_IS_TREE_VIEW (column->priv->tree_view));
1295   g_return_if_fail (gtk_widget_get_realized (column->priv->tree_view));
1296   g_return_if_fail (column->priv->button != NULL);
1297 
1298   gtk_tree_view_column_update_button (column);
1299 }
1300 
1301 void
_gtk_tree_view_column_unset_model(GtkTreeViewColumn * column,GtkTreeModel * old_model)1302 _gtk_tree_view_column_unset_model (GtkTreeViewColumn *column,
1303 				   GtkTreeModel      *old_model)
1304 {
1305   GtkTreeViewColumnPrivate *priv = column->priv;
1306 
1307   if (priv->sort_column_changed_signal)
1308     {
1309       g_signal_handler_disconnect (old_model,
1310 				   priv->sort_column_changed_signal);
1311       priv->sort_column_changed_signal = 0;
1312     }
1313   gtk_tree_view_column_set_sort_indicator (column, FALSE);
1314 }
1315 
1316 void
_gtk_tree_view_column_set_tree_view(GtkTreeViewColumn * column,GtkTreeView * tree_view)1317 _gtk_tree_view_column_set_tree_view (GtkTreeViewColumn *column,
1318 				     GtkTreeView       *tree_view)
1319 {
1320   GtkTreeViewColumnPrivate *priv = column->priv;
1321 
1322   g_assert (priv->tree_view == NULL);
1323 
1324   priv->tree_view = GTK_WIDGET (tree_view);
1325 
1326   /* avoid a warning with our messed up CSS nodes */
1327   gtk_widget_insert_after (priv->button, GTK_WIDGET (tree_view), NULL);
1328 
1329   priv->property_changed_signal =
1330     g_signal_connect_swapped (tree_view,
1331 			      "notify::model",
1332 			      G_CALLBACK (gtk_tree_view_column_setup_sort_column_id_callback),
1333 			      column);
1334 
1335   gtk_tree_view_column_setup_sort_column_id_callback (column);
1336 }
1337 
1338 void
_gtk_tree_view_column_unset_tree_view(GtkTreeViewColumn * column)1339 _gtk_tree_view_column_unset_tree_view (GtkTreeViewColumn *column)
1340 {
1341   GtkTreeViewColumnPrivate *priv = column->priv;
1342 
1343   if (priv->tree_view == NULL)
1344     return;
1345 
1346   gtk_widget_unparent (priv->button);
1347 
1348   if (priv->property_changed_signal)
1349     {
1350       g_signal_handler_disconnect (priv->tree_view, priv->property_changed_signal);
1351       priv->property_changed_signal = 0;
1352     }
1353 
1354   if (priv->sort_column_changed_signal)
1355     {
1356       g_signal_handler_disconnect (gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree_view)),
1357                                    priv->sort_column_changed_signal);
1358       priv->sort_column_changed_signal = 0;
1359     }
1360 
1361   priv->tree_view = NULL;
1362 }
1363 
1364 gboolean
_gtk_tree_view_column_has_editable_cell(GtkTreeViewColumn * column)1365 _gtk_tree_view_column_has_editable_cell (GtkTreeViewColumn *column)
1366 {
1367   GtkTreeViewColumnPrivate *priv = column->priv;
1368   gboolean ret = FALSE;
1369   GList *list, *cells;
1370 
1371   cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (priv->cell_area));
1372 
1373   for (list = cells; list; list = list->next)
1374     {
1375       GtkCellRenderer *cell = list->data;
1376       GtkCellRendererMode mode;
1377 
1378       g_object_get (cell, "mode", &mode, NULL);
1379 
1380       if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
1381         {
1382           ret = TRUE;
1383           break;
1384         }
1385     }
1386 
1387   g_list_free (cells);
1388 
1389   return ret;
1390 }
1391 
1392 /* gets cell being edited */
1393 GtkCellRenderer *
_gtk_tree_view_column_get_edited_cell(GtkTreeViewColumn * column)1394 _gtk_tree_view_column_get_edited_cell (GtkTreeViewColumn *column)
1395 {
1396   GtkTreeViewColumnPrivate *priv = column->priv;
1397 
1398   return gtk_cell_area_get_edited_cell (priv->cell_area);
1399 }
1400 
1401 GtkCellRenderer *
_gtk_tree_view_column_get_cell_at_pos(GtkTreeViewColumn * column,GdkRectangle * cell_area,GdkRectangle * background_area,int x,int y)1402 _gtk_tree_view_column_get_cell_at_pos (GtkTreeViewColumn *column,
1403                                        GdkRectangle      *cell_area,
1404                                        GdkRectangle      *background_area,
1405                                        int                x,
1406                                        int                y)
1407 {
1408   GtkCellRenderer *match = NULL;
1409   GtkTreeViewColumnPrivate *priv = column->priv;
1410 
1411   /* If (x, y) is outside of the background area, immediately return */
1412   if (x < background_area->x ||
1413       x > background_area->x + background_area->width ||
1414       y < background_area->y ||
1415       y > background_area->y + background_area->height)
1416     return NULL;
1417 
1418   /* If (x, y) is inside the background area, clamp it to the cell_area
1419    * so that a cell is still returned.  The main reason for doing this
1420    * (on the x axis) is for handling clicks in the indentation area
1421    * (either at the left or right depending on RTL setting).  Another
1422    * reason is for handling clicks on the area where the focus rectangle
1423    * is drawn (this is outside of cell area), this manifests itself
1424    * mainly when a large setting is used for focus-line-width.
1425    */
1426   if (x < cell_area->x)
1427     x = cell_area->x;
1428   else if (x > cell_area->x + cell_area->width)
1429     x = cell_area->x + cell_area->width;
1430 
1431   if (y < cell_area->y)
1432     y = cell_area->y;
1433   else if (y > cell_area->y + cell_area->height)
1434     y = cell_area->y + cell_area->height;
1435 
1436   match = gtk_cell_area_get_cell_at_position (priv->cell_area,
1437                                               priv->cell_area_context,
1438                                               priv->tree_view,
1439                                               cell_area,
1440                                               x, y,
1441                                               NULL);
1442 
1443   return match;
1444 }
1445 
1446 gboolean
_gtk_tree_view_column_is_blank_at_pos(GtkTreeViewColumn * column,GdkRectangle * cell_area,GdkRectangle * background_area,int x,int y)1447 _gtk_tree_view_column_is_blank_at_pos (GtkTreeViewColumn *column,
1448                                        GdkRectangle      *cell_area,
1449                                        GdkRectangle      *background_area,
1450                                        int                x,
1451                                        int                y)
1452 {
1453   GtkCellRenderer *match;
1454   GdkRectangle cell_alloc, aligned_area, inner_area;
1455   GtkTreeViewColumnPrivate *priv = column->priv;
1456 
1457   match = _gtk_tree_view_column_get_cell_at_pos (column,
1458                                                  cell_area,
1459                                                  background_area,
1460                                                  x, y);
1461   if (!match)
1462     return FALSE;
1463 
1464   gtk_cell_area_get_cell_allocation (priv->cell_area,
1465                                      priv->cell_area_context,
1466                                      priv->tree_view,
1467                                      match,
1468                                      cell_area,
1469                                      &cell_alloc);
1470 
1471   gtk_cell_area_inner_cell_area (priv->cell_area, priv->tree_view,
1472                                  &cell_alloc, &inner_area);
1473   gtk_cell_renderer_get_aligned_area (match, priv->tree_view, 0,
1474                                       &inner_area, &aligned_area);
1475 
1476   if (x < aligned_area.x ||
1477       x > aligned_area.x + aligned_area.width ||
1478       y < aligned_area.y ||
1479       y > aligned_area.y + aligned_area.height)
1480     return TRUE;
1481 
1482   return FALSE;
1483 }
1484 
1485 /* Public Functions */
1486 
1487 
1488 /**
1489  * gtk_tree_view_column_new:
1490  *
1491  * Creates a new `GtkTreeViewColumn`.
1492  *
1493  * Returns: A newly created `GtkTreeViewColumn`.
1494  **/
1495 GtkTreeViewColumn *
gtk_tree_view_column_new(void)1496 gtk_tree_view_column_new (void)
1497 {
1498   GtkTreeViewColumn *tree_column;
1499 
1500   tree_column = g_object_new (GTK_TYPE_TREE_VIEW_COLUMN, NULL);
1501 
1502   return tree_column;
1503 }
1504 
1505 /**
1506  * gtk_tree_view_column_new_with_area:
1507  * @area: the `GtkCellArea` that the newly created column should use to layout cells.
1508  *
1509  * Creates a new `GtkTreeViewColumn` using @area to render its cells.
1510  *
1511  * Returns: A newly created `GtkTreeViewColumn`.
1512  */
1513 GtkTreeViewColumn *
gtk_tree_view_column_new_with_area(GtkCellArea * area)1514 gtk_tree_view_column_new_with_area (GtkCellArea *area)
1515 {
1516   GtkTreeViewColumn *tree_column;
1517 
1518   tree_column = g_object_new (GTK_TYPE_TREE_VIEW_COLUMN, "cell-area", area, NULL);
1519 
1520   return tree_column;
1521 }
1522 
1523 
1524 /**
1525  * gtk_tree_view_column_new_with_attributes:
1526  * @title: The title to set the header to
1527  * @cell: The `GtkCellRenderer`
1528  * @...: A %NULL-terminated list of attributes
1529  *
1530  * Creates a new `GtkTreeViewColumn` with a number of default values.
1531  * This is equivalent to calling gtk_tree_view_column_set_title(),
1532  * gtk_tree_view_column_pack_start(), and
1533  * gtk_tree_view_column_set_attributes() on the newly created `GtkTreeViewColumn`.
1534  *
1535  * Here’s a simple example:
1536  * |[<!-- language="C" -->
1537  *  enum { TEXT_COLUMN, COLOR_COLUMN, N_COLUMNS };
1538  *  // ...
1539  *  {
1540  *    GtkTreeViewColumn *column;
1541  *    GtkCellRenderer   *renderer = gtk_cell_renderer_text_new ();
1542  *
1543  *    column = gtk_tree_view_column_new_with_attributes ("Title",
1544  *                                                       renderer,
1545  *                                                       "text", TEXT_COLUMN,
1546  *                                                       "foreground", COLOR_COLUMN,
1547  *                                                       NULL);
1548  *  }
1549  * ]|
1550  *
1551  * Returns: A newly created `GtkTreeViewColumn`.
1552  **/
1553 GtkTreeViewColumn *
gtk_tree_view_column_new_with_attributes(const char * title,GtkCellRenderer * cell,...)1554 gtk_tree_view_column_new_with_attributes (const char      *title,
1555 					  GtkCellRenderer *cell,
1556 					  ...)
1557 {
1558   GtkTreeViewColumn *retval;
1559   va_list args;
1560 
1561   retval = gtk_tree_view_column_new ();
1562 
1563   gtk_tree_view_column_set_title (retval, title);
1564   gtk_tree_view_column_pack_start (retval, cell, TRUE);
1565 
1566   va_start (args, cell);
1567   gtk_tree_view_column_set_attributesv (retval, cell, args);
1568   va_end (args);
1569 
1570   return retval;
1571 }
1572 
1573 /**
1574  * gtk_tree_view_column_pack_start:
1575  * @tree_column: A `GtkTreeViewColumn`.
1576  * @cell: The `GtkCellRenderer`
1577  * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
1578  *
1579  * Packs the @cell into the beginning of the column. If @expand is %FALSE, then
1580  * the @cell is allocated no more space than it needs. Any unused space is divided
1581  * evenly between cells for which @expand is %TRUE.
1582  **/
1583 void
gtk_tree_view_column_pack_start(GtkTreeViewColumn * tree_column,GtkCellRenderer * cell,gboolean expand)1584 gtk_tree_view_column_pack_start (GtkTreeViewColumn *tree_column,
1585 				 GtkCellRenderer   *cell,
1586 				 gboolean           expand)
1587 {
1588   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (tree_column), cell, expand);
1589 }
1590 
1591 /**
1592  * gtk_tree_view_column_pack_end:
1593  * @tree_column: A `GtkTreeViewColumn`.
1594  * @cell: The `GtkCellRenderer`
1595  * @expand: %TRUE if @cell is to be given extra space allocated to @tree_column.
1596  *
1597  * Adds the @cell to end of the column. If @expand is %FALSE, then the @cell
1598  * is allocated no more space than it needs. Any unused space is divided
1599  * evenly between cells for which @expand is %TRUE.
1600  **/
1601 void
gtk_tree_view_column_pack_end(GtkTreeViewColumn * tree_column,GtkCellRenderer * cell,gboolean expand)1602 gtk_tree_view_column_pack_end (GtkTreeViewColumn  *tree_column,
1603 			       GtkCellRenderer    *cell,
1604 			       gboolean            expand)
1605 {
1606   gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (tree_column), cell, expand);
1607 }
1608 
1609 /**
1610  * gtk_tree_view_column_clear:
1611  * @tree_column: A `GtkTreeViewColumn`
1612  *
1613  * Unsets all the mappings on all renderers on the @tree_column.
1614  **/
1615 void
gtk_tree_view_column_clear(GtkTreeViewColumn * tree_column)1616 gtk_tree_view_column_clear (GtkTreeViewColumn *tree_column)
1617 {
1618   gtk_cell_layout_clear (GTK_CELL_LAYOUT (tree_column));
1619 }
1620 
1621 /**
1622  * gtk_tree_view_column_add_attribute:
1623  * @tree_column: A `GtkTreeViewColumn`
1624  * @cell_renderer: the `GtkCellRenderer` to set attributes on
1625  * @attribute: An attribute on the renderer
1626  * @column: The column position on the model to get the attribute from.
1627  *
1628  * Adds an attribute mapping to the list in @tree_column.
1629  *
1630  * The @column is the
1631  * column of the model to get a value from, and the @attribute is the
1632  * parameter on @cell_renderer to be set from the value. So for example
1633  * if column 2 of the model contains strings, you could have the
1634  * “text” attribute of a `GtkCellRendererText` get its values from
1635  * column 2.
1636  **/
1637 void
gtk_tree_view_column_add_attribute(GtkTreeViewColumn * tree_column,GtkCellRenderer * cell_renderer,const char * attribute,int column)1638 gtk_tree_view_column_add_attribute (GtkTreeViewColumn *tree_column,
1639 				    GtkCellRenderer   *cell_renderer,
1640 				    const char        *attribute,
1641 				    int                column)
1642 {
1643   gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (tree_column),
1644                                  cell_renderer, attribute, column);
1645 }
1646 
1647 static void
gtk_tree_view_column_set_attributesv(GtkTreeViewColumn * tree_column,GtkCellRenderer * cell_renderer,va_list args)1648 gtk_tree_view_column_set_attributesv (GtkTreeViewColumn *tree_column,
1649 				      GtkCellRenderer   *cell_renderer,
1650 				      va_list            args)
1651 {
1652   GtkTreeViewColumnPrivate *priv = tree_column->priv;
1653   char *attribute;
1654   int column;
1655 
1656   attribute = va_arg (args, char *);
1657 
1658   gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (priv->cell_area),
1659                                     cell_renderer);
1660 
1661   while (attribute != NULL)
1662     {
1663       column = va_arg (args, int);
1664       gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (priv->cell_area),
1665                                      cell_renderer, attribute, column);
1666       attribute = va_arg (args, char *);
1667     }
1668 }
1669 
1670 /**
1671  * gtk_tree_view_column_set_attributes:
1672  * @tree_column: A `GtkTreeViewColumn`
1673  * @cell_renderer: the `GtkCellRenderer` we’re setting the attributes of
1674  * @...: A %NULL-terminated list of attributes
1675  *
1676  * Sets the attributes in the list as the attributes of @tree_column.
1677  *
1678  * The attributes should be in attribute/column order, as in
1679  * gtk_tree_view_column_add_attribute(). All existing attributes
1680  * are removed, and replaced with the new attributes.
1681  */
1682 void
gtk_tree_view_column_set_attributes(GtkTreeViewColumn * tree_column,GtkCellRenderer * cell_renderer,...)1683 gtk_tree_view_column_set_attributes (GtkTreeViewColumn *tree_column,
1684 				     GtkCellRenderer   *cell_renderer,
1685 				     ...)
1686 {
1687   va_list args;
1688 
1689   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1690   g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1691 
1692   va_start (args, cell_renderer);
1693   gtk_tree_view_column_set_attributesv (tree_column, cell_renderer, args);
1694   va_end (args);
1695 }
1696 
1697 
1698 /**
1699  * gtk_tree_view_column_set_cell_data_func:
1700  * @tree_column: A `GtkTreeViewColumn`
1701  * @cell_renderer: A `GtkCellRenderer`
1702  * @func: (nullable): The `GtkTreeCellDataFunc` to use.
1703  * @func_data: (closure): The user data for @func.
1704  * @destroy: The destroy notification for @func_data
1705  *
1706  * Sets the `GtkTreeCellDataFunc` to use for the column.
1707  *
1708  * This
1709  * function is used instead of the standard attributes mapping for
1710  * setting the column value, and should set the value of @tree_column's
1711  * cell renderer as appropriate.  @func may be %NULL to remove an
1712  * older one.
1713  **/
1714 void
gtk_tree_view_column_set_cell_data_func(GtkTreeViewColumn * tree_column,GtkCellRenderer * cell_renderer,GtkTreeCellDataFunc func,gpointer func_data,GDestroyNotify destroy)1715 gtk_tree_view_column_set_cell_data_func (GtkTreeViewColumn   *tree_column,
1716 					 GtkCellRenderer     *cell_renderer,
1717 					 GtkTreeCellDataFunc  func,
1718 					 gpointer             func_data,
1719 					 GDestroyNotify       destroy)
1720 {
1721   gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (tree_column),
1722                                       cell_renderer,
1723                                       (GtkCellLayoutDataFunc)func,
1724                                       func_data, destroy);
1725 }
1726 
1727 
1728 /**
1729  * gtk_tree_view_column_clear_attributes:
1730  * @tree_column: a `GtkTreeViewColumn`
1731  * @cell_renderer: a `GtkCellRenderer` to clear the attribute mapping on.
1732  *
1733  * Clears all existing attributes previously set with
1734  * gtk_tree_view_column_set_attributes().
1735  **/
1736 void
gtk_tree_view_column_clear_attributes(GtkTreeViewColumn * tree_column,GtkCellRenderer * cell_renderer)1737 gtk_tree_view_column_clear_attributes (GtkTreeViewColumn *tree_column,
1738 				       GtkCellRenderer   *cell_renderer)
1739 {
1740   gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (tree_column),
1741                                     cell_renderer);
1742 }
1743 
1744 /**
1745  * gtk_tree_view_column_set_spacing:
1746  * @tree_column: A `GtkTreeViewColumn`.
1747  * @spacing: distance between cell renderers in pixels.
1748  *
1749  * Sets the spacing field of @tree_column, which is the number of pixels to
1750  * place between cell renderers packed into it.
1751  **/
1752 void
gtk_tree_view_column_set_spacing(GtkTreeViewColumn * tree_column,int spacing)1753 gtk_tree_view_column_set_spacing (GtkTreeViewColumn *tree_column,
1754 				  int                spacing)
1755 {
1756   GtkTreeViewColumnPrivate *priv;
1757 
1758   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1759   g_return_if_fail (spacing >= 0);
1760 
1761   priv = tree_column->priv;
1762 
1763   if (gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (priv->cell_area)) != spacing)
1764     {
1765       gtk_cell_area_box_set_spacing (GTK_CELL_AREA_BOX (priv->cell_area), spacing);
1766       if (priv->tree_view)
1767         _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
1768       g_object_notify_by_pspec (G_OBJECT (tree_column), tree_column_props[PROP_SPACING]);
1769     }
1770 }
1771 
1772 /**
1773  * gtk_tree_view_column_get_spacing:
1774  * @tree_column: A `GtkTreeViewColumn`.
1775  *
1776  * Returns the spacing of @tree_column.
1777  *
1778  * Returns: the spacing of @tree_column.
1779  **/
1780 int
gtk_tree_view_column_get_spacing(GtkTreeViewColumn * tree_column)1781 gtk_tree_view_column_get_spacing (GtkTreeViewColumn *tree_column)
1782 {
1783   GtkTreeViewColumnPrivate *priv;
1784 
1785   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1786 
1787   priv = tree_column->priv;
1788 
1789   return gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (priv->cell_area));
1790 }
1791 
1792 /* Options for manipulating the columns */
1793 
1794 /**
1795  * gtk_tree_view_column_set_visible:
1796  * @tree_column: A `GtkTreeViewColumn`.
1797  * @visible: %TRUE if the @tree_column is visible.
1798  *
1799  * Sets the visibility of @tree_column.
1800  */
1801 void
gtk_tree_view_column_set_visible(GtkTreeViewColumn * tree_column,gboolean visible)1802 gtk_tree_view_column_set_visible (GtkTreeViewColumn *tree_column,
1803                                   gboolean           visible)
1804 {
1805   GtkTreeViewColumnPrivate *priv;
1806 
1807   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1808 
1809   priv    = tree_column->priv;
1810   visible = !! visible;
1811 
1812   if (priv->visible == visible)
1813     return;
1814 
1815   priv->visible = visible;
1816 
1817   gtk_widget_set_visible (priv->button, visible);
1818 
1819   if (priv->visible)
1820     _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
1821 
1822   gtk_tree_view_column_update_button (tree_column);
1823   g_object_notify_by_pspec (G_OBJECT (tree_column), tree_column_props[PROP_VISIBLE]);
1824 }
1825 
1826 /**
1827  * gtk_tree_view_column_get_visible:
1828  * @tree_column: A `GtkTreeViewColumn`.
1829  *
1830  * Returns %TRUE if @tree_column is visible.
1831  *
1832  * Returns: whether the column is visible or not.  If it is visible, then
1833  * the tree will show the column.
1834  **/
1835 gboolean
gtk_tree_view_column_get_visible(GtkTreeViewColumn * tree_column)1836 gtk_tree_view_column_get_visible (GtkTreeViewColumn *tree_column)
1837 {
1838   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
1839 
1840   return tree_column->priv->visible;
1841 }
1842 
1843 /**
1844  * gtk_tree_view_column_set_resizable:
1845  * @tree_column: A `GtkTreeViewColumn`
1846  * @resizable: %TRUE, if the column can be resized
1847  *
1848  * If @resizable is %TRUE, then the user can explicitly resize the column by
1849  * grabbing the outer edge of the column button.
1850  *
1851  * If resizable is %TRUE and
1852  * sizing mode of the column is %GTK_TREE_VIEW_COLUMN_AUTOSIZE, then the sizing
1853  * mode is changed to %GTK_TREE_VIEW_COLUMN_GROW_ONLY.
1854  **/
1855 void
gtk_tree_view_column_set_resizable(GtkTreeViewColumn * tree_column,gboolean resizable)1856 gtk_tree_view_column_set_resizable (GtkTreeViewColumn *tree_column,
1857 				    gboolean           resizable)
1858 {
1859   GtkTreeViewColumnPrivate *priv;
1860 
1861   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1862 
1863   priv      = tree_column->priv;
1864   resizable = !! resizable;
1865 
1866   if (priv->resizable == resizable)
1867     return;
1868 
1869   priv->resizable = resizable;
1870 
1871   if (resizable && priv->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
1872     gtk_tree_view_column_set_sizing (tree_column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1873 
1874   gtk_tree_view_column_update_button (tree_column);
1875 
1876   g_object_notify_by_pspec (G_OBJECT (tree_column), tree_column_props[PROP_RESIZABLE]);
1877 }
1878 
1879 /**
1880  * gtk_tree_view_column_get_resizable:
1881  * @tree_column: A `GtkTreeViewColumn`
1882  *
1883  * Returns %TRUE if the @tree_column can be resized by the end user.
1884  *
1885  * Returns: %TRUE, if the @tree_column can be resized.
1886  **/
1887 gboolean
gtk_tree_view_column_get_resizable(GtkTreeViewColumn * tree_column)1888 gtk_tree_view_column_get_resizable (GtkTreeViewColumn *tree_column)
1889 {
1890   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
1891 
1892   return tree_column->priv->resizable;
1893 }
1894 
1895 
1896 /**
1897  * gtk_tree_view_column_set_sizing:
1898  * @tree_column: A `GtkTreeViewColumn`.
1899  * @type: The `GtkTreeViewColumn`Sizing.
1900  *
1901  * Sets the growth behavior of @tree_column to @type.
1902  **/
1903 void
gtk_tree_view_column_set_sizing(GtkTreeViewColumn * tree_column,GtkTreeViewColumnSizing type)1904 gtk_tree_view_column_set_sizing (GtkTreeViewColumn       *tree_column,
1905                                  GtkTreeViewColumnSizing  type)
1906 {
1907   GtkTreeViewColumnPrivate *priv;
1908 
1909   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1910 
1911   priv      = tree_column->priv;
1912 
1913   if (type == priv->column_type)
1914     return;
1915 
1916   if (type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
1917     gtk_tree_view_column_set_resizable (tree_column, FALSE);
1918 
1919   priv->column_type = type;
1920 
1921   gtk_tree_view_column_update_button (tree_column);
1922 
1923   g_object_notify_by_pspec (G_OBJECT (tree_column), tree_column_props[PROP_SIZING]);
1924 }
1925 
1926 /**
1927  * gtk_tree_view_column_get_sizing:
1928  * @tree_column: A `GtkTreeViewColumn`.
1929  *
1930  * Returns the current type of @tree_column.
1931  *
1932  * Returns: The type of @tree_column.
1933  **/
1934 GtkTreeViewColumnSizing
gtk_tree_view_column_get_sizing(GtkTreeViewColumn * tree_column)1935 gtk_tree_view_column_get_sizing (GtkTreeViewColumn *tree_column)
1936 {
1937   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1938 
1939   return tree_column->priv->column_type;
1940 }
1941 
1942 /**
1943  * gtk_tree_view_column_get_width:
1944  * @tree_column: A `GtkTreeViewColumn`.
1945  *
1946  * Returns the current size of @tree_column in pixels.
1947  *
1948  * Returns: The current width of @tree_column.
1949  **/
1950 int
gtk_tree_view_column_get_width(GtkTreeViewColumn * tree_column)1951 gtk_tree_view_column_get_width (GtkTreeViewColumn *tree_column)
1952 {
1953   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1954 
1955   return tree_column->priv->width;
1956 }
1957 
1958 /**
1959  * gtk_tree_view_column_get_x_offset:
1960  * @tree_column: A `GtkTreeViewColumn`.
1961  *
1962  * Returns the current X offset of @tree_column in pixels.
1963  *
1964  * Returns: The current X offset of @tree_column.
1965  */
1966 int
gtk_tree_view_column_get_x_offset(GtkTreeViewColumn * tree_column)1967 gtk_tree_view_column_get_x_offset (GtkTreeViewColumn *tree_column)
1968 {
1969   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1970 
1971   return tree_column->priv->x_offset;
1972 }
1973 
1974 int
_gtk_tree_view_column_request_width(GtkTreeViewColumn * tree_column)1975 _gtk_tree_view_column_request_width (GtkTreeViewColumn *tree_column)
1976 {
1977   GtkTreeViewColumnPrivate *priv;
1978   int real_requested_width;
1979 
1980   priv = tree_column->priv;
1981 
1982   if (priv->fixed_width != -1)
1983     {
1984       real_requested_width = priv->fixed_width;
1985     }
1986   else if (gtk_tree_view_get_headers_visible (GTK_TREE_VIEW (priv->tree_view)))
1987     {
1988       int button_request;
1989       int requested_width;
1990 
1991       gtk_cell_area_context_get_preferred_width (priv->cell_area_context, &requested_width, NULL);
1992       requested_width += priv->padding;
1993 
1994       gtk_widget_measure (priv->button, GTK_ORIENTATION_HORIZONTAL, -1,
1995                           &button_request, NULL, NULL, NULL);
1996       real_requested_width = MAX (requested_width, button_request);
1997     }
1998   else
1999     {
2000       int requested_width;
2001 
2002       gtk_cell_area_context_get_preferred_width (priv->cell_area_context, &requested_width, NULL);
2003       requested_width += priv->padding;
2004 
2005       real_requested_width = requested_width;
2006       if (real_requested_width < 0)
2007         real_requested_width = 0;
2008     }
2009 
2010   if (priv->min_width != -1)
2011     real_requested_width = MAX (real_requested_width, priv->min_width);
2012 
2013   if (priv->max_width != -1)
2014     real_requested_width = MIN (real_requested_width, priv->max_width);
2015 
2016   return real_requested_width;
2017 }
2018 
2019 void
_gtk_tree_view_column_allocate(GtkTreeViewColumn * tree_column,int x_offset,int width,int height)2020 _gtk_tree_view_column_allocate (GtkTreeViewColumn *tree_column,
2021 				int                x_offset,
2022 				int                width,
2023                                 int                height)
2024 {
2025   GtkTreeViewColumnPrivate *priv;
2026   GtkAllocation             allocation = { 0, 0, 0, 0 };
2027 
2028   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2029 
2030   priv = tree_column->priv;
2031 
2032   if (priv->width != width)
2033     gtk_widget_queue_draw (priv->tree_view);
2034 
2035   priv->x_offset = x_offset;
2036   priv->width = width;
2037 
2038   gtk_cell_area_context_allocate (priv->cell_area_context, priv->width - priv->padding, -1);
2039 
2040   if (gtk_tree_view_get_headers_visible (GTK_TREE_VIEW (priv->tree_view)))
2041     {
2042       /* TODO: Underallocates the button horizontally, but
2043        * https://bugzilla.gnome.org/show_bug.cgi?id=770388
2044        */
2045       allocation.x      = x_offset;
2046       allocation.y      = 0;
2047       allocation.width  = width;
2048       allocation.height = height;
2049 
2050       gtk_widget_size_allocate (priv->button, &allocation, -1);
2051     }
2052 
2053   g_object_notify_by_pspec (G_OBJECT (tree_column), tree_column_props[PROP_X_OFFSET]);
2054   g_object_notify_by_pspec (G_OBJECT (tree_column), tree_column_props[PROP_WIDTH]);
2055 }
2056 
2057 /**
2058  * gtk_tree_view_column_set_fixed_width:
2059  * @tree_column: A `GtkTreeViewColumn`.
2060  * @fixed_width: The new fixed width, in pixels, or -1.
2061  *
2062  * If @fixed_width is not -1, sets the fixed width of @tree_column; otherwise
2063  * unsets it.  The effective value of @fixed_width is clamped between the
2064  * minimum and maximum width of the column; however, the value stored in the
2065  * “fixed-width” property is not clamped.  If the column sizing is
2066  * %GTK_TREE_VIEW_COLUMN_GROW_ONLY or %GTK_TREE_VIEW_COLUMN_AUTOSIZE, setting
2067  * a fixed width overrides the automatically calculated width.  Note that
2068  * @fixed_width is only a hint to GTK; the width actually allocated to the
2069  * column may be greater or less than requested.
2070  *
2071  * Along with “expand”, the “fixed-width” property changes when the column is
2072  * resized by the user.
2073  **/
2074 void
gtk_tree_view_column_set_fixed_width(GtkTreeViewColumn * tree_column,int fixed_width)2075 gtk_tree_view_column_set_fixed_width (GtkTreeViewColumn *tree_column,
2076 				      int                fixed_width)
2077 {
2078   GtkTreeViewColumnPrivate *priv;
2079 
2080   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2081   g_return_if_fail (fixed_width >= -1);
2082 
2083   priv = tree_column->priv;
2084 
2085   if (priv->fixed_width != fixed_width)
2086     {
2087       priv->fixed_width = fixed_width;
2088       if (priv->visible &&
2089           priv->tree_view != NULL &&
2090           gtk_widget_get_realized (priv->tree_view))
2091         gtk_widget_queue_resize (priv->tree_view);
2092 
2093       g_object_notify_by_pspec (G_OBJECT (tree_column), tree_column_props[PROP_FIXED_WIDTH]);
2094     }
2095 }
2096 
2097 /**
2098  * gtk_tree_view_column_get_fixed_width:
2099  * @tree_column: A `GtkTreeViewColumn`.
2100  *
2101  * Gets the fixed width of the column.  This may not be the actual displayed
2102  * width of the column; for that, use gtk_tree_view_column_get_width().
2103  *
2104  * Returns: The fixed width of the column.
2105  **/
2106 int
gtk_tree_view_column_get_fixed_width(GtkTreeViewColumn * tree_column)2107 gtk_tree_view_column_get_fixed_width (GtkTreeViewColumn *tree_column)
2108 {
2109   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
2110 
2111   return tree_column->priv->fixed_width;
2112 }
2113 
2114 /**
2115  * gtk_tree_view_column_set_min_width:
2116  * @tree_column: A `GtkTreeViewColumn`.
2117  * @min_width: The minimum width of the column in pixels, or -1.
2118  *
2119  * Sets the minimum width of the @tree_column.  If @min_width is -1, then the
2120  * minimum width is unset.
2121  **/
2122 void
gtk_tree_view_column_set_min_width(GtkTreeViewColumn * tree_column,int min_width)2123 gtk_tree_view_column_set_min_width (GtkTreeViewColumn *tree_column,
2124 				    int                min_width)
2125 {
2126   GtkTreeViewColumnPrivate *priv;
2127 
2128   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2129   g_return_if_fail (min_width >= -1);
2130 
2131   priv = tree_column->priv;
2132 
2133   if (min_width == priv->min_width)
2134     return;
2135 
2136   if (priv->visible &&
2137       priv->tree_view != NULL &&
2138       gtk_widget_get_realized (priv->tree_view))
2139     {
2140       if (min_width > priv->width)
2141 	gtk_widget_queue_resize (priv->tree_view);
2142     }
2143 
2144   priv->min_width = min_width;
2145   g_object_freeze_notify (G_OBJECT (tree_column));
2146   if (priv->max_width != -1 && priv->max_width < min_width)
2147     {
2148       priv->max_width = min_width;
2149       g_object_notify_by_pspec (G_OBJECT (tree_column), tree_column_props[PROP_MAX_WIDTH]);
2150     }
2151   g_object_notify_by_pspec (G_OBJECT (tree_column), tree_column_props[PROP_MIN_WIDTH]);
2152   g_object_thaw_notify (G_OBJECT (tree_column));
2153 
2154   if (priv->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE && priv->tree_view)
2155     _gtk_tree_view_column_autosize (GTK_TREE_VIEW (priv->tree_view),
2156 				    tree_column);
2157 }
2158 
2159 /**
2160  * gtk_tree_view_column_get_min_width:
2161  * @tree_column: A `GtkTreeViewColumn`.
2162  *
2163  * Returns the minimum width in pixels of the @tree_column, or -1 if no minimum
2164  * width is set.
2165  *
2166  * Returns: The minimum width of the @tree_column.
2167  **/
2168 int
gtk_tree_view_column_get_min_width(GtkTreeViewColumn * tree_column)2169 gtk_tree_view_column_get_min_width (GtkTreeViewColumn *tree_column)
2170 {
2171   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), -1);
2172 
2173   return tree_column->priv->min_width;
2174 }
2175 
2176 /**
2177  * gtk_tree_view_column_set_max_width:
2178  * @tree_column: A `GtkTreeViewColumn`.
2179  * @max_width: The maximum width of the column in pixels, or -1.
2180  *
2181  * Sets the maximum width of the @tree_column.  If @max_width is -1, then the
2182  * maximum width is unset.  Note, the column can actually be wider than max
2183  * width if it’s the last column in a view.  In this case, the column expands to
2184  * fill any extra space.
2185  **/
2186 void
gtk_tree_view_column_set_max_width(GtkTreeViewColumn * tree_column,int max_width)2187 gtk_tree_view_column_set_max_width (GtkTreeViewColumn *tree_column,
2188 				    int                max_width)
2189 {
2190   GtkTreeViewColumnPrivate *priv;
2191 
2192   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2193   g_return_if_fail (max_width >= -1);
2194 
2195   priv = tree_column->priv;
2196 
2197   if (max_width == priv->max_width)
2198     return;
2199 
2200   if (priv->visible &&
2201       priv->tree_view != NULL &&
2202       gtk_widget_get_realized (priv->tree_view))
2203     {
2204       if (max_width != -1 && max_width < priv->width)
2205 	gtk_widget_queue_resize (priv->tree_view);
2206     }
2207 
2208   priv->max_width = max_width;
2209   g_object_freeze_notify (G_OBJECT (tree_column));
2210   if (max_width != -1 && max_width < priv->min_width)
2211     {
2212       priv->min_width = max_width;
2213       g_object_notify_by_pspec (G_OBJECT (tree_column), tree_column_props[PROP_MIN_WIDTH]);
2214     }
2215   g_object_notify_by_pspec (G_OBJECT (tree_column), tree_column_props[PROP_MAX_WIDTH]);
2216   g_object_thaw_notify (G_OBJECT (tree_column));
2217 
2218   if (priv->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE && priv->tree_view)
2219     _gtk_tree_view_column_autosize (GTK_TREE_VIEW (priv->tree_view),
2220 				    tree_column);
2221 }
2222 
2223 /**
2224  * gtk_tree_view_column_get_max_width:
2225  * @tree_column: A `GtkTreeViewColumn`.
2226  *
2227  * Returns the maximum width in pixels of the @tree_column, or -1 if no maximum
2228  * width is set.
2229  *
2230  * Returns: The maximum width of the @tree_column.
2231  **/
2232 int
gtk_tree_view_column_get_max_width(GtkTreeViewColumn * tree_column)2233 gtk_tree_view_column_get_max_width (GtkTreeViewColumn *tree_column)
2234 {
2235   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), -1);
2236 
2237   return tree_column->priv->max_width;
2238 }
2239 
2240 /**
2241  * gtk_tree_view_column_clicked:
2242  * @tree_column: a `GtkTreeViewColumn`
2243  *
2244  * Emits the “clicked” signal on the column.  This function will only work if
2245  * @tree_column is clickable.
2246  **/
2247 void
gtk_tree_view_column_clicked(GtkTreeViewColumn * tree_column)2248 gtk_tree_view_column_clicked (GtkTreeViewColumn *tree_column)
2249 {
2250   GtkTreeViewColumnPrivate *priv;
2251 
2252   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2253 
2254   priv = tree_column->priv;
2255 
2256   if (priv->visible && priv->clickable)
2257     g_signal_emit_by_name (priv->button, "clicked");
2258 }
2259 
2260 /**
2261  * gtk_tree_view_column_set_title:
2262  * @tree_column: A `GtkTreeViewColumn`.
2263  * @title: The title of the @tree_column.
2264  *
2265  * Sets the title of the @tree_column.  If a custom widget has been set, then
2266  * this value is ignored.
2267  **/
2268 void
gtk_tree_view_column_set_title(GtkTreeViewColumn * tree_column,const char * title)2269 gtk_tree_view_column_set_title (GtkTreeViewColumn *tree_column,
2270 				const char        *title)
2271 {
2272   GtkTreeViewColumnPrivate *priv;
2273   char                     *new_title;
2274 
2275   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2276 
2277   priv = tree_column->priv;
2278 
2279   new_title = g_strdup (title);
2280   g_free (priv->title);
2281   priv->title = new_title;
2282 
2283   gtk_tree_view_column_update_button (tree_column);
2284   g_object_notify_by_pspec (G_OBJECT (tree_column), tree_column_props[PROP_TITLE]);
2285 }
2286 
2287 /**
2288  * gtk_tree_view_column_get_title:
2289  * @tree_column: A `GtkTreeViewColumn`.
2290  *
2291  * Returns the title of the widget.
2292  *
2293  * Returns: the title of the column. This string should not be
2294  * modified or freed.
2295  **/
2296 const char *
gtk_tree_view_column_get_title(GtkTreeViewColumn * tree_column)2297 gtk_tree_view_column_get_title (GtkTreeViewColumn *tree_column)
2298 {
2299   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), NULL);
2300 
2301   return tree_column->priv->title;
2302 }
2303 
2304 /**
2305  * gtk_tree_view_column_set_expand:
2306  * @tree_column: A `GtkTreeViewColumn`.
2307  * @expand: %TRUE if the column should expand to fill available space.
2308  *
2309  * Sets the column to take available extra space.  This space is shared equally
2310  * amongst all columns that have the expand set to %TRUE.  If no column has this
2311  * option set, then the last column gets all extra space.  By default, every
2312  * column is created with this %FALSE.
2313  *
2314  * Along with “fixed-width”, the “expand” property changes when the column is
2315  * resized by the user.
2316  **/
2317 void
gtk_tree_view_column_set_expand(GtkTreeViewColumn * tree_column,gboolean expand)2318 gtk_tree_view_column_set_expand (GtkTreeViewColumn *tree_column,
2319 				 gboolean           expand)
2320 {
2321   GtkTreeViewColumnPrivate *priv;
2322 
2323   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2324 
2325   priv = tree_column->priv;
2326 
2327   expand = expand?TRUE:FALSE;
2328   if (priv->expand == expand)
2329     return;
2330   priv->expand = expand;
2331 
2332   if (priv->visible &&
2333       priv->tree_view != NULL &&
2334       gtk_widget_get_realized (priv->tree_view))
2335     {
2336       gtk_widget_queue_resize (priv->tree_view);
2337     }
2338 
2339   g_object_notify_by_pspec (G_OBJECT (tree_column), tree_column_props[PROP_EXPAND]);
2340 }
2341 
2342 /**
2343  * gtk_tree_view_column_get_expand:
2344  * @tree_column: A `GtkTreeViewColumn`.
2345  *
2346  * Returns %TRUE if the column expands to fill available space.
2347  *
2348  * Returns: %TRUE if the column expands to fill available space.
2349  **/
2350 gboolean
gtk_tree_view_column_get_expand(GtkTreeViewColumn * tree_column)2351 gtk_tree_view_column_get_expand (GtkTreeViewColumn *tree_column)
2352 {
2353   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
2354 
2355   return tree_column->priv->expand;
2356 }
2357 
2358 /**
2359  * gtk_tree_view_column_set_clickable:
2360  * @tree_column: A `GtkTreeViewColumn`.
2361  * @clickable: %TRUE if the header is active.
2362  *
2363  * Sets the header to be active if @clickable is %TRUE.  When the header is
2364  * active, then it can take keyboard focus, and can be clicked.
2365  **/
2366 void
gtk_tree_view_column_set_clickable(GtkTreeViewColumn * tree_column,gboolean clickable)2367 gtk_tree_view_column_set_clickable (GtkTreeViewColumn *tree_column,
2368                                     gboolean           clickable)
2369 {
2370   GtkTreeViewColumnPrivate *priv;
2371 
2372   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2373 
2374   priv = tree_column->priv;
2375 
2376   clickable = !! clickable;
2377   if (priv->clickable == clickable)
2378     return;
2379 
2380   priv->clickable = clickable;
2381   gtk_tree_view_column_update_button (tree_column);
2382   g_object_notify_by_pspec (G_OBJECT (tree_column), tree_column_props[PROP_CLICKABLE]);
2383 }
2384 
2385 /**
2386  * gtk_tree_view_column_get_clickable:
2387  * @tree_column: a `GtkTreeViewColumn`
2388  *
2389  * Returns %TRUE if the user can click on the header for the column.
2390  *
2391  * Returns: %TRUE if user can click the column header.
2392  **/
2393 gboolean
gtk_tree_view_column_get_clickable(GtkTreeViewColumn * tree_column)2394 gtk_tree_view_column_get_clickable (GtkTreeViewColumn *tree_column)
2395 {
2396   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
2397 
2398   return tree_column->priv->clickable;
2399 }
2400 
2401 /**
2402  * gtk_tree_view_column_set_widget:
2403  * @tree_column: A `GtkTreeViewColumn`.
2404  * @widget: (nullable): A child `GtkWidget`
2405  *
2406  * Sets the widget in the header to be @widget.  If widget is %NULL, then the
2407  * header button is set with a `GtkLabel` set to the title of @tree_column.
2408  **/
2409 void
gtk_tree_view_column_set_widget(GtkTreeViewColumn * tree_column,GtkWidget * widget)2410 gtk_tree_view_column_set_widget (GtkTreeViewColumn *tree_column,
2411 				 GtkWidget         *widget)
2412 {
2413   GtkTreeViewColumnPrivate *priv;
2414 
2415   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2416   g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
2417 
2418   priv = tree_column->priv;
2419 
2420   if (widget)
2421     g_object_ref_sink (widget);
2422 
2423   if (priv->child)
2424     g_object_unref (priv->child);
2425 
2426   priv->child = widget;
2427   gtk_tree_view_column_update_button (tree_column);
2428   g_object_notify_by_pspec (G_OBJECT (tree_column), tree_column_props[PROP_WIDGET]);
2429 }
2430 
2431 /**
2432  * gtk_tree_view_column_get_widget:
2433  * @tree_column: A `GtkTreeViewColumn`
2434  *
2435  * Returns the `GtkWidget` in the button on the column header.
2436  *
2437  * If a custom widget has not been set then %NULL is returned.
2438  *
2439  * Returns: (nullable) (transfer none): The `GtkWidget` in the column header
2440  */
2441 GtkWidget *
gtk_tree_view_column_get_widget(GtkTreeViewColumn * tree_column)2442 gtk_tree_view_column_get_widget (GtkTreeViewColumn *tree_column)
2443 {
2444   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), NULL);
2445 
2446   return tree_column->priv->child;
2447 }
2448 
2449 /**
2450  * gtk_tree_view_column_set_alignment:
2451  * @tree_column: A `GtkTreeViewColumn`.
2452  * @xalign: The alignment, which is between [0.0 and 1.0] inclusive.
2453  *
2454  * Sets the alignment of the title or custom widget inside the column header.
2455  * The alignment determines its location inside the button -- 0.0 for left, 0.5
2456  * for center, 1.0 for right.
2457  **/
2458 void
gtk_tree_view_column_set_alignment(GtkTreeViewColumn * tree_column,float xalign)2459 gtk_tree_view_column_set_alignment (GtkTreeViewColumn *tree_column,
2460                                     float              xalign)
2461 {
2462   GtkTreeViewColumnPrivate *priv;
2463 
2464   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2465 
2466   priv = tree_column->priv;
2467 
2468   xalign = CLAMP (xalign, 0.0, 1.0);
2469 
2470   if (priv->xalign == xalign)
2471     return;
2472 
2473   priv->xalign = xalign;
2474   gtk_tree_view_column_update_button (tree_column);
2475   g_object_notify_by_pspec (G_OBJECT (tree_column), tree_column_props[PROP_ALIGNMENT]);
2476 }
2477 
2478 /**
2479  * gtk_tree_view_column_get_alignment:
2480  * @tree_column: A `GtkTreeViewColumn`.
2481  *
2482  * Returns the current x alignment of @tree_column.  This value can range
2483  * between 0.0 and 1.0.
2484  *
2485  * Returns: The current alignent of @tree_column.
2486  **/
2487 float
gtk_tree_view_column_get_alignment(GtkTreeViewColumn * tree_column)2488 gtk_tree_view_column_get_alignment (GtkTreeViewColumn *tree_column)
2489 {
2490   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0.5);
2491 
2492   return tree_column->priv->xalign;
2493 }
2494 
2495 /**
2496  * gtk_tree_view_column_set_reorderable:
2497  * @tree_column: A `GtkTreeViewColumn`
2498  * @reorderable: %TRUE, if the column can be reordered.
2499  *
2500  * If @reorderable is %TRUE, then the column can be reordered by the end user
2501  * dragging the header.
2502  **/
2503 void
gtk_tree_view_column_set_reorderable(GtkTreeViewColumn * tree_column,gboolean reorderable)2504 gtk_tree_view_column_set_reorderable (GtkTreeViewColumn *tree_column,
2505 				      gboolean           reorderable)
2506 {
2507   GtkTreeViewColumnPrivate *priv;
2508 
2509   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2510 
2511   priv = tree_column->priv;
2512 
2513   /*  if (reorderable)
2514       gtk_tree_view_column_set_clickable (tree_column, TRUE);*/
2515 
2516   if (priv->reorderable == (reorderable?TRUE:FALSE))
2517     return;
2518 
2519   priv->reorderable = (reorderable?TRUE:FALSE);
2520   gtk_tree_view_column_update_button (tree_column);
2521   g_object_notify_by_pspec (G_OBJECT (tree_column), tree_column_props[PROP_REORDERABLE]);
2522 }
2523 
2524 /**
2525  * gtk_tree_view_column_get_reorderable:
2526  * @tree_column: A `GtkTreeViewColumn`
2527  *
2528  * Returns %TRUE if the @tree_column can be reordered by the user.
2529  *
2530  * Returns: %TRUE if the @tree_column can be reordered by the user.
2531  **/
2532 gboolean
gtk_tree_view_column_get_reorderable(GtkTreeViewColumn * tree_column)2533 gtk_tree_view_column_get_reorderable (GtkTreeViewColumn *tree_column)
2534 {
2535   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
2536 
2537   return tree_column->priv->reorderable;
2538 }
2539 
2540 
2541 /**
2542  * gtk_tree_view_column_set_sort_column_id:
2543  * @tree_column: a `GtkTreeViewColumn`
2544  * @sort_column_id: The @sort_column_id of the model to sort on.
2545  *
2546  * Sets the logical @sort_column_id that this column sorts on when this column
2547  * is selected for sorting.  Doing so makes the column header clickable.
2548  **/
2549 void
gtk_tree_view_column_set_sort_column_id(GtkTreeViewColumn * tree_column,int sort_column_id)2550 gtk_tree_view_column_set_sort_column_id (GtkTreeViewColumn *tree_column,
2551 					 int                sort_column_id)
2552 {
2553   GtkTreeViewColumnPrivate *priv;
2554 
2555   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2556   g_return_if_fail (sort_column_id >= -1);
2557 
2558   priv = tree_column->priv;
2559 
2560   if (priv->sort_column_id == sort_column_id)
2561     return;
2562 
2563   priv->sort_column_id = sort_column_id;
2564 
2565   /* Handle unsetting the id */
2566   if (sort_column_id == -1)
2567     {
2568       GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree_view));
2569 
2570       if (priv->sort_clicked_signal)
2571 	{
2572 	  g_signal_handler_disconnect (tree_column, priv->sort_clicked_signal);
2573 	  priv->sort_clicked_signal = 0;
2574 	}
2575 
2576       if (priv->sort_column_changed_signal)
2577 	{
2578 	  g_signal_handler_disconnect (model, priv->sort_column_changed_signal);
2579 	  priv->sort_column_changed_signal = 0;
2580 	}
2581 
2582       gtk_tree_view_column_set_sort_order (tree_column, GTK_SORT_ASCENDING);
2583       gtk_tree_view_column_set_sort_indicator (tree_column, FALSE);
2584       gtk_tree_view_column_set_clickable (tree_column, FALSE);
2585       g_object_notify_by_pspec (G_OBJECT (tree_column), tree_column_props[PROP_SORT_COLUMN_ID]);
2586       return;
2587     }
2588 
2589   gtk_tree_view_column_set_clickable (tree_column, TRUE);
2590 
2591   if (! priv->sort_clicked_signal)
2592     priv->sort_clicked_signal = g_signal_connect (tree_column,
2593 						  "clicked",
2594 						  G_CALLBACK (gtk_tree_view_column_sort),
2595 						  NULL);
2596 
2597   gtk_tree_view_column_setup_sort_column_id_callback (tree_column);
2598   g_object_notify_by_pspec (G_OBJECT (tree_column), tree_column_props[PROP_SORT_COLUMN_ID]);
2599 }
2600 
2601 /**
2602  * gtk_tree_view_column_get_sort_column_id:
2603  * @tree_column: a `GtkTreeViewColumn`
2604  *
2605  * Gets the logical @sort_column_id that the model sorts on
2606  * when this column is selected for sorting.
2607  *
2608  * See [method@Gtk.TreeViewColumn.set_sort_column_id].
2609  *
2610  * Returns: the current @sort_column_id for this column, or -1 if
2611  *   this column can’t be used for sorting
2612  */
2613 int
gtk_tree_view_column_get_sort_column_id(GtkTreeViewColumn * tree_column)2614 gtk_tree_view_column_get_sort_column_id (GtkTreeViewColumn *tree_column)
2615 {
2616   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
2617 
2618   return tree_column->priv->sort_column_id;
2619 }
2620 
2621 /**
2622  * gtk_tree_view_column_set_sort_indicator:
2623  * @tree_column: a `GtkTreeViewColumn`
2624  * @setting: %TRUE to display an indicator that the column is sorted
2625  *
2626  * Call this function with a @setting of %TRUE to display an arrow in
2627  * the header button indicating the column is sorted. Call
2628  * gtk_tree_view_column_set_sort_order() to change the direction of
2629  * the arrow.
2630  *
2631  **/
2632 void
gtk_tree_view_column_set_sort_indicator(GtkTreeViewColumn * tree_column,gboolean setting)2633 gtk_tree_view_column_set_sort_indicator (GtkTreeViewColumn     *tree_column,
2634                                          gboolean               setting)
2635 {
2636   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2637 
2638   setting = setting != FALSE;
2639 
2640   if (setting == tree_column->priv->show_sort_indicator)
2641     return;
2642 
2643   tree_column->priv->show_sort_indicator = setting;
2644   gtk_tree_view_column_update_button (tree_column);
2645   g_object_notify_by_pspec (G_OBJECT (tree_column), tree_column_props[PROP_SORT_INDICATOR]);
2646 }
2647 
2648 /**
2649  * gtk_tree_view_column_get_sort_indicator:
2650  * @tree_column: a `GtkTreeViewColumn`
2651  *
2652  * Gets the value set by gtk_tree_view_column_set_sort_indicator().
2653  *
2654  * Returns: whether the sort indicator arrow is displayed
2655  **/
2656 gboolean
gtk_tree_view_column_get_sort_indicator(GtkTreeViewColumn * tree_column)2657 gtk_tree_view_column_get_sort_indicator  (GtkTreeViewColumn     *tree_column)
2658 {
2659   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
2660 
2661   return tree_column->priv->show_sort_indicator;
2662 }
2663 
2664 /**
2665  * gtk_tree_view_column_set_sort_order:
2666  * @tree_column: a `GtkTreeViewColumn`
2667  * @order: sort order that the sort indicator should indicate
2668  *
2669  * Changes the appearance of the sort indicator.
2670  *
2671  * This does not actually sort the model.  Use
2672  * gtk_tree_view_column_set_sort_column_id() if you want automatic sorting
2673  * support.  This function is primarily for custom sorting behavior, and should
2674  * be used in conjunction with gtk_tree_sortable_set_sort_column_id() to do
2675  * that. For custom models, the mechanism will vary.
2676  *
2677  * The sort indicator changes direction to indicate normal sort or reverse sort.
2678  * Note that you must have the sort indicator enabled to see anything when
2679  * calling this function; see gtk_tree_view_column_set_sort_indicator().
2680  **/
2681 void
gtk_tree_view_column_set_sort_order(GtkTreeViewColumn * tree_column,GtkSortType order)2682 gtk_tree_view_column_set_sort_order      (GtkTreeViewColumn     *tree_column,
2683                                           GtkSortType            order)
2684 {
2685   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2686 
2687   if (order == tree_column->priv->sort_order)
2688     return;
2689 
2690   tree_column->priv->sort_order = order;
2691   gtk_tree_view_column_update_button (tree_column);
2692   g_object_notify_by_pspec (G_OBJECT (tree_column), tree_column_props[PROP_SORT_ORDER]);
2693 }
2694 
2695 /**
2696  * gtk_tree_view_column_get_sort_order:
2697  * @tree_column: a `GtkTreeViewColumn`
2698  *
2699  * Gets the value set by gtk_tree_view_column_set_sort_order().
2700  *
2701  * Returns: the sort order the sort indicator is indicating
2702  **/
2703 GtkSortType
gtk_tree_view_column_get_sort_order(GtkTreeViewColumn * tree_column)2704 gtk_tree_view_column_get_sort_order      (GtkTreeViewColumn     *tree_column)
2705 {
2706   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
2707 
2708   return tree_column->priv->sort_order;
2709 }
2710 
2711 /**
2712  * gtk_tree_view_column_cell_set_cell_data:
2713  * @tree_column: A `GtkTreeViewColumn`.
2714  * @tree_model: The `GtkTreeModel` to get the cell renderers attributes from.
2715  * @iter: The `GtkTreeIter` to get the cell renderer’s attributes from.
2716  * @is_expander: %TRUE, if the row has children
2717  * @is_expanded: %TRUE, if the row has visible children
2718  *
2719  * Sets the cell renderer based on the @tree_model and @iter.  That is, for
2720  * every attribute mapping in @tree_column, it will get a value from the set
2721  * column on the @iter, and use that value to set the attribute on the cell
2722  * renderer.  This is used primarily by the `GtkTreeView`.
2723  **/
2724 void
gtk_tree_view_column_cell_set_cell_data(GtkTreeViewColumn * tree_column,GtkTreeModel * tree_model,GtkTreeIter * iter,gboolean is_expander,gboolean is_expanded)2725 gtk_tree_view_column_cell_set_cell_data (GtkTreeViewColumn *tree_column,
2726 					 GtkTreeModel      *tree_model,
2727 					 GtkTreeIter       *iter,
2728 					 gboolean           is_expander,
2729 					 gboolean           is_expanded)
2730 {
2731   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2732 
2733   if (tree_model == NULL)
2734     return;
2735 
2736   gtk_cell_area_apply_attributes (tree_column->priv->cell_area, tree_model, iter,
2737                                   is_expander, is_expanded);
2738 }
2739 
2740 /**
2741  * gtk_tree_view_column_cell_get_size:
2742  * @tree_column: A `GtkTreeViewColumn`.
2743  * @x_offset: (out) (optional): location to return x offset of a cell relative to @cell_area
2744  * @y_offset: (out) (optional): location to return y offset of a cell relative to @cell_area
2745  * @width: (out) (optional): location to return width needed to render a cell
2746  * @height: (out) (optional): location to return height needed to render a cell
2747  *
2748  * Obtains the width and height needed to render the column.  This is used
2749  * primarily by the `GtkTreeView`.
2750  **/
2751 void
gtk_tree_view_column_cell_get_size(GtkTreeViewColumn * tree_column,int * x_offset,int * y_offset,int * width,int * height)2752 gtk_tree_view_column_cell_get_size (GtkTreeViewColumn  *tree_column,
2753                                     int                *x_offset,
2754                                     int                *y_offset,
2755                                     int                *width,
2756                                     int                *height)
2757 {
2758   GtkTreeViewColumnPrivate *priv;
2759   int min_width = 0, min_height = 0;
2760 
2761   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2762 
2763   priv = tree_column->priv;
2764 
2765   g_signal_handler_block (priv->cell_area_context,
2766 			  priv->context_changed_signal);
2767 
2768   gtk_cell_area_get_preferred_width (priv->cell_area,
2769                                      priv->cell_area_context,
2770                                      priv->tree_view,
2771                                      NULL, NULL);
2772 
2773   gtk_cell_area_context_get_preferred_width (priv->cell_area_context, &min_width, NULL);
2774 
2775   gtk_cell_area_get_preferred_height_for_width (priv->cell_area,
2776                                                 priv->cell_area_context,
2777                                                 priv->tree_view,
2778                                                 min_width,
2779                                                 &min_height,
2780                                                 NULL);
2781 
2782   g_signal_handler_unblock (priv->cell_area_context,
2783 			    priv->context_changed_signal);
2784 
2785 
2786   if (height)
2787     * height = min_height;
2788   if (width)
2789     * width = min_width;
2790 
2791 }
2792 
2793 /**
2794  * gtk_tree_view_column_cell_snapshot:
2795  * @tree_column: A `GtkTreeViewColumn`.
2796  * @snapshot: `GtkSnapshot` to draw to
2797  * @background_area: entire cell area (including tree expanders and maybe padding on the sides)
2798  * @cell_area: area normally rendered by a cell renderer
2799  * @flags: flags that affect rendering
2800  *
2801  * Renders the cell contained by #tree_column. This is used primarily by the
2802  * `GtkTreeView`.
2803  **/
2804 void
gtk_tree_view_column_cell_snapshot(GtkTreeViewColumn * tree_column,GtkSnapshot * snapshot,const GdkRectangle * background_area,const GdkRectangle * cell_area,guint flags,gboolean draw_focus)2805 gtk_tree_view_column_cell_snapshot (GtkTreeViewColumn  *tree_column,
2806 				    GtkSnapshot        *snapshot,
2807 				    const GdkRectangle *background_area,
2808 				    const GdkRectangle *cell_area,
2809 				    guint               flags,
2810                                     gboolean            draw_focus)
2811 {
2812   GtkTreeViewColumnPrivate *priv;
2813 
2814   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2815   g_return_if_fail (snapshot != NULL);
2816   g_return_if_fail (background_area != NULL);
2817   g_return_if_fail (cell_area != NULL);
2818 
2819   priv = tree_column->priv;
2820 
2821   gtk_cell_area_snapshot (priv->cell_area, priv->cell_area_context,
2822                           priv->tree_view, snapshot,
2823                           background_area, cell_area, flags,
2824                           draw_focus);
2825 }
2826 
2827 gboolean
_gtk_tree_view_column_cell_event(GtkTreeViewColumn * tree_column,GdkEvent * event,const GdkRectangle * cell_area,guint flags)2828 _gtk_tree_view_column_cell_event (GtkTreeViewColumn  *tree_column,
2829 				  GdkEvent           *event,
2830 				  const GdkRectangle *cell_area,
2831 				  guint               flags)
2832 {
2833   GtkTreeViewColumnPrivate *priv;
2834 
2835   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
2836 
2837   priv = tree_column->priv;
2838 
2839   return gtk_cell_area_event (priv->cell_area,
2840                               priv->cell_area_context,
2841                               priv->tree_view,
2842                               event,
2843                               cell_area,
2844                               flags);
2845 }
2846 
2847 /**
2848  * gtk_tree_view_column_cell_is_visible:
2849  * @tree_column: A `GtkTreeViewColumn`
2850  *
2851  * Returns %TRUE if any of the cells packed into the @tree_column are visible.
2852  * For this to be meaningful, you must first initialize the cells with
2853  * gtk_tree_view_column_cell_set_cell_data()
2854  *
2855  * Returns: %TRUE, if any of the cells packed into the @tree_column are currently visible
2856  **/
2857 gboolean
gtk_tree_view_column_cell_is_visible(GtkTreeViewColumn * tree_column)2858 gtk_tree_view_column_cell_is_visible (GtkTreeViewColumn *tree_column)
2859 {
2860   GList *list;
2861   GList *cells;
2862   GtkTreeViewColumnPrivate *priv;
2863 
2864   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
2865 
2866   priv = tree_column->priv;
2867 
2868   cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (priv->cell_area));
2869   for (list = cells; list; list = list->next)
2870     {
2871       if (gtk_cell_renderer_get_visible (list->data))
2872         {
2873           g_list_free (cells);
2874           return TRUE;
2875         }
2876     }
2877 
2878   g_list_free (cells);
2879 
2880   return FALSE;
2881 }
2882 
2883 /**
2884  * gtk_tree_view_column_focus_cell:
2885  * @tree_column: A `GtkTreeViewColumn`
2886  * @cell: A `GtkCellRenderer`
2887  *
2888  * Sets the current keyboard focus to be at @cell, if the column contains
2889  * 2 or more editable and activatable cells.
2890  **/
2891 void
gtk_tree_view_column_focus_cell(GtkTreeViewColumn * tree_column,GtkCellRenderer * cell)2892 gtk_tree_view_column_focus_cell (GtkTreeViewColumn *tree_column,
2893 				 GtkCellRenderer   *cell)
2894 {
2895   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2896   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
2897 
2898   gtk_cell_area_set_focus_cell (tree_column->priv->cell_area, cell);
2899 }
2900 
2901 void
_gtk_tree_view_column_cell_set_dirty(GtkTreeViewColumn * tree_column,gboolean install_handler)2902 _gtk_tree_view_column_cell_set_dirty (GtkTreeViewColumn *tree_column,
2903 				      gboolean           install_handler)
2904 {
2905   GtkTreeViewColumnPrivate *priv = tree_column->priv;
2906 
2907   priv->dirty = TRUE;
2908   priv->padding = 0;
2909   priv->width = 0;
2910 
2911   /* Issue a manual reset on the context to have all
2912    * sizes re-requested for the context.
2913    */
2914   g_signal_handler_block (priv->cell_area_context,
2915 			  priv->context_changed_signal);
2916   gtk_cell_area_context_reset (priv->cell_area_context);
2917   g_signal_handler_unblock (priv->cell_area_context,
2918 			    priv->context_changed_signal);
2919 
2920   if (priv->tree_view &&
2921       gtk_widget_get_realized (priv->tree_view))
2922     {
2923       _gtk_tree_view_install_mark_rows_col_dirty (GTK_TREE_VIEW (priv->tree_view), install_handler);
2924       gtk_widget_queue_resize (priv->tree_view);
2925     }
2926 }
2927 
2928 gboolean
_gtk_tree_view_column_cell_get_dirty(GtkTreeViewColumn * tree_column)2929 _gtk_tree_view_column_cell_get_dirty (GtkTreeViewColumn  *tree_column)
2930 {
2931   return tree_column->priv->dirty;
2932 }
2933 
2934 /**
2935  * gtk_tree_view_column_cell_get_position:
2936  * @tree_column: a `GtkTreeViewColumn`
2937  * @cell_renderer: a `GtkCellRenderer`
2938  * @x_offset: (out) (optional): return location for the horizontal
2939  *   position of @cell within @tree_column
2940  * @width: (out) (optional): return location for the width of @cell
2941  *
2942  * Obtains the horizontal position and size of a cell in a column.
2943  *
2944  * If the  cell is not found in the column, @start_pos and @width
2945  * are not changed and %FALSE is returned.
2946  *
2947  * Returns: %TRUE if @cell belongs to @tree_column
2948  */
2949 gboolean
gtk_tree_view_column_cell_get_position(GtkTreeViewColumn * tree_column,GtkCellRenderer * cell_renderer,int * x_offset,int * width)2950 gtk_tree_view_column_cell_get_position (GtkTreeViewColumn *tree_column,
2951 					GtkCellRenderer   *cell_renderer,
2952 					int               *x_offset,
2953 					int               *width)
2954 {
2955   GtkTreeViewColumnPrivate *priv;
2956   GdkRectangle cell_area;
2957   GdkRectangle allocation;
2958 
2959   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
2960   g_return_val_if_fail (GTK_IS_CELL_RENDERER (cell_renderer), FALSE);
2961 
2962   priv = tree_column->priv;
2963 
2964   if (! gtk_cell_area_has_renderer (priv->cell_area, cell_renderer))
2965     return FALSE;
2966 
2967   gtk_tree_view_get_background_area (GTK_TREE_VIEW (priv->tree_view),
2968                                      NULL, tree_column, &cell_area);
2969 
2970   gtk_cell_area_get_cell_allocation (priv->cell_area,
2971                                      priv->cell_area_context,
2972                                      priv->tree_view,
2973                                      cell_renderer,
2974                                      &cell_area,
2975                                      &allocation);
2976 
2977   if (x_offset)
2978     *x_offset = allocation.x - cell_area.x;
2979 
2980   if (width)
2981     *width = allocation.width;
2982 
2983   return TRUE;
2984 }
2985 
2986 /**
2987  * gtk_tree_view_column_queue_resize:
2988  * @tree_column: A `GtkTreeViewColumn`
2989  *
2990  * Flags the column, and the cell renderers added to this column, to have
2991  * their sizes renegotiated.
2992  **/
2993 void
gtk_tree_view_column_queue_resize(GtkTreeViewColumn * tree_column)2994 gtk_tree_view_column_queue_resize (GtkTreeViewColumn *tree_column)
2995 {
2996   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2997 
2998   if (tree_column->priv->tree_view)
2999     _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
3000 }
3001 
3002 /**
3003  * gtk_tree_view_column_get_tree_view:
3004  * @tree_column: A `GtkTreeViewColumn`
3005  *
3006  * Returns the `GtkTreeView` wherein @tree_column has been inserted.
3007  * If @column is currently not inserted in any tree view, %NULL is
3008  * returned.
3009  *
3010  * Returns: (nullable) (transfer none): The tree view wherein @column
3011  *   has been inserted
3012  */
3013 GtkWidget *
gtk_tree_view_column_get_tree_view(GtkTreeViewColumn * tree_column)3014 gtk_tree_view_column_get_tree_view (GtkTreeViewColumn *tree_column)
3015 {
3016   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), NULL);
3017 
3018   return tree_column->priv->tree_view;
3019 }
3020 
3021 /**
3022  * gtk_tree_view_column_get_button:
3023  * @tree_column: A `GtkTreeViewColumn`
3024  *
3025  * Returns the button used in the treeview column header
3026  *
3027  * Returns: (transfer none): The button for the column header.
3028  */
3029 GtkWidget *
gtk_tree_view_column_get_button(GtkTreeViewColumn * tree_column)3030 gtk_tree_view_column_get_button (GtkTreeViewColumn *tree_column)
3031 {
3032   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), NULL);
3033 
3034   return tree_column->priv->button;
3035 }
3036 
3037 void
_gtk_tree_view_column_push_padding(GtkTreeViewColumn * column,int padding)3038 _gtk_tree_view_column_push_padding (GtkTreeViewColumn  *column,
3039 				    int                 padding)
3040 {
3041   column->priv->padding = MAX (column->priv->padding, padding);
3042 }
3043 
3044 int
_gtk_tree_view_column_get_requested_width(GtkTreeViewColumn * column)3045 _gtk_tree_view_column_get_requested_width (GtkTreeViewColumn  *column)
3046 {
3047   int requested_width;
3048 
3049   gtk_cell_area_context_get_preferred_width (column->priv->cell_area_context, &requested_width, NULL);
3050 
3051   return requested_width + column->priv->padding;
3052 }
3053 
3054 int
_gtk_tree_view_column_get_drag_x(GtkTreeViewColumn * column)3055 _gtk_tree_view_column_get_drag_x (GtkTreeViewColumn  *column)
3056 {
3057   return column->priv->drag_x;
3058 }
3059 
3060 GtkCellAreaContext *
_gtk_tree_view_column_get_context(GtkTreeViewColumn * column)3061 _gtk_tree_view_column_get_context (GtkTreeViewColumn  *column)
3062 {
3063   return column->priv->cell_area_context;
3064 }
3065 
3066 gboolean
_gtk_tree_view_column_coords_in_resize_rect(GtkTreeViewColumn * column,double x,double y)3067 _gtk_tree_view_column_coords_in_resize_rect (GtkTreeViewColumn *column,
3068                                              double             x,
3069                                              double             y)
3070 {
3071   GtkTreeViewColumnPrivate *priv = column->priv;
3072   graphene_rect_t button_bounds;
3073 
3074   /* x and y are in treeview coordinates. */
3075 
3076   if (!gtk_widget_get_realized (priv->button) ||
3077       !priv->resizable ||
3078       !priv->visible)
3079     return FALSE;
3080 
3081   if (!gtk_widget_compute_bounds (priv->button, priv->tree_view, &button_bounds))
3082     return FALSE;
3083 
3084   if (gtk_widget_get_direction (priv->tree_view) == GTK_TEXT_DIR_LTR)
3085     button_bounds.origin.x += button_bounds.size.width - TREE_VIEW_DRAG_WIDTH;
3086 
3087   button_bounds.size.width = TREE_VIEW_DRAG_WIDTH;
3088 
3089   return graphene_rect_contains_point (&button_bounds,
3090                                        &(graphene_point_t){x, y});
3091 }
3092