X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkcombobox.c;h=f8ce6db0ee27b814c5cd6fdfdb1dd274ed6783eb;hb=f53ad339941a6cab1468eef279bd518992ae68bc;hp=f4459f46abaca118ec7efa55b212de6432986505;hpb=66882103cc59402783df5e2ec3571fa6ce6cc7fa;p=~andy%2Fgtk diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c index f4459f46a..f8ce6db0e 100644 --- a/gtk/gtkcombobox.c +++ b/gtk/gtkcombobox.c @@ -51,7 +51,6 @@ #include "gtkintl.h" #include "gtktreeprivate.h" -#include "gtkalias.h" /* WELCOME, to THE house of evil code */ @@ -69,7 +68,6 @@ struct _ComboCellInfo guint pack : 1; }; -#define GTK_COMBO_BOX_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_COMBO_BOX, GtkComboBoxPrivate)) struct _GtkComboBoxPrivate { @@ -109,8 +107,9 @@ struct _GtkComboBoxPrivate guint scroll_timer; guint resize_idle_id; - gint width; - gint height; + gint minimum_width; + gint natural_width; + GSList *cells; guint popup_in_progress : 1; @@ -127,6 +126,9 @@ struct _GtkComboBoxPrivate gpointer row_separator_data; GDestroyNotify row_separator_destroy; + GdkDevice *grab_pointer; + GdkDevice *grab_keyboard; + gchar *tearoff_title; }; @@ -219,7 +221,7 @@ static void gtk_combo_box_cell_layout_init (GtkCellLayoutIface *iface); static void gtk_combo_box_cell_editable_init (GtkCellEditableIface *iface); static void gtk_combo_box_dispose (GObject *object); static void gtk_combo_box_finalize (GObject *object); -static void gtk_combo_box_destroy (GtkObject *object); +static void gtk_combo_box_destroy (GtkWidget *widget); static void gtk_combo_box_set_property (GObject *object, guint prop_id, @@ -271,22 +273,20 @@ static void gtk_combo_box_menu_position (GtkMenu *menu, gint *push_in, gpointer user_data); -static gint gtk_combo_box_calc_requested_width (GtkComboBox *combo_box, - GtkTreePath *path); +static void gtk_combo_box_update_requested_width(GtkComboBox *combo_box, + GtkTreePath *path); 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, GtkCallback callback, gpointer callback_data); -static gboolean gtk_combo_box_expose_event (GtkWidget *widget, - GdkEventExpose *event); +static gboolean gtk_combo_box_draw (GtkWidget *widget, + cairo_t *cr); static gboolean gtk_combo_box_scroll_event (GtkWidget *widget, GdkEventScroll *event); static void gtk_combo_box_set_active_internal (GtkComboBox *combo_box, @@ -463,8 +463,23 @@ static void gtk_combo_box_buildable_custom_tag_end (GtkBuildable *bui gpointer *data); /* GtkCellEditable method implementations */ -static void gtk_combo_box_start_editing (GtkCellEditable *cell_editable, - GdkEvent *event); +static void gtk_combo_box_start_editing (GtkCellEditable *cell_editable, + GdkEvent *event); + +static void gtk_combo_box_get_preferred_width (GtkWidget *widget, + gint *minimum_size, + gint *natural_size); +static void gtk_combo_box_get_preferred_height (GtkWidget *widget, + gint *minimum_size, + gint *natural_size); +static void gtk_combo_box_get_preferred_width_for_height (GtkWidget *widget, + gint avail_size, + gint *minimum_size, + gint *natural_size); +static void gtk_combo_box_get_preferred_height_for_width (GtkWidget *widget, + gint avail_size, + gint *minimum_size, + gint *natural_size); G_DEFINE_TYPE_WITH_CODE (GtkComboBox, gtk_combo_box, GTK_TYPE_BIN, @@ -481,7 +496,6 @@ static void gtk_combo_box_class_init (GtkComboBoxClass *klass) { GObjectClass *object_class; - GtkObjectClass *gtk_object_class; GtkContainerClass *container_class; GtkWidgetClass *widget_class; GtkBindingSet *binding_set; @@ -495,16 +509,17 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass) 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->draw = gtk_combo_box_draw; widget_class->scroll_event = gtk_combo_box_scroll_event; widget_class->mnemonic_activate = gtk_combo_box_mnemonic_activate; widget_class->grab_focus = gtk_combo_box_grab_focus; 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; + widget_class->get_preferred_width = gtk_combo_box_get_preferred_width; + widget_class->get_preferred_height = gtk_combo_box_get_preferred_height; + widget_class->get_preferred_height_for_width = gtk_combo_box_get_preferred_height_for_width; + widget_class->get_preferred_width_for_height = gtk_combo_box_get_preferred_width_for_height; + widget_class->destroy = gtk_combo_box_destroy; object_class = (GObjectClass *)klass; object_class->dispose = gtk_combo_box_dispose; @@ -599,53 +614,53 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass) /* key bindings */ binding_set = gtk_binding_set_by_class (widget_class); - gtk_binding_entry_add_signal (binding_set, GDK_Down, GDK_MOD1_MASK, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Down, GDK_MOD1_MASK, "popup", 0); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, GDK_MOD1_MASK, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Down, GDK_MOD1_MASK, "popup", 0); - gtk_binding_entry_add_signal (binding_set, GDK_Up, GDK_MOD1_MASK, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Up, GDK_MOD1_MASK, "popdown", 0); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, GDK_MOD1_MASK, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Up, GDK_MOD1_MASK, "popdown", 0); - gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0, "popdown", 0); - gtk_binding_entry_add_signal (binding_set, GDK_Up, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Up, 0, "move-active", 1, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_UP); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Up, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Up, 0, "move-active", 1, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_UP); - gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Page_Up, 0, "move-active", 1, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_UP); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Up, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Page_Up, 0, "move-active", 1, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_UP); - gtk_binding_entry_add_signal (binding_set, GDK_Home, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Home, 0, "move-active", 1, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_START); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Home, 0, "move-active", 1, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_START); - gtk_binding_entry_add_signal (binding_set, GDK_Down, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Down, 0, "move-active", 1, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_DOWN); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Down, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Down, 0, "move-active", 1, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_DOWN); - gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_Page_Down, 0, "move-active", 1, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_DOWN); - gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Down, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Page_Down, 0, "move-active", 1, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_DOWN); - gtk_binding_entry_add_signal (binding_set, GDK_End, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_End, 0, "move-active", 1, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_END); - gtk_binding_entry_add_signal (binding_set, GDK_KP_End, 0, + gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_End, 0, "move-active", 1, GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_END); @@ -925,15 +940,21 @@ gtk_combo_box_cell_editable_init (GtkCellEditableIface *iface) static void gtk_combo_box_init (GtkComboBox *combo_box) { - GtkComboBoxPrivate *priv = GTK_COMBO_BOX_GET_PRIVATE (combo_box); + GtkComboBoxPrivate *priv; + + combo_box->priv = G_TYPE_INSTANCE_GET_PRIVATE (combo_box, + GTK_TYPE_COMBO_BOX, + GtkComboBoxPrivate); + priv = combo_box->priv; priv->cell_view = gtk_cell_view_new (); gtk_widget_set_parent (priv->cell_view, GTK_WIDGET (combo_box)); - GTK_BIN (combo_box)->child = priv->cell_view; + _gtk_bin_set_child (GTK_BIN (combo_box), priv->cell_view); gtk_widget_show (priv->cell_view); - priv->width = 0; - priv->height = 0; + priv->minimum_width = 0; + priv->natural_width = 0; + priv->wrap_width = 0; priv->active = -1; @@ -950,8 +971,6 @@ gtk_combo_box_init (GtkComboBox *combo_box) priv->focus_on_click = TRUE; priv->button_sensitivity = GTK_SENSITIVITY_AUTO; - combo_box->priv = priv; - gtk_combo_box_check_appearance (combo_box); } @@ -1031,7 +1050,7 @@ gtk_combo_box_get_property (GObject *object, GParamSpec *pspec) { GtkComboBox *combo_box = GTK_COMBO_BOX (object); - GtkComboBoxPrivate *priv = GTK_COMBO_BOX_GET_PRIVATE (combo_box); + GtkComboBoxPrivate *priv = combo_box->priv; switch (prop_id) { @@ -1096,11 +1115,11 @@ gtk_combo_box_state_changed (GtkWidget *widget, GtkComboBox *combo_box = GTK_COMBO_BOX (widget); GtkComboBoxPrivate *priv = combo_box->priv; - if (GTK_WIDGET_REALIZED (widget)) + if (gtk_widget_get_realized (widget)) { if (priv->tree_view && priv->cell_view) gtk_cell_view_set_background_color (GTK_CELL_VIEW (priv->cell_view), - &widget->style->base[GTK_WIDGET_STATE (widget)]); + >k_widget_get_style (widget)->base[gtk_widget_get_state (widget)]); } gtk_widget_queue_draw (widget); @@ -1114,16 +1133,16 @@ gtk_combo_box_button_state_changed (GtkWidget *widget, GtkComboBox *combo_box = GTK_COMBO_BOX (data); GtkComboBoxPrivate *priv = combo_box->priv; - if (GTK_WIDGET_REALIZED (widget)) + if (gtk_widget_get_realized (widget)) { if (!priv->tree_view && priv->cell_view) { - if ((GTK_WIDGET_STATE (widget) == GTK_STATE_INSENSITIVE) != - (GTK_WIDGET_STATE (priv->cell_view) == GTK_STATE_INSENSITIVE)) - gtk_widget_set_sensitive (priv->cell_view, GTK_WIDGET_SENSITIVE (widget)); + if ((gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE) != + (gtk_widget_get_state (priv->cell_view) == GTK_STATE_INSENSITIVE)) + gtk_widget_set_sensitive (priv->cell_view, gtk_widget_get_sensitive (widget)); gtk_widget_set_state (priv->cell_view, - GTK_WIDGET_STATE (widget)); + gtk_widget_get_state (widget)); } } @@ -1178,15 +1197,17 @@ gtk_combo_box_style_set (GtkWidget *widget, { GtkComboBox *combo_box = GTK_COMBO_BOX (widget); GtkComboBoxPrivate *priv = combo_box->priv; + GtkWidget *child; gtk_combo_box_check_appearance (combo_box); if (priv->tree_view && priv->cell_view) gtk_cell_view_set_background_color (GTK_CELL_VIEW (priv->cell_view), - &widget->style->base[GTK_WIDGET_STATE (widget)]); + >k_widget_get_style (widget)->base[gtk_widget_get_state (widget)]); - if (GTK_IS_ENTRY (GTK_BIN (combo_box)->child)) - g_object_set (GTK_BIN (combo_box)->child, "shadow-type", + child = gtk_bin_get_child (GTK_BIN (combo_box)); + if (GTK_IS_ENTRY (child)) + g_object_set (child, "shadow-type", GTK_SHADOW_NONE == priv->shadow_type ? GTK_SHADOW_IN : GTK_SHADOW_NONE, NULL); } @@ -1213,15 +1234,16 @@ gtk_combo_box_add (GtkContainer *container, GtkComboBox *combo_box = GTK_COMBO_BOX (container); GtkComboBoxPrivate *priv = combo_box->priv; - if (priv->cell_view && priv->cell_view->parent) + if (priv->cell_view && + gtk_widget_get_parent (priv->cell_view)) { gtk_widget_unparent (priv->cell_view); - GTK_BIN (container)->child = NULL; + _gtk_bin_set_child (GTK_BIN (container), NULL); gtk_widget_queue_resize (GTK_WIDGET (container)); } gtk_widget_set_parent (widget, GTK_WIDGET (container)); - GTK_BIN (container)->child = widget; + _gtk_bin_set_child (GTK_BIN (container), widget); if (priv->cell_view && widget != priv->cell_view) @@ -1231,8 +1253,8 @@ gtk_combo_box_add (GtkContainer *container, if (!priv->tree_view && priv->separator) { - gtk_container_remove (GTK_CONTAINER (priv->separator->parent), - priv->separator); + gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (priv->separator)), + priv->separator); priv->separator = NULL; gtk_widget_queue_resize (GTK_WIDGET (container)); @@ -1259,9 +1281,9 @@ gtk_combo_box_remove (GtkContainer *container, priv->cell_view = NULL; gtk_widget_unparent (widget); - GTK_BIN (container)->child = NULL; + _gtk_bin_set_child (GTK_BIN (container), NULL); - if (GTK_OBJECT_FLAGS (combo_box) & GTK_IN_DESTRUCTION) + if (gtk_widget_in_destruction (combo_box)) return; gtk_widget_queue_resize (GTK_WIDGET (container)); @@ -1284,7 +1306,7 @@ gtk_combo_box_remove (GtkContainer *container, { priv->cell_view = gtk_cell_view_new (); gtk_widget_set_parent (priv->cell_view, GTK_WIDGET (container)); - GTK_BIN (container)->child = priv->cell_view; + _gtk_bin_set_child (GTK_BIN (container), priv->cell_view); gtk_widget_show (priv->cell_view); gtk_cell_view_set_model (GTK_CELL_VIEW (priv->cell_view), @@ -1477,6 +1499,7 @@ gtk_combo_box_menu_position_below (GtkMenu *menu, gpointer user_data) { GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); + GtkAllocation child_allocation; gint sx, sy; GtkWidget *child; GtkRequisition req; @@ -1485,32 +1508,36 @@ gtk_combo_box_menu_position_below (GtkMenu *menu, GdkRectangle monitor; /* FIXME: is using the size request here broken? */ - child = GTK_BIN (combo_box)->child; + child = gtk_bin_get_child (GTK_BIN (combo_box)); sx = sy = 0; + gtk_widget_get_allocation (child, &child_allocation); + if (!gtk_widget_get_has_window (child)) { - sx += child->allocation.x; - sy += child->allocation.y; + sx += child_allocation.x; + sy += child_allocation.y; } - gdk_window_get_root_coords (child->window, sx, sy, &sx, &sy); + gdk_window_get_root_coords (gtk_widget_get_window (child), + sx, sy, &sx, &sy); if (GTK_SHADOW_NONE != combo_box->priv->shadow_type) - sx -= GTK_WIDGET (combo_box)->style->xthickness; + sx -= gtk_widget_get_style (GTK_WIDGET (combo_box))->xthickness; - gtk_widget_size_request (GTK_WIDGET (menu), &req); + gtk_widget_get_preferred_size (GTK_WIDGET (menu), + &req, NULL); if (gtk_widget_get_direction (GTK_WIDGET (combo_box)) == GTK_TEXT_DIR_LTR) *x = sx; else - *x = sx + child->allocation.width - req.width; + *x = sx + child_allocation.width - req.width; *y = sy; screen = gtk_widget_get_screen (GTK_WIDGET (combo_box)); monitor_num = gdk_screen_get_monitor_at_window (screen, - GTK_WIDGET (combo_box)->window); + gtk_widget_get_window (GTK_WIDGET (combo_box))); gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor); if (*x < monitor.x) @@ -1518,12 +1545,12 @@ gtk_combo_box_menu_position_below (GtkMenu *menu, 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; + if (monitor.y + monitor.height - *y - child_allocation.height >= req.height) + *y += child_allocation.height; else if (*y - monitor.y >= req.height) *y -= req.height; - else if (monitor.y + monitor.height - *y - child->allocation.height > *y - monitor.y) - *y += child->allocation.height; + else if (monitor.y + monitor.height - *y - child_allocation.height > *y - monitor.y) + *y += child_allocation.height; else *y -= req.height; @@ -1537,32 +1564,34 @@ gtk_combo_box_menu_position_over (GtkMenu *menu, gboolean *push_in, gpointer user_data) { - GtkComboBox *combo_box; - GtkWidget *active; - GtkWidget *child; - GtkWidget *widget; - GtkRequisition requisition; - GList *children; - gint screen_width; - gint menu_xpos; - gint menu_ypos; - gint menu_width; + GtkComboBox *combo_box; + GtkWidget *active; + GtkWidget *child; + GtkWidget *widget; + GtkAllocation allocation; + GtkAllocation child_allocation; + GList *children; + gint screen_width; + gint menu_xpos; + gint menu_ypos; + gint menu_width; 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)); - menu_xpos = widget->allocation.x; - menu_ypos = widget->allocation.y + widget->allocation.height / 2 - 2; + gtk_widget_get_allocation (widget, &allocation); + + menu_xpos = allocation.x; + menu_ypos = allocation.y + allocation.height / 2 - 2; + + gtk_widget_get_preferred_width (GTK_WIDGET (menu), &menu_width, NULL); if (active != NULL) { - gtk_widget_get_child_requisition (active, &requisition); - menu_ypos -= requisition.height / 2; + gtk_widget_get_allocation (active, &child_allocation); + menu_ypos -= child_allocation.height / 2; } children = GTK_MENU_SHELL (combo_box->priv->popup_widget)->children; @@ -1573,19 +1602,21 @@ gtk_combo_box_menu_position_over (GtkMenu *menu, if (active == child) break; - if (GTK_WIDGET_VISIBLE (child)) + if (gtk_widget_get_visible (child)) { - gtk_widget_get_child_requisition (child, &requisition); - menu_ypos -= requisition.height; + gtk_widget_get_allocation (child, &child_allocation); + + menu_ypos -= child_allocation.height; } children = children->next; } if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) - menu_xpos = menu_xpos + widget->allocation.width - menu_width; + menu_xpos = menu_xpos + allocation.width - menu_width; - gdk_window_get_root_coords (widget->window, menu_xpos, menu_ypos, + gdk_window_get_root_coords (gtk_widget_get_window (widget), + menu_xpos, menu_ypos, &menu_xpos, &menu_ypos); /* Clamp the position on screen */ @@ -1627,7 +1658,7 @@ gtk_combo_box_menu_position (GtkMenu *menu, gtk_combo_box_menu_position_over (menu, x, y, push_in, user_data); } - if (!GTK_WIDGET_VISIBLE (GTK_MENU (priv->popup_widget)->toplevel)) + if (!gtk_widget_get_visible (GTK_MENU (priv->popup_widget)->toplevel)) gtk_window_set_type_hint (GTK_WINDOW (GTK_MENU (priv->popup_widget)->toplevel), GDK_WINDOW_TYPE_HINT_COMBO); } @@ -1640,46 +1671,54 @@ gtk_combo_box_list_position (GtkComboBox *combo_box, gint *height) { GtkComboBoxPrivate *priv = combo_box->priv; + GtkAllocation allocation; GdkScreen *screen; gint monitor_num; GdkRectangle monitor; GtkRequisition popup_req; GtkPolicyType hpolicy, vpolicy; - + GdkWindow *window; + /* under windows, the drop down list is as wide as the combo box itself. see bug #340204 */ - GtkWidget *sample = GTK_WIDGET (combo_box); + GtkWidget *widget = GTK_WIDGET (combo_box); *x = *y = 0; - if (!gtk_widget_get_has_window (sample)) + gtk_widget_get_allocation (widget, &allocation); + + if (!gtk_widget_get_has_window (widget)) { - *x += sample->allocation.x; - *y += sample->allocation.y; + *x += allocation.x; + *y += allocation.y; } - - gdk_window_get_root_coords (sample->window, *x, *y, x, y); - *width = sample->allocation.width; + window = gtk_widget_get_window (widget); + + gdk_window_get_root_coords (gtk_widget_get_window (widget), + *x, *y, x, y); + + *width = allocation.width; hpolicy = vpolicy = GTK_POLICY_NEVER; gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window), hpolicy, vpolicy); - gtk_widget_size_request (priv->scrolled_window, &popup_req); + gtk_widget_get_preferred_size (priv->scrolled_window, + &popup_req, NULL); if (popup_req.width > *width) { hpolicy = GTK_POLICY_ALWAYS; gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window), hpolicy, vpolicy); - gtk_widget_size_request (priv->scrolled_window, &popup_req); + gtk_widget_get_preferred_size (priv->scrolled_window, + &popup_req, NULL); } *height = popup_req.height; screen = gtk_widget_get_screen (GTK_WIDGET (combo_box)); - monitor_num = gdk_screen_get_monitor_at_window (screen, - GTK_WIDGET (combo_box)->window); + monitor_num = gdk_screen_get_monitor_at_window (screen, window); gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor); if (*x < monitor.x) @@ -1687,13 +1726,13 @@ gtk_combo_box_list_position (GtkComboBox *combo_box, 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; + if (*y + allocation.height + *height <= monitor.y + monitor.height) + *y += allocation.height; else if (*y - *height >= monitor.y) *y -= *height; - else if (monitor.y + monitor.height - (*y + sample->allocation.height) > *y - monitor.y) + else if (monitor.y + monitor.height - (*y + allocation.height) > *y - monitor.y) { - *y += sample->allocation.height; + *y += allocation.height; *height = monitor.y + monitor.height - *y; } else @@ -1787,7 +1826,7 @@ update_menu_sensitivity (GtkComboBox *combo_box, for (child = children; child; child = child->next) { item = GTK_WIDGET (child->data); - cell_view = GTK_BIN (item)->child; + cell_view = gtk_bin_get_child (GTK_BIN (item)); if (!GTK_IS_CELL_VIEW (cell_view)) continue; @@ -1824,8 +1863,7 @@ gtk_combo_box_menu_popup (GtkComboBox *combo_box, GtkComboBoxPrivate *priv = combo_box->priv; GtkTreePath *path; gint active_item; - GtkRequisition requisition; - gint width; + gint width, min_width; update_menu_sensitivity (combo_box, priv->popup_widget); @@ -1845,12 +1883,15 @@ gtk_combo_box_menu_popup (GtkComboBox *combo_box, if (priv->wrap_width == 0) { - width = GTK_WIDGET (combo_box)->allocation.width; + GtkAllocation allocation; + + gtk_widget_get_allocation (GTK_WIDGET (combo_box), &allocation); + width = allocation.width; gtk_widget_set_size_request (priv->popup_widget, -1, -1); - gtk_widget_size_request (priv->popup_widget, &requisition); + gtk_widget_get_preferred_width (priv->popup_widget, &min_width, NULL); gtk_widget_set_size_request (priv->popup_widget, - MAX (width, requisition.width), -1); + MAX (width, min_width), -1); } gtk_menu_popup (GTK_MENU (priv->popup_widget), @@ -1861,27 +1902,31 @@ gtk_combo_box_menu_popup (GtkComboBox *combo_box, static gboolean popup_grab_on_window (GdkWindow *window, - guint32 activate_time, - gboolean grab_keyboard) -{ - if ((gdk_pointer_grab (window, TRUE, - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | - GDK_POINTER_MOTION_MASK, - NULL, NULL, activate_time) == 0)) + GdkDevice *keyboard, + GdkDevice *pointer, + guint32 activate_time) +{ + if (keyboard && + gdk_device_grab (keyboard, window, + GDK_OWNERSHIP_WINDOW, TRUE, + GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK, + NULL, activate_time) != GDK_GRAB_SUCCESS) + return FALSE; + + if (pointer && + gdk_device_grab (pointer, window, + GDK_OWNERSHIP_WINDOW, TRUE, + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK, + NULL, activate_time) != GDK_GRAB_SUCCESS) { - if (!grab_keyboard || - gdk_keyboard_grab (window, TRUE, - activate_time) == 0) - return TRUE; - else - { - gdk_display_pointer_ungrab (gdk_drawable_get_display (window), - activate_time); - return FALSE; - } + if (keyboard) + gdk_device_ungrab (keyboard, activate_time); + + return FALSE; } - return FALSE; + return TRUE; } /** @@ -1903,20 +1948,53 @@ gtk_combo_box_popup (GtkComboBox *combo_box) g_signal_emit (combo_box, combo_box_signals[POPUP], 0); } -static void -gtk_combo_box_real_popup (GtkComboBox *combo_box) +/** + * gtk_combo_box_popup_for_device: + * @combo_box: a #GtkComboBox + * @device: a #GdkDevice + * + * Pops up the menu or dropdown list of @combo_box, the popup window + * will be grabbed so only @device and its associated pointer/keyboard + * are the only #GdkDevices able to send events to it. + * + * Since: 3.0 + **/ +void +gtk_combo_box_popup_for_device (GtkComboBox *combo_box, + GdkDevice *device) { GtkComboBoxPrivate *priv = combo_box->priv; gint x, y, width, height; GtkTreePath *path = NULL, *ppath; GtkWidget *toplevel; + GdkDevice *keyboard, *pointer; + guint32 time; - if (!GTK_WIDGET_REALIZED (combo_box)) + g_return_if_fail (GTK_IS_COMBO_BOX (combo_box)); + g_return_if_fail (GDK_IS_DEVICE (device)); + + if (!gtk_widget_get_realized (GTK_WIDGET (combo_box))) + return; + + if (gtk_widget_get_mapped (priv->popup_widget)) return; - if (GTK_WIDGET_MAPPED (priv->popup_widget)) + if (priv->grab_pointer && priv->grab_keyboard) return; + time = gtk_get_current_event_time (); + + if (device->source == GDK_SOURCE_KEYBOARD) + { + keyboard = device; + pointer = gdk_device_get_associated_device (device); + } + else + { + pointer = device; + keyboard = gdk_device_get_associated_device (device); + } + if (GTK_IS_MENU (priv->popup_widget)) { gtk_combo_box_menu_popup (combo_box, @@ -1962,17 +2040,44 @@ gtk_combo_box_real_popup (GtkComboBox *combo_box) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), TRUE); - if (!GTK_WIDGET_HAS_FOCUS (priv->tree_view)) + if (!gtk_widget_has_focus (priv->tree_view)) gtk_widget_grab_focus (priv->tree_view); - if (!popup_grab_on_window (priv->popup_window->window, - GDK_CURRENT_TIME, TRUE)) + if (!popup_grab_on_window (gtk_widget_get_window (priv->popup_window), + keyboard, pointer, time)) { gtk_widget_hide (priv->popup_window); return; } - gtk_grab_add (priv->popup_window); + gtk_device_grab_add (priv->popup_window, pointer, TRUE); + priv->grab_pointer = pointer; + priv->grab_keyboard = keyboard; +} + +static void +gtk_combo_box_real_popup (GtkComboBox *combo_box) +{ + GdkDevice *device; + + device = gtk_get_current_event_device (); + + if (!device) + { + GdkDeviceManager *device_manager; + GdkDisplay *display; + GList *devices; + + display = gtk_widget_get_display (GTK_WIDGET (combo_box)); + device_manager = gdk_display_get_device_manager (display); + + /* No device was set, pick the first master device */ + devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER); + device = devices->data; + g_list_free (devices); + } + + gtk_combo_box_popup_for_device (combo_box, device); } static gboolean @@ -2011,22 +2116,24 @@ gtk_combo_box_popdown (GtkComboBox *combo_box) return; } - if (!GTK_WIDGET_REALIZED (GTK_WIDGET (combo_box))) + if (!gtk_widget_get_realized (GTK_WIDGET (combo_box))) return; - gtk_grab_remove (priv->popup_window); + gtk_device_grab_remove (priv->popup_window, priv->grab_pointer); gtk_widget_hide_all (priv->popup_window); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), FALSE); + + priv->grab_pointer = NULL; + priv->grab_keyboard = NULL; } -static gint -gtk_combo_box_calc_requested_width (GtkComboBox *combo_box, - GtkTreePath *path) +static void +gtk_combo_box_update_requested_width (GtkComboBox *combo_box, + GtkTreePath *path) { GtkComboBoxPrivate *priv = combo_box->priv; - gint padding; - GtkRequisition req; + gint padding, min_width, nat_width; if (priv->cell_view) gtk_widget_style_get (priv->cell_view, @@ -2039,174 +2146,30 @@ gtk_combo_box_calc_requested_width (GtkComboBox *combo_box, padding += BONUS_PADDING; if (priv->cell_view) - gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (priv->cell_view), - path, &req); + gtk_cell_view_get_desired_width_of_row (GTK_CELL_VIEW (priv->cell_view), + path, &min_width, &nat_width); else - req.width = 0; - - return req.width + padding; -} - -static void -gtk_combo_box_remeasure (GtkComboBox *combo_box) -{ - GtkComboBoxPrivate *priv = combo_box->priv; - GtkTreeIter iter; - GtkTreePath *path; - - if (!priv->model || - !gtk_tree_model_get_iter_first (priv->model, &iter)) - return; - - priv->width = 0; - priv->height = 0; - - path = gtk_tree_path_new_from_indices (0, -1); - - do - { - GtkRequisition req; - - if (priv->cell_view) - gtk_cell_view_get_size_of_row (GTK_CELL_VIEW (priv->cell_view), - path, &req); - else - { - req.width = 0; - req.height = 0; - } - - priv->width = MAX (priv->width, req.width); - priv->height = MAX (priv->height, req.height); - - gtk_tree_path_next (path); - } - while (gtk_tree_model_iter_next (priv->model, &iter)); - - gtk_tree_path_free (path); -} + min_width = nat_width = 0; -static void -gtk_combo_box_size_request (GtkWidget *widget, - GtkRequisition *requisition) -{ - gint width, height; - gint focus_width, focus_pad; - gint font_size; - gint arrow_size; - GtkRequisition bin_req; - PangoContext *context; - PangoFontMetrics *metrics; - PangoFontDescription *font_desc; - - GtkComboBox *combo_box = GTK_COMBO_BOX (widget); - GtkComboBoxPrivate *priv = combo_box->priv; - - /* common */ - gtk_widget_size_request (GTK_BIN (widget)->child, &bin_req); - gtk_combo_box_remeasure (combo_box); - bin_req.width = MAX (bin_req.width, priv->width); - bin_req.height = MAX (bin_req.height, priv->height); - - gtk_widget_style_get (GTK_WIDGET (widget), - "focus-line-width", &focus_width, - "focus-padding", &focus_pad, - "arrow-size", &arrow_size, - NULL); + min_width += padding; + nat_width += padding; - font_desc = GTK_BIN (widget)->child->style->font_desc; - context = gtk_widget_get_pango_context (widget); - metrics = pango_context_get_metrics (context, font_desc, - pango_context_get_language (context)); - font_size = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) + - pango_font_metrics_get_descent (metrics)); - pango_font_metrics_unref (metrics); - - arrow_size = MAX (arrow_size, font_size); - - gtk_widget_set_size_request (priv->arrow, arrow_size, arrow_size); - - if (!priv->tree_view) + if (min_width > priv->minimum_width || nat_width > priv->natural_width) { - /* menu mode */ + priv->minimum_width = MAX (priv->minimum_width, min_width); + priv->natural_width = MAX (priv->natural_width, nat_width); if (priv->cell_view) - { - GtkRequisition button_req, sep_req, arrow_req; - gint border_width, xthickness, ythickness; - - gtk_widget_size_request (priv->button, &button_req); - border_width = GTK_CONTAINER (combo_box)->border_width; - xthickness = priv->button->style->xthickness; - ythickness = priv->button->style->ythickness; - - bin_req.width = MAX (bin_req.width, priv->width); - bin_req.height = MAX (bin_req.height, priv->height); - - gtk_widget_size_request (priv->separator, &sep_req); - gtk_widget_size_request (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 += 2*(border_width + ythickness + focus_width + focus_pad); - width += 2*(border_width + xthickness + focus_width + focus_pad); - - requisition->width = width; - requisition->height = height; - } - else - { - GtkRequisition but_req; - - gtk_widget_size_request (priv->button, &but_req); - - requisition->width = bin_req.width + but_req.width; - requisition->height = MAX (bin_req.height, but_req.height); - } - } - else - { - /* list mode */ - GtkRequisition button_req, frame_req; - - /* sample + frame */ - *requisition = bin_req; - - requisition->width += 2 * focus_width; - - if (priv->cell_view_frame) - { - gtk_widget_size_request (priv->cell_view_frame, &frame_req); - if (priv->has_frame) - { - requisition->width += 2 * - (GTK_CONTAINER (priv->cell_view_frame)->border_width + - GTK_WIDGET (priv->cell_view_frame)->style->xthickness); - requisition->height += 2 * - (GTK_CONTAINER (priv->cell_view_frame)->border_width + - GTK_WIDGET (priv->cell_view_frame)->style->ythickness); - } - } - - /* the button */ - gtk_widget_size_request (priv->button, &button_req); - - requisition->height = MAX (requisition->height, button_req.height); - requisition->width += button_req.width; - } - - if (GTK_SHADOW_NONE != priv->shadow_type) - { - requisition->height += 2 * widget->style->ythickness; - requisition->width += 2 * widget->style->xthickness; + { + gtk_widget_set_size_request (priv->cell_view, min_width, -1); + gtk_widget_queue_resize (priv->cell_view); + } } } #define GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON \ - gtk_widget_size_request (combo_box->priv->button, &req); \ + gtk_widget_get_preferred_size (combo_box->priv->button, \ + &req, NULL); \ \ if (is_rtl) \ child.x = allocation->x + shadow_width; \ @@ -2227,23 +2190,27 @@ gtk_combo_box_size_allocate (GtkWidget *widget, { GtkComboBox *combo_box = GTK_COMBO_BOX (widget); GtkComboBoxPrivate *priv = combo_box->priv; + GtkWidget *child_widget; gint shadow_width, shadow_height; gint focus_width, focus_pad; GtkAllocation child; GtkRequisition req; + GtkStyle *style; gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL; - widget->allocation = *allocation; + gtk_widget_set_allocation (widget, allocation); + child_widget = gtk_bin_get_child (GTK_BIN (widget)); - gtk_widget_style_get (GTK_WIDGET (widget), + style = gtk_widget_get_style (widget); + gtk_widget_style_get (widget, "focus-line-width", &focus_width, "focus-padding", &focus_pad, NULL); if (GTK_SHADOW_NONE != priv->shadow_type) { - shadow_width = widget->style->xthickness; - shadow_height = widget->style->ythickness; + shadow_width = style->xthickness; + shadow_height = style->ythickness; } else { @@ -2255,8 +2222,9 @@ gtk_combo_box_size_allocate (GtkWidget *widget, { if (priv->cell_view) { - gint border_width, xthickness, ythickness; + gint xthickness, ythickness; gint width; + guint border_width; /* menu mode */ allocation->x += shadow_width; @@ -2267,9 +2235,10 @@ gtk_combo_box_size_allocate (GtkWidget *widget, gtk_widget_size_allocate (priv->button, allocation); /* set some things ready */ - border_width = GTK_CONTAINER (priv->button)->border_width; - xthickness = priv->button->style->xthickness; - ythickness = priv->button->style->ythickness; + border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->button)); + style = gtk_widget_get_style (priv->button); + xthickness = style->xthickness; + ythickness = style->ythickness; child.x = allocation->x; child.y = allocation->y; @@ -2286,7 +2255,7 @@ gtk_combo_box_size_allocate (GtkWidget *widget, /* handle the children */ - gtk_widget_size_request (priv->arrow, &req); + gtk_widget_get_preferred_size (priv->arrow, &req, NULL); child.width = req.width; if (!is_rtl) child.x += width - req.width; @@ -2295,7 +2264,7 @@ gtk_combo_box_size_allocate (GtkWidget *widget, gtk_widget_size_allocate (priv->arrow, &child); if (is_rtl) child.x += req.width; - gtk_widget_size_request (priv->separator, &req); + gtk_widget_get_preferred_size (priv->separator, &req, NULL); child.width = req.width; if (!is_rtl) child.x -= req.width; @@ -2318,26 +2287,29 @@ gtk_combo_box_size_allocate (GtkWidget *widget, child.width -= child.x; } - if (GTK_WIDGET_VISIBLE (priv->popup_widget)) + if (gtk_widget_get_visible (priv->popup_widget)) { - gint width; - GtkRequisition requisition; + gint width, min_width; - /* Warning here, without the check in the position func */ - gtk_menu_reposition (GTK_MENU (priv->popup_widget)); if (priv->wrap_width == 0) { - width = GTK_WIDGET (combo_box)->allocation.width; + GtkAllocation combo_box_allocation; + + gtk_widget_get_allocation (GTK_WIDGET (combo_box), &combo_box_allocation); + width = combo_box_allocation.width; gtk_widget_set_size_request (priv->popup_widget, -1, -1); - gtk_widget_size_request (priv->popup_widget, &requisition); + gtk_widget_get_preferred_width (priv->popup_widget, &min_width, NULL); gtk_widget_set_size_request (priv->popup_widget, - MAX (width, requisition.width), -1); + MAX (width, min_width), -1); } + + /* reposition the menu after giving it a new width */ + gtk_menu_reposition (GTK_MENU (priv->popup_widget)); } child.width = MAX (1, child.width); child.height = MAX (1, child.height); - gtk_widget_size_allocate (GTK_BIN (widget)->child, &child); + gtk_widget_size_allocate (child_widget, &child); } else { @@ -2351,7 +2323,7 @@ gtk_combo_box_size_allocate (GtkWidget *widget, child.width = allocation->width - req.width - 2 * shadow_width; child.width = MAX (1, child.width); child.height = MAX (1, child.height); - gtk_widget_size_allocate (GTK_BIN (widget)->child, &child); + gtk_widget_size_allocate (child_widget, &child); } } else @@ -2359,8 +2331,9 @@ gtk_combo_box_size_allocate (GtkWidget *widget, /* list mode */ /* Combobox thickness + border-width */ - int delta_x = shadow_width + GTK_CONTAINER (widget)->border_width; - int delta_y = shadow_height + GTK_CONTAINER (widget)->border_width; + guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); + int delta_x = shadow_width + border_width; + int delta_y = shadow_height + border_width; /* button */ GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON @@ -2386,10 +2359,10 @@ gtk_combo_box_size_allocate (GtkWidget *widget, /* the sample */ if (priv->has_frame) { - delta_x = GTK_CONTAINER (priv->cell_view_frame)->border_width + - GTK_WIDGET (priv->cell_view_frame)->style->xthickness; - delta_y = GTK_CONTAINER (priv->cell_view_frame)->border_width + - GTK_WIDGET (priv->cell_view_frame)->style->ythickness; + border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->cell_view_frame)); + style = gtk_widget_get_style (priv->cell_view_frame); + delta_x = border_width + style->xthickness; + delta_y = border_width + style->ythickness; child.x += delta_x; child.y += delta_y; @@ -2405,7 +2378,7 @@ gtk_combo_box_size_allocate (GtkWidget *widget, child.height -= delta_y * 2; } - if (GTK_WIDGET_VISIBLE (priv->popup_window)) + if (gtk_widget_get_visible (priv->popup_window)) { gint x, y, width, height; gtk_combo_box_list_position (combo_box, &x, &y, &width, &height); @@ -2417,7 +2390,7 @@ gtk_combo_box_size_allocate (GtkWidget *widget, child.width = MAX (1, child.width); child.height = MAX (1, child.height); - gtk_widget_size_allocate (GTK_BIN (combo_box)->child, &child); + gtk_widget_size_allocate (child_widget, &child); } } @@ -2472,6 +2445,7 @@ gtk_combo_box_forall (GtkContainer *container, { GtkComboBox *combo_box = GTK_COMBO_BOX (container); GtkComboBoxPrivate *priv = combo_box->priv; + GtkWidget *child; if (include_internals) { @@ -2481,8 +2455,9 @@ gtk_combo_box_forall (GtkContainer *container, (* callback) (priv->cell_view_frame, callback_data); } - if (GTK_BIN (container)->child) - (* callback) (GTK_BIN (container)->child, callback_data); + child = gtk_bin_get_child (GTK_BIN (container)); + if (child) + (* callback) (child, callback_data); } static void @@ -2506,33 +2481,35 @@ gtk_combo_box_child_hide (GtkWidget *widget, } static gboolean -gtk_combo_box_expose_event (GtkWidget *widget, - GdkEventExpose *event) +gtk_combo_box_draw (GtkWidget *widget, + cairo_t *cr) { GtkComboBox *combo_box = GTK_COMBO_BOX (widget); GtkComboBoxPrivate *priv = combo_box->priv; - if (GTK_WIDGET_DRAWABLE (widget) && - GTK_SHADOW_NONE != priv->shadow_type) + if (priv->shadow_type != GTK_SHADOW_NONE) { - gtk_paint_shadow (widget->style, widget->window, + gtk_paint_shadow (gtk_widget_get_style (widget), + cr, GTK_STATE_NORMAL, priv->shadow_type, - NULL, widget, "combobox", - widget->allocation.x, widget->allocation.y, - widget->allocation.width, widget->allocation.height); + widget, "combobox", + 0, 0, + gtk_widget_get_allocated_width (widget), + gtk_widget_get_allocated_height (widget)); } - gtk_container_propagate_expose (GTK_CONTAINER (widget), - priv->button, event); + gtk_container_propagate_draw (GTK_CONTAINER (widget), + priv->button, cr); if (priv->tree_view && priv->cell_view_frame) { - gtk_container_propagate_expose (GTK_CONTAINER (widget), - priv->cell_view_frame, event); + gtk_container_propagate_draw (GTK_CONTAINER (widget), + priv->cell_view_frame, cr); } - gtk_container_propagate_expose (GTK_CONTAINER (widget), - GTK_BIN (widget)->child, event); + gtk_container_propagate_draw (GTK_CONTAINER (widget), + gtk_bin_get_child (GTK_BIN (widget)), + cr); return FALSE; } @@ -2812,8 +2789,11 @@ gtk_combo_box_menu_setup (GtkComboBox *combo_box, gboolean add_children) { GtkComboBoxPrivate *priv = combo_box->priv; + GtkWidget *child; GtkWidget *menu; + child = gtk_bin_get_child (GTK_BIN (combo_box)); + if (priv->cell_view) { priv->button = gtk_toggle_button_new (); @@ -2823,7 +2803,7 @@ gtk_combo_box_menu_setup (GtkComboBox *combo_box, g_signal_connect (priv->button, "toggled", G_CALLBACK (gtk_combo_box_button_toggled), combo_box); gtk_widget_set_parent (priv->button, - GTK_BIN (combo_box)->child->parent); + gtk_widget_get_parent (child)); priv->box = gtk_hbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (priv->button), priv->box); @@ -2845,7 +2825,7 @@ gtk_combo_box_menu_setup (GtkComboBox *combo_box, g_signal_connect (priv->button, "toggled", G_CALLBACK (gtk_combo_box_button_toggled), combo_box); gtk_widget_set_parent (priv->button, - GTK_BIN (combo_box)->child->parent); + gtk_widget_get_parent (child)); priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); gtk_container_add (GTK_CONTAINER (priv->button), priv->arrow); @@ -2927,7 +2907,7 @@ gtk_cell_view_menu_item_new (GtkComboBox *combo_box, gtk_tree_path_free (path); gtk_combo_box_sync_cells (combo_box, GTK_CELL_LAYOUT (cell_view)); - gtk_widget_size_request (cell_view, &req); + gtk_widget_get_preferred_size (cell_view, &req, NULL); gtk_widget_show (cell_view); return item; @@ -3168,7 +3148,7 @@ gtk_combo_box_menu_button_press (GtkWidget *widget, event->type == GDK_BUTTON_PRESS && event->button == 1) { if (priv->focus_on_click && - !GTK_WIDGET_HAS_FOCUS (priv->button)) + !gtk_widget_has_focus (priv->button)) gtk_widget_grab_focus (priv->button); gtk_combo_box_menu_popup (combo_box, event->button, event->time); @@ -3188,7 +3168,7 @@ gtk_combo_box_menu_item_activate (GtkWidget *item, GtkTreePath *path; GtkTreeIter iter; - cell_view = GTK_BIN (item)->child; + cell_view = gtk_bin_get_child (GTK_BIN (item)); g_return_if_fail (GTK_IS_CELL_VIEW (cell_view)); @@ -3328,7 +3308,7 @@ list_popup_resize_idle (gpointer user_data) GtkComboBoxPrivate *priv = combo_box->priv; gint x, y, width, height; - if (priv->tree_view && GTK_WIDGET_MAPPED (priv->popup_window)) + if (priv->tree_view && gtk_widget_get_mapped (priv->popup_window)) { gtk_combo_box_list_position (combo_box, &x, &y, &width, &height); @@ -3369,6 +3349,7 @@ find_menu_by_path (GtkWidget *menu, gboolean skip_first) { GList *i, *list; + GtkWidget *child; GtkWidget *item; GtkWidget *submenu; GtkTreeRowReference *mref; @@ -3380,6 +3361,7 @@ find_menu_by_path (GtkWidget *menu, item = NULL; for (i = list; i; i = i->next) { + child = gtk_bin_get_child (i->data); if (GTK_IS_SEPARATOR_MENU_ITEM (i->data)) { mref = g_object_get_data (G_OBJECT (i->data), "gtk-combo-box-item-path"); @@ -3390,7 +3372,7 @@ find_menu_by_path (GtkWidget *menu, else mpath = gtk_tree_row_reference_get_path (mref); } - else if (GTK_IS_CELL_VIEW (GTK_BIN (i->data)->child)) + else if (GTK_IS_CELL_VIEW (child)) { if (skip) { @@ -3398,7 +3380,7 @@ find_menu_by_path (GtkWidget *menu, continue; } - mpath = gtk_cell_view_get_displayed_row (GTK_CELL_VIEW (GTK_BIN (i->data)->child)); + mpath = gtk_cell_view_get_displayed_row (GTK_CELL_VIEW (child)); } else continue; @@ -3509,7 +3491,7 @@ gtk_combo_box_menu_row_inserted (GtkTreeModel *model, combo_box); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), separator); - if (cell_view_is_sensitive (GTK_CELL_VIEW (GTK_BIN (item)->child))) + if (cell_view_is_sensitive (GTK_CELL_VIEW (gtk_bin_get_child (GTK_BIN (item))))) { gtk_widget_show (item); gtk_widget_show (separator); @@ -3608,7 +3590,6 @@ gtk_combo_box_menu_row_changed (GtkTreeModel *model, GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); GtkComboBoxPrivate *priv = combo_box->priv; GtkWidget *item; - gint width; gboolean is_separator; if (!priv->popup_widget) @@ -3628,7 +3609,8 @@ gtk_combo_box_menu_row_changed (GtkTreeModel *model, gtk_combo_box_menu_row_inserted (model, path, iter, combo_box); } - if (priv->wrap_width && item->parent == priv->popup_widget) + if (priv->wrap_width && + gtk_widget_get_parent (item) == priv->popup_widget) { GtkWidget *pitem = NULL; GtkTreePath *prev; @@ -3653,17 +3635,7 @@ gtk_combo_box_menu_row_changed (GtkTreeModel *model, gtk_combo_box_relayout_item (combo_box, item, iter, pitem); } - width = gtk_combo_box_calc_requested_width (combo_box, path); - - if (width > priv->width) - { - if (priv->cell_view) - { - gtk_widget_set_size_request (priv->cell_view, width, -1); - gtk_widget_queue_resize (priv->cell_view); - } - priv->width = width; - } + gtk_combo_box_update_requested_width (combo_box, path); } /* @@ -3675,10 +3647,14 @@ gtk_combo_box_list_setup (GtkComboBox *combo_box) { GtkComboBoxPrivate *priv = combo_box->priv; GtkTreeSelection *sel; + GtkStyle *style; + GtkWidget *child; + GtkWidget *widget = GTK_WIDGET (combo_box); priv->button = gtk_toggle_button_new (); + child = gtk_bin_get_child (GTK_BIN (combo_box)); gtk_widget_set_parent (priv->button, - GTK_BIN (combo_box)->child->parent); + gtk_widget_get_parent (child)); g_signal_connect (priv->button, "button-press-event", G_CALLBACK (gtk_combo_box_list_button_pressed), combo_box); g_signal_connect (priv->button, "toggled", @@ -3691,8 +3667,9 @@ gtk_combo_box_list_setup (GtkComboBox *combo_box) if (priv->cell_view) { - gtk_cell_view_set_background_color (GTK_CELL_VIEW (priv->cell_view), - >K_WIDGET (combo_box)->style->base[GTK_WIDGET_STATE (combo_box)]); + style = gtk_widget_get_style (widget); + gtk_cell_view_set_background_color (GTK_CELL_VIEW (priv->cell_view), + &style->base[gtk_widget_get_state (widget)]); priv->box = gtk_event_box_new (); gtk_event_box_set_visible_window (GTK_EVENT_BOX (priv->box), @@ -3710,9 +3687,9 @@ gtk_combo_box_list_setup (GtkComboBox *combo_box) gtk_event_box_set_visible_window (GTK_EVENT_BOX (combo_box->priv->cell_view_frame), FALSE); } - + gtk_widget_set_parent (priv->cell_view_frame, - GTK_BIN (combo_box)->child->parent); + gtk_widget_get_parent (child)); gtk_container_add (GTK_CONTAINER (priv->cell_view_frame), priv->box); gtk_widget_show_all (priv->cell_view_frame); @@ -3890,10 +3867,10 @@ gtk_combo_box_list_button_pressed (GtkWidget *widget, return FALSE; if (priv->focus_on_click && - !GTK_WIDGET_HAS_FOCUS (priv->button)) + !gtk_widget_has_focus (priv->button)) gtk_widget_grab_focus (priv->button); - gtk_combo_box_popup (combo_box); + gtk_combo_box_popup_for_device (combo_box, event->device); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), TRUE); @@ -3987,12 +3964,12 @@ gtk_combo_box_menu_key_press (GtkWidget *widget, { GtkComboBox *combo_box = GTK_COMBO_BOX (data); - if (!gtk_bindings_activate_event (GTK_OBJECT (widget), event)) + if (!gtk_bindings_activate_event (G_OBJECT (widget), event)) { /* The menu hasn't managed the * event, forward it to the combobox */ - gtk_bindings_activate_event (GTK_OBJECT (combo_box), event); + gtk_bindings_activate_event (G_OBJECT (combo_box), event); } return TRUE; @@ -4006,8 +3983,8 @@ gtk_combo_box_list_key_press (GtkWidget *widget, GtkComboBox *combo_box = GTK_COMBO_BOX (data); GtkTreeIter iter; - if (event->keyval == GDK_Return || event->keyval == GDK_ISO_Enter || event->keyval == GDK_KP_Enter || - event->keyval == GDK_space || event->keyval == GDK_KP_Space) + if (event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_ISO_Enter || event->keyval == GDK_KEY_KP_Enter || + event->keyval == GDK_KEY_space || event->keyval == GDK_KEY_KP_Space) { GtkTreeModel *model = NULL; @@ -4026,12 +4003,12 @@ gtk_combo_box_list_key_press (GtkWidget *widget, return TRUE; } - if (!gtk_bindings_activate_event (GTK_OBJECT (widget), event)) + if (!gtk_bindings_activate_event (G_OBJECT (widget), event)) { /* The list hasn't managed the * event, forward it to the combobox */ - gtk_bindings_activate_event (GTK_OBJECT (combo_box), event); + gtk_bindings_activate_event (G_OBJECT (combo_box), event); } return TRUE; @@ -4042,41 +4019,44 @@ gtk_combo_box_list_auto_scroll (GtkComboBox *combo_box, gint x, gint y) { - GtkWidget *tree_view = combo_box->priv->tree_view; GtkAdjustment *adj; + GtkAllocation allocation; + GtkWidget *tree_view = combo_box->priv->tree_view; gdouble value; + gtk_widget_get_allocation (tree_view, &allocation); + adj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (combo_box->priv->scrolled_window)); if (adj && adj->upper - adj->lower > adj->page_size) { - if (x <= tree_view->allocation.x && + if (x <= allocation.x && adj->lower < adj->value) { - value = adj->value - (tree_view->allocation.x - x + 1); - gtk_adjustment_set_value (adj, CLAMP (value, adj->lower, adj->upper - adj->page_size)); + value = adj->value - (allocation.x - x + 1); + gtk_adjustment_set_value (adj, value); } - else if (x >= tree_view->allocation.x + tree_view->allocation.width && + else if (x >= allocation.x + allocation.width && adj->upper - adj->page_size > adj->value) { - value = adj->value + (x - tree_view->allocation.x - tree_view->allocation.width + 1); - gtk_adjustment_set_value (adj, CLAMP (value, 0.0, adj->upper - adj->page_size)); + value = adj->value + (x - allocation.x - allocation.width + 1); + gtk_adjustment_set_value (adj, MAX (value, 0.0)); } } adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (combo_box->priv->scrolled_window)); if (adj && adj->upper - adj->lower > adj->page_size) { - if (y <= tree_view->allocation.y && + if (y <= allocation.y && adj->lower < adj->value) { - value = adj->value - (tree_view->allocation.y - y + 1); - gtk_adjustment_set_value (adj, CLAMP (value, adj->lower, adj->upper - adj->page_size)); + value = adj->value - (allocation.y - y + 1); + gtk_adjustment_set_value (adj, value); } - else if (y >= tree_view->allocation.height && + else if (y >= allocation.height && adj->upper - adj->page_size > adj->value) { - value = adj->value + (y - tree_view->allocation.height + 1); - gtk_adjustment_set_value (adj, CLAMP (value, 0.0, adj->upper - adj->page_size)); + value = adj->value + (y - allocation.height + 1); + gtk_adjustment_set_value (adj, MAX (value, 0.0)); } } } @@ -4089,7 +4069,9 @@ gtk_combo_box_list_scroll_timeout (GtkComboBox *combo_box) if (priv->auto_scroll) { - gdk_window_get_pointer (priv->tree_view->window, &x, &y, NULL); + gdk_window_get_device_position (gtk_widget_get_window (priv->tree_view), + priv->grab_pointer, + &x, &y, NULL); gtk_combo_box_list_auto_scroll (combo_box, x, y); } @@ -4160,20 +4142,8 @@ gtk_combo_box_list_row_changed (GtkTreeModel *model, gpointer data) { GtkComboBox *combo_box = GTK_COMBO_BOX (data); - GtkComboBoxPrivate *priv = combo_box->priv; - gint width; - - width = gtk_combo_box_calc_requested_width (combo_box, path); - if (width > priv->width) - { - if (priv->cell_view) - { - gtk_widget_set_size_request (priv->cell_view, width, -1); - gtk_widget_queue_resize (priv->cell_view); - } - priv->width = width; - } + gtk_combo_box_update_requested_width (combo_box, path); } /* @@ -4186,14 +4156,16 @@ pack_start_recurse (GtkWidget *menu, gboolean expand) { GList *i, *list; + GtkWidget *child; GtkWidget *submenu; list = gtk_container_get_children (GTK_CONTAINER (menu)); for (i = list; i; i = i->next) { - if (GTK_IS_CELL_LAYOUT (GTK_BIN (i->data)->child)) - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (GTK_BIN (i->data)->child), - cell, expand); + child = gtk_bin_get_child (GTK_BIN (i->data)); + if (GTK_IS_CELL_LAYOUT (child)) + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (child), + cell, expand); submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (i->data)); if (submenu != NULL) @@ -4224,8 +4196,11 @@ gtk_combo_box_cell_layout_pack_start (GtkCellLayout *layout, priv->cells = g_slist_append (priv->cells, info); if (priv->cell_view) - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (priv->cell_view), - cell, expand); + { + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (priv->cell_view), + cell, expand); + + } if (priv->column) gtk_tree_view_column_pack_start (priv->column, cell, expand); @@ -4240,14 +4215,16 @@ pack_end_recurse (GtkWidget *menu, gboolean expand) { GList *i, *list; + GtkWidget *child; GtkWidget *submenu; list = gtk_container_get_children (GTK_CONTAINER (menu)); for (i = list; i; i = i->next) { - if (GTK_IS_CELL_LAYOUT (GTK_BIN (i->data)->child)) - gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (GTK_BIN (i->data)->child), - cell, expand); + child = gtk_bin_get_child (GTK_BIN (i->data)); + if (GTK_IS_CELL_LAYOUT (child)) + gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (child), + cell, expand); submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (i->data)); if (submenu != NULL) @@ -4309,13 +4286,15 @@ static void clear_recurse (GtkWidget *menu) { GList *i, *list; + GtkWidget *child; GtkWidget *submenu; list = gtk_container_get_children (GTK_CONTAINER (menu)); for (i = list; i; i = i->next) { - if (GTK_IS_CELL_LAYOUT (GTK_BIN (i->data)->child)) - gtk_cell_layout_clear (GTK_CELL_LAYOUT (GTK_BIN (i->data)->child)); + child = gtk_bin_get_child (GTK_BIN (i->data)); + if (GTK_IS_CELL_LAYOUT (child)) + gtk_cell_layout_clear (GTK_CELL_LAYOUT (child)); submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (i->data)); if (submenu != NULL) @@ -4361,14 +4340,16 @@ add_attribute_recurse (GtkWidget *menu, gint column) { GList *i, *list; + GtkWidget *child; GtkWidget *submenu; - + list = gtk_container_get_children (GTK_CONTAINER (menu)); for (i = list; i; i = i->next) { - if (GTK_IS_CELL_LAYOUT (GTK_BIN (i->data)->child)) - gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (GTK_BIN (i->data)->child), - cell, attribute, column); + child = gtk_bin_get_child (GTK_BIN (i->data)); + if (GTK_IS_CELL_LAYOUT (child)) + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (child), + cell, attribute, column); submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (i->data)); if (submenu != NULL) @@ -4444,7 +4425,7 @@ set_cell_data_func_recurse (GtkWidget *menu, list = gtk_container_get_children (GTK_CONTAINER (menu)); for (i = list; i; i = i->next) { - cell_view = GTK_BIN (i->data)->child; + cell_view = gtk_bin_get_child (GTK_BIN (i->data)); if (GTK_IS_CELL_LAYOUT (cell_view)) { /* Override sensitivity for inner nodes; we don't @@ -4506,15 +4487,16 @@ clear_attributes_recurse (GtkWidget *menu, GtkCellRenderer *cell) { GList *i, *list; - GtkWidget *submenu; - + GtkWidget *submenu; + GtkWidget *child; + list = gtk_container_get_children (GTK_CONTAINER (menu)); for (i = list; i; i = i->next) { - if (GTK_IS_CELL_LAYOUT (GTK_BIN (i->data)->child)) - gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (GTK_BIN (i->data)->child), - cell); - + child = gtk_bin_get_child (GTK_BIN (i->data)); + if (GTK_IS_CELL_LAYOUT (child)) + gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (child), cell); + submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (i->data)); if (submenu != NULL) clear_attributes_recurse (submenu, cell); @@ -4564,15 +4546,17 @@ reorder_recurse (GtkWidget *menu, gint position) { GList *i, *list; + GtkWidget *child; GtkWidget *submenu; - + list = gtk_container_get_children (GTK_CONTAINER (menu)); for (i = list; i; i = i->next) { - if (GTK_IS_CELL_LAYOUT (GTK_BIN (i->data)->child)) - gtk_cell_layout_reorder (GTK_CELL_LAYOUT (GTK_BIN (i->data)->child), - cell, position); - + child = gtk_bin_get_child (GTK_BIN (i->data)); + if (GTK_IS_CELL_LAYOUT (child)) + gtk_cell_layout_reorder (GTK_CELL_LAYOUT (child), + cell, position); + submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (i->data)); if (submenu != NULL) reorder_recurse (submenu, cell, position); @@ -4971,7 +4955,7 @@ gtk_combo_box_set_active_internal (GtkComboBox *combo_box, /** * gtk_combo_box_get_active_iter: * @combo_box: A #GtkComboBox - * @iter: The uninitialized #GtkTreeIter + * @iter: (out): The uninitialized #GtkTreeIter * * Sets @iter to point to the current active item, if it exists. * @@ -5001,12 +4985,10 @@ gtk_combo_box_get_active_iter (GtkComboBox *combo_box, /** * gtk_combo_box_set_active_iter: * @combo_box: A #GtkComboBox - * @iter: The #GtkTreeIter, or %NULL + * @iter: (allow-none): The #GtkTreeIter, or %NULL * * Sets the current active item to be the one referenced by @iter, or * unsets the active item if @iter is %NULL. - * - * @iter must correspond to a path of depth one, or be %NULL. * * Since: 2.4 */ @@ -5107,12 +5089,13 @@ out: } /** - * gtk_combo_box_get_model + * gtk_combo_box_get_model: * @combo_box: A #GtkComboBox * * Returns the #GtkTreeModel which is acting as data source for @combo_box. * - * Return value: (transfer none): A #GtkTreeModel which was passed during construction. + * Return value: (transfer none): A #GtkTreeModel which was passed + * during construction. * * Since: 2.4 */ @@ -5434,9 +5417,9 @@ gtk_combo_box_grab_focus (GtkWidget *widget) } static void -gtk_combo_box_destroy (GtkObject *object) +gtk_combo_box_destroy (GtkWidget *widget) { - GtkComboBox *combo_box = GTK_COMBO_BOX (object); + GtkComboBox *combo_box = GTK_COMBO_BOX (widget); if (combo_box->priv->popup_idle_id > 0) { @@ -5453,7 +5436,7 @@ gtk_combo_box_destroy (GtkObject *object) combo_box->priv->row_separator_data = NULL; combo_box->priv->row_separator_destroy = NULL; - GTK_OBJECT_CLASS (gtk_combo_box_parent_class)->destroy (object); + GTK_WIDGET_CLASS (gtk_combo_box_parent_class)->destroy (widget); combo_box->priv->cell_view = NULL; } @@ -5518,7 +5501,7 @@ gtk_cell_editable_key_press (GtkWidget *widget, { GtkComboBox *combo_box = GTK_COMBO_BOX (data); - if (event->keyval == GDK_Escape) + if (event->keyval == GDK_KEY_Escape) { g_object_set (combo_box, "editing-canceled", TRUE, @@ -5528,9 +5511,9 @@ gtk_cell_editable_key_press (GtkWidget *widget, return TRUE; } - else if (event->keyval == GDK_Return || - event->keyval == GDK_ISO_Enter || - event->keyval == GDK_KP_Enter) + else if (event->keyval == GDK_KEY_Return || + event->keyval == GDK_KEY_ISO_Enter || + event->keyval == GDK_KEY_KP_Enter) { gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (combo_box)); gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (combo_box)); @@ -5594,6 +5577,7 @@ gtk_combo_box_start_editing (GtkCellEditable *cell_editable, GdkEvent *event) { GtkComboBox *combo_box = GTK_COMBO_BOX (cell_editable); + GtkWidget *child; combo_box->priv->is_cell_renderer = TRUE; @@ -5607,12 +5591,14 @@ gtk_combo_box_start_editing (GtkCellEditable *cell_editable, } else { - g_signal_connect_object (GTK_BIN (combo_box)->child, "key-press-event", + child = gtk_bin_get_child (GTK_BIN (combo_box)); + + g_signal_connect_object (child, "key-press-event", G_CALLBACK (gtk_cell_editable_key_press), cell_editable, 0); - gtk_widget_grab_focus (GTK_WIDGET (GTK_BIN (combo_box)->child)); - GTK_WIDGET_UNSET_FLAGS (combo_box->priv->button, GTK_CAN_FOCUS); + gtk_widget_grab_focus (child); + gtk_widget_set_can_focus (combo_box->priv->button, FALSE); } /* we do the immediate popup only for the optionmenu-like @@ -5749,7 +5735,8 @@ gtk_combo_box_set_title (GtkComboBox *combo_box, * This function is mostly intended for use by accessibility technologies; * applications should have little use for it. * - * Returns: the accessible object corresponding to the combo box's popup. + * Returns: (transfer none): the accessible object corresponding + * to the combo box's popup. * * Since: 2.6 */ @@ -5791,8 +5778,8 @@ gtk_combo_box_get_row_separator_func (GtkComboBox *combo_box) * gtk_combo_box_set_row_separator_func: * @combo_box: a #GtkComboBox * @func: a #GtkTreeViewRowSeparatorFunc - * @data: user data to pass to @func, or %NULL - * @destroy: destroy notifier for @data, or %NULL + * @data: (allow-none): user data to pass to @func, or %NULL + * @destroy: (allow-none): destroy notifier for @data, or %NULL * * Sets the row separator function, which is used to determine * whether a row should be drawn as a separator. If the row separator @@ -5959,5 +5946,361 @@ gtk_combo_box_buildable_custom_tag_end (GtkBuildable *buildable, data); } -#define __GTK_COMBO_BOX_C__ -#include "gtkaliasdef.c" + +static void +gtk_combo_box_remeasure (GtkComboBox *combo_box) +{ + GtkComboBoxPrivate *priv = combo_box->priv; + GtkTreeIter iter; + GtkTreePath *path; + + if (!priv->model || + !gtk_tree_model_get_iter_first (priv->model, &iter)) + return; + + priv->minimum_width = priv->natural_width = 0; + + path = gtk_tree_path_new_from_indices (0, -1); + + do + { + gint row_min = 0, row_nat = 0; + + if (priv->cell_view) + gtk_cell_view_get_desired_width_of_row (GTK_CELL_VIEW (priv->cell_view), + path, &row_min, &row_nat); + + priv->minimum_width = MAX (priv->minimum_width, row_min); + priv->natural_width = MAX (priv->natural_width, row_nat); + + gtk_tree_path_next (path); + } + while (gtk_tree_model_iter_next (priv->model, &iter)); + + gtk_tree_path_free (path); +} + + +static void +gtk_combo_box_measure_height_for_width (GtkComboBox *combo_box, + gint avail_width, + gint *min_height, + gint *nat_height) +{ + GtkWidget *child; + GtkComboBoxPrivate *priv = combo_box->priv; + GtkTreeIter iter; + GtkTreePath *path; + gint child_min, child_nat; + + child = gtk_bin_get_child (GTK_BIN (combo_box)); + + gtk_widget_get_preferred_height_for_width (child, avail_width, + &child_min, &child_nat); + + if (!priv->model || + !gtk_tree_model_get_iter_first (priv->model, &iter)) + goto out; + + path = gtk_tree_path_new_from_indices (0, -1); + + do + { + gint row_min = 0, row_nat = 0; + + if (priv->cell_view) + gtk_cell_view_get_desired_height_for_width_of_row (GTK_CELL_VIEW (priv->cell_view), + path, avail_width, + &row_min, &row_nat); + + child_min = MAX (child_min, row_min); + child_nat = MAX (child_nat, row_nat); + + gtk_tree_path_next (path); + } + while (gtk_tree_model_iter_next (priv->model, &iter)); + + gtk_tree_path_free (path); + + out: + + if (min_height) + *min_height = child_min; + if (nat_height) + *nat_height = child_nat; +} + + +static void +gtk_combo_box_get_preferred_width (GtkWidget *widget, + gint *minimum_size, + gint *natural_size) +{ + GtkComboBox *combo_box = GTK_COMBO_BOX (widget); + GtkComboBoxPrivate *priv = combo_box->priv; + GtkStyle *style; + gint focus_width, focus_pad; + gint font_size, arrow_size; + PangoContext *context; + PangoFontMetrics *metrics; + PangoFontDescription *font_desc; + GtkWidget *child; + gint minimum_width, natural_width; + gint child_min, child_nat; + + child = gtk_bin_get_child (GTK_BIN (widget)); + + /* common */ + gtk_widget_get_preferred_width (child, &child_min, &child_nat); + gtk_combo_box_remeasure (combo_box); + + child_min = MAX (child_min, priv->minimum_width); + child_nat = MAX (child_nat, priv->natural_width); + + gtk_widget_style_get (GTK_WIDGET (widget), + "focus-line-width", &focus_width, + "focus-padding", &focus_pad, + "arrow-size", &arrow_size, + NULL); + + font_desc = gtk_widget_get_style (child)->font_desc; + context = gtk_widget_get_pango_context (GTK_WIDGET (widget)); + metrics = pango_context_get_metrics (context, font_desc, + pango_context_get_language (context)); + font_size = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) + + pango_font_metrics_get_descent (metrics)); + pango_font_metrics_unref (metrics); + + arrow_size = MAX (arrow_size, font_size); + + gtk_widget_set_size_request (priv->arrow, arrow_size, arrow_size); + + if (!priv->tree_view) + { + /* menu mode */ + + if (priv->cell_view) + { + gint sep_width, arrow_width; + gint border_width, xthickness, xpad; + + border_width = gtk_container_get_border_width (GTK_CONTAINER (combo_box)); + xthickness = gtk_widget_get_style (priv->button)->xthickness; + + gtk_widget_get_preferred_width (priv->separator, &sep_width, NULL); + gtk_widget_get_preferred_width (priv->arrow, &arrow_width, NULL); + + xpad = 2*(border_width + xthickness + focus_width + focus_pad); + + minimum_width = child_min + sep_width + arrow_width + xpad; + natural_width = child_nat + sep_width + arrow_width + xpad; + } + else + { + gint but_width, but_nat_width; + + gtk_widget_get_preferred_width (priv->button, + &but_width, &but_nat_width); + + minimum_width = child_min + but_width; + natural_width = child_nat + but_nat_width; + } + } + else + { + /* list mode */ + gint button_width, button_nat_width; + + /* sample + frame */ + minimum_width = child_min; + natural_width = child_nat; + + minimum_width += 2 * focus_width; + natural_width += 2 * focus_width; + + if (priv->cell_view_frame) + { + if (priv->has_frame) + { + gint border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->cell_view_frame)); + gint xpad = 2 * (border_width + gtk_widget_get_style (GTK_WIDGET (priv->cell_view_frame))->xthickness); + + minimum_width += xpad; + natural_width += xpad; + } + } + + /* the button */ + gtk_widget_get_preferred_width (priv->button, + &button_width, &button_nat_width); + + minimum_width += button_width; + natural_width += button_nat_width; + } + + if (GTK_SHADOW_NONE != priv->shadow_type) + { + style = gtk_widget_get_style (GTK_WIDGET (widget)); + + minimum_width += 2 * style->xthickness; + natural_width += 2 * style->xthickness; + } + + if (minimum_size) + *minimum_size = minimum_width; + + if (natural_size) + *natural_size = natural_width; +} + +static void +gtk_combo_box_get_preferred_height (GtkWidget *widget, + gint *minimum_size, + gint *natural_size) +{ + gint min_width; + + /* Combo box is height-for-width only + * (so we always just reserve enough height for the minimum width) */ + GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, &min_width, NULL); + GTK_WIDGET_GET_CLASS (widget)->get_preferred_height_for_width (widget, min_width, minimum_size, natural_size); +} + +static void +gtk_combo_box_get_preferred_width_for_height (GtkWidget *widget, + gint avail_size, + gint *minimum_size, + gint *natural_size) +{ + /* Combo box is height-for-width only + * (so we assume we always reserved enough height for the minimum width) */ + GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, minimum_size, natural_size); +} + + +static void +gtk_combo_box_get_preferred_height_for_width (GtkWidget *widget, + gint avail_size, + gint *minimum_size, + gint *natural_size) +{ + GtkComboBox *combo_box = GTK_COMBO_BOX (widget); + GtkComboBoxPrivate *priv = combo_box->priv; + GtkStyle *style; + gint focus_width, focus_pad; + gint min_height, nat_height; + gint size; + + gtk_widget_style_get (GTK_WIDGET (widget), + "focus-line-width", &focus_width, + "focus-padding", &focus_pad, + NULL); + + size = avail_size; + + if (GTK_SHADOW_NONE != priv->shadow_type) + size -= gtk_widget_get_style (GTK_WIDGET (widget))->xthickness; + + if (!priv->tree_view) + { + /* menu mode */ + if (priv->cell_view) + { + GtkStyle *button_style; + /* calculate x/y padding and separator/arrow size */ + gint sep_width, arrow_width, sep_height, arrow_height; + gint border_width, xthickness, ythickness, xpad, ypad; + + border_width = gtk_container_get_border_width (GTK_CONTAINER (combo_box)); + button_style = gtk_widget_get_style (priv->button); + + xthickness = button_style->xthickness; + ythickness = button_style->ythickness; + + gtk_widget_get_preferred_width (priv->separator, &sep_width, NULL); + gtk_widget_get_preferred_width (priv->arrow, &arrow_width, NULL); + gtk_widget_get_preferred_height_for_width (priv->separator, + sep_width, &sep_height, NULL); + gtk_widget_get_preferred_height_for_width (priv->arrow, + arrow_width, &arrow_height, NULL); + + xpad = 2*(border_width + xthickness + focus_width + focus_pad); + ypad = 2*(border_width + ythickness + focus_width + focus_pad); + + size -= sep_width + arrow_width + xpad; + + gtk_combo_box_measure_height_for_width (combo_box, size, &min_height, &nat_height); + + arrow_height = MAX (arrow_height, sep_height); + min_height = MAX (min_height, arrow_height); + nat_height = MAX (nat_height, arrow_height); + + min_height += ypad; + nat_height += ypad; + } + else + { + /* there is a custom child widget inside (no priv->cell_view) */ + gint but_width, but_height; + + gtk_widget_get_preferred_width (priv->button, &but_width, NULL); + gtk_widget_get_preferred_height_for_width (priv->button, + but_width, &but_height, NULL); + + size -= but_width; + + gtk_combo_box_measure_height_for_width (combo_box, size, &min_height, &nat_height); + + min_height = MAX (min_height, but_height); + nat_height = MAX (nat_height, but_height); + } + } + else + { + /* list mode */ + gint but_width, but_height; + gint xpad = 0, ypad = 0; + + gtk_widget_get_preferred_width (priv->button, &but_width, NULL); + gtk_widget_get_preferred_height_for_width (priv->button, + but_width, &but_height, NULL); + + if (priv->cell_view_frame && priv->has_frame) + { + GtkStyle *cell_style; + gint border_width; + + border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->cell_view_frame)); + cell_style = gtk_widget_get_style (GTK_WIDGET (priv->cell_view_frame)); + + xpad = 2 * (border_width + cell_style->xthickness); + ypad = 2 * (border_width + cell_style->ythickness); + } + + size -= but_width; + size -= 2 * focus_width; + size -= xpad; + + gtk_combo_box_measure_height_for_width (combo_box, size, &min_height, &nat_height); + + min_height = MAX (min_height, but_height); + nat_height = MAX (nat_height, but_height); + + min_height += ypad; + nat_height += ypad; + } + + if (GTK_SHADOW_NONE != priv->shadow_type) + { + style = gtk_widget_get_style (GTK_WIDGET (widget)); + + min_height += 2 * style->ythickness; + nat_height += 2 * style->ythickness; + } + + if (minimum_size) + *minimum_size = min_height; + + if (natural_size) + *natural_size = nat_height; +}