/* * Goat exercise plug-in by Øyvind Kolås, pippin@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 . */ #include "config.h" #define PIKA_DISABLE_COMPAR_CRUFT #include #include #include "libpika/stdplugins-intl.h" #define PLUG_IN_BINARY "goat-exercise-c" #define PLUG_IN_SOURCE PLUG_IN_BINARY ".c" #define PLUG_IN_PROC "plug-in-goat-exercise-c" #define PLUG_IN_ROLE "goat-exercise-c" #define GOAT_URI "https://gitlab.gnome.org/GNOME/pika/blob/master/extensions/goat-exercises/goat-exercise-c.c" typedef struct _Goat Goat; typedef struct _GoatClass GoatClass; struct _Goat { PikaPlugIn parent_instance; }; struct _GoatClass { PikaPlugInClass parent_class; }; /* Declare local functions. */ #define GOAT_TYPE (goat_get_type ()) #define GOAT (obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GOAT_TYPE, Goat)) GType goat_get_type (void) G_GNUC_CONST; static GList * goat_query_procedures (PikaPlugIn *plug_in); static PikaProcedure * goat_create_procedure (PikaPlugIn *plug_in, const gchar *name); static PikaValueArray * goat_run (PikaProcedure *procedure, PikaRunMode run_mode, PikaImage *image, gint n_drawables, PikaDrawable **drawables, PikaProcedureConfig *config, gpointer run_data); G_DEFINE_TYPE (Goat, goat, PIKA_TYPE_PLUG_IN) PIKA_MAIN (GOAT_TYPE) static void goat_class_init (GoatClass *klass) { PikaPlugInClass *plug_in_class = PIKA_PLUG_IN_CLASS (klass); plug_in_class->query_procedures = goat_query_procedures; plug_in_class->create_procedure = goat_create_procedure; } static void goat_init (Goat *goat) { } static GList * goat_query_procedures (PikaPlugIn *plug_in) { return g_list_append (NULL, g_strdup (PLUG_IN_PROC)); } static PikaProcedure * goat_create_procedure (PikaPlugIn *plug_in, const gchar *name) { PikaProcedure *procedure = NULL; if (! strcmp (name, PLUG_IN_PROC)) { procedure = pika_image_procedure_new (plug_in, name, PIKA_PDB_PROC_TYPE_PLUGIN, goat_run, NULL, NULL); pika_procedure_set_image_types (procedure, "*"); pika_procedure_set_sensitivity_mask (procedure, PIKA_PROCEDURE_SENSITIVE_DRAWABLE); pika_procedure_set_menu_label (procedure, _("Exercise in _C minor")); pika_procedure_set_icon_name (procedure, PIKA_ICON_GEGL); pika_procedure_add_menu_path (procedure, "/Filters/Development/Goat exercises/"); pika_procedure_set_documentation (procedure, _("Exercise a goat in the C language"), "Takes a goat for a walk", PLUG_IN_PROC); pika_procedure_set_attribution (procedure, "Øyvind Kolås ", "Øyvind Kolås ", "21 march 2012"); } return procedure; } static PikaValueArray * goat_run (PikaProcedure *procedure, PikaRunMode run_mode, PikaImage *image, gint n_drawables, PikaDrawable **drawables, PikaProcedureConfig *config, gpointer run_data) { PikaDrawable *drawable; PikaPDBStatusType status = PIKA_PDB_SUCCESS; gint x, y, width, height; if (n_drawables != 1) { GError *error = NULL; g_set_error (&error, PIKA_PLUG_IN_ERROR, 0, _("Procedure '%s' only works with one drawable."), PLUG_IN_PROC); return pika_procedure_new_return_values (procedure, PIKA_PDB_CALLING_ERROR, error); } else { drawable = drawables[0]; } /* In interactive mode, display a dialog to advertise the exercise. */ if (run_mode == PIKA_RUN_INTERACTIVE) { GtkTextBuffer *buffer; GtkWidget *dialog; GtkWidget *box; GtkWidget *widget; GtkWidget *scrolled; GFile *file; GFileInputStream *input; gchar *head_text; gchar *path; GdkGeometry geometry; gchar source_text[4096]; gssize read; gint response; pika_ui_init (PLUG_IN_BINARY); dialog = pika_dialog_new (_("Exercise a goat (C)"), PLUG_IN_ROLE, NULL, GTK_DIALOG_USE_HEADER_BAR, pika_standard_help_func, PLUG_IN_PROC, _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Source"), GTK_RESPONSE_APPLY, _("_Run"), GTK_RESPONSE_OK, NULL); geometry.min_aspect = 0.5; geometry.max_aspect = 1.0; gtk_window_set_geometry_hints (GTK_WINDOW (dialog), NULL, &geometry, GDK_HINT_ASPECT); box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); gtk_container_set_border_width (GTK_CONTAINER (box), 12); gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), box); gtk_widget_show (box); head_text = g_strdup_printf (_("This plug-in is an exercise in '%s' " "to demo plug-in creation.\n" "Check out the last version " "of the source code online by " "clicking the \"Source\" button."), "C"); widget = gtk_label_new (head_text); g_free (head_text); gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 1); gtk_widget_show (widget); scrolled = gtk_scrolled_window_new (NULL, NULL); gtk_box_pack_start (GTK_BOX (box), scrolled, TRUE, TRUE, 1); gtk_widget_set_vexpand (GTK_WIDGET (scrolled), TRUE); gtk_widget_show (scrolled); path = g_build_filename (pika_plug_in_directory (), "extensions", "technology.heckin.extension.goat-exercises", PLUG_IN_SOURCE, NULL); file = g_file_new_for_path (path); g_free (path); widget = gtk_text_view_new (); gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (widget), GTK_WRAP_WORD); gtk_text_view_set_editable (GTK_TEXT_VIEW (widget), FALSE); buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget)); input = g_file_read (file, NULL, NULL); while ((read = g_input_stream_read (G_INPUT_STREAM (input), source_text, 4096, NULL, NULL)) && read != -1) { gtk_text_buffer_insert_at_cursor (buffer, source_text, read); } g_object_unref (file); gtk_container_add (GTK_CONTAINER (scrolled), widget); gtk_widget_show (widget); while ((response = pika_dialog_run (PIKA_DIALOG (dialog)))) { if (response == GTK_RESPONSE_OK) { gtk_widget_destroy (dialog); break; } else if (response == GTK_RESPONSE_APPLY) { /* Show the code. */ g_app_info_launch_default_for_uri (GOAT_URI, NULL, NULL); continue; } else /* CANCEL, CLOSE, DELETE_EVENT */ { gtk_widget_destroy (dialog); return pika_procedure_new_return_values (procedure, PIKA_PDB_CANCEL, NULL); } } } if (pika_drawable_mask_intersect (drawable, &x, &y, &width, &height)) { GeglBuffer *buffer; GeglBuffer *shadow_buffer; gegl_init (NULL, NULL); buffer = pika_drawable_get_buffer (drawable); shadow_buffer = pika_drawable_get_shadow_buffer (drawable); gegl_render_op (buffer, shadow_buffer, "gegl:invert", NULL); g_object_unref (shadow_buffer); /* flushes the shadow tiles */ g_object_unref (buffer); pika_drawable_merge_shadow (drawable, TRUE); pika_drawable_update (drawable, x, y, width, height); pika_displays_flush (); gegl_exit (); } return pika_procedure_new_return_values (procedure, status, NULL); }