* Copyright (C) 2002, 2003 Kristian Rietveld <kris@gtk.org> * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. #include <gtk/gtkversion.h> #if !GTK_CHECK_VERSION(2,4,0) #include <gtk/gtkarrow.h> #include <gtk/gtkbindings.h> #include "gtkcelllayout.h" #include <gtk/gtkcellrenderertext.h> #include "gtkcellviewmenuitem.h" #include <gtk/gtkeventbox.h> #include <gtk/gtkframe.h> #include <gtk/gtkliststore.h> #include <gtk/gtktogglebutton.h> #include <gtk/gtktreeselection.h> #include <gtk/gtktreeprivate.h> #include <gtk/gtkvseparator.h> #include <gtk/gtkwindow.h> #include <gtk/gtkversion.h> #include <gdk/gdkkeysyms.h> #include <gobject/gvaluecollector.h> /* WELCOME, to THE house of evil code */ typedef struct _ComboCellInfo ComboCellInfo; GtkCellLayoutDataFunc func; struct _GtkComboBoxPrivate GtkTreeViewColumn *column; GtkWidget *cell_view_frame; guint popup_in_progress : 1; /* While debugging this evil code, I have learned that * there are actually 4 modes to this widget, which can * be characterized as follows * 1) menu mode, no child added * cell_view -> GtkCellView, regular child * cell_view_frame -> NULL * button -> GtkToggleButton set_parent to combo * separator -> child of box * popup_widget -> GtkMenu * 2) menu mode, child added * cell_view_frame -> NULL * button -> GtkToggleButton set_parent to combo * arrow -> GtkArrow, child of button * popup_widget -> GtkMenu * 3) list mode, no child added * tree_view -> GtkTreeView, child of popup_frame * cell_view -> GtkCellView, regular child * cell_view_frame -> GtkFrame, set parent to combo * button -> GtkToggleButton, set_parent to combo * arrow -> GtkArrow, child of button * popup_widget -> tree_view * popup_window -> GtkWindow * popup_frame -> GtkFrame, child of popup_window * 4) list mode, child added * tree_view -> GtkTreeView, child of popup_frame * cell_view_frame -> NULL * button -> GtkToggleButton, set_parent to combo * arrow -> GtkArrow, child of button * popup_widget -> tree_view * popup_window -> GtkWindow * popup_frame -> GtkFrame, child of popup_window static GtkBinClass *parent_class = NULL; static guint combo_box_signals[LAST_SIGNAL] = {0,}; static void gtk_combo_box_class_init (GtkComboBoxClass *klass); static void gtk_combo_box_cell_layout_init (GtkCellLayoutIface *iface); static void gtk_combo_box_init (GtkComboBox *combo_box); static void gtk_combo_box_finalize (GObject *object); static void gtk_combo_box_destroy (GtkObject *object); static void gtk_combo_box_set_property (GObject *object, static void gtk_combo_box_get_property (GObject *object, static void gtk_combo_box_state_changed (GtkWidget *widget, static void gtk_combo_box_style_set (GtkWidget *widget, static void gtk_combo_box_button_toggled (GtkWidget *widget, static void gtk_combo_box_add (GtkContainer *container, static void gtk_combo_box_remove (GtkContainer *container, static ComboCellInfo *gtk_combo_box_get_cell_info (GtkComboBox *combo_box, static void gtk_combo_box_menu_show (GtkWidget *menu, static void gtk_combo_box_menu_hide (GtkWidget *menu, static void gtk_combo_box_set_popup_widget (GtkComboBox *combo_box, #if GTK_CHECK_VERSION(2,2,0) static void gtk_combo_box_menu_position_below (GtkMenu *menu, static void gtk_combo_box_menu_position_over (GtkMenu *menu, static void gtk_combo_box_menu_position (GtkMenu *menu, static gint gtk_combo_box_calc_requested_width (GtkComboBox *combo_box, static void gtk_combo_box_remeasure (GtkComboBox *combo_box); static void gtk_combo_box_unset_model (GtkComboBox *combo_box); static void gtk_combo_box_size_request (GtkWidget *widget, GtkRequisition *requisition); static void gtk_combo_box_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static void gtk_combo_box_forall (GtkContainer *container, gboolean include_internals, static gboolean gtk_combo_box_expose_event (GtkWidget *widget, static gboolean gtk_combo_box_scroll_event (GtkWidget *widget, static void gtk_combo_box_set_active_internal (GtkComboBox *combo_box, static gboolean gtk_combo_box_key_press (GtkWidget *widget, /* listening to the model */ static void gtk_combo_box_model_row_inserted (GtkTreeModel *model, static void gtk_combo_box_model_row_deleted (GtkTreeModel *model, static void gtk_combo_box_model_rows_reordered (GtkTreeModel *model, static void gtk_combo_box_model_row_changed (GtkTreeModel *model, static void gtk_combo_box_list_position (GtkComboBox *combo_box, static void gtk_combo_box_list_setup (GtkComboBox *combo_box); static void gtk_combo_box_list_destroy (GtkComboBox *combo_box); static void gtk_combo_box_list_remove_grabs (GtkComboBox *combo_box); static gboolean gtk_combo_box_list_button_released (GtkWidget *widget, static gboolean gtk_combo_box_list_key_press (GtkWidget *widget, static gboolean gtk_combo_box_list_button_pressed (GtkWidget *widget, static void gtk_combo_box_list_row_changed (GtkTreeModel *model, static void gtk_combo_box_menu_setup (GtkComboBox *combo_box, static void gtk_combo_box_menu_fill (GtkComboBox *combo_box); static void gtk_combo_box_menu_destroy (GtkComboBox *combo_box); static void gtk_combo_box_item_get_size (GtkComboBox *combo_box, static void gtk_combo_box_relayout_item (GtkComboBox *combo_box, static void gtk_combo_box_relayout (GtkComboBox *combo_box); static gboolean gtk_combo_box_menu_button_press (GtkWidget *widget, static void gtk_combo_box_menu_item_activate (GtkWidget *item, static void gtk_combo_box_menu_row_inserted (GtkTreeModel *model, static void gtk_combo_box_menu_row_deleted (GtkTreeModel *model, static void gtk_combo_box_menu_rows_reordered (GtkTreeModel *model, static void gtk_combo_box_menu_row_changed (GtkTreeModel *model, static gboolean gtk_combo_box_menu_key_press (GtkWidget *widget, static void gtk_combo_box_cell_layout_pack_start (GtkCellLayout *layout, static void gtk_combo_box_cell_layout_pack_end (GtkCellLayout *layout, static void gtk_combo_box_cell_layout_clear (GtkCellLayout *layout); static void gtk_combo_box_cell_layout_add_attribute (GtkCellLayout *layout, static void gtk_combo_box_cell_layout_set_cell_data_func (GtkCellLayout *layout, GtkCellLayoutDataFunc func, static void gtk_combo_box_cell_layout_clear_attributes (GtkCellLayout *layout, static void gtk_combo_box_cell_layout_reorder (GtkCellLayout *layout, static gboolean gtk_combo_box_mnemonic_activate (GtkWidget *widget, static void cell_view_sync_cells (GtkComboBox *combo_box, #if !GTK_CHECK_VERSION(2,4,0) static void gtk_menu_attach (GtkMenu *menu, gtk_combo_box_get_type (void) static GType combo_box_type = 0; static const GTypeInfo combo_box_info = sizeof (GtkComboBoxClass), NULL, /* base_finalize */ (GClassInitFunc) gtk_combo_box_class_init, NULL, /* class_finalize */ (GInstanceInitFunc) gtk_combo_box_init static const GInterfaceInfo cell_layout_info = (GInterfaceInitFunc) gtk_combo_box_cell_layout_init, combo_box_type = g_type_register_static (GTK_TYPE_BIN, g_type_add_interface_static (combo_box_type, gtk_combo_box_class_init (GtkComboBoxClass *klass) GObjectClass *object_class; GtkBindingSet *binding_set; GtkObjectClass *gtk_object_class; GtkContainerClass *container_class; GtkWidgetClass *widget_class; binding_set = gtk_binding_set_by_class (klass); container_class = (GtkContainerClass *)klass; container_class->forall = gtk_combo_box_forall; container_class->add = gtk_combo_box_add; container_class->remove = gtk_combo_box_remove; widget_class = (GtkWidgetClass *)klass; widget_class->size_allocate = gtk_combo_box_size_allocate; widget_class->size_request = gtk_combo_box_size_request; widget_class->expose_event = gtk_combo_box_expose_event; widget_class->scroll_event = gtk_combo_box_scroll_event; widget_class->mnemonic_activate = gtk_combo_box_mnemonic_activate; widget_class->style_set = gtk_combo_box_style_set; widget_class->state_changed = gtk_combo_box_state_changed; gtk_object_class = (GtkObjectClass *)klass; gtk_object_class->destroy = gtk_combo_box_destroy; object_class = (GObjectClass *)klass; object_class->finalize = gtk_combo_box_finalize; object_class->set_property = gtk_combo_box_set_property; object_class->get_property = gtk_combo_box_get_property; parent_class = g_type_class_peek_parent (klass); combo_box_signals[CHANGED] = G_OBJECT_CLASS_TYPE (klass), G_STRUCT_OFFSET (GtkComboBoxClass, changed), g_cclosure_marshal_VOID__VOID, g_object_class_install_property (object_class, g_param_spec_object ("model", P_("The model for the combo box"), g_object_class_install_property (object_class, g_param_spec_int ("wrap_width", P_("Wrap width for layouting the items in a grid"), g_object_class_install_property (object_class, g_param_spec_int ("row_span_column", P_("TreeModel column containing the row span values"), g_object_class_install_property (object_class, g_param_spec_int ("column_span_column", P_("Column span column"), P_("TreeModel column containing the column span values"), g_object_class_install_property (object_class, g_param_spec_int ("active", P_("The item which is currently active"), gtk_widget_class_install_style_property (widget_class, g_param_spec_boolean ("appears-as-list", P_("Whether combobox dropdowns should look like lists rather than menus"), gtk_combo_box_cell_layout_init (GtkCellLayoutIface *iface) iface->pack_start = gtk_combo_box_cell_layout_pack_start; iface->pack_end = gtk_combo_box_cell_layout_pack_end; iface->clear = gtk_combo_box_cell_layout_clear; iface->add_attribute = gtk_combo_box_cell_layout_add_attribute; iface->set_cell_data_func = gtk_combo_box_cell_layout_set_cell_data_func; iface->clear_attributes = gtk_combo_box_cell_layout_clear_attributes; iface->reorder = gtk_combo_box_cell_layout_reorder; gtk_combo_box_init (GtkComboBox *combo_box) combo_box->priv = g_new0(GtkComboBoxPrivate,1); combo_box->priv->cell_view = gtk_cell_view_new (); gtk_widget_set_parent (combo_box->priv->cell_view, GTK_WIDGET (combo_box)); GTK_BIN (combo_box)->child = combo_box->priv->cell_view; gtk_widget_show (combo_box->priv->cell_view); combo_box->priv->width = 0; combo_box->priv->wrap_width = 0; combo_box->priv->active_item = -1; combo_box->priv->col_column = -1; combo_box->priv->row_column = -1; gtk_combo_box_set_property (GObject *object, GtkComboBox *combo_box = GTK_COMBO_BOX (object); gtk_combo_box_set_model (combo_box, g_value_get_object (value)); gtk_combo_box_set_wrap_width (combo_box, g_value_get_int (value)); case PROP_ROW_SPAN_COLUMN: gtk_combo_box_set_row_span_column (combo_box, g_value_get_int (value)); case PROP_COLUMN_SPAN_COLUMN: gtk_combo_box_set_column_span_column (combo_box, g_value_get_int (value)); gtk_combo_box_set_active (combo_box, g_value_get_int (value)); gtk_combo_box_get_property (GObject *object, GtkComboBox *combo_box = GTK_COMBO_BOX (object); g_value_set_object (value, combo_box->priv->model); g_value_set_int (value, combo_box->priv->wrap_width); case PROP_ROW_SPAN_COLUMN: g_value_set_int (value, combo_box->priv->row_column); case PROP_COLUMN_SPAN_COLUMN: g_value_set_int (value, combo_box->priv->col_column); g_value_set_int (value, gtk_combo_box_get_active (combo_box)); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); gtk_combo_box_state_changed (GtkWidget *widget, GtkComboBox *combo_box = GTK_COMBO_BOX (widget); if (GTK_WIDGET_REALIZED (widget)) if (combo_box->priv->tree_view && combo_box->priv->cell_view) gtk_cell_view_set_background_color (GTK_CELL_VIEW (combo_box->priv->cell_view), &widget->style->base[GTK_WIDGET_STATE (widget)]); gtk_widget_queue_draw (widget); gtk_combo_box_check_appearance (GtkComboBox *combo_box) gboolean appears_as_list; /* if wrap_width > 0, then we are in grid-mode and forced to use if (combo_box->priv->wrap_width) gtk_widget_style_get (GTK_WIDGET (combo_box), "appears-as-list", &appears_as_list, /* Destroy all the menu mode widgets, if they exist. */ if (GTK_IS_MENU (combo_box->priv->popup_widget)) gtk_combo_box_menu_destroy (combo_box); /* Create the list mode widgets, if they don't already exist. */ if (!GTK_IS_TREE_VIEW (combo_box->priv->tree_view)) gtk_combo_box_list_setup (combo_box); /* Destroy all the list mode widgets, if they exist. */ if (GTK_IS_TREE_VIEW (combo_box->priv->tree_view)) gtk_combo_box_list_destroy (combo_box); /* Create the menu mode widgets, if they don't already exist. */ if (!GTK_IS_MENU (combo_box->priv->popup_widget)) gtk_combo_box_menu_setup (combo_box, TRUE); gtk_combo_box_style_set (GtkWidget *widget, GtkComboBox *combo_box = GTK_COMBO_BOX (widget); gtk_combo_box_check_appearance (combo_box); if (combo_box->priv->tree_view && combo_box->priv->cell_view) gtk_cell_view_set_background_color (GTK_CELL_VIEW (combo_box->priv->cell_view), &widget->style->base[GTK_WIDGET_STATE (widget)]); gtk_combo_box_button_toggled (GtkWidget *widget, GtkComboBox *combo_box = GTK_COMBO_BOX (data); if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) if (!combo_box->priv->popup_in_progress) gtk_combo_box_popup (combo_box); gtk_combo_box_popdown (combo_box); gtk_combo_box_add (GtkContainer *container, GtkComboBox *combo_box = GTK_COMBO_BOX (container); if (combo_box->priv->cell_view && combo_box->priv->cell_view->parent) gtk_widget_unparent (combo_box->priv->cell_view); GTK_BIN (container)->child = NULL; gtk_widget_queue_resize (GTK_WIDGET (container)); gtk_widget_set_parent (widget, GTK_WIDGET (container)); GTK_BIN (container)->child = widget; if (combo_box->priv->cell_view && widget != combo_box->priv->cell_view) /* since the cell_view was unparented, it's gone now */ combo_box->priv->cell_view = NULL; if (!combo_box->priv->tree_view && combo_box->priv->separator) gtk_container_remove (GTK_CONTAINER (combo_box->priv->separator->parent), combo_box->priv->separator); combo_box->priv->separator = NULL; gtk_widget_queue_resize (GTK_WIDGET (container)); else if (combo_box->priv->cell_view_frame) gtk_widget_unparent (combo_box->priv->cell_view_frame); combo_box->priv->cell_view_frame = NULL; gtk_combo_box_remove (GtkContainer *container, GtkComboBox *combo_box = GTK_COMBO_BOX (container); gboolean appears_as_list; gtk_widget_unparent (widget); GTK_BIN (container)->child = NULL; if (combo_box->priv->destroying) gtk_widget_queue_resize (GTK_WIDGET (container)); if (!combo_box->priv->tree_view) gtk_combo_box_list_destroy (combo_box); else if (GTK_IS_MENU (combo_box->priv->popup_widget)) gtk_combo_box_menu_destroy (combo_box); gtk_menu_detach (GTK_MENU (combo_box->priv->popup_widget)); combo_box->priv->popup_widget = NULL; if (!combo_box->priv->cell_view) combo_box->priv->cell_view = gtk_cell_view_new (); gtk_widget_set_parent (combo_box->priv->cell_view, GTK_WIDGET (container)); GTK_BIN (container)->child = combo_box->priv->cell_view; gtk_widget_show (combo_box->priv->cell_view); gtk_cell_view_set_model (GTK_CELL_VIEW (combo_box->priv->cell_view), cell_view_sync_cells (combo_box, GTK_CELL_VIEW (combo_box->priv->cell_view)); gtk_combo_box_list_setup (combo_box); gtk_combo_box_menu_setup (combo_box, TRUE); gtk_combo_box_set_active_internal (combo_box, combo_box->priv->active_item); gtk_combo_box_get_cell_info (GtkComboBox *combo_box, for (i = combo_box->priv->cells; i; i = i->next) ComboCellInfo *info = (ComboCellInfo *)i->data; if (info && info->cell == cell) gtk_combo_box_menu_show (GtkWidget *menu, GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button), combo_box->priv->popup_in_progress = FALSE; gtk_combo_box_menu_hide (GtkWidget *menu, GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button), gtk_combo_box_detacher (GtkWidget *widget, g_return_if_fail (GTK_IS_COMBO_BOX (widget)); combo_box = GTK_COMBO_BOX (widget); g_return_if_fail (combo_box->priv->popup_widget == (GtkWidget*) menu); g_signal_handlers_disconnect_by_func (menu, g_signal_handlers_disconnect_by_func (menu, combo_box->priv->popup_widget = NULL; gtk_combo_box_set_popup_widget (GtkComboBox *combo_box, if (GTK_IS_MENU (combo_box->priv->popup_widget)) gtk_menu_detach (GTK_MENU (combo_box->priv->popup_widget)); combo_box->priv->popup_widget = NULL; else if (combo_box->priv->popup_widget) gtk_container_remove (GTK_CONTAINER (combo_box->priv->popup_frame), combo_box->priv->popup_widget); g_object_unref (G_OBJECT (combo_box->priv->popup_widget)); combo_box->priv->popup_widget = NULL; if (combo_box->priv->popup_window) gtk_widget_destroy (combo_box->priv->popup_window); combo_box->priv->popup_window = NULL; combo_box->priv->popup_frame = NULL; combo_box->priv->popup_widget = popup; g_signal_connect (popup, "show", G_CALLBACK (gtk_combo_box_menu_show), combo_box); g_signal_connect (popup, "hide", G_CALLBACK (gtk_combo_box_menu_hide), combo_box); gtk_menu_attach_to_widget (GTK_MENU (popup), if (!combo_box->priv->popup_window) combo_box->priv->popup_window = gtk_window_new (GTK_WINDOW_POPUP); gtk_window_set_resizable (GTK_WINDOW (combo_box->priv->popup_window), FALSE); #if GTK_CHECK_VERSION(2,2,0) gtk_window_set_screen (GTK_WINDOW (combo_box->priv->popup_window), gtk_widget_get_screen (GTK_WIDGET (combo_box))); combo_box->priv->popup_frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (combo_box->priv->popup_frame), gtk_container_add (GTK_CONTAINER (combo_box->priv->popup_window), combo_box->priv->popup_frame); gtk_widget_show (combo_box->priv->popup_frame); gtk_container_add (GTK_CONTAINER (combo_box->priv->popup_frame), g_object_ref (G_OBJECT (popup)); combo_box->priv->popup_widget = popup; #if GTK_CHECK_VERSION(2,2,0) gtk_combo_box_menu_position_below (GtkMenu *menu, GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); /* FIXME: is using the size request here broken? */ child = GTK_BIN (combo_box)->child; gdk_window_get_origin (child->window, &sx, &sy); if (GTK_WIDGET_NO_WINDOW (child)) sx += child->allocation.x; sy += child->allocation.y; gtk_widget_size_request (GTK_WIDGET (menu), &req); if (gtk_widget_get_direction (GTK_WIDGET (combo_box)) == GTK_TEXT_DIR_LTR) *x = sx + child->allocation.width - req.width; screen = gtk_widget_get_screen (GTK_WIDGET (combo_box)); monitor_num = gdk_screen_get_monitor_at_window (screen, GTK_WIDGET (combo_box)->window); gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor); else if (*x + req.width > monitor.x + monitor.width) *x = monitor.x + monitor.width - req.width; if (monitor.y + monitor.height - *y - child->allocation.height >= req.height) *y += child->allocation.height; else if (*y - monitor.y >= req.height) else if (monitor.y + monitor.height - *y - child->allocation.height > *y - monitor.y) *y += child->allocation.height; gtk_combo_box_menu_position_over (GtkMenu *menu, GtkRequisition requisition; g_return_if_fail (GTK_IS_COMBO_BOX (user_data)); combo_box = GTK_COMBO_BOX (user_data); widget = GTK_WIDGET (combo_box); gtk_widget_get_child_requisition (GTK_WIDGET (menu), &requisition); menu_width = requisition.width; active = gtk_menu_get_active (GTK_MENU (combo_box->priv->popup_widget)); gdk_window_get_origin (widget->window, &menu_xpos, &menu_ypos); menu_xpos += widget->allocation.x; menu_ypos += widget->allocation.y + widget->allocation.height / 2 - 2; gtk_widget_get_child_requisition (active, &requisition); menu_ypos -= requisition.height / 2; children = GTK_MENU_SHELL (combo_box->priv->popup_widget)->children; if (GTK_WIDGET_VISIBLE (child)) gtk_widget_get_child_requisition (child, &requisition); menu_ypos -= requisition.height; children = children->next; if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) menu_xpos = menu_xpos + widget->allocation.width - menu_width; /* Clamp the position on screen */ screen_width = gdk_screen_get_width (gtk_widget_get_screen (widget)); else if ((menu_xpos + menu_width) > screen_width) menu_xpos -= ((menu_xpos + menu_width) - screen_width); gtk_combo_box_menu_position (GtkMenu *menu, combo_box = GTK_COMBO_BOX (user_data); if (combo_box->priv->wrap_width > 0 || combo_box->priv->cell_view == NULL) gtk_combo_box_menu_position_below (menu, x, y, push_in, user_data); menu_item = gtk_menu_get_active (GTK_MENU (combo_box->priv->popup_widget)); gtk_menu_shell_select_item (GTK_MENU_SHELL (combo_box->priv->popup_widget), gtk_combo_box_menu_position_over (menu, x, y, push_in, user_data); gtk_combo_box_list_position (GtkComboBox *combo_box, GtkRequisition popup_req; #if GTK_CHECK_VERSION(2,2,0) sample = GTK_BIN (combo_box)->child; *width = sample->allocation.width; gtk_widget_size_request (combo_box->priv->popup_window, &popup_req); *height = popup_req.height; gdk_window_get_origin (sample->window, x, y); if (combo_box->priv->cell_view_frame) *x -= GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width + GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness; *width += 2 * (GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width + GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness); if (GTK_WIDGET_NO_WINDOW (sample)) *x += sample->allocation.x; *y += sample->allocation.y; #if GTK_CHECK_VERSION(2,2,0) screen = gtk_widget_get_screen (GTK_WIDGET (combo_box)); monitor_num = gdk_screen_get_monitor_at_window (screen, GTK_WIDGET (combo_box)->window); gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor); else if (*x + *width > monitor.x + monitor.width) *x = monitor.x + monitor.width - *width; if (*y + sample->allocation.height + *height <= monitor.y + monitor.height) *y += sample->allocation.height; * @combo_box: a #GtkComboBox * Pops up the menu or dropdown list of @combo_box. * This function is mostly intended for use by accessibility technologies; * applications should have little use for it. gtk_combo_box_popup (GtkComboBox *combo_box) gint x, y, width, height; g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); if (GTK_WIDGET_MAPPED (combo_box->priv->popup_widget)) if (GTK_IS_MENU (combo_box->priv->popup_widget)) gtk_menu_set_active (GTK_MENU (combo_box->priv->popup_widget), combo_box->priv->active_item); if (combo_box->priv->wrap_width == 0) GtkRequisition requisition; width = GTK_WIDGET (combo_box)->allocation.width; gtk_widget_size_request (combo_box->priv->popup_widget, &requisition); gtk_widget_set_size_request (combo_box->priv->popup_widget, MAX (width, requisition.width), -1); gtk_menu_popup (GTK_MENU (combo_box->priv->popup_widget), #if GTK_CHECK_VERSION(2,2,0) gtk_combo_box_menu_position, gtk_widget_show_all (combo_box->priv->popup_frame); gtk_combo_box_list_position (combo_box, &x, &y, &width, &height); gtk_widget_set_size_request (combo_box->priv->popup_window, width, -1); gtk_window_move (GTK_WINDOW (combo_box->priv->popup_window), x, y); gtk_widget_show (combo_box->priv->popup_window); gtk_widget_grab_focus (combo_box->priv->popup_window); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button), if (!GTK_WIDGET_HAS_FOCUS (combo_box->priv->tree_view)) gdk_keyboard_grab (combo_box->priv->popup_window->window, FALSE, GDK_CURRENT_TIME); gtk_widget_grab_focus (combo_box->priv->tree_view); gtk_grab_add (combo_box->priv->popup_window); gdk_pointer_grab (combo_box->priv->popup_window->window, TRUE, GDK_BUTTON_RELEASE_MASK | NULL, NULL, GDK_CURRENT_TIME); gtk_grab_add (combo_box->priv->tree_view); * @combo_box: a #GtkComboBox * Hides the menu or dropdown list of @combo_box. * This function is mostly intended for use by accessibility technologies; * applications should have little use for it. gtk_combo_box_popdown (GtkComboBox *combo_box) g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); if (!GTK_WIDGET_REALIZED (GTK_WIDGET (combo_box))) if (GTK_IS_MENU (combo_box->priv->popup_widget)) gtk_menu_popdown (GTK_MENU (combo_box->priv->popup_widget)); gtk_combo_box_list_remove_grabs (combo_box); gtk_widget_hide_all (combo_box->priv->popup_window); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button), gtk_combo_box_calc_requested_width (GtkComboBox *combo_box, if (combo_box->priv->cell_view) gtk_widget_style_get (combo_box->priv->cell_view, "focus-line-width", &padding, /* add some pixels for good measure */ padding += BONUS_PADDING; if (combo_box->priv->cell_view) gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (combo_box->priv->cell_view), return req.width + padding; gtk_combo_box_remeasure (GtkComboBox *combo_box) if (!combo_box->priv->model || !gtk_tree_model_get_iter_first (combo_box->priv->model, &iter)) combo_box->priv->width = 0; #if GTK_CHECK_VERSION(2,2,0) path = gtk_tree_path_new_from_indices (0, -1); path = gtk_tree_path_new_first(); if (combo_box->priv->cell_view) gtk_widget_style_get (combo_box->priv->cell_view, "focus-line-width", &padding, /* add some pixels for good measure */ padding += BONUS_PADDING; if (combo_box->priv->cell_view) gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (combo_box->priv->cell_view), combo_box->priv->width = MAX (combo_box->priv->width, gtk_tree_path_next (path); while (gtk_tree_model_iter_next (combo_box->priv->model, &iter)); gtk_tree_path_free (path); gtk_combo_box_size_request (GtkWidget *widget, GtkRequisition *requisition) GtkComboBox *combo_box = GTK_COMBO_BOX (widget); gtk_widget_size_request (GTK_BIN (widget)->child, &bin_req); gtk_combo_box_remeasure (combo_box); bin_req.width = MAX (bin_req.width, combo_box->priv->width); gtk_combo_box_check_appearance (combo_box); if (!combo_box->priv->tree_view) if (combo_box->priv->cell_view) GtkRequisition button_req, sep_req, arrow_req; gint border_width, xthickness, ythickness; gtk_widget_size_request (combo_box->priv->button, &button_req); border_width = GTK_CONTAINER (combo_box->priv->button)->border_width; xthickness = combo_box->priv->button->style->xthickness; ythickness = combo_box->priv->button->style->ythickness; bin_req.width = MAX (bin_req.width, combo_box->priv->width); gtk_widget_size_request (combo_box->priv->separator, &sep_req); gtk_widget_size_request (combo_box->priv->arrow, &arrow_req); height = MAX (sep_req.height, arrow_req.height); height = MAX (height, bin_req.height); width = bin_req.width + sep_req.width + arrow_req.width; height += border_width + 1 + ythickness * 2 + 4; width += border_width + 1 + xthickness * 2 + 4; requisition->width = width; requisition->height = height; gtk_widget_size_request (combo_box->priv->button, &but_req); requisition->width = bin_req.width + but_req.width; requisition->height = MAX (bin_req.height, but_req.height); GtkRequisition button_req, frame_req; if (combo_box->priv->cell_view_frame) gtk_widget_size_request (combo_box->priv->cell_view_frame, &frame_req); requisition->width += 2 * (GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width + GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness); requisition->height += 2 * (GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width + GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness); gtk_widget_size_request (combo_box->priv->button, &button_req); requisition->height = MAX (requisition->height, button_req.height); requisition->width += button_req.width; gtk_combo_box_size_allocate (GtkWidget *widget, GtkAllocation *allocation) GtkComboBox *combo_box = GTK_COMBO_BOX (widget); gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL; widget->allocation = *allocation; gtk_combo_box_check_appearance (combo_box); if (!combo_box->priv->tree_view) if (combo_box->priv->cell_view) gint border_width, xthickness, ythickness; gtk_widget_size_allocate (combo_box->priv->button, allocation); /* set some things ready */ border_width = GTK_CONTAINER (combo_box->priv->button)->border_width; xthickness = combo_box->priv->button->style->xthickness; ythickness = combo_box->priv->button->style->ythickness; child.x = allocation->x + border_width + 1 + xthickness + 2; child.y = allocation->y + border_width + 1 + ythickness + 2; width = MAX(1, allocation->width - (border_width + 1 + xthickness * 2 + 4)); /* handle the children */ gtk_widget_size_request (combo_box->priv->arrow, &req); child.height = MAX(1, allocation->height - 2 * (child.y - allocation->y)); child.x += width - req.width; gtk_widget_size_allocate (combo_box->priv->arrow, &child); gtk_widget_size_request (combo_box->priv->separator, &req); gtk_widget_size_allocate (combo_box->priv->separator, &child); child.width = MAX(1, allocation->x + allocation->width - (border_width + 1 + xthickness + 2) - child.x); child.x = allocation->x + border_width + 1 + xthickness + 2; child.width = MAX(1, child.width - child.x); gtk_widget_size_allocate (GTK_BIN (widget)->child, &child); gtk_widget_size_request (combo_box->priv->button, &req); child.x = allocation->x + allocation->width - req.width; child.height = allocation->height; gtk_widget_size_allocate (combo_box->priv->button, &child); child.x = allocation->x + req.width; child.width = MAX(1, allocation->width - req.width); gtk_widget_size_allocate (GTK_BIN (widget)->child, &child); gtk_widget_size_request (combo_box->priv->button, &req); child.x = allocation->x + allocation->width - req.width; child.height = allocation->height; gtk_widget_size_allocate (combo_box->priv->button, &child); child.x = allocation->x + req.width; child.width = MAX (1, allocation->width - req.width); child.height = allocation->height; if (combo_box->priv->cell_view_frame) gtk_widget_size_allocate (combo_box->priv->cell_view_frame, &child); GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width + GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness; GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width + GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness; GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width + GTK_WIDGET (combo_box->priv->cell_view_frame)->style->xthickness); child.width = MAX(1,child.width); GTK_CONTAINER (combo_box->priv->cell_view_frame)->border_width + GTK_WIDGET (combo_box->priv->cell_view_frame)->style->ythickness); child.height = MAX(1,child.height); gtk_widget_size_allocate (GTK_BIN (combo_box)->child, &child); gtk_combo_box_unset_model (GtkComboBox *combo_box) if (combo_box->priv->model) g_signal_handler_disconnect (combo_box->priv->model, combo_box->priv->inserted_id); g_signal_handler_disconnect (combo_box->priv->model, combo_box->priv->deleted_id); g_signal_handler_disconnect (combo_box->priv->model, combo_box->priv->reordered_id); g_signal_handler_disconnect (combo_box->priv->model, combo_box->priv->changed_id); if (!combo_box->priv->tree_view) if (combo_box->priv->popup_widget) gtk_container_foreach (GTK_CONTAINER (combo_box->priv->popup_widget), (GtkCallback)gtk_widget_destroy, NULL); if (combo_box->priv->model) g_object_unref (G_OBJECT (combo_box->priv->model)); combo_box->priv->model = NULL; if (combo_box->priv->cell_view) gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (combo_box->priv->cell_view), NULL); gtk_combo_box_forall (GtkContainer *container, gboolean include_internals, GtkComboBox *combo_box = GTK_COMBO_BOX (container); if (combo_box->priv->button) (* callback) (combo_box->priv->button, callback_data); if (combo_box->priv->cell_view_frame) (* callback) (combo_box->priv->cell_view_frame, callback_data); if (GTK_BIN (container)->child) (* callback) (GTK_BIN (container)->child, callback_data); gtk_combo_box_expose_event (GtkWidget *widget, GtkComboBox *combo_box = GTK_COMBO_BOX (widget); if (!combo_box->priv->tree_view) gtk_container_propagate_expose (GTK_CONTAINER (widget), combo_box->priv->button, event); gtk_container_propagate_expose (GTK_CONTAINER (widget), combo_box->priv->button, event); if (combo_box->priv->cell_view_frame) gtk_container_propagate_expose (GTK_CONTAINER (widget), combo_box->priv->cell_view_frame, event); gtk_container_propagate_expose (GTK_CONTAINER (widget), GTK_BIN (widget)->child, event); gtk_combo_box_scroll_event (GtkWidget *widget, GtkComboBox *combo_box = GTK_COMBO_BOX (widget); index = gtk_combo_box_get_active (combo_box); items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL); if (event->direction == GDK_SCROLL_UP) gtk_combo_box_set_active (combo_box, CLAMP (index, 0, items - 1)); cell_view_sync_cells (GtkComboBox *combo_box, for (k = combo_box->priv->cells; k; k = k->next) ComboCellInfo *info = (ComboCellInfo *)k->data; if (info->pack == GTK_PACK_START) gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cell_view), info->cell, info->expand); else if (info->pack == GTK_PACK_END) gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (cell_view), info->cell, info->expand); gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (cell_view), info->func, info->func_data, NULL); for (j = info->attributes; j; j = j->next->next) gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (cell_view), GPOINTER_TO_INT (j->next->data)); gtk_combo_box_menu_setup (GtkComboBox *combo_box, if (combo_box->priv->cell_view) combo_box->priv->button = gtk_toggle_button_new (); g_signal_connect (combo_box->priv->button, "toggled", G_CALLBACK (gtk_combo_box_button_toggled), combo_box); g_signal_connect_after (combo_box->priv->button, "key_press_event", G_CALLBACK (gtk_combo_box_key_press), combo_box); gtk_widget_set_parent (combo_box->priv->button, GTK_BIN (combo_box)->child->parent); combo_box->priv->box = gtk_hbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (combo_box->priv->button), combo_box->priv->separator = gtk_vseparator_new (); gtk_container_add (GTK_CONTAINER (combo_box->priv->box), combo_box->priv->separator); combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); gtk_container_add (GTK_CONTAINER (combo_box->priv->box), gtk_widget_show_all (combo_box->priv->button); combo_box->priv->button = gtk_toggle_button_new (); g_signal_connect (combo_box->priv->button, "toggled", G_CALLBACK (gtk_combo_box_button_toggled), combo_box); g_signal_connect_after (combo_box, "key_press_event", G_CALLBACK (gtk_combo_box_key_press), combo_box); gtk_widget_set_parent (combo_box->priv->button, GTK_BIN (combo_box)->child->parent); combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); gtk_container_add (GTK_CONTAINER (combo_box->priv->button), gtk_widget_show_all (combo_box->priv->button); g_signal_connect (combo_box->priv->button, "button_press_event", G_CALLBACK (gtk_combo_box_menu_button_press), /* create our funky menu */ g_signal_connect (menu, "key_press_event", G_CALLBACK (gtk_combo_box_menu_key_press), combo_box); gtk_combo_box_set_popup_widget (combo_box, menu); gtk_combo_box_menu_fill (combo_box); gtk_combo_box_menu_fill (GtkComboBox *combo_box) if (!combo_box->priv->model) items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL); menu = combo_box->priv->popup_widget; for (i = 0; i < items; i++) #if GTK_CHECK_VERSION(2,2,0) path = gtk_tree_path_new_from_indices (i, -1); g_snprintf(buf, sizeof(buf), "%d", i); path = gtk_tree_path_new_from_string(buf); tmp = gtk_cell_view_menu_item_new_from_model (combo_box->priv->model, g_signal_connect (tmp, "activate", G_CALLBACK (gtk_combo_box_menu_item_activate), cell_view_sync_cells (combo_box, GTK_CELL_VIEW (GTK_BIN (tmp)->child)); gtk_menu_shell_append (GTK_MENU_SHELL (menu), tmp); if (combo_box->priv->wrap_width) gtk_combo_box_relayout_item (combo_box, i); gtk_tree_path_free (path); gtk_combo_box_menu_destroy (GtkComboBox *combo_box) g_signal_handlers_disconnect_matched (combo_box->priv->button, gtk_combo_box_menu_button_press, NULL); /* unparent will remove our latest ref */ gtk_widget_unparent (combo_box->priv->button); combo_box->priv->box = NULL; combo_box->priv->button = NULL; combo_box->priv->arrow = NULL; combo_box->priv->separator = NULL; /* changing the popup window will unref the menu and the children */ gtk_combo_box_item_get_size (GtkComboBox *combo_box, gtk_tree_model_iter_nth_child (combo_box->priv->model, &iter, NULL, index_); if (combo_box->priv->col_column == -1) gtk_tree_model_get (combo_box->priv->model, &iter, combo_box->priv->col_column, cols, if (combo_box->priv->row_column == -1) gtk_tree_model_get (combo_box->priv->model, &iter, combo_box->priv->row_column, rows, menu_occupied (GtkMenu *menu, g_return_val_if_fail (GTK_IS_MENU (menu), TRUE); g_return_val_if_fail (left_attach < right_attach, TRUE); g_return_val_if_fail (top_attach < bottom_attach, TRUE); for (i = GTK_MENU_SHELL (menu)->children; i; i = i->next) gboolean h_intersect = FALSE; gboolean v_intersect = FALSE; gtk_container_child_get (GTK_CONTAINER (menu), i->data, /* look if this item intersects with the given coordinates */ h_intersect = left_attach <= l && l <= right_attach; h_intersect &= left_attach <= r && r <= right_attach; v_intersect = top_attach <= t && t <= bottom_attach; v_intersect &= top_attach <= b && b <= bottom_attach; if (h_intersect && v_intersect) gtk_combo_box_relayout_item (GtkComboBox *combo_box, gint current_col = 0, current_row = 0; menu = combo_box->priv->popup_widget; if (!GTK_IS_MENU_SHELL (menu)) list = gtk_container_get_children (GTK_CONTAINER (menu)); nth = g_list_nth (list, index); gtk_combo_box_item_get_size (combo_box, index, &cols, &rows); if (combo_box->priv->col_column == -1 && combo_box->priv->row_column == -1 && gtk_container_child_get (GTK_CONTAINER (menu), "right_attach", ¤t_col, "top_attach", ¤t_row, if (current_col + cols > combo_box->priv->wrap_width) /* look for a good spot */ if (current_col + cols > combo_box->priv->wrap_width) if (!menu_occupied (GTK_MENU (menu), current_col, current_col + cols, current_row, current_row + rows)) gtk_menu_attach (GTK_MENU (menu), item, current_col, current_col + cols, current_row, current_row + rows); gtk_combo_box_relayout (GtkComboBox *combo_box) menu = combo_box->priv->popup_widget; /* do nothing unless we are in menu style and realized */ if (combo_box->priv->tree_view || !GTK_IS_MENU_SHELL (menu)) /* get rid of all children */ list = gtk_container_get_children (GTK_CONTAINER (menu)); for (j = g_list_last (list); j; j = j->prev) gtk_container_remove (GTK_CONTAINER (menu), j->data); gtk_combo_box_menu_fill (combo_box); gtk_combo_box_menu_button_press (GtkWidget *widget, GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); if (! GTK_IS_MENU (combo_box->priv->popup_widget)) if (event->type == GDK_BUTTON_PRESS && event->button == 1) combo_box->priv->popup_in_progress = TRUE; gtk_menu_set_active (GTK_MENU (combo_box->priv->popup_widget), combo_box->priv->active_item); if (combo_box->priv->wrap_width == 0) GtkRequisition requisition; width = GTK_WIDGET (combo_box)->allocation.width; gtk_widget_size_request (combo_box->priv->popup_widget, &requisition); gtk_widget_set_size_request (combo_box->priv->popup_widget, MAX (width, requisition.width), -1); gtk_menu_popup (GTK_MENU (combo_box->priv->popup_widget), #if GTK_CHECK_VERSION(2,2,0) gtk_combo_box_menu_position, combo_box, event->button, event->time); gtk_combo_box_menu_item_activate (GtkWidget *item, GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); menu = combo_box->priv->popup_widget; g_return_if_fail (GTK_IS_MENU (menu)); index = g_list_index (GTK_MENU_SHELL (menu)->children, item); gtk_combo_box_set_active (combo_box, index); gtk_combo_box_model_row_inserted (GtkTreeModel *model, GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); gint index = gtk_tree_path_get_indices (path)[0]; if (combo_box->priv->active_item >= index) combo_box->priv->active_item++; if (!combo_box->priv->tree_view) gtk_combo_box_menu_row_inserted (model, path, iter, user_data); gtk_combo_box_model_row_deleted (GtkTreeModel *model, GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); gint index = gtk_tree_path_get_indices (path)[0]; if (!combo_box->priv->tree_view) gtk_combo_box_menu_row_deleted (model, path, user_data); if (index == combo_box->priv->active_item) gint items = gtk_tree_model_iter_n_children (model, NULL); gtk_combo_box_set_active_internal (combo_box, -1); gtk_combo_box_set_active_internal (combo_box, index - 1); gtk_combo_box_set_active_internal (combo_box, index); else if (combo_box->priv->active_item > index) combo_box->priv->active_item--; gtk_combo_box_model_rows_reordered (GtkTreeModel *model, GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); gint items = gtk_tree_model_iter_n_children (model, NULL); for (i = 0; i < items; i++) if (new_order[i] == combo_box->priv->active_item) combo_box->priv->active_item = i; if (!combo_box->priv->tree_view) gtk_combo_box_menu_rows_reordered (model, path, iter, new_order, user_data); gtk_combo_box_model_row_changed (GtkTreeModel *model, GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); gint index = gtk_tree_path_get_indices (path)[0]; if (index == combo_box->priv->active_item && combo_box->priv->cell_view) gtk_widget_queue_resize (GTK_WIDGET (combo_box->priv->cell_view)); if (combo_box->priv->tree_view) gtk_combo_box_list_row_changed (model, path, iter, user_data); gtk_combo_box_menu_row_changed (model, path, iter, user_data); gtk_combo_box_menu_row_inserted (GtkTreeModel *model, GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); if (!combo_box->priv->popup_widget) menu = combo_box->priv->popup_widget; g_return_if_fail (GTK_IS_MENU (menu)); item = gtk_cell_view_menu_item_new_from_model (model, path); g_signal_connect (item, "activate", G_CALLBACK (gtk_combo_box_menu_item_activate), cell_view_sync_cells (combo_box, GTK_CELL_VIEW (GTK_BIN (item)->child)); gtk_menu_shell_insert (GTK_MENU_SHELL (menu), item, gtk_tree_path_get_indices (path)[0]); gtk_combo_box_menu_row_deleted (GtkTreeModel *model, GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); if (!combo_box->priv->popup_widget) index = gtk_tree_path_get_indices (path)[0]; menu = combo_box->priv->popup_widget; g_return_if_fail (GTK_IS_MENU (menu)); item = g_list_nth_data (GTK_MENU_SHELL (menu)->children, index); g_return_if_fail (GTK_IS_MENU_ITEM (item)); gtk_container_remove (GTK_CONTAINER (menu), item); gtk_combo_box_menu_rows_reordered (GtkTreeModel *model, GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); gtk_combo_box_relayout (combo_box); gtk_combo_box_menu_row_changed (GtkTreeModel *model, GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); if (!combo_box->priv->popup_widget) if (combo_box->priv->wrap_width) gtk_combo_box_relayout_item (combo_box, gtk_tree_path_get_indices (path)[0]); width = gtk_combo_box_calc_requested_width (combo_box, path); if (width > combo_box->priv->width) if (combo_box->priv->cell_view) gtk_widget_set_size_request (combo_box->priv->cell_view, width, -1); gtk_widget_queue_resize (combo_box->priv->cell_view); combo_box->priv->width = width; gtk_combo_box_list_setup (GtkComboBox *combo_box) combo_box->priv->button = gtk_toggle_button_new (); gtk_widget_set_parent (combo_box->priv->button, GTK_BIN (combo_box)->child->parent); g_signal_connect (combo_box->priv->button, "button_press_event", G_CALLBACK (gtk_combo_box_list_button_pressed), combo_box); g_signal_connect (combo_box->priv->button, "toggled", G_CALLBACK (gtk_combo_box_button_toggled), combo_box); g_signal_connect_after (combo_box, "key_press_event", G_CALLBACK (gtk_combo_box_key_press), combo_box); combo_box->priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); gtk_container_add (GTK_CONTAINER (combo_box->priv->button), combo_box->priv->separator = NULL; gtk_widget_show_all (combo_box->priv->button); if (combo_box->priv->cell_view) combo_box->priv->cell_view_frame = gtk_frame_new (NULL); gtk_widget_set_parent (combo_box->priv->cell_view_frame, GTK_BIN (combo_box)->child->parent); gtk_frame_set_shadow_type (GTK_FRAME (combo_box->priv->cell_view_frame), gtk_cell_view_set_background_color (GTK_CELL_VIEW (combo_box->priv->cell_view), >K_WIDGET (combo_box)->style->base[GTK_WIDGET_STATE (combo_box)]); combo_box->priv->box = gtk_event_box_new (); gtk_event_box_set_visible_window (GTK_EVENT_BOX (combo_box->priv->box), gtk_container_add (GTK_CONTAINER (combo_box->priv->cell_view_frame), gtk_widget_show_all (combo_box->priv->cell_view_frame); g_signal_connect (combo_box->priv->box, "button_press_event", G_CALLBACK (gtk_combo_box_list_button_pressed), combo_box->priv->tree_view = gtk_tree_view_new (); sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view)); gtk_tree_selection_set_mode (sel, GTK_SELECTION_BROWSE); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (combo_box->priv->tree_view), _gtk_tree_view_set_hover_selection (GTK_TREE_VIEW (combo_box->priv->tree_view), if (combo_box->priv->model) gtk_tree_view_set_model (GTK_TREE_VIEW (combo_box->priv->tree_view), g_signal_connect (combo_box->priv->tree_view, "button_press_event", G_CALLBACK (gtk_combo_box_list_button_pressed), g_signal_connect (combo_box->priv->tree_view, "button_release_event", G_CALLBACK (gtk_combo_box_list_button_released), g_signal_connect (combo_box->priv->tree_view, "key_press_event", G_CALLBACK (gtk_combo_box_list_key_press), combo_box->priv->column = gtk_tree_view_column_new (); gtk_tree_view_append_column (GTK_TREE_VIEW (combo_box->priv->tree_view), combo_box->priv->column); for (i = combo_box->priv->cells; i; i = i->next) ComboCellInfo *info = (ComboCellInfo *)i->data; if (info->pack == GTK_PACK_START) gtk_tree_view_column_pack_start (combo_box->priv->column, info->cell, info->expand); else if (info->pack == GTK_PACK_END) gtk_tree_view_column_pack_end (combo_box->priv->column, info->cell, info->expand); for (j = info->attributes; j; j = j->next->next) gtk_tree_view_column_add_attribute (combo_box->priv->column, GPOINTER_TO_INT (j->next->data)); if (combo_box->priv->active_item != -1) #if GTK_CHECK_VERSION(2,2,0) path = gtk_tree_path_new_from_indices (combo_box->priv->active_item, -1); g_snprintf(buf, sizeof(buf), "%d", combo_box->priv->active_item); path = gtk_tree_path_new_from_string(buf); gtk_tree_view_set_cursor (GTK_TREE_VIEW (combo_box->priv->tree_view), gtk_tree_path_free (path); /* set sample/popup widgets */ gtk_combo_box_set_popup_widget (combo_box, combo_box->priv->tree_view); gtk_widget_show (combo_box->priv->tree_view); gtk_combo_box_list_destroy (GtkComboBox *combo_box) g_signal_handlers_disconnect_matched (combo_box->priv->tree_view, 0, 0, NULL, NULL, combo_box); g_signal_handlers_disconnect_matched (combo_box->priv->button, gtk_combo_box_list_button_pressed, if (combo_box->priv->box) g_signal_handlers_disconnect_matched (combo_box->priv->box, gtk_combo_box_list_button_pressed, /* destroy things (unparent will kill the latest ref from us) * last unref on button will destroy the arrow gtk_widget_unparent (combo_box->priv->button); combo_box->priv->button = NULL; combo_box->priv->arrow = NULL; if (combo_box->priv->cell_view) g_object_set (G_OBJECT (combo_box->priv->cell_view), if (combo_box->priv->cell_view_frame) gtk_widget_unparent (combo_box->priv->cell_view_frame); combo_box->priv->cell_view_frame = NULL; combo_box->priv->box = NULL; gtk_widget_destroy (combo_box->priv->tree_view); combo_box->priv->tree_view = NULL; combo_box->priv->popup_widget = NULL; gtk_combo_box_list_remove_grabs (GtkComboBox *combo_box) if (combo_box->priv->tree_view && GTK_WIDGET_HAS_GRAB (combo_box->priv->tree_view)) gtk_grab_remove (combo_box->priv->tree_view); if (combo_box->priv->popup_window && GTK_WIDGET_HAS_GRAB (combo_box->priv->popup_window)) gtk_grab_remove (combo_box->priv->popup_window); gdk_keyboard_ungrab (GDK_CURRENT_TIME); gdk_pointer_ungrab (GDK_CURRENT_TIME); gtk_combo_box_list_button_pressed (GtkWidget *widget, GtkComboBox *combo_box = GTK_COMBO_BOX (data); GtkWidget *ewidget = gtk_get_event_widget ((GdkEvent *)event); if (ewidget == combo_box->priv->tree_view) if ((ewidget != combo_box->priv->button && ewidget != combo_box->priv->box) || gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (combo_box->priv->button))) gtk_combo_box_popup (combo_box); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo_box->priv->button), combo_box->priv->popup_in_progress = TRUE; gtk_combo_box_list_button_released (GtkWidget *widget, GtkTreePath *path = NULL; GtkComboBox *combo_box = GTK_COMBO_BOX (data); gboolean popup_in_progress = FALSE; GtkWidget *ewidget = gtk_get_event_widget ((GdkEvent *)event); if (combo_box->priv->popup_in_progress) popup_in_progress = TRUE; combo_box->priv->popup_in_progress = FALSE; if (ewidget != combo_box->priv->tree_view) if (ewidget == combo_box->priv->button && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (combo_box->priv->button))) gtk_combo_box_popdown (combo_box); /* released outside treeview */ if (ewidget != combo_box->priv->button) gtk_combo_box_popdown (combo_box); /* select something cool */ ret = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), return TRUE; /* clicked outside window? */ gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]); gtk_combo_box_popdown (combo_box); gtk_tree_path_free (path); gtk_combo_box_key_press (GtkWidget *widget, GtkComboBox *combo_box = GTK_COMBO_BOX (data); guint state = event->state & gtk_accelerator_get_default_mod_mask (); gint index = gtk_combo_box_get_active (combo_box); if (combo_box->priv->model) items = gtk_tree_model_iter_n_children (combo_box->priv->model, NULL); if ((event->keyval == GDK_Down || event->keyval == GDK_KP_Down) && gtk_combo_box_popup (combo_box); gtk_combo_box_set_active (combo_box, CLAMP (new_index, 0, items - 1)); gtk_combo_box_menu_key_press (GtkWidget *widget, GtkComboBox *combo_box = GTK_COMBO_BOX (data); guint state = event->state & gtk_accelerator_get_default_mod_mask (); if ((event->keyval == GDK_Up || event->keyval == GDK_KP_Up) && gtk_combo_box_popdown (combo_box); gtk_combo_box_list_key_press (GtkWidget *widget, GtkComboBox *combo_box = GTK_COMBO_BOX (data); guint state = event->state & gtk_accelerator_get_default_mod_mask (); if (event->keyval == GDK_Escape || ((event->keyval == GDK_Up || event->keyval == GDK_KP_Up) && /* reset active item -- this is incredibly lame and ugly */ gtk_combo_box_set_active (combo_box, gtk_combo_box_get_active (combo_box)); gtk_combo_box_popdown (combo_box); if (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter || event->keyval == GDK_space || event->keyval == GDK_KP_Space) GtkTreeModel *model = NULL; if (combo_box->priv->model) GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view)); ret = gtk_tree_selection_get_selected (sel, &model, &iter); path = gtk_tree_model_get_path (model, &iter); gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]); gtk_tree_path_free (path); gtk_combo_box_popdown (combo_box); gtk_combo_box_list_row_changed (GtkTreeModel *model, GtkComboBox *combo_box = GTK_COMBO_BOX (data); width = gtk_combo_box_calc_requested_width (combo_box, path); if (width > combo_box->priv->width) if (combo_box->priv->cell_view) gtk_widget_set_size_request (combo_box->priv->cell_view, width, -1); gtk_widget_queue_resize (combo_box->priv->cell_view); combo_box->priv->width = width; * GtkCellLayout implementation gtk_combo_box_cell_layout_pack_start (GtkCellLayout *layout, g_return_if_fail (GTK_IS_COMBO_BOX (layout)); g_return_if_fail (GTK_IS_CELL_RENDERER (cell)); combo_box = GTK_COMBO_BOX (layout); g_object_ref (G_OBJECT (cell)); gtk_object_sink (GTK_OBJECT (cell)); info = g_new0 (ComboCellInfo, 1); info->pack = GTK_PACK_START; combo_box->priv->cells = g_slist_append (combo_box->priv->cells, info); if (combo_box->priv->cell_view) gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box->priv->cell_view), if (combo_box->priv->column) gtk_tree_view_column_pack_start (combo_box->priv->column, cell, expand); menu = combo_box->priv->popup_widget; list = gtk_container_get_children (GTK_CONTAINER (menu)); for (i = list; i; i = i->next) if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data)) view = GTK_CELL_VIEW (GTK_BIN (i->data)->child); view = GTK_CELL_VIEW (i->data); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (view), cell, expand); gtk_combo_box_cell_layout_pack_end (GtkCellLayout *layout, g_return_if_fail (GTK_IS_COMBO_BOX (layout)); g_return_if_fail (GTK_IS_CELL_RENDERER (cell)); combo_box = GTK_COMBO_BOX (layout); g_object_ref (G_OBJECT (cell)); gtk_object_sink (GTK_OBJECT (cell)); info = g_new0 (ComboCellInfo, 1); info->pack = GTK_PACK_END; combo_box->priv->cells = g_slist_append (combo_box->priv->cells, info); if (combo_box->priv->cell_view) gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (combo_box->priv->cell_view), if (combo_box->priv->column) gtk_tree_view_column_pack_end (combo_box->priv->column, cell, expand); menu = combo_box->priv->popup_widget; list = gtk_container_get_children (GTK_CONTAINER (menu)); for (i = list; i; i = i->next) if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data)) view = GTK_CELL_VIEW (GTK_BIN (i->data)->child); view = GTK_CELL_VIEW (i->data); gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (view), cell, expand); gtk_combo_box_cell_layout_clear (GtkCellLayout *layout) g_return_if_fail (GTK_IS_COMBO_BOX (layout)); combo_box = GTK_COMBO_BOX (layout); if (combo_box->priv->cell_view) gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo_box->priv->cell_view)); if (combo_box->priv->column) gtk_tree_view_column_clear (combo_box->priv->column); for (i = combo_box->priv->cells; i; i = i->next) ComboCellInfo *info = (ComboCellInfo *)i->data; gtk_combo_box_cell_layout_clear_attributes (layout, info->cell); g_object_unref (G_OBJECT (info->cell)); g_slist_free (combo_box->priv->cells); combo_box->priv->cells = NULL; menu = combo_box->priv->popup_widget; list = gtk_container_get_children (GTK_CONTAINER (menu)); for (i = list; i; i = i->next) if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data)) view = GTK_CELL_VIEW (GTK_BIN (i->data)->child); view = GTK_CELL_VIEW (i->data); gtk_cell_layout_clear (GTK_CELL_LAYOUT (view)); gtk_combo_box_cell_layout_add_attribute (GtkCellLayout *layout, g_return_if_fail (GTK_IS_COMBO_BOX (layout)); g_return_if_fail (GTK_IS_CELL_RENDERER (cell)); combo_box = GTK_COMBO_BOX (layout); info = gtk_combo_box_get_cell_info (combo_box, cell); info->attributes = g_slist_prepend (info->attributes, GINT_TO_POINTER (column)); info->attributes = g_slist_prepend (info->attributes, if (combo_box->priv->cell_view) gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box->priv->cell_view), cell, attribute, column); if (combo_box->priv->column) gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo_box->priv->column), cell, attribute, column); menu = combo_box->priv->popup_widget; list = gtk_container_get_children (GTK_CONTAINER (menu)); for (i = list; i; i = i->next) if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data)) view = GTK_CELL_VIEW (GTK_BIN (i->data)->child); view = GTK_CELL_VIEW (i->data); gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (view), cell, gtk_widget_queue_resize (GTK_WIDGET (combo_box)); gtk_combo_box_cell_layout_set_cell_data_func (GtkCellLayout *layout, GtkCellLayoutDataFunc func, g_return_if_fail (GTK_IS_COMBO_BOX (layout)); combo_box = GTK_COMBO_BOX (layout); info = gtk_combo_box_get_cell_info (combo_box, cell); g_return_if_fail (info != NULL); GDestroyNotify d = info->destroy; info->func_data = func_data; if (combo_box->priv->cell_view) gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo_box->priv->cell_view), cell, func, func_data, NULL); if (combo_box->priv->column) gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo_box->priv->column), cell, func, func_data, NULL); menu = combo_box->priv->popup_widget; list = gtk_container_get_children (GTK_CONTAINER (menu)); for (i = list; i; i = i->next) if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data)) view = GTK_CELL_VIEW (GTK_BIN (i->data)->child); view = GTK_CELL_VIEW (i->data); gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (view), cell, gtk_widget_queue_resize (GTK_WIDGET (combo_box)); gtk_combo_box_cell_layout_clear_attributes (GtkCellLayout *layout, g_return_if_fail (GTK_IS_COMBO_BOX (layout)); g_return_if_fail (GTK_IS_CELL_RENDERER (cell)); combo_box = GTK_COMBO_BOX (layout); info = gtk_combo_box_get_cell_info (combo_box, cell); while (list && list->next) g_slist_free (info->attributes); if (combo_box->priv->cell_view) gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (combo_box->priv->cell_view), cell); if (combo_box->priv->column) gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (combo_box->priv->column), cell); menu = combo_box->priv->popup_widget; list = gtk_container_get_children (GTK_CONTAINER (menu)); for (i = list; i; i = i->next) if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data)) view = GTK_CELL_VIEW (GTK_BIN (i->data)->child); view = GTK_CELL_VIEW (i->data); gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (view), cell); gtk_widget_queue_resize (GTK_WIDGET (combo_box)); gtk_combo_box_cell_layout_reorder (GtkCellLayout *layout, g_return_if_fail (GTK_IS_COMBO_BOX (layout)); g_return_if_fail (GTK_IS_CELL_RENDERER (cell)); combo_box = GTK_COMBO_BOX (layout); info = gtk_combo_box_get_cell_info (combo_box, cell); g_return_if_fail (info != NULL); g_return_if_fail (position >= 0); link = g_slist_find (combo_box->priv->cells, info); g_return_if_fail (link != NULL); combo_box->priv->cells = g_slist_remove_link (combo_box->priv->cells, link); combo_box->priv->cells = g_slist_insert (combo_box->priv->cells, info, if (combo_box->priv->cell_view) gtk_cell_layout_reorder (GTK_CELL_LAYOUT (combo_box->priv->cell_view), if (combo_box->priv->column) gtk_cell_layout_reorder (GTK_CELL_LAYOUT (combo_box->priv->column), menu = combo_box->priv->popup_widget; list = gtk_container_get_children (GTK_CONTAINER (menu)); for (i = list; i; i = i->next) if (GTK_IS_CELL_VIEW_MENU_ITEM (i->data)) view = GTK_CELL_VIEW (GTK_BIN (i->data)->child); view = GTK_CELL_VIEW (i->data); gtk_cell_layout_reorder (GTK_CELL_LAYOUT (view), cell, position); gtk_widget_queue_draw (GTK_WIDGET (combo_box)); * Creates a new empty #GtkComboBox. * Return value: A new #GtkComboBox. return GTK_WIDGET (g_object_new (GTK_TYPE_COMBO_BOX, NULL)); * gtk_combo_box_new_with_model: * @model: A #GtkTreeModel. * Creates a new #GtkComboBox with the model initialized to @model. * Return value: A new #GtkComboBox. gtk_combo_box_new_with_model (GtkTreeModel *model) g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL); combo_box = GTK_COMBO_BOX (g_object_new (GTK_TYPE_COMBO_BOX, return GTK_WIDGET (combo_box); * gtk_combo_box_set_wrap_width: * @combo_box: A #GtkComboBox. * @width: Preferred number of columns. * Sets the wrap width of @combo_box to be @width. The wrap width is basically * the preferred number of columns when you want to the popup to be layed out gtk_combo_box_set_wrap_width (GtkComboBox *combo_box, g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); g_return_if_fail (width >= 0); if (width != combo_box->priv->wrap_width) combo_box->priv->wrap_width = width; gtk_combo_box_check_appearance (combo_box); gtk_combo_box_relayout (combo_box); g_object_notify (G_OBJECT (combo_box), "wrap_width"); * gtk_combo_box_set_row_span_column: * @combo_box: A #GtkComboBox. * @row_span: A column in the model passed during construction. * Sets the column with row span information for @combo_box to be @row_span. * The row span column contains integers which indicate how many rows gtk_combo_box_set_row_span_column (GtkComboBox *combo_box, g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); col = gtk_tree_model_get_n_columns (combo_box->priv->model); g_return_if_fail (row_span >= 0 && row_span < col); if (row_span != combo_box->priv->row_column) combo_box->priv->row_column = row_span; gtk_combo_box_relayout (combo_box); g_object_notify (G_OBJECT (combo_box), "row_span_column"); * gtk_combo_box_set_column_span_column: * @combo_box: A #GtkComboBox. * @column_span: A column in the model passed during construction. * Sets the column with column span information for @combo_box to be * @column_span. The column span column contains integers which indicate * how many columns an item should span. gtk_combo_box_set_column_span_column (GtkComboBox *combo_box, g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); col = gtk_tree_model_get_n_columns (combo_box->priv->model); g_return_if_fail (column_span >= 0 && column_span < col); if (column_span != combo_box->priv->col_column) combo_box->priv->col_column = column_span; gtk_combo_box_relayout (combo_box); g_object_notify (G_OBJECT (combo_box), "column_span_column"); * gtk_combo_box_get_active: * @combo_box: A #GtkComboBox. * Returns the index of the currently active item, or -1 if there's no * Return value: An integer which is the index of the currently active item, or * -1 if there's no active item. gtk_combo_box_get_active (GtkComboBox *combo_box) g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), 0); return combo_box->priv->active_item; * gtk_combo_box_set_active: * @combo_box: A #GtkComboBox. * @index_: An index in the model passed during construction, or -1 to have * Sets the active item of @combo_box to be the item at @index. gtk_combo_box_set_active (GtkComboBox *combo_box, g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); /* -1 means "no item selected" */ g_return_if_fail (index_ >= -1); if (combo_box->priv->active_item == index_) gtk_combo_box_set_active_internal (combo_box, index_); gtk_combo_box_set_active_internal (GtkComboBox *combo_box, combo_box->priv->active_item = index; if (combo_box->priv->tree_view) gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (combo_box->priv->tree_view))); GtkMenu *menu = GTK_MENU (combo_box->priv->popup_widget); gtk_menu_set_active (menu, -1); if (combo_box->priv->cell_view) gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (combo_box->priv->cell_view), NULL); #if GTK_CHECK_VERSION(2,2,0) path = gtk_tree_path_new_from_indices (index, -1); g_snprintf(buf, sizeof(buf), "%d", index); path = gtk_tree_path_new_from_string(buf); if (combo_box->priv->tree_view) gtk_tree_view_set_cursor (GTK_TREE_VIEW (combo_box->priv->tree_view), path, NULL, FALSE); GtkMenu *menu = GTK_MENU (combo_box->priv->popup_widget); gtk_menu_set_active (GTK_MENU (menu), index); if (combo_box->priv->cell_view) gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (combo_box->priv->cell_view), path); gtk_tree_path_free (path); g_signal_emit_by_name (combo_box, "changed", NULL, NULL); * gtk_combo_box_get_active_iter: * @combo_box: A #GtkComboBox * @iter: The uninitialized #GtkTreeIter. * Sets @iter to point to the current active item, if it exists. * Return value: %TRUE, if @iter was set gtk_combo_box_get_active_iter (GtkComboBox *combo_box, #if !GTK_CHECK_VERSION(2,2,0) g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), FALSE); active = gtk_combo_box_get_active (combo_box); #if GTK_CHECK_VERSION(2,2,0) path = gtk_tree_path_new_from_indices (active, -1); g_snprintf(buf, sizeof(buf), "%d", active); path = gtk_tree_path_new_from_string(buf); retval = gtk_tree_model_get_iter (gtk_combo_box_get_model (combo_box), gtk_tree_path_free (path); * gtk_combo_box_set_active_iter: * @combo_box: A #GtkComboBox * @iter: The #GtkTreeIter. * Sets the current active item to be the one referenced by @iter. * @iter must correspond to a path of depth one. gtk_combo_box_set_active_iter (GtkComboBox *combo_box, g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); path = gtk_tree_model_get_path (gtk_combo_box_get_model (combo_box), iter); g_return_if_fail (path != NULL); g_return_if_fail (gtk_tree_path_get_depth (path) == 1); gtk_combo_box_set_active (combo_box, gtk_tree_path_get_indices (path)[0]); gtk_tree_path_free (path); * gtk_combo_box_set_model: * @combo_box: A #GtkComboBox. * @model: A #GtkTreeModel. * Sets the model used by @combo_box to be @model. Will unset a previously set * model (if applicable). If @model is %NULL, then it will unset the model. * Note that this function does not clear the cell renderers, you have to * call gtk_combo_box_cell_layout_clear() yourself if you need to set up * different cell renderers for the new model. gtk_combo_box_set_model (GtkComboBox *combo_box, g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); gtk_combo_box_unset_model (combo_box); g_return_if_fail (GTK_IS_TREE_MODEL (model)); if (model == combo_box->priv->model) if (combo_box->priv->model) gtk_combo_box_unset_model (combo_box); combo_box->priv->model = model; g_object_ref (G_OBJECT (combo_box->priv->model)); combo_box->priv->inserted_id = g_signal_connect (combo_box->priv->model, "row_inserted", G_CALLBACK (gtk_combo_box_model_row_inserted), combo_box->priv->deleted_id = g_signal_connect (combo_box->priv->model, "row_deleted", G_CALLBACK (gtk_combo_box_model_row_deleted), combo_box->priv->reordered_id = g_signal_connect (combo_box->priv->model, "rows_reordered", G_CALLBACK (gtk_combo_box_model_rows_reordered), combo_box->priv->changed_id = g_signal_connect (combo_box->priv->model, "row_changed", G_CALLBACK (gtk_combo_box_model_row_changed), if (combo_box->priv->tree_view) gtk_tree_view_set_model (GTK_TREE_VIEW (combo_box->priv->tree_view), if (combo_box->priv->popup_widget) gtk_combo_box_menu_fill (combo_box); if (combo_box->priv->cell_view) gtk_cell_view_set_model (GTK_CELL_VIEW (combo_box->priv->cell_view), * gtk_combo_box_get_model * @combo_box: A #GtkComboBox. * Returns the #GtkTreeModel which is acting as data source for @combo_box. * Return value: A #GtkTreeModel which was passed during construction. gtk_combo_box_get_model (GtkComboBox *combo_box) g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), NULL); return combo_box->priv->model; /* convenience API for simple text combos */ * gtk_combo_box_new_text: * Convenience function which constructs a new text combo box, which is a * #GtkComboBox just displaying strings. If you use this function to create * a text combo box, you should only manipulate its data source with the * following convenience functions: gtk_combo_box_append_text(), * gtk_combo_box_insert_text(), gtk_combo_box_prepend_text() and * gtk_combo_box_remove_text(). * Return value: A new text combo box. gtk_combo_box_new_text (void) store = gtk_list_store_new (1, G_TYPE_STRING); combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store)); cell = gtk_cell_renderer_text_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, TRUE); gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), cell, * gtk_combo_box_append_text: * @combo_box: A #GtkComboBox constructed using gtk_combo_box_new_text(). * Appends @string to the list of strings stored in @combo_box. Note that * you can only use this function with combo boxes constructed with * gtk_combo_box_new_text(). gtk_combo_box_append_text (GtkComboBox *combo_box, g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model)); g_return_if_fail (text != NULL); store = GTK_LIST_STORE (combo_box->priv->model); gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, 0, text, -1); * gtk_combo_box_insert_text: * @combo_box: A #GtkComboBox constructed using gtk_combo_box_new_text(). * @position: An index to insert @text. * Inserts @string at @position in the list of strings stored in @combo_box. * Note that you can only use this function with combo boxes constructed * with gtk_combo_box_new_text(). gtk_combo_box_insert_text (GtkComboBox *combo_box, g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model)); g_return_if_fail (position >= 0); g_return_if_fail (text != NULL); store = GTK_LIST_STORE (combo_box->priv->model); gtk_list_store_insert (store, &iter, position); gtk_list_store_set (store, &iter, 0, text, -1); * gtk_combo_box_prepend_text: * @combo_box: A #GtkComboBox constructed with gtk_combo_box_new_text(). * Prepends @string to the list of strings stored in @combo_box. Note that * you can only use this function with combo boxes constructed with * gtk_combo_box_new_text(). gtk_combo_box_prepend_text (GtkComboBox *combo_box, g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model)); g_return_if_fail (text != NULL); store = GTK_LIST_STORE (combo_box->priv->model); gtk_list_store_prepend (store, &iter); gtk_list_store_set (store, &iter, 0, text, -1); * gtk_combo_box_remove_text: * @combo_box: A #GtkComboBox constructed with gtk_combo_box_new_text(). * @position: Index of the item to remove. * Removes the string at @position from @combo_box. Note that you can only use * this function with combo boxes constructed with gtk_combo_box_new_text(). gtk_combo_box_remove_text (GtkComboBox *combo_box, g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); g_return_if_fail (GTK_IS_LIST_STORE (combo_box->priv->model)); g_return_if_fail (position >= 0); store = GTK_LIST_STORE (combo_box->priv->model); if (gtk_tree_model_iter_nth_child (combo_box->priv->model, &iter, gtk_list_store_remove (store, &iter); gtk_combo_box_mnemonic_activate (GtkWidget *widget, GtkComboBox *combo_box = GTK_COMBO_BOX (widget); gtk_widget_grab_focus (combo_box->priv->button); gtk_combo_box_destroy (GtkObject *object) GtkComboBox *combo_box = GTK_COMBO_BOX (object); gtk_combo_box_popdown (combo_box); combo_box->priv->destroying = 1; GTK_OBJECT_CLASS (parent_class)->destroy (object); combo_box->priv->cell_view = NULL; combo_box->priv->destroying = 0; gtk_combo_box_finalize (GObject *object) GtkComboBox *combo_box = GTK_COMBO_BOX (object); if (GTK_IS_MENU (combo_box->priv->popup_widget)) gtk_combo_box_menu_destroy (combo_box); gtk_menu_detach (GTK_MENU (combo_box->priv->popup_widget)); combo_box->priv->popup_widget = NULL; if (GTK_IS_TREE_VIEW (combo_box->priv->tree_view)) gtk_combo_box_list_destroy (combo_box); if (combo_box->priv->popup_window) gtk_widget_destroy (combo_box->priv->popup_window); gtk_combo_box_unset_model (combo_box); for (i = combo_box->priv->cells; i; i = i->next) ComboCellInfo *info = (ComboCellInfo *)i->data; GSList *list = info->attributes; info->destroy (info->func_data); while (list && list->next) g_slist_free (info->attributes); g_object_unref (G_OBJECT (info->cell)); g_slist_free (combo_box->priv->cells); g_free (combo_box->priv); G_OBJECT_CLASS (parent_class)->finalize (object); * Code below this point has been pulled in from gtkmenu.c in 2.4.14 * and is needed to provide gtk_menu_attach() gint effective_left_attach; gint effective_right_attach; gint effective_top_attach; gint effective_bottom_attach; #define ATTACH_INFO_KEY "gtk-menu-child-attach-info-key" get_attach_info (GtkWidget *child) GObject *object = G_OBJECT (child); AttachInfo *ai = g_object_get_data (object, ATTACH_INFO_KEY); ai = g_new0 (AttachInfo, 1); g_object_set_data_full (object, ATTACH_INFO_KEY, ai, g_free); * @child: a #GtkMenuItem. * @left_attach: The column number to attach the left side of the item to. * @right_attach: The column number to attach the right side of the item to. * @top_attach: The row number to attach the top of the item to. * @bottom_attach: The row number to attach the bottom of the item to. * Adds a new #GtkMenuItem to a (table) menu. The number of 'cells' that * an item will occupy is specified by @left_attach, @right_attach, * @top_attach and @bottom_attach. These each represent the leftmost, * rightmost, uppermost and lower column and row numbers of the table. * (Columns and rows are indexed from zero). * Note that this function is not related to gtk_menu_detach(). gtk_menu_attach (GtkMenu *menu, GtkMenuShell *menu_shell; g_return_if_fail (GTK_IS_MENU (menu)); g_return_if_fail (GTK_IS_MENU_ITEM (child)); g_return_if_fail (child->parent == NULL || child->parent == GTK_WIDGET (menu)); g_return_if_fail (left_attach < right_attach); g_return_if_fail (top_attach < bottom_attach); menu_shell = GTK_MENU_SHELL (menu); AttachInfo *ai = get_attach_info (child); ai->left_attach = left_attach; ai->right_attach = right_attach; ai->top_attach = top_attach; ai->bottom_attach = bottom_attach; menu_shell->children = g_list_append (menu_shell->children, child); gtk_widget_set_parent (child, GTK_WIDGET (menu)); menu_queue_resize (menu); gtk_container_child_set (GTK_CONTAINER (child->parent), child, "left_attach", left_attach, "right_attach", right_attach, "top_attach", top_attach, "bottom_attach", bottom_attach,