From 068b17829c8a1386d22eb5e6665ac95de5f5c2a2 Mon Sep 17 00:00:00 2001
From: Alexander Schwinn <alexxcons@xfce.org>
Date: Sat, 16 May 2020 23:03:56 +0200
Subject: [PATCH] re-introduce redirection of tooltips into statusbar (Issue
 #293)

---
 thunar/thunar-standard-view.c |   1 +
 thunar/thunar-window.c        | 183 ++++++++++++++--------------------
 thunar/thunar-window.h        |   2 +
 3 files changed, 80 insertions(+), 106 deletions(-)

diff --git a/thunar/thunar-standard-view.c b/thunar/thunar-standard-view.c
index 964aeb03f..34967fec8 100644
--- a/thunar/thunar-standard-view.c
+++ b/thunar/thunar-standard-view.c
@@ -3538,6 +3538,7 @@ thunar_standard_view_context_menu (ThunarStandardView *standard_view)
     }
   thunar_menu_hide_accel_labels (context_menu);
   gtk_widget_show_all (GTK_WIDGET (context_menu));
+  thunar_window_redirect_menu_tooltips_to_statusbar (THUNAR_WINDOW (window), GTK_MENU (context_menu));
 
   /* if there is a drag_timer_event (long press), we use it */
   if (standard_view->priv->drag_timer_event != NULL)
diff --git a/thunar/thunar-window.c b/thunar/thunar-window.c
index d90f4358a..4aaeb278b 100644
--- a/thunar/thunar-window.c
+++ b/thunar/thunar-window.c
@@ -195,18 +195,10 @@ static gboolean  thunar_window_propagate_key_event        (GtkWindow
 static void      thunar_window_action_open_file_menu      (ThunarWindow           *window);
 static void      thunar_window_current_directory_changed  (ThunarFile             *current_directory,
                                                            ThunarWindow           *window);
-static void     thunar_window_connect_proxy               (GtkUIManager           *manager,
-                                                           GtkAction              *action,
-                                                           GtkWidget              *proxy,
-                                                           ThunarWindow           *window);
-static void     thunar_window_disconnect_proxy            (GtkUIManager           *manager,
-                                                           GtkAction              *action,
-                                                           GtkWidget              *proxy,
-                                                           ThunarWindow           *window);
-static void     thunar_window_menu_item_selected          (GtkWidget              *menu_item,
-                                                           ThunarWindow           *window);
-static void     thunar_window_menu_item_deselected        (GtkWidget              *menu_item,
-                                                           ThunarWindow           *window);
+static void      thunar_window_menu_item_selected         (ThunarWindow           *window,
+                                                           GtkWidget              *menu_item);
+static void      thunar_window_menu_item_deselected       (ThunarWindow           *window,
+                                                           GtkWidget              *menu_item);
 static void     thunar_window_update_custom_actions       (ThunarView             *view,
                                                            GParamSpec             *pspec,
                                                            ThunarWindow           *window);
@@ -309,10 +301,6 @@ struct _ThunarWindow
   /* to be able to change folder on "device-pre-unmount" if required */
   ThunarDeviceMonitor    *device_monitor;
 
-  /* closures for the menu_item_selected()/menu_item_deselected() callbacks */
-  GClosure               *menu_item_selected_closure;
-  GClosure               *menu_item_deselected_closure;
-
   /* custom menu actions for the file menu */
   GtkActionGroup         *custom_actions;
   guint                   custom_merge_id;
@@ -685,15 +673,6 @@ thunar_window_init (ThunarWindow *window)
   g_signal_connect (window->device_monitor, "device-removed", G_CALLBACK (thunar_window_device_changed), window);
   g_signal_connect (window->device_monitor, "device-changed", G_CALLBACK (thunar_window_device_changed), window);
 
-  /* allocate a closure for the menu_item_selected() callback */
-  window->menu_item_selected_closure = g_cclosure_new_object (G_CALLBACK (thunar_window_menu_item_selected), G_OBJECT (window));
-  g_closure_ref (window->menu_item_selected_closure);
-  g_closure_sink (window->menu_item_selected_closure);
-
-  /* allocate a closure for the menu_item_deselected() callback */
-  window->menu_item_deselected_closure = g_cclosure_new_object (G_CALLBACK (thunar_window_menu_item_deselected), G_OBJECT (window));
-  g_closure_ref (window->menu_item_deselected_closure);
-  g_closure_sink (window->menu_item_deselected_closure);
   window->icon_factory = thunar_icon_factory_get_default ();
 
   /* Catch key events before accelerators get processed */
@@ -707,6 +686,9 @@ thunar_window_init (ThunarWindow *window)
   window->launcher = g_object_new (THUNAR_TYPE_LAUNCHER, "widget", GTK_WIDGET (window),
                                   "select-files-closure",  window->select_files_closure, NULL);
 
+  window->ui_manager = gtk_ui_manager_new ();
+  gtk_ui_manager_add_ui_from_string (window->ui_manager, thunar_window_ui, thunar_window_ui_length, NULL);
+
   exo_binding_new (G_OBJECT (window), "current-directory", G_OBJECT (window->launcher), "current-directory");
   g_signal_connect_swapped (G_OBJECT (window->launcher), "change-directory", G_CALLBACK (thunar_window_set_current_directory), window);
   g_signal_connect_swapped (G_OBJECT (window->launcher), "open-new-tab", G_CALLBACK (thunar_window_notebook_insert), window);
@@ -872,6 +854,17 @@ G_GNUC_END_IGNORE_DEPRECATIONS
   thunar_window_install_sidepane (window, type);
   g_free (last_side_pane);
 
+  /* setup a new statusbar */
+  window->statusbar = thunar_statusbar_new ();
+  gtk_widget_set_hexpand (window->statusbar, TRUE);
+  gtk_grid_attach (GTK_GRID (window->view_box), window->statusbar, 0, 2, 1, 1);
+  if (last_statusbar_visible)
+    gtk_widget_show (window->statusbar);
+
+  if (G_LIKELY (window->view != NULL))
+    thunar_window_binding_create (window, window->view, "statusbar-text", window->statusbar, "text", G_BINDING_SYNC_CREATE);
+
+
   /* setup a new statusbar */
   window->statusbar = thunar_statusbar_new ();
   gtk_widget_set_hexpand (window->statusbar, TRUE);
@@ -987,6 +980,7 @@ thunar_window_create_file_menu (ThunarWindow     *window,
   gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu), GTK_WIDGET (submenu));
   gtk_widget_show_all (GTK_WIDGET (submenu));
 
