1224 lines
39 KiB
Diff
1224 lines
39 KiB
Diff
--- gtk+-2.6.4/gtk/gtkmenu.c 2005-03-01 08:28:56.000000000 +0200
|
|
+++ gtk+-2.6.4/gtk/gtkmenu.c 2005-04-06 16:19:36.921925376 +0300
|
|
@@ -24,10 +24,16 @@
|
|
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
|
*/
|
|
|
|
+/* Modified for Nokia Oyj during 2002-2005. See CHANGES file for list
|
|
+ * of changes.
|
|
+ */
|
|
+
|
|
#define GTK_MENU_INTERNALS
|
|
|
|
#include <config.h>
|
|
#include <string.h> /* memset */
|
|
+#include <math.h>
|
|
+#include <stdlib.h>
|
|
#include "gdk/gdkkeysyms.h"
|
|
#include "gtkalias.h"
|
|
#include "gtkaccellabel.h"
|
|
@@ -44,7 +50,11 @@
|
|
#include "gtkvscrollbar.h"
|
|
#include "gtksettings.h"
|
|
#include "gtkintl.h"
|
|
+#include "gtkcombobox.h"
|
|
|
|
+/* Hildon : We need this to figure out if menu should have
|
|
+ * corners etc. */
|
|
+#include "gtkmenubar.h"
|
|
|
|
#define MENU_ITEM_CLASS(w) GTK_MENU_ITEM_GET_CLASS (w)
|
|
|
|
@@ -55,16 +65,43 @@
|
|
* extends below the submenu
|
|
*/
|
|
|
|
+/* HILDON:
|
|
+ * Urgh, nasty thing to hard-code things like these :p
|
|
+ * One should really do some rewriting here...
|
|
+ */
|
|
+
|
|
#define MENU_SCROLL_STEP1 8
|
|
#define MENU_SCROLL_STEP2 15
|
|
-#define MENU_SCROLL_ARROW_HEIGHT 16
|
|
-#define MENU_SCROLL_FAST_ZONE 8
|
|
+#define MENU_SCROLL_ARROW_HEIGHT 20 /* This used to be: 23; This hard-coding should be
|
|
+ * changed. Add arrow_height style property into
|
|
+ * commongtkrc and read it from there everywhere
|
|
+ * where a reference to MENU_SCROLL_ARROW_HEIGHT
|
|
+ * is made.
|
|
+ * If these changes are made, please modify also
|
|
+ * gtkcombobox.c.
|
|
+ */
|
|
+#define MENU_SCROLL_FAST_ZONE MENU_SCROLL_ARROW_HEIGHT /* Was originally 8 */
|
|
#define MENU_SCROLL_TIMEOUT1 50
|
|
#define MENU_SCROLL_TIMEOUT2 20
|
|
|
|
#define ATTACH_INFO_KEY "gtk-menu-child-attach-info-key"
|
|
#define ATTACHED_MENUS "gtk-attached-menus"
|
|
|
|
+/* HILDON: */
|
|
+#define HILDON_MENU_NAME_SHARP "menu_with_corners"
|
|
+
|
|
+/* needed to allow different themeing for first level menus */
|
|
+#define HILDON_MENU_NAME_ROUND_FIRST_LEVEL "menu_without_corners_first_level"
|
|
+#define HILDON_MENU_NAME_ROUND "menu_without_corners"
|
|
+#define HILDON_MENU_NAME_FORCE_SHARP "menu_force_with_corners"
|
|
+#define HILDON_MENU_NAME_FORCE_ROUND "menu_force_without_corners"
|
|
+
|
|
+/* maximum sizes for menus when attached to comboboxes */
|
|
+#define HILDON_MENU_COMBO_MAX_WIDTH 406
|
|
+#define HILDON_MENU_COMBO_MIN_WIDTH 66
|
|
+#define HILDON_MENU_COMBO_MAX_HEIGHT 305
|
|
+#define HILDON_MENU_COMBO_MIN_HEIGHT 70
|
|
+
|
|
typedef struct _GtkMenuAttachData GtkMenuAttachData;
|
|
typedef struct _GtkMenuPrivate GtkMenuPrivate;
|
|
|
|
@@ -92,6 +129,15 @@
|
|
gboolean have_layout;
|
|
gint n_rows;
|
|
gint n_columns;
|
|
+
|
|
+ /* Arrow states */
|
|
+ GtkStateType lower_arrow_state;
|
|
+ GtkStateType upper_arrow_state;
|
|
+
|
|
+ /* For context menu behavior */
|
|
+ gboolean context_menu;
|
|
+ int popup_pointer_x;
|
|
+ int popup_pointer_y;
|
|
};
|
|
|
|
typedef struct
|
|
@@ -108,6 +154,7 @@
|
|
|
|
enum {
|
|
MOVE_SCROLL,
|
|
+ CLOSE_CURRENT,
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
@@ -191,7 +238,8 @@
|
|
static void gtk_menu_handle_scrolling (GtkMenu *menu,
|
|
gint event_x,
|
|
gint event_y,
|
|
- gboolean enter);
|
|
+ gboolean enter,
|
|
+ gboolean motion);
|
|
static void gtk_menu_set_tearoff_hints (GtkMenu *menu,
|
|
gint width);
|
|
static void gtk_menu_style_set (GtkWidget *widget,
|
|
@@ -232,6 +280,9 @@
|
|
guint signal_id);
|
|
static void _gtk_menu_refresh_accel_paths (GtkMenu *menu,
|
|
gboolean group_changed);
|
|
+static gboolean gtk_menu_check_name (GtkWidget *widget);
|
|
+
|
|
+static void _gtk_menu_close_current (GtkMenu *menu);
|
|
|
|
static GtkMenuShellClass *parent_class = NULL;
|
|
static const gchar attach_data_key[] = "gtk-menu-attach-data";
|
|
@@ -496,7 +547,6 @@
|
|
widget_class->hide_all = gtk_menu_hide_all;
|
|
widget_class->enter_notify_event = gtk_menu_enter_notify;
|
|
widget_class->leave_notify_event = gtk_menu_leave_notify;
|
|
- widget_class->motion_notify_event = gtk_menu_motion_notify;
|
|
widget_class->style_set = gtk_menu_style_set;
|
|
widget_class->focus = gtk_menu_focus;
|
|
widget_class->can_activate_accel = gtk_menu_real_can_activate_accel;
|
|
@@ -521,6 +571,15 @@
|
|
_gtk_marshal_VOID__ENUM,
|
|
G_TYPE_NONE, 1,
|
|
GTK_TYPE_SCROLL_TYPE);
|
|
+
|
|
+ menu_signals[CLOSE_CURRENT] =
|
|
+ _gtk_binding_signal_new ("close_current",
|
|
+ G_OBJECT_CLASS_TYPE (object_class),
|
|
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
|
+ G_CALLBACK (_gtk_menu_close_current),
|
|
+ NULL, NULL,
|
|
+ _gtk_marshal_VOID__VOID,
|
|
+ G_TYPE_NONE, 0);
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_TEAROFF_TITLE,
|
|
@@ -606,6 +665,11 @@
|
|
G_PARAM_READWRITE));
|
|
|
|
binding_set = gtk_binding_set_by_class (class);
|
|
+ /* Hildon : We moved handling of escape-key here because we need it to
|
|
+ * work like closing a submenu, not closing all the menus. */
|
|
+ gtk_binding_entry_add_signal (binding_set,
|
|
+ GDK_Escape, 0,
|
|
+ "close_current", 0);
|
|
gtk_binding_entry_add_signal (binding_set,
|
|
GDK_Up, 0,
|
|
"move_current", 1,
|
|
@@ -709,6 +773,25 @@
|
|
DEFAULT_POPDOWN_DELAY,
|
|
G_PARAM_READWRITE));
|
|
|
|
+ /* Hildon addition : border width was
|
|
+ replaced with horizontal-padding and
|
|
+ vertical-padding (which already is an style
|
|
+ property for GtkMenu). */
|
|
+ gtk_widget_class_install_style_property (widget_class,
|
|
+ g_param_spec_int ("horizontal-padding",
|
|
+ P_("Horizontal Padding"),
|
|
+ P_("Extra space at the left and right edges of the menu"),
|
|
+ 0,
|
|
+ G_MAXINT,
|
|
+ 0, /* 1, */
|
|
+ G_PARAM_READABLE));
|
|
+
|
|
+ gtk_widget_class_install_style_property (widget_class,
|
|
+ g_param_spec_boolean ("double_arrows",
|
|
+ P_("Double Arrows"),
|
|
+ P_("When scrolling, always show both arrows."),
|
|
+ FALSE,
|
|
+ G_PARAM_READABLE));
|
|
}
|
|
|
|
|
|
@@ -884,13 +967,14 @@
|
|
menu->toggle_size = 0;
|
|
|
|
menu->toplevel = g_object_connect (g_object_new (GTK_TYPE_WINDOW,
|
|
- "type", GTK_WINDOW_POPUP,
|
|
- "child", menu,
|
|
- NULL),
|
|
+ "type", GTK_WINDOW_POPUP,
|
|
+ "child", menu,
|
|
+ NULL),
|
|
"signal::event", gtk_menu_window_event, menu,
|
|
"signal::size_request", gtk_menu_window_size_request, menu,
|
|
"signal::destroy", gtk_widget_destroyed, &menu->toplevel,
|
|
NULL);
|
|
+
|
|
gtk_window_set_resizable (GTK_WINDOW (menu->toplevel), FALSE);
|
|
gtk_window_set_mnemonic_modifier (GTK_WINDOW (menu->toplevel), 0);
|
|
|
|
@@ -919,6 +1003,15 @@
|
|
menu->lower_arrow_visible = FALSE;
|
|
menu->upper_arrow_prelight = FALSE;
|
|
menu->lower_arrow_prelight = FALSE;
|
|
+
|
|
+ /* <Hildon> */
|
|
+ priv->upper_arrow_state = GTK_STATE_NORMAL;
|
|
+ priv->lower_arrow_state = GTK_STATE_NORMAL;
|
|
+
|
|
+ priv->context_menu = FALSE;
|
|
+ priv->popup_pointer_x = -1;
|
|
+ priv->popup_pointer_y = -1;
|
|
+ /* </hildon */
|
|
|
|
priv->have_layout = FALSE;
|
|
}
|
|
@@ -1220,7 +1313,8 @@
|
|
|
|
static gboolean
|
|
popup_grab_on_window (GdkWindow *window,
|
|
- guint32 activate_time)
|
|
+ guint32 activate_time,
|
|
+ gboolean grab_keyboard)
|
|
{
|
|
if ((gdk_pointer_grab (window, TRUE,
|
|
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
|
|
@@ -1228,7 +1322,8 @@
|
|
GDK_POINTER_MOTION_MASK,
|
|
NULL, NULL, activate_time) == 0))
|
|
{
|
|
- if (gdk_keyboard_grab (window, TRUE,
|
|
+ if (!grab_keyboard ||
|
|
+ gdk_keyboard_grab (window, TRUE,
|
|
activate_time) == 0)
|
|
return TRUE;
|
|
else
|
|
@@ -1282,6 +1377,7 @@
|
|
GtkWidget *parent;
|
|
GdkEvent *current_event;
|
|
GtkMenuShell *menu_shell;
|
|
+ gboolean grab_keyboard;
|
|
GtkMenuPrivate *priv = gtk_menu_get_private (menu);
|
|
|
|
g_return_if_fail (GTK_IS_MENU (menu));
|
|
@@ -1333,10 +1429,28 @@
|
|
* probably could just leave the grab on the other window, with a
|
|
* little reorganization of the code in gtkmenu*).
|
|
*/
|
|
+
|
|
+ grab_keyboard = gtk_menu_shell_get_take_focus (menu_shell);
|
|
+ gtk_window_set_accept_focus (GTK_WINDOW (menu->toplevel), grab_keyboard);
|
|
+
|
|
if (xgrab_shell && xgrab_shell != widget)
|
|
{
|
|
- if (popup_grab_on_window (xgrab_shell->window, activate_time))
|
|
+ if (popup_grab_on_window (xgrab_shell->window, activate_time, grab_keyboard))
|
|
GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE;
|
|
+
|
|
+ /* HILDON:
|
|
+ * Check wheter parent is GtkMenuBar. If so,
|
|
+ * then we need sharp upper corners for this menu.
|
|
+ */
|
|
+ if (gtk_menu_check_name (widget))
|
|
+ {
|
|
+ if (GTK_IS_MENU_BAR (parent_menu_shell))
|
|
+ gtk_widget_set_name (widget, HILDON_MENU_NAME_SHARP);
|
|
+ else if (GTK_IS_MENU (parent_menu_shell))
|
|
+ gtk_widget_set_name( widget, HILDON_MENU_NAME_ROUND);
|
|
+ else
|
|
+ gtk_widget_set_name (widget, HILDON_MENU_NAME_ROUND_FIRST_LEVEL);
|
|
+ }
|
|
}
|
|
else
|
|
{
|
|
@@ -1344,8 +1458,14 @@
|
|
|
|
xgrab_shell = widget;
|
|
transfer_window = menu_grab_transfer_window_get (menu);
|
|
- if (popup_grab_on_window (transfer_window, activate_time))
|
|
+ if (popup_grab_on_window (transfer_window, activate_time, grab_keyboard))
|
|
GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE;
|
|
+
|
|
+ /* HILDON:
|
|
+ * We want this menu to have round corners (Used by default)
|
|
+ */
|
|
+ if (gtk_menu_check_name (widget))
|
|
+ gtk_widget_set_name (widget, HILDON_MENU_NAME_ROUND_FIRST_LEVEL);
|
|
}
|
|
|
|
if (!GTK_MENU_SHELL (xgrab_shell)->have_xgrab)
|
|
@@ -1409,6 +1529,23 @@
|
|
|
|
/* Position the menu, possibly changing the size request
|
|
*/
|
|
+ if (GTK_IS_COMBO_BOX (gtk_menu_get_attach_widget (menu)))
|
|
+ {
|
|
+ /* Hildon - limit the size if the menu is attached to a ComboBox */
|
|
+ GtkRequisition req;
|
|
+ gint width, height;
|
|
+
|
|
+ gtk_widget_set_size_request (widget, -1, -1);
|
|
+ gtk_widget_size_request (widget, &req);
|
|
+
|
|
+ width = MAX (MIN (req.width, HILDON_MENU_COMBO_MAX_WIDTH),
|
|
+ HILDON_MENU_COMBO_MIN_WIDTH);
|
|
+ height = MAX (MIN (req.height, HILDON_MENU_COMBO_MAX_HEIGHT),
|
|
+ HILDON_MENU_COMBO_MIN_HEIGHT);
|
|
+
|
|
+ gtk_widget_set_size_request (widget, width, height);
|
|
+ }
|
|
+
|
|
gtk_menu_position (menu);
|
|
|
|
/* Compute the size of the toplevel and realize it so we
|
|
@@ -1430,13 +1567,29 @@
|
|
|
|
gtk_menu_scroll_to (menu, menu->scroll_offset);
|
|
|
|
+ if (priv->context_menu)
|
|
+ {
|
|
+ /* Save position of the pointer during popup */
|
|
+ /* currently not-multihead safe */
|
|
+ GdkScreen *screen;
|
|
+ GdkDisplay *display;
|
|
+
|
|
+ screen = gtk_widget_get_screen (widget);
|
|
+ display = gdk_screen_get_display (screen);
|
|
+
|
|
+ gdk_display_get_pointer (display, NULL,
|
|
+ &priv->popup_pointer_x,
|
|
+ &priv->popup_pointer_y,
|
|
+ NULL);
|
|
+ }
|
|
+
|
|
/* Once everything is set up correctly, map the toplevel window on
|
|
the screen.
|
|
*/
|
|
gtk_widget_show (menu->toplevel);
|
|
|
|
if (xgrab_shell == widget)
|
|
- popup_grab_on_window (widget->window, activate_time); /* Should always succeed */
|
|
+ popup_grab_on_window (widget->window, activate_time, grab_keyboard); /* Should always succeed */
|
|
gtk_grab_add (GTK_WIDGET (menu));
|
|
}
|
|
|
|
@@ -1996,6 +2149,7 @@
|
|
GtkWidget *child;
|
|
GList *children;
|
|
guint vertical_padding;
|
|
+ guint horizontal_padding;
|
|
|
|
g_return_if_fail (GTK_IS_MENU (widget));
|
|
|
|
@@ -2025,9 +2179,10 @@
|
|
|
|
gtk_widget_style_get (GTK_WIDGET (menu),
|
|
"vertical-padding", &vertical_padding,
|
|
+ "horizontal-padding", &horizontal_padding,
|
|
NULL);
|
|
|
|
- attributes.x = border_width + widget->style->xthickness;
|
|
+ attributes.x = border_width + widget->style->xthickness + horizontal_padding;
|
|
attributes.y = border_width + widget->style->ythickness + vertical_padding;
|
|
attributes.width = MAX (1, widget->allocation.width - attributes.x * 2);
|
|
attributes.height = MAX (1, widget->allocation.height - attributes.y * 2);
|
|
@@ -2040,11 +2195,14 @@
|
|
if (menu->lower_arrow_visible)
|
|
attributes.height -= MENU_SCROLL_ARROW_HEIGHT;
|
|
|
|
+ attributes.window_type = GDK_WINDOW_CHILD;
|
|
+
|
|
menu->view_window = gdk_window_new (widget->window, &attributes, attributes_mask);
|
|
gdk_window_set_user_data (menu->view_window, menu);
|
|
|
|
attributes.x = 0;
|
|
attributes.y = 0;
|
|
+ attributes.width = MAX (1, widget->requisition.width - (border_width + widget->style->xthickness + horizontal_padding) * 2);
|
|
attributes.height = MAX (1, widget->requisition.height - (border_width + widget->style->ythickness + vertical_padding) * 2);
|
|
|
|
menu->bin_window = gdk_window_new (menu->view_window, &attributes, attributes_mask);
|
|
@@ -2164,6 +2322,10 @@
|
|
guint vertical_padding;
|
|
GtkRequisition child_requisition;
|
|
GtkMenuPrivate *priv;
|
|
+ guint horizontal_padding;
|
|
+ GdkScreen *screen;
|
|
+ GdkRectangle monitor;
|
|
+ gint monitor_num;
|
|
|
|
g_return_if_fail (GTK_IS_MENU (widget));
|
|
g_return_if_fail (requisition != NULL);
|
|
@@ -2182,6 +2344,16 @@
|
|
priv->heights = g_new0 (guint, gtk_menu_get_n_rows (menu));
|
|
priv->heights_length = gtk_menu_get_n_rows (menu);
|
|
|
|
+/* Hildon addition to find out the monitor width */
|
|
+ screen = gtk_widget_get_screen (widget);
|
|
+ if (widget->window != NULL)
|
|
+ monitor_num = gdk_screen_get_monitor_at_window (screen, widget->window);
|
|
+ else
|
|
+ monitor_num = 0;
|
|
+ if (monitor_num < 0)
|
|
+ monitor_num = 0;
|
|
+ gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
|
|
+
|
|
children = menu_shell->children;
|
|
while (children)
|
|
{
|
|
@@ -2223,15 +2395,18 @@
|
|
|
|
requisition->width += max_toggle_size + max_accel_width;
|
|
requisition->width *= gtk_menu_get_n_columns (menu);
|
|
- requisition->width += (GTK_CONTAINER (menu)->border_width +
|
|
- widget->style->xthickness) * 2;
|
|
|
|
gtk_widget_style_get (GTK_WIDGET (menu),
|
|
+ "horizontal-padding", &horizontal_padding,
|
|
"vertical-padding", &vertical_padding,
|
|
NULL);
|
|
+ requisition->width += (GTK_CONTAINER (menu)->border_width + horizontal_padding +
|
|
+ widget->style->xthickness) * 2;
|
|
requisition->height += (GTK_CONTAINER (menu)->border_width + vertical_padding +
|
|
widget->style->ythickness) * 2;
|
|
|
|
+/* Hildon addition to not make the menu too wide for the screen. */
|
|
+ requisition->width = MIN (requisition->width, monitor.width);
|
|
menu->toggle_size = max_toggle_size;
|
|
|
|
/* Don't resize the tearoff if it is not active, because it won't redraw (it is only a background pixmap).
|
|
@@ -2253,6 +2428,7 @@
|
|
GList *children;
|
|
gint x, y;
|
|
gint width, height;
|
|
+ guint horizontal_padding;
|
|
guint vertical_padding;
|
|
|
|
g_return_if_fail (GTK_IS_MENU (widget));
|
|
@@ -2266,10 +2442,11 @@
|
|
gtk_widget_get_child_requisition (GTK_WIDGET (menu), &child_requisition);
|
|
|
|
gtk_widget_style_get (GTK_WIDGET (menu),
|
|
+ "horizontal-padding", &horizontal_padding,
|
|
"vertical-padding", &vertical_padding,
|
|
NULL);
|
|
|
|
- x = GTK_CONTAINER (menu)->border_width + widget->style->xthickness;
|
|
+ x = GTK_CONTAINER (menu)->border_width + widget->style->xthickness + horizontal_padding;
|
|
y = GTK_CONTAINER (menu)->border_width + widget->style->ythickness + vertical_padding;
|
|
|
|
width = MAX (1, allocation->width - x * 2);
|
|
@@ -2407,27 +2584,32 @@
|
|
GdkEventExpose *event)
|
|
{
|
|
GtkMenu *menu;
|
|
- gint width, height;
|
|
- gint border_x, border_y;
|
|
- guint vertical_padding;
|
|
|
|
g_return_if_fail (GTK_IS_MENU (widget));
|
|
|
|
menu = GTK_MENU (widget);
|
|
|
|
- gtk_widget_style_get (GTK_WIDGET (menu),
|
|
- "vertical-padding", &vertical_padding,
|
|
- NULL);
|
|
-
|
|
- border_x = GTK_CONTAINER (widget)->border_width + widget->style->xthickness;
|
|
- border_y = GTK_CONTAINER (widget)->border_width + widget->style->ythickness + vertical_padding;
|
|
- gdk_drawable_get_size (widget->window, &width, &height);
|
|
-
|
|
if (event->window == widget->window)
|
|
{
|
|
+ gint width, height;
|
|
+ gint border_x, border_y;
|
|
+ guint vertical_padding;
|
|
+ guint horizontal_padding;
|
|
+ GtkMenuPrivate *priv;
|
|
gint arrow_space = MENU_SCROLL_ARROW_HEIGHT - 2 * widget->style->ythickness;
|
|
gint arrow_size = 0.7 * arrow_space;
|
|
|
|
+ priv = gtk_menu_get_private (menu);
|
|
+
|
|
+ gtk_widget_style_get (GTK_WIDGET (menu),
|
|
+ "vertical-padding", &vertical_padding,
|
|
+ "horizontal-padding", &horizontal_padding,
|
|
+ NULL);
|
|
+
|
|
+ border_x = GTK_CONTAINER (widget)->border_width + widget->style->xthickness + horizontal_padding;
|
|
+ border_y = GTK_CONTAINER (widget)->border_width + widget->style->ythickness + vertical_padding;
|
|
+ gdk_drawable_get_size (widget->window, &width, &height);
|
|
+
|
|
gtk_paint_box (widget->style,
|
|
widget->window,
|
|
GTK_STATE_NORMAL,
|
|
@@ -2436,21 +2618,9 @@
|
|
0, 0, -1, -1);
|
|
if (menu->upper_arrow_visible && !menu->tearoff_active)
|
|
{
|
|
- gtk_paint_box (widget->style,
|
|
- widget->window,
|
|
- menu->upper_arrow_prelight ?
|
|
- GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
|
|
- GTK_SHADOW_OUT,
|
|
- NULL, widget, "menu",
|
|
- border_x,
|
|
- border_y,
|
|
- width - 2 * border_x,
|
|
- MENU_SCROLL_ARROW_HEIGHT);
|
|
-
|
|
gtk_paint_arrow (widget->style,
|
|
widget->window,
|
|
- menu->upper_arrow_prelight ?
|
|
- GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
|
|
+ priv->upper_arrow_state,
|
|
GTK_SHADOW_OUT,
|
|
NULL, widget, "menu_scroll_arrow_up",
|
|
GTK_ARROW_UP,
|
|
@@ -2462,21 +2632,9 @@
|
|
|
|
if (menu->lower_arrow_visible && !menu->tearoff_active)
|
|
{
|
|
- gtk_paint_box (widget->style,
|
|
- widget->window,
|
|
- menu->lower_arrow_prelight ?
|
|
- GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
|
|
- GTK_SHADOW_OUT,
|
|
- NULL, widget, "menu",
|
|
- border_x,
|
|
- height - border_y - MENU_SCROLL_ARROW_HEIGHT,
|
|
- width - 2*border_x,
|
|
- MENU_SCROLL_ARROW_HEIGHT);
|
|
-
|
|
gtk_paint_arrow (widget->style,
|
|
widget->window,
|
|
- menu->lower_arrow_prelight ?
|
|
- GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
|
|
+ priv->lower_arrow_state,
|
|
GTK_SHADOW_OUT,
|
|
NULL, widget, "menu_scroll_arrow_down",
|
|
GTK_ARROW_DOWN,
|
|
@@ -2516,18 +2674,82 @@
|
|
GTK_WIDGET_CLASS (parent_class)->show (widget);
|
|
}
|
|
|
|
+static GtkWidget *
|
|
+find_active_menu_item (GdkEventButton *event)
|
|
+{
|
|
+ GtkWidget *menu_item;
|
|
+
|
|
+ menu_item = gtk_get_event_widget ((GdkEvent*) event);
|
|
+ while (menu_item && !GTK_IS_MENU_ITEM (menu_item))
|
|
+ menu_item = menu_item->parent;
|
|
+
|
|
+ return menu_item;
|
|
+}
|
|
+
|
|
+static gboolean
|
|
+pointer_in_menu_tree (GtkWidget *widget)
|
|
+{
|
|
+ GtkMenuShell *mshell;
|
|
+ int width, height, x, y;
|
|
+
|
|
+ mshell = GTK_MENU_SHELL (widget);
|
|
+
|
|
+ gdk_window_get_pointer (widget->window, &x, &y, NULL);
|
|
+ gdk_drawable_get_size (widget->window, &width, &height);
|
|
+
|
|
+ if ((x <= width) && (x >= 0) && (y <= height) && (y >= 0))
|
|
+ return TRUE;
|
|
+
|
|
+ if ((mshell->parent_menu_shell != NULL) &&
|
|
+ GTK_IS_MENU (mshell->parent_menu_shell))
|
|
+ return pointer_in_menu_tree (mshell->parent_menu_shell);
|
|
+
|
|
+ return FALSE;
|
|
+}
|
|
+
|
|
+static int
|
|
+distance_traveled (GtkWidget *widget)
|
|
+{
|
|
+ GtkMenuPrivate *priv;
|
|
+ GdkScreen *screen;
|
|
+ GdkDisplay *display;
|
|
+ int x, y, dx, dy;
|
|
+
|
|
+ priv = gtk_menu_get_private (GTK_MENU (widget));
|
|
+
|
|
+ screen = gtk_widget_get_screen (widget);
|
|
+ display = gdk_screen_get_display (screen);
|
|
+
|
|
+ gdk_display_get_pointer (display, NULL, &x, &y, NULL);
|
|
+
|
|
+ dx = (priv->popup_pointer_x - x);
|
|
+ dy = (priv->popup_pointer_y - y);
|
|
+
|
|
+ return abs ((int) sqrt ((double) (dx * dx + dy * dy)));
|
|
+}
|
|
+
|
|
static gboolean
|
|
gtk_menu_button_press (GtkWidget *widget,
|
|
- GdkEventButton *event)
|
|
+ GdkEventButton *event)
|
|
{
|
|
- /* Don't pop down the menu for releases over scroll arrows
|
|
- */
|
|
- if (GTK_IS_MENU (widget))
|
|
+ GtkWidget *menu_item;
|
|
+
|
|
+ menu_item = find_active_menu_item (event);
|
|
+ if (menu_item == NULL)
|
|
{
|
|
GtkMenu *menu = GTK_MENU (widget);
|
|
|
|
- if (menu->upper_arrow_prelight || menu->lower_arrow_prelight)
|
|
- return TRUE;
|
|
+ if (menu->upper_arrow_prelight || menu->lower_arrow_prelight)
|
|
+ {
|
|
+ gtk_menu_handle_scrolling (GTK_MENU (widget), event->x_root, event->y_root, TRUE, FALSE);
|
|
+
|
|
+ return TRUE;
|
|
+ }
|
|
+
|
|
+ /* Don't pass down to menu shell if a non-menuitem part
|
|
+ * of the menu was clicked. */
|
|
+ if (pointer_in_menu_tree (widget))
|
|
+ return TRUE;
|
|
}
|
|
|
|
return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
|
|
@@ -2537,14 +2759,44 @@
|
|
gtk_menu_button_release (GtkWidget *widget,
|
|
GdkEventButton *event)
|
|
{
|
|
- /* Don't pop down the menu for releases over scroll arrows
|
|
- */
|
|
- if (GTK_IS_MENU (widget))
|
|
+ GtkMenuPrivate *priv;
|
|
+ GtkWidget *menu_item;
|
|
+
|
|
+ priv = gtk_menu_get_private (GTK_MENU (widget));
|
|
+
|
|
+ menu_item = find_active_menu_item (event);
|
|
+ if (menu_item == NULL)
|
|
{
|
|
GtkMenu *menu = GTK_MENU (widget);
|
|
|
|
- if (menu->upper_arrow_prelight || menu->lower_arrow_prelight)
|
|
- return TRUE;
|
|
+ if (menu->upper_arrow_prelight || menu->lower_arrow_prelight)
|
|
+ {
|
|
+ gtk_menu_handle_scrolling (GTK_MENU (widget), event->x_root, event->y_root, FALSE, FALSE);
|
|
+
|
|
+ return TRUE;
|
|
+ }
|
|
+
|
|
+ if (priv->context_menu &&
|
|
+ (priv->popup_pointer_x >= 0) &&
|
|
+ (priv->popup_pointer_y >= 0))
|
|
+ {
|
|
+ int distance;
|
|
+
|
|
+ distance = distance_traveled (widget);
|
|
+
|
|
+ priv->popup_pointer_x = -1;
|
|
+ priv->popup_pointer_y = -1;
|
|
+
|
|
+ /* Don't popdown if we traveled less than 20px since popup point,
|
|
+ * as per the specs. */
|
|
+ if (distance < 20)
|
|
+ return TRUE;
|
|
+ }
|
|
+
|
|
+ /* Don't pass down to menu shell if a non-menuitem part
|
|
+ * of the menu was clicked. */
|
|
+ if (pointer_in_menu_tree (widget))
|
|
+ return TRUE;
|
|
}
|
|
|
|
return GTK_WIDGET_CLASS (parent_class)->button_release_event (widget, event);
|
|
@@ -2765,7 +3017,7 @@
|
|
gboolean need_enter;
|
|
|
|
if (GTK_IS_MENU (widget))
|
|
- gtk_menu_handle_scrolling (GTK_MENU (widget), event->x_root, event->y_root, TRUE);
|
|
+ gtk_menu_handle_scrolling (GTK_MENU (widget), event->x_root, event->y_root, TRUE, TRUE);
|
|
|
|
/* We received the event for one of two reasons:
|
|
*
|
|
@@ -2779,7 +3031,27 @@
|
|
menu_item = gtk_get_event_widget ((GdkEvent*) event);
|
|
if (!menu_item || !GTK_IS_MENU_ITEM (menu_item) ||
|
|
!GTK_IS_MENU (menu_item->parent))
|
|
- return FALSE;
|
|
+ {
|
|
+ GtkMenuPrivate *priv;
|
|
+
|
|
+ priv = gtk_menu_get_private (GTK_MENU (widget));
|
|
+
|
|
+ if (priv->context_menu)
|
|
+ {
|
|
+ /* Context menu mode. If we dragged out of the menu,
|
|
+ * close the menu, as by the specs. */
|
|
+ if (!pointer_in_menu_tree (widget) &&
|
|
+ (distance_traveled (widget) >= 20) &&
|
|
+ (event->state & GDK_BUTTON1_MASK))
|
|
+ {
|
|
+ gtk_menu_deactivate (GTK_MENU_SHELL (widget));
|
|
+
|
|
+ return TRUE;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return FALSE;
|
|
+ }
|
|
|
|
menu_shell = GTK_MENU_SHELL (menu_item->parent);
|
|
menu = GTK_MENU (menu_shell);
|
|
@@ -2795,6 +3067,11 @@
|
|
*/
|
|
if (gtk_menu_navigating_submenu (menu, event->x_root, event->y_root))
|
|
return TRUE;
|
|
+/* HILDON MOD.
|
|
+ * Close the submenus that are two levels down from the currently selected.
|
|
+ * This ensures that the focus is correct all the time.*/
|
|
+ if (GTK_MENU_ITEM(menu_item)->submenu != NULL)
|
|
+ gtk_menu_shell_deselect (GTK_MENU_SHELL(&(GTK_MENU(GTK_MENU_ITEM(menu_item)->submenu)->menu_shell)));
|
|
|
|
/* Make sure we pop down if we enter a non-selectable menu item, so we
|
|
* don't show a submenu when the cursor is outside the stay-up triangle.
|
|
@@ -2828,6 +3105,7 @@
|
|
send_event->crossing.y_root = event->y_root;
|
|
send_event->crossing.x = event->x;
|
|
send_event->crossing.y = event->y;
|
|
+ send_event->crossing.state = event->state;
|
|
|
|
/* We send the event to 'widget', the currently active menu,
|
|
* instead of 'menu', the menu that the pointer is in. This
|
|
@@ -2852,17 +3130,24 @@
|
|
GtkWidget *widget;
|
|
gint offset;
|
|
gint view_width, view_height;
|
|
+ gboolean double_arrows;
|
|
|
|
widget = GTK_WIDGET (menu);
|
|
offset = menu->scroll_offset + step;
|
|
|
|
+ /* get double_arrows style property */
|
|
+ gtk_widget_style_get (widget,
|
|
+ "double_arrows", &double_arrows,
|
|
+ NULL);
|
|
+
|
|
/* If we scroll upward and the non-visible top part
|
|
* is smaller than the scroll arrow it would be
|
|
* pretty stupid to show the arrow and taking more
|
|
* screen space than just scrolling to the top.
|
|
*/
|
|
- if ((step < 0) && (offset < MENU_SCROLL_ARROW_HEIGHT))
|
|
- offset = 0;
|
|
+ if (!double_arrows)
|
|
+ if ((step < 0) && (offset < MENU_SCROLL_ARROW_HEIGHT))
|
|
+ offset = 0;
|
|
|
|
/* Don't scroll over the top if we weren't before: */
|
|
if ((menu->scroll_offset >= 0) && (offset < 0))
|
|
@@ -2874,6 +3159,12 @@
|
|
if (menu->scroll_offset > 0)
|
|
view_height -= MENU_SCROLL_ARROW_HEIGHT;
|
|
|
|
+ /* When both arrows are always shown, reduce
|
|
+ * view height even more.
|
|
+ */
|
|
+ if (double_arrows)
|
|
+ view_height -= MENU_SCROLL_ARROW_HEIGHT;
|
|
+
|
|
if ((menu->scroll_offset + view_height <= widget->requisition.height) &&
|
|
(offset + view_height > widget->requisition.height))
|
|
offset = widget->requisition.height - view_height;
|
|
@@ -2922,18 +3213,21 @@
|
|
gtk_menu_handle_scrolling (GtkMenu *menu,
|
|
gint x,
|
|
gint y,
|
|
- gboolean enter)
|
|
+ gboolean enter,
|
|
+ gboolean motion)
|
|
{
|
|
GtkMenuShell *menu_shell;
|
|
+ GtkMenuPrivate *priv;
|
|
gint width, height;
|
|
gint border;
|
|
GdkRectangle rect;
|
|
- gboolean in_arrow;
|
|
gboolean scroll_fast = FALSE;
|
|
guint vertical_padding;
|
|
gint top_x, top_y;
|
|
gint win_x, win_y;
|
|
|
|
+ priv = gtk_menu_get_private (menu);
|
|
+
|
|
menu_shell = GTK_MENU_SHELL (menu);
|
|
|
|
gdk_drawable_get_size (GTK_WIDGET (menu)->window, &width, &height);
|
|
@@ -2946,10 +3240,11 @@
|
|
GTK_WIDGET (menu)->style->ythickness + vertical_padding;
|
|
|
|
gdk_window_get_position (menu->toplevel->window, &top_x, &top_y);
|
|
+ x -= top_x;
|
|
+ y -= top_y;
|
|
+
|
|
gdk_window_get_position (GTK_WIDGET (menu)->window, &win_x, &win_y);
|
|
- win_x += top_x;
|
|
- win_y += top_y;
|
|
-
|
|
+
|
|
if (menu->upper_arrow_visible && !menu->tearoff_active)
|
|
{
|
|
rect.x = win_x;
|
|
@@ -2957,35 +3252,49 @@
|
|
rect.width = width;
|
|
rect.height = MENU_SCROLL_ARROW_HEIGHT + border;
|
|
|
|
- in_arrow = FALSE;
|
|
+ menu->upper_arrow_prelight = FALSE;
|
|
if ((x >= rect.x) && (x < rect.x + rect.width) &&
|
|
(y >= rect.y) && (y < rect.y + rect.height))
|
|
- {
|
|
- in_arrow = TRUE;
|
|
- scroll_fast = (y < rect.y + MENU_SCROLL_FAST_ZONE);
|
|
- }
|
|
-
|
|
- if (enter && in_arrow &&
|
|
- (!menu->upper_arrow_prelight || menu->scroll_fast != scroll_fast))
|
|
- {
|
|
- menu->upper_arrow_prelight = TRUE;
|
|
- menu->scroll_fast = scroll_fast;
|
|
- gdk_window_invalidate_rect (GTK_WIDGET (menu)->window, &rect, FALSE);
|
|
-
|
|
- /* Deselect the active item so that any submenus are poped down */
|
|
- gtk_menu_shell_deselect (menu_shell);
|
|
+ menu->upper_arrow_prelight = TRUE;
|
|
|
|
- gtk_menu_remove_scroll_timeout (menu);
|
|
- menu->scroll_step = (scroll_fast) ? -MENU_SCROLL_STEP2 : -MENU_SCROLL_STEP1;
|
|
- menu->timeout_id = g_timeout_add ((scroll_fast) ? MENU_SCROLL_TIMEOUT2 : MENU_SCROLL_TIMEOUT1,
|
|
- gtk_menu_scroll_timeout,
|
|
- menu);
|
|
- }
|
|
- else if (!enter && !in_arrow && menu->upper_arrow_prelight)
|
|
+ if (priv->upper_arrow_state != GTK_STATE_INSENSITIVE)
|
|
{
|
|
- gdk_window_invalidate_rect (GTK_WIDGET (menu)->window, &rect, FALSE);
|
|
-
|
|
- gtk_menu_stop_scrolling (menu);
|
|
+ if (enter && menu->upper_arrow_prelight &&
|
|
+ (menu->timeout_id == 0 || menu->scroll_fast != scroll_fast))
|
|
+ {
|
|
+ menu->scroll_fast = scroll_fast;
|
|
+
|
|
+ /* Deselect the active item so that any submenus are poped down */
|
|
+ gtk_menu_shell_deselect (menu_shell);
|
|
+
|
|
+ gtk_menu_remove_scroll_timeout (menu);
|
|
+ menu->scroll_step = (scroll_fast) ? -MENU_SCROLL_STEP2 : -MENU_SCROLL_STEP1;
|
|
+
|
|
+ if (!motion)
|
|
+ {
|
|
+ /* Only do stuff on click. */
|
|
+ GtkSettings *settings;
|
|
+ guint timeout;
|
|
+
|
|
+ settings = gtk_settings_get_default ();
|
|
+ g_object_get (settings, "gtk-update-timeout", &timeout, NULL);
|
|
+
|
|
+ menu->timeout_id = g_timeout_add (timeout / 2, gtk_menu_scroll_timeout, menu);
|
|
+
|
|
+ priv->upper_arrow_state = GTK_STATE_ACTIVE;
|
|
+ }
|
|
+
|
|
+ gdk_window_invalidate_rect (GTK_WIDGET (menu)->window, &rect, FALSE);
|
|
+ }
|
|
+ else if (!enter)
|
|
+ {
|
|
+ gtk_menu_stop_scrolling (menu);
|
|
+
|
|
+ priv->upper_arrow_state = menu->upper_arrow_prelight ?
|
|
+ GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
|
|
+
|
|
+ gdk_window_invalidate_rect (GTK_WIDGET (menu)->window, &rect, FALSE);
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -2996,36 +3305,50 @@
|
|
rect.width = width;
|
|
rect.height = MENU_SCROLL_ARROW_HEIGHT + border;
|
|
|
|
- in_arrow = FALSE;
|
|
+ menu->lower_arrow_prelight = FALSE;
|
|
if ((x >= rect.x) && (x < rect.x + rect.width) &&
|
|
(y >= rect.y) && (y < rect.y + rect.height))
|
|
- {
|
|
- in_arrow = TRUE;
|
|
- scroll_fast = (y > rect.y + rect.height - MENU_SCROLL_FAST_ZONE);
|
|
- }
|
|
+ menu->lower_arrow_prelight = TRUE;
|
|
|
|
- if (enter && in_arrow &&
|
|
- (!menu->lower_arrow_prelight || menu->scroll_fast != scroll_fast))
|
|
+ if (priv->lower_arrow_state != GTK_STATE_INSENSITIVE)
|
|
{
|
|
- menu->lower_arrow_prelight = TRUE;
|
|
- menu->scroll_fast = scroll_fast;
|
|
- gdk_window_invalidate_rect (GTK_WIDGET (menu)->window, &rect, FALSE);
|
|
+ if (enter && menu->lower_arrow_prelight &&
|
|
+ (menu->timeout_id == 0 || menu->scroll_fast != scroll_fast))
|
|
+ {
|
|
+ menu->scroll_fast = scroll_fast;
|
|
|
|
- /* Deselect the active item so that any submenus are poped down */
|
|
- gtk_menu_shell_deselect (menu_shell);
|
|
+ /* Deselect the active item so that any submenus are poped down */
|
|
+ gtk_menu_shell_deselect (menu_shell);
|
|
|
|
- gtk_menu_remove_scroll_timeout (menu);
|
|
- menu->scroll_step = (scroll_fast) ? MENU_SCROLL_STEP2 : MENU_SCROLL_STEP1;
|
|
- menu->timeout_id = g_timeout_add ((scroll_fast) ? MENU_SCROLL_TIMEOUT2 : MENU_SCROLL_TIMEOUT1,
|
|
- gtk_menu_scroll_timeout,
|
|
- menu);
|
|
- }
|
|
- else if (!enter && !in_arrow && menu->lower_arrow_prelight)
|
|
- {
|
|
- gdk_window_invalidate_rect (GTK_WIDGET (menu)->window, &rect, FALSE);
|
|
-
|
|
- gtk_menu_stop_scrolling (menu);
|
|
- }
|
|
+ gtk_menu_remove_scroll_timeout (menu);
|
|
+ menu->scroll_step = (scroll_fast) ? MENU_SCROLL_STEP2 : MENU_SCROLL_STEP1;
|
|
+
|
|
+ if (!motion)
|
|
+ {
|
|
+ /* Only do stuff on click. */
|
|
+ GtkSettings *settings;
|
|
+ guint timeout;
|
|
+
|
|
+ settings = gtk_settings_get_default ();
|
|
+ g_object_get (settings, "gtk-update-timeout", &timeout, NULL);
|
|
+
|
|
+ menu->timeout_id = g_timeout_add (timeout / 2, gtk_menu_scroll_timeout, menu);
|
|
+
|
|
+ priv->lower_arrow_state = GTK_STATE_ACTIVE;
|
|
+ }
|
|
+
|
|
+ gdk_window_invalidate_rect (GTK_WIDGET (menu)->window, &rect, FALSE);
|
|
+ }
|
|
+ else if (!enter)
|
|
+ {
|
|
+ gtk_menu_stop_scrolling (menu);
|
|
+
|
|
+ priv->lower_arrow_state = menu->lower_arrow_prelight ?
|
|
+ GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
|
|
+
|
|
+ gdk_window_invalidate_rect (GTK_WIDGET (menu)->window, &rect, FALSE);
|
|
+ }
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -3041,7 +3364,7 @@
|
|
GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget);
|
|
|
|
if (!menu_shell->ignore_enter)
|
|
- gtk_menu_handle_scrolling (GTK_MENU (widget), event->x_root, event->y_root, TRUE);
|
|
+ gtk_menu_handle_scrolling (GTK_MENU (widget), event->x_root, event->y_root, TRUE, TRUE);
|
|
}
|
|
|
|
if (menu_item && GTK_IS_MENU_ITEM (menu_item))
|
|
@@ -3106,7 +3429,7 @@
|
|
if (gtk_menu_navigating_submenu (menu, event->x_root, event->y_root))
|
|
return TRUE;
|
|
|
|
- gtk_menu_handle_scrolling (menu, event->x_root, event->y_root, FALSE);
|
|
+ gtk_menu_handle_scrolling (menu, event->x_root, event->y_root, FALSE, TRUE);
|
|
|
|
event_widget = gtk_get_event_widget ((GdkEvent*) event);
|
|
|
|
@@ -3611,7 +3934,13 @@
|
|
requisition.width, requisition.height);
|
|
}
|
|
|
|
- menu->scroll_offset = scroll_offset;
|
|
+ /* Hildon hack for menu in comboboxes:
|
|
+ * in case the menu in attached to a ComboBox, the scroll_offset is
|
|
+ * calculated in the positioning function so we dont't overwrite it
|
|
+ * with the value calculated above (in this function) */
|
|
+ if ( !GTK_IS_COMBO_BOX(gtk_menu_get_attach_widget(menu)) )
|
|
+ menu->scroll_offset = scroll_offset;
|
|
+
|
|
}
|
|
|
|
static void
|
|
@@ -3628,9 +3957,6 @@
|
|
gtk_menu_stop_scrolling (GtkMenu *menu)
|
|
{
|
|
gtk_menu_remove_scroll_timeout (menu);
|
|
-
|
|
- menu->upper_arrow_prelight = FALSE;
|
|
- menu->lower_arrow_prelight = FALSE;
|
|
}
|
|
|
|
static void
|
|
@@ -3644,6 +3970,8 @@
|
|
gboolean last_visible;
|
|
gint menu_height;
|
|
guint vertical_padding;
|
|
+ guint horizontal_padding;
|
|
+ gboolean double_arrows;
|
|
|
|
widget = GTK_WIDGET (menu);
|
|
|
|
@@ -3663,19 +3991,93 @@
|
|
|
|
gtk_widget_style_get (GTK_WIDGET (menu),
|
|
"vertical-padding", &vertical_padding,
|
|
+ "horizontal-padding", &horizontal_padding,
|
|
+ "double_arrows", &double_arrows,
|
|
NULL);
|
|
|
|
border_width = GTK_CONTAINER (menu)->border_width;
|
|
- view_width -= (border_width + widget->style->xthickness) * 2;
|
|
+ view_width -= (border_width + widget->style->xthickness + horizontal_padding) * 2;
|
|
view_height -= (border_width + widget->style->ythickness + vertical_padding) * 2;
|
|
menu_height = widget->requisition.height -
|
|
(border_width + widget->style->ythickness + vertical_padding) * 2;
|
|
|
|
- x = border_width + widget->style->xthickness;
|
|
+ x = border_width + widget->style->xthickness + horizontal_padding;
|
|
y = border_width + widget->style->ythickness + vertical_padding;
|
|
|
|
+ if (double_arrows && !menu->tearoff_active && (view_height < menu_height))
|
|
+ {
|
|
+ GtkMenuPrivate *priv;
|
|
+ GtkStateType upper_arrow_previous_state, lower_arrow_previous_state;
|
|
+
|
|
+ priv = gtk_menu_get_private (menu);
|
|
+
|
|
+ upper_arrow_previous_state = priv->upper_arrow_state;
|
|
+ lower_arrow_previous_state = priv->lower_arrow_state;
|
|
+
|
|
+ if (!menu->upper_arrow_visible || !menu->lower_arrow_visible)
|
|
+ gtk_widget_queue_draw (GTK_WIDGET (menu));
|
|
+
|
|
+ view_height -= 2*MENU_SCROLL_ARROW_HEIGHT;
|
|
+ y += MENU_SCROLL_ARROW_HEIGHT;
|
|
+
|
|
+ menu->upper_arrow_visible = menu->lower_arrow_visible = TRUE;
|
|
+ if (priv->upper_arrow_state == GTK_STATE_INSENSITIVE)
|
|
+ {
|
|
+ priv->upper_arrow_state = menu->upper_arrow_prelight ?
|
|
+ GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
|
|
+ }
|
|
+ if (priv->lower_arrow_state == GTK_STATE_INSENSITIVE)
|
|
+ {
|
|
+ priv->lower_arrow_state = menu->lower_arrow_prelight ?
|
|
+ GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
|
|
+ }
|
|
+
|
|
+ if (offset <= 0)
|
|
+ {
|
|
+ offset = 0;
|
|
+ priv->upper_arrow_state = GTK_STATE_INSENSITIVE;
|
|
+ }
|
|
+ if (offset >= menu_height - view_height)
|
|
+ {
|
|
+ offset = menu_height - view_height;
|
|
+ priv->lower_arrow_state = GTK_STATE_INSENSITIVE;
|
|
+ }
|
|
+
|
|
+ if ((priv->upper_arrow_state != upper_arrow_previous_state) ||
|
|
+ (priv->lower_arrow_state != lower_arrow_previous_state))
|
|
+ gtk_widget_queue_draw (GTK_WIDGET (menu));
|
|
+
|
|
+ if (upper_arrow_previous_state != GTK_STATE_INSENSITIVE &&
|
|
+ priv->upper_arrow_state == GTK_STATE_INSENSITIVE)
|
|
+ {
|
|
+ /* If we hid the upper arrow, possibly remove timeout */
|
|
+ if (menu->scroll_step < 0)
|
|
+ {
|
|
+ gtk_menu_stop_scrolling (menu);
|
|
+ gtk_widget_queue_draw (GTK_WIDGET (menu));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (lower_arrow_previous_state != GTK_STATE_INSENSITIVE &&
|
|
+ priv->lower_arrow_state == GTK_STATE_INSENSITIVE)
|
|
+ {
|
|
+ /* If we hid the lower arrow, possibly remove timeout */
|
|
+ if (menu->scroll_step > 0)
|
|
+ {
|
|
+ gtk_menu_stop_scrolling (menu);
|
|
+ gtk_widget_queue_draw (GTK_WIDGET (menu));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ else
|
|
if (!menu->tearoff_active)
|
|
{
|
|
+ if (offset <= 0)
|
|
+ offset = 0;
|
|
+
|
|
+ if (offset >= menu_height - view_height)
|
|
+ offset = menu_height - view_height;
|
|
+
|
|
last_visible = menu->upper_arrow_visible;
|
|
menu->upper_arrow_visible = offset > 0;
|
|
|
|
@@ -3685,8 +4087,6 @@
|
|
if ( (last_visible != menu->upper_arrow_visible) &&
|
|
!menu->upper_arrow_visible)
|
|
{
|
|
- menu->upper_arrow_prelight = FALSE;
|
|
-
|
|
/* If we hid the upper arrow, possibly remove timeout */
|
|
if (menu->scroll_step < 0)
|
|
{
|
|
@@ -3704,8 +4104,6 @@
|
|
if ( (last_visible != menu->lower_arrow_visible) &&
|
|
!menu->lower_arrow_visible)
|
|
{
|
|
- menu->lower_arrow_prelight = FALSE;
|
|
-
|
|
/* If we hid the lower arrow, possibly remove timeout */
|
|
if (menu->scroll_step > 0)
|
|
{
|
|
@@ -3792,12 +4190,14 @@
|
|
&child_offset, &child_height, &last_child))
|
|
{
|
|
guint vertical_padding;
|
|
+ gboolean double_arrows;
|
|
|
|
y = menu->scroll_offset;
|
|
gdk_drawable_get_size (GTK_WIDGET (menu)->window, &width, &height);
|
|
|
|
gtk_widget_style_get (GTK_WIDGET (menu),
|
|
"vertical-padding", &vertical_padding,
|
|
+ "double_arrows", &double_arrows,
|
|
NULL);
|
|
|
|
height -= 2*GTK_CONTAINER (menu)->border_width + 2*GTK_WIDGET (menu)->style->ythickness + 2*vertical_padding;
|
|
@@ -3820,11 +4220,11 @@
|
|
if (child_offset + child_height > y + height - arrow_height)
|
|
{
|
|
arrow_height = 0;
|
|
- if (!last_child && !menu->tearoff_active)
|
|
+ if ((!last_child && !menu->tearoff_active) || (double_arrows))
|
|
arrow_height += MENU_SCROLL_ARROW_HEIGHT;
|
|
|
|
y = child_offset + child_height - height + arrow_height;
|
|
- if ((y > 0) && !menu->tearoff_active)
|
|
+ if (((y > 0) && !menu->tearoff_active) || (double_arrows))
|
|
{
|
|
/* Need upper arrow */
|
|
arrow_height += MENU_SCROLL_ARROW_HEIGHT;
|
|
@@ -4374,3 +4774,60 @@
|
|
return list;
|
|
}
|
|
|
|
+/* Little help function for making some sanity tests on this menu.
|
|
+ * Checks that given widget really is a menu and that it has no name
|
|
+ * assigned to it yet.
|
|
+ * Names used to do hildon theming:
|
|
+ * HILDON_MENU_NAME_SHARP for menu with sharp upper corners
|
|
+ * HILDON_MENU_NAME_ROUND for menu with round corners
|
|
+ */
|
|
+static gboolean
|
|
+gtk_menu_check_name (GtkWidget *widget)
|
|
+{
|
|
+ gboolean legal_name = FALSE;
|
|
+ gchar **tmp = NULL;
|
|
+ const gchar *name = NULL;
|
|
+ static gchar *menu_names[] = { "GtkMenu",
|
|
+ HILDON_MENU_NAME_SHARP,
|
|
+ HILDON_MENU_NAME_ROUND,
|
|
+ HILDON_MENU_NAME_ROUND_FIRST_LEVEL,
|
|
+ NULL };
|
|
+ if (GTK_IS_MENU (widget) &&
|
|
+ (name = gtk_widget_get_name (widget)))
|
|
+ {
|
|
+ if (!g_ascii_strcasecmp (name, HILDON_MENU_NAME_FORCE_SHARP) || !g_ascii_strcasecmp (name, HILDON_MENU_NAME_FORCE_ROUND))
|
|
+ return FALSE;
|
|
+ for (tmp = menu_names; *tmp; tmp++)
|
|
+ if (!g_ascii_strcasecmp (name, *tmp ))
|
|
+ {
|
|
+ legal_name = TRUE;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return legal_name;
|
|
+}
|
|
+
|
|
+/* A function called when esc-key is pressed. */
|
|
+static void
|
|
+_gtk_menu_close_current (GtkMenu * menu)
|
|
+{
|
|
+ GtkMenuShell * shell = GTK_MENU_SHELL (menu);
|
|
+
|
|
+ /* Check is a submenu of current menu item is visible.
|
|
+ * If it is, close that first. */
|
|
+ if (shell->active_menu_item && (GTK_MENU_ITEM (shell->active_menu_item)->submenu) && GTK_WIDGET_VISIBLE (GTK_MENU_ITEM (shell->active_menu_item)->submenu))
|
|
+ gtk_menu_popdown (GTK_MENU (GTK_MENU_ITEM (shell->active_menu_item)->submenu));
|
|
+ else
|
|
+ gtk_menu_popdown (menu);
|
|
+
|
|
+}
|
|
+
|
|
+/* Hildon function to make context menus behave according to spec */
|
|
+void
|
|
+_gtk_menu_enable_context_menu_behavior (GtkMenu *menu)
|
|
+{
|
|
+ GtkMenuPrivate *priv = gtk_menu_get_private (menu);
|
|
+
|
|
+ priv->context_menu = TRUE;
|
|
+}
|