added boolean property gtk-touchscreen-mode, which essentially means

2006-02-22  Michael Natterer  <mitch@imendio.com>

	* gtk/gtksettings.c: added boolean property gtk-touchscreen-mode,
	which essentially means "there are no motion notify events", so
	widgets can't use the pointer hovering them for anything.

	* gtk/gtkmenu.c: if gtk-touchscreen-mode is TRUE, scroll menus
	when clicking the scroll arrows, since hovering goes undetected.
	Fixes bug #323028.

	Added boolean style property "double-arrows" which always makes
	both scroll arrows visible when the menu is too long.
	For pushed-in popup menus, both arrows are always shown
	(regardless of double-arrows), in order to fix user confusion
	about the blank area. Fixes bug #129463.
This commit is contained in:
Michael Natterer 2006-02-22 10:10:23 +00:00 committed by Michael Natterer
parent 9c359af5d8
commit 3b3b722ccf
4 changed files with 578 additions and 146 deletions

View File

@ -1,3 +1,19 @@
2006-02-22 Michael Natterer <mitch@imendio.com>
* gtk/gtksettings.c: added boolean property gtk-touchscreen-mode,
which essentially means "there are no motion notify events", so
widgets can't use the pointer hovering them for anything.
* gtk/gtkmenu.c: if gtk-touchscreen-mode is TRUE, scroll menus
when clicking the scroll arrows, since hovering goes undetected.
Fixes bug #323028.
Added boolean style property "double-arrows" which always makes
both scroll arrows visible when the menu is too long.
For pushed-in popup menus, both arrows are always shown
(regardless of double-arrows), in order to fix user confusion
about the blank area. Fixes bug #129463.
2006-02-21 Kristian Rietveld <kris@imendio.com>
* gtk/gtktreemodelfilter.c (gtk_tree_model_filter_rows_reordered):

View File

@ -1,3 +1,19 @@
2006-02-22 Michael Natterer <mitch@imendio.com>
* gtk/gtksettings.c: added boolean property gtk-touchscreen-mode,
which essentially means "there are no motion notify events", so
widgets can't use the pointer hovering them for anything.
* gtk/gtkmenu.c: if gtk-touchscreen-mode is TRUE, scroll menus
when clicking the scroll arrows, since hovering goes undetected.
Fixes bug #323028.
Added boolean style property "double-arrows" which always makes
both scroll arrows visible when the menu is too long.
For pushed-in popup menus, both arrows are always shown
(regardless of double-arrows), in order to fix user confusion
about the blank area. Fixes bug #129463.
2006-02-21 Kristian Rietveld <kris@imendio.com>
* gtk/gtktreemodelfilter.c (gtk_tree_model_filter_rows_reordered):

View File