+  thunar_window_redirect_menu_tooltips_to_statusbar (window, GTK_MENU (submenu));
   return FALSE;
 }
 
@@ -1026,6 +1020,7 @@ thunar_window_create_edit_menu (ThunarWindow     *window,
   gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu), GTK_WIDGET (submenu));
   gtk_widget_show_all (GTK_WIDGET (submenu));
 
+  thunar_window_redirect_menu_tooltips_to_statusbar (window, GTK_MENU (submenu));
   return FALSE;
 }
 
@@ -1095,6 +1090,7 @@ thunar_window_create_view_menu (ThunarWindow     *window,
   gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu), GTK_WIDGET (submenu));
   gtk_widget_show_all (GTK_WIDGET (submenu));
 
+  thunar_window_redirect_menu_tooltips_to_statusbar (window, GTK_MENU (submenu));
   return FALSE;
 }
 
@@ -1169,6 +1165,7 @@ thunar_window_create_go_menu (ThunarWindow     *window,
   xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_LOCATION), G_OBJECT (window), GTK_MENU_SHELL (submenu));
   gtk_widget_show_all (GTK_WIDGET (submenu));
 
+  thunar_window_redirect_menu_tooltips_to_statusbar (window, GTK_MENU (submenu));
   return FALSE;
 }
 
@@ -1191,6 +1188,7 @@ thunar_window_create_help_menu (ThunarWindow     *window,
   gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu), GTK_WIDGET (submenu));
   gtk_widget_show_all (GTK_WIDGET (submenu));
 
+  thunar_window_redirect_menu_tooltips_to_statusbar (window, GTK_MENU (submenu));
   return FALSE;
 }
 
