X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=hildon%2Fhildon-app-menu.c;h=9c9808112ab3c148b5ce2e838b996d9405747759;hb=ab90c2aebca089438622f1b63faca01fc147edf2;hp=7e838e445a702900af48fcd47b9d872e61652c68;hpb=2e82a267b1f5146952dd71d1cbb5151c69b6cf0a;p=hildon diff --git a/hildon/hildon-app-menu.c b/hildon/hildon-app-menu.c index 7e838e4..9c98081 100644 --- a/hildon/hildon-app-menu.c +++ b/hildon/hildon-app-menu.c @@ -18,10 +18,10 @@ /** * SECTION:hildon-app-menu - * @short_description: Widget representing the application menu in the Hildon framework. + * @short_description: Application menu for Hildon applications. * - * The #HildonAppMenu is a GTK widget which represents an application - * menu in the Hildon framework. + * #HildonAppMenu is an application menu for applications in the Hildon + * framework. * * This menu opens from the top of the screen and contains a number of * entries (#GtkButton) organized in one or two columns, depending on @@ -29,8 +29,12 @@ * if the screen is resized). Entries are added left to right and top * to bottom. * - * Besides that, the #HildonAppMenu can contain a group of filter buttons - * (#GtkToggleButton or #GtkRadioButton). + * Besides that, #HildonAppMenu can contain a group of filter buttons + * (#GtkToggleButton or #GtkRadioButton). Filters are meant to change + * the way data is presented in the application, rather than change + * the layout of the menu itself. For example, a file manager can have + * filters to decide the order used to display a list of files (name, + * date, size, etc.). * * To use a #HildonAppMenu, add it to a #HildonWindow using * hildon_window_set_app_menu(). The menu will appear when the user @@ -100,6 +104,7 @@ #include "hildon-app-menu-private.h" #include "hildon-window.h" #include "hildon-banner.h" +#include "hildon-animation-actor.h" static GdkWindow * grab_transfer_window_get (GtkWidget *widget); @@ -126,6 +131,11 @@ filter_visibility_changed (GtkWidget *item, GParamSpec *arg1, HildonAppMenu *menu); +static gboolean +menu_item_button_event (GtkButton *item, + GdkEventButton *event, + GtkWidget *menu); + static void remove_item_from_list (GList **list, gpointer item); @@ -190,6 +200,10 @@ hildon_app_menu_insert (HildonAppMenu *menu, g_signal_connect_swapped (item, "clicked", G_CALLBACK (gtk_widget_hide), menu); g_signal_connect (item, "notify::visible", G_CALLBACK (item_visibility_changed), menu); + /* Keep track of the latest menu item to receive a button-press event */ + g_signal_connect (item, "button-press-event", G_CALLBACK (menu_item_button_event), menu); + g_signal_connect (item, "button-release-event", G_CALLBACK (menu_item_button_event), menu); + /* Remove item from list when it is destroyed */ g_object_weak_ref (G_OBJECT (item), (GWeakNotify) remove_item_from_list, &(priv->buttons)); } @@ -297,6 +311,10 @@ hildon_app_menu_add_filter (HildonAppMenu *menu, g_signal_connect_swapped (filter, "clicked", G_CALLBACK (gtk_widget_hide), menu); g_signal_connect (filter, "notify::visible", G_CALLBACK (filter_visibility_changed), menu); + /* Keep track of the latest menu item to receive a button-press event */ + g_signal_connect (filter, "button-press-event", G_CALLBACK (menu_item_button_event), menu); + g_signal_connect (filter, "button-release-event", G_CALLBACK (menu_item_button_event), menu); + /* Remove filter from list when it is destroyed */ g_object_weak_ref (G_OBJECT (filter), (GWeakNotify) remove_item_from_list, &(priv->filters)); } @@ -418,6 +436,27 @@ filter_visibility_changed (GtkWidget *item, hildon_app_menu_repack_filters (menu); } +static gboolean +menu_item_button_event (GtkButton *item, + GdkEventButton *event, + GtkWidget *menu) +{ + HildonAppMenuPrivate *priv = HILDON_APP_MENU_GET_PRIVATE (menu); + + if (event->type == GDK_BUTTON_PRESS) { + priv->last_pressed_button = item; + } else if (event->type == GDK_BUTTON_RELEASE) { + /* A pressed button might not receive the button-release event due + * to the grab that HildonAppMenu has, so we have to simulate that + * event. See NB#108337 */ + if (priv->last_pressed_button && priv->last_pressed_button != item) { + gtk_button_released (priv->last_pressed_button); + } + priv->last_pressed_button = NULL; + } + return FALSE; +} + static void remove_item_from_list (GList **list, gpointer item) @@ -492,7 +531,7 @@ hildon_app_menu_find_intruder (gpointer data) * Yes, this is a hack. See NB#111027 */ if (HILDON_IS_BANNER (i->data)) { gtk_widget_hide (i->data); - } else { + } else if (!HILDON_IS_ANIMATION_ACTOR (i->data)) { intruder_found = TRUE; } } @@ -515,14 +554,15 @@ hildon_app_menu_map (GtkWidget *widget) { HildonAppMenuPrivate *priv = HILDON_APP_MENU_GET_PRIVATE(widget); + if (priv->transfer_window == NULL) + priv->transfer_window = grab_transfer_window_get (widget); + GTK_WIDGET_CLASS (hildon_app_menu_parent_class)->map (widget); /* Grab pointer and keyboard */ - if (priv->transfer_window == NULL) { + if (priv->transfer_window != NULL) { gboolean has_grab = FALSE; - priv->transfer_window = grab_transfer_window_get (widget); - if (gdk_pointer_grab (priv->transfer_window, TRUE, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | @@ -549,7 +589,8 @@ hildon_app_menu_map (GtkWidget *widget) * new window appears */ gtk_window_set_is_temporary (GTK_WINDOW (widget), TRUE); - priv->find_intruder_idle_id = gdk_threads_add_idle (hildon_app_menu_find_intruder, widget); + if (priv->find_intruder_idle_id == 0) + priv->find_intruder_idle_id = gdk_threads_add_idle (hildon_app_menu_find_intruder, widget); } static void @@ -691,6 +732,8 @@ hildon_app_menu_button_release (GtkWidget *widget, } priv->pressed_outside = FALSE; /* Always reset pressed_outside to FALSE */ + } else if (priv->last_pressed_button) { + menu_item_button_event (NULL, event, widget); } if (GTK_WIDGET_CLASS (hildon_app_menu_parent_class)->button_release_event) { @@ -790,6 +833,7 @@ static void hildon_app_menu_apply_style (GtkWidget *widget) { GdkScreen *screen; + gint filter_group_width; guint horizontal_spacing, vertical_spacing, filter_vertical_spacing; guint inner_border, external_border; HildonAppMenuPrivate *priv; @@ -799,6 +843,7 @@ hildon_app_menu_apply_style (GtkWidget *widget) gtk_widget_style_get (widget, "horizontal-spacing", &horizontal_spacing, "vertical-spacing", &vertical_spacing, + "filter-group-width", &filter_group_width, "filter-vertical-spacing", &filter_vertical_spacing, "inner-border", &inner_border, "external-border", &external_border, @@ -812,6 +857,9 @@ hildon_app_menu_apply_style (GtkWidget *widget) /* Set inner border */ gtk_container_set_border_width (GTK_CONTAINER (widget), inner_border); + /* Set width of the group of filter buttons */ + gtk_widget_set_size_request (GTK_WIDGET (priv->filters_hbox), filter_group_width, -1); + /* Compute width request */ screen = gtk_widget_get_screen (widget); if (gdk_screen_get_width (screen) < gdk_screen_get_height (screen)) { @@ -868,14 +916,18 @@ hildon_app_menu_repack_items (HildonAppMenu *menu, gint start_from) { HildonAppMenuPrivate *priv; - gint row, col; + gint row, col, nvisible, i; GList *iter; priv = HILDON_APP_MENU_GET_PRIVATE(menu); - /* Remove buttons from their parent */ - if (start_from != -1) { - for (iter = g_list_nth (priv->buttons, start_from); iter != NULL; iter = iter->next) { + i = nvisible = 0; + for (iter = priv->buttons; iter != NULL; iter = iter->next) { + /* Count number of visible items */ + if (GTK_WIDGET_VISIBLE (iter->data)) + nvisible++; + /* Remove buttons from their parent */ + if (start_from != -1 && i >= start_from) { GtkWidget *item = GTK_WIDGET (iter->data); GtkWidget *parent = gtk_widget_get_parent (item); if (parent) { @@ -883,10 +935,16 @@ hildon_app_menu_repack_items (HildonAppMenu *menu, gtk_container_remove (GTK_CONTAINER (parent), item); } } + i++; + } - /* If items have been removed, recalculate the size of the menu */ + /* If items have been removed, recalculate the size of the menu */ + if (start_from != -1) gtk_window_resize (GTK_WINDOW (menu), 1, 1); - } + + /* Set the final size now to avoid unnecessary resizes later */ + if (nvisible > 0) + gtk_table_resize (priv->table, ((nvisible - 1) / priv->columns) + 1, priv->columns); /* Add buttons */ row = col = 0; @@ -906,14 +964,6 @@ hildon_app_menu_repack_items (HildonAppMenu *menu, } } } - - /* The number of rows/columns might have changed, so we have to - * resize the table */ - if (col == 0) { - gtk_table_resize (priv->table, MAX (row, 1), priv->columns); - } else { - gtk_table_resize (priv->table, row + 1, priv->columns); - } } /** @@ -1009,6 +1059,7 @@ hildon_app_menu_init (HildonAppMenu *menu) priv->transfer_window = NULL; priv->pressed_outside = FALSE; priv->inhibit_repack = FALSE; + priv->last_pressed_button = NULL; priv->buttons = NULL; priv->filters = NULL; priv->columns = 2; @@ -1113,6 +1164,16 @@ hildon_app_menu_class_init (HildonAppMenuClass *klass) gtk_widget_class_install_style_property ( widget_class, + g_param_spec_int ( + "filter-group-width", + "Width of the group of filter buttons", + "Total width of the group of filter buttons, " + "or -1 to use the natural size request.", + -1, G_MAXINT, 444, + G_PARAM_READABLE)); + + gtk_widget_class_install_style_property ( + widget_class, g_param_spec_uint ( "filter-vertical-spacing", "Vertical spacing between filters and menu items",