PIKApp/extensions/goat-exercises/goat-exercise-c.c

288 lines
9.5 KiB
C

/*
* 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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#define PIKA_DISABLE_COMPAR_CRUFT
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#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,
const PikaValueArray *args,
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,
"<Image>/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 <pippin@gimp.org>",
"Øyvind Kolås <pippin@gimp.org>",
"21 march 2012");
}
return procedure;
}
static PikaValueArray *
goat_run (PikaProcedure *procedure,
PikaRunMode run_mode,
PikaImage *image,
gint n_drawables,
PikaDrawable **drawables,
const PikaValueArray *args,
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);
}