@@ -1246,10 +1244,6 @@ thunar_window_finalize (GObject *object)
 {
   ThunarWindow *window = THUNAR_WINDOW (object);
 
-  /* drop our references on the menu_item_selected()/menu_item_deselected() closures */
-  g_closure_unref (window->menu_item_deselected_closure);
-  g_closure_unref (window->menu_item_selected_closure);
-
   /* disconnect from the volume monitor */
   g_signal_handlers_disconnect_matched (window->device_monitor, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, window);
   g_object_unref (window->device_monitor);
@@ -2811,25 +2805,7 @@ thunar_window_action_statusbar_changed (ThunarWindow *window)
 
   g_object_get (window->preferences, "last-statusbar-visible", &last_statusbar_visible, NULL);
 
-  /* check if we should drop the statusbar */
-  if (!last_statusbar_visible && window->statusbar != NULL)
-    {
-      /* just get rid of the statusbar */
-      gtk_widget_destroy (window->statusbar);
-      window->statusbar = NULL;
-    }
-  else if (last_statusbar_visible && window->statusbar == NULL)
-    {
-      /* setup a new statusbar */
-      window->statusbar = thunar_statusbar_new ();
-      gtk_widget_set_hexpand (window->statusbar, TRUE);
-      gtk_grid_attach (GTK_GRID (window->view_box), window->statusbar, 0, 2, 1, 1);
-      gtk_widget_show (window->statusbar);
-
-      /* connect to the view (if any) */
-      if (G_LIKELY (window->view != NULL))
-        thunar_window_binding_create (window, window->view, "statusbar-text", window->statusbar, "text", G_BINDING_SYNC_CREATE);
-    }
+  gtk_widget_set_visible (window->statusbar, !last_statusbar_visible);
 
   g_object_set (G_OBJECT (window->preferences), "last-statusbar-visible", !last_statusbar_visible, NULL);
 }
@@ -3518,73 +3494,24 @@ thunar_window_current_directory_changed (ThunarFile   *current_directory,
 
 
 static void
-thunar_window_connect_proxy (GtkUIManager *manager,
-                             GtkAction    *action,
-                             GtkWidget    *proxy,
-                             ThunarWindow *window)
-{
-  /* we want to get informed when the user hovers a menu item */
-  if (GTK_IS_MENU_ITEM (proxy))
-    {
-      g_signal_connect_closure (G_OBJECT (proxy), "select", window->menu_item_selected_closure, FALSE);
-      g_signal_connect_closure (G_OBJECT (proxy), "deselect", window->menu_item_deselected_closure, FALSE);
-    }
-}
-
-
-
-static void
-thunar_window_disconnect_proxy (GtkUIManager *manager,
-                                GtkAction    *action,
-                                GtkWidget    *proxy,
-                                ThunarWindow *window)
+thunar_window_menu_item_selected (ThunarWindow *window,
+                                  GtkWidget    *menu_item)
 {
-  /* undo what we did in connect_proxy() */
-  if (GTK_IS_MENU_ITEM (proxy))
-    {
-      g_signal_handlers_disconnect_matched (G_OBJECT (proxy), G_SIGNAL_MATCH_CLOSURE, 0, 0, window->menu_item_selected_closure, NULL, NULL);
-      g_signal_handlers_disconnect_matched (G_OBJECT (proxy), G_SIGNAL_MATCH_CLOSURE, 0, 0, window->menu_item_deselected_closure, NULL, NULL);
-    }
-}
+  gchar *tooltip;
+  gint   id;
 
-
-
-static void
-thunar_window_menu_item_selected (GtkWidget    *menu_item,
-                                  ThunarWindow *window)
-{
-  GtkAction   *action;
-  const gchar *tooltip;
-  gint         id;
-  gchar       *short_tip = NULL;
-  gchar       *p;
+  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
   /* we can only display tooltips if we have a statusbar */
   if (G_LIKELY (window->statusbar != NULL))
     {
-G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-      /* determine the action for the menu item */
-      action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (menu_item));
-      if (G_UNLIKELY (action == NULL))
-        return;
-
-      /* determine the tooltip from the action */
-      tooltip = gtk_action_get_tooltip (action);
-G_GNUC_END_IGNORE_DEPRECATIONS
+      tooltip = gtk_widget_get_tooltip_text (menu_item);
       if (G_LIKELY (tooltip != NULL))
         {
-          /* check if there is a new line in the tooltip */
-          p = strchr (tooltip, '\n');
-          if (p != NULL)
-            {
-              short_tip = g_strndup (tooltip, p - tooltip);
-              tooltip = short_tip;
-            }
-
           /* push to the statusbar */
           id = gtk_statusbar_get_context_id (GTK_STATUSBAR (window->statusbar), "Menu tooltip");
           gtk_statusbar_push (GTK_STATUSBAR (window->statusbar), id, tooltip);
-          g_free (short_tip);
+          g_free (tooltip);
         }
     }
 }