@ -95,6 +95,13 @@ struct _GtkMenuPrivate
gint n_columns;
gchar *title;
/* Arrow states */
GtkStateType lower_arrow_state;
GtkStateType upper_arrow_state;
gboolean ignore_button_release;
gboolean initially_pushed_in;
};
typedef struct
@ -183,6 +190,8 @@ static void gtk_menu_grab_notify (GtkWidget *widget,
static void gtk_menu_stop_scrolling (GtkMenu *menu);
static void gtk_menu_remove_scroll_timeout (GtkMenu *menu);
static gboolean gtk_menu_scroll_timeout (gpointer data);
static gboolean gtk_menu_scroll_timeout_initial (gpointer data);
static void gtk_menu_start_scrolling (GtkMenu *menu);
static void gtk_menu_scroll_item_visible (GtkMenuShell *menu_shell,
GtkWidget *menu_item);
@ -196,7 +205,8 @@ static void gtk_menu_scrollbar_changed (GtkAdjustment *adjustment,
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,
@ -559,6 +569,13 @@ gtk_menu_class_init (GtkMenuClass *class)
-2,
GTK_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."),
TRUE,
GTK_PARAM_READABLE));
gtk_container_class_install_child_property (container_class,
CHILD_PROP_LEFT_ATTACH,
@ -908,6 +925,9 @@ gtk_menu_init (GtkMenu *menu)
menu->upper_arrow_prelight = FALSE;
menu->lower_arrow_prelight = FALSE;
priv->upper_arrow_state = GTK_STATE_NORMAL;
priv->lower_arrow_state = GTK_STATE_NORMAL;
priv->have_layout = FALSE;
}
@ -2052,6 +2072,7 @@ gtk_menu_realize (GtkWidget *widget)
attributes.y += MENU_SCROLL_ARROW_HEIGHT;
attributes.height -= MENU_SCROLL_ARROW_HEIGHT;
}
if (menu->lower_arrow_visible)
attributes.height -= MENU_SCROLL_ARROW_HEIGHT;
@ -2428,6 +2449,7 @@ gtk_menu_paint (GtkWidget *widget,
GdkEventExpose *event)
{
GtkMenu *menu;
GtkMenuPrivate *priv;
gint width, height;
gint border_x, border_y;
guint vertical_padding;
@ -2436,6 +2458,7 @@ gtk_menu_paint (GtkWidget *widget,
g_return_if_fail (GTK_IS_MENU (widget));
menu = GTK_MENU (widget);
priv = gtk_menu_get_private (menu);
gtk_widget_style_get (GTK_WIDGET (menu),
"vertical-padding", &vertical_padding,
@ -2457,12 +2480,12 @@ gtk_menu_paint (GtkWidget *widget,
GTK_SHADOW_OUT,
NULL, widget, "menu",
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,
priv->upper_arrow_state,
GTK_SHADOW_OUT,
NULL, widget, "menu",
border_x,
@ -2472,8 +2495,7 @@ gtk_menu_paint (GtkWidget *widget,
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,
@ -2487,8 +2509,7 @@ gtk_menu_paint (GtkWidget *widget,
{
gtk_paint_box (widget->style,
widget->window,
menu->lower_arrow_prelight ?
GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
priv->lower_arrow_state,
GTK_SHADOW_OUT,
NULL, widget, "menu",
border_x,
@ -2498,8 +2519,7 @@ gtk_menu_paint (GtkWidget *widget,
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,
@ -2550,18 +2570,46 @@ gtk_menu_show (GtkWidget *widget)
}
static gboolean
gtk_menu_button_press (GtkWidget *widget,
gtk_menu_button_scroll (GtkWidget *widget,
GdkEventButton *event)
{
/* Don't pop down the menu for releases over scroll arrows
*/
if (GTK_IS_MENU (widget))
{
GtkMenu *menu = GTK_MENU (widget);
if (menu->upper_arrow_prelight || menu->lower_arrow_prelight)
{
GtkSettings *settings = gtk_widget_get_settings (widget);
gboolean touchscreen_mode;
g_object_get (G_OBJECT (settings),
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
if (touchscreen_mode)
gtk_menu_handle_scrolling (menu,
event->x_root, event->y_root,
event->type == GDK_BUTTON_PRESS,
FALSE);
return TRUE;
}
}
return FALSE;
}
static gboolean
gtk_menu_button_press (GtkWidget *widget,
GdkEventButton *event)
{
if (event->type != GDK_BUTTON_PRESS)
return FALSE;
/* Don't pop down the menu for presses over scroll arrows
*/
if (gtk_menu_button_scroll (widget, event))
return TRUE;
return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
}
@ -2570,15 +2618,24 @@ static gboolean
gtk_menu_button_release (GtkWidget *widget,
GdkEventButton *event)
{
/* Don't pop down the menu for releases over scroll arrows
*/
if (GTK_IS_MENU (widget))
{
GtkMenu *menu = GTK_MENU (widget);
GtkMenuPrivate *priv = gtk_menu_get_private (GTK_MENU (widget));
if (menu->upper_arrow_prelight || menu->lower_arrow_prelight)
return TRUE;
if (priv->ignore_button_release)
{
priv->ignore_button_release = FALSE;
return FALSE;
}
}
if (event->type != GDK_BUTTON_RELEASE)
return FALSE;
/* Don't pop down the menu for releases over scroll arrows
*/
if (gtk_menu_button_scroll (widget, event))
return TRUE;
return GTK_WIDGET_CLASS (parent_class)->button_release_event (widget, event);
}
@ -2797,7 +2854,15 @@ gtk_menu_motion_notify (GtkWidget *widget,
gboolean need_enter;
if (GTK_IS_MENU (widget))
gtk_menu_handle_scrolling (GTK_MENU (widget), event->x_root, event->y_root, TRUE);
{
GtkMenuPrivate *priv = gtk_menu_get_private (GTK_MENU (widget));
if (priv->ignore_button_release)
priv->ignore_button_release = FALSE;
gtk_menu_handle_scrolling (GTK_MENU (widget), event->x_root, event->y_root,
TRUE, TRUE);
}
/* We received the event for one of two reasons:
*
@ -2809,7 +2874,7 @@ gtk_menu_motion_notify (GtkWidget *widget,
* which may be different from 'widget'.
*/
menu_item = gtk_get_event_widget ((GdkEvent*) event);
if (!menu_item || !GTK_IS_MENU_ITEM (menu_item) ||
if (!GTK_IS_MENU_ITEM (menu_item) ||
!GTK_IS_MENU (menu_item->parent))
return FALSE;
@ -2875,6 +2940,20 @@ gtk_menu_motion_notify (GtkWidget *widget,
return FALSE;
}
static gboolean
get_double_arrows (GtkMenu *menu)
{
GtkMenuPrivate *priv = gtk_menu_get_private (menu);
gboolean double_arrows;
gtk_widget_style_get (GTK_WIDGET (menu),
"double-arrows", &double_arrows,
NULL);
return double_arrows || (priv->initially_pushed_in &&
menu->scroll_offset != 0);
}
static void
gtk_menu_scroll_by (GtkMenu *menu,
gint step)
@ -2882,15 +2961,19 @@ gtk_menu_scroll_by (GtkMenu *menu,
GtkWidget *widget;
gint offset;
gint view_width, view_height;
gboolean double_arrows;
widget = GTK_WIDGET (menu);
offset = menu->scroll_offset + step;
double_arrows = get_double_arrows (menu);
/* 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 (!double_arrows)
if ((step < 0) && (offset < MENU_SCROLL_ARROW_HEIGHT))
offset = 0;
@ -2904,6 +2987,12 @@ gtk_menu_scroll_by (GtkMenu *menu,
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;
@ -2912,21 +3001,102 @@ gtk_menu_scroll_by (GtkMenu *menu,
gtk_menu_scroll_to (menu, offset);
}
static void
gtk_menu_do_timeout_scroll (GtkMenu *menu,
gboolean touchscreen_mode)
{
gboolean upper_visible;
gboolean lower_visible;
upper_visible = menu->upper_arrow_visible;
lower_visible = menu->lower_arrow_visible;
gtk_menu_scroll_by (menu, menu->scroll_step);
if (touchscreen_mode &&
(upper_visible != menu->upper_arrow_visible ||
lower_visible != menu->lower_arrow_visible))
{
/* We are about to hide a scroll arrow while the mouse is pressed,
* this would cause the uncovered menu item to be activated on button
* release. Therefore we need to ignore button release here
*/
GTK_MENU_SHELL (menu)->ignore_enter = TRUE;
gtk_menu_get_private (menu)->ignore_button_release = TRUE;
}
}
static gboolean
gtk_menu_scroll_timeout (gpointer data)
{
GtkMenu *menu;
GtkSettings *settings;
gboolean touchscreen_mode;
GDK_THREADS_ENTER ();
menu = GTK_MENU (data);
gtk_menu_scroll_by (menu, menu->scroll_step);
settings = gtk_widget_get_settings (GTK_WIDGET (menu));
g_object_get (settings,
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
gtk_menu_do_timeout_scroll (menu, touchscreen_mode);
GDK_THREADS_LEAVE ();
return TRUE;
}
static gboolean
gtk_menu_scroll_timeout_initial (gpointer data)
{
GtkMenu *menu;
GtkSettings *settings;
guint timeout;
gboolean touchscreen_mode;
GDK_THREADS_ENTER ();
menu = GTK_MENU (data);
settings = gtk_widget_get_settings (GTK_WIDGET (menu));
g_object_get (settings,
"gtk-timeout-repeat", &timeout,
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
gtk_menu_do_timeout_scroll (menu, touchscreen_mode);
gtk_menu_remove_scroll_timeout (menu);
menu->timeout_id = g_timeout_add (timeout, gtk_menu_scroll_timeout, menu);
GDK_THREADS_LEAVE ();
return FALSE;
}
static void
gtk_menu_start_scrolling (GtkMenu *menu)
{
GtkSettings *settings;
guint timeout;
gboolean touchscreen_mode;
settings = gtk_widget_get_settings (GTK_WIDGET (menu));
g_object_get (settings,
"gtk-timeout-repeat", &timeout,
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
gtk_menu_do_timeout_scroll (menu, touchscreen_mode);
menu->timeout_id = g_timeout_add (timeout, gtk_menu_scroll_timeout_initial,
menu);
}
static gboolean
gtk_menu_scroll (GtkWidget *widget,
GdkEventScroll *event)
@ -2952,9 +3122,11 @@ static void
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;
@ -2963,11 +3135,19 @@ gtk_menu_handle_scrolling (GtkMenu *menu,
guint vertical_padding;
gint top_x, top_y;
gint win_x, win_y;
GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (menu));
gboolean touchscreen_mode;
priv = gtk_menu_get_private (menu);
menu_shell = GTK_MENU_SHELL (menu);
gdk_drawable_get_size (GTK_WIDGET (menu)->window, &width, &height);
g_object_get (G_OBJECT (settings),
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
gtk_widget_style_get (GTK_WIDGET (menu),
"vertical-padding", &vertical_padding,
NULL);
@ -2981,105 +3161,222 @@ gtk_menu_handle_scrolling (GtkMenu *menu,
gdk_window_get_position (GTK_WIDGET (menu)->window, &win_x, &win_y);
if (menu->upper_arrow_visible && !menu->tearoff_active)
{
/* upper arrow handling */
rect.x = win_x;
rect.y = win_y;
rect.width = width;
rect.height = MENU_SCROLL_ARROW_HEIGHT + border;
in_arrow = FALSE;
if ((x >= rect.x) && (x < rect.x + rect.width) &&
if (menu->upper_arrow_visible && !menu->tearoff_active &&
(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);
if (touchscreen_mode)
menu->upper_arrow_prelight = in_arrow;
/* Deselect the active item so that any submenus are poped down */
if (priv->upper_arrow_state != GTK_STATE_INSENSITIVE)
{
if (menu->upper_arrow_visible && !menu->tearoff_active)
{
if (touchscreen_mode)
{
if (enter && menu->upper_arrow_prelight &&
menu->timeout_id == 0)
{
/* Deselect the active item so that
* any submenus are popped 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->upper_arrow_prelight)
menu->scroll_step = -MENU_SCROLL_STEP2; /* always fast */
if (!motion)
{
gdk_window_invalidate_rect (GTK_WIDGET (menu)->window, &rect, FALSE);
/* Only do stuff on click. */
gtk_menu_start_scrolling (menu);
priv->upper_arrow_state = GTK_STATE_ACTIVE;
}
gdk_window_invalidate_rect (GTK_WIDGET (menu)->window,
&rect, FALSE);
}
else if (!enter)
{
gdk_window_invalidate_rect (GTK_WIDGET (menu)->window,
&rect, FALSE);
gtk_menu_stop_scrolling (menu);
}
}
if (menu->lower_arrow_visible && !menu->tearoff_active)
else /* !touchscreen_mode */
{
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 popped 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->upper_arrow_prelight)
{
gdk_window_invalidate_rect (GTK_WIDGET (menu)->window,
&rect, FALSE);
gtk_menu_stop_scrolling (menu);
}
}
}
priv->upper_arrow_state = menu->upper_arrow_prelight ?
GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
}
/* lower arrow handling */
rect.x = win_x;
rect.y = win_y + height - border - MENU_SCROLL_ARROW_HEIGHT;
rect.width = width;
rect.height = MENU_SCROLL_ARROW_HEIGHT + border;
in_arrow = FALSE;
if ((x >= rect.x) && (x < rect.x + rect.width) &&
if (menu->lower_arrow_visible && !menu->tearoff_active &&
(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);
}
if (enter && in_arrow &&
(!menu->lower_arrow_prelight || menu->scroll_fast != scroll_fast))
{
menu->lower_arrow_prelight = TRUE;
menu->scroll_fast = scroll_fast;
gdk_window_invalidate_rect (GTK_WIDGET (menu)->window, &rect, FALSE);
if (touchscreen_mode)
menu->lower_arrow_prelight = in_arrow;
/* Deselect the active item so that any submenus are poped down */
if (priv->lower_arrow_state != GTK_STATE_INSENSITIVE)
{
if (menu->lower_arrow_visible && !menu->tearoff_active)
{
if (touchscreen_mode)
{
if (enter && menu->lower_arrow_prelight &&
menu->timeout_id == 0)
{
/* Deselect the active item so that
* any submenus are popped 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)
menu->scroll_step = MENU_SCROLL_STEP2; /* always fast */
if (!motion)
{
gdk_window_invalidate_rect (GTK_WIDGET (menu)->window, &rect, FALSE);
/* Only do stuff on click. */
gtk_menu_start_scrolling (menu);
priv->lower_arrow_state = GTK_STATE_ACTIVE;
}
gdk_window_invalidate_rect (GTK_WIDGET (menu)->window,
&rect, FALSE);
}
else if (!enter)
{
gdk_window_invalidate_rect (GTK_WIDGET (menu)->window,
&rect, FALSE);
gtk_menu_stop_scrolling (menu);
}
}
else /* !touchscreen_mode */
{
scroll_fast = (y > rect.y + rect.height - MENU_SCROLL_FAST_ZONE);
if (enter && in_arrow &&
(!menu->lower_arrow_prelight ||
menu->scroll_fast != scroll_fast))
{
menu->lower_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 popped 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);
}
}
}
priv->lower_arrow_state = menu->lower_arrow_prelight ?
GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
}
}
static gboolean
gtk_menu_enter_notify (GtkWidget *widget,
GdkEventCrossing *event)
{
GtkSettings *settings = gtk_widget_get_settings (widget);
GtkWidget *menu_item;
gboolean touchscreen_mode;
g_object_get (G_OBJECT (settings),
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
menu_item = gtk_get_event_widget ((GdkEvent*) event);
if (widget && GTK_IS_MENU (widget))
if (GTK_IS_MENU (widget))
{
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))
if (!touchscreen_mode && GTK_IS_MENU_ITEM (menu_item))
{
GtkWidget *menu = menu_item->parent;
if (menu && GTK_IS_MENU (menu))
if (GTK_IS_MENU (menu))
{
GtkMenuPrivate *priv = gtk_menu_get_private (GTK_MENU (menu));
GtkMenuShell *menu_shell = GTK_MENU_SHELL (menu);
@ -3115,8 +3412,9 @@ gtk_menu_enter_notify (GtkWidget *widget,
* will not correspond to the event widget's parent. Check to see
* if we are in the parent's navigation region.
*/
if (menu_item && GTK_IS_MENU_ITEM (menu_item) && GTK_IS_MENU (menu_item->parent) &&
gtk_menu_navigating_submenu (GTK_MENU (menu_item->parent), event->x_root, event->y_root))
if (GTK_IS_MENU_ITEM (menu_item) && GTK_IS_MENU (menu_item->parent) &&
gtk_menu_navigating_submenu (GTK_MENU (menu_item->parent),
event->x_root, event->y_root))
return TRUE;
return GTK_WIDGET_CLASS (parent_class)->enter_notify_event (widget, event);
@ -3137,11 +3435,11 @@ gtk_menu_leave_notify (GtkWidget *widget,
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);
if (!event_widget || !GTK_IS_MENU_ITEM (event_widget))
if (!GTK_IS_MENU_ITEM (event_widget))
return TRUE;
menu_item = GTK_MENU_ITEM (event_widget);
@ -3429,7 +3727,6 @@ gtk_menu_position (GtkMenu *menu)
gint x, y;
gint scroll_offset;
gint menu_height;
gboolean push_in;
GdkScreen *screen;
GdkScreen *pointer_screen;
GdkRectangle monitor;
@ -3463,11 +3760,12 @@ gtk_menu_position (GtkMenu *menu)
private = gtk_menu_get_private (menu);
private->monitor_num = gdk_screen_get_monitor_at_point (screen, x, y);
push_in = FALSE;
private->initially_pushed_in = FALSE;
if (menu->position_func)
{
(* menu->position_func) (menu, &x, &y, &push_in, menu->position_func_data);
(* menu->position_func) (menu, &x, &y, &private->initially_pushed_in,
menu->position_func_data);
if (private->monitor_num < 0)
private->monitor_num = gdk_screen_get_monitor_at_point (screen, x, y);
@ -3593,7 +3891,7 @@ gtk_menu_position (GtkMenu *menu)
scroll_offset = 0;
if (push_in)
if (private->initially_pushed_in)
{
menu_height = GTK_WIDGET (menu)->requisition.height;
@ -3658,10 +3956,20 @@ gtk_menu_remove_scroll_timeout (GtkMenu *menu)
static void
gtk_menu_stop_scrolling (GtkMenu *menu)
{
GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (menu));
gboolean touchscreen_mode;
gtk_menu_remove_scroll_timeout (menu);
g_object_get (G_OBJECT (settings),
"gtk-touchscreen-mode", &touchscreen_mode,
NULL);
if (!touchscreen_mode)
{
menu->upper_arrow_prelight = FALSE;
menu->lower_arrow_prelight = FALSE;
}
}
static void
@ -3672,10 +3980,10 @@ gtk_menu_scroll_to (GtkMenu *menu,
gint x, y;
gint view_width, view_height;
gint border_width;
gboolean last_visible;
gint menu_height;
guint vertical_padding;
guint horizontal_padding;
gboolean double_arrows;
widget = GTK_WIDGET (menu);
@ -3698,6 +4006,8 @@ gtk_menu_scroll_to (GtkMenu *menu,
"horizontal-padding", &horizontal_padding,
NULL);
double_arrows = get_double_arrows (menu);
border_width = GTK_CONTAINER (menu)->border_width;
view_width -= (border_width + widget->style->xthickness + horizontal_padding) * 2;
view_height -= (border_width + widget->style->ythickness + vertical_padding) * 2;
@ -3707,15 +4017,84 @@ gtk_menu_scroll_to (GtkMenu *menu,
x = border_width + widget->style->xthickness + horizontal_padding;
y = border_width + widget->style->ythickness + vertical_padding;
if (!menu->tearoff_active)
if (double_arrows && !menu->tearoff_active)
{
if (view_height < menu_height ||
(offset > 0 && menu->scroll_offset > 0) ||
(offset < 0 && menu->scroll_offset < 0))
{
GtkMenuPrivate *priv = gtk_menu_get_private (menu);
GtkStateType upper_arrow_previous_state = priv->upper_arrow_state;
GtkStateType 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 (offset <= 0)
priv->upper_arrow_state = GTK_STATE_INSENSITIVE;
else
priv->upper_arrow_state = menu->upper_arrow_prelight ?
GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
if (offset >= menu_height - view_height)
priv->lower_arrow_state = GTK_STATE_INSENSITIVE;
else
priv->lower_arrow_state = menu->lower_arrow_prelight ?
GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
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)
{
/* At the upper border, 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)
{
/* At the lower border, possibly remove timeout */
if (menu->scroll_step > 0)
{
gtk_menu_stop_scrolling (menu);
gtk_widget_queue_draw (GTK_WIDGET (menu));
}
}
}
else if (menu->upper_arrow_visible || menu->lower_arrow_visible)
{
offset = 0;
menu->upper_arrow_visible = menu->lower_arrow_visible = FALSE;
menu->upper_arrow_prelight = menu->lower_arrow_prelight = FALSE;
gtk_menu_stop_scrolling (menu);
gtk_widget_queue_draw (GTK_WIDGET (menu));
}
}
else if (!menu->tearoff_active)
{
gboolean last_visible;
last_visible = menu->upper_arrow_visible;
menu->upper_arrow_visible = offset > 0;
if (menu->upper_arrow_visible)
view_height -= MENU_SCROLL_ARROW_HEIGHT;
if ( (last_visible != menu->upper_arrow_visible) &&
if ((last_visible != menu->upper_arrow_visible) &&
!menu->upper_arrow_visible)
{
menu->upper_arrow_prelight = FALSE;
@ -3734,7 +4113,7 @@ gtk_menu_scroll_to (GtkMenu *menu,
if (menu->lower_arrow_visible)
view_height -= MENU_SCROLL_ARROW_HEIGHT;
if ( (last_visible != menu->lower_arrow_visible) &&
if ((last_visible != menu->lower_arrow_visible) &&
!menu->lower_arrow_visible)
{
menu->lower_arrow_prelight = FALSE;
@ -3825,6 +4204,7 @@ gtk_menu_scroll_item_visible (GtkMenuShell *menu_shell,
&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);
@ -3833,6 +4213,8 @@ gtk_menu_scroll_item_visible (GtkMenuShell *menu_shell,
"vertical-padding", &vertical_padding,
NULL);
double_arrows = get_double_arrows (menu);
height -= 2*GTK_CONTAINER (menu)->border_width + 2*GTK_WIDGET (menu)->style->ythickness + 2*vertical_padding;
if (child_offset < y)
@ -3853,11 +4235,11 @@ gtk_menu_scroll_item_visible (GtkMenuShell *menu_shell,
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;

View File

@ -89,6 +89,7 @@ enum {
PROP_TIMEOUT_REPEAT,
PROP_COLOR_SCHEME,
PROP_ENABLE_ANIMATIONS,
PROP_TOUCHSCREEN_MODE,
PROP_COLOR_HASH
};
@ -491,6 +492,24 @@ gtk_settings_class_init (GtkSettingsClass *class)
g_assert (result == PROP_ENABLE_ANIMATIONS);
/**
* GtkSettings:gtk-touchscreen-mode:
*
* When TRUE, there are no motion notify events delivered on this screen,
* and widgets can't use the pointer hovering them for any essential
* functionality.
*
* Since: 2.10
*/
result = settings_install_property_parser (class,
g_param_spec_boolean ("gtk-touchscreen-mode",
P_("Enable Touchscreen Mode"),
P_("When TRUE, there are no motion notify events delivered on this screen"),
FALSE,
GTK_PARAM_READWRITE),
NULL);
g_assert (result == PROP_TOUCHSCREEN_MODE);
/**
* GtkSettings:color-hash:
@ -509,7 +528,6 @@ gtk_settings_class_init (GtkSettingsClass *class)
GTK_PARAM_READABLE));
class_n_properties++;
}
static void