[gimp] app: GimpAction now has a "reason" parameter to explain being disabled.



commit 811d3569533174d18117f197acc4f0136f3de661
Author: Jehan <jehan girinstud io>
Date:   Fri Apr 23 18:49:29 2021 +0200

    app: GimpAction now has a "reason" parameter to explain being disabled.
    
    In some cases, in particular for actions generated from plug-in
    procedure right now, we were displaying the reason of the insensitivity
    (typically right now, only the drawable type is cited). This was done by
    appending the reason to the tooltip, separated by 2 newlines, which
    resulted in extra ugly design, no nice way to style this info directly
    (with pango for instance if the widget display allows it, or on a
    separate info widget in a possible future, or whatnot).
    
    Also it would mean that the action search could match a disabled action
    by mistake if a search word happens to be in the reason message.
    
    This improves the situation with the following changes:
    * gimp_action_set_sensitive() now takes an optional reason string to set
      the reason message.
    * Same for gimp_action_group_set_action_sensitive().
    * gimp_action_get_sensitive() returns an optional reason string.
    * gimp_procedure_get_sensitive()'s tooltip return value now becomes a
      reason (it won't contain anymore the tooltip and the reason
      concatenated, only the reason for separate processing).

 app/actions/brushes-actions.c            |  2 +-
 app/actions/buffers-actions.c            | 22 +++++-----
 app/actions/channels-actions.c           |  2 +-
 app/actions/colormap-actions.c           |  2 +-
 app/actions/dashboard-actions.c          |  2 +-
 app/actions/debug-actions.c              |  2 +-
 app/actions/dockable-actions.c           |  2 +-
 app/actions/documents-actions.c          |  2 +-
 app/actions/drawable-actions.c           |  2 +-
 app/actions/dynamics-actions.c           |  2 +-
 app/actions/edit-actions.c               |  2 +-
 app/actions/error-console-actions.c      |  2 +-
 app/actions/file-actions.c               |  4 +-
 app/actions/filters-actions.c            | 35 +++++++++-------
 app/actions/fonts-actions.c              |  2 +-
 app/actions/gimpgeglprocedure.c          |  4 +-
 app/actions/gradient-editor-actions.c    |  2 +-
 app/actions/gradients-actions.c          |  2 +-
 app/actions/image-actions.c              |  2 +-
 app/actions/images-actions.c             |  2 +-
 app/actions/items-actions.c              |  2 +-
 app/actions/layers-actions.c             |  2 +-
 app/actions/mypaint-brushes-actions.c    |  2 +-
 app/actions/palette-editor-actions.c     |  2 +-
 app/actions/palettes-actions.c           |  2 +-
 app/actions/patterns-actions.c           |  2 +-
 app/actions/plug-in-actions.c            | 28 ++++++-------
 app/actions/quick-mask-actions.c         |  2 +-
 app/actions/select-actions.c             |  2 +-
 app/actions/templates-actions.c          |  2 +-
 app/actions/text-tool-actions.c          |  2 +-
 app/actions/tool-options-actions.c       |  2 +-
 app/actions/tool-preset-editor-actions.c |  2 +-
 app/actions/tool-presets-actions.c       |  2 +-
 app/actions/tools-actions.c              |  2 +-
 app/actions/vectors-actions.c            |  2 +-
 app/actions/view-actions.c               |  2 +-
 app/actions/windows-actions.c            |  6 ++-
 app/dialogs/action-search-dialog.c       |  6 +--
 app/dialogs/file-save-dialog.c           |  4 +-
 app/display/gimpdisplayshell-actions.c   |  4 +-
 app/pdb/gimpprocedure.c                  | 10 ++---
 app/pdb/gimpprocedure.h                  |  4 +-
 app/plug-in/gimppluginprocedure.c        | 21 +++++-----
 app/plug-in/gimppluginprocedure.h        |  2 +-
 app/widgets/gimpaction.c                 | 41 ++++++++++++++++---
 app/widgets/gimpaction.h                 | 23 +++++++----
 app/widgets/gimpactiongroup.c            |  5 ++-
 app/widgets/gimpactiongroup.h            |  3 +-
 app/widgets/gimpactionimpl.c             | 69 ++++++++++++++++++++++++--------
 app/widgets/gimpactionimpl.h             |  1 +
 app/widgets/gimpeditor.c                 |  2 +-
 app/widgets/gimpsearchpopup.c            | 34 +++++++++++-----
 53 files changed, 243 insertions(+), 149 deletions(-)
---
diff --git a/app/actions/brushes-actions.c b/app/actions/brushes-actions.c
index 87daed6edd..03dbf77ac2 100644
--- a/app/actions/brushes-actions.c
+++ b/app/actions/brushes-actions.c
@@ -136,7 +136,7 @@ brushes_actions_update (GimpActionGroup *group,
     }
 
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 
   SET_SENSITIVE ("brushes-edit",                 brush);
   SET_SENSITIVE ("brushes-open-as-image",        file && ! GIMP_IS_BRUSH_GENERATED (brush));
diff --git a/app/actions/buffers-actions.c b/app/actions/buffers-actions.c
index 6fbd2c1e28..42a611b092 100644
--- a/app/actions/buffers-actions.c
+++ b/app/actions/buffers-actions.c
@@ -120,17 +120,17 @@ buffers_actions_update (GimpActionGroup *group,
   if (context)
     buffer = gimp_context_get_buffer (context);
 
-#define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
-
-  SET_SENSITIVE ("buffers-paste",                       buffer);
-  SET_SENSITIVE ("buffers-paste-in-place",              buffer);
-  SET_SENSITIVE ("buffers-paste-into",                  buffer);
-  SET_SENSITIVE ("buffers-paste-into-in-place",         buffer);
-  SET_SENSITIVE ("buffers-paste-as-new-layer",          buffer);
-  SET_SENSITIVE ("buffers-paste-as-new-layer-in-place", buffer);
-  SET_SENSITIVE ("buffers-paste-as-new-image",          buffer);
-  SET_SENSITIVE ("buffers-delete",                      buffer);
+#define SET_SENSITIVE(action,condition,reason) \
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, reason)
+
+  SET_SENSITIVE ("buffers-paste",                       buffer, _("No selected buffer"));
+  SET_SENSITIVE ("buffers-paste-in-place",              buffer, _("No selected buffer"));
+  SET_SENSITIVE ("buffers-paste-into",                  buffer, _("No selected buffer"));
+  SET_SENSITIVE ("buffers-paste-into-in-place",         buffer, _("No selected buffer"));
+  SET_SENSITIVE ("buffers-paste-as-new-layer",          buffer, _("No selected buffer"));
+  SET_SENSITIVE ("buffers-paste-as-new-layer-in-place", buffer, _("No selected buffer"));
+  SET_SENSITIVE ("buffers-paste-as-new-image",          buffer, _("No selected buffer"));
+  SET_SENSITIVE ("buffers-delete",                      buffer, _("No selected buffer"));
 
 #undef SET_SENSITIVE
 }
diff --git a/app/actions/channels-actions.c b/app/actions/channels-actions.c
index 5a8ac57d5d..081cddb31f 100644
--- a/app/actions/channels-actions.c
+++ b/app/actions/channels-actions.c
@@ -320,7 +320,7 @@ channels_actions_update (GimpActionGroup *group,
     }
 
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 
   SET_SENSITIVE ("channels-edit-attributes", !fs && n_channels == 1);
 