@@ -3592,11 +3519,13 @@ G_GNUC_END_IGNORE_DEPRECATIONS
 
 
 static void
-thunar_window_menu_item_deselected (GtkWidget    *menu_item,
-                                    ThunarWindow *window)
+thunar_window_menu_item_deselected (ThunarWindow *window,
+                                    GtkWidget    *menu_item)
 {
   gint id;
 
+  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
+
   /* we can only undisplay tooltips if we have a statusbar */
   if (G_LIKELY (window->statusbar != NULL))
     {
@@ -4192,6 +4121,48 @@ thunar_window_get_launcher (ThunarWindow *window)
 
 
 
+static void
+thunar_window_redirect_menu_tooltips_to_statusbar_recursive (GtkWidget    *menu_item,
+                                                             ThunarWindow *window)
+{
+  GtkWidget  *submenu;
+
+  if (GTK_IS_MENU_ITEM (menu_item))
+    {
+      submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (menu_item));
+      if (submenu != NULL)
+          gtk_container_foreach (GTK_CONTAINER (submenu), (GtkCallback) (void (*)(void)) thunar_window_redirect_menu_tooltips_to_statusbar_recursive, window);
+
+      /* this disables to show the tooltip on hover */
+      gtk_widget_set_has_tooltip (menu_item, FALSE);
+
+      /* These method will put the tooltip on the statusbar */
+      g_signal_connect_swapped (G_OBJECT (menu_item), "select", G_CALLBACK (thunar_window_menu_item_selected), window);
+      g_signal_connect_swapped (G_OBJECT (menu_item), "deselect", G_CALLBACK (thunar_window_menu_item_deselected), window);
+    }
+}
+
+
+
+/**
+ * thunar_window_redirect_menu_tooltips_to_statusbar:
+ * @window : a #ThunarWindow instance.
+ * @menu   : #GtkMenu for which all tooltips should be shown in the statusbar
+ *
+ * All tooltips of the provided #GtkMenu and any submenu will not be shown directly any more.
+ * Instead they will be shown in the status bar of the passed #ThunarWindow
+ **/
+void
+thunar_window_redirect_menu_tooltips_to_statusbar (ThunarWindow *window, GtkMenu *menu)
+{
+  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
+  _thunar_return_if_fail (GTK_IS_MENU (menu));
+
+  gtk_container_foreach (GTK_CONTAINER (menu), (GtkCallback) (void (*)(void)) thunar_window_redirect_menu_tooltips_to_statusbar_recursive, window);
+}
+
+
+
 static gboolean
 thunar_window_button_press_event (GtkWidget      *view,
                                   GdkEventButton *event,
diff --git a/thunar/thunar-window.h b/thunar/thunar-window.h
index 947e08b74..5b595d6f4 100644
--- a/thunar/thunar-window.h
+++ b/thunar/thunar-window.h
@@ -118,6 +118,8 @@ void                      thunar_window_append_menu_item                    (Thu
                                                                              GtkMenuShell        *menu,
                                                                              ThunarWindowAction   action);
 ThunarLauncher*           thunar_window_get_launcher                        (ThunarWindow        *window);
+void                      thunar_window_redirect_menu_tooltips_to_statusbar (ThunarWindow        *window,
+                                                                             GtkMenu             *menu);
 const XfceGtkActionEntry* thunar_window_get_action_entry                    (ThunarWindow        *window,
                                                                              ThunarWindowAction   action);
 G_END_DECLS;
-- 
GitLab