3 * Copyright (C) 2010 Openismus GmbH
6 * Tristan Van Berkom <tristanvb@openismus.com>
8 * Based on some GtkComboBox menu code by Kristian Rietveld <kris@gtk.org>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
26 * @Short_Description: A GtkMenu automatically created from a #GtkTreeModel
29 * The #GtkTreeMenu is used to display a drop-down menu allowing selection
30 * of every row in the model and is used by the #GtkComboBox for its drop-down
36 #include "gtktreemenu.h"
37 #include "gtkmarshalers.h"
38 #include "gtkmenuitem.h"
39 #include "gtkseparatormenuitem.h"
40 #include "gtkcellareabox.h"
41 #include "gtkcellareacontext.h"
42 #include "gtkcelllayout.h"
43 #include "gtkcellview.h"
44 #include "gtkmenushellprivate.h"
45 #include "gtkprivate.h"
48 #undef GDK_DEPRECATED_FOR
49 #define GDK_DEPRECATED
50 #define GDK_DEPRECATED_FOR(f)
52 #include "deprecated/gtktearoffmenuitem.h"
55 static GObject *gtk_tree_menu_constructor (GType type,
56 guint n_construct_properties,
57 GObjectConstructParam *construct_properties);
58 static void gtk_tree_menu_dispose (GObject *object);
59 static void gtk_tree_menu_finalize (GObject *object);
60 static void gtk_tree_menu_set_property (GObject *object,
64 static void gtk_tree_menu_get_property (GObject *object,
70 static void gtk_tree_menu_get_preferred_width (GtkWidget *widget,
73 static void gtk_tree_menu_get_preferred_height (GtkWidget *widget,
77 /* GtkCellLayoutIface */
78 static void gtk_tree_menu_cell_layout_init (GtkCellLayoutIface *iface);
79 static GtkCellArea *gtk_tree_menu_cell_layout_get_area (GtkCellLayout *layout);
82 /* TreeModel/DrawingArea callbacks and building menus/submenus */
83 static inline void rebuild_menu (GtkTreeMenu *menu);
84 static gboolean menu_occupied (GtkTreeMenu *menu,
89 static void relayout_item (GtkTreeMenu *menu,
93 static void gtk_tree_menu_populate (GtkTreeMenu *menu);
94 static GtkWidget *gtk_tree_menu_create_item (GtkTreeMenu *menu,
96 gboolean header_item);
97 static void gtk_tree_menu_create_submenu (GtkTreeMenu *menu,
100 static void gtk_tree_menu_set_area (GtkTreeMenu *menu,
102 static GtkWidget *gtk_tree_menu_get_path_item (GtkTreeMenu *menu,
104 static gboolean gtk_tree_menu_path_in_menu (GtkTreeMenu *menu,
106 gboolean *header_item);
107 static void row_inserted_cb (GtkTreeModel *model,
111 static void row_deleted_cb (GtkTreeModel *model,
114 static void row_reordered_cb (GtkTreeModel *model,
119 static void row_changed_cb (GtkTreeModel *model,
123 static void context_size_changed_cb (GtkCellAreaContext *context,
126 static void area_apply_attributes_cb (GtkCellArea *area,
127 GtkTreeModel *tree_model,
129 gboolean is_expander,
130 gboolean is_expanded,
132 static void item_activated_cb (GtkMenuItem *item,
134 static void submenu_activated_cb (GtkTreeMenu *submenu,
137 static void gtk_tree_menu_set_model_internal (GtkTreeMenu *menu,
138 GtkTreeModel *model);
142 struct _GtkTreeMenuPrivate
144 /* TreeModel and parent for this menu */
146 GtkTreeRowReference *root;
148 /* CellArea and context for this menu */
150 GtkCellAreaContext *context;
153 gulong size_changed_id;
154 gulong apply_attributes_id;
155 gulong row_inserted_id;
156 gulong row_deleted_id;
157 gulong row_reordered_id;
158 gulong row_changed_id;
166 guint32 menu_with_header : 1;
170 GtkTreeViewRowSeparatorFunc row_separator_func;
171 gpointer row_separator_data;
172 GDestroyNotify row_separator_destroy;
174 /* Submenu headers */
175 GtkTreeMenuHeaderFunc header_func;
176 gpointer header_data;
177 GDestroyNotify header_destroy;
192 SIGNAL_MENU_ACTIVATE,
196 static guint tree_menu_signals[N_SIGNALS] = { 0 };
197 static GQuark tree_menu_path_quark = 0;
199 G_DEFINE_TYPE_WITH_CODE (GtkTreeMenu, _gtk_tree_menu, GTK_TYPE_MENU,
200 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
201 gtk_tree_menu_cell_layout_init));
204 _gtk_tree_menu_init (GtkTreeMenu *menu)
206 GtkTreeMenuPrivate *priv;
208 menu->priv = G_TYPE_INSTANCE_GET_PRIVATE (menu,
216 priv->context = NULL;
218 priv->size_changed_id = 0;
219 priv->row_inserted_id = 0;
220 priv->row_deleted_id = 0;
221 priv->row_reordered_id = 0;
222 priv->row_changed_id = 0;
224 priv->wrap_width = 0;
225 priv->row_span_col = -1;
226 priv->col_span_col = -1;
228 priv->menu_with_header = FALSE;
229 priv->tearoff = FALSE;
231 priv->row_separator_func = NULL;
232 priv->row_separator_data = NULL;
233 priv->row_separator_destroy = NULL;
235 priv->header_func = NULL;
236 priv->header_data = NULL;
237 priv->header_destroy = NULL;
239 gtk_menu_set_reserve_toggle_size (GTK_MENU (menu), FALSE);
243 _gtk_tree_menu_class_init (GtkTreeMenuClass *class)
245 GObjectClass *object_class = G_OBJECT_CLASS (class);
246 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
248 tree_menu_path_quark = g_quark_from_static_string ("gtk-tree-menu-path");
250 object_class->constructor = gtk_tree_menu_constructor;
251 object_class->dispose = gtk_tree_menu_dispose;
252 object_class->finalize = gtk_tree_menu_finalize;
253 object_class->set_property = gtk_tree_menu_set_property;
254 object_class->get_property = gtk_tree_menu_get_property;
256 widget_class->get_preferred_width = gtk_tree_menu_get_preferred_width;
257 widget_class->get_preferred_height = gtk_tree_menu_get_preferred_height;
260 * GtkTreeMenu::menu-activate:
261 * @menu: a #GtkTreeMenu
262 * @path: the #GtkTreePath string for the item which was activated
263 * @user_data: the user data
265 * This signal is emitted to notify that a menu item in the #GtkTreeMenu
266 * was activated and provides the path string from the #GtkTreeModel
267 * to specify which row was selected.
271 tree_menu_signals[SIGNAL_MENU_ACTIVATE] =
272 g_signal_new (I_("menu-activate"),
273 G_OBJECT_CLASS_TYPE (object_class),
275 0, /* No class closure here */
277 _gtk_marshal_VOID__STRING,
278 G_TYPE_NONE, 1, G_TYPE_STRING);
283 * The #GtkTreeModel from which the menu is constructed.
287 g_object_class_install_property (object_class,
289 g_param_spec_object ("model",
290 P_("TreeMenu model"),
291 P_("The model for the tree menu"),
293 GTK_PARAM_READWRITE));
298 * The #GtkTreePath that is the root for this menu, or %NULL.
300 * The #GtkTreeMenu recursively creates submenus for #GtkTreeModel
301 * rows that have children and the "root" for each menu is provided
302 * by the parent menu.
304 * If you dont provide a root for the #GtkTreeMenu then the whole
305 * model will be added to the menu. Specifying a root allows you
306 * to build a menu for a given #GtkTreePath and its children.
310 g_object_class_install_property (object_class,
312 g_param_spec_boxed ("root",
313 P_("TreeMenu root row"),
314 P_("The TreeMenu will display children of the "
317 GTK_PARAM_READWRITE));
320 * GtkTreeMenu:cell-area:
322 * The #GtkCellArea used to render cells in the menu items.
324 * You can provide a different cell area at object construction
325 * time, otherwise the #GtkTreeMenu will use a #GtkCellAreaBox.
329 g_object_class_install_property (object_class,
331 g_param_spec_object ("cell-area",
333 P_("The GtkCellArea used to layout cells"),
335 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
338 * GtkTreeMenu:tearoff:
340 * Specifies whether this menu comes with a leading tearoff menu item
344 g_object_class_install_property (object_class,
346 g_param_spec_boolean ("tearoff",
348 P_("Whether the menu has a tearoff item"),
350 GTK_PARAM_READWRITE));
353 * GtkTreeMenu:wrap-width:
355 * If wrap-width is set to a positive value, the list will be
356 * displayed in multiple columns, the number of columns is
357 * determined by wrap-width.
361 g_object_class_install_property (object_class,
363 g_param_spec_int ("wrap-width",
365 P_("Wrap width for laying out items in a grid"),
369 GTK_PARAM_READWRITE));
372 * GtkTreeMenu:row-span-column:
374 * If this is set to a non-negative value, it must be the index of a column
375 * of type %G_TYPE_INT in the model.
377 * The values of that column are used to determine how many rows a value in
378 * the list will span. Therefore, the values in the model column pointed to
379 * by this property must be greater than zero and not larger than wrap-width.
383 g_object_class_install_property (object_class,
385 g_param_spec_int ("row-span-column",
386 P_("Row span column"),
387 P_("TreeModel column containing the row span values"),
391 GTK_PARAM_READWRITE));
394 * GtkTreeMenu:column-span-column:
396 * If this is set to a non-negative value, it must be the index of a column
397 * of type %G_TYPE_INT in the model.
399 * The values of that column are used to determine how many columns a value
400 * in the list will span.
404 g_object_class_install_property (object_class,
406 g_param_spec_int ("column-span-column",
407 P_("Column span column"),
408 P_("TreeModel column containing the column span values"),
412 GTK_PARAM_READWRITE));
414 g_type_class_add_private (object_class, sizeof (GtkTreeMenuPrivate));
417 /****************************************************************
419 ****************************************************************/
421 gtk_tree_menu_constructor (GType type,
422 guint n_construct_properties,
423 GObjectConstructParam *construct_properties)
427 GtkTreeMenuPrivate *priv;
429 object = G_OBJECT_CLASS (_gtk_tree_menu_parent_class)->constructor
430 (type, n_construct_properties, construct_properties);
432 menu = GTK_TREE_MENU (object);
437 GtkCellArea *area = gtk_cell_area_box_new ();
439 gtk_tree_menu_set_area (menu, area);
442 priv->context = gtk_cell_area_create_context (priv->area);
444 priv->size_changed_id =
445 g_signal_connect (priv->context, "notify",
446 G_CALLBACK (context_size_changed_cb), menu);
452 gtk_tree_menu_dispose (GObject *object)
455 GtkTreeMenuPrivate *priv;
457 menu = GTK_TREE_MENU (object);
460 _gtk_tree_menu_set_model (menu, NULL);
461 gtk_tree_menu_set_area (menu, NULL);
465 /* Disconnect signals */
466 g_signal_handler_disconnect (priv->context, priv->size_changed_id);
468 g_object_unref (priv->context);
469 priv->context = NULL;
470 priv->size_changed_id = 0;
473 G_OBJECT_CLASS (_gtk_tree_menu_parent_class)->dispose (object);
477 gtk_tree_menu_finalize (GObject *object)
480 GtkTreeMenuPrivate *priv;
482 menu = GTK_TREE_MENU (object);
485 _gtk_tree_menu_set_row_separator_func (menu, NULL, NULL, NULL);
486 _gtk_tree_menu_set_header_func (menu, NULL, NULL, NULL);
489 gtk_tree_row_reference_free (priv->root);
491 G_OBJECT_CLASS (_gtk_tree_menu_parent_class)->finalize (object);
495 gtk_tree_menu_set_property (GObject *object,
500 GtkTreeMenu *menu = GTK_TREE_MENU (object);
505 _gtk_tree_menu_set_model (menu, g_value_get_object (value));
509 _gtk_tree_menu_set_root (menu, g_value_get_boxed (value));
513 /* Construct-only, can only be assigned once */
514 gtk_tree_menu_set_area (menu, (GtkCellArea *)g_value_get_object (value));
518 _gtk_tree_menu_set_tearoff (menu, g_value_get_boolean (value));
521 case PROP_WRAP_WIDTH:
522 _gtk_tree_menu_set_wrap_width (menu, g_value_get_int (value));
525 case PROP_ROW_SPAN_COL:
526 _gtk_tree_menu_set_row_span_column (menu, g_value_get_int (value));
529 case PROP_COL_SPAN_COL:
530 _gtk_tree_menu_set_column_span_column (menu, g_value_get_int (value));
534 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
540 gtk_tree_menu_get_property (GObject *object,
545 GtkTreeMenu *menu = GTK_TREE_MENU (object);
546 GtkTreeMenuPrivate *priv = menu->priv;
551 g_value_set_object (value, priv->model);
555 g_value_set_boxed (value, priv->root);
559 g_value_set_object (value, priv->area);
563 g_value_set_boolean (value, priv->tearoff);
567 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
572 /****************************************************************
574 ****************************************************************/
576 /* We tell all the menu items to reserve space for the submenu
577 * indicator if there is at least one submenu, this way we ensure
578 * that every internal cell area gets allocated the
579 * same width (and requested height for the same appropriate width).
582 sync_reserve_submenu_size (GtkTreeMenu *menu)
585 gboolean has_submenu = FALSE;
587 children = gtk_container_get_children (GTK_CONTAINER (menu));
588 for (l = children; l; l = l->next)
590 GtkMenuItem *item = l->data;
592 if (gtk_menu_item_get_submenu (item) != NULL)
599 for (l = children; l; l = l->next)
601 GtkMenuItem *item = l->data;
603 gtk_menu_item_set_reserve_indicator (item, has_submenu);
606 g_list_free (children);
610 gtk_tree_menu_get_preferred_width (GtkWidget *widget,
614 GtkTreeMenu *menu = GTK_TREE_MENU (widget);
615 GtkTreeMenuPrivate *priv = menu->priv;
617 /* We leave the requesting work up to the cellviews which operate in the same
618 * context, reserving space for the submenu indicator if any of the items have
619 * submenus ensures that every cellview will receive the same allocated width.
621 * Since GtkMenu does hieght-for-width correctly, we know that the width of
622 * every cell will be requested before the height-for-widths are requested.
624 g_signal_handler_block (priv->context, priv->size_changed_id);
626 sync_reserve_submenu_size (menu);
628 GTK_WIDGET_CLASS (_gtk_tree_menu_parent_class)->get_preferred_width (widget, minimum_size, natural_size);
630 g_signal_handler_unblock (priv->context, priv->size_changed_id);
634 gtk_tree_menu_get_preferred_height (GtkWidget *widget,
638 GtkTreeMenu *menu = GTK_TREE_MENU (widget);
639 GtkTreeMenuPrivate *priv = menu->priv;
641 g_signal_handler_block (priv->context, priv->size_changed_id);
643 sync_reserve_submenu_size (menu);
645 GTK_WIDGET_CLASS (_gtk_tree_menu_parent_class)->get_preferred_height (widget, minimum_size, natural_size);
647 g_signal_handler_unblock (priv->context, priv->size_changed_id);
650 /****************************************************************
651 * GtkCellLayoutIface *
652 ****************************************************************/
654 gtk_tree_menu_cell_layout_init (GtkCellLayoutIface *iface)
656 iface->get_area = gtk_tree_menu_cell_layout_get_area;
660 gtk_tree_menu_cell_layout_get_area (GtkCellLayout *layout)
662 GtkTreeMenu *menu = GTK_TREE_MENU (layout);
663 GtkTreeMenuPrivate *priv = menu->priv;
669 /****************************************************************
670 * TreeModel callbacks/populating menus *
671 ****************************************************************/
673 gtk_tree_menu_get_path_item (GtkTreeMenu *menu,
676 GtkWidget *item = NULL;
679 children = gtk_container_get_children (GTK_CONTAINER (menu));
681 for (l = children; item == NULL && l != NULL; l = l->next)
683 GtkWidget *child = l->data;
684 GtkTreePath *path = NULL;
686 if (GTK_IS_SEPARATOR_MENU_ITEM (child))
688 GtkTreeRowReference *row =
689 g_object_get_qdata (G_OBJECT (child), tree_menu_path_quark);
693 path = gtk_tree_row_reference_get_path (row);
696 /* Return any first child where its row-reference became invalid,
697 * this is because row-references get null paths before we recieve
698 * the "row-deleted" signal.
703 else if (!GTK_IS_TEAROFF_MENU_ITEM (child))
705 GtkWidget *view = gtk_bin_get_child (GTK_BIN (child));
707 /* It's always a cellview */
708 if (GTK_IS_CELL_VIEW (view))
709 path = gtk_cell_view_get_displayed_row (GTK_CELL_VIEW (view));
712 /* Return any first child where its row-reference became invalid,
713 * this is because row-references get null paths before we recieve
714 * the "row-deleted" signal.
721 if (gtk_tree_path_compare (search, path) == 0)
724 gtk_tree_path_free (path);
728 g_list_free (children);
734 gtk_tree_menu_path_in_menu (GtkTreeMenu *menu,
736 gboolean *header_item)
738 GtkTreeMenuPrivate *priv = menu->priv;
739 gboolean in_menu = FALSE;
740 gboolean is_header = FALSE;
742 /* Check if the is in root of the model */
743 if (gtk_tree_path_get_depth (path) == 1 && !priv->root)
745 /* If we are a submenu, compare the parent path */
748 GtkTreePath *root_path = gtk_tree_row_reference_get_path (priv->root);
749 GtkTreePath *search_path = gtk_tree_path_copy (path);
753 if (priv->menu_with_header &&
754 gtk_tree_path_compare (root_path, search_path) == 0)
759 else if (gtk_tree_path_get_depth (search_path) > 1)
761 gtk_tree_path_up (search_path);
763 if (gtk_tree_path_compare (root_path, search_path) == 0)
767 gtk_tree_path_free (root_path);
768 gtk_tree_path_free (search_path);
772 *header_item = is_header;
778 gtk_tree_menu_path_needs_submenu (GtkTreeMenu *menu,
781 GtkWidget *item = NULL;
783 GtkTreePath *parent_path;
785 if (gtk_tree_path_get_depth (search) <= 1)
788 parent_path = gtk_tree_path_copy (search);
789 gtk_tree_path_up (parent_path);
791 children = gtk_container_get_children (GTK_CONTAINER (menu));
793 for (l = children; item == NULL && l != NULL; l = l->next)
795 GtkWidget *child = l->data;
796 GtkTreePath *path = NULL;
798 /* Separators dont get submenus, if it already has a submenu then let
799 * the submenu handle inserted rows */
800 if (!GTK_IS_SEPARATOR_MENU_ITEM (child) &&
801 !gtk_menu_item_get_submenu (GTK_MENU_ITEM (child)))
803 GtkWidget *view = gtk_bin_get_child (GTK_BIN (child));
805 /* It's always a cellview */
806 if (GTK_IS_CELL_VIEW (view))
807 path = gtk_cell_view_get_displayed_row (GTK_CELL_VIEW (view));
812 if (gtk_tree_path_compare (parent_path, path) == 0)
815 gtk_tree_path_free (path);
819 g_list_free (children);
820 gtk_tree_path_free (parent_path);
826 find_empty_submenu (GtkTreeMenu *menu)
828 GtkTreeMenuPrivate *priv = menu->priv;
830 GtkWidget *submenu = NULL;
832 children = gtk_container_get_children (GTK_CONTAINER (menu));
834 for (l = children; submenu == NULL && l != NULL; l = l->next)
836 GtkWidget *child = l->data;
837 GtkTreePath *path = NULL;
840 /* Separators dont get submenus, if it already has a submenu then let
841 * the submenu handle inserted rows */
842 if (!GTK_IS_SEPARATOR_MENU_ITEM (child) && !GTK_IS_TEAROFF_MENU_ITEM (child))
844 GtkWidget *view = gtk_bin_get_child (GTK_BIN (child));
846 /* It's always a cellview */
847 if (GTK_IS_CELL_VIEW (view))
848 path = gtk_cell_view_get_displayed_row (GTK_CELL_VIEW (view));
853 if (gtk_tree_model_get_iter (priv->model, &iter, path) &&
854 !gtk_tree_model_iter_has_child (priv->model, &iter))
855 submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (child));
857 gtk_tree_path_free (path);
861 g_list_free (children);
867 row_inserted_cb (GtkTreeModel *model,
872 GtkTreeMenuPrivate *priv = menu->priv;
873 gint *indices, index, depth;
876 /* If the iter should be in this menu then go ahead and insert it */
877 if (gtk_tree_menu_path_in_menu (menu, path, NULL))
879 if (priv->wrap_width > 0)
883 /* Get the index of the path for this depth */
884 indices = gtk_tree_path_get_indices (path);
885 depth = gtk_tree_path_get_depth (path);
886 index = indices[depth -1];
888 /* Menus with a header include a menuitem for its root node
889 * and a separator menu item */
890 if (priv->menu_with_header)
893 /* Index after the tearoff item for the root menu if
894 * there is a tearoff item
896 if (priv->root == NULL && priv->tearoff)
899 item = gtk_tree_menu_create_item (menu, iter, FALSE);
900 gtk_menu_shell_insert (GTK_MENU_SHELL (menu), item, index);
902 /* Resize everything */
903 gtk_cell_area_context_reset (menu->priv->context);
908 /* Create submenus for iters if we need to */
909 item = gtk_tree_menu_path_needs_submenu (menu, path);
912 GtkTreePath *item_path = gtk_tree_path_copy (path);
914 gtk_tree_path_up (item_path);
915 gtk_tree_menu_create_submenu (menu, item, item_path);
916 gtk_tree_path_free (item_path);
922 row_deleted_cb (GtkTreeModel *model,
926 GtkTreeMenuPrivate *priv = menu->priv;
929 /* If it's the header item we leave it to the parent menu
930 * to remove us from its menu
932 item = gtk_tree_menu_get_path_item (menu, path);
936 if (priv->wrap_width > 0)
940 /* Get rid of the deleted item */
941 gtk_widget_destroy (item);
943 /* Resize everything */
944 gtk_cell_area_context_reset (menu->priv->context);
949 /* It's up to the parent menu to destroy a child menu that becomes empty
950 * since the topmost menu belongs to the user and is allowed to have no contents */
951 GtkWidget *submenu = find_empty_submenu (menu);
953 gtk_widget_destroy (submenu);
958 row_reordered_cb (GtkTreeModel *model,
964 GtkTreeMenuPrivate *priv = menu->priv;
965 gboolean this_menu = FALSE;
967 if (gtk_tree_path_get_depth (path) == 0 && !priv->root)
971 GtkTreePath *root_path =
972 gtk_tree_row_reference_get_path (priv->root);
974 if (gtk_tree_path_compare (root_path, path) == 0)
977 gtk_tree_path_free (root_path);
985 menu_item_position (GtkTreeMenu *menu,
991 children = gtk_container_get_children (GTK_CONTAINER (menu));
992 for (position = 0, l = children; l; position++, l = l->next)
994 GtkWidget *iitem = l->data;
1000 g_list_free (children);
1006 row_changed_cb (GtkTreeModel *model,
1011 GtkTreeMenuPrivate *priv = menu->priv;
1012 gboolean is_separator = FALSE;
1013 gboolean has_header = FALSE;
1016 item = gtk_tree_menu_get_path_item (menu, path);
1020 GtkTreePath *root_path =
1021 gtk_tree_row_reference_get_path (priv->root);
1023 if (root_path && gtk_tree_path_compare (root_path, path) == 0)
1025 if (priv->header_func)
1027 priv->header_func (priv->model, iter, priv->header_data);
1029 if (has_header && !item)
1031 item = gtk_separator_menu_item_new ();
1032 gtk_widget_show (item);
1033 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
1035 item = gtk_tree_menu_create_item (menu, iter, TRUE);
1036 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
1038 priv->menu_with_header = TRUE;
1040 else if (!has_header && item)
1042 /* Destroy the header item and then the following separator */
1043 gtk_widget_destroy (item);
1044 gtk_widget_destroy (GTK_MENU_SHELL (menu)->priv->children->data);
1046 priv->menu_with_header = FALSE;
1049 gtk_tree_path_free (root_path);
1055 if (priv->wrap_width > 0)
1056 /* Ugly, we need to rebuild the menu here if
1057 * the row-span/row-column values change
1059 rebuild_menu (menu);
1062 if (priv->row_separator_func)
1064 priv->row_separator_func (model, iter,
1065 priv->row_separator_data);
1068 if (is_separator != GTK_IS_SEPARATOR_MENU_ITEM (item))
1070 gint position = menu_item_position (menu, item);
1072 gtk_widget_destroy (item);
1073 item = gtk_tree_menu_create_item (menu, iter, FALSE);
1074 gtk_menu_shell_insert (GTK_MENU_SHELL (menu), item, position);
1081 context_size_changed_cb (GtkCellAreaContext *context,
1085 if (!strcmp (pspec->name, "minimum-width") ||
1086 !strcmp (pspec->name, "natural-width") ||
1087 !strcmp (pspec->name, "minimum-height") ||
1088 !strcmp (pspec->name, "natural-height"))
1089 gtk_widget_queue_resize (menu);
1093 area_is_sensitive (GtkCellArea *area)
1095 GList *cells, *list;
1096 gboolean sensitive = FALSE;
1098 cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (area));
1100 for (list = cells; list; list = list->next)
1102 g_object_get (list->data, "sensitive", &sensitive, NULL);
1107 g_list_free (cells);
1113 area_apply_attributes_cb (GtkCellArea *area,
1114 GtkTreeModel *tree_model,
1116 gboolean is_expander,
1117 gboolean is_expanded,
1120 /* If the menu for this iter has a submenu */
1121 GtkTreeMenuPrivate *priv = menu->priv;
1127 path = gtk_tree_model_get_path (tree_model, iter);
1129 if (gtk_tree_menu_path_in_menu (menu, path, &is_header))
1131 item = gtk_tree_menu_get_path_item (menu, path);
1133 /* If there is no submenu, go ahead and update item sensitivity,
1134 * items with submenus are always sensitive */
1135 if (item && !gtk_menu_item_get_submenu (GTK_MENU_ITEM (item)))
1137 sensitive = area_is_sensitive (priv->area);
1139 gtk_widget_set_sensitive (item, sensitive);
1143 /* For header items we need to set the sensitivity
1144 * of the following separator item
1146 if (GTK_MENU_SHELL (menu)->priv->children &&
1147 GTK_MENU_SHELL (menu)->priv->children->next)
1149 GtkWidget *separator =
1150 GTK_MENU_SHELL (menu)->priv->children->next->data;
1152 gtk_widget_set_sensitive (separator, sensitive);
1158 gtk_tree_path_free (path);
1162 gtk_tree_menu_set_area (GtkTreeMenu *menu,
1165 GtkTreeMenuPrivate *priv = menu->priv;
1169 g_signal_handler_disconnect (priv->area,
1170 priv->apply_attributes_id);
1171 priv->apply_attributes_id = 0;
1173 g_object_unref (priv->area);
1180 g_object_ref_sink (priv->area);
1182 priv->apply_attributes_id =
1183 g_signal_connect (priv->area, "apply-attributes",
1184 G_CALLBACK (area_apply_attributes_cb), menu);
1189 menu_occupied (GtkTreeMenu *menu,
1193 guint bottom_attach)
1197 for (i = GTK_MENU_SHELL (menu)->priv->children; i; i = i->next)
1201 gtk_container_child_get (GTK_CONTAINER (menu),
1205 "bottom-attach", &b,
1209 /* look if this item intersects with the given coordinates */
1210 if (right_attach > l && left_attach < r && bottom_attach > t && top_attach < b)
1218 relayout_item (GtkTreeMenu *menu,
1223 GtkTreeMenuPrivate *priv = menu->priv;
1224 gint current_col = 0, current_row = 0;
1225 gint rows = 1, cols = 1;
1227 if (priv->col_span_col == -1 &&
1228 priv->row_span_col == -1 &&
1231 gtk_container_child_get (GTK_CONTAINER (menu), prev,
1232 "right-attach", ¤t_col,
1233 "top-attach", ¤t_row,
1235 if (current_col + cols > priv->wrap_width)
1243 if (priv->col_span_col != -1)
1244 gtk_tree_model_get (priv->model, iter,
1245 priv->col_span_col, &cols,
1247 if (priv->row_span_col != -1)
1248 gtk_tree_model_get (priv->model, iter,
1249 priv->row_span_col, &rows,
1254 if (current_col + cols > priv->wrap_width)
1260 if (!menu_occupied (menu,
1261 current_col, current_col + cols,
1262 current_row, current_row + rows))
1269 /* set attach props */
1270 gtk_menu_attach (GTK_MENU (menu), item,
1271 current_col, current_col + cols,
1272 current_row, current_row + rows);
1276 gtk_tree_menu_create_submenu (GtkTreeMenu *menu,
1280 GtkTreeMenuPrivate *priv = menu->priv;
1284 view = gtk_bin_get_child (GTK_BIN (item));
1285 gtk_cell_view_set_draw_sensitive (GTK_CELL_VIEW (view), TRUE);
1287 submenu = _gtk_tree_menu_new_with_area (priv->area);
1289 _gtk_tree_menu_set_row_separator_func (GTK_TREE_MENU (submenu),
1290 priv->row_separator_func,
1291 priv->row_separator_data,
1292 priv->row_separator_destroy);
1293 _gtk_tree_menu_set_header_func (GTK_TREE_MENU (submenu),
1296 priv->header_destroy);
1298 _gtk_tree_menu_set_wrap_width (GTK_TREE_MENU (submenu), priv->wrap_width);
1299 _gtk_tree_menu_set_row_span_column (GTK_TREE_MENU (submenu), priv->row_span_col);
1300 _gtk_tree_menu_set_column_span_column (GTK_TREE_MENU (submenu), priv->col_span_col);
1302 gtk_tree_menu_set_model_internal (GTK_TREE_MENU (submenu), priv->model);
1303 _gtk_tree_menu_set_root (GTK_TREE_MENU (submenu), path);
1304 gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
1306 g_signal_connect (submenu, "menu-activate",
1307 G_CALLBACK (submenu_activated_cb), menu);
1311 gtk_tree_menu_create_item (GtkTreeMenu *menu,
1313 gboolean header_item)
1315 GtkTreeMenuPrivate *priv = menu->priv;
1316 GtkWidget *item, *view;
1318 gboolean is_separator = FALSE;
1320 path = gtk_tree_model_get_path (priv->model, iter);
1322 if (priv->row_separator_func)
1324 priv->row_separator_func (priv->model, iter,
1325 priv->row_separator_data);
1329 item = gtk_separator_menu_item_new ();
1330 gtk_widget_show (item);
1332 g_object_set_qdata_full (G_OBJECT (item),
1333 tree_menu_path_quark,
1334 gtk_tree_row_reference_new (priv->model, path),
1335 (GDestroyNotify)gtk_tree_row_reference_free);
1339 view = gtk_cell_view_new_with_context (priv->area, priv->context);
1340 item = gtk_menu_item_new ();
1341 gtk_widget_show (view);
1342 gtk_widget_show (item);
1344 gtk_cell_view_set_model (GTK_CELL_VIEW (view), priv->model);
1345 gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (view), path);
1347 gtk_widget_show (view);
1348 gtk_container_add (GTK_CONTAINER (item), view);
1350 g_signal_connect (item, "activate", G_CALLBACK (item_activated_cb), menu);
1352 /* Add a GtkTreeMenu submenu to render the children of this row */
1353 if (header_item == FALSE &&
1354 gtk_tree_model_iter_has_child (priv->model, iter))
1355 gtk_tree_menu_create_submenu (menu, item, path);
1358 gtk_tree_path_free (path);
1364 rebuild_menu (GtkTreeMenu *menu)
1366 GtkTreeMenuPrivate *priv = menu->priv;
1368 /* Destroy all the menu items */
1369 gtk_container_foreach (GTK_CONTAINER (menu),
1370 (GtkCallback) gtk_widget_destroy, NULL);
1374 gtk_tree_menu_populate (menu);
1379 gtk_tree_menu_populate (GtkTreeMenu *menu)
1381 GtkTreeMenuPrivate *priv = menu->priv;
1382 GtkTreePath *path = NULL;
1385 gboolean valid = FALSE;
1386 GtkWidget *menu_item, *prev = NULL;
1392 path = gtk_tree_row_reference_get_path (priv->root);
1396 if (gtk_tree_model_get_iter (priv->model, &parent, path))
1398 valid = gtk_tree_model_iter_children (priv->model, &iter, &parent);
1400 if (priv->header_func &&
1401 priv->header_func (priv->model, &parent, priv->header_data))
1403 /* Add a submenu header for rows which desire one, used for
1404 * combo boxes to allow all rows to be activatable/selectable
1406 menu_item = gtk_tree_menu_create_item (menu, &parent, TRUE);
1407 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
1409 menu_item = gtk_separator_menu_item_new ();
1410 gtk_widget_show (menu_item);
1411 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
1414 priv->menu_with_header = TRUE;
1417 gtk_tree_path_free (path);
1421 /* Tearoff menu items only go in the root menu */
1424 menu_item = gtk_tearoff_menu_item_new ();
1425 gtk_widget_show (menu_item);
1427 if (priv->wrap_width > 0)
1428 gtk_menu_attach (GTK_MENU (menu), menu_item, 0, priv->wrap_width, 0, 1);
1430 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
1435 valid = gtk_tree_model_iter_children (priv->model, &iter, NULL);
1438 /* Create a menu item for every row at the current depth, add a GtkTreeMenu
1439 * submenu for iters/items that have children */
1442 menu_item = gtk_tree_menu_create_item (menu, &iter, FALSE);
1444 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
1446 if (priv->wrap_width > 0)
1447 relayout_item (menu, menu_item, &iter, prev);
1450 valid = gtk_tree_model_iter_next (priv->model, &iter);
1455 item_activated_cb (GtkMenuItem *item,
1462 /* Only activate leafs, not parents */
1463 if (!gtk_menu_item_get_submenu (item))
1465 view = GTK_CELL_VIEW (gtk_bin_get_child (GTK_BIN (item)));
1466 path = gtk_cell_view_get_displayed_row (view);
1467 path_str = gtk_tree_path_to_string (path);
1469 g_signal_emit (menu, tree_menu_signals[SIGNAL_MENU_ACTIVATE], 0, path_str);
1472 gtk_tree_path_free (path);
1477 submenu_activated_cb (GtkTreeMenu *submenu,
1481 g_signal_emit (menu, tree_menu_signals[SIGNAL_MENU_ACTIVATE], 0, path);
1484 /* Sets the model without rebuilding the menu, prevents
1485 * infinite recursion while building submenus (we wait
1486 * until the root is set and then build the menu) */
1488 gtk_tree_menu_set_model_internal (GtkTreeMenu *menu,
1489 GtkTreeModel *model)
1491 GtkTreeMenuPrivate *priv;
1495 if (priv->model != model)
1499 /* Disconnect signals */
1500 g_signal_handler_disconnect (priv->model,
1501 priv->row_inserted_id);
1502 g_signal_handler_disconnect (priv->model,
1503 priv->row_deleted_id);
1504 g_signal_handler_disconnect (priv->model,
1505 priv->row_reordered_id);
1506 g_signal_handler_disconnect (priv->model,
1507 priv->row_changed_id);
1508 priv->row_inserted_id = 0;
1509 priv->row_deleted_id = 0;
1510 priv->row_reordered_id = 0;
1511 priv->row_changed_id = 0;
1513 g_object_unref (priv->model);
1516 priv->model = model;
1520 g_object_ref (priv->model);
1522 /* Connect signals */
1523 priv->row_inserted_id = g_signal_connect (priv->model, "row-inserted",
1524 G_CALLBACK (row_inserted_cb), menu);
1525 priv->row_deleted_id = g_signal_connect (priv->model, "row-deleted",
1526 G_CALLBACK (row_deleted_cb), menu);
1527 priv->row_reordered_id = g_signal_connect (priv->model, "rows-reordered",
1528 G_CALLBACK (row_reordered_cb), menu);
1529 priv->row_changed_id = g_signal_connect (priv->model, "row-changed",
1530 G_CALLBACK (row_changed_cb), menu);
1535 /****************************************************************
1537 ****************************************************************/
1540 * _gtk_tree_menu_new:
1542 * Creates a new #GtkTreeMenu.
1544 * Return value: A newly created #GtkTreeMenu with no model or root.
1549 _gtk_tree_menu_new (void)
1551 return (GtkWidget *)g_object_new (GTK_TYPE_TREE_MENU, NULL);
1555 * _gtk_tree_menu_new_with_area:
1556 * @area: the #GtkCellArea to use to render cells in the menu
1558 * Creates a new #GtkTreeMenu using @area to render its cells.
1560 * Return value: A newly created #GtkTreeMenu with no model or root.
1565 _gtk_tree_menu_new_with_area (GtkCellArea *area)
1567 return (GtkWidget *)g_object_new (GTK_TYPE_TREE_MENU,
1573 * _gtk_tree_menu_new_full:
1574 * @area: (allow-none): the #GtkCellArea to use to render cells in the menu, or %NULL.
1575 * @model: (allow-none): the #GtkTreeModel to build the menu heirarchy from, or %NULL.
1576 * @root: (allow-none): the #GtkTreePath indicating the root row for this menu, or %NULL.
1578 * Creates a new #GtkTreeMenu hierarchy from the provided @model and @root using @area to render its cells.
1580 * Return value: A newly created #GtkTreeMenu.
1585 _gtk_tree_menu_new_full (GtkCellArea *area,
1586 GtkTreeModel *model,
1589 return (GtkWidget *)g_object_new (GTK_TYPE_TREE_MENU,
1597 * _gtk_tree_menu_set_model:
1598 * @menu: a #GtkTreeMenu
1599 * @model: (allow-none): the #GtkTreeModel to build the menu hierarchy from, or %NULL.
1601 * Sets @model to be used to build the menu heirarhcy.
1606 _gtk_tree_menu_set_model (GtkTreeMenu *menu,
1607 GtkTreeModel *model)
1609 g_return_if_fail (GTK_IS_TREE_MENU (menu));
1610 g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
1612 gtk_tree_menu_set_model_internal (menu, model);
1614 rebuild_menu (menu);
1618 * _gtk_tree_menu_get_model:
1619 * @menu: a #GtkTreeMenu
1621 * Gets the @model currently used for the menu heirarhcy.
1623 * Return value: (transfer none): the #GtkTreeModel which is used
1624 * for @menu's hierarchy.
1629 _gtk_tree_menu_get_model (GtkTreeMenu *menu)
1631 GtkTreeMenuPrivate *priv;
1633 g_return_val_if_fail (GTK_IS_TREE_MENU (menu), NULL);
1641 * _gtk_tree_menu_set_root:
1642 * @menu: a #GtkTreeMenu
1643 * @path: (allow-none): the #GtkTreePath which is the root of @menu, or %NULL.
1645 * Sets the root of a @menu's hierarchy to be @path. @menu must already
1646 * have a model set and @path must point to a valid path inside the model.
1651 _gtk_tree_menu_set_root (GtkTreeMenu *menu,
1654 GtkTreeMenuPrivate *priv;
1656 g_return_if_fail (GTK_IS_TREE_MENU (menu));
1657 g_return_if_fail (menu->priv->model != NULL || path == NULL);
1662 gtk_tree_row_reference_free (priv->root);
1665 priv->root = gtk_tree_row_reference_new (priv->model, path);
1669 rebuild_menu (menu);
1673 * _gtk_tree_menu_get_root:
1674 * @menu: a #GtkTreeMenu
1676 * Gets the @root path for @menu's hierarchy, or returns %NULL if @menu
1677 * has no model or is building a heirarchy for the entire model. *
1679 * Return value: (transfer full) (allow-none): A newly created #GtkTreePath
1680 * pointing to the root of @menu which must be freed with gtk_tree_path_free().
1685 _gtk_tree_menu_get_root (GtkTreeMenu *menu)
1687 GtkTreeMenuPrivate *priv;
1689 g_return_val_if_fail (GTK_IS_TREE_MENU (menu), NULL);
1694 return gtk_tree_row_reference_get_path (priv->root);
1700 * _gtk_tree_menu_get_tearoff:
1701 * @menu: a #GtkTreeMenu
1703 * Gets whether this menu is build with a leading tearoff menu item.
1705 * Return value: %TRUE if the menu has a tearoff item.
1710 _gtk_tree_menu_get_tearoff (GtkTreeMenu *menu)
1712 GtkTreeMenuPrivate *priv;
1714 g_return_val_if_fail (GTK_IS_TREE_MENU (menu), FALSE);
1718 return priv->tearoff;
1722 * _gtk_tree_menu_set_tearoff:
1723 * @menu: a #GtkTreeMenu
1724 * @tearoff: whether the menu should have a leading tearoff menu item.
1726 * Sets whether this menu has a leading tearoff menu item.
1731 _gtk_tree_menu_set_tearoff (GtkTreeMenu *menu,
1734 GtkTreeMenuPrivate *priv;
1736 g_return_if_fail (GTK_IS_TREE_MENU (menu));
1740 if (priv->tearoff != tearoff)
1742 priv->tearoff = tearoff;
1744 rebuild_menu (menu);
1746 g_object_notify (G_OBJECT (menu), "tearoff");
1751 * _gtk_tree_menu_get_wrap_width:
1752 * @menu: a #GtkTreeMenu
1754 * Gets the wrap width which is used to determine the number of columns
1755 * for @menu. If the wrap width is larger than 1, @menu is in table mode.
1757 * Return value: the wrap width.
1762 _gtk_tree_menu_get_wrap_width (GtkTreeMenu *menu)
1764 GtkTreeMenuPrivate *priv;
1766 g_return_val_if_fail (GTK_IS_TREE_MENU (menu), FALSE);
1770 return priv->wrap_width;
1774 * _gtk_tree_menu_set_wrap_width:
1775 * @menu: a #GtkTreeMenu
1776 * @width: the wrap width
1778 * Sets the wrap width which is used to determine the number of columns
1779 * for @menu. If the wrap width is larger than 1, @menu is in table mode.
1784 _gtk_tree_menu_set_wrap_width (GtkTreeMenu *menu,
1787 GtkTreeMenuPrivate *priv;
1789 g_return_if_fail (GTK_IS_TREE_MENU (menu));
1790 g_return_if_fail (width >= 0);
1794 if (priv->wrap_width != width)
1796 priv->wrap_width = width;
1798 rebuild_menu (menu);
1800 g_object_notify (G_OBJECT (menu), "wrap-width");
1805 * _gtk_tree_menu_get_row_span_column:
1806 * @menu: a #GtkTreeMenu
1808 * Gets the column with row span information for @menu.
1809 * The row span column contains integers which indicate how many rows
1810 * a menu item should span.
1812 * Return value: the column in @menu's model containing row span information, or -1.
1817 _gtk_tree_menu_get_row_span_column (GtkTreeMenu *menu)
1819 GtkTreeMenuPrivate *priv;
1821 g_return_val_if_fail (GTK_IS_TREE_MENU (menu), FALSE);
1825 return priv->row_span_col;
1829 * _gtk_tree_menu_set_row_span_column:
1830 * @menu: a #GtkTreeMenu
1831 * @row_span: the column in the model to fetch the row span for a given menu item.
1833 * Sets the column with row span information for @menu to be @row_span.
1834 * The row span column contains integers which indicate how many rows
1835 * a menu item should span.
1840 _gtk_tree_menu_set_row_span_column (GtkTreeMenu *menu,
1843 GtkTreeMenuPrivate *priv;
1845 g_return_if_fail (GTK_IS_TREE_MENU (menu));
1849 if (priv->row_span_col != row_span)
1851 priv->row_span_col = row_span;
1853 if (priv->wrap_width > 0)
1854 rebuild_menu (menu);
1856 g_object_notify (G_OBJECT (menu), "row-span-column");
1861 * _gtk_tree_menu_get_column_span_column:
1862 * @menu: a #GtkTreeMenu
1864 * Gets the column with column span information for @menu.
1865 * The column span column contains integers which indicate how many columns
1866 * a menu item should span.
1868 * Return value: the column in @menu's model containing column span information, or -1.
1873 _gtk_tree_menu_get_column_span_column (GtkTreeMenu *menu)
1875 GtkTreeMenuPrivate *priv;
1877 g_return_val_if_fail (GTK_IS_TREE_MENU (menu), FALSE);
1881 return priv->col_span_col;
1885 * _gtk_tree_menu_set_column_span_column:
1886 * @menu: a #GtkTreeMenu
1887 * @column_span: the column in the model to fetch the column span for a given menu item.
1889 * Sets the column with column span information for @menu to be @column_span.
1890 * The column span column contains integers which indicate how many columns
1891 * a menu item should span.
1896 _gtk_tree_menu_set_column_span_column (GtkTreeMenu *menu,
1899 GtkTreeMenuPrivate *priv;
1901 g_return_if_fail (GTK_IS_TREE_MENU (menu));
1905 if (priv->col_span_col != column_span)
1907 priv->col_span_col = column_span;
1909 if (priv->wrap_width > 0)
1910 rebuild_menu (menu);
1912 g_object_notify (G_OBJECT (menu), "column-span-column");
1917 * _gtk_tree_menu_get_row_separator_func:
1918 * @menu: a #GtkTreeMenu
1920 * Gets the current #GtkTreeViewRowSeparatorFunc separator function.
1922 * Return value: the current row separator function.
1926 GtkTreeViewRowSeparatorFunc
1927 _gtk_tree_menu_get_row_separator_func (GtkTreeMenu *menu)
1929 GtkTreeMenuPrivate *priv;
1931 g_return_val_if_fail (GTK_IS_TREE_MENU (menu), NULL);
1935 return priv->row_separator_func;
1939 * _gtk_tree_menu_set_row_separator_func:
1940 * @menu: a #GtkTreeMenu
1941 * @func: (allow-none): a #GtkTreeViewRowSeparatorFunc, or %NULL to unset the separator function.
1942 * @data: (allow-none): user data to pass to @func, or %NULL
1943 * @destroy: (allow-none): destroy notifier for @data, or %NULL
1945 * Sets the row separator function, which is used to determine
1946 * whether a row should be drawn as a separator. If the row separator
1947 * function is %NULL, no separators are drawn. This is the default value.
1952 _gtk_tree_menu_set_row_separator_func (GtkTreeMenu *menu,
1953 GtkTreeViewRowSeparatorFunc func,
1955 GDestroyNotify destroy)
1957 GtkTreeMenuPrivate *priv;
1959 g_return_if_fail (GTK_IS_TREE_MENU (menu));
1963 if (priv->row_separator_destroy)
1964 priv->row_separator_destroy (priv->row_separator_data);
1966 priv->row_separator_func = func;
1967 priv->row_separator_data = data;
1968 priv->row_separator_destroy = destroy;
1970 rebuild_menu (menu);
1974 * _gtk_tree_menu_get_header_func:
1975 * @menu: a #GtkTreeMenu
1977 * Gets the current #GtkTreeMenuHeaderFunc header function.
1979 * Return value: the current header function.
1983 GtkTreeMenuHeaderFunc
1984 _gtk_tree_menu_get_header_func (GtkTreeMenu *menu)
1986 GtkTreeMenuPrivate *priv;
1988 g_return_val_if_fail (GTK_IS_TREE_MENU (menu), NULL);
1992 return priv->header_func;
1996 * _gtk_tree_menu_set_header_func:
1997 * @menu: a #GtkTreeMenu
1998 * @func: (allow-none): a #GtkTreeMenuHeaderFunc, or %NULL to unset the header function.
1999 * @data: (allow-none): user data to pass to @func, or %NULL
2000 * @destroy: (allow-none): destroy notifier for @data, or %NULL
2002 * Sets the header function, which is used to determine
2003 * whether a row width children should contain a leading header
2004 * menu item to allow that row to be selectable as an independant
2005 * menu item. If the header function is %NULL, no rows with children
2006 * have menu items which can be activated as leafs.
2007 * This is the default value.
2012 _gtk_tree_menu_set_header_func (GtkTreeMenu *menu,
2013 GtkTreeMenuHeaderFunc func,
2015 GDestroyNotify destroy)
2017 GtkTreeMenuPrivate *priv;
2019 g_return_if_fail (GTK_IS_TREE_MENU (menu));
2023 if (priv->header_destroy)
2024 priv->header_destroy (priv->header_data);
2026 priv->header_func = func;
2027 priv->header_data = data;
2028 priv->header_destroy = destroy;
2030 rebuild_menu (menu);