diff --git a/app/actions/colormap-actions.c b/app/actions/colormap-actions.c
index 1c5d59fba5..292bfb2bca 100644
--- a/app/actions/colormap-actions.c
+++ b/app/actions/colormap-actions.c
@@ -144,7 +144,7 @@ colormap_actions_update (GimpActionGroup *group,
     }
 
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 #define SET_COLOR(action,color) \
         gimp_action_group_set_action_color (group, action, color, FALSE);
 
diff --git a/app/actions/dashboard-actions.c b/app/actions/dashboard-actions.c
index e471307d66..767cf77321 100644
--- a/app/actions/dashboard-actions.c
+++ b/app/actions/dashboard-actions.c
@@ -176,7 +176,7 @@ dashboard_actions_update (GimpActionGroup *group,
   recording = gimp_dashboard_log_is_recording (dashboard);
 
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 #define SET_ACTIVE(action,condition) \
         gimp_action_group_set_action_active (group, action, (condition) != 0)
 
diff --git a/app/actions/debug-actions.c b/app/actions/debug-actions.c
index 22ca38b15e..c2a6931a69 100644
--- a/app/actions/debug-actions.c
+++ b/app/actions/debug-actions.c
@@ -104,7 +104,7 @@ debug_actions_update (GimpActionGroup *group,
                       gpointer         data)
 {
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 
   SET_SENSITIVE ("debug-show-image-graph", gegl_has_operation ("gegl:introspect"));
 
diff --git a/app/actions/dockable-actions.c b/app/actions/dockable-actions.c
index 3f7e2f645b..0adcb63021 100644
--- a/app/actions/dockable-actions.c
+++ b/app/actions/dockable-actions.c
@@ -278,7 +278,7 @@ dockable_actions_update (GimpActionGroup *group,
 #define SET_VISIBLE(action,active) \
         gimp_action_group_set_action_visible (group, action, (active) != 0)
 #define SET_SENSITIVE(action,sensitive) \
-        gimp_action_group_set_action_sensitive (group, action, (sensitive) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (sensitive) != 0, NULL)
 
 
   locked = gimp_dockable_get_locked (dockable);
diff --git a/app/actions/documents-actions.c b/app/actions/documents-actions.c
index 80c0371139..b5f0511af9 100644
--- a/app/actions/documents-actions.c
+++ b/app/actions/documents-actions.c
@@ -126,7 +126,7 @@ documents_actions_update (GimpActionGroup *group,
     imagefile = gimp_context_get_imagefile (context);
 
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 
   SET_SENSITIVE ("documents-open",                 imagefile);
   SET_SENSITIVE ("documents-raise-or-open",        imagefile);
diff --git a/app/actions/drawable-actions.c b/app/actions/drawable-actions.c
index 99e1d222cc..4148e75afd 100644
--- a/app/actions/drawable-actions.c
+++ b/app/actions/drawable-actions.c
@@ -215,7 +215,7 @@ drawable_actions_update (GimpActionGroup *group,
     }
 
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 #define SET_ACTIVE(action,condition) \
         gimp_action_group_set_action_active (group, action, (condition) != 0)
 
diff --git a/app/actions/dynamics-actions.c b/app/actions/dynamics-actions.c
index ce6b005f8a..58aca154da 100644
--- a/app/actions/dynamics-actions.c
+++ b/app/actions/dynamics-actions.c
@@ -125,7 +125,7 @@ dynamics_actions_update (GimpActionGroup *group,
     }
 
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 
   SET_SENSITIVE ("dynamics-edit",                 dynamics);
   SET_SENSITIVE ("dynamics-duplicate",            dynamics && gimp_data_is_duplicatable (data));
diff --git a/app/actions/edit-actions.c b/app/actions/edit-actions.c
index 59ee225fc0..fa3269bfca 100644
--- a/app/actions/edit-actions.c
+++ b/app/actions/edit-actions.c
@@ -348,7 +348,7 @@ edit_actions_update (GimpActionGroup *group,
 #define SET_LABEL(action,label) \
         gimp_action_group_set_action_label (group, action, (label))
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 
   SET_LABEL ("edit-undo", undo_name ? undo_name : _("_Undo"));
   SET_LABEL ("edit-redo", redo_name ? redo_name : _("_Redo"));
diff --git a/app/actions/error-console-actions.c b/app/actions/error-console-actions.c
index e82b55a4c5..658cd37c66 100644
--- a/app/actions/error-console-actions.c
+++ b/app/actions/error-console-actions.c
@@ -127,7 +127,7 @@ error_console_actions_update (GimpActionGroup *group,
 #define SET_ACTIVE(action,condition)                                           \
         gimp_action_group_set_action_active (group, action, (condition) != 0)
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 
   SET_SENSITIVE ("error-console-clear",          TRUE);
   SET_SENSITIVE ("error-console-select-all",     TRUE);
diff --git a/app/actions/file-actions.c b/app/actions/file-actions.c
index 17b16c0a8f..f9392196d8 100644
--- a/app/actions/file-actions.c
+++ b/app/actions/file-actions.c
@@ -284,7 +284,7 @@ file_actions_update (GimpActionGroup *group,
 #define SET_VISIBLE(action,condition) \
         gimp_action_group_set_action_visible (group, action, (condition) != 0)
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 
   SET_SENSITIVE ("file-save",                 drawables);
   SET_SENSITIVE ("file-save-as",              drawables);
@@ -434,7 +434,7 @@ file_actions_close_all_update (GimpContainer   *images,
         sensitive = FALSE;
     }
 
-  gimp_action_group_set_action_sensitive (group, "file-close-all", sensitive);
+  gimp_action_group_set_action_sensitive (group, "file-close-all", sensitive, NULL);
 }
 
 static gchar *
diff --git a/app/actions/filters-actions.c b/app/actions/filters-actions.c
index bc83a543ac..f98085987d 100644
--- a/app/actions/filters-actions.c
+++ b/app/actions/filters-actions.c
@@ -895,7 +895,7 @@ filters_actions_update (GimpActionGroup *group,
    }
 
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 
   SET_SENSITIVE ("filters-alien-map",               writable);
   SET_SENSITIVE ("filters-antialias",               writable);
@@ -1029,19 +1029,20 @@ filters_actions_update (GimpActionGroup *group,
 #undef SET_SENSITIVE
 
   {
-    GimpProcedure *proc = gimp_filter_history_nth (group->gimp, 0);
+    GimpProcedure *proc   = gimp_filter_history_nth (group->gimp, 0);
+    const gchar   *reason = NULL;
     gint           i;
 
     if (proc &&
-        gimp_procedure_get_sensitive (proc, GIMP_OBJECT (image), NULL))
+        gimp_procedure_get_sensitive (proc, GIMP_OBJECT (image), &reason))
       {
-        gimp_action_group_set_action_sensitive (group, "filters-repeat", TRUE);
-        gimp_action_group_set_action_sensitive (group, "filters-reshow", TRUE);
+        gimp_action_group_set_action_sensitive (group, "filters-repeat", TRUE, NULL);
+        gimp_action_group_set_action_sensitive (group, "filters-reshow", TRUE, NULL);
       }
     else
       {
-        gimp_action_group_set_action_sensitive (group, "filters-repeat", FALSE);
-        gimp_action_group_set_action_sensitive (group, "filters-reshow", FALSE);
+        gimp_action_group_set_action_sensitive (group, "filters-repeat", FALSE, reason);
+        gimp_action_group_set_action_sensitive (group, "filters-reshow", FALSE, reason);
      }
 
     for (i = 0; i < gimp_filter_history_length (group->gimp); i++)
@@ -1051,10 +1052,11 @@ filters_actions_update (GimpActionGroup *group,
 
         proc = gimp_filter_history_nth (group->gimp, i);
 
+        reason = NULL;
         sensitive = gimp_procedure_get_sensitive (proc, GIMP_OBJECT (image),
-                                                  NULL);
+                                                  &reason);
 
-        gimp_action_group_set_action_sensitive (group, name, sensitive);
+        gimp_action_group_set_action_sensitive (group, name, sensitive, reason);
 
         g_free (name);
       }
@@ -1119,6 +1121,7 @@ filters_actions_history_changed (Gimp            *gimp,
       const gchar *label;
       gchar       *repeat;
       gchar       *reshow;
+      const gchar *reason    = NULL;
       gboolean     sensitive = FALSE;
 
       label = gimp_procedure_get_label (proc);
@@ -1152,12 +1155,12 @@ filters_actions_history_changed (Gimp            *gimp,
         }
 
       if (actual_action)
-        sensitive = gimp_action_get_sensitive (actual_action);
+        sensitive = gimp_action_get_sensitive (actual_action, &reason);
 
       gimp_action_group_set_action_sensitive (group, "filters-repeat",
-                                              sensitive);
+                                              sensitive, reason);
       gimp_action_group_set_action_sensitive (group, "filters-reshow",
-                                              sensitive);
+                                              sensitive, reason);
    }
   else
     {
@@ -1166,8 +1169,10 @@ filters_actions_history_changed (Gimp            *gimp,
       gimp_action_group_set_action_label (group, "filters-reshow",
                                           _("Re-Show Last"));
 
-      gimp_action_group_set_action_sensitive (group, "filters-repeat", FALSE);
-      gimp_action_group_set_action_sensitive (group, "filters-reshow", FALSE);
+      gimp_action_group_set_action_sensitive (group, "filters-repeat",
+                                              FALSE, _("No last used filters"));
+      gimp_action_group_set_action_sensitive (group, "filters-reshow",
+                                              FALSE, _("No last used filters"));
     }
 
   for (i = 0; i < gimp_filter_history_length (gimp); i++)
@@ -1201,7 +1206,7 @@ filters_actions_history_changed (Gimp            *gimp,
         }
 
       if (actual_action)
-        sensitive = gimp_action_get_sensitive (actual_action);
+        sensitive = gimp_action_get_sensitive (actual_action, NULL);
 
       g_object_set (action,
                     "visible",   TRUE,
diff --git a/app/actions/fonts-actions.c b/app/actions/fonts-actions.c
index 5191dcc585..8bfca2ef42 100644
--- a/app/actions/fonts-actions.c
+++ b/app/actions/fonts-actions.c
@@ -65,7 +65,7 @@ fonts_actions_update (GimpActionGroup *group,
                       gpointer         data)
 {
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 
   SET_SENSITIVE ("fonts-refresh", TRUE);
 
diff --git a/app/actions/gimpgeglprocedure.c b/app/actions/gimpgeglprocedure.c
index b186fab59c..25a6159fce 100644
--- a/app/actions/gimpgeglprocedure.c
+++ b/app/actions/gimpgeglprocedure.c
@@ -66,7 +66,7 @@ static gchar  * gimp_gegl_procedure_get_description     (GimpViewable   *viewabl
 static const gchar * gimp_gegl_procedure_get_menu_label (GimpProcedure  *procedure);
 static gboolean      gimp_gegl_procedure_get_sensitive  (GimpProcedure  *procedure,
                                                          GimpObject     *object,
-                                                         const gchar   **tooltip);
+                                                         const gchar   **reason);
 static GimpValueArray * gimp_gegl_procedure_execute     (GimpProcedure  *procedure,
                                                          Gimp           *gimp,
                                                          GimpContext    *context,
@@ -166,7 +166,7 @@ gimp_gegl_procedure_get_menu_label (GimpProcedure *procedure)
 static gboolean
 gimp_gegl_procedure_get_sensitive (GimpProcedure  *procedure,
                                    GimpObject     *object,
-                                   const gchar   **tooltip)
+                                   const gchar   **reason)
 {
   GimpImage *image     = GIMP_IMAGE (object);
   GList     *drawables = NULL;
diff --git a/app/actions/gradient-editor-actions.c b/app/actions/gradient-editor-actions.c
index ca730e6ec8..ec0cdb56e7 100644
--- a/app/actions/gradient-editor-actions.c
+++ b/app/actions/gradient-editor-actions.c
@@ -578,7 +578,7 @@ gradient_editor_actions_update (GimpActionGroup *group,
 #define SET_LABEL(action,label) \
         gimp_action_group_set_action_label (group, action, (label))
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 #define SET_VISIBLE(action,condition) \
         gimp_action_group_set_action_visible (group, action, (condition) != 0)
 
diff --git a/app/actions/gradients-actions.c b/app/actions/gradients-actions.c
index f4b22ef8bb..6d1197deab 100644
--- a/app/actions/gradients-actions.c
+++ b/app/actions/gradients-actions.c
@@ -137,7 +137,7 @@ gradients_actions_update (GimpActionGroup *group,
     }
 
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 
   SET_SENSITIVE ("gradients-edit",                 gradient);
   SET_SENSITIVE ("gradients-duplicate",            gradient);
diff --git a/app/actions/image-actions.c b/app/actions/image-actions.c
index 89ab63e982..ce42238d3c 100644
--- a/app/actions/image-actions.c
+++ b/app/actions/image-actions.c
@@ -370,7 +370,7 @@ image_actions_update (GimpActionGroup *group,
 #define SET_LABEL(action,label) \
         gimp_action_group_set_action_label (group, action, (label))
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 #define SET_ACTIVE(action,condition) \
         gimp_action_group_set_action_active (group, action, (condition) != 0)
 #define SET_VISIBLE(action,condition) \
diff --git a/app/actions/images-actions.c b/app/actions/images-actions.c
index 74745c189b..2a99c39457 100644
--- a/app/actions/images-actions.c
+++ b/app/actions/images-actions.c
@@ -88,7 +88,7 @@ images_actions_update (GimpActionGroup *group,
     }
 
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 
   SET_SENSITIVE ("images-raise-views", image);
   SET_SENSITIVE ("images-new-view",    image);
diff --git a/app/actions/items-actions.c b/app/actions/items-actions.c
index bbfd1152d5..8dc398f346 100644
--- a/app/actions/items-actions.c
+++ b/app/actions/items-actions.c
@@ -121,7 +121,7 @@ items_actions_update (GimpActionGroup *group,
     }
 
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 #define SET_ACTIVE(action,condition) \
         gimp_action_group_set_action_active (group, action, (condition) != 0)
 #define SET_COLOR(action,color) \
diff --git a/app/actions/layers-actions.c b/app/actions/layers-actions.c
index a32a1a1789..898477338f 100644
--- a/app/actions/layers-actions.c
+++ b/app/actions/layers-actions.c
@@ -994,7 +994,7 @@ layers_actions_update (GimpActionGroup *group,
 #define SET_VISIBLE(action,condition) \
         gimp_action_group_set_action_visible (group, action, (condition) != 0)
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 #define SET_ACTIVE(action,condition) \
         gimp_action_group_set_action_active (group, action, (condition) != 0)
 #define SET_LABEL(action,label) \
diff --git a/app/actions/mypaint-brushes-actions.c b/app/actions/mypaint-brushes-actions.c
index 0f39df38ed..ae83277a94 100644
--- a/app/actions/mypaint-brushes-actions.c
+++ b/app/actions/mypaint-brushes-actions.c
@@ -130,7 +130,7 @@ mypaint_brushes_actions_update (GimpActionGroup *group,
     }
 
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 
   SET_SENSITIVE ("mypaint-brushes-edit",                 brush && FALSE);
   SET_SENSITIVE ("mypaint-brushes-duplicate",            brush && gimp_data_is_duplicatable (data));
diff --git a/app/actions/palette-editor-actions.c b/app/actions/palette-editor-actions.c
index 1540126efe..ec0c3bdb32 100644
--- a/app/actions/palette-editor-actions.c
+++ b/app/actions/palette-editor-actions.c
@@ -156,7 +156,7 @@ palette_editor_actions_update (GimpActionGroup *group,
   edit_active = gimp_data_editor_get_edit_active (data_editor);
 
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 #define SET_ACTIVE(action,condition) \
         gimp_action_group_set_action_active (group, action, (condition) != 0)
 #define SET_COLOR(action,color) \
diff --git a/app/actions/palettes-actions.c b/app/actions/palettes-actions.c
index 80dab41943..1bff123f0a 100644
--- a/app/actions/palettes-actions.c
+++ b/app/actions/palettes-actions.c
@@ -146,7 +146,7 @@ palettes_actions_update (GimpActionGroup *group,
     }
 
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 
   SET_SENSITIVE ("palettes-edit",                 palette);
   SET_SENSITIVE ("palettes-duplicate",            palette && gimp_data_is_duplicatable (data));
diff --git a/app/actions/patterns-actions.c b/app/actions/patterns-actions.c
index f563ef6c98..9a8acb7fce 100644
--- a/app/actions/patterns-actions.c
+++ b/app/actions/patterns-actions.c
@@ -136,7 +136,7 @@ patterns_actions_update (GimpActionGroup *group,
     }
 
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 
   SET_SENSITIVE ("patterns-edit",                 pattern && FALSE);
   SET_SENSITIVE ("patterns-open-as-image",        file);
diff --git a/app/actions/plug-in-actions.c b/app/actions/plug-in-actions.c
index dff6df4185..fc0893f896 100644
--- a/app/actions/plug-in-actions.c
+++ b/app/actions/plug-in-actions.c
@@ -144,12 +144,8 @@ plug_in_actions_update (GimpActionGroup *group,
 {
   GimpImage         *image    = action_data_get_image (data);
   GimpPlugInManager *manager  = group->gimp->plug_in_manager;
-  GimpDrawable      *drawable = NULL;
   GSList            *list;
 
-  if (image)
-    drawable = gimp_image_get_active_drawable (image);
-
   for (list = manager->plug_in_procedures; list; list = g_slist_next (list))
     {
       GimpPlugInProcedure *proc = list->data;
@@ -161,21 +157,21 @@ plug_in_actions_update (GimpActionGroup *group,
           GimpProcedure *procedure = GIMP_PROCEDURE (proc);
           gboolean       sensitive;
           const gchar   *tooltip;
+          const gchar   *reason;
 
           sensitive = gimp_procedure_get_sensitive (procedure,
                                                     GIMP_OBJECT (image),
-                                                    &tooltip);
+                                                    &reason);
 
           gimp_action_group_set_action_sensitive (group,
                                                   gimp_object_get_name (proc),
-                                                  sensitive);
-
-          if (sensitive || ! drawable || ! tooltip)
-            tooltip = gimp_procedure_get_blurb (procedure);
+                                                  sensitive, reason);
 
-          gimp_action_group_set_action_tooltip (group,
-                                                gimp_object_get_name (proc),
-                                                tooltip);
+          tooltip = gimp_procedure_get_blurb (procedure);
+          if (tooltip)
+            gimp_action_group_set_action_tooltip (group,
+                                                  gimp_object_get_name (proc),
+                                                  tooltip);
         }
     }
 }
@@ -332,16 +328,18 @@ plug_in_actions_add_proc (GimpActionGroup     *group,
       GimpImage    *image    = gimp_context_get_image (context);
       gboolean      sensitive;
       const gchar  *tooltip;
+      const gchar  *reason;
 
       sensitive = gimp_procedure_get_sensitive (GIMP_PROCEDURE (proc),
                                                 GIMP_OBJECT (image),
-                                                &tooltip);
+                                                &reason);
 
       gimp_action_group_set_action_sensitive (group,
                                               gimp_object_get_name (proc),
-                                              sensitive);
+                                              sensitive, reason);
 
-      if (! sensitive && tooltip)
+      tooltip = gimp_procedure_get_blurb (GIMP_PROCEDURE (proc));
+      if (tooltip)
         gimp_action_group_set_action_tooltip (group,
                                               gimp_object_get_name (proc),
                                               tooltip);
diff --git a/app/actions/quick-mask-actions.c b/app/actions/quick-mask-actions.c
index 542d0f4cfc..d57b02715d 100644
--- a/app/actions/quick-mask-actions.c
+++ b/app/actions/quick-mask-actions.c
@@ -110,7 +110,7 @@ quick_mask_actions_update (GimpActionGroup *group,
     }
 
 #define SET_SENSITIVE(action,sensitive) \
-        gimp_action_group_set_action_sensitive (group, action, (sensitive) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (sensitive) != 0, NULL)
 #define SET_ACTIVE(action,active) \
         gimp_action_group_set_action_active (group, action, (active) != 0)
 #define SET_COLOR(action,color) \
diff --git a/app/actions/select-actions.c b/app/actions/select-actions.c
index 67c64ad6c5..cfc166e1c0 100644
--- a/app/actions/select-actions.c
+++ b/app/actions/select-actions.c
@@ -193,7 +193,7 @@ select_actions_update (GimpActionGroup *group,
     }
 
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 
   SET_SENSITIVE ("select-all",    image);
   SET_SENSITIVE ("select-none",   image && sel);
diff --git a/app/actions/templates-actions.c b/app/actions/templates-actions.c
index e3a59adafb..03369716bc 100644
--- a/app/actions/templates-actions.c
+++ b/app/actions/templates-actions.c
@@ -93,7 +93,7 @@ templates_actions_update (GimpActionGroup *group,
     template = gimp_context_get_template (context);
 
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 
   SET_SENSITIVE ("templates-create-image", template);
   SET_SENSITIVE ("templates-new",          context);
diff --git a/app/actions/text-tool-actions.c b/app/actions/text-tool-actions.c
index 1c7e6798d8..8cfb548a44 100644
--- a/app/actions/text-tool-actions.c
+++ b/app/actions/text-tool-actions.c
@@ -189,7 +189,7 @@ text_tool_actions_update (GimpActionGroup *group,
 #define SET_VISIBLE(action,condition) \
         gimp_action_group_set_action_visible (group, action, (condition) != 0)
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 #define SET_ACTIVE(action,condition) \
         gimp_action_group_set_action_active (group, action, (condition) != 0)
 
diff --git a/app/actions/tool-options-actions.c b/app/actions/tool-options-actions.c
index 10c59eb2c8..51aa8b555e 100644
--- a/app/actions/tool-options-actions.c
+++ b/app/actions/tool-options-actions.c
@@ -98,7 +98,7 @@ static const GimpActionEntry tool_options_actions[] =
 #define SET_VISIBLE(action,condition) \
         gimp_action_group_set_action_visible (group, action, (condition) != 0)
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 #define SET_HIDE_EMPTY(action,condition) \
         gimp_action_group_set_action_hide_empty (group, action, (condition) != 0)
 
diff --git a/app/actions/tool-preset-editor-actions.c b/app/actions/tool-preset-editor-actions.c
index 8b22e6ff26..4c049dae16 100644
--- a/app/actions/tool-preset-editor-actions.c
+++ b/app/actions/tool-preset-editor-actions.c
@@ -92,7 +92,7 @@ tool_preset_editor_actions_update (GimpActionGroup *group,
   edit_active = gimp_data_editor_get_edit_active (data_editor);
 
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 #define SET_ACTIVE(action,condition) \
         gimp_action_group_set_action_active (group, action, (condition) != 0)
 
diff --git a/app/actions/tool-presets-actions.c b/app/actions/tool-presets-actions.c
index 36baabdbe8..71d9287361 100644
--- a/app/actions/tool-presets-actions.c
+++ b/app/actions/tool-presets-actions.c
@@ -141,7 +141,7 @@ tool_presets_actions_update (GimpActionGroup *group,
     }
 
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 
   SET_SENSITIVE ("tool-presets-edit",                 tool_preset);
   SET_SENSITIVE ("tool-presets-duplicate",            tool_preset && gimp_data_is_duplicatable (data));
diff --git a/app/actions/tools-actions.c b/app/actions/tools-actions.c
index 0625b875d6..c3e320d9fc 100644
--- a/app/actions/tools-actions.c
+++ b/app/actions/tools-actions.c
@@ -800,7 +800,7 @@ tools_actions_update (GimpActionGroup *group,
   GimpImage *image = action_data_get_image (data);
 
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 
   SET_SENSITIVE ("tools-gegl", image);
 
diff --git a/app/actions/vectors-actions.c b/app/actions/vectors-actions.c
index f7ad91bd72..f0ebe5e63b 100644
--- a/app/actions/vectors-actions.c
+++ b/app/actions/vectors-actions.c
@@ -410,7 +410,7 @@ vectors_actions_update (GimpActionGroup *group,
     }
 
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 #define SET_ACTIVE(action,condition) \
         gimp_action_group_set_action_active (group, action, (condition) != 0)
 
diff --git a/app/actions/view-actions.c b/app/actions/view-actions.c
index bbcec89ec3..cca55e64b5 100644
--- a/app/actions/view-actions.c
+++ b/app/actions/view-actions.c
@@ -922,7 +922,7 @@ view_actions_update (GimpActionGroup *group,
 #define SET_ACTIVE(action,condition) \
         gimp_action_group_set_action_active (group, action, (condition) != 0)
 #define SET_SENSITIVE(action,condition) \
-        gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
+        gimp_action_group_set_action_sensitive (group, action, (condition) != 0, NULL)
 #define SET_COLOR(action,color) \
         gimp_action_group_set_action_color (group, action, color, FALSE)
 
diff --git a/app/actions/windows-actions.c b/app/actions/windows-actions.c
index 8beb5b837e..1da0efd0b0 100644
--- a/app/actions/windows-actions.c
+++ b/app/actions/windows-actions.c
@@ -282,8 +282,10 @@ windows_actions_update (GimpActionGroup *group,
     }
 
   gimp_action_group_set_action_active (group, action, TRUE);
-  gimp_action_group_set_action_sensitive (group, "windows-tab-position", config->single_window_mode);
-  gimp_action_group_set_action_sensitive (group, "windows-show-tabs", config->single_window_mode);
+  gimp_action_group_set_action_sensitive (group, "windows-tab-position", config->single_window_mode,
+                                          _("Single-window mode disabled"));
+  gimp_action_group_set_action_sensitive (group, "windows-show-tabs", config->single_window_mode,
+                                          _("Single-window mode disabled"));
 
 #undef SET_ACTIVE
 }
diff --git a/app/dialogs/action-search-dialog.c b/app/dialogs/action-search-dialog.c
index 79b4f5e96d..cfe7208870 100644
--- a/app/dialogs/action-search-dialog.c
+++ b/app/dialogs/action-search-dialog.c
@@ -99,7 +99,7 @@ action_search_history_and_actions (GimpSearchPopup *popup,
   /* 0. Top result: matching action in run history. */
   for (list = history_actions; list; list = g_list_next (list))
     gimp_search_popup_add_result (popup, list->data,
-                                  gimp_action_is_sensitive (list->data) ? 0 : ACTION_SECTION_INACTIVE);
+                                  gimp_action_is_sensitive (list->data, NULL) ? 0 : ACTION_SECTION_INACTIVE);
 
   /* 1. Then other matching actions. */
   for (list = gimp_ui_manager_get_action_groups (manager);
@@ -219,7 +219,7 @@ action_search_match_keyword (GimpAction  *action,
        * matches.
        */
       if (section)
-        *section = gimp_action_is_sensitive (action) ? 0 : ACTION_SECTION_INACTIVE;
+        *section = gimp_action_is_sensitive (action, NULL) ? 0 : ACTION_SECTION_INACTIVE;
 
       return TRUE;
     }
@@ -389,7 +389,7 @@ one_tooltip_matched:
   g_strfreev (label_tokens);
   g_strfreev (label_alternates);
 
-  if (matched && section && ! gimp_action_is_sensitive (action))
+  if (matched && section && ! gimp_action_is_sensitive (action, NULL))
     *section += ACTION_SECTION_INACTIVE;
 
   return matched;
diff --git a/app/dialogs/file-save-dialog.c b/app/dialogs/file-save-dialog.c
index 5a51c1a873..2bb82bd1bd 100644
--- a/app/dialogs/file-save-dialog.c
+++ b/app/dialogs/file-save-dialog.c
@@ -810,7 +810,7 @@ file_save_dialog_save_image (GimpProgress        *progress,
        list;
        list = g_list_next (list))
     {
-      gimp_action_group_set_action_sensitive (list->data, "file-quit", FALSE);
+      gimp_action_group_set_action_sensitive (list->data, "file-quit", FALSE, NULL);
     }
 
   gimp_image_set_xcf_compression (image, xcf_compression);
@@ -848,7 +848,7 @@ file_save_dialog_save_image (GimpProgress        *progress,
        list;
        list = g_list_next (list))
     {
-      gimp_action_group_set_action_sensitive (list->data, "file-quit", TRUE);
+      gimp_action_group_set_action_sensitive (list->data, "file-quit", TRUE, NULL);
     }
 
   return success;
diff --git a/app/display/gimpdisplayshell-actions.c b/app/display/gimpdisplayshell-actions.c
index fa0b5efb52..e6c87eed90 100644
--- a/app/display/gimpdisplayshell-actions.c
+++ b/app/display/gimpdisplayshell-actions.c
@@ -55,7 +55,7 @@ gimp_display_shell_set_action_sensitive (GimpDisplayShell *shell,
       action_group = gimp_ui_manager_get_action_group (manager, "view");
 
       if (action_group)
-        gimp_action_group_set_action_sensitive (action_group, action, sensitive);
+        gimp_action_group_set_action_sensitive (action_group, action, sensitive, NULL);
     }
 
   context = gimp_get_user_context (shell->display->gimp);
@@ -68,7 +68,7 @@ gimp_display_shell_set_action_sensitive (GimpDisplayShell *shell,
                                                        "view");
 
       if (action_group)
-        gimp_action_group_set_action_sensitive (action_group, action, sensitive);
+        gimp_action_group_set_action_sensitive (action_group, action, sensitive, NULL);
     }
 }
 
diff --git a/app/pdb/gimpprocedure.c b/app/pdb/gimpprocedure.c
index 535eda83cf..ed421af2f2 100644
--- a/app/pdb/gimpprocedure.c
+++ b/app/pdb/gimpprocedure.c
@@ -450,9 +450,9 @@ gimp_procedure_get_help_id (GimpProcedure *procedure)
 gboolean
 gimp_procedure_get_sensitive (GimpProcedure  *procedure,
                               GimpObject     *object,
-                              const gchar   **tooltip)
+                              const gchar   **reason)
 {
-  const gchar *my_tooltip = NULL;
+  const gchar *my_reason  = NULL;
   gboolean     sensitive;
 
   g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), FALSE);
@@ -460,10 +460,10 @@ gimp_procedure_get_sensitive (GimpProcedure  *procedure,
 
   sensitive = GIMP_PROCEDURE_GET_CLASS (procedure)->get_sensitive (procedure,
                                                                    object,
-                                                                   &my_tooltip);
+                                                                   &my_reason);
 
-  if (tooltip)
-    *tooltip = my_tooltip;
+  if (reason)
+    *reason = my_reason;
 
   return sensitive;
 }
diff --git a/app/pdb/gimpprocedure.h b/app/pdb/gimpprocedure.h
index 9b30d92e03..3be2e69682 100644
--- a/app/pdb/gimpprocedure.h
+++ b/app/pdb/gimpprocedure.h
@@ -79,7 +79,7 @@ struct _GimpProcedureClass
   const gchar    * (* get_help_id)    (GimpProcedure   *procedure);
   gboolean         (* get_sensitive)  (GimpProcedure   *procedure,
                                        GimpObject      *object,
-                                       const gchar    **tooltip);
+                                       const gchar    **reason);
 
   GimpValueArray * (* execute)        (GimpProcedure   *procedure,
                                        Gimp            *gimp,
@@ -137,7 +137,7 @@ const gchar    * gimp_procedure_get_help           (GimpProcedure    *procedure)
 const gchar    * gimp_procedure_get_help_id        (GimpProcedure    *procedure);
 gboolean         gimp_procedure_get_sensitive      (GimpProcedure    *procedure,
                                                     GimpObject       *object,
-                                                    const gchar     **tooltip);
+                                                    const gchar     **reason);
 
 void             gimp_procedure_add_argument       (GimpProcedure    *procedure,
                                                     GParamSpec       *pspec);
diff --git a/app/plug-in/gimppluginprocedure.c b/app/plug-in/gimppluginprocedure.c
index 102cc58c18..41c77fff4d 100644
--- a/app/plug-in/gimppluginprocedure.c
+++ b/app/plug-in/gimppluginprocedure.c
@@ -71,7 +71,7 @@ static const gchar * gimp_plug_in_procedure_get_blurb  (GimpProcedure  *procedur
 static const gchar * gimp_plug_in_procedure_get_help_id(GimpProcedure  *procedure);
 static gboolean   gimp_plug_in_procedure_get_sensitive (GimpProcedure  *procedure,
                                                         GimpObject     *object,
-                                                        const gchar  **tooltip);
+                                                        const gchar  **reason);
 static GimpValueArray * gimp_plug_in_procedure_execute (GimpProcedure  *procedure,
                                                         Gimp           *gimp,
                                                         GimpContext    *context,
@@ -159,7 +159,7 @@ gimp_plug_in_procedure_finalize (GObject *object)
 
   g_free (proc->icon_data);
   g_free (proc->image_types);
-  g_free (proc->image_types_tooltip);
+  g_free (proc->insensitive_reason);
 
   g_free (proc->extensions);
   g_free (proc->prefixes);
@@ -301,7 +301,7 @@ gimp_plug_in_procedure_get_help_id (GimpProcedure *procedure)
 static gboolean
 gimp_plug_in_procedure_get_sensitive (GimpProcedure  *procedure,
                                       GimpObject     *object,
-                                      const gchar   **tooltip)
+                                      const gchar   **reason)
 {
   GimpPlugInProcedure *proc       = GIMP_PLUG_IN_PROCEDURE (procedure);
   GimpImage           *image;
@@ -362,7 +362,7 @@ gimp_plug_in_procedure_get_sensitive (GimpProcedure  *procedure,
   g_list_free (drawables);
 
   if (! sensitive)
-    *tooltip = proc->image_types_tooltip;
+    *reason = proc->insensitive_reason;
 
   return sensitive ? TRUE : FALSE;
 }
@@ -1019,7 +1019,7 @@ gimp_plug_in_procedure_set_image_types (GimpPlugInProcedure *proc,
   proc->image_types_val = image_types_parse (gimp_object_get_name (proc),
                                              proc->image_types);
 
-  g_clear_pointer (&proc->image_types_tooltip, g_free);
+  g_clear_pointer (&proc->insensitive_reason, g_free);
 
   if (proc->image_types_val &
       (GIMP_PLUG_IN_RGB_IMAGE | GIMP_PLUG_IN_RGBA_IMAGE))
@@ -1082,12 +1082,9 @@ gimp_plug_in_procedure_set_image_types (GimpPlugInProcedure *proc,
 
       types = g_list_reverse (types);
 
-      string = g_string_new (gimp_procedure_get_blurb (GIMP_PROCEDURE (proc)));
-
-      g_string_append (string, "\n\n");
-      g_string_append (string, _("This plug-in only works on the "
-                                 "following layer types:"));
-      g_string_append (string, "\n");
+      string = g_string_new (_("This plug-in only works on the "
+                               "following layer types:"));
+      g_string_append (string, " ");
 
       for (list = types; list; list = g_list_next (list))
         {
@@ -1101,7 +1098,7 @@ gimp_plug_in_procedure_set_image_types (GimpPlugInProcedure *proc,
 
       g_list_free (types);
 
-      proc->image_types_tooltip = g_string_free (string, FALSE);
+      proc->insensitive_reason = g_string_free (string, FALSE);
     }
 }
 
diff --git a/app/plug-in/gimppluginprocedure.h b/app/plug-in/gimppluginprocedure.h
index b9a924726b..88e90a4e90 100644
--- a/app/plug-in/gimppluginprocedure.h
+++ b/app/plug-in/gimppluginprocedure.h
@@ -50,7 +50,7 @@ struct _GimpPlugInProcedure
   guint8              *icon_data;
   gchar               *image_types;
   GimpPlugInImageType  image_types_val;
-  gchar               *image_types_tooltip;
+  gchar               *insensitive_reason;
   gint                 sensitivity_mask;
   gint64               mtime;
   gboolean             installed_during_init;
diff --git a/app/widgets/gimpaction.c b/app/widgets/gimpaction.c
index 80e2a82fab..e3954b19be 100644
--- a/app/widgets/gimpaction.c
+++ b/app/widgets/gimpaction.c
@@ -228,22 +228,51 @@ gimp_action_is_visible (GimpAction *action)
 }
 
 void
-gimp_action_set_sensitive (GimpAction *action,
-                           gboolean    sensitive)
+gimp_action_set_sensitive (GimpAction  *action,
+                           gboolean     sensitive,
+                           const gchar *reason)
 {
   gtk_action_set_sensitive ((GtkAction *) action, sensitive);
+
+  if (GIMP_ACTION_GET_INTERFACE (action)->set_disable_reason)
+    GIMP_ACTION_GET_INTERFACE (action)->set_disable_reason (action,
+                                                            ! sensitive ? reason : NULL);
 }
 
 gboolean
-gimp_action_get_sensitive (GimpAction *action)
+gimp_action_get_sensitive (GimpAction   *action,
+                           const gchar **reason)
 {
-  return gtk_action_get_sensitive ((GtkAction *) action);
+  gboolean sensitive;
+
+  sensitive = gtk_action_get_sensitive ((GtkAction *) action);
+
+  if (reason)
+    {
+      *reason = NULL;
+      if (! sensitive && GIMP_ACTION_GET_INTERFACE (action)->get_disable_reason)
+        *reason = GIMP_ACTION_GET_INTERFACE (action)->get_disable_reason (action);
+    }
+
+  return sensitive;
 }
 
 gboolean
-gimp_action_is_sensitive (GimpAction *action)
+gimp_action_is_sensitive (GimpAction   *action,
+                          const gchar **reason)
 {
-  return gtk_action_is_sensitive ((GtkAction *) action);
+  gboolean sensitive;
+
+  sensitive = gtk_action_is_sensitive ((GtkAction *) action);
+
+  if (reason)
+    {
+      *reason = NULL;
+      if (! sensitive && GIMP_ACTION_GET_INTERFACE (action)->get_disable_reason)
+        *reason = GIMP_ACTION_GET_INTERFACE (action)->get_disable_reason (action);
+    }
+
+  return sensitive;
 }
 
 GClosure *
diff --git a/app/widgets/gimpaction.h b/app/widgets/gimpaction.h
index 58bd798cd1..85895fb231 100644
--- a/app/widgets/gimpaction.h
+++ b/app/widgets/gimpaction.h
@@ -34,10 +34,16 @@ struct _GimpActionInterface
 {
   GTypeInterface base_interface;
 
-  void (* activate)     (GimpAction *action,
-                         GVariant   *value);
-  void (* change_state) (GimpAction *action,
-                         GVariant   *value);
+  /* Signals */
+  void          (* activate)           (GimpAction  *action,
+                                        GVariant    *value);
+  void          (* change_state)       (GimpAction  *action,
+                                        GVariant    *value);
+
+  /* Virtual methods */
+  void          (* set_disable_reason) (GimpAction  *action,
+                                        const gchar *reason);
+  const gchar * (* get_disable_reason) (GimpAction  *action);
 };
 
 
@@ -81,9 +87,12 @@ gboolean      gimp_action_get_visible         (GimpAction    *action);
 gboolean      gimp_action_is_visible          (GimpAction    *action);
 
 void          gimp_action_set_sensitive       (GimpAction    *action,
-                                               gboolean       sensitive);
-gboolean      gimp_action_get_sensitive       (GimpAction    *action);
-gboolean      gimp_action_is_sensitive        (GimpAction    *action);
+                                               gboolean       sensitive,
+                                               const gchar   *reason);
+gboolean      gimp_action_get_sensitive       (GimpAction    *action,
+                                               const gchar  **reason);
+gboolean      gimp_action_is_sensitive        (GimpAction    *action,
+                                               const gchar  **reason);
 
 GClosure    * gimp_action_get_accel_closure   (GimpAction    *action);
 
diff --git a/app/widgets/gimpactiongroup.c b/app/widgets/gimpactiongroup.c
index 10cb415136..637d20bd82 100644
--- a/app/widgets/gimpactiongroup.c
+++ b/app/widgets/gimpactiongroup.c
@@ -765,7 +765,8 @@ gimp_action_group_set_action_visible (GimpActionGroup *group,
 void
 gimp_action_group_set_action_sensitive (GimpActionGroup *group,
                                         const gchar     *action_name,
-                                        gboolean         sensitive)
+                                        gboolean         sensitive,
+                                        const gchar     *reason)
 {
   GimpAction *action;
 
@@ -782,7 +783,7 @@ gimp_action_group_set_action_sensitive (GimpActionGroup *group,
       return;
     }
 
-  gimp_action_set_sensitive (action, sensitive);
+  gimp_action_set_sensitive (action, sensitive, reason);
 }
 
 void
diff --git a/app/widgets/gimpactiongroup.h b/app/widgets/gimpactiongroup.h
index 3436be3f0a..f3bd72c487 100644
--- a/app/widgets/gimpactiongroup.h
+++ b/app/widgets/gimpactiongroup.h
@@ -204,7 +204,8 @@ void          gimp_action_group_set_action_visible    (GimpActionGroup *group,
                                                        gboolean         visible);
 void          gimp_action_group_set_action_sensitive  (GimpActionGroup *group,
                                                        const gchar     *action_name,
-                                                       gboolean         sensitive);
+                                                       gboolean         sensitive,
+                                                       const gchar     *reason);
 void          gimp_action_group_set_action_active     (GimpActionGroup *group,
                                                        const gchar     *action_name,
                                                        gboolean         active);
diff --git a/app/widgets/gimpactionimpl.c b/app/widgets/gimpactionimpl.c
index 8ebe6d2a6c..e697285cee 100644
--- a/app/widgets/gimpactionimpl.c
+++ b/app/widgets/gimpactionimpl.c
@@ -55,26 +55,33 @@ enum
 };
 
 
-static void   gimp_action_impl_finalize      (GObject        *object);
-static void   gimp_action_impl_set_property  (GObject        *object,
-                                              guint           prop_id,
-                                              const GValue   *value,
-                                              GParamSpec     *pspec);
-static void   gimp_action_impl_get_property  (GObject        *object,
-                                              guint           prop_id,
-                                              GValue         *value,
-                                              GParamSpec     *pspec);
+static void   gimp_action_iface_init              (GimpActionInterface *iface);
 
-static void   gimp_action_impl_activate      (GtkAction      *action);
-static void   gimp_action_impl_connect_proxy (GtkAction      *action,
-                                              GtkWidget      *proxy);
+static void   gimp_action_impl_finalize           (GObject             *object);
+static void   gimp_action_impl_set_property       (GObject             *object,
+                                                   guint                prop_id,
+                                                   const GValue        *value,
+                                                   GParamSpec          *pspec);
+static void   gimp_action_impl_get_property       (GObject             *object,
+                                                   guint                prop_id,
+                                                   GValue              *value,
+                                                   GParamSpec          *pspec);
 
-static void   gimp_action_impl_set_proxy     (GimpActionImpl *impl,
-                                              GtkWidget      *proxy);
+static void   gimp_action_impl_set_disable_reason (GimpAction          *action,
+                                                   const gchar         *reason);
+static const gchar *
+              gimp_action_impl_get_disable_reason (GimpAction          *action);
+
+static void   gimp_action_impl_activate           (GtkAction           *action);
+static void   gimp_action_impl_connect_proxy      (GtkAction           *action,
+                                                   GtkWidget           *proxy);
+
+static void   gimp_action_impl_set_proxy          (GimpActionImpl      *impl,
+                                                   GtkWidget           *proxy);
 
 
 G_DEFINE_TYPE_WITH_CODE (GimpActionImpl, gimp_action_impl, GTK_TYPE_ACTION,
-                         G_IMPLEMENT_INTERFACE (GIMP_TYPE_ACTION, NULL))
+                         G_IMPLEMENT_INTERFACE (GIMP_TYPE_ACTION, gimp_action_iface_init))
 
 #define parent_class gimp_action_impl_parent_class
 
@@ -127,11 +134,19 @@ gimp_action_impl_class_init (GimpActionImplClass *klass)
                                                      GIMP_PARAM_READWRITE));
 }
 
+static void
+gimp_action_iface_init (GimpActionInterface *iface)
+{
+  iface->set_disable_reason = gimp_action_impl_set_disable_reason;
+  iface->get_disable_reason = gimp_action_impl_get_disable_reason;
+}
+
 static void
 gimp_action_impl_init (GimpActionImpl *impl)
 {
   impl->ellipsize       = PANGO_ELLIPSIZE_NONE;
   impl->max_width_chars = -1;
+  impl->disable_reason  = NULL;
 
   gimp_action_init (GIMP_ACTION (impl));
 }
@@ -141,9 +156,10 @@ gimp_action_impl_finalize (GObject *object)
 {
   GimpActionImpl *impl = GIMP_ACTION_IMPL (object);
 
-  g_clear_object (&impl->context);
+  g_clear_pointer (&impl->disable_reason, g_free);
+  g_clear_object  (&impl->context);
   g_clear_pointer (&impl->color, g_free);
-  g_clear_object (&impl->viewable);
+  g_clear_object  (&impl->viewable);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -238,6 +254,25 @@ gimp_action_impl_set_property (GObject      *object,
     }
 }
 
+static void
+gimp_action_impl_set_disable_reason (GimpAction  *action,
+                                     const gchar *reason)
+{
+  GimpActionImpl *impl = GIMP_ACTION_IMPL (action);
+
+  g_clear_pointer (&impl->disable_reason, g_free);
+  if (reason)
+    impl->disable_reason = g_strdup (reason);
+}
+
+static const gchar *
+gimp_action_impl_get_disable_reason (GimpAction *action)
+{
+  GimpActionImpl *impl = GIMP_ACTION_IMPL (action);
+
+  return (const gchar *) impl->disable_reason;
+}
+
 static void
 gimp_action_impl_activate (GtkAction *action)
 {
diff --git a/app/widgets/gimpactionimpl.h b/app/widgets/gimpactionimpl.h
index cd6e7a5fad..7b7e7bcfdf 100644
--- a/app/widgets/gimpactionimpl.h
+++ b/app/widgets/gimpactionimpl.h
@@ -38,6 +38,7 @@ struct _GimpActionImpl
 
   GimpContext        *context;
 
+  gchar              *disable_reason;
   GimpRGB            *color;
   GimpViewable       *viewable;
   PangoEllipsizeMode  ellipsize;
diff --git a/app/widgets/gimpeditor.c b/app/widgets/gimpeditor.c
index caea8d3e69..625571227e 100644
--- a/app/widgets/gimpeditor.c
+++ b/app/widgets/gimpeditor.c
@@ -589,7 +589,7 @@ gimp_editor_button_extended_clicked (GtkWidget       *button,
       ExtendedAction *ext = list->data;
 
       if ((ext->mod_mask & mask) == ext->mod_mask &&
-          gimp_action_get_sensitive (ext->action))
+          gimp_action_get_sensitive (ext->action, NULL))
         {
           gimp_action_activate (ext->action);
           break;
diff --git a/app/widgets/gimpsearchpopup.c b/app/widgets/gimpsearchpopup.c
index 330a661957..3f8f77b37d 100644
--- a/app/widgets/gimpsearchpopup.c
+++ b/app/widgets/gimpsearchpopup.c
@@ -236,14 +236,17 @@ gimp_search_popup_add_result (GimpSearchPopup *popup,
   gchar        *markup;
   gchar        *action_name;
   gchar        *label;
-  gchar        *escaped_label = NULL;
+  gchar        *escaped_label    = NULL;
   const gchar  *icon_name;
   gchar        *accel_string;
-  gchar        *escaped_accel = NULL;
-  gboolean      has_shortcut = FALSE;
+  gchar        *escaped_accel    = NULL;
+  gboolean      has_shortcut     = FALSE;
   const gchar  *tooltip;
-  gchar        *escaped_tooltip = NULL;
-  gboolean      has_tooltip  = FALSE;
+  gchar        *escaped_tooltip  = NULL;
+  gboolean      has_tooltip      = FALSE;
+  gboolean      sensitive        = FALSE;
+  const gchar  *sensitive_reason = NULL;
+  gchar        *escaped_reason   = NULL;
 
   label = g_strstrip (gimp_strip_uline (gimp_action_get_label (action)));
 
@@ -281,12 +284,24 @@ gimp_search_popup_add_result (GimpSearchPopup *popup,
       has_tooltip = TRUE;
     }
 
-  markup = g_strdup_printf ("%s<small>%s%s%s<span weight='light'>%s</span></small>",
+  sensitive = gimp_action_is_sensitive (action, &sensitive_reason);
+  if (sensitive_reason != NULL)
+    {
+      escaped_reason = g_markup_escape_text (sensitive_reason, -1);
+    }
+
+  markup = g_strdup_printf ("%s"                                           /* Label           */
+                            "<small>%s%s"                                  /* Shortcut        */
+                            "%s<span weight='light'>%s</span>"             /* Tooltip         */
+                            "%s<i><span weight='ultralight'>%s</span></i>" /* Inactive reason */
+                            "</small>",
                             escaped_label,
                             has_shortcut ? " | " : "",
                             has_shortcut ? escaped_accel : "",
                             has_tooltip ? "\n" : "",
-                            has_tooltip ? escaped_tooltip : "");
+                            has_tooltip ? escaped_tooltip : "",
+                            escaped_reason ? "\n" : "",
+                            escaped_reason ? escaped_reason : "");
 
   action_name = g_markup_escape_text (gimp_action_get_name (action), -1);
 
@@ -323,7 +338,7 @@ gimp_search_popup_add_result (GimpSearchPopup *popup,
                       COLUMN_TOOLTIP,   action_name,
                       COLUMN_ACTION,    action,
                       COLUMN_SECTION,   section,
-                      COLUMN_SENSITIVE, gimp_action_is_sensitive (action),
+                      COLUMN_SENSITIVE, sensitive,
                       -1);
 
   g_free (accel_string);
@@ -333,6 +348,7 @@ gimp_search_popup_add_result (GimpSearchPopup *popup,
   g_free (escaped_accel);
   g_free (escaped_label);
   g_free (escaped_tooltip);
+  g_free (escaped_reason);
 }
 
 /************ Private Functions ****************/
@@ -663,7 +679,7 @@ gimp_search_popup_run_selected (GimpSearchPopup *popup)
 
       gtk_tree_model_get (model, &iter, COLUMN_ACTION, &action, -1);
 
-      if (gimp_action_is_sensitive (action))
+      if (gimp_action_is_sensitive (action, NULL))
         {
           /* Close the search popup on activation. */
           GIMP_POPUP_CLASS (parent_class)->cancel (GIMP_POPUP (popup));


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]