[gtk+/xi2] GtkMenu(Shell): Add gtk_menu_popup_for_device().
- From: Carlos Garnacho <carlosg src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gtk+/xi2] GtkMenu(Shell): Add gtk_menu_popup_for_device().
- Date: Wed, 30 Dec 2009 21:18:02 +0000 (UTC)
commit 052bb2c27c44e9787193b726dd7cd53d02900295
Author: Carlos Garnacho <carlos gnome org>
Date: Thu Dec 24 02:26:54 2009 +0100
GtkMenu(Shell): Add gtk_menu_popup_for_device().
The internals have been modified to use device-aware API. The device
pair that initiates the menu popup are the only ones able to deliver
events to it.
gtk/gtkmenu.c | 176 ++++++++++++++++++++++++++++++++++++++++------------
gtk/gtkmenu.h | 9 +++
gtk/gtkmenushell.c | 47 +++++++++++++-
gtk/gtkmenushell.h | 8 +++
4 files changed, 195 insertions(+), 45 deletions(-)
---
diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c
index 6a37604..c69d7c4 100644
--- a/gtk/gtkmenu.c
+++ b/gtk/gtkmenu.c
@@ -1377,28 +1377,32 @@ gtk_menu_tearoff_bg_copy (GtkMenu *menu)
static gboolean
popup_grab_on_window (GdkWindow *window,
- guint32 activate_time,
- gboolean grab_keyboard)
+ GdkDevice *keyboard,
+ GdkDevice *pointer,
+ guint32 activate_time)
{
- if ((gdk_pointer_grab (window, TRUE,
- GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
- GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
- GDK_POINTER_MOTION_MASK,
- NULL, NULL, activate_time) == 0))
+ if (keyboard &&
+ gdk_device_grab (keyboard, window,
+ GDK_OWNERSHIP_WINDOW, TRUE,
+ GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
+ NULL, activate_time) != GDK_GRAB_SUCCESS)
+ return FALSE;
+
+ if (pointer &&
+ gdk_device_grab (pointer, window,
+ GDK_OWNERSHIP_WINDOW, TRUE,
+ GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+ GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
+ GDK_POINTER_MOTION_MASK,
+ NULL, activate_time) != GDK_GRAB_SUCCESS)
{
- if (!grab_keyboard ||
- gdk_keyboard_grab (window, TRUE,
- activate_time) == 0)
- return TRUE;
- else
- {
- gdk_display_pointer_ungrab (gdk_drawable_get_display (window),
- activate_time);
- return FALSE;
- }
+ if (keyboard)
+ gdk_device_ungrab (keyboard, activate_time);
+
+ return FALSE;
}
- return FALSE;
+ return TRUE;
}
/**
@@ -1430,13 +1434,14 @@ popup_grab_on_window (GdkWindow *window,
* be used instead.
*/
void
-gtk_menu_popup (GtkMenu *menu,
- GtkWidget *parent_menu_shell,
- GtkWidget *parent_menu_item,
- GtkMenuPositionFunc func,
- gpointer data,
- guint button,
- guint32 activate_time)
+gtk_menu_popup_for_device (GtkMenu *menu,
+ GdkDevice *device,
+ GtkWidget *parent_menu_shell,
+ GtkWidget *parent_menu_item,
+ GtkMenuPositionFunc func,
+ gpointer data,
+ guint button,
+ guint32 activate_time)
{
GtkWidget *widget;
GtkWidget *xgrab_shell;
@@ -1446,13 +1451,26 @@ gtk_menu_popup (GtkMenu *menu,
gboolean grab_keyboard;
GtkMenuPrivate *priv;
GtkWidget *parent_toplevel;
+ GdkDevice *keyboard, *pointer;
g_return_if_fail (GTK_IS_MENU (menu));
+ g_return_if_fail (GDK_IS_DEVICE (device));
widget = GTK_WIDGET (menu);
menu_shell = GTK_MENU_SHELL (menu);
priv = gtk_menu_get_private (menu);
+ if (device->source == GDK_SOURCE_KEYBOARD)
+ {
+ keyboard = device;
+ pointer = gdk_device_get_associated_device (device);
+ }
+ else
+ {
+ pointer = device;
+ keyboard = gdk_device_get_associated_device (device);
+ }
+
menu_shell->parent_menu_shell = parent_menu_shell;
priv->seen_item_enter = FALSE;
@@ -1500,10 +1518,13 @@ gtk_menu_popup (GtkMenu *menu,
grab_keyboard = gtk_menu_shell_get_take_focus (menu_shell);
gtk_window_set_accept_focus (GTK_WINDOW (menu->toplevel), grab_keyboard);
+ if (!grab_keyboard)
+ keyboard = NULL;
+
if (xgrab_shell && xgrab_shell != widget)
{
- if (popup_grab_on_window (xgrab_shell->window, activate_time, grab_keyboard))
- GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE;
+ if (popup_grab_on_window (xgrab_shell->window, keyboard, pointer, activate_time))
+ GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE;
}
else
{
@@ -1511,8 +1532,8 @@ gtk_menu_popup (GtkMenu *menu,
xgrab_shell = widget;
transfer_window = menu_grab_transfer_window_get (menu);
- if (popup_grab_on_window (transfer_window, activate_time, grab_keyboard))
- GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE;
+ if (popup_grab_on_window (transfer_window, keyboard, pointer, activate_time))
+ GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE;
}
if (!GTK_MENU_SHELL (xgrab_shell)->have_xgrab)
@@ -1526,6 +1547,7 @@ gtk_menu_popup (GtkMenu *menu,
return;
}
+ _gtk_menu_shell_set_grab_devices (GTK_MENU_SHELL (menu), keyboard, pointer);
menu_shell->active = TRUE;
menu_shell->button = button;
@@ -1621,10 +1643,76 @@ gtk_menu_popup (GtkMenu *menu,
gtk_widget_show (menu->toplevel);
if (xgrab_shell == widget)
- popup_grab_on_window (widget->window, activate_time, grab_keyboard); /* Should always succeed */
+ popup_grab_on_window (widget->window, keyboard, pointer, activate_time); /* Should always succeed */
+
gtk_grab_add (GTK_WIDGET (menu));
}
+/**
+ * gtk_menu_popup:
+ * @menu: a #GtkMenu.
+ * @parent_menu_shell: the menu shell containing the triggering menu item, or %NULL
+ * @parent_menu_item: the menu item whose activation triggered the popup, or %NULL
+ * @func: a user supplied function used to position the menu, or %NULL
+ * @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.
+ *
+ * Displays a menu and makes it available for selection. Applications can use
+ * this function to display context-sensitive menus, and will typically supply
+ * %NULL for the @parent_menu_shell, @parent_menu_item, @func and @data
+ * parameters. The default menu positioning function will position the menu
+ * at the current mouse cursor position.
+ *
+ * The @button parameter should be the mouse button pressed to initiate
+ * the menu popup. If the menu popup was initiated by something other than
+ * a mouse button press, such as a mouse button release or a keypress,
+ * @button should be 0.
+ *
+ * The @activate_time parameter is used to conflict-resolve initiation of
+ * concurrent requests for mouse/keyboard grab requests. To function
+ * properly, this needs to be the time stamp of the user event (such as
+ * a mouse click or key press) that caused the initiation of the popup.
+ * Only if no such event is available, gtk_get_current_event_time() can
+ * be used instead.
+ */
+void
+gtk_menu_popup (GtkMenu *menu,
+ GtkWidget *parent_menu_shell,
+ GtkWidget *parent_menu_item,
+ GtkMenuPositionFunc func,
+ gpointer data,
+ guint button,
+ guint32 activate_time)
+{
+ GdkDevice *device;
+
+ g_return_if_fail (GTK_IS_MENU (menu));
+
+ device = gtk_get_current_event_device ();
+
+ if (!device)
+ {
+ GdkDisplay *display;
+ GdkDeviceManager *device_manager;
+ GList *devices;
+
+ display = gtk_widget_get_display (GTK_WIDGET (menu));
+ device_manager = gdk_display_get_device_manager (display);
+ devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
+
+ device = devices->data;
+
+ g_list_free (devices);
+ }
+
+ gtk_menu_popup_for_device (menu, device,
+ parent_menu_shell,
+ parent_menu_item,
+ func, data,
+ button, activate_time);
+}
+
void
gtk_menu_popdown (GtkMenu *menu)
{
@@ -1671,15 +1759,16 @@ gtk_menu_popdown (GtkMenu *menu)
}
else
{
- /* We popped up the menu from the tearoff, so we need to
+ GdkDevice *keyboard, *pointer;
+
+ /* 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)
+ if (menu_shell->have_xgrab &&
+ _gtk_menu_shell_get_grab_devices (menu_shell, &keyboard, &pointer))
{
- GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (menu));
-
- gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
- gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
+ gdk_device_ungrab (keyboard, GDK_CURRENT_TIME);
+ gdk_device_ungrab (pointer, GDK_CURRENT_TIME);
}
}
@@ -1695,6 +1784,7 @@ gtk_menu_popdown (GtkMenu *menu)
gtk_widget_hide (GTK_WIDGET (menu));
menu_shell->have_xgrab = FALSE;
+ _gtk_menu_shell_set_grab_devices (menu_shell, NULL, NULL);
gtk_grab_remove (GTK_WIDGET (menu));
menu_grab_transfer_window_destroy (menu);
@@ -3963,7 +4053,9 @@ gtk_menu_stop_navigating_submenu_cb (gpointer user_data)
if (GTK_WIDGET_REALIZED (menu))
{
- child_window = gdk_window_get_pointer (menu->bin_window, NULL, NULL, NULL);
+ child_window = gdk_window_get_device_position (menu->bin_window,
+ popdown_data->device,
+ NULL, NULL, NULL);
if (child_window)
{
@@ -4199,15 +4291,17 @@ gtk_menu_position (GtkMenu *menu)
GdkScreen *screen;
GdkScreen *pointer_screen;
GdkRectangle monitor;
-
+ GdkDevice *pointer;
+
g_return_if_fail (GTK_IS_MENU (menu));
widget = GTK_WIDGET (menu);
screen = gtk_widget_get_screen (widget);
- gdk_display_get_pointer (gdk_screen_get_display (screen),
- &pointer_screen, &x, &y, NULL);
-
+ _gtk_menu_shell_get_grab_devices (GTK_MENU_SHELL (menu), NULL, &pointer);
+ gdk_display_get_device_state (gdk_screen_get_display (screen),
+ pointer, &pointer_screen, &x, &y, NULL);
+
/* We need the requisition to figure out the right place to
* popup the menu. In fact, we always need to ask here, since
* if a size_request was queued while we weren't popped up,
diff --git a/gtk/gtkmenu.h b/gtk/gtkmenu.h
index 694457a..039083b 100644
--- a/gtk/gtkmenu.h
+++ b/gtk/gtkmenu.h
@@ -133,6 +133,15 @@ void gtk_menu_popup (GtkMenu *menu,
gpointer data,
guint button,
guint32 activate_time);
+void gtk_menu_popup_for_device (GtkMenu *menu,
+ GdkDevice *device,
+ GtkWidget *parent_menu_shell,
+ GtkWidget *parent_menu_item,
+ GtkMenuPositionFunc func,
+ gpointer data,
+ guint button,
+ guint32 activate_time);
+
/* Position the menu according to its position function. Called
* from gtkmenuitem.c when a menu-item changes its allocation
diff --git a/gtk/gtkmenushell.c b/gtk/gtkmenushell.c
index 910c760..21f040f 100644
--- a/gtk/gtkmenushell.c
+++ b/gtk/gtkmenushell.c
@@ -134,6 +134,9 @@ struct _GtkMenuShellPrivate
GtkMnemonicHash *mnemonic_hash;
GtkKeyHash *key_hash;
+ GdkDevice *grab_keyboard;
+ GdkDevice *grab_pointer;
+
guint take_focus : 1;
guint activated_submenu : 1;
};
@@ -991,11 +994,14 @@ gtk_real_menu_shell_deactivate (GtkMenuShell *menu_shell)
}
if (menu_shell->have_xgrab)
{
- GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (menu_shell));
-
+ GtkMenuShellPrivate *priv = GTK_MENU_SHELL_GET_PRIVATE (menu_shell);
+
+ gdk_device_ungrab (priv->grab_pointer, GDK_CURRENT_TIME);
+ gdk_device_ungrab (priv->grab_keyboard, GDK_CURRENT_TIME);
+
menu_shell->have_xgrab = FALSE;
- gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
- gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
+ priv->grab_pointer = NULL;
+ priv->grab_keyboard = NULL;
}
}
}
@@ -1621,6 +1627,39 @@ _gtk_menu_shell_remove_mnemonic (GtkMenuShell *menu_shell,
gtk_menu_shell_reset_key_hash (menu_shell);
}
+void
+_gtk_menu_shell_set_grab_devices (GtkMenuShell *menu_shell,
+ GdkDevice *keyboard,
+ GdkDevice *pointer)
+{
+ GtkMenuShellPrivate *priv = GTK_MENU_SHELL_GET_PRIVATE (menu_shell);
+
+ g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
+ g_return_if_fail (!keyboard || GDK_IS_DEVICE (keyboard));
+ g_return_if_fail (!pointer || GDK_IS_DEVICE (pointer));
+
+ priv->grab_keyboard = keyboard;
+ priv->grab_pointer = pointer;
+}
+
+gboolean
+_gtk_menu_shell_get_grab_devices (GtkMenuShell *menu_shell,
+ GdkDevice **keyboard,
+ GdkDevice **pointer)
+{
+ GtkMenuShellPrivate *priv = GTK_MENU_SHELL_GET_PRIVATE (menu_shell);
+
+ g_return_val_if_fail (GTK_IS_MENU_SHELL (menu_shell), FALSE);
+
+ if (keyboard)
+ *keyboard = priv->grab_keyboard;
+
+ if (pointer)
+ *pointer = priv->grab_pointer;
+
+ return TRUE;
+}
+
/**
* gtk_menu_shell_get_take_focus:
* @menu_shell: a #GtkMenuShell
diff --git a/gtk/gtkmenushell.h b/gtk/gtkmenushell.h
index e8281bc..70e4db7 100644
--- a/gtk/gtkmenushell.h
+++ b/gtk/gtkmenushell.h
@@ -117,6 +117,14 @@ void _gtk_menu_shell_select_last (GtkMenuShell *menu_shell,
gboolean search_sensitive);
void _gtk_menu_shell_activate (GtkMenuShell *menu_shell);
gint _gtk_menu_shell_get_popup_delay (GtkMenuShell *menu_shell);
+
+void _gtk_menu_shell_set_grab_devices (GtkMenuShell *menu_shell,
+ GdkDevice *keyboard,
+ GdkDevice *pointer);
+gboolean _gtk_menu_shell_get_grab_devices (GtkMenuShell *menu_shell,
+ GdkDevice **keyboard,
+ GdkDevice **pointer);
+
void gtk_menu_shell_cancel (GtkMenuShell *menu_shell);
void _gtk_menu_shell_add_mnemonic (GtkMenuShell *menu_shell,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]