diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c index 229f44852d..b4cfc07780 100644 --- a/gtk/gtkcombobox.c +++ b/gtk/gtkcombobox.c @@ -286,11 +286,6 @@ static void gtk_combo_box_model_row_changed (GtkTreeModel *model, GtkTreeIter *iter, gpointer data); -/* menu */ -static void gtk_combo_box_menu_setup (GtkComboBox *combo_box); -static void gtk_combo_box_menu_destroy (GtkComboBox *combo_box); - - static gboolean gtk_combo_box_menu_button_press (GtkWidget *widget, GdkEventButton *event, gpointer user_data); @@ -973,7 +968,14 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass) gtk_widget_class_bind_template_child_internal_private (widget_class, GtkComboBox, box); gtk_widget_class_bind_template_child_internal_private (widget_class, GtkComboBox, button); gtk_widget_class_bind_template_child_internal_private (widget_class, GtkComboBox, arrow); + gtk_widget_class_bind_template_child_internal_private (widget_class, GtkComboBox, area); + gtk_widget_class_bind_template_child_internal_private (widget_class, GtkComboBox, popup_widget); gtk_widget_class_bind_template_callback (widget_class, gtk_combo_box_button_toggled); + gtk_widget_class_bind_template_callback (widget_class, gtk_combo_box_menu_button_press); + gtk_widget_class_bind_template_callback (widget_class, gtk_combo_box_menu_activate); + gtk_widget_class_bind_template_callback (widget_class, gtk_combo_box_menu_key_press); + gtk_widget_class_bind_template_callback (widget_class, gtk_combo_box_menu_show); + gtk_widget_class_bind_template_callback (widget_class, gtk_combo_box_menu_hide); gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_COMBO_BOX_ACCESSIBLE); gtk_widget_class_set_css_name (widget_class, "combobox"); @@ -1001,17 +1003,30 @@ gtk_combo_box_cell_editable_init (GtkCellEditableIface *iface) iface->start_editing = gtk_combo_box_start_editing; } +static gboolean +gtk_combo_box_row_separator_func (GtkTreeModel *model, + GtkTreeIter *iter, + GtkComboBox *combo) +{ + GtkComboBoxPrivate *priv = combo->priv; + + if (priv->row_separator_func) + return priv->row_separator_func (model, iter, priv->row_separator_data); + + return FALSE; +} + static void gtk_combo_box_init (GtkComboBox *combo_box) { GtkComboBoxPrivate *priv; GtkCssNode *widget_node; GtkStyleContext *context; + GtkTreeMenu *menu; combo_box->priv = gtk_combo_box_get_instance_private (combo_box); priv = combo_box->priv; - priv->popup_widget = NULL; priv->wrap_width = 0; priv->active = -1; @@ -1033,6 +1048,7 @@ gtk_combo_box_init (GtkComboBox *combo_box) priv->id_column = -1; g_type_ensure (GTK_TYPE_ICON); + g_type_ensure (GTK_TYPE_TREE_MENU); gtk_widget_init_template (GTK_WIDGET (combo_box)); gtk_widget_add_events (priv->button, GDK_SCROLL_MASK); @@ -1048,6 +1064,17 @@ gtk_combo_box_init (GtkComboBox *combo_box) gtk_combo_box_allocate, gtk_combo_box_render, NULL, NULL); + + menu = GTK_TREE_MENU (priv->popup_widget); + _gtk_tree_menu_set_wrap_width (menu, priv->wrap_width); + _gtk_tree_menu_set_row_span_column (menu, priv->row_column); + _gtk_tree_menu_set_column_span_column (menu, priv->col_column); + _gtk_tree_menu_set_row_separator_func (menu, + (GtkTreeViewRowSeparatorFunc)gtk_combo_box_row_separator_func, + combo_box, NULL); + gtk_menu_attach_to_widget (GTK_MENU (menu), + GTK_WIDGET (combo_box), + NULL); } static void @@ -1335,17 +1362,8 @@ gtk_combo_box_remove (GtkContainer *container, gtk_widget_queue_resize (GTK_WIDGET (container)); - if (priv->popup_widget) - { - gtk_combo_box_menu_destroy (combo_box); - gtk_menu_detach (GTK_MENU (priv->popup_widget)); - priv->popup_widget = NULL; - } - gtk_combo_box_create_child (combo_box); - gtk_combo_box_menu_setup (combo_box); - if (gtk_tree_row_reference_valid (priv->active_row)) { path = gtk_tree_row_reference_get_path (priv->active_row); @@ -1385,25 +1403,6 @@ gtk_combo_box_menu_hide (GtkWidget *menu, FALSE); } -static void -gtk_combo_box_detacher (GtkWidget *widget, - GtkMenu *menu) -{ - GtkComboBox *combo_box = GTK_COMBO_BOX (widget); - GtkComboBoxPrivate *priv = combo_box->priv; - - g_return_if_fail (priv->popup_widget == (GtkWidget *) menu); - - g_signal_handlers_disconnect_by_func (menu->priv->toplevel, - gtk_combo_box_menu_show, - combo_box); - g_signal_handlers_disconnect_by_func (menu->priv->toplevel, - gtk_combo_box_menu_hide, - combo_box); - - priv->popup_widget = NULL; -} - static gboolean cell_layout_is_sensitive (GtkCellLayout *layout) { @@ -1982,91 +1981,6 @@ gtk_combo_box_scroll_event (GtkWidget *widget, return TRUE; } -/* - * menu style - */ -static gboolean -gtk_combo_box_row_separator_func (GtkTreeModel *model, - GtkTreeIter *iter, - GtkComboBox *combo) -{ - GtkComboBoxPrivate *priv = combo->priv; - - if (priv->row_separator_func) - return priv->row_separator_func (model, iter, priv->row_separator_data); - - return FALSE; -} - -static void -gtk_combo_box_menu_setup (GtkComboBox *combo_box) -{ - GtkComboBoxPrivate *priv = combo_box->priv; - GtkWidget *menu; - - g_signal_connect (priv->button, "button-press-event", - G_CALLBACK (gtk_combo_box_menu_button_press), - combo_box); - - /* create our funky menu */ - menu = _gtk_tree_menu_new_with_area (priv->area); - gtk_widget_set_name (menu, "gtk-combobox-popup-menu"); - - _gtk_tree_menu_set_model (GTK_TREE_MENU (menu), priv->model); - - _gtk_tree_menu_set_wrap_width (GTK_TREE_MENU (menu), priv->wrap_width); - _gtk_tree_menu_set_row_span_column (GTK_TREE_MENU (menu), priv->row_column); - _gtk_tree_menu_set_column_span_column (GTK_TREE_MENU (menu), priv->col_column); - - g_signal_connect (menu, "menu-activate", - G_CALLBACK (gtk_combo_box_menu_activate), combo_box); - - /* Chain our row_separator_func through */ - _gtk_tree_menu_set_row_separator_func (GTK_TREE_MENU (menu), - (GtkTreeViewRowSeparatorFunc)gtk_combo_box_row_separator_func, - combo_box, NULL); - - g_signal_connect (menu, "key-press-event", - G_CALLBACK (gtk_combo_box_menu_key_press), combo_box); - - /* Set up the popup menu */ - if (priv->popup_widget) - gtk_menu_detach (GTK_MENU (priv->popup_widget)); - - priv->popup_widget = menu; - - /* - * Note that we connect to show/hide on the toplevel, not the - * menu itself, since the menu is not shown/hidden when it is - * popped up while torn-off. - */ - g_signal_connect (GTK_MENU (menu)->priv->toplevel, "show", - G_CALLBACK (gtk_combo_box_menu_show), combo_box); - g_signal_connect (GTK_MENU (menu)->priv->toplevel, "hide", - G_CALLBACK (gtk_combo_box_menu_hide), combo_box); - - gtk_menu_attach_to_widget (GTK_MENU (menu), - GTK_WIDGET (combo_box), - gtk_combo_box_detacher); -} - -static void -gtk_combo_box_menu_destroy (GtkComboBox *combo_box) -{ - GtkComboBoxPrivate *priv = combo_box->priv; - - g_signal_handlers_disconnect_matched (priv->button, - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, - gtk_combo_box_menu_button_press, NULL); - g_signal_handlers_disconnect_matched (priv->popup_widget, - G_SIGNAL_MATCH_DATA, - 0, 0, NULL, - gtk_combo_box_menu_activate, combo_box); - - /* changing the popup window will unref the menu and the children */ -} - /* callbacks */ static gboolean gtk_combo_box_menu_button_press (GtkWidget *widget, @@ -2221,16 +2135,8 @@ gtk_combo_box_menu_key_press (GtkWidget *widget, static GtkCellArea * gtk_combo_box_cell_layout_get_area (GtkCellLayout *cell_layout) { - GtkComboBox *combo = GTK_COMBO_BOX (cell_layout); - GtkComboBoxPrivate *priv = combo->priv; - - if (G_UNLIKELY (!priv->area)) - { - priv->area = gtk_cell_area_box_new (); - g_object_ref_sink (priv->area); - } - - return priv->area; + GtkComboBox *combo_box = GTK_COMBO_BOX (cell_layout); + return combo_box->priv->area; } /* @@ -2915,7 +2821,6 @@ gtk_combo_box_destroy (GtkWidget *widget) priv->box = NULL; priv->button = NULL; priv->arrow = NULL; - priv->cell_view = NULL; _gtk_bin_set_child (GTK_BIN (combo_box), NULL); } @@ -3019,18 +2924,8 @@ gtk_combo_box_constructed (GObject *object) G_OBJECT_CLASS (gtk_combo_box_parent_class)->constructed (object); - if (!priv->area) - { - priv->area = gtk_cell_area_box_new (); - g_object_ref_sink (priv->area); - } - gtk_combo_box_create_child (combo_box); - /* Create the popup menu, if it doesn’t already exist. */ - if (!priv->popup_widget) - gtk_combo_box_menu_setup (combo_box); - if (priv->has_entry) { priv->text_renderer = gtk_cell_renderer_text_new (); @@ -3041,7 +2936,6 @@ gtk_combo_box_constructed (GObject *object) } } - static void gtk_combo_box_dispose (GObject* object) { @@ -3050,17 +2944,14 @@ gtk_combo_box_dispose (GObject* object) if (priv->popup_widget) { - gtk_combo_box_menu_destroy (combo_box); + /* Stop menu destruction triggering toggle on a now-invalid button */ + g_signal_handlers_disconnect_by_func (priv->popup_widget, + gtk_combo_box_menu_hide, + combo_box); gtk_menu_detach (GTK_MENU (priv->popup_widget)); priv->popup_widget = NULL; } - if (priv->area) - { - g_object_unref (priv->area); - priv->area = NULL; - } - gtk_combo_box_unset_model (combo_box); G_OBJECT_CLASS (gtk_combo_box_parent_class)->dispose (object); diff --git a/gtk/ui/gtkcombobox.ui b/gtk/ui/gtkcombobox.ui index 2e6ac30a2b..0a8ac8ba98 100644 --- a/gtk/ui/gtkcombobox.ui +++ b/gtk/ui/gtkcombobox.ui @@ -26,6 +26,7 @@ + end @@ -34,4 +35,12 @@ + + + area + + + + +