* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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 <http://www.gnu.org/licenses/>.
*/
/*
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
+/**
+ * SECTION:gtkmenu
+ * @Short_description: A menu widget
+ * @Title: GtkMenu
+ *
+ * A #GtkMenu is a #GtkMenuShell that implements a drop down menu
+ * consisting of a list of #GtkMenuItem objects which can be navigated
+ * and activated by the user to perform application functions.
+ *
+ * A #GtkMenu is most commonly dropped down by activating a
+ * #GtkMenuItem in a #GtkMenuBar or popped up by activating a
+ * #GtkMenuItem in another #GtkMenu.
+ *
+ * A #GtkMenu can also be popped up by activating a #GtkOptionMenu.
+ * Other composite widgets such as the #GtkNotebook can pop up a
+ * #GtkMenu as well.
+ *
+ * Applications can display a #GtkMenu as a popup menu by calling the
+ * gtk_menu_popup() function. The example below shows how an application
+ * can pop up a menu when the 3rd mouse button is pressed.
+ *
+ * <example>
+ * <title>Connecting the popup signal handler.</title>
+ * <programlisting>
+ * /<!---->* connect our handler which will popup the menu *<!---->/
+ * g_signal_connect_swapped (window, "button_press_event",
+ * G_CALLBACK (my_popup_handler), menu);
+ * </programlisting>
+ * </example>
+ *
+ * <example>
+ * <title>Signal handler which displays a popup menu.</title>
+ * <programlisting>
+ * static gint
+ * my_popup_handler (GtkWidget *widget, GdkEvent *event)
+ * {
+ * GtkMenu *menu;
+ * GdkEventButton *event_button;
+ *
+ * g_return_val_if_fail (widget != NULL, FALSE);
+ * g_return_val_if_fail (GTK_IS_MENU (widget), FALSE);
+ * g_return_val_if_fail (event != NULL, FALSE);
+ *
+ * /<!---->* The "widget" is the menu that was supplied when
+ * * g_signal_connect_swapped() was called.
+ * *<!---->/
+ * menu = GTK_MENU (widget);
+ *
+ * if (event->type == GDK_BUTTON_PRESS)
+ * {
+ * event_button = (GdkEventButton *) event;
+ * if (event_button->button == GDK_BUTTON_SECONDARY)
+ * {
+ * gtk_menu_popup (menu, NULL, NULL, NULL, NULL,
+ * event_button->button, event_button->time);
+ * return TRUE;
+ * }
+ * }
+ *
+ * return FALSE;
+ * }
+ * </programlisting>
+ * </example>
+ */
+
#include "config.h"
+
#include <string.h>
-#include "gdk/gdkkeysyms.h"
+
+#include <gobject/gvaluecollector.h>
+
#include "gtkaccellabel.h"
#include "gtkaccelmap.h"
+#include "gtkadjustment.h"
#include "gtkbindings.h"
#include "gtkcheckmenuitem.h"
-#include <gobject/gvaluecollector.h>
#include "gtkmain.h"
#include "gtkmarshalers.h"
#include "gtkmenuprivate.h"
-#include "gtktearoffmenuitem.h"
+#include "gtkmenuitemprivate.h"
+#include "gtkmenushellprivate.h"
#include "gtkwindow.h"
-#include "gtkhbox.h"
-#include "gtkvscrollbar.h"
+#include "gtkbox.h"
+#include "gtkscrollbar.h"
#include "gtksettings.h"
#include "gtkprivate.h"
+#include "gtkwidgetpath.h"
+#include "gtkwidgetprivate.h"
+#include "gtkdnd.h"
#include "gtkintl.h"
+#include "gtktypebuiltins.h"
+#include "gtkwidgetprivate.h"
+
+#include "deprecated/gtktearoffmenuitem.h"
+
+
+#include "a11y/gtkmenuaccessible.h"
#define NAVIGATION_REGION_OVERSHOOT 50 /* How much the navigation region
* extends below the submenu
GtkMenuDetachFunc detacher;
};
-struct _OldGtkMenuPrivate
-{
- gint x;
- gint y;
- gboolean initially_pushed_in;
-
- GDestroyNotify position_func_data_destroy;
-
- /* info used for the table */
- guint *heights;
- gint heights_length;
- gint requested_height;
-
- gint monitor_num;
-
- /* Cached layout information */
- gint n_rows;
- gint n_columns;
-
- guint accel_size;
-
- gchar *title;
-
- /* Arrow states */
- GtkStateFlags lower_arrow_state;
- GtkStateFlags upper_arrow_state;
-
- /* navigation region */
- int navigation_x;
- int navigation_y;
- int navigation_width;
- int navigation_height;
-
- guint have_layout : 1;
- guint seen_item_enter : 1;
- guint have_position : 1;
- guint ignore_button_release : 1;
- guint no_toggle_size : 1;
-};
-
struct _GtkMenuPopdownData
{
GtkMenu *menu;
gint offset);
static void gtk_menu_grab_notify (GtkWidget *widget,
gboolean was_grabbed);
+static gboolean gtk_menu_captured_event (GtkWidget *widget,
+ GdkEvent *event);
+
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);
static guint menu_signals[LAST_SIGNAL] = { 0 };
-static GtkMenuPrivate *
-gtk_menu_get_private (GtkMenu *menu)
-{
- return G_TYPE_INSTANCE_GET_PRIVATE (menu, GTK_TYPE_MENU, GtkMenuPrivate);
-}
-
G_DEFINE_TYPE (GtkMenu, gtk_menu, GTK_TYPE_MENU_SHELL)
static void
static void
menu_ensure_layout (GtkMenu *menu)
{
- GtkMenuPrivate *priv = gtk_menu_get_private (menu);
+ GtkMenuPrivate *priv = menu->priv;
if (!priv->have_layout)
{
GList *l;
gchar *row_occupied;
gint current_row;
- gint max_right_attach;
+ gint max_right_attach;
gint max_bottom_attach;
/* Find extents of gridded portion
max_right_attach = 1;
max_bottom_attach = 0;
- for (l = menu_shell->children; l; l = l->next)
+ for (l = menu_shell->priv->children; l; l = l->next)
{
GtkWidget *child = l->data;
AttachInfo *ai = get_attach_info (child);
/* Find empty rows */
row_occupied = g_malloc0 (max_bottom_attach);
- for (l = menu_shell->children; l; l = l->next)
+ for (l = menu_shell->priv->children; l; l = l->next)
{
GtkWidget *child = l->data;
AttachInfo *ai = get_attach_info (child);
/* Lay non-grid-items out in those rows
*/
current_row = 0;
- for (l = menu_shell->children; l; l = l->next)
+ for (l = menu_shell->priv->children; l; l = l->next)
{
GtkWidget *child = l->data;
AttachInfo *ai = get_attach_info (child);
static gint
gtk_menu_get_n_columns (GtkMenu *menu)
{
- GtkMenuPrivate *priv = gtk_menu_get_private (menu);
+ GtkMenuPrivate *priv = menu->priv;
menu_ensure_layout (menu);
static gint
gtk_menu_get_n_rows (GtkMenu *menu)
{
- GtkMenuPrivate *priv = gtk_menu_get_private (menu);
+ GtkMenuPrivate *priv = menu->priv;
menu_ensure_layout (menu);
menu_shell_class->get_popup_delay = gtk_menu_get_popup_delay;
menu_shell_class->move_current = gtk_menu_move_current;
+ /**
+ * GtkMenu::move-scroll:
+ * @menu: a #GtkMenu
+ * @scroll_type: a #GtkScrollType
+ */
menu_signals[MOVE_SCROLL] =
g_signal_new_class_handler (I_("move-scroll"),
G_OBJECT_CLASS_TYPE (gobject_class),
GTK_PARAM_READWRITE));
/**
- * GtkMenu::arrow-scaling
+ * GtkMenu:arrow-scaling:
*
* Arbitrary constant to scale down the size of the scroll arrow.
*
GTK_SCROLL_PAGE_DOWN);
g_type_class_add_private (gobject_class, sizeof (GtkMenuPrivate));
+
+ gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_MENU_ACCESSIBLE);
}
switch (prop_id)
{
case PROP_ACTIVE:
- g_value_set_int (value, g_list_index (GTK_MENU_SHELL (menu)->children, gtk_menu_get_active (menu)));
+ g_value_set_int (value, g_list_index (GTK_MENU_SHELL (menu)->priv->children, gtk_menu_get_active (menu)));
break;
case PROP_ACCEL_GROUP:
g_value_set_object (value, gtk_menu_get_accel_group (menu));
case GDK_KEY_RELEASE:
handled = gtk_widget_event (menu, event);
break;
+ case GDK_WINDOW_STATE:
+ /* Window for the menu has been closed by the display server or by GDK.
+ * Update the internal state as if the user had clicked outside the
+ * menu
+ */
+ if (event->window_state.new_window_state & GDK_WINDOW_STATE_WITHDRAWN &&
+ event->window_state.changed_mask & GDK_WINDOW_STATE_WITHDRAWN)
+ gtk_menu_shell_deactivate (GTK_MENU_SHELL(menu));
+ break;
default:
break;
}
priv->needs_destruction_ref = TRUE;
priv->monitor_num = -1;
+ priv->drag_start_y = -1;
context = gtk_widget_get_style_context (GTK_WIDGET (menu));
gtk_style_context_add_class (context, GTK_STYLE_CLASS_MENU);
+
+ _gtk_widget_set_captured_event_handler (GTK_WIDGET (menu), gtk_menu_captured_event);
}
static void
menu_change_screen (menu, gtk_widget_get_screen (attach_widget));
}
+/**
+ * gtk_menu_attach_to_widget:
+ * @menu: a #GtkMenu
+ * @attach_widget: the #GtkWidget that the menu will be attached to
+ * @detacher: (scope async)(allow-none): the user supplied callback function
+ * that will be called when the menu calls gtk_menu_detach()
+ *
+ * Attaches the menu to the widget and provides a callback function
+ * that will be invoked when the menu calls gtk_menu_detach() during
+ * its destruction.
+ */
void
gtk_menu_attach_to_widget (GtkMenu *menu,
GtkWidget *attach_widget,
if (gtk_widget_get_state_flags (GTK_WIDGET (menu)) != 0)
gtk_widget_set_state_flags (GTK_WIDGET (menu), 0, TRUE);
- /* we don't need to set the style here, since
- * we are a toplevel widget.
- */
+ /* Attach the widget to the toplevel window. */
+ gtk_window_set_attached_to (GTK_WINDOW (menu->priv->toplevel), attach_widget);
/* Fallback title for menu comes from attach widget */
gtk_menu_update_title (menu);
g_object_notify (G_OBJECT (menu), "attach-widget");
}
+/**
+ * gtk_menu_get_attach_widget:
+ * @menu: a #GtkMenu
+ *
+ * Returns the #GtkWidget that the menu is attached to.
+ *
+ * Returns: (transfer none): the #GtkWidget that the menu is attached to
+ */
GtkWidget*
gtk_menu_get_attach_widget (GtkMenu *menu)
{
return NULL;
}
+/**
+ * gtk_menu_detach:
+ * @menu: a #GtkMenu
+ *
+ * Detaches the menu from the widget to which it had been attached.
+ * This function will call the callback function, @detacher, provided
+ * when the gtk_menu_attach_to_widget() function was called.
+ */
void
gtk_menu_detach (GtkMenu *menu)
{
}
g_object_set_data (G_OBJECT (menu), I_(attach_data_key), NULL);
+ /* Detach the toplevel window. */
+ gtk_window_set_attached_to (GTK_WINDOW (menu->priv->toplevel), NULL);
+
g_signal_handlers_disconnect_by_func (data->attach_widget,
(gpointer) attach_widget_screen_changed,
menu);
menu_queue_resize (menu);
}
+/**
+ * gtk_menu_new:
+ *
+ * Creates a new #GtkMenu
+ *
+ * Returns: a new #GtkMenu
+ */
GtkWidget*
gtk_menu_new (void)
{
gtk_menu_tearoff_bg_copy (GtkMenu *menu)
{
GtkMenuPrivate *priv = menu->priv;
- GtkWidget *widget;
gint width, height;
- widget = GTK_WIDGET (menu);
-
if (priv->torn_off)
{
GdkWindow *window;
if (pointer &&
gdk_device_grab (pointer, window,
GDK_OWNERSHIP_WINDOW, TRUE,
+ GDK_SMOOTH_SCROLL_MASK |
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
GDK_POINTER_MOTION_MASK,
/**
* gtk_menu_popup_for_device:
- * @menu: a #GtkMenu.
+ * @menu: a #GtkMenu
* @device: (allow-none): a #GdkDevice
* @parent_menu_shell: (allow-none): the menu shell containing the triggering
* menu item, or %NULL
GtkMenuShell *menu_shell;
gboolean grab_keyboard;
GtkWidget *parent_toplevel;
- GdkDevice *keyboard, *pointer;
+ GdkDevice *keyboard, *pointer, *source_device = NULL;
g_return_if_fail (GTK_IS_MENU (menu));
g_return_if_fail (device == NULL || GDK_IS_DEVICE (device));
keyboard = gdk_device_get_associated_device (device);
}
- menu_shell->parent_menu_shell = parent_menu_shell;
+ menu_shell->priv->parent_menu_shell = parent_menu_shell;
priv->seen_item_enter = FALSE;
if (viewable)
xgrab_shell = parent;
- parent = GTK_MENU_SHELL (parent)->parent_menu_shell;
+ parent = GTK_MENU_SHELL (parent)->priv->parent_menu_shell;
}
/* We want to receive events generated when we map the menu;
if (popup_grab_on_window (gtk_widget_get_window (xgrab_shell), keyboard, pointer, activate_time))
{
_gtk_menu_shell_set_grab_device (GTK_MENU_SHELL (xgrab_shell), pointer);
- GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE;
+ GTK_MENU_SHELL (xgrab_shell)->priv->have_xgrab = TRUE;
}
}
else
if (popup_grab_on_window (transfer_window, keyboard, pointer, activate_time))
{
_gtk_menu_shell_set_grab_device (GTK_MENU_SHELL (xgrab_shell), pointer);
- GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE;
+ GTK_MENU_SHELL (xgrab_shell)->priv->have_xgrab = TRUE;
}
}
- if (!GTK_MENU_SHELL (xgrab_shell)->have_xgrab)
+ if (!GTK_MENU_SHELL (xgrab_shell)->priv->have_xgrab)
{
/* We failed to make our pointer/keyboard grab.
* Rather than leaving the user with a stuck up window,
* we just abort here. Presumably the user will try again.
*/
- menu_shell->parent_menu_shell = NULL;
+ menu_shell->priv->parent_menu_shell = NULL;
menu_grab_transfer_window_destroy (menu);
return;
}
_gtk_menu_shell_set_grab_device (GTK_MENU_SHELL (menu), pointer);
- menu_shell->active = TRUE;
- menu_shell->button = button;
+ menu_shell->priv->active = TRUE;
+ menu_shell->priv->button = button;
/* If we are popping up the menu from something other than, a button
* press then, as a heuristic, we ignore enter events for the menu
{
if ((current_event->type != GDK_BUTTON_PRESS) &&
(current_event->type != GDK_ENTER_NOTIFY))
- menu_shell->ignore_enter = TRUE;
+ menu_shell->priv->ignore_enter = TRUE;
+ source_device = gdk_event_get_source_device (current_event);
gdk_event_free (current_event);
}
else
- menu_shell->ignore_enter = TRUE;
+ menu_shell->priv->ignore_enter = TRUE;
if (priv->torn_off)
{
priv->position_func = func;
priv->position_func_data = data;
priv->position_func_data_destroy = destroy;
- menu_shell->activate_time = activate_time;
+ menu_shell->priv->activate_time = activate_time;
/* We need to show the menu here rather in the init function
* because code expects to be able to tell if the menu is onscreen
/* Compute the size of the toplevel and realize it so we
* can scroll correctly.
*/
+ if (!gtk_widget_get_realized (GTK_WIDGET (menu)))
{
GtkRequisition tmp_request;
GtkAllocation tmp_allocation = { 0, };
gtk_widget_size_allocate (priv->toplevel, &tmp_allocation);
- gtk_widget_realize (GTK_WIDGET (menu));
+ gtk_widget_realize (priv->toplevel);
}
gtk_menu_scroll_to (menu, priv->scroll_offset);
/* if no item is selected, select the first one */
- if (!menu_shell->active_menu_item)
- {
- gboolean touchscreen_mode;
-
- g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
- "gtk-touchscreen-mode", &touchscreen_mode,
- NULL);
-
- if (touchscreen_mode)
- gtk_menu_shell_select_first (menu_shell, TRUE);
- }
+ if (!menu_shell->priv->active_menu_item &&
+ source_device && gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)
+ gtk_menu_shell_select_first (menu_shell, TRUE);
/* Once everything is set up correctly, map the toplevel */
gtk_widget_show (priv->toplevel);
keyboard_mode = _gtk_menu_shell_get_keyboard_mode (GTK_MENU_SHELL (parent_menu_shell));
_gtk_menu_shell_set_keyboard_mode (menu_shell, keyboard_mode);
}
- else if (menu_shell->button == 0) /* a keynav-activated context menu */
+ else if (menu_shell->priv->button == 0) /* a keynav-activated context menu */
_gtk_menu_shell_set_keyboard_mode (menu_shell, TRUE);
_gtk_menu_shell_update_mnemonics (menu_shell);
/**
* gtk_menu_popup:
- * @menu: a #GtkMenu.
+ * @menu: a #GtkMenu
* @parent_menu_shell: (allow-none): the menu shell containing the
* triggering menu item, or %NULL
* @parent_menu_item: (allow-none): the menu item whose activation
* triggered the popup, or %NULL
* @func: (allow-none): a user supplied function used to position
* the menu, or %NULL
- * @data: (allow-none): user supplied data to be passed to @func.
+ * @data: user supplied data to be passed to @func.
* @button: the mouse button which was pressed to initiate the event.
* @activate_time: the time at which the activation event occurred.
*
button, activate_time);
}
+/**
+ * gtk_menu_popdown:
+ * @menu: a #GtkMenu
+ *
+ * Removes the menu from the screen.
+ */
void
gtk_menu_popdown (GtkMenu *menu)
{
menu_shell = GTK_MENU_SHELL (menu);
priv = menu->priv;
- menu_shell->parent_menu_shell = NULL;
- menu_shell->active = FALSE;
- menu_shell->ignore_enter = FALSE;
+ menu_shell->priv->parent_menu_shell = NULL;
+ menu_shell->priv->active = FALSE;
+ menu_shell->priv->ignore_enter = FALSE;
priv->have_position = FALSE;
gtk_menu_stop_scrolling (menu);
gtk_menu_stop_navigating_submenu (menu);
- if (menu_shell->active_menu_item)
+ if (menu_shell->priv->active_menu_item)
{
if (priv->old_active_menu_item)
g_object_unref (priv->old_active_menu_item);
- priv->old_active_menu_item = menu_shell->active_menu_item;
+ priv->old_active_menu_item = menu_shell->priv->active_menu_item;
g_object_ref (priv->old_active_menu_item);
}
/* We popped up the menu from the tearoff, so we need to
* release the grab - we aren't actually hiding the menu.
*/
- if (menu_shell->have_xgrab && pointer)
+ if (menu_shell->priv->have_xgrab && pointer)
{
GdkDevice *keyboard;
else
gtk_widget_hide (GTK_WIDGET (menu));
- menu_shell->have_xgrab = FALSE;
+ menu_shell->priv->have_xgrab = FALSE;
if (pointer)
gtk_device_grab_remove (GTK_WIDGET (menu), pointer);
menu_grab_transfer_window_destroy (menu);
}
+/**
+ * gtk_menu_get_active:
+ * @menu: a #GtkMenu
+ *
+ * Returns the selected menu item from the menu. This is used by the
+ * #GtkOptionMenu.
+ *
+ * Returns: (transfer none): the #GtkMenuItem that was last selected
+ * in the menu. If a selection has not yet been made, the
+ * first menu item is selected.
+ */
GtkWidget*
gtk_menu_get_active (GtkMenu *menu)
{
if (!priv->old_active_menu_item)
{
child = NULL;
- children = GTK_MENU_SHELL (menu)->children;
+ children = GTK_MENU_SHELL (menu)->priv->children;
while (children)
{
return priv->old_active_menu_item;
}
+/**
+ * gtk_menu_set_active:
+ * @menu: a #GtkMenu
+ * @index: the index of the menu item to select. Iindex values are
+ * from 0 to n-1
+ *
+ * Selects the specified menu item within the menu. This is used by
+ * the #GtkOptionMenu and should not be used by anyone else.
+ */
void
gtk_menu_set_active (GtkMenu *menu,
guint index)
g_return_if_fail (GTK_IS_MENU (menu));
- tmp_list = g_list_nth (GTK_MENU_SHELL (menu)->children, index);
+ tmp_list = g_list_nth (GTK_MENU_SHELL (menu)->priv->children, index);
if (tmp_list)
{
child = tmp_list->data;
/**
* gtk_menu_set_accel_group:
- * @accel_group: (allow-none):
+ * @menu: a #GtkMenu
+ * @accel_group: (allow-none): the #GtkAccelGroup to be associated
+ * with the menu.
+ *
+ * Set the #GtkAccelGroup which holds global accelerators for the
+ * menu. This accelerator group needs to also be added to all windows
+ * that this menu is being used in with gtk_window_add_accel_group(),
+ * in order for those windows to support all the accelerators
+ * contained in this group.
*/
void
gtk_menu_set_accel_group (GtkMenu *menu,
}
}
+/**
+ * gtk_menu_get_accel_group:
+ * @menu: a #GtkMenu
+ *
+ * Gets the #GtkAccelGroup which holds global accelerators for the
+ * menu. See gtk_menu_set_accel_group().
+ *
+ * Returns: (transfer none): the #GtkAccelGroup associated with the menu
+ */
GtkAccelGroup*
gtk_menu_get_accel_group (GtkMenu *menu)
{
}
/**
- * gtk_menu_set_accel_path
+ * gtk_menu_set_accel_path:
* @menu: a valid #GtkMenu
* @accel_path: (allow-none): a valid accelerator path
*
}
/**
- * gtk_menu_get_accel_path
+ * gtk_menu_get_accel_path:
* @menu: a valid #GtkMenu
*
* Retrieves the accelerator path set on the menu.
}
}
+/**
+ * gtk_menu_reposition:
+ * @menu: a #GtkMenu
+ *
+ * Repositions the menu according to its position function.
+ */
void
gtk_menu_reposition (GtkMenu *menu)
{
gtk_menu_scrollbar_changed (GtkAdjustment *adjustment,
GtkMenu *menu)
{
- g_return_if_fail (GTK_IS_MENU (menu));
+ double value;
- if (adjustment->value != menu->priv->scroll_offset)
- gtk_menu_scroll_to (menu, adjustment->value);
+ value = gtk_adjustment_get_value (adjustment);
+ if (menu->priv->scroll_offset != value)
+ gtk_menu_scroll_to (menu, value);
}
static void
gtk_menu_set_tearoff_state (menu, FALSE);
}
+/**
+ * gtk_menu_set_tearoff_state:
+ * @menu: a #GtkMenu
+ * @torn_off: If %TRUE, menu is displayed as a tearoff menu.
+ *
+ * Changes the tearoff state of the menu. A menu is normally
+ * displayed as drop down menu which persists as long as the menu is
+ * active. It can also be displayed as a tearoff menu which persists
+ * until it is closed or reattached.
+ */
void
gtk_menu_set_tearoff_state (GtkMenu *menu,
gboolean torn_off)
priv->tearoff_scrollbar,
FALSE, FALSE, 0);
- if (priv->tearoff_adjustment->upper > height)
+ if (gtk_adjustment_get_upper (priv->tearoff_adjustment) > height)
gtk_widget_show (priv->tearoff_scrollbar);
gtk_widget_show (priv->tearoff_hbox);
* has no title set on it. This string is owned by GTK+
* and should not be modified or freed.
**/
-G_CONST_RETURN gchar *
+const gchar *
gtk_menu_get_title (GtkMenu *menu)
{
g_return_val_if_fail (GTK_IS_MENU (menu), NULL);
return menu->priv->title;
}
+/**
+ * gtk_menu_reorder_child:
+ * @menu: a #GtkMenu
+ * @child: the #GtkMenuItem to move
+ * @position: the new position to place @child.
+ * Positions are numbered from 0 to n - 1
+ *
+ * Moves @child to a new @position in the list of @menu
+ * children.
+ */
void
gtk_menu_reorder_child (GtkMenu *menu,
GtkWidget *child,
menu_shell = GTK_MENU_SHELL (menu);
- if (g_list_find (menu_shell->children, child))
+ if (g_list_find (menu_shell->priv->children, child))
{
- menu_shell->children = g_list_remove (menu_shell->children, child);
- menu_shell->children = g_list_insert (menu_shell->children, child, position);
+ menu_shell->priv->children = g_list_remove (menu_shell->priv->children, child);
+ menu_shell->priv->children = g_list_insert (menu_shell->priv->children, child, position);
menu_queue_resize (menu);
}
static void
gtk_menu_style_updated (GtkWidget *widget)
{
+ GTK_WIDGET_CLASS (gtk_menu_parent_class)->style_updated (widget);
+
if (gtk_widget_get_realized (widget))
{
GtkMenu *menu = GTK_MENU (widget);
}
static void
-get_menu_border (GtkWidget *widget,
- GtkBorder *border)
+get_menu_padding (GtkWidget *widget,
+ GtkBorder *padding)
{
GtkStyleContext *context;
GtkStateFlags state;
- GtkBorder *border_width;
context = gtk_widget_get_style_context (widget);
state = gtk_widget_get_state_flags (widget);
- gtk_style_context_get (context, state,
- "border-width", &border_width,
- NULL);
-
- *border = *border_width;
- gtk_border_free (border_width);
+ gtk_style_context_get_padding (context, state, padding);
}
static void
GList *children;
guint vertical_padding;
guint horizontal_padding;
- GtkBorder arrow_border, border;
+ GtkBorder arrow_border, padding;
g_return_if_fail (GTK_IS_MENU (widget));
gtk_widget_set_window (widget, window);
gdk_window_set_user_data (window, widget);
- get_menu_border (widget, &border);
+ get_menu_padding (widget, &padding);
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
context = gtk_widget_get_style_context (widget);
gtk_widget_get_allocation (widget, &allocation);
- attributes.x = border_width + border.left + horizontal_padding;
- attributes.y = border_width + border.top + vertical_padding;
+ attributes.x = border_width + padding.left + horizontal_padding;
+ attributes.y = border_width + padding.top + vertical_padding;
attributes.width = allocation.width -
- (2 * (border_width + horizontal_padding)) - border.left - border.right;
+ (2 * (border_width + horizontal_padding)) - padding.left - padding.right;
attributes.height = allocation.height -
- (2 * (border_width + vertical_padding)) - border.top - border.bottom;
+ (2 * (border_width + vertical_padding)) - padding.top - padding.bottom;
get_arrows_border (menu, &arrow_border);
attributes.y += arrow_border.top;
attributes.x = 0;
attributes.y = 0;
attributes.width = allocation.width + (2 * (border_width + horizontal_padding)) +
- border.left + border.right;
+ padding.left + padding.right;
attributes.height = priv->requested_height - (2 * (border_width + vertical_padding)) +
- border.top + border.bottom;
+ padding.top + padding.bottom;
attributes.width = MAX (1, attributes.width);
attributes.height = MAX (1, attributes.height);
&attributes, attributes_mask);
gdk_window_set_user_data (priv->bin_window, menu);
- children = GTK_MENU_SHELL (menu)->children;
+ children = GTK_MENU_SHELL (menu)->priv->children;
while (children)
{
child = children->data;
gtk_style_context_set_background (context, priv->view_window);
gtk_style_context_set_background (context, window);
- if (GTK_MENU_SHELL (widget)->active_menu_item)
+ if (GTK_MENU_SHELL (widget)->priv->active_menu_item)
gtk_menu_scroll_item_visible (GTK_MENU_SHELL (widget),
- GTK_MENU_SHELL (widget)->active_menu_item);
+ GTK_MENU_SHELL (widget)->priv->active_menu_item);
gdk_window_show (priv->bin_window);
gdk_window_show (priv->view_window);
guint **ret_min_heights,
guint **ret_nat_heights)
{
+ GtkBorder padding;
GtkMenuPrivate *priv;
GtkMenuShell *menu_shell;
GtkWidget *child, *widget;
gtk_widget_style_get (GTK_WIDGET (menu),
"horizontal-padding", &horizontal_padding,
NULL);
+ get_menu_padding (widget, &padding);
border_width = gtk_container_get_border_width (GTK_CONTAINER (menu));
- avail_width -= (border_width + horizontal_padding + gtk_widget_get_style (widget)->xthickness) * 2;
+ avail_width -= (border_width + horizontal_padding) * 2 + padding.left + padding.right;
- for (children = menu_shell->children; children; children = children->next)
+ for (children = menu_shell->priv->children; children; children = children->next)
{
gint part;
gint toggle_size;
guint border_width;
guint vertical_padding;
guint horizontal_padding;
- GtkBorder border;
+ GtkBorder padding;
g_return_if_fail (GTK_IS_MENU (widget));
g_return_if_fail (allocation != NULL);
"horizontal-padding", &horizontal_padding,
NULL);
- get_menu_border (widget, &border);
+ get_menu_padding (widget, &padding);
border_width = gtk_container_get_border_width (GTK_CONTAINER (menu));
g_free (priv->heights);
/* refresh our cached height request */
priv->requested_height = (2 * (border_width + vertical_padding)) +
- border.top + border.bottom;
+ padding.top + padding.bottom;
for (i = 0; i < priv->heights_length; i++)
priv->requested_height += priv->heights[i];
- x = border_width + border.left + horizontal_padding;
- y = border_width + border.top + vertical_padding;
+ x = border_width + padding.left + horizontal_padding;
+ y = border_width + padding.top + vertical_padding;
width = allocation->width - (2 * (border_width + horizontal_padding)) -
- border.left - border.right;
+ padding.left - padding.right;
height = allocation->height - (2 * (border_width + vertical_padding)) -
- border.top - border.bottom;
+ padding.top - padding.bottom;
- if (menu_shell->active)
+ if (menu_shell->priv->active)
gtk_menu_scroll_to (menu, priv->scroll_offset);
if (!priv->tearoff_active)
gdk_window_move_resize (priv->view_window, x, y, width, height);
}
- if (menu_shell->children)
+ if (menu_shell->priv->children)
{
gint base_width = width / gtk_menu_get_n_columns (menu);
- children = menu_shell->children;
+ children = menu_shell->priv->children;
while (children)
{
child = children->data;
}
else
{
- priv->tearoff_adjustment->upper = priv->requested_height;
- priv->tearoff_adjustment->page_size = allocation->height;
-
- if (priv->tearoff_adjustment->value + priv->tearoff_adjustment->page_size >
- priv->tearoff_adjustment->upper)
- {
- gint value;
- value = priv->tearoff_adjustment->upper - priv->tearoff_adjustment->page_size;
- if (value < 0)
- value = 0;
- gtk_menu_scroll_to (menu, value);
- }
-
- gtk_adjustment_changed (priv->tearoff_adjustment);
+ gtk_adjustment_configure (priv->tearoff_adjustment,
+ gtk_adjustment_get_value (priv->tearoff_adjustment),
+ 0,
+ priv->requested_height,
+ gtk_adjustment_get_step_increment (priv->tearoff_adjustment),
+ gtk_adjustment_get_page_increment (priv->tearoff_adjustment),
+ allocation->height);
if (!gtk_widget_get_visible (priv->tearoff_scrollbar))
{
guint vertical_padding;
guint horizontal_padding;
gint scroll_arrow_height;
- GtkBorder menu_border;
+ GtkBorder menu_padding;
gtk_widget_style_get (widget,
"vertical-padding", &vertical_padding,
"arrow-placement", &arrow_placement,
NULL);
- get_menu_border (widget, &menu_border);
+ get_menu_padding (widget, &menu_padding);
border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
- border->x = border_width + menu_border.left + horizontal_padding;
- border->y = border_width + menu_border.top + vertical_padding;
+ border->x = border_width + menu_padding.left + horizontal_padding;
+ border->y = border_width + menu_padding.top + vertical_padding;
border->width = gdk_window_get_width (gtk_widget_get_window (widget));
border->height = gdk_window_get_height (gtk_widget_get_window (widget));
lower->x = lower->y = lower->width = lower->height = 0;
}
- *arrow_space = scroll_arrow_height - menu_border.top - menu_border.bottom;
+ *arrow_space = scroll_arrow_height - menu_padding.top - menu_padding.bottom;
}
static gboolean
GdkRectangle border;
GdkRectangle upper;
GdkRectangle lower;
- GdkWindow *window;
gint arrow_space;
- GtkStateFlags state;
- GtkBorder menu_border;
+ GtkBorder menu_padding;
menu = GTK_MENU (widget);
- priv = gtk_menu_get_private (menu);
+ priv = menu->priv;
context = gtk_widget_get_style_context (widget);
- window = gtk_widget_get_window (widget);
- state = gtk_widget_get_state_flags (widget);
get_arrows_visible_area (menu, &border, &upper, &lower, &arrow_space);
- get_menu_border (widget, &menu_border);
+ get_menu_padding (widget, &menu_padding);
if (gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget)))
{
upper.width, upper.height);
gtk_render_arrow (context, cr, 0,
- upper.x + (upper.width - arrow_size) / 2,
- upper.y + menu_border.top + (arrow_space - arrow_size) / 2,
- arrow_size);
+ upper.x + (upper.width - arrow_size) / 2,
+ upper.y + menu_padding.top + (arrow_space - arrow_size) / 2,
+ arrow_size);
gtk_style_context_restore (context);
}
gtk_render_arrow (context, cr, G_PI,
lower.x + (lower.width - arrow_size) / 2,
- lower.y + menu_border.top + (arrow_space - arrow_size) / 2,
+ lower.y + menu_padding.bottom + (arrow_space - arrow_size) / 2,
arrow_size);
gtk_style_context_restore (context);
guint border_width;
gint child_min, child_nat;
gint min_width, nat_width;
- GtkBorder border;
+ GtkBorder padding;
menu = GTK_MENU (widget);
menu_shell = GTK_MENU_SHELL (widget);
max_toggle_size = 0;
max_accel_width = 0;
- children = menu_shell->children;
+ children = menu_shell->priv->children;
while (children)
{
gint part;
* case the toggle size request depends on the size
* request of a child of the child (e.g. for ImageMenuItem)
*/
- GTK_MENU_ITEM (child)->show_submenu_indicator = TRUE;
gtk_widget_get_preferred_width (child, &child_min, &child_nat);
gtk_menu_item_toggle_size_request (GTK_MENU_ITEM (child), &toggle_size);
max_toggle_size = MAX (max_toggle_size, toggle_size);
max_accel_width = MAX (max_accel_width,
- GTK_MENU_ITEM (child)->accelerator_width);
+ GTK_MENU_ITEM (child)->priv->accelerator_width);
part = child_min / (r - l);
min_width = MAX (min_width, part);
!priv->no_toggle_size)
{
GtkStyleContext *context;
- GtkWidgetPath *menu_path, *check_path;
+ GtkWidgetPath *check_path;
guint toggle_spacing;
guint indicator_size;
- context = gtk_widget_get_style_context (widget);
- menu_path = gtk_widget_path_copy (gtk_style_context_get_path (context));
+ context = gtk_style_context_new ();
/* Create a GtkCheckMenuItem path, only to query indicator spacing */
- check_path = gtk_widget_path_copy (menu_path);
+ check_path = _gtk_widget_create_path (widget);
gtk_widget_path_append_type (check_path, GTK_TYPE_CHECK_MENU_ITEM);
gtk_style_context_set_path (context, check_path);
gtk_widget_path_free (check_path);
+ gtk_style_context_set_screen (context, gtk_widget_get_screen (widget));
gtk_style_context_get_style (context,
"toggle-spacing", &toggle_spacing,
max_toggle_size = indicator_size + toggle_spacing;
- /* Restore real widget path */
- gtk_style_context_set_path (context, menu_path);
- gtk_widget_path_free (menu_path);
+ g_object_unref (context);
}
min_width += 2 * max_toggle_size + max_accel_width;
"horizontal-padding", &horizontal_padding,
NULL);
- get_menu_border (widget, &border);
+ get_menu_padding (widget, &padding);
border_width = gtk_container_get_border_width (GTK_CONTAINER (menu));
min_width += (2 * (border_width + horizontal_padding)) +
- border.left + border.right;
+ padding.left + padding.right;
nat_width += (2 * (border_width + horizontal_padding)) +
- border.top + border.bottom;
+ padding.left + padding.right;
priv->toggle_size = max_toggle_size;
priv->accel_size = max_accel_width;
gint *minimum_size,
gint *natural_size)
{
+ GtkBorder padding;
GtkMenu *menu = GTK_MENU (widget);
GtkMenuPrivate *priv = menu->priv;
guint *min_heights, *nat_heights;
gtk_widget_style_get (widget, "vertical-padding", &vertical_padding, NULL);
border_width = gtk_container_get_border_width (GTK_CONTAINER (menu));
+ get_menu_padding (widget, &padding);
- min_height = nat_height = (border_width + vertical_padding + gtk_widget_get_style (widget)->ythickness) * 2;
+ min_height = nat_height = (border_width + vertical_padding) * 2 +
+ padding.top + padding.bottom;
n_heights =
calculate_line_heights (menu, for_size, &min_heights, &nat_heights);
GdkScreen *screen = gtk_widget_get_screen (priv->toplevel);
GdkRectangle monitor;
- gdk_screen_get_monitor_geometry (screen, priv->monitor_num, &monitor);
+ gdk_screen_get_monitor_workarea (screen, priv->monitor_num, &monitor);
if (priv->position_y + min_height > monitor.y + monitor.height)
min_height = monitor.y + monitor.height - priv->position_y;
g_free (nat_heights);
}
-
-
-static gboolean
-gtk_menu_button_scroll (GtkMenu *menu,
- GdkEventButton *event)
-{
- GtkMenuPrivate *priv = menu->priv;
-
- if (priv->upper_arrow_prelight || priv->lower_arrow_prelight)
- {
- gboolean touchscreen_mode;
-
- g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
- "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
pointer_in_menu_window (GtkWidget *widget,
gdouble x_root,
menu_shell = GTK_MENU_SHELL (widget);
- if (GTK_IS_MENU (menu_shell->parent_menu_shell))
- return pointer_in_menu_window (menu_shell->parent_menu_shell,
+ if (GTK_IS_MENU (menu_shell->priv->parent_menu_shell))
+ return pointer_in_menu_window (menu_shell->priv->parent_menu_shell,
x_root, y_root);
}
gtk_menu_button_press (GtkWidget *widget,
GdkEventButton *event)
{
+ GdkDevice *source_device;
+ GtkWidget *event_widget;
+ GtkMenu *menu;
+
if (event->type != GDK_BUTTON_PRESS)
return FALSE;
- /* Don't pass down to menu shell for presses over scroll arrows
- */
- if (gtk_menu_button_scroll (GTK_MENU (widget), event))
- return TRUE;
+ source_device = gdk_event_get_source_device ((GdkEvent *) event);
+ event_widget = gtk_get_event_widget ((GdkEvent *) event);
+ menu = GTK_MENU (widget);
/* Don't pass down to menu shell if a non-menuitem part of the menu
* was clicked. The check for the event_widget being a GtkMenuShell
* the menu or on its border are delivered relative to
* menu_shell->window.
*/
- if (GTK_IS_MENU_SHELL (gtk_get_event_widget ((GdkEvent *) event)) &&
+ if (GTK_IS_MENU_SHELL (event_widget) &&
pointer_in_menu_window (widget, event->x_root, event->y_root))
return TRUE;
+ if (GTK_IS_MENU_ITEM (event_widget) &&
+ gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN &&
+ GTK_MENU_ITEM (event_widget)->priv->submenu != NULL &&
+ !gtk_widget_is_drawable (GTK_MENU_ITEM (event_widget)->priv->submenu))
+ menu->priv->ignore_button_release = TRUE;
+
return GTK_WIDGET_CLASS (gtk_menu_parent_class)->button_press_event (widget, event);
}
if (event->type != GDK_BUTTON_RELEASE)
return FALSE;
- /* Don't pass down to menu shell for releases over scroll arrows
- */
- if (gtk_menu_button_scroll (GTK_MENU (widget), event))
- return TRUE;
-
/* Don't pass down to menu shell if a non-menuitem part of the menu
* was clicked (see comment in button_press()).
*/
* next button_press/button_release in GtkMenuShell.
* See bug #449371.
*/
- if (GTK_MENU_SHELL (widget)->active)
- GTK_MENU_SHELL (widget)->button = 0;
+ if (GTK_MENU_SHELL (widget)->priv->active)
+ GTK_MENU_SHELL (widget)->priv->button = 0;
return TRUE;
}
path = _gtk_widget_get_accel_path (menu_item, locked);
if (!path)
{
- path = GTK_MENU_ITEM (menu_item)->accel_path;
+ path = GTK_MENU_ITEM (menu_item)->priv->accel_path;
if (locked)
{
}
/* Figure out what modifiers went into determining the key symbol */
- gdk_keymap_translate_keyboard_state (gdk_keymap_get_for_display (display),
+ _gtk_translate_keyboard_accel_state (gdk_keymap_get_for_display (display),
event->hardware_keycode,
- event->state, event->group,
- NULL, NULL, NULL, &consumed_modifiers);
+ event->state,
+ gtk_accelerator_get_default_mod_mask (),
+ event->group,
+ &accel_key, NULL, NULL, &consumed_modifiers);
- accel_key = gdk_keyval_to_lower (event->keyval);
+ accel_key = gdk_keyval_to_lower (accel_key);
accel_mods = event->state & gtk_accelerator_get_default_mod_mask () & ~consumed_modifiers;
/* If lowercasing affects the keysym, then we need to include SHIFT
- * in the modifiers, we re-uppercase when we match against the keyval,
- * but display and save in caseless form.
+ * in the modifiers, We re-upper case when we match against the
+ * keyval, but display and save in caseless form.
*/
if (accel_key != event->keyval)
accel_mods |= GDK_SHIFT_MASK;
/* Modify the accelerators */
if (can_change_accels &&
- menu_shell->active_menu_item &&
- gtk_bin_get_child (GTK_BIN (menu_shell->active_menu_item)) && /* no separators */
- GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu == NULL && /* no submenus */
+ menu_shell->priv->active_menu_item &&
+ gtk_bin_get_child (GTK_BIN (menu_shell->priv->active_menu_item)) && /* no separators */
+ GTK_MENU_ITEM (menu_shell->priv->active_menu_item)->priv->submenu == NULL && /* no submenus */
(delete || gtk_accelerator_valid (accel_key, accel_mods)))
{
- GtkWidget *menu_item = menu_shell->active_menu_item;
+ GtkWidget *menu_item = menu_shell->priv->active_menu_item;
gboolean locked, replace_accels = TRUE;
const gchar *path;
gint x,
gint y)
{
- GdkWindow *window = GTK_MENU_ITEM (widget)->event_window;
+ GdkWindow *window = GTK_MENU_ITEM (widget)->priv->event_window;
int w, h;
w = gdk_window_get_width (window);
GtkMenu *menu;
GtkMenuShell *menu_shell;
GtkWidget *parent;
+ GdkDevice *source_device;
gboolean need_enter;
- if (GTK_IS_MENU (widget))
+ source_device = gdk_event_get_source_device ((GdkEvent *) event);
+
+ if (GTK_IS_MENU (widget) &&
+ gdk_device_get_source (source_device) != GDK_SOURCE_TOUCHSCREEN)
{
GtkMenuPrivate *priv = GTK_MENU(widget)->priv;
menu = GTK_MENU (menu_shell);
if (definitely_within_item (menu_item, event->x, event->y))
- menu_shell->activate_time = 0;
+ menu_shell->priv->activate_time = 0;
- need_enter = (gtk_menu_has_navigation_triangle (menu) || menu_shell->ignore_enter);
+ need_enter = (gtk_menu_has_navigation_triangle (menu) || menu_shell->priv->ignore_enter);
/* Check to see if we are within an active submenu's navigation region
*/
/* The menu is now sensitive to enter events on its items, but
* was previously sensitive. So we fake an enter event.
*/
- menu_shell->ignore_enter = FALSE;
+ menu_shell->priv->ignore_enter = FALSE;
if (event->x >= 0 && event->x < gdk_window_get_width (event->window) &&
event->y >= 0 && event->y < gdk_window_get_height (event->window))
gtk_menu_scroll_to (menu, offset);
}
-static void
-gtk_menu_do_timeout_scroll (GtkMenu *menu,
- gboolean touchscreen_mode)
-{
- GtkMenuPrivate *priv = menu->priv;
- gboolean upper_visible;
- gboolean lower_visible;
-
- upper_visible = priv->upper_arrow_visible;
- lower_visible = priv->lower_arrow_visible;
-
- gtk_menu_scroll_by (menu, priv->scroll_step);
-
- if (touchscreen_mode &&
- (upper_visible != priv->upper_arrow_visible ||
- lower_visible != priv->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;
- priv->ignore_button_release = TRUE;
- }
-}
-
static gboolean
gtk_menu_scroll_timeout (gpointer data)
{
GtkMenu *menu;
- gboolean touchscreen_mode;
menu = GTK_MENU (data);
-
- g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
- "gtk-touchscreen-mode", &touchscreen_mode,
- NULL);
-
- gtk_menu_do_timeout_scroll (menu, touchscreen_mode);
+ gtk_menu_scroll_by (menu, menu->priv->scroll_step);
return TRUE;
}
-static gboolean
-gtk_menu_scroll_timeout_initial (gpointer data)
-{
- GtkMenu *menu;
- guint timeout;
- gboolean touchscreen_mode;
-
- menu = GTK_MENU (data);
-
- g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
- "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->priv->scroll_timeout =
- gdk_threads_add_timeout (timeout, gtk_menu_scroll_timeout, menu);
-
- return FALSE;
-}
-
-static void
-gtk_menu_start_scrolling (GtkMenu *menu)
-{
- guint timeout;
- gboolean touchscreen_mode;
-
- g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
- "gtk-timeout-repeat", &timeout,
- "gtk-touchscreen-mode", &touchscreen_mode,
- NULL);
-
- gtk_menu_do_timeout_scroll (menu, touchscreen_mode);
-
- menu->priv->scroll_timeout =
- gdk_threads_add_timeout (timeout, gtk_menu_scroll_timeout_initial, menu);
-}
-
static gboolean
gtk_menu_scroll (GtkWidget *widget,
GdkEventScroll *event)
case GDK_SCROLL_UP:
gtk_menu_scroll_by (menu, - MENU_SCROLL_STEP2);
break;
+ case GDK_SCROLL_SMOOTH:
+ gtk_menu_scroll_by (menu, event->delta_y);
+ break;
}
return TRUE;
guint vertical_padding;
gint win_x, win_y;
gint scroll_arrow_height;
+ GtkBorder padding;
window = gtk_widget_get_window (widget);
width = gdk_window_get_width (window);
"arrow-placement", &arrow_placement,
NULL);
- border = gtk_container_get_border_width (GTK_CONTAINER (menu)) +
- gtk_widget_get_style (widget)->ythickness + vertical_padding;
+ border = gtk_container_get_border_width (GTK_CONTAINER (menu)) + vertical_padding;
+ get_menu_padding (widget, &padding);
gdk_window_get_position (window, &win_x, &win_y);
upper->x = win_x;
upper->y = win_y;
upper->width = width;
- upper->height = scroll_arrow_height + border;
+ upper->height = scroll_arrow_height + border + padding.top;
}
if (lower)
{
lower->x = win_x;
- lower->y = win_y + height - border - scroll_arrow_height;
+ lower->y = win_y + height - border - padding.bottom - scroll_arrow_height;
lower->width = width;
- lower->height = scroll_arrow_height + border;
+ lower->height = scroll_arrow_height + border + padding.bottom;
}
break;
upper->x = win_x;
upper->y = win_y;
upper->width = width / 2;
- upper->height = scroll_arrow_height + border;
+ upper->height = scroll_arrow_height + border + padding.top;
}
if (lower)
lower->x = win_x + width / 2;
lower->y = win_y;
lower->width = width / 2;
- lower->height = scroll_arrow_height + border;
+ lower->height = scroll_arrow_height + border + padding.bottom;
}
break;
upper->x = win_x;
upper->y = win_y + height - border - scroll_arrow_height;
upper->width = width / 2;
- upper->height = scroll_arrow_height + border;
+ upper->height = scroll_arrow_height + border + padding.top;
}
if (lower)
lower->x = win_x + width / 2;
lower->y = win_y + height - border - scroll_arrow_height;
lower->width = width / 2;
- lower->height = scroll_arrow_height + border;
+ lower->height = scroll_arrow_height + border + padding.bottom;
}
break;
}
gboolean in_arrow;
gboolean scroll_fast = FALSE;
gint top_x, top_y;
- gboolean touchscreen_mode;
menu_shell = GTK_MENU_SHELL (menu);
- g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
- "gtk-touchscreen-mode", &touchscreen_mode,
- NULL);
-
gdk_window_get_position (gtk_widget_get_window (priv->toplevel),
&top_x, &top_y);
x -= top_x;
in_arrow = TRUE;
}
- if (touchscreen_mode)
- priv->upper_arrow_prelight = in_arrow;
-
if ((priv->upper_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
{
gboolean arrow_pressed = FALSE;
if (priv->upper_arrow_visible && !priv->tearoff_active)
{
- if (touchscreen_mode)
+ scroll_fast = (y < rect.y + MENU_SCROLL_FAST_ZONE);
+
+ if (enter && in_arrow &&
+ (!priv->upper_arrow_prelight ||
+ priv->scroll_fast != scroll_fast))
{
- if (enter && priv->upper_arrow_prelight)
- {
- if (priv->scroll_timeout == 0)
- {
- /* Deselect the active item so that
- * any submenus are popped down
- */
- gtk_menu_shell_deselect (menu_shell);
-
- gtk_menu_remove_scroll_timeout (menu);
- priv->scroll_step = -MENU_SCROLL_STEP2; /* always fast */
-
- if (!motion)
- {
- /* Only do stuff on click. */
- gtk_menu_start_scrolling (menu);
- arrow_pressed = TRUE;
- }
- }
- else
- {
- arrow_pressed = TRUE;
- }
- }
- else if (!enter)
- {
- gtk_menu_stop_scrolling (menu);
- }
+ priv->upper_arrow_prelight = TRUE;
+ priv->scroll_fast = scroll_fast;
+
+ /* Deselect the active item so that
+ * any submenus are popped down
+ */
+ gtk_menu_shell_deselect (menu_shell);
+
+ gtk_menu_remove_scroll_timeout (menu);
+ priv->scroll_step = scroll_fast
+ ? -MENU_SCROLL_STEP2
+ : -MENU_SCROLL_STEP1;
+
+ priv->scroll_timeout =
+ gdk_threads_add_timeout (scroll_fast
+ ? MENU_SCROLL_TIMEOUT2
+ : MENU_SCROLL_TIMEOUT1,
+ gtk_menu_scroll_timeout, menu);
}
- else /* !touchscreen_mode */
+ else if (!enter && !in_arrow && priv->upper_arrow_prelight)
{
- scroll_fast = (y < rect.y + MENU_SCROLL_FAST_ZONE);
-
- if (enter && in_arrow &&
- (!priv->upper_arrow_prelight ||
- priv->scroll_fast != scroll_fast))
- {
- priv->upper_arrow_prelight = TRUE;
- priv->scroll_fast = scroll_fast;
-
- /* Deselect the active item so that
- * any submenus are popped down
- */
- gtk_menu_shell_deselect (menu_shell);
-
- gtk_menu_remove_scroll_timeout (menu);
- priv->scroll_step = scroll_fast
- ? -MENU_SCROLL_STEP2
- : -MENU_SCROLL_STEP1;
-
- priv->scroll_timeout =
- gdk_threads_add_timeout (scroll_fast
- ? MENU_SCROLL_TIMEOUT2
- : MENU_SCROLL_TIMEOUT1,
- gtk_menu_scroll_timeout, menu);
- }
- else if (!enter && !in_arrow && priv->upper_arrow_prelight)
- {
- gtk_menu_stop_scrolling (menu);
- }
+ gtk_menu_stop_scrolling (menu);
}
}
- /* gtk_menu_start_scrolling() might have hit the top of the
- * menu, so check if the button isn't insensitive before
+ /* check if the button isn't insensitive before
* changing it to something else.
*/
if ((priv->upper_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
in_arrow = TRUE;
}
- if (touchscreen_mode)
- priv->lower_arrow_prelight = in_arrow;
-
if ((priv->lower_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
{
gboolean arrow_pressed = FALSE;
if (priv->lower_arrow_visible && !priv->tearoff_active)
{
- if (touchscreen_mode)
+ scroll_fast = (y > rect.y + rect.height - MENU_SCROLL_FAST_ZONE);
+
+ if (enter && in_arrow &&
+ (!priv->lower_arrow_prelight ||
+ priv->scroll_fast != scroll_fast))
{
- if (enter && priv->lower_arrow_prelight)
- {
- if (priv->scroll_timeout == 0)
- {
- /* Deselect the active item so that
- * any submenus are popped down
- */
- gtk_menu_shell_deselect (menu_shell);
-
- gtk_menu_remove_scroll_timeout (menu);
- priv->scroll_step = MENU_SCROLL_STEP2; /* always fast */
-
- if (!motion)
- {
- /* Only do stuff on click. */
- gtk_menu_start_scrolling (menu);
- arrow_pressed = TRUE;
- }
- }
- else
- {
- arrow_pressed = TRUE;
- }
- }
- else if (!enter)
- {
- gtk_menu_stop_scrolling (menu);
- }
+ priv->lower_arrow_prelight = TRUE;
+ priv->scroll_fast = scroll_fast;
+
+ /* Deselect the active item so that
+ * any submenus are popped down
+ */
+ gtk_menu_shell_deselect (menu_shell);
+
+ gtk_menu_remove_scroll_timeout (menu);
+ priv->scroll_step = scroll_fast
+ ? MENU_SCROLL_STEP2
+ : MENU_SCROLL_STEP1;
+
+ priv->scroll_timeout =
+ gdk_threads_add_timeout (scroll_fast
+ ? MENU_SCROLL_TIMEOUT2
+ : MENU_SCROLL_TIMEOUT1,
+ gtk_menu_scroll_timeout, menu);
}
- else /* !touchscreen_mode */
+ else if (!enter && !in_arrow && priv->lower_arrow_prelight)
{
- scroll_fast = (y > rect.y + rect.height - MENU_SCROLL_FAST_ZONE);
-
- if (enter && in_arrow &&
- (!priv->lower_arrow_prelight ||
- priv->scroll_fast != scroll_fast))
- {
- priv->lower_arrow_prelight = TRUE;
- priv->scroll_fast = scroll_fast;
-
- /* Deselect the active item so that
- * any submenus are popped down
- */
- gtk_menu_shell_deselect (menu_shell);
-
- gtk_menu_remove_scroll_timeout (menu);
- priv->scroll_step = scroll_fast
- ? MENU_SCROLL_STEP2
- : MENU_SCROLL_STEP1;
-
- priv->scroll_timeout =
- gdk_threads_add_timeout (scroll_fast
- ? MENU_SCROLL_TIMEOUT2
- : MENU_SCROLL_TIMEOUT1,
- gtk_menu_scroll_timeout, menu);
- }
- else if (!enter && !in_arrow && priv->lower_arrow_prelight)
- {
- gtk_menu_stop_scrolling (menu);
- }
+ gtk_menu_stop_scrolling (menu);
}
}
- /* gtk_menu_start_scrolling() might have hit the bottom of the
- * menu, so check if the button isn't insensitive before
+ /* check if the button isn't insensitive before
* changing it to something else.
*/
if ((priv->lower_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
{
GtkWidget *menu_item;
GtkWidget *parent;
- gboolean touchscreen_mode;
+ GdkDevice *source_device;
if (event->mode == GDK_CROSSING_GTK_GRAB ||
event->mode == GDK_CROSSING_GTK_UNGRAB ||
event->mode == GDK_CROSSING_STATE_CHANGED)
return TRUE;
- g_object_get (gtk_widget_get_settings (widget),
- "gtk-touchscreen-mode", &touchscreen_mode,
- NULL);
-
+ source_device = gdk_event_get_source_device ((GdkEvent *) event);
menu_item = gtk_get_event_widget ((GdkEvent*) event);
- if (GTK_IS_MENU (widget))
+
+ if (GTK_IS_MENU (widget) &&
+ gdk_device_get_source (source_device) != GDK_SOURCE_TOUCHSCREEN)
{
GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget);
- if (!menu_shell->ignore_enter)
+ if (!menu_shell->priv->ignore_enter)
gtk_menu_handle_scrolling (GTK_MENU (widget),
event->x_root, event->y_root, TRUE, TRUE);
}
- if (!touchscreen_mode && GTK_IS_MENU_ITEM (menu_item))
+ if (gdk_device_get_source (source_device) != GDK_SOURCE_TOUCHSCREEN &&
+ GTK_IS_MENU_ITEM (menu_item))
{
GtkWidget *menu = gtk_widget_get_parent (menu_item);
if (GTK_IS_MENU (menu))
{
- GtkMenuPrivate *priv = gtk_menu_get_private (GTK_MENU (menu));
+ GtkMenuPrivate *priv = (GTK_MENU (menu))->priv;
GtkMenuShell *menu_shell = GTK_MENU_SHELL (menu);
if (priv->seen_item_enter)
* on this menu. This means a release should always
* mean activate.
*/
- menu_shell->activate_time = 0;
+ menu_shell->priv->activate_time = 0;
}
else if ((event->detail != GDK_NOTIFY_NONLINEAR &&
event->detail != GDK_NOTIFY_NONLINEAR_VIRTUAL))
* far enough away from the enter point. (see
* gtk_menu_motion_notify())
*/
- menu_shell->activate_time = 0;
+ menu_shell->priv->activate_time = 0;
}
}
GtkMenu *menu;
GtkMenuItem *menu_item;
GtkWidget *event_widget;
+ GdkDevice *source_device;
if (event->mode == GDK_CROSSING_GTK_GRAB ||
event->mode == GDK_CROSSING_GTK_UNGRAB ||
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, TRUE);
+ source_device = gdk_event_get_source_device ((GdkEvent *) event);
+
+ if (gdk_device_get_source (source_device) != GDK_SOURCE_TOUCHSCREEN)
+ gtk_menu_handle_scrolling (menu, event->x_root, event->y_root, FALSE, TRUE);
event_widget = gtk_get_event_widget ((GdkEvent*) event);
/* Here we check to see if we're leaving an active menu item
* with a submenu, in which case we enter submenu navigation mode.
*/
- if (menu_shell->active_menu_item != NULL
- && menu_item->submenu != NULL
- && menu_item->submenu_placement == GTK_LEFT_RIGHT)
+ if (menu_shell->priv->active_menu_item != NULL
+ && menu_item->priv->submenu != NULL
+ && menu_item->priv->submenu_placement == GTK_LEFT_RIGHT)
{
- if (GTK_MENU_SHELL (menu_item->submenu)->active)
+ if (GTK_MENU_SHELL (menu_item->priv->submenu)->priv->active)
{
gtk_menu_set_submenu_navigation_region (menu, menu_item, event);
return TRUE;
}
- else if (menu_item == GTK_MENU_ITEM (menu_shell->active_menu_item))
+ else if (menu_item == GTK_MENU_ITEM (menu_shell->priv->active_menu_item))
{
/* We are leaving an active menu item with nonactive submenu.
* Deselect it so we don't surprise the user with by popping
return GTK_WIDGET_CLASS (gtk_menu_parent_class)->leave_notify_event (widget, event);
}
+static gboolean
+pointer_on_menu_widget (GtkMenu *menu,
+ gdouble x_root,
+ gdouble y_root)
+{
+ GtkMenuPrivate *priv = menu->priv;
+ GtkAllocation allocation;
+ gint window_x, window_y;
+
+ gtk_widget_get_allocation (GTK_WIDGET (menu), &allocation);
+ gdk_window_get_position (gtk_widget_get_window (priv->toplevel),
+ &window_x, &window_y);
+
+ if (x_root >= window_x && x_root < window_x + allocation.width &&
+ y_root >= window_y && y_root < window_y + allocation.height)
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+gtk_menu_captured_event (GtkWidget *widget,
+ GdkEvent *event)
+{
+ GdkDevice *source_device;
+ gboolean retval = FALSE;
+ GtkMenuPrivate *priv;
+ GtkMenu *menu;
+ gdouble x_root, y_root;
+ guint button;
+ GdkModifierType state;
+
+ menu = GTK_MENU (widget);
+ priv = menu->priv;
+
+ if (!priv->upper_arrow_visible && !priv->lower_arrow_visible)
+ return retval;
+
+ source_device = gdk_event_get_source_device (event);
+ gdk_event_get_root_coords (event, &x_root, &y_root);
+
+ switch (event->type)
+ {
+ case GDK_TOUCH_BEGIN:
+ case GDK_BUTTON_PRESS:
+ if ((!gdk_event_get_button (event, &button) || button == 1) &&
+ gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN &&
+ pointer_on_menu_widget (menu, x_root, y_root))
+ {
+ priv->drag_start_y = event->button.y_root;
+ priv->initial_drag_offset = priv->scroll_offset;
+ priv->drag_scroll_started = FALSE;
+ }
+ else
+ priv->drag_start_y = -1;
+
+ priv->drag_already_pressed = TRUE;
+ break;
+ case GDK_TOUCH_END:
+ case GDK_BUTTON_RELEASE:
+ if (priv->drag_scroll_started)
+ {
+ priv->drag_scroll_started = FALSE;
+ priv->drag_start_y = -1;
+ priv->drag_already_pressed = FALSE;
+ retval = TRUE;
+ }
+ break;
+ case GDK_TOUCH_UPDATE:
+ case GDK_MOTION_NOTIFY:
+ if ((!gdk_event_get_state (event, &state) || (state & GDK_BUTTON1_MASK)
+!= 0) &&
+ gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)
+ {
+ if (!priv->drag_already_pressed)
+ {
+ if (pointer_on_menu_widget (menu, x_root, y_root))
+ {
+ priv->drag_start_y = y_root;
+ priv->initial_drag_offset = priv->scroll_offset;
+ priv->drag_scroll_started = FALSE;
+ }
+ else
+ priv->drag_start_y = -1;
+
+ priv->drag_already_pressed = TRUE;
+ }
+
+ if (priv->drag_start_y < 0 && !priv->drag_scroll_started)
+ break;
+
+ if (priv->drag_scroll_started)
+ {
+ gint offset, view_height;
+ GtkBorder arrow_border;
+ gdouble y_diff;
+
+ y_diff = y_root - priv->drag_start_y;
+ offset = priv->initial_drag_offset - y_diff;
+
+ view_height = gdk_window_get_height (gtk_widget_get_window (widget));
+ get_arrows_border (menu, &arrow_border);
+
+ if (priv->upper_arrow_visible)
+ view_height -= arrow_border.top;
+
+ if (priv->lower_arrow_visible)
+ view_height -= arrow_border.bottom;
+
+ offset = CLAMP (offset, 0, priv->requested_height - view_height);
+ gtk_menu_scroll_to (menu, offset);
+
+ retval = TRUE;
+ }
+ else if (gtk_drag_check_threshold (widget,
+ 0, priv->drag_start_y,
+ 0, y_root))
+ {
+ priv->drag_scroll_started = TRUE;
+ gtk_menu_shell_deselect (GTK_MENU_SHELL (menu));
+ retval = TRUE;
+ }
+ }
+ break;
+ case GDK_ENTER_NOTIFY:
+ case GDK_LEAVE_NOTIFY:
+ if (priv->drag_scroll_started)
+ retval = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ return retval;
+}
+
static void
gtk_menu_stop_navigating_submenu (GtkMenu *menu)
{
gint submenu_top = 0;
gint submenu_bottom = 0;
gint width = 0;
- gint height = 0;
GtkWidget *event_widget;
GtkMenuPopdownData *popdown_data;
GdkWindow *window;
- g_return_if_fail (menu_item->submenu != NULL);
+ g_return_if_fail (menu_item->priv->submenu != NULL);
g_return_if_fail (event != NULL);
event_widget = gtk_get_event_widget ((GdkEvent*) event);
- window = gtk_widget_get_window (menu_item->submenu);
+ window = gtk_widget_get_window (menu_item->priv->submenu);
gdk_window_get_origin (window, &submenu_left, &submenu_top);
submenu_right = submenu_left + gdk_window_get_width (window);
submenu_bottom = submenu_top + gdk_window_get_height (window);
width = gdk_window_get_width (gtk_widget_get_window (event_widget));
- height = gdk_window_get_height (gtk_widget_get_window (event_widget));
if (event->x >= 0 && event->x < width)
{
* location of the rectangle. This is why the width or height
* can be negative.
*/
- if (menu_item->submenu_direction == GTK_DIRECTION_RIGHT)
+ if (menu_item->priv->submenu_direction == GTK_DIRECTION_RIGHT)
{
/* right */
priv->navigation_x = submenu_left;
g_return_if_fail (GTK_IS_MENU (menu_shell));
- parent = menu_shell->parent_menu_shell;
+ parent = menu_shell->priv->parent_menu_shell;
- menu_shell->activate_time = 0;
+ menu_shell->priv->activate_time = 0;
gtk_menu_popdown (GTK_MENU (menu_shell));
if (parent)
GtkRequisition requisition;
gint x, y;
gint scroll_offset;
- gint menu_height;
GdkScreen *screen;
GdkScreen *pointer_screen;
GdkRectangle monitor;
screen = gtk_widget_get_screen (widget);
pointer = _gtk_menu_shell_get_grab_device (GTK_MENU_SHELL (menu));
- gdk_display_get_device_state (gdk_screen_get_display (screen),
- pointer, &pointer_screen, &x, &y, NULL);
+ gdk_device_get_position (pointer, &pointer_screen, &x, &y);
- /* Get the minimum height for minimum width to figure out
+ /* Realize so we have the proper width and heigh to figure out
* the right place to popup the menu.
*/
- gtk_widget_get_preferred_size (widget, &requisition, NULL);
+ gtk_widget_realize (priv->toplevel);
+ requisition.width = gtk_widget_get_allocated_width (widget);
+ requisition.height = gtk_widget_get_allocated_height (widget);
if (pointer_screen != screen)
{
if (priv->monitor_num < 0)
priv->monitor_num = gdk_screen_get_monitor_at_point (screen, x, y);
- gdk_screen_get_monitor_geometry (screen, priv->monitor_num, &monitor);
+ gdk_screen_get_monitor_workarea (screen, priv->monitor_num, &monitor);
}
else
{
gint space_left, space_right, space_above, space_below;
gint needed_width;
gint needed_height;
- GtkBorder border;
+ GtkBorder padding;
gboolean rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
- get_menu_border (widget, &border);
+ get_menu_padding (widget, &padding);
/* The placement of popup menus horizontally works like this (with
* RTL in parentheses)
* Positioning in the vertical direction is similar: first try below
* mouse cursor, then above.
*/
- gdk_screen_get_monitor_geometry (screen, priv->monitor_num, &monitor);
+ gdk_screen_get_monitor_workarea (screen, priv->monitor_num, &monitor);
space_left = x - monitor.x;
space_right = monitor.x + monitor.width - x - 1;
/* the amount of space we need to position the menu.
* Note the menu is offset "thickness" pixels
*/
- needed_width = requisition.width - border.left;
+ needed_width = requisition.width - padding.left;
if (needed_width <= space_left ||
needed_width <= space_right)
(!rtl && needed_width > space_right))
{
/* position left */
- x = x + border.left - requisition.width + 1;
+ x = x + padding.left - requisition.width + 1;
}
else
{
/* position right */
- x = x - border.right;
+ x = x - padding.right;
}
/* x is clamped on-screen further down */
* The algorithm is the same as above, but simpler
* because we don't have to take RTL into account.
*/
- needed_height = requisition.height - border.top;
+ needed_height = requisition.height - padding.top;
if (needed_height <= space_above ||
needed_height <= space_below)
{
if (needed_height <= space_below)
- y = y - border.top;
+ y = y - padding.top;
else
- y = y + border.bottom - requisition.height + 1;
+ y = y + padding.bottom - requisition.height + 1;
y = CLAMP (y, monitor.y,
monitor.y + monitor.height - requisition.height);
scroll_offset = 0;
- if (priv->initially_pushed_in)
+ if (y + requisition.height > monitor.y + monitor.height)
{
- menu_height = requisition.height;
-
- if (y + menu_height > monitor.y + monitor.height)
- {
- scroll_offset -= y + menu_height - (monitor.y + monitor.height);
- y = (monitor.y + monitor.height) - menu_height;
- }
+ if (priv->initially_pushed_in)
+ scroll_offset += (monitor.y + monitor.height) - requisition.height - y;
+ y = (monitor.y + monitor.height) - requisition.height;
+ }
- if (y < monitor.y)
- {
- scroll_offset += monitor.y - y;
- y = monitor.y;
- }
+ if (y < monitor.y)
+ {
+ if (priv->initially_pushed_in)
+ scroll_offset += monitor.y - y;
+ y = monitor.y;
}
- /* FIXME: should this be done in the various position_funcs ? */
x = CLAMP (x, monitor.x, MAX (monitor.x, monitor.x + monitor.width - requisition.width));
- if (GTK_MENU_SHELL (menu)->active)
+ if (GTK_MENU_SHELL (menu)->priv->active)
{
priv->have_position = TRUE;
priv->position_x = x;
priv->position_y = y;
}
- if (y + requisition.height > monitor.y + monitor.height)
- requisition.height = (monitor.y + monitor.height) - y;
-
- if (y < monitor.y)
- {
- scroll_offset += monitor.y - y;
- requisition.height -= monitor.y - y;
- y = monitor.y;
- }
-
- if (scroll_offset > 0)
+ if (scroll_offset != 0)
{
GtkBorder arrow_border;
scroll_offset += arrow_border.top;
}
- gtk_window_move (GTK_WINDOW (GTK_MENU_SHELL (menu)->active ? priv->toplevel : priv->tearoff_window),
+ gtk_window_move (GTK_WINDOW (GTK_MENU_SHELL (menu)->priv->active ? priv->toplevel : priv->tearoff_window),
x, y);
- if (!GTK_MENU_SHELL (menu)->active)
+ if (!GTK_MENU_SHELL (menu)->priv->active)
{
gtk_window_resize (GTK_WINDOW (priv->tearoff_window),
requisition.width, requisition.height);
gtk_menu_stop_scrolling (GtkMenu *menu)
{
GtkMenuPrivate *priv = menu->priv;
- gboolean touchscreen_mode;
gtk_menu_remove_scroll_timeout (menu);
-
- g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
- "gtk-touchscreen-mode", &touchscreen_mode,
- NULL);
-
- if (!touchscreen_mode)
- {
- priv->upper_arrow_prelight = FALSE;
- priv->lower_arrow_prelight = FALSE;
- }
+ priv->upper_arrow_prelight = FALSE;
+ priv->lower_arrow_prelight = FALSE;
}
static void
gint offset)
{
GtkMenuPrivate *priv = menu->priv;
- GtkAllocation allocation;
- GtkBorder arrow_border, border;
+ GtkBorder arrow_border, padding;
GtkWidget *widget;
gint x, y;
gint view_width, view_height;
widget = GTK_WIDGET (menu);
- if (priv->tearoff_active &&
- priv->tearoff_adjustment &&
- (priv->tearoff_adjustment->value != offset))
- {
- priv->tearoff_adjustment->value =
- CLAMP (offset,
- 0, priv->tearoff_adjustment->upper - priv->tearoff_adjustment->page_size);
- gtk_adjustment_value_changed (priv->tearoff_adjustment);
- }
+ if (priv->tearoff_active && priv->tearoff_adjustment)
+ gtk_adjustment_set_value (priv->tearoff_adjustment, offset);
/* Move/resize the viewport according to arrows: */
- gtk_widget_get_allocation (widget, &allocation);
- view_width = allocation.width;
- view_height = allocation.height;
+ view_width = gtk_widget_get_allocated_width (widget);
+ view_height = gtk_widget_get_allocated_height (widget);
gtk_widget_style_get (GTK_WIDGET (menu),
"vertical-padding", &vertical_padding,
"horizontal-padding", &horizontal_padding,
NULL);
- get_menu_border (widget, &border);
+ get_menu_padding (widget, &padding);
double_arrows = get_double_arrows (menu);
border_width = gtk_container_get_border_width (GTK_CONTAINER (menu));
- view_width -= (2 * (border_width + horizontal_padding)) + border.left + border.right;
- view_height -= (2 * (border_width + vertical_padding)) + border.top + border.bottom;
+ view_width -= (2 * (border_width + horizontal_padding)) + padding.left + padding.right;
+ view_height -= (2 * (border_width + vertical_padding)) + padding.top + padding.bottom;
menu_height = priv->requested_height - (2 * (border_width + vertical_padding)) -
- border.top - border.bottom;
+ padding.top - padding.bottom;
- x = border_width + border.left + horizontal_padding;
- y = border_width + border.top + vertical_padding;
+ x = border_width + padding.left + horizontal_padding;
+ y = border_width + padding.top + vertical_padding;
if (double_arrows && !priv->tearoff_active)
{
if (!priv->heights || priv->heights_length < gtk_menu_get_n_rows (menu))
return FALSE;
- /* when we have a row with only invisible children, it's height will
+ /* when we have a row with only invisible children, its height will
* be zero, so there's no need to check WIDGET_VISIBLE here
*/
for (i = 0; i < item_top_attach; i++)
GtkMenuPrivate *priv = menu->priv;
GtkWidget *widget = GTK_WIDGET (menu_shell);
gint child_offset, child_height;
- gint width, height;
+ gint height;
gint y;
gint arrow_height;
gboolean last_child = 0;
* If not we need to scroll the menu so that it becomes fully
* visible.
*/
-
if (compute_child_offset (menu, menu_item,
&child_offset, &child_height, &last_child))
{
guint vertical_padding;
gboolean double_arrows;
+ GtkBorder padding;
y = priv->scroll_offset;
- width = gdk_window_get_width (gtk_widget_get_window (widget));
height = gdk_window_get_height (gtk_widget_get_window (widget));
gtk_widget_style_get (widget,
NULL);
double_arrows = get_double_arrows (menu);
+ get_menu_padding (widget, &padding);
height -= 2 * gtk_container_get_border_width (GTK_CONTAINER (menu)) +
- 2 * gtk_widget_get_style (widget)->ythickness +
+ padding.top + padding.bottom +
2 * vertical_padding;
if (child_offset < y)
{
/* Ignore the enter event we might get if the pointer
* is on the menu
*/
- menu_shell->ignore_enter = TRUE;
+ menu_shell->priv->ignore_enter = TRUE;
gtk_menu_scroll_to (menu, child_offset);
}
else
/* Ignore the enter event we might get if the pointer
* is on the menu
*/
- menu_shell->ignore_enter = TRUE;
+ menu_shell->priv->ignore_enter = TRUE;
gtk_menu_scroll_to (menu, y);
}
}
ai->top_attach = top_attach;
ai->bottom_attach = bottom_attach;
- menu_shell->children = g_list_append (menu_shell->children, child);
+ menu_shell->priv->children = g_list_append (menu_shell->priv->children, child);
gtk_widget_set_parent (child, GTK_WIDGET (menu));
/* find a child which includes the area given by
* left, right, top, bottom.
*/
- for (list = menu_shell->children; list; list = list->next)
+ for (list = menu_shell->priv->children; list; list = list->next)
{
gint l, r, t, b;
}
/* use special table menu key bindings */
- if (menu_shell->active_menu_item && gtk_menu_get_n_columns (menu) > 1)
+ if (menu_shell->priv->active_menu_item && gtk_menu_get_n_columns (menu) > 1)
{
- get_effective_child_attach (menu_shell->active_menu_item, &l, &r, &t, &b);
+ get_effective_child_attach (menu_shell->priv->active_menu_item, &l, &r, &t, &b);
if (direction == GTK_MENU_DIR_NEXT)
{
if (!match)
{
- GtkWidget *parent = menu_shell->parent_menu_shell;
+ GtkWidget *parent = menu_shell->priv->parent_menu_shell;
if (!parent
- || g_list_length (GTK_MENU_SHELL (parent)->children) <= 1)
- match = menu_shell->active_menu_item;
+ || g_list_length (GTK_MENU_SHELL (parent)->priv->children) <= 1)
+ match = menu_shell->priv->active_menu_item;
}
}
else if (direction == GTK_MENU_DIR_CHILD)
if (!match)
{
- GtkWidget *parent = menu_shell->parent_menu_shell;
+ GtkWidget *parent = menu_shell->priv->parent_menu_shell;
- if (! GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu &&
+ if (! GTK_MENU_ITEM (menu_shell->priv->active_menu_item)->priv->submenu &&
(!parent ||
- g_list_length (GTK_MENU_SHELL (parent)->children) <= 1))
- match = menu_shell->active_menu_item;
+ g_list_length (GTK_MENU_SHELL (parent)->priv->children) <= 1))
+ match = menu_shell->priv->active_menu_item;
}
}
GtkAllocation allocation;
GtkWidget *widget = GTK_WIDGET (menu);
GtkContainer *container = GTK_CONTAINER (menu);
+ GtkBorder padding;
gint menu_height;
gtk_widget_get_allocation (widget, &allocation);
- menu_height = (allocation.height
- - 2 * (gtk_container_get_border_width (container)
- + gtk_widget_get_style (widget)->ythickness));
+ get_menu_padding (widget, &padding);
+
+ menu_height = (allocation.height -
+ (2 * gtk_container_get_border_width (container)) -
+ padding.top - padding.bottom);
if (!priv->tearoff_active)
{
lower = priv->scroll_offset;
upper = priv->scroll_offset + menu_height;
- for (children = menu_shell->children; children; children = children->next)
+ for (children = menu_shell->priv->children; children; children = children->next)
{
if (gtk_widget_get_visible (children->data))
{
get_menu_height (GtkMenu *menu)
{
GtkMenuPrivate *priv = menu->priv;
- GtkAllocation allocation;
GtkWidget *widget = GTK_WIDGET (menu);
+ GtkBorder padding;
gint height;
- gtk_widget_get_allocation (widget, &allocation);
+ get_menu_padding (widget, &padding);
- height = allocation.height;
- height -= (gtk_container_get_border_width (GTK_CONTAINER (widget)) + gtk_widget_get_style (widget)->ythickness) * 2;
+ height = priv->requested_height;
+ height -= (gtk_container_get_border_width (GTK_CONTAINER (widget)) * 2) +
+ padding.top + padding.bottom;
if (!priv->tearoff_active)
{
else
step = page_size;
- if (menu_shell->active_menu_item)
+ if (menu_shell->priv->active_menu_item)
{
gint child_height;
- compute_child_offset (menu, menu_shell->active_menu_item,
+ compute_child_offset (menu, menu_shell->priv->active_menu_item,
&child_offset, &child_height, NULL);
child_offset += child_height / 2;
}
- menu_shell->ignore_enter = TRUE;
+ menu_shell->priv->ignore_enter = TRUE;
old_upper_arrow_visible = priv->upper_arrow_visible && !priv->tearoff_active;
old_offset = priv->scroll_offset;
gtk_menu_scroll_to (menu, new_offset);
- if (menu_shell->active_menu_item)
+ if (menu_shell->priv->active_menu_item)
{
GtkWidget *new_child;
gboolean new_upper_arrow_visible = priv->upper_arrow_visible && !priv->tearoff_active;
break;
case GTK_SCROLL_START:
/* Ignore the enter event we might get if the pointer is on the menu */
- menu_shell->ignore_enter = TRUE;
- gtk_menu_scroll_to (menu, 0);
+ menu_shell->priv->ignore_enter = TRUE;
gtk_menu_shell_select_first (menu_shell, TRUE);
break;
case GTK_SCROLL_END:
/* Ignore the enter event we might get if the pointer is on the menu */
- menu_shell->ignore_enter = TRUE;
- gtk_menu_scroll_to (menu, end_position - page_size);
+ menu_shell->priv->ignore_enter = TRUE;
_gtk_menu_shell_select_last (menu_shell, TRUE);
break;
default:
}
}
-
/**
* gtk_menu_set_monitor:
* @menu: a #GtkMenu
gtk_menu_grab_notify (GtkWidget *widget,
gboolean was_grabbed)
{
+ GtkMenu *menu;
GtkWidget *toplevel;
GtkWindowGroup *group;
GtkWidget *grab;
GdkDevice *pointer;
+ menu = GTK_MENU (widget);
pointer = _gtk_menu_shell_get_grab_device (GTK_MENU_SHELL (widget));
if (!pointer ||
group = gtk_window_get_group (GTK_WINDOW (toplevel));
grab = gtk_window_group_get_current_device_grab (group, pointer);
- if (GTK_MENU_SHELL (widget)->active && !GTK_IS_MENU_SHELL (grab))
+ if (GTK_MENU_SHELL (widget)->priv->active && !GTK_IS_MENU_SHELL (grab))
gtk_menu_shell_cancel (GTK_MENU_SHELL (widget));
+
+ menu->priv->drag_scroll_started = FALSE;
}
/**