combobox: Move area and menu to .ui file

Now that priv->area is guaranteed to be constructed by us, and not
passed in by a user, we can move it to the .ui file and stop manually
managing its lifetime altogether. And once the area is there, we can
move the menu there too (and stop pointlessly destroying/rebuilding it).
This commit is contained in:
Daniel Boles 2017-01-21 20:23:27 +00:00
parent 439fcf7578
commit 8c980445e3
2 changed files with 48 additions and 148 deletions

View File

@ -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 doesnt 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);

View File

@ -26,6 +26,7 @@
</child>
</object>
</child>
<signal name="button-press-event" handler="gtk_combo_box_menu_button_press" swapped="no" />
</object>
<packing>
<property name="pack-type">end</property>
@ -34,4 +35,12 @@
</object>
</child>
</template>
<object class="GtkCellAreaBox" id="area" />
<object class="GtkTreeMenu" id="popup_widget">
<property name="cell-area">area</property>
<signal name="menu-activate" handler="gtk_combo_box_menu_activate" swapped="no" />
<signal name="key-press-event" handler="gtk_combo_box_menu_key_press" swapped="no" />
<signal name="show" handler="gtk_combo_box_menu_show" swapped="no" />
<signal name="hide" handler="gtk_combo_box_menu_hide" swapped="no" />
</object>
</interface>