Commit 3831f624 authored by Michael Natterer's avatar Michael Natterer 😴

Bug 759316 - "Recently used" menu not updated with gegl filters

Add GimpGeglProceure to keep track of recently used GEGL operations in
the filter history. The new procedure also takes care of running the
op in the GEGL tool, so filters-commands.c is almost empty now.

Change gimp-filter-history.c to find procedures by name instead of
comparing pointers.

The only thing missing now is rerunning a GEGL op with the last
settings (not just showing its UI).
parent 32469d53
......@@ -17,6 +17,9 @@ libappactions_a_SOURCES = \
actions.c \
actions.h \
\
gimpgeglprocedure.c \
gimpgeglprocedure.h \
\
brush-editor-actions.c \
brush-editor-actions.h \
brushes-actions.c \
......
......@@ -778,6 +778,7 @@ filters_actions_history_changed (Gimp *gimp,
if (proc)
{
GtkAction *actual_action = NULL;
const gchar *label;
gchar *repeat;
gchar *reshow;
......@@ -794,20 +795,28 @@ filters_actions_history_changed (Gimp *gimp,
g_free (repeat);
g_free (reshow);
/* copy the sensitivity of the plug-in procedure's actual action
* instead of calling filters_actions_update() because doing the
* latter would set the sensitivity of this image's action on
* all images' actions. See bug #517683.
*/
if (plug_in_group)
if (g_str_has_prefix (gimp_object_get_name (proc), "filters-"))
{
GtkAction *actual_action =
actual_action =
gtk_action_group_get_action (GTK_ACTION_GROUP (group),
gimp_object_get_name (proc));
}
else if (plug_in_group)
{
/* copy the sensitivity of the plug-in procedure's actual
* action instead of calling filters_actions_update()
* because doing the latter would set the sensitivity of
* this image's action on all images' actions. See bug
* #517683.
*/
actual_action =
gtk_action_group_get_action (GTK_ACTION_GROUP (plug_in_group),
gimp_object_get_name (proc));
if (actual_action)
sensitive = gtk_action_get_sensitive (actual_action);
}
if (actual_action)
sensitive = gtk_action_get_sensitive (actual_action);
gimp_action_group_set_action_sensitive (group, "filters-repeat",
sensitive);
gimp_action_group_set_action_sensitive (group, "filters-reshow",
......@@ -827,6 +836,7 @@ filters_actions_history_changed (Gimp *gimp,
for (i = 0; i < gimp_filter_history_length (gimp); i++)
{
GtkAction *action;
GtkAction *actual_action = NULL;
const gchar *label;
gchar *name;
gboolean sensitive = FALSE;
......@@ -839,16 +849,23 @@ filters_actions_history_changed (Gimp *gimp,
label = gimp_procedure_get_menu_label (proc);
/* see comment above */
if (plug_in_group)
if (g_str_has_prefix (gimp_object_get_name (proc), "filters-"))
{
GtkAction *actual_action =
actual_action =
gtk_action_group_get_action (GTK_ACTION_GROUP (group),
gimp_object_get_name (proc));
}
else if (plug_in_group)
{
/* see comment above */
actual_action =
gtk_action_group_get_action (GTK_ACTION_GROUP (plug_in_group),
gimp_object_get_name (proc));
if (actual_action)
sensitive = gtk_action_get_sensitive (actual_action);
}
if (actual_action)
sensitive = gtk_action_get_sensitive (actual_action);
g_object_set (action,
"visible", TRUE,
"sensitive", sensitive,
......
......@@ -26,22 +26,13 @@
#include "core/gimp.h"
#include "core/gimp-filter-history.h"
#include "core/gimpcontext.h"
#include "core/gimpimage.h"
#include "core/gimpprogress.h"
#include "core/gimptoolinfo.h"
#include "pdb/gimpprocedure.h"
#include "tools/gimpoperationtool.h"
#include "tools/tool_manager.h"
#include "actions.h"
#include "filters-commands.h"
#include "gimpgeglprocedure.h"
#include "procedure-commands.h"
#include "gimp-intl.h"
/* public functions */
......@@ -50,53 +41,21 @@ filters_filter_cmd_callback (GtkAction *action,
const gchar *operation,
gpointer data)
{
GimpImage *image;
GimpDrawable *drawable;
GimpDisplay *display;
GimpTool *active_tool;
return_if_no_drawable (image, drawable, data);
GimpDisplay *display;
GimpProcedure *procedure;
return_if_no_display (display, data);
active_tool = tool_manager_get_active (image->gimp);
if (G_TYPE_FROM_INSTANCE (active_tool) != GIMP_TYPE_OPERATION_TOOL)
{
GimpToolInfo *tool_info = gimp_get_tool_info (image->gimp,
"gimp-operation-tool");
if (GIMP_IS_TOOL_INFO (tool_info))
gimp_context_set_tool (action_data_get_context (data), tool_info);
}
else
{
gimp_context_tool_changed (action_data_get_context (data));
}
active_tool = tool_manager_get_active (image->gimp);
procedure = gimp_gegl_procedure_new (action_data_get_gimp (data),
operation,
gtk_action_get_name (action),
gtk_action_get_label (action),
gtk_action_get_icon_name (action),
gtk_action_get_tooltip (action));
if (GIMP_IS_OPERATION_TOOL (active_tool))
{
gchar *label = gimp_strip_uline (gtk_action_get_label (action));
const gchar *ellipsis = _("...");
gint label_len;
gint ellipsis_len;
label_len = strlen (label);
ellipsis_len = strlen (ellipsis);
gimp_filter_history_add (action_data_get_gimp (data), procedure);
filters_history_cmd_callback (NULL, procedure, data);
if (label_len > ellipsis_len &&
strcmp (label + label_len - ellipsis_len, ellipsis) == 0)
{
label[label_len - ellipsis_len] = '\0';
}
gimp_operation_tool_set_operation (GIMP_OPERATION_TOOL (active_tool),
operation, label,
gtk_action_get_icon_name (action));
tool_manager_initialize_active (image->gimp, display);
g_free (label);
}
g_object_unref (procedure);
}
void
......@@ -104,10 +63,10 @@ filters_repeat_cmd_callback (GtkAction *action,
gint value,
gpointer data)
{
GimpProcedure *procedure;
Gimp *gimp;
GimpDisplay *display;
GimpRunMode run_mode;
GimpProcedure *procedure;
return_if_no_gimp (gimp, data);
return_if_no_display (display, data);
......@@ -123,23 +82,10 @@ filters_repeat_cmd_callback (GtkAction *action,
if (args)
{
GError *error = NULL;
g_value_set_int (gimp_value_array_index (args, 0), run_mode);
gimp_procedure_execute_async (procedure, gimp,
gimp_get_user_context (gimp),
GIMP_PROGRESS (display), args,
GIMP_OBJECT (display), &error);
if (error)
{
gimp_message_literal (gimp,
G_OBJECT (display), GIMP_MESSAGE_ERROR,
error->message);
g_clear_error (&error);
}
else
if (procedure_commands_run_procedure (procedure, gimp,
GIMP_PROGRESS (display),
run_mode, args,
display))
{
gimp_filter_history_add (gimp, procedure);
}
......@@ -164,23 +110,10 @@ filters_history_cmd_callback (GtkAction *action,
if (args)
{
GError *error = NULL;
g_value_set_int (gimp_value_array_index (args, 0), GIMP_RUN_INTERACTIVE);
gimp_procedure_execute_async (procedure, gimp,
gimp_get_user_context (gimp),
GIMP_PROGRESS (display), args,
GIMP_OBJECT (display), &error);
if (error)
{
gimp_message_literal (gimp,
G_OBJECT (display), GIMP_MESSAGE_ERROR,
error->message);
g_clear_error (&error);
}
else
if (procedure_commands_run_procedure (procedure, gimp,
GIMP_PROGRESS (display),
GIMP_RUN_INTERACTIVE, args,
display))
{
gimp_filter_history_add (gimp, procedure);
}
......
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpgeglprocedure.c
* Copyright (C) 2016 Michael Natterer <mitch@gimp.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libgimpbase/gimpbase.h"
#include "actions-types.h"
#include "core/gimp.h"
#include "core/gimp-memsize.h"
#include "core/gimpcontext.h"
#include "core/gimplayermask.h"
#include "core/gimpparamspecs.h"
#include "core/gimptoolinfo.h"
#include "display/gimpdisplay.h"
#include "tools/gimpoperationtool.h"
#include "tools/tool_manager.h"
#include "gimpgeglprocedure.h"
static void gimp_gegl_procedure_finalize (GObject *object);
static gint64 gimp_gegl_procedure_get_memsize (GimpObject *object,
gint64 *gui_size);
static gchar * gimp_gegl_procedure_get_description (GimpViewable *viewable,
gchar **tooltip);
static const gchar * gimp_gegl_procedure_get_label (GimpProcedure *procedure);
static const gchar * gimp_gegl_procedure_get_menu_label (GimpProcedure *procedure);
static gboolean gimp_gegl_procedure_get_sensitive (GimpProcedure *procedure,
GimpObject *object);
static GimpValueArray * gimp_gegl_procedure_execute (GimpProcedure *procedure,
Gimp *gimp,
GimpContext *context,
GimpProgress *progress,
GimpValueArray *args,
GError **error);
static void gimp_gegl_procedure_execute_async (GimpProcedure *procedure,
Gimp *gimp,
GimpContext *context,
GimpProgress *progress,
GimpValueArray *args,
GimpObject *display);
G_DEFINE_TYPE (GimpGeglProcedure, gimp_gegl_procedure,
GIMP_TYPE_PROCEDURE)
#define parent_class gimp_gegl_procedure_parent_class
static void
gimp_gegl_procedure_class_init (GimpGeglProcedureClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass);
GimpProcedureClass *proc_class = GIMP_PROCEDURE_CLASS (klass);
object_class->finalize = gimp_gegl_procedure_finalize;
gimp_object_class->get_memsize = gimp_gegl_procedure_get_memsize;
viewable_class->default_icon_name = "gimp-gegl";
viewable_class->get_description = gimp_gegl_procedure_get_description;
proc_class->get_label = gimp_gegl_procedure_get_label;
proc_class->get_menu_label = gimp_gegl_procedure_get_menu_label;
proc_class->get_sensitive = gimp_gegl_procedure_get_sensitive;
proc_class->execute = gimp_gegl_procedure_execute;
proc_class->execute_async = gimp_gegl_procedure_execute_async;
}
static void
gimp_gegl_procedure_init (GimpGeglProcedure *proc)
{
}
static void
gimp_gegl_procedure_finalize (GObject *object)
{
GimpGeglProcedure *proc = GIMP_GEGL_PROCEDURE (object);
g_free (proc->menu_label);
g_free (proc->label);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gint64
gimp_gegl_procedure_get_memsize (GimpObject *object,
gint64 *gui_size)
{
GimpGeglProcedure *proc = GIMP_GEGL_PROCEDURE (object);
gint64 memsize = 0;
memsize += gimp_string_get_memsize (proc->menu_label);
memsize += gimp_string_get_memsize (proc->label);
return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
gui_size);
}
static gchar *
gimp_gegl_procedure_get_description (GimpViewable *viewable,
gchar **tooltip)
{
GimpProcedure *procedure = GIMP_PROCEDURE (viewable);
if (tooltip)
*tooltip = g_strdup (gimp_procedure_get_blurb (procedure));
return g_strdup (gimp_procedure_get_label (procedure));
}
static const gchar *
gimp_gegl_procedure_get_label (GimpProcedure *procedure)
{
GimpGeglProcedure *proc = GIMP_GEGL_PROCEDURE (procedure);
gchar *ellipsis;
gchar *label;
if (proc->label)
return proc->label;
label = gimp_strip_uline (gimp_procedure_get_menu_label (procedure));
ellipsis = strstr (label, "...");
if (! ellipsis)
ellipsis = strstr (label, "\342\200\246" /* U+2026 HORIZONTAL ELLIPSIS */);
if (ellipsis && ellipsis == (label + strlen (label) - 3))
*ellipsis = '\0';
proc->label = label;
return proc->label;
}
static const gchar *
gimp_gegl_procedure_get_menu_label (GimpProcedure *procedure)
{
GimpGeglProcedure *proc = GIMP_GEGL_PROCEDURE (procedure);
if (proc->menu_label)
return proc->menu_label;
return GIMP_PROCEDURE_CLASS (parent_class)->get_menu_label (procedure);
}
static gboolean
gimp_gegl_procedure_get_sensitive (GimpProcedure *procedure,
GimpObject *object)
{
GimpDrawable *drawable;
gboolean sensitive = FALSE;
g_return_val_if_fail (object == NULL || GIMP_IS_DRAWABLE (object), FALSE);
drawable = GIMP_DRAWABLE (object);
if (drawable)
{
GimpItem *item;
if (GIMP_IS_LAYER_MASK (drawable))
item = GIMP_ITEM (gimp_layer_mask_get_layer (GIMP_LAYER_MASK (drawable)));
else
item = GIMP_ITEM (drawable);
sensitive = ! gimp_item_is_content_locked (item);
if (gimp_viewable_get_children (GIMP_VIEWABLE (drawable)))
sensitive = FALSE;
}
return sensitive;
}
static GimpValueArray *
gimp_gegl_procedure_execute (GimpProcedure *procedure,
Gimp *gimp,
GimpContext *context,
GimpProgress *progress,
GimpValueArray *args,
GError **error)
{
return GIMP_PROCEDURE_CLASS (parent_class)->execute (procedure, gimp,
context, progress,
args, error);
}
static void
gimp_gegl_procedure_execute_async (GimpProcedure *procedure,
Gimp *gimp,
GimpContext *context,
GimpProgress *progress,
GimpValueArray *args,
GimpObject *display)
{
GimpTool *active_tool = tool_manager_get_active (gimp);
/* do not use the passed context because we need to set the active
* tool on the global user context
*/
context = gimp_get_user_context (gimp);
if (G_TYPE_FROM_INSTANCE (active_tool) != GIMP_TYPE_OPERATION_TOOL)
{
GimpToolInfo *tool_info = gimp_get_tool_info (gimp,
"gimp-operation-tool");
if (GIMP_IS_TOOL_INFO (tool_info))
gimp_context_set_tool (context, tool_info);
}
else
{
gimp_context_tool_changed (context);
}
active_tool = tool_manager_get_active (gimp);
if (GIMP_IS_OPERATION_TOOL (active_tool))
{
gimp_operation_tool_set_operation (GIMP_OPERATION_TOOL (active_tool),
procedure->original_name,
gimp_procedure_get_label (procedure),
gimp_viewable_get_icon_name (GIMP_VIEWABLE (procedure)));
tool_manager_initialize_active (gimp, GIMP_DISPLAY (display));
}
}
/* public functions */
GimpProcedure *
gimp_gegl_procedure_new (Gimp *gimp,
const gchar *operation,
const gchar *name,
const gchar *menu_label,
const gchar *icon_name,
const gchar *tooltip)
{
GimpProcedure *procedure;
g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
g_return_val_if_fail (operation != NULL, NULL);
g_return_val_if_fail (name != NULL, NULL);
g_return_val_if_fail (menu_label != NULL, NULL);
procedure = g_object_new (GIMP_TYPE_GEGL_PROCEDURE, NULL);
GIMP_GEGL_PROCEDURE (procedure)->menu_label = g_strdup (menu_label);
gimp_object_set_name (GIMP_OBJECT (procedure), name);
gimp_viewable_set_icon_name (GIMP_VIEWABLE (procedure), icon_name);
gimp_procedure_set_strings (procedure,
operation,
tooltip,
"help",
"author", "copyright", "date",
NULL);
gimp_procedure_add_argument (procedure,
gimp_param_spec_int32 ("dummy-param",
"Dummy Param",
"Dummy parameter",
G_MININT32, G_MAXINT32, 0,
GIMP_PARAM_READWRITE));
gimp_procedure_add_argument (procedure,
gimp_param_spec_image_id ("image",
"Image",
"Input image",
gimp, FALSE,
GIMP_PARAM_READWRITE));
gimp_procedure_add_argument (procedure,
gimp_param_spec_drawable_id ("drawable",
"Drawable",
"Input drawable",
gimp, TRUE,
GIMP_PARAM_READWRITE));
return procedure;
}
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpgeglprocedure.h
* Copyright (C) 2016 Michael Natterer <mitch@gimp.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GIMP_GEGL_PROCEDURE_H__
#define __GIMP_GEGL_PROCEDURE_H__
#include "pdb/gimpprocedure.h"
#define GIMP_TYPE_GEGL_PROCEDURE (gimp_gegl_procedure_get_type ())
#define GIMP_GEGL_PROCEDURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_GEGL_PROCEDURE, GimpGeglProcedure))
#define GIMP_GEGL_PROCEDURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_GEGL_PROCEDURE, GimpGeglProcedureClass))
#define GIMP_IS_GEGL_PROCEDURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_GEGL_PROCEDURE))
#define GIMP_IS_GEGL_PROCEDURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_GEGL_PROCEDURE))
#define GIMP_GEGL_PROCEDURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_GEGL_PROCEDURE, GimpGeglProcedureClass))
typedef struct _GimpGeglProcedure GimpGeglProcedure;
typedef struct _GimpGeglProcedureClass GimpGeglProcedureClass;
struct _GimpGeglProcedure
{
GimpProcedure parent_instance;
gchar *menu_label;
gchar *label;
};
struct _GimpGeglProcedureClass
{
GimpProcedureClass parent_class;
};
GType gimp_gegl_procedure_get_type (void) G_GNUC_CONST;
GimpProcedure * gimp_gegl_procedure_new (Gimp *gimp,
const gchar *operation,
const gchar *name,
const gchar *menu_label,
const gchar *icon_name,
const gchar *tooltip);
#endif /* __GIMP_GEGL_PROCEDURE_H__ */
......@@ -17,8 +17,6 @@
#include "config.h"
#include <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
......@@ -29,10 +27,8 @@
#include "core/gimp.h"
#include "core/gimp-filter-history.h"
#include "core/gimp-utils.h"
#include "core/gimpcontainer.h"
#include "core/gimpcontext.h"
#include "core/gimpdrawable.h"
#include "core/gimpimage.h"
#include "core/gimpitem.h"
#include "core/gimpparamspecs.h"
......@@ -53,8 +49,6 @@
#include "widgets/gimpmessagebox.h"
#include "widgets/gimpmessagedialog.h"
#include "display/gimpdisplay.h"
#include "actions.h"
#include "plug-in-commands.h"
#include "procedure-commands.h"
......@@ -144,24 +138,10 @@ plug_in_run_cmd_callback (GtkAction *action,
if (args)
{
GError *error = NULL;
g_value_set_int (gimp_value_array_index (args, 0),
GIMP_RUN_INTERACTIVE);
gimp_procedure_execute_async (procedure, gimp,
gimp_get_user_context (gimp),
GIMP_PROGRESS (display), args,
GIMP_OBJECT (display), &error);
if (error)
{
gimp_message_literal (gimp,
G_OBJECT (display), GIMP_MESSAGE_ERROR,
error->message);
g_error_free (error);
}
else
if (procedure_commands_run_procedure (procedure, gimp,
GIMP_PROGRESS (display),
GIMP_RUN_INTERACTIVE, args,
display))
{
/* remember only image plug-ins */
if (procedure->num_args >= 2 &&
......
......@@ -27,11 +27,4 @@ void plug_in_reset_all_cmd_callback (GtkAction *action,
gpointer data);
/* FIXME history */
gint plug_in_collect_display_args (GtkAction *action,
GimpDisplay *display,
GParamSpec **pspecs,
GimpValueArray *args,
gint n_args);
#endif /* __PLUG_IN_COMMANDS_H__ */
......@@ -24,8 +24,10 @@
#include "actions-types.h"
#include "core/gimp.h"
#include "core/gimpimage.h"
#include "core/gimpparamspecs.h"
#include "core/gimpprogress.h"
#include "pdb/gimpprocedure.h"
......@@ -222,3 +224,38 @@ procedure_commands_get_display_args (GimpProcedure *procedure,
return args;
}
gboolean
procedure_commands_run_procedure (GimpProcedure *procedure,
Gimp *gimp,
GimpProgress *progress,
GimpRunMode run_mode,
GimpValueArray *args,
GimpDisplay *display)
{
GError *error = NULL;
g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), FALSE);
g_return_val_if_fail (GIMP_IS_GIMP (gimp), FALSE);
g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE);
g_return_val_if_fail (display == NULL || GIMP_IS_DISPLAY (display), FALSE);
g_return_val_if_fail (args != NULL, FALSE);
g_value_set_int (gimp_value_array_index (args, 0), run_mode);