Commit 29a6fb74 authored by Theo Linkspfeifer's avatar Theo Linkspfeifer Committed by Alexander Schwinn

Fix queued context menu popup

Co-authored-by: Alexander Schwinn's avatarAlexander Schwinn <>
parent e1a9778a
......@@ -131,27 +131,53 @@ thunar_gtk_label_set_a11y_relation (GtkLabel *label,
* thunar_gtk_menu_run:
* @menu : a #GtkMenu.
* A simple wrapper around gtk_menu_popup_at_pointer(), which takes care on the
* menu and returns only after the @menu was deactivated.
* Conveniance wrapper for thunar_gtk_menu_run_at_event_pointer, to run a menu for the current event
thunar_gtk_menu_run (GtkMenu *menu)
GdkEvent *event = gtk_get_current_event ();
thunar_gtk_menu_run_at_event (menu, event);
gdk_event_free (event);
* thunar_gtk_menu_run_at_event:
* @menu : a #GtkMenu.
* @event : a #GdkEvent which may be NULL if no previous event was stored.
* A simple wrapper around gtk_menu_popup_at_pointer(), which runs the @menu in a separate
* main loop and returns only after the @menu was deactivated.
* This method automatically takes over the floating reference of @menu if any and
* releases it on return. That means if you created the menu via gtk_menu_new() you'll
* not need to take care of destroying the menu later.
thunar_gtk_menu_run (GtkMenu *menu)
thunar_gtk_menu_run_at_event (GtkMenu *menu, GdkEvent *event)
GdkEvent *event;
GMainLoop *loop;
gulong signal_id;
_thunar_return_if_fail (GTK_IS_MENU (menu));
/* take over the floating reference on the menu */
g_object_ref_sink (G_OBJECT (menu));
event = gtk_get_current_event ();
/* run an internal main loop */
loop = g_main_loop_new (NULL, FALSE);
signal_id = g_signal_connect_swapped (G_OBJECT (menu), "deactivate", G_CALLBACK (g_main_loop_quit), loop);
gtk_menu_popup_at_pointer (menu, event);
gdk_event_free (event);
gtk_menu_reposition (menu);
gtk_grab_add (GTK_WIDGET (menu));
g_main_loop_run (loop);
g_main_loop_unref (loop);
gtk_grab_remove (GTK_WIDGET (menu));
g_signal_handler_disconnect (G_OBJECT (menu), signal_id);
/* release the menu reference */
g_object_unref (G_OBJECT (menu));
......@@ -37,6 +37,9 @@ void thunar_gtk_label_set_a11y_relation (GtkLabel
void thunar_gtk_menu_run (GtkMenu *menu);
void thunar_gtk_menu_run_at_event (GtkMenu *menu,
GdkEvent *event);
GtkAction *thunar_gtk_ui_manager_get_action_by_name (GtkUIManager *ui_manager,
const gchar *action_name);
......@@ -349,6 +349,7 @@ struct _ThunarStandardViewPrivate
GList *drag_g_file_list;
guint drag_scroll_timer_id;
guint drag_timer_id;
GdkEvent *drag_timer_event;
gint drag_x;
gint drag_y;
......@@ -849,6 +850,13 @@ thunar_standard_view_dispose (GObject *object)
if (G_UNLIKELY (standard_view->priv->drag_timer_id != 0))
g_source_remove (standard_view->priv->drag_timer_id);
/* be sure to free any pending drag timer event */
if (G_UNLIKELY (standard_view->priv->drag_timer_event != NULL))
gdk_event_free (standard_view->priv->drag_timer_event);
standard_view->priv->drag_timer_event = NULL;
/* reset the UI manager property */
thunar_component_set_ui_manager (THUNAR_COMPONENT (standard_view), NULL);
......@@ -3081,6 +3089,8 @@ thunar_standard_view_motion_notify_event (GtkWidget *view,
/* cancel the drag timer, as we won't popup the menu anymore */
g_source_remove (standard_view->priv->drag_timer_id);
gdk_event_free (standard_view->priv->drag_timer_event);
standard_view->priv->drag_timer_event = NULL;
* - according to doc, the GdkWindow associated to the widget needs to enable the GDK_POINTER_MOTION_MASK mask to use this event.
......@@ -4334,7 +4344,15 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
/* run the menu (figuring out whether to use the file or the folder context menu) */
menu = gtk_ui_manager_get_widget (standard_view->ui_manager, (selected_items != NULL) ? "/file-context-menu" : "/folder-context-menu");
thunar_gtk_menu_run (GTK_MENU (menu));
/* if there is a drag_timer_event (long press), we use it */
if (standard_view->priv->drag_timer_event != NULL)
thunar_gtk_menu_run_at_event (GTK_MENU (menu), standard_view->priv->drag_timer_event);
gdk_event_free (standard_view->priv->drag_timer_event);
standard_view->priv->drag_timer_event = NULL;
thunar_gtk_menu_run (GTK_MENU (menu));
g_list_free_full (selected_items, (GDestroyNotify) gtk_tree_path_free);
......@@ -4389,6 +4407,8 @@ thunar_standard_view_queue_popup (ThunarStandardView *standard_view,
/* schedule the timer */
standard_view->priv->drag_timer_id = g_timeout_add_full (G_PRIORITY_LOW, MAX (225, delay), thunar_standard_view_drag_timer,
standard_view, thunar_standard_view_drag_timer_destroy);
/* store current event data */
standard_view->priv->drag_timer_event = gtk_get_current_event ();
/* register the motion notify and the button release events on the real view */
g_signal_connect (G_OBJECT (view), "button-release-event", G_CALLBACK (thunar_standard_view_button_release_event), standard_view);
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment