diff --git a/thunar/thunar-gtk-extensions.c b/thunar/thunar-gtk-extensions.c index 4852c118aa2b0a7a300924ed0f0d0b6749af7142..dd349a36059c7358df324b724607a3712a8a4c65 100644 --- a/thunar/thunar-gtk-extensions.c +++ b/thunar/thunar-gtk-extensions.c @@ -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 + **/ +void +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. + * **/ void -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)); diff --git a/thunar/thunar-gtk-extensions.h b/thunar/thunar-gtk-extensions.h index a264595c1b94283ea7e3a556b344aef0ed7cf8fa..98e0c30fcc8e5bb8909f654b02fa83f9dcd8f3a2 100644 --- a/thunar/thunar-gtk-extensions.h +++ b/thunar/thunar-gtk-extensions.h @@ -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); diff --git a/thunar/thunar-standard-view.c b/thunar/thunar-standard-view.c index af514ddd646000caf852246b27a42fa943322448..9b3d8b33b631c9c4db1220e6c2f4a7b308f118f9 100644 --- a/thunar/thunar-standard-view.c +++ b/thunar/thunar-standard-view.c @@ -346,6 +346,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; @@ -859,6 +860,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); @@ -3106,6 +3114,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; /* FIXME * - according to doc, the GdkWindow associated to the widget needs to enable the GDK_POINTER_MOTION_MASK mask to use this event. @@ -4359,7 +4369,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"); G_GNUC_END_IGNORE_DEPRECATIONS - 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; + } + else + thunar_gtk_menu_run (GTK_MENU (menu)); g_list_free_full (selected_items, (GDestroyNotify) gtk_tree_path_free); @@ -4414,6 +4432,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);