X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkcombobox.c;h=794cd00dd33688d706377bc942035cf8f1863320;hb=e09957a47da9425cc26d1b33cb4e9cc3e92e9ac7;hp=195362505e05c35054708c9b06506f98efa296a4;hpb=1bbd2c48c56051ea9290cee085a0110f2b5c3de6;p=~andy%2Fgtk diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c index 195362505..794cd00dd 100644 --- a/gtk/gtkcombobox.c +++ b/gtk/gtkcombobox.c @@ -12,13 +12,14 @@ * 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. + * License along with this library. If not, see . */ #include "config.h" + #include "gtkcombobox.h" + +#include "gtkadjustment.h" #include "gtkcellareabox.h" #include "gtktreemenu.h" #include "gtkarrow.h" @@ -39,6 +40,8 @@ #include "gtktogglebutton.h" #include "gtktreeselection.h" #include "gtkseparator.h" +#include "gtkwidgetpath.h" +#include "gtkwidgetprivate.h" #include "gtkwindow.h" #include "gtktypebuiltins.h" #include "gtkprivate.h" @@ -492,6 +495,8 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass) container_class->remove = gtk_combo_box_remove; container_class->get_path_for_child = gtk_combo_box_get_path_for_child; + gtk_container_class_handle_border_width (container_class); + widget_class = (GtkWidgetClass *)klass; widget_class->size_allocate = gtk_combo_box_size_allocate; widget_class->draw = gtk_combo_box_draw; @@ -1377,11 +1382,17 @@ gtk_combo_box_button_state_flags_changed (GtkWidget *widget, gtk_widget_queue_draw (widget); } +static void +gtk_combo_box_invalidate_order_foreach (GtkWidget *widget) +{ + _gtk_widget_invalidate_style_context (widget, GTK_CSS_CHANGE_POSITION | GTK_CSS_CHANGE_SIBLING_POSITION); +} + static void gtk_combo_box_invalidate_order (GtkComboBox *combo_box) { gtk_container_forall (GTK_CONTAINER (combo_box), - (GtkCallback) gtk_widget_reset_style, + (GtkCallback) gtk_combo_box_invalidate_order_foreach, NULL); } @@ -1404,7 +1415,7 @@ gtk_combo_box_get_path_for_child (GtkContainer *container, GtkWidgetPath *sibling_path; int pos; - path = gtk_widget_path_copy (gtk_widget_get_path (GTK_WIDGET (container))); + path = _gtk_widget_create_path (GTK_WIDGET (container)); if (gtk_widget_get_visible (child)) { @@ -1881,7 +1892,11 @@ gtk_combo_box_menu_position_below (GtkMenu *menu, gdk_window_get_root_coords (gtk_widget_get_window (child), sx, sy, &sx, &sy); get_widget_padding_and_border (GTK_WIDGET (combo_box), &padding); - sx -= padding.left; + + if (gtk_widget_get_direction (GTK_WIDGET (combo_box)) == GTK_TEXT_DIR_RTL) + sx += padding.left; + else + sx -= padding.left; if (combo_box->priv->popup_fixed_width) gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL); @@ -2316,6 +2331,19 @@ popup_grab_on_window (GdkWindow *window, return TRUE; } +static gboolean +gtk_combo_box_grab_broken_event (GtkWidget *widget, + GdkEventGrabBroken *event, + gpointer user_data) +{ + GtkComboBox *combo_box = GTK_COMBO_BOX (user_data); + + if (event->grab_window == NULL) + gtk_combo_box_popdown (combo_box); + + return TRUE; +} + /** * gtk_combo_box_popup: * @combo_box: a #GtkComboBox @@ -2440,6 +2468,11 @@ gtk_combo_box_popup_for_device (GtkComboBox *combo_box, gtk_device_grab_add (priv->popup_window, pointer, TRUE); priv->grab_pointer = pointer; priv->grab_keyboard = keyboard; + + g_signal_connect (priv->popup_window, + "grab-broken-event", + G_CALLBACK (gtk_combo_box_grab_broken_event), + combo_box); } static void @@ -2506,6 +2539,10 @@ gtk_combo_box_popdown (GtkComboBox *combo_box) if (!gtk_widget_get_realized (GTK_WIDGET (combo_box))) return; + if (priv->grab_keyboard) + gdk_device_ungrab (priv->grab_keyboard, GDK_CURRENT_TIME); + gdk_device_ungrab (priv->grab_pointer, GDK_CURRENT_TIME); + gtk_device_grab_remove (priv->popup_window, priv->grab_pointer); gtk_widget_hide (priv->popup_window); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), @@ -2515,22 +2552,24 @@ gtk_combo_box_popdown (GtkComboBox *combo_box) priv->grab_keyboard = NULL; } -#define GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON \ - gtk_widget_get_preferred_size (combo_box->priv->button, \ - &req, NULL); \ - \ - if (is_rtl) \ - child.x = allocation->x + padding.right; \ - else \ - child.x = allocation->x + allocation->width - req.width - padding.left; \ - \ - child.y = allocation->y + padding.top; \ - child.width = req.width; \ - child.height = allocation->height - (padding.top + padding.bottom); \ - child.width = MAX (1, child.width); \ - child.height = MAX (1, child.height); \ - \ - gtk_widget_size_allocate (combo_box->priv->button, &child); +#define GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON \ + GtkAllocation button_allocation; \ + gtk_widget_get_preferred_size (combo_box->priv->button, \ + &req, NULL); \ + \ + if (is_rtl) \ + button_allocation.x = allocation->x; \ + else \ + button_allocation.x = allocation->x + allocation->width \ + - req.width; \ + \ + button_allocation.y = allocation->y; \ + button_allocation.width = MAX (1, req.width); \ + button_allocation.height = allocation->height; \ + button_allocation.height = MAX (1, button_allocation.height); \ + \ + gtk_widget_size_allocate (combo_box->priv->button, \ + &button_allocation); static void @@ -2549,6 +2588,11 @@ gtk_combo_box_size_allocate (GtkWidget *widget, child_widget = gtk_bin_get_child (GTK_BIN (widget)); get_widget_padding_and_border (widget, &padding); + allocation->x += padding.left; + allocation->y += padding.top; + allocation->width -= padding.left + padding.right; + allocation->height -= padding.top + padding.bottom; + if (!priv->tree_view) { if (priv->cell_view) @@ -2557,18 +2601,15 @@ gtk_combo_box_size_allocate (GtkWidget *widget, gint width; guint border_width; - gtk_widget_size_allocate (priv->button, allocation); - - /* menu mode */ - allocation->x += padding.left; - allocation->y += padding.top; - allocation->width -= padding.left + padding.right; - allocation->height -= padding.top + padding.bottom; - - /* set some things ready */ border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->button)); get_widget_padding_and_border (priv->button, &button_padding); + /* menu mode; child_widget is priv->cell_view. + * Allocate the button to the full combobox allocation (minus the + * padding). + */ + gtk_widget_size_allocate (priv->button, allocation); + child.x = allocation->x; child.y = allocation->y; width = allocation->width; @@ -2576,6 +2617,9 @@ gtk_combo_box_size_allocate (GtkWidget *widget, if (!priv->is_cell_renderer) { + /* restrict allocation of the child into the button box + * if we're not in cell renderer mode. + */ child.x += border_width + button_padding.left; child.y += border_width + button_padding.top; width -= 2 * border_width + @@ -2584,7 +2628,7 @@ gtk_combo_box_size_allocate (GtkWidget *widget, button_padding.top + button_padding.bottom; } - /* handle the children */ + /* allocate the box containing the separator and the arrow */ gtk_widget_get_preferred_size (priv->box, &req, NULL); child.width = req.width; if (!is_rtl) @@ -2597,7 +2641,7 @@ gtk_combo_box_size_allocate (GtkWidget *widget, { child.x += req.width; child.width = allocation->x + allocation->width - - border_width - child.x; + - border_width - child.x - button_padding.right; } else { @@ -2638,49 +2682,56 @@ gtk_combo_box_size_allocate (GtkWidget *widget, } else { + /* menu mode; child_widget has been set with gtk_container_add(). + * E.g. it might be a GtkEntry if priv->has_entry is TRUE. + * Allocate the button at the far end, according to the direction + * of the widget. + */ GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON + /* After the macro, button_allocation has the button allocation rect */ + if (is_rtl) - child.x = allocation->x + req.width + padding.right; + child.x = button_allocation.x + button_allocation.width; else - child.x = allocation->x + padding.left; - child.y = allocation->y + padding.top; - child.width = allocation->width - req.width - (padding.left + padding.right); + child.x = allocation->x; + + child.y = allocation->y; + child.width = allocation->width - button_allocation.width; + child.height = button_allocation.height; + child.width = MAX (1, child.width); - child.height = MAX (1, child.height); + gtk_widget_size_allocate (child_widget, &child); } } else { - /* list mode */ - guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); + /* list mode; child_widget might be either priv->cell_view or a child + * added with gtk_container_add(). + */ - /* button */ + /* After the macro, button_allocation has the button allocation rect */ GTK_COMBO_BOX_SIZE_ALLOCATE_BUTTON - /* frame */ if (is_rtl) - child.x = allocation->x + req.width; + child.x = button_allocation.x + button_allocation.width; else child.x = allocation->x; child.y = allocation->y; - child.width = allocation->width - req.width; - child.height = allocation->height; + child.width = allocation->width - button_allocation.width; + child.height = button_allocation.height; if (priv->cell_view_frame) { - child.x += padding.left + border_width; - child.y += padding.top + border_width; - child.width = MAX (1, child.width - (2 * border_width) - (padding.left + padding.right)); - child.height = MAX (1, child.height - (2 * border_width) - (padding.top + padding.bottom)); gtk_widget_size_allocate (priv->cell_view_frame, &child); - /* the sample */ + /* restrict allocation of the child into the frame box if it's present */ if (priv->has_frame) { GtkBorder frame_padding; + guint border_width; border_width = gtk_container_get_border_width (GTK_CONTAINER (priv->cell_view_frame)); get_widget_padding_and_border (priv->cell_view_frame, &frame_padding); @@ -2691,13 +2742,6 @@ gtk_combo_box_size_allocate (GtkWidget *widget, child.height -= (2 * border_width) + frame_padding.top + frame_padding.bottom; } } - else - { - child.x += padding.left + border_width; - child.y += padding.top + border_width; - child.width -= (2 * border_width) - (padding.left + padding.right); - child.height -= (2 * border_width) - (padding.top + padding.bottom); - } if (gtk_widget_get_visible (priv->popup_window)) { @@ -2707,6 +2751,7 @@ gtk_combo_box_size_allocate (GtkWidget *widget, gtk_widget_set_size_request (priv->popup_window, width, height); } + /* allocate the child */ child.width = MAX (1, child.width); child.height = MAX (1, child.height); gtk_widget_size_allocate (child_widget, &child); @@ -3117,6 +3162,7 @@ gtk_combo_box_menu_setup (GtkComboBox *combo_box, priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); gtk_container_add (GTK_CONTAINER (priv->box), priv->arrow); + gtk_widget_add_events (priv->button, GDK_SCROLL_MASK); gtk_widget_show_all (priv->button); } @@ -3133,6 +3179,7 @@ gtk_combo_box_menu_setup (GtkComboBox *combo_box, priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); gtk_container_add (GTK_CONTAINER (priv->button), priv->arrow); + gtk_widget_add_events (priv->button, GDK_SCROLL_MASK); gtk_widget_show_all (priv->button); } @@ -5421,12 +5468,9 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget, gint font_size, arrow_size; PangoContext *context; PangoFontMetrics *metrics; - const PangoFontDescription *font_desc; GtkWidget *child; gint minimum_width = 0, natural_width = 0; gint child_min, child_nat; - GtkStyleContext *style_context; - GtkStateFlags state; GtkBorder padding; gfloat arrow_scaling; @@ -5440,14 +5484,11 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget, "arrow-scaling", &arrow_scaling, NULL); - style_context = gtk_widget_get_style_context (widget); - state = gtk_widget_get_state_flags (widget); - get_widget_padding_and_border (widget, &padding); - font_desc = gtk_style_context_get_font (style_context, state); context = gtk_widget_get_pango_context (GTK_WIDGET (widget)); - metrics = pango_context_get_metrics (context, font_desc, + metrics = pango_context_get_metrics (context, + pango_context_get_font_description (context), pango_context_get_language (context)); font_size = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent (metrics)); @@ -5462,16 +5503,13 @@ gtk_combo_box_get_preferred_width (GtkWidget *widget, /* menu mode */ if (priv->cell_view) { - gint box_width; - gint border_width, xpad; + gint box_width, xpad; GtkBorder button_padding; - border_width = gtk_container_get_border_width (GTK_CONTAINER (combo_box)); get_widget_padding_and_border (priv->button, &button_padding); gtk_widget_get_preferred_width (priv->box, &box_width, NULL); - xpad = 2 * border_width + - button_padding.left + button_padding.right + padding.left + padding.right; + xpad = button_padding.left + button_padding.right + padding.left + padding.right; minimum_width = child_min + box_width + xpad; natural_width = child_nat + box_width + xpad; @@ -5580,20 +5618,17 @@ gtk_combo_box_get_preferred_height_for_width (GtkWidget *widget, { /* calculate x/y padding and separator/arrow size */ gint box_width, box_height; - gint border_width, xpad, ypad; + gint xpad, ypad; GtkBorder button_padding; - border_width = gtk_container_get_border_width (GTK_CONTAINER (combo_box)); get_widget_padding_and_border (priv->button, &button_padding); gtk_widget_get_preferred_width (priv->box, &box_width, NULL); gtk_widget_get_preferred_height_for_width (priv->box, box_width, &box_height, NULL); - xpad = 2 * border_width + - button_padding.left + button_padding.right; - ypad = 2 * border_width + - button_padding.top + button_padding.bottom; + xpad = button_padding.left + button_padding.right; + ypad = button_padding.top + button_padding.bottom; size -= box_width + xpad;