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 [class@Gtk.TreeView] 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](section-tree-widget.html)
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 [class@Gtk.TreeView] documentation for specifics
58 * about the CSS node structure for treeviews and their headers.
59 */
60
61
62/* Type methods */
63static void gtk_tree_view_column_cell_layout_init (GtkCellLayoutIface *iface);
64
65/* GObject methods */
66static void gtk_tree_view_column_set_property (GObject *object,
67 guint prop_id,
68 const GValue *value,
69 GParamSpec *pspec);
70static void gtk_tree_view_column_get_property (GObject *object,
71 guint prop_id,
72 GValue *value,
73 GParamSpec *pspec);
74static void gtk_tree_view_column_finalize (GObject *object);
75static void gtk_tree_view_column_dispose (GObject *object);
76static void gtk_tree_view_column_constructed (GObject *object);
77
78/* GtkCellLayout implementation */
79static void gtk_tree_view_column_ensure_cell_area (GtkTreeViewColumn *column,
80 GtkCellArea *cell_area);
81
82static GtkCellArea *gtk_tree_view_column_cell_layout_get_area (GtkCellLayout *cell_layout);
83
84/* Button handling code */
85static void gtk_tree_view_column_create_button (GtkTreeViewColumn *tree_column);
86static void gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column);
87
88/* Button signal handlers */
89static void column_button_drag_begin (GtkGestureDrag *gesture,
90 double x,
91 double y,
92 GtkTreeViewColumn *column);
93static void column_button_drag_update (GtkGestureDrag *gesture,
94 double offset_x,
95 double offset_y,
96 GtkTreeViewColumn *column);
97
98static void gtk_tree_view_column_button_clicked (GtkWidget *widget,
99 gpointer data);
100static gboolean gtk_tree_view_column_mnemonic_activate (GtkWidget *widget,
101 gboolean group_cycling,
102 gpointer data);
103
104/* Property handlers */
105static void gtk_tree_view_model_sort_column_changed (GtkTreeSortable *sortable,
106 GtkTreeViewColumn *tree_column);
107
108/* GtkCellArea/GtkCellAreaContext callbacks */
109static void gtk_tree_view_column_context_changed (GtkCellAreaContext *context,
110 GParamSpec *pspec,
111 GtkTreeViewColumn *tree_column);
112static 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);
118static 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 */
124static void gtk_tree_view_column_sort (GtkTreeViewColumn *tree_column,
125 gpointer data);
126static void gtk_tree_view_column_setup_sort_column_id_callback (GtkTreeViewColumn *tree_column);
127static void gtk_tree_view_column_set_attributesv (GtkTreeViewColumn *tree_column,
128 GtkCellRenderer *cell_renderer,
129 va_list args);
130
131/* GtkBuildable implementation */
132static void gtk_tree_view_column_buildable_init (GtkBuildableIface *iface);
133
134typedef struct _GtkTreeViewColumnClass GtkTreeViewColumnClass;
135typedef struct _GtkTreeViewColumnPrivate GtkTreeViewColumnPrivate;
136
137struct _GtkTreeViewColumn
138{
139 GInitiallyUnowned parent_instance;
140
141 GtkTreeViewColumnPrivate *priv;
142};
143
144struct _GtkTreeViewColumnClass
145{
146 GInitiallyUnownedClass parent_class;
147
148 void (*clicked) (GtkTreeViewColumn *tree_column);
149};
150
151
152struct _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
202enum
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
227enum
228{
229 CLICKED,
230 LAST_SIGNAL
231};
232
233static guint tree_column_signals[LAST_SIGNAL] = { 0 };
234static GParamSpec *tree_column_props[LAST_PROP] = { NULL, };
235
236G_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
244static void
245gtk_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 signal_flags: G_SIGNAL_RUN_LAST,
269 G_STRUCT_OFFSET (GtkTreeViewColumnClass, clicked),
270 NULL, NULL,
271 NULL,
272 G_TYPE_NONE, n_params: 0);
273
274 tree_column_props[PROP_VISIBLE] =
275 g_param_spec_boolean (name: "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 (name: "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 (name: "x-offset",
290 P_("X position"),
291 P_("Current X position of the column"),
292 minimum: -G_MAXINT, G_MAXINT,
293 default_value: 0,
294 GTK_PARAM_READABLE);
295
296 tree_column_props[PROP_WIDTH] =
297 g_param_spec_int (name: "width",
298 P_("Width"),
299 P_("Current width of the column"),
300 minimum: 0, G_MAXINT,
301 default_value: 0,
302 GTK_PARAM_READABLE);
303
304 tree_column_props[PROP_SPACING] =
305 g_param_spec_int (name: "spacing",
306 P_("Spacing"),
307 P_("Space which is inserted between cells"),
308 minimum: 0, G_MAXINT,
309 default_value: 0,
310 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
311
312 tree_column_props[PROP_SIZING] =
313 g_param_spec_enum (name: "sizing",
314 P_("Sizing"),
315 P_("Resize mode of the column"),
316 enum_type: GTK_TYPE_TREE_VIEW_COLUMN_SIZING,
317 default_value: 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 (name: "fixed-width",
322 P_("Fixed Width"),
323 P_("Current fixed width of the column"),
324 minimum: -1, G_MAXINT,
325 default_value: -1,
326 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
327
328 tree_column_props[PROP_MIN_WIDTH] =
329 g_param_spec_int (name: "min-width",
330 P_("Minimum Width"),
331 P_("Minimum allowed width of the column"),
332 minimum: -1, G_MAXINT,
333 default_value: -1,
334 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
335
336 tree_column_props[PROP_MAX_WIDTH] =
337 g_param_spec_int (name: "max-width",
338 P_("Maximum Width"),
339 P_("Maximum allowed width of the column"),
340 minimum: -1, G_MAXINT,
341 default_value: -1,
342 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
343
344 tree_column_props[PROP_TITLE] =
345 g_param_spec_string (name: "title",
346 P_("Title"),
347 P_("Title to appear in column header"),
348 default_value: "",
349 GTK_PARAM_READWRITE);
350
351 tree_column_props[PROP_EXPAND] =
352 g_param_spec_boolean (name: "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 (name: "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 (name: "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 (name: "alignment",
374 P_("Alignment"),
375 P_("X Alignment of the column header text or widget"),
376 minimum: 0.0, maximum: 1.0, default_value: 0.0,
377 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
378
379 tree_column_props[PROP_REORDERABLE] =
380 g_param_spec_boolean (name: "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 (name: "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 (name: "sort-order",
395 P_("Sort order"),
396 P_("Sort direction the sort indicator should indicate"),
397 enum_type: GTK_TYPE_SORT_TYPE,
398 default_value: 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 (name: "sort-column-id",
409 P_("Sort column ID"),
410 P_("Logical sort column ID this column sorts on when selected for sorting"),
411 minimum: -1, G_MAXINT,
412 default_value: -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 (name: "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 (oclass: object_class, n_pspecs: LAST_PROP, pspecs: tree_column_props);
431}
432
433static void
434gtk_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
444static void
445gtk_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
452static void
453gtk_tree_view_column_cell_layout_init (GtkCellLayoutIface *iface)
454{
455 iface->get_area = gtk_tree_view_column_cell_layout_get_area;
456}
457
458static void
459gtk_tree_view_column_init (GtkTreeViewColumn *tree_column)
460{
461 GtkTreeViewColumnPrivate *priv;
462
463 tree_column->priv = gtk_tree_view_column_get_instance_private (self: 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 (str: "");
488
489 gtk_tree_view_column_create_button (tree_column);
490}
491
492static void
493gtk_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 (column: tree_column, NULL);
500}
501
502static void
503gtk_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), column: tree_column);
513
514 if (priv->cell_area_context)
515 {
516 g_signal_handler_disconnect (instance: priv->cell_area_context,
517 handler_id: priv->context_changed_signal);
518
519 g_object_unref (object: 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 (instance: priv->cell_area,
528 handler_id: priv->add_editable_signal);
529 g_signal_handler_disconnect (instance: priv->cell_area,
530 handler_id: priv->remove_editable_signal);
531
532 g_object_unref (object: 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 (object: 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
549static void
550gtk_tree_view_column_finalize (GObject *object)
551{
552 GtkTreeViewColumn *tree_column = (GtkTreeViewColumn *) object;
553 GtkTreeViewColumnPrivate *priv = tree_column->priv;
554
555 g_free (mem: priv->title);
556
557 G_OBJECT_CLASS (gtk_tree_view_column_parent_class)->finalize (object);
558}
559
560static void
561gtk_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 visible: g_value_get_boolean (value));
576 break;
577
578 case PROP_RESIZABLE:
579 gtk_tree_view_column_set_resizable (tree_column,
580 resizable: g_value_get_boolean (value));
581 break;
582
583 case PROP_SIZING:
584 gtk_tree_view_column_set_sizing (tree_column,
585 type: g_value_get_enum (value));
586 break;
587
588 case PROP_FIXED_WIDTH:
589 gtk_tree_view_column_set_fixed_width (tree_column,
590 fixed_width: g_value_get_int (value));
591 break;
592
593 case PROP_MIN_WIDTH:
594 gtk_tree_view_column_set_min_width (tree_column,
595 min_width: g_value_get_int (value));
596 break;
597
598 case PROP_MAX_WIDTH:
599 gtk_tree_view_column_set_max_width (tree_column,
600 max_width: g_value_get_int (value));
601 break;
602
603 case PROP_SPACING:
604 gtk_tree_view_column_set_spacing (tree_column,
605 spacing: g_value_get_int (value));
606 break;
607
608 case PROP_TITLE:
609 gtk_tree_view_column_set_title (tree_column,
610 title: g_value_get_string (value));
611 break;
612
613 case PROP_EXPAND:
614 gtk_tree_view_column_set_expand (tree_column,
615 expand: g_value_get_boolean (value));
616 break;
617
618 case PROP_CLICKABLE:
619 gtk_tree_view_column_set_clickable (tree_column,
620 clickable: g_value_get_boolean (value));
621 break;
622
623 case PROP_WIDGET:
624 gtk_tree_view_column_set_widget (tree_column,
625 widget: (GtkWidget*) g_value_get_object (value));
626 break;
627
628 case PROP_ALIGNMENT:
629 gtk_tree_view_column_set_alignment (tree_column,
630 xalign: g_value_get_float (value));
631 break;
632
633 case PROP_REORDERABLE:
634 gtk_tree_view_column_set_reorderable (tree_column,
635 reorderable: g_value_get_boolean (value));
636 break;
637
638 case PROP_SORT_INDICATOR:
639 gtk_tree_view_column_set_sort_indicator (tree_column,
640 setting: g_value_get_boolean (value));
641 break;
642
643 case PROP_SORT_ORDER:
644 gtk_tree_view_column_set_sort_order (tree_column,
645 order: 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 sort_column_id: 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 (object: area);
664 }
665 else
666 gtk_tree_view_column_ensure_cell_area (column: tree_column, cell_area: area);
667 }
668 break;
669
670 default:
671 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
672 break;
673 }
674}
675
676static void
677gtk_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 v_boolean: gtk_tree_view_column_get_visible (tree_column));
691 break;
692
693 case PROP_RESIZABLE:
694 g_value_set_boolean (value,
695 v_boolean: gtk_tree_view_column_get_resizable (tree_column));
696 break;
697
698 case PROP_X_OFFSET:
699 g_value_set_int (value,
700 v_int: gtk_tree_view_column_get_x_offset (tree_column));
701 break;
702
703 case PROP_WIDTH:
704 g_value_set_int (value,
705 v_int: gtk_tree_view_column_get_width (tree_column));
706 break;
707
708 case PROP_SPACING:
709 g_value_set_int (value,
710 v_int: gtk_tree_view_column_get_spacing (tree_column));
711 break;
712
713 case PROP_SIZING:
714 g_value_set_enum (value,
715 v_enum: gtk_tree_view_column_get_sizing (tree_column));
716 break;
717
718 case PROP_FIXED_WIDTH:
719 g_value_set_int (value,
720 v_int: gtk_tree_view_column_get_fixed_width (tree_column));
721 break;
722
723 case PROP_MIN_WIDTH:
724 g_value_set_int (value,
725 v_int: gtk_tree_view_column_get_min_width (tree_column));
726 break;
727
728 case PROP_MAX_WIDTH:
729 g_value_set_int (value,
730 v_int: gtk_tree_view_column_get_max_width (tree_column));
731 break;
732
733 case PROP_TITLE:
734 g_value_set_string (value,
735 v_string: gtk_tree_view_column_get_title (tree_column));
736 break;
737
738 case PROP_EXPAND:
739 g_value_set_boolean (value,
740 v_boolean: gtk_tree_view_column_get_expand (tree_column));
741 break;
742
743 case PROP_CLICKABLE:
744 g_value_set_boolean (value,
745 v_boolean: gtk_tree_view_column_get_clickable (tree_column));
746 break;
747
748 case PROP_WIDGET:
749 g_value_set_object (value,
750 v_object: (GObject*) gtk_tree_view_column_get_widget (tree_column));
751 break;
752
753 case PROP_ALIGNMENT:
754 g_value_set_float (value,
755 v_float: gtk_tree_view_column_get_alignment (tree_column));
756 break;
757
758 case PROP_REORDERABLE:
759 g_value_set_boolean (value,
760 v_boolean: gtk_tree_view_column_get_reorderable (tree_column));
761 break;
762
763 case PROP_SORT_INDICATOR:
764 g_value_set_boolean (value,
765 v_boolean: gtk_tree_view_column_get_sort_indicator (tree_column));
766 break;
767
768 case PROP_SORT_ORDER:
769 g_value_set_enum (value,
770 v_enum: 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 v_int: gtk_tree_view_column_get_sort_column_id (tree_column));
776 break;
777
778 case PROP_CELL_AREA:
779 g_value_set_object (value, v_object: 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
791static void
792gtk_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 (area: 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
824static GtkCellArea *
825gtk_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
836static void
837focus_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 */
845static void
846gtk_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 (widget: priv->button, FALSE);
858 gtk_widget_set_overflow (widget: priv->button, overflow: 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, phase: GTK_PHASE_CAPTURE);
870 gtk_widget_add_controller (widget: 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 (widget: priv->button, controller);
875
876 priv->frame = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 0);
877 gtk_widget_set_hexpand (widget: priv->frame, TRUE);
878 gtk_widget_set_halign (widget: priv->frame, align: GTK_ALIGN_START);
879
880 hbox = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 2);
881 priv->arrow = gtk_builtin_icon_new (css_name: "sort-indicator");
882
883 if (priv->child)
884 child = priv->child;
885 else
886 child = gtk_label_new (str: 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), child: priv->frame);
895 gtk_box_append (GTK_BOX (hbox), child: priv->arrow);
896 }
897 else
898 {
899 gtk_box_append (GTK_BOX (hbox), child: priv->arrow);
900 gtk_box_append (GTK_BOX (hbox), child: priv->frame);
901 }
902
903 gtk_box_append (GTK_BOX (priv->frame), child);
904 gtk_button_set_child (GTK_BUTTON (priv->button), child: hbox);
905}
906
907static void
908gtk_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 (widget: 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), child: current_child);
934 gtk_box_append (GTK_BOX (frame), child: priv->child);
935 }
936 }
937 else
938 {
939 if (current_child == NULL)
940 {
941 current_child = gtk_label_new (NULL);
942 gtk_widget_show (widget: current_child);
943 gtk_box_append (GTK_BOX (frame), child: 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 str: priv->title);
951 else
952 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
953 str: "");
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: &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 (object: gtk_widget_get_settings (widget: priv->tree_view),
967 first_property_name: "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 (widget: arrow, css_class: "descending");
976 gtk_widget_add_css_class (widget: arrow, css_class: "ascending");
977 }
978 else
979 {
980 gtk_widget_remove_css_class (widget: arrow, css_class: "ascending");
981 gtk_widget_add_css_class (widget: arrow, css_class: "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), child: arrow, sibling: gtk_widget_get_last_child (widget: hbox));
991 else
992 gtk_box_reorder_child_after (GTK_BOX (hbox), child: arrow, NULL);
993
994 if (priv->show_sort_indicator
995 || (GTK_IS_TREE_SORTABLE (model) && priv->sort_column_id >= 0))
996 gtk_widget_show (widget: arrow);
997 else
998 gtk_widget_hide (widget: arrow);
999
1000 if (priv->show_sort_indicator)
1001 gtk_widget_set_opacity (widget: arrow, opacity: 1.0);
1002 else
1003 gtk_widget_set_opacity (widget: arrow, opacity: 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 (widget: 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 (widget: priv->button);
1014 }
1015 else
1016 {
1017 gtk_widget_hide (widget: priv->button);
1018 }
1019 }
1020
1021 if (priv->reorderable || priv->clickable)
1022 {
1023 gtk_widget_set_focusable (widget: priv->button, TRUE);
1024 }
1025 else
1026 {
1027 gtk_widget_set_focusable (widget: priv->button, FALSE);
1028 if (gtk_widget_has_focus (widget: priv->button))
1029 {
1030 GtkRoot *root = gtk_widget_get_root (widget: priv->tree_view);
1031 gtk_root_set_focus (self: 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 (widget: priv->tree_view))
1038 gtk_widget_queue_resize (widget: priv->tree_view);
1039}
1040
1041/* Button signal handlers
1042 */
1043
1044static void
1045column_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 state: GTK_EVENT_SEQUENCE_DENIED);
1056 return;
1057 }
1058
1059 priv->drag_x = x;
1060 priv->drag_y = y;
1061 gtk_widget_grab_focus (widget: priv->button);
1062}
1063
1064static void
1065column_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 (widget: priv->button, start_x: 0, start_y: 0, current_x: offset_x, current_y: offset_y))
1073 {
1074 gtk_gesture_set_state (GTK_GESTURE (gesture), state: GTK_EVENT_SEQUENCE_CLAIMED);
1075 _gtk_tree_view_column_start_drag (GTK_TREE_VIEW (priv->tree_view), column,
1076 device: gtk_gesture_get_device (GTK_GESTURE (gesture)));
1077 }
1078}
1079
1080static void
1081gtk_tree_view_column_button_clicked (GtkWidget *widget, gpointer data)
1082{
1083 g_signal_emit_by_name (instance: data, detailed_signal: "clicked");
1084}
1085
1086static gboolean
1087gtk_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 (instance: priv->button, detailed_signal: "clicked");
1100 else if (gtk_widget_get_focusable (widget: priv->button))
1101 gtk_widget_grab_focus (widget: priv->button);
1102 else
1103 gtk_widget_grab_focus (widget: priv->tree_view);
1104
1105 return TRUE;
1106}
1107
1108static void
1109gtk_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: &sort_column_id,
1118 order: &order))
1119 {
1120 if (sort_column_id == priv->sort_column_id)
1121 {
1122 gtk_tree_view_column_set_sort_indicator (tree_column: column, TRUE);
1123 gtk_tree_view_column_set_sort_order (tree_column: column, order);
1124 }
1125 else
1126 {
1127 gtk_tree_view_column_set_sort_indicator (tree_column: column, FALSE);
1128 }
1129 }
1130 else
1131 {
1132 gtk_tree_view_column_set_sort_indicator (tree_column: column, FALSE);
1133 }
1134}
1135
1136static void
1137gtk_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: &sort_column_id,
1156 order: &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 sort_column_id: priv->sort_column_id,
1166 order: 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 order: GTK_SORT_ASCENDING);
1171 else
1172 gtk_tree_sortable_set_sort_column_id (sortable,
1173 sort_column_id: priv->sort_column_id,
1174 order: GTK_SORT_ASCENDING);
1175 }
1176 else
1177 {
1178 gtk_tree_sortable_set_sort_column_id (sortable,
1179 sort_column_id: priv->sort_column_id,
1180 order: GTK_SORT_ASCENDING);
1181 }
1182}
1183
1184static void
1185gtk_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 sort_column_id: &real_sort_column_id,
1212 order: &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, order: real_order);
1217 }
1218 else
1219 {
1220 gtk_tree_view_column_set_sort_indicator (tree_column, FALSE);
1221 }
1222 }
1223}
1224
1225static void
1226gtk_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 (s1: pspec->name, s2: "minimum-width") ||
1241 !strcmp (s1: pspec->name, s2: "natural-width") ||
1242 !strcmp (s1: pspec->name, s2: "minimum-height") ||
1243 !strcmp (s1: pspec->name, s2: "natural-height"))
1244 _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
1245}
1246
1247static void
1248gtk_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: path_string);
1262
1263 _gtk_tree_view_add_editable (GTK_TREE_VIEW (priv->tree_view),
1264 column,
1265 path,
1266 cell_editable: edit_widget,
1267 cell_area);
1268
1269 gtk_tree_path_free (path);
1270 }
1271}
1272
1273static void
1274gtk_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 cell_editable: edit_widget);
1286}
1287
1288/* Exported Private Functions.
1289 * These should only be called by gtktreeview.c or gtktreeviewcolumn.c
1290 */
1291void
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 (tree_column: column);
1299}
1300
1301void
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 (instance: old_model,
1310 handler_id: priv->sort_column_changed_signal);
1311 priv->sort_column_changed_signal = 0;
1312 }
1313 gtk_tree_view_column_set_sort_indicator (tree_column: column, FALSE);
1314}
1315
1316void
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 (widget: 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 (tree_column: column);
1336}
1337
1338void
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 (widget: priv->button);
1347
1348 if (priv->property_changed_signal)
1349 {
1350 g_signal_handler_disconnect (instance: priv->tree_view, handler_id: 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 (instance: gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree_view)),
1357 handler_id: priv->sort_column_changed_signal);
1358 priv->sort_column_changed_signal = 0;
1359 }
1360
1361 priv->tree_view = NULL;
1362}
1363
1364gboolean
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 (object: cell, first_property_name: "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 (list: cells);
1388
1389 return ret;
1390}
1391
1392/* gets cell being edited */
1393GtkCellRenderer *
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 (area: priv->cell_area);
1399}
1400
1401GtkCellRenderer *
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 (area: priv->cell_area,
1437 context: priv->cell_area_context,
1438 widget: priv->tree_view,
1439 cell_area,
1440 x, y,
1441 NULL);
1442
1443 return match;
1444}
1445
1446gboolean
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 (area: priv->cell_area,
1465 context: priv->cell_area_context,
1466 widget: priv->tree_view,
1467 renderer: match,
1468 cell_area,
1469 allocation: &cell_alloc);
1470
1471 gtk_cell_area_inner_cell_area (area: priv->cell_area, widget: priv->tree_view,
1472 cell_area: &cell_alloc, inner_area: &inner_area);
1473 gtk_cell_renderer_get_aligned_area (cell: match, widget: priv->tree_view, flags: 0,
1474 cell_area: &inner_area, aligned_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 **/
1495GtkTreeViewColumn *
1496gtk_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 */
1513GtkTreeViewColumn *
1514gtk_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, first_property_name: "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 **/
1553GtkTreeViewColumn *
1554gtk_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 (tree_column: retval, title);
1564 gtk_tree_view_column_pack_start (tree_column: retval, cell, TRUE);
1565
1566 va_start (args, cell);
1567 gtk_tree_view_column_set_attributesv (tree_column: retval, cell_renderer: 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 **/
1583void
1584gtk_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 **/
1601void
1602gtk_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 **/
1615void
1616gtk_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 **/
1637void
1638gtk_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: cell_renderer, attribute, column);
1645}
1646
1647static void
1648gtk_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: 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: 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 */
1682void
1683gtk_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 **/
1714void
1715gtk_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: cell_renderer,
1723 func: (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 **/
1736void
1737gtk_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: 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 **/
1752void
1753gtk_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), pspec: 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 **/
1780int
1781gtk_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 */
1801void
1802gtk_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 (widget: 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), pspec: 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 **/
1835gboolean
1836gtk_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 **/
1855void
1856gtk_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, type: 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), pspec: 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 **/
1887gboolean
1888gtk_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 **/
1903void
1904gtk_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), pspec: 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 **/
1934GtkTreeViewColumnSizing
1935gtk_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 **/
1950int
1951gtk_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 */
1966int
1967gtk_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
1974int
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 (context: priv->cell_area_context, minimum_width: &requested_width, NULL);
1992 requested_width += priv->padding;
1993
1994 gtk_widget_measure (widget: priv->button, orientation: GTK_ORIENTATION_HORIZONTAL, for_size: -1,
1995 minimum: &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 (context: priv->cell_area_context, minimum_width: &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
2019void
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 (widget: priv->tree_view);
2034
2035 priv->x_offset = x_offset;
2036 priv->width = width;
2037
2038 gtk_cell_area_context_allocate (context: priv->cell_area_context, width: priv->width - priv->padding, height: -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 (widget: priv->button, allocation: &allocation, baseline: -1);
2051 }
2052
2053 g_object_notify_by_pspec (G_OBJECT (tree_column), pspec: tree_column_props[PROP_X_OFFSET]);
2054 g_object_notify_by_pspec (G_OBJECT (tree_column), pspec: 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 **/
2074void
2075gtk_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 (widget: priv->tree_view))
2091 gtk_widget_queue_resize (widget: priv->tree_view);
2092
2093 g_object_notify_by_pspec (G_OBJECT (tree_column), pspec: 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 **/
2106int
2107gtk_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 **/
2122void
2123gtk_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 (widget: priv->tree_view))
2139 {
2140 if (min_width > priv->width)
2141 gtk_widget_queue_resize (widget: 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), pspec: tree_column_props[PROP_MAX_WIDTH]);
2150 }
2151 g_object_notify_by_pspec (G_OBJECT (tree_column), pspec: 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 column: 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 **/
2168int
2169gtk_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 **/
2186void
2187gtk_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 (widget: priv->tree_view))
2203 {
2204 if (max_width != -1 && max_width < priv->width)
2205 gtk_widget_queue_resize (widget: 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), pspec: tree_column_props[PROP_MIN_WIDTH]);
2214 }
2215 g_object_notify_by_pspec (G_OBJECT (tree_column), pspec: 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 column: 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 **/
2232int
2233gtk_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 **/
2247void
2248gtk_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 (instance: priv->button, detailed_signal: "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 **/
2268void
2269gtk_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 (str: title);
2280 g_free (mem: 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), pspec: 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 **/
2296const char *
2297gtk_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 **/
2317void
2318gtk_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 (widget: priv->tree_view))
2335 {
2336 gtk_widget_queue_resize (widget: priv->tree_view);
2337 }
2338
2339 g_object_notify_by_pspec (G_OBJECT (tree_column), pspec: 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 **/
2350gboolean
2351gtk_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 **/
2366void
2367gtk_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), pspec: 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 **/
2393gboolean
2394gtk_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 **/
2409void
2410gtk_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 (object: 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), pspec: 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 */
2441GtkWidget *
2442gtk_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 **/
2458void
2459gtk_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), pspec: 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 **/
2487float
2488gtk_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 **/
2503void
2504gtk_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), pspec: 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 **/
2532gboolean
2533gtk_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 **/
2549void
2550gtk_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 (instance: tree_column, handler_id: 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 (instance: model, handler_id: priv->sort_column_changed_signal);
2579 priv->sort_column_changed_signal = 0;
2580 }
2581
2582 gtk_tree_view_column_set_sort_order (tree_column, order: 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), pspec: 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), pspec: 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 */
2613int
2614gtk_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 **/
2632void
2633gtk_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), pspec: 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 **/
2656gboolean
2657gtk_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 **/
2681void
2682gtk_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), pspec: 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 **/
2703GtkSortType
2704gtk_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 **/
2724void
2725gtk_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 (area: 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 **/
2751void
2752gtk_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 (instance: priv->cell_area_context,
2766 handler_id: priv->context_changed_signal);
2767
2768 gtk_cell_area_get_preferred_width (area: priv->cell_area,
2769 context: priv->cell_area_context,
2770 widget: priv->tree_view,
2771 NULL, NULL);
2772
2773 gtk_cell_area_context_get_preferred_width (context: priv->cell_area_context, minimum_width: &min_width, NULL);
2774
2775 gtk_cell_area_get_preferred_height_for_width (area: priv->cell_area,
2776 context: priv->cell_area_context,
2777 widget: priv->tree_view,
2778 width: min_width,
2779 minimum_height: &min_height,
2780 NULL);
2781
2782 g_signal_handler_unblock (instance: priv->cell_area_context,
2783 handler_id: 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 **/
2804void
2805gtk_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 (area: priv->cell_area, context: priv->cell_area_context,
2822 widget: priv->tree_view, snapshot,
2823 background_area, cell_area, flags,
2824 paint_focus: draw_focus);
2825}
2826
2827gboolean
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 (area: priv->cell_area,
2840 context: priv->cell_area_context,
2841 widget: 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 **/
2857gboolean
2858gtk_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 (cell: list->data))
2872 {
2873 g_list_free (list: cells);
2874 return TRUE;
2875 }
2876 }
2877
2878 g_list_free (list: 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 **/
2891void
2892gtk_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 (area: tree_column->priv->cell_area, renderer: cell);
2899}
2900
2901void
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 (instance: priv->cell_area_context,
2915 handler_id: priv->context_changed_signal);
2916 gtk_cell_area_context_reset (context: priv->cell_area_context);
2917 g_signal_handler_unblock (instance: priv->cell_area_context,
2918 handler_id: priv->context_changed_signal);
2919
2920 if (priv->tree_view &&
2921 gtk_widget_get_realized (widget: 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 (widget: priv->tree_view);
2925 }
2926}
2927
2928gboolean
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 */
2949gboolean
2950gtk_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 (area: priv->cell_area, renderer: cell_renderer))
2965 return FALSE;
2966
2967 gtk_tree_view_get_background_area (GTK_TREE_VIEW (priv->tree_view),
2968 NULL, column: tree_column, rect: &cell_area);
2969
2970 gtk_cell_area_get_cell_allocation (area: priv->cell_area,
2971 context: priv->cell_area_context,
2972 widget: priv->tree_view,
2973 renderer: cell_renderer,
2974 cell_area: &cell_area,
2975 allocation: &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 **/
2993void
2994gtk_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 */
3013GtkWidget *
3014gtk_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 */
3029GtkWidget *
3030gtk_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
3037void
3038_gtk_tree_view_column_push_padding (GtkTreeViewColumn *column,
3039 int padding)
3040{
3041 column->priv->padding = MAX (column->priv->padding, padding);
3042}
3043
3044int
3045_gtk_tree_view_column_get_requested_width (GtkTreeViewColumn *column)
3046{
3047 int requested_width;
3048
3049 gtk_cell_area_context_get_preferred_width (context: column->priv->cell_area_context, minimum_width: &requested_width, NULL);
3050
3051 return requested_width + column->priv->padding;
3052}
3053
3054int
3055_gtk_tree_view_column_get_drag_x (GtkTreeViewColumn *column)
3056{
3057 return column->priv->drag_x;
3058}
3059
3060GtkCellAreaContext *
3061_gtk_tree_view_column_get_context (GtkTreeViewColumn *column)
3062{
3063 return column->priv->cell_area_context;
3064}
3065
3066gboolean
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 (widget: priv->button) ||
3077 !priv->resizable ||
3078 !priv->visible)
3079 return FALSE;
3080
3081 if (!gtk_widget_compute_bounds (widget: priv->button, target: priv->tree_view, out_bounds: &button_bounds))
3082 return FALSE;
3083
3084 if (gtk_widget_get_direction (widget: 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 (r: &button_bounds,
3090 p: &(graphene_point_t){x, y});
3091}
3092

source code of gtk/gtk/gtktreeviewcolumn.c