[gimp/wip/nielsdg/vapi: 27/27] Allow building vala plugins



commit 3de830d7f819fe8dcf0a806b43116d5ee2139ee1
Author: Niels De Graef <nielsdegraef gmail com>
Date:   Fri May 8 21:49:44 2020 +0200

    Allow building vala plugins

 .gitlab-ci.yml                                  |   1 +
 acinclude.m4                                    |   1 +
 configure.ac                                    |  34 +++++
 libgimp/GimpUi-3.0.metadata                     |  25 ++++
 libgimp/Makefile.am                             |  64 ++++++++++
 libgimp/meson.build                             |  25 ++++
 m4macros/Makefile.am                            |   3 +-
 m4macros/vapigen.m4                             |  96 ++++++++++++++
 meson.build                                     |  16 +++
 meson_options.txt                               |   1 +
 plug-ins/goat-exercises/Makefile.am             |  36 ++++++
 plug-ins/goat-exercises/goat-exercise-vala.vala | 161 ++++++++++++++++++++++++
 plug-ins/goat-exercises/meson.build             |  22 ++++
 13 files changed, 484 insertions(+), 1 deletion(-)
---
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b2bc22cbeb..ae39e238df 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -120,6 +120,7 @@ deps-debian/testing:
         meson
         mypaint-brushes
         poppler-data
+        valac
         xauth
         xvfb
     - export PKG_CONFIG_PATH="${INSTALL_PREFIX}/lib/pkgconfig:${INSTALL_PREFIX}/share/pkgconfig"
diff --git a/acinclude.m4 b/acinclude.m4
index c803690211..009690d31c 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -6,3 +6,4 @@ m4_include([m4macros/ax_prog_cc_for_build.m4])
 m4_include([m4macros/ax_prog_perl_version.m4])
 m4_include([m4macros/detectcflags.m4])
 m4_include([m4macros/python3dev.m4])
+m4_include([m4macros/vapigen.m4])
diff --git a/configure.ac b/configure.ac
index 34a1b93f80..98b5f0c89b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -49,6 +49,10 @@ m4_define([gimp_full_name], [GNU Image Manipulation Program])
 m4_define([alsa_required_version], [1.0.0])
 m4_define([appstream_glib_required_version], [0.7.7])
 m4_define([atk_required_version], [2.4.0])
+m4_define([babl_major_minor_version], [0.1])
+m4_define([babl_micro_version], [74])
+m4_define([babl_required_version],
+          [babl_major_minor_version.babl_micro_version])
 m4_define([babl_required_version], [0.1.74])
 m4_define([cairo_required_version], [1.14.0])
 m4_define([cairo_pdf_required_version], [1.12.2])
@@ -83,6 +87,7 @@ m4_define([poppler_required_version], [0.69.0])
 m4_define([poppler_data_required_version], [0.4.9])
 m4_define([python3_required_version], [3.6.0])
 m4_define([rsvg_required_version], [2.40.6])
+m4_define([vala_required_version], [0.40.0])
 m4_define([webkitgtk_required_version], [2.20.3])
 m4_define([webp_required_version], [0.6.0])
 m4_define([wmf_required_version], [0.2.8])
@@ -155,6 +160,7 @@ AC_DEFINE(GIMP_TOOL_VERSION, "gimp_tool_version",
 # These are used for substitution (.pc, INSTALL, etc.).
 APPSTREAM_GLIB_REQUIRED_VERSION=appstream_glib_required_version
 ATK_REQUIRED_VERSION=atk_required_version
+BABL_MAJOR_MINOR_VERSION=babl_major_minor_version
 BABL_REQUIRED_VERSION=babl_required_version
 CAIRO_REQUIRED_VERSION=cairo_required_version
 CAIRO_PDF_REQUIRED_VERSION=cairo_pdf_required_version
@@ -181,6 +187,7 @@ POPPLER_REQUIRED_VERSION=poppler_required_version
 POPPLER_DATA_REQUIRED_VERSION=poppler_data_required_version
 PYTHON3_REQUIRED_VERSION=python3_required_version
 RSVG_REQUIRED_VERSION=rsvg_required_version
+VALA_REQUIRED_VERSION=vala_required_version
 WEBKITGTK_REQUIRED_VERSION=webkitgtk_required_version
 WEBP_REQUIRED_VERSION=webp_required_version
 WMF_REQUIRED_VERSION=wmf_required_version
@@ -188,6 +195,7 @@ LIBUNWIND_REQUIRED_VERSION=libunwind_required_version
 XGETTEXT_REQUIRED_VERSION=xgettext_required_version
 AC_SUBST(APPSTREAM_GLIB_REQUIRED_VERSION)
 AC_SUBST(ATK_REQUIRED_VERSION)
+AC_SUBST(BABL_MAJOR_MINOR_VERSION)
 AC_SUBST(BABL_REQUIRED_VERSION)
 AC_SUBST(CAIRO_REQUIRED_VERSION)
 AC_SUBST(CAIRO_PDF_REQUIRED_VERSION)
@@ -214,6 +222,7 @@ AC_SUBST(POPPLER_REQUIRED_VERSION)
 AC_SUBST(POPPLER_DATA_REQUIRED_VERSION)
 AC_SUBST(PYTHON3_REQUIRED_VERSION)
 AC_SUBST(RSVG_REQUIRED_VERSION)
+AC_SUBST(VALA_REQUIRED_VERSION)
 AC_SUBST(WEBKITGTK_REQUIRED_VERSION)
 AC_SUBST(WEBP_REQUIRED_VERSION)
 AC_SUBST(WMF_REQUIRED_VERSION)
@@ -2419,6 +2428,30 @@ fi
 AM_CONDITIONAL(HAS_LUA_INTERP, test "x$LUA" != "xno")
 AM_CONDITIONAL(BUILD_LUA, test "x$with_lua" != xno)
 
+#######################################
+# Check for Vala buildtime dependencies
+#######################################
+
+AC_ARG_WITH(vala,
+            [  --with-vala=no|yes install Vala plug-ins (default=yes)], ,
+            [with_vala=yes])
+
+if test "x$with_vala" = xno; then
+  warning_vala="
+WARNING: you disabled the installation of core Vala plug-ins. This
+         is discouraged as it won't provide the full GIMP experience."
+else
+  VAPIGEN_CHECK($VALA_REQUIRED_VERSION)
+  with_vala="yes"
+  warning_vala=
+  AC_PATH_PROG(VALAC, valac, no)
+  if test "x$VALAC" = xno; then
+    AC_MSG_ERROR([Vala-plugins are enabled, but could not find vala compiler])
+  fi
+fi
+
+AM_CONDITIONAL(BUILD_VALA, test "x$with_vala" != xno)
+
 ###########################################################
 # Some plug-ins don't build on Win32, others are Win32-only
 ###########################################################
@@ -3186,6 +3219,7 @@ Optional Plug-Ins:
   Python 3 plug-ins:         $with_python
   JavaScript plug-ins:       $with_javascript
   Lua plug-ins:              $with_lua
+  Vala plug-ins:             $with_vala
   TWAIN (Win32):             $os_win32
   Webpage:                   $have_webkit
   WMF:                       $have_libwmf
diff --git a/libgimp/GimpUi-3.0.metadata b/libgimp/GimpUi-3.0.metadata
new file mode 100644
index 0000000000..6397503fd1
--- /dev/null
+++ b/libgimp/GimpUi-3.0.metadata
@@ -0,0 +1,25 @@
+// Extra metadata for Vala, to deal with
+// annotations that GIR can't handle.
+//
+// For example, GIR function doesn't handle
+// varargs, but Vala *can* do this, so we can
+// remove the (skip) annotation.
+Dialog
+  .new skip=false
+  .add_buttons skip=false
+IntComboBox
+  .new skip=false
+IntStore
+  .new skip=false
+MessageDialog
+  .new skip=false
+ProcBrowserDialog
+  .new skip=false
+ToolDialog
+  .new skip=false
+OverlayDialog
+  .new skip=false
+ViewableDialog
+  .new skip=false
+
+text_layer_set
diff --git a/libgimp/Makefile.am b/libgimp/Makefile.am
index b65bff955c..744d3ae4a9 100644
--- a/libgimp/Makefile.am
+++ b/libgimp/Makefile.am
@@ -396,3 +396,67 @@ typelibdir = $(libdir)/girepository-1.0
 typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
 
 CLEANFILES += $(gir_DATA) $(typelib_DATA)
+
+
+if ENABLE_VAPIGEN
+
+-include $(VAPIGEN_MAKEFILE)
+
+gimp-@GIMP_API_MAJOR_VERSION@.vapi: Gimp-@GIMP_API_VERSION@.gir gimp-@GIMP_API_MAJOR_VERSION@.deps
+gimp-ui-@GIMP_API_MAJOR_VERSION@.vapi: GimpUi-@GIMP_API_VERSION@.gir GimpUi-@GIMP_API_VERSION@.metadata 
gimp-ui-@GIMP_API_MAJOR_VERSION@.deps gimp-@GIMP_API_MAJOR_VERSION@.vapi
+
+VAPIGEN_VAPIS = gimp-@GIMP_API_MAJOR_VERSION@.vapi gimp-ui-@GIMP_API_MAJOR_VERSION@.vapi
+
+# gimp VAPI
+gimp_@GIMP_API_MAJOR_VERSION@_vapi_DEPS = \
+       babl-@BABL_MAJOR_MINOR_VERSION@ \
+       cairo \
+       gdk-pixbuf-2.0 \
+       gegl-@GEGL_MAJOR_MINOR_VERSION@ \
+       glib-2.0 \
+       gio-2.0 \
+       gtk+-3.0
+gimp_@GIMP_API_MAJOR_VERSION@_vapi_GIRDIRS = $(builddir)
+gimp_@GIMP_API_MAJOR_VERSION@_vapi_METADATADIRS = $(srcdir)
+gimp_@GIMP_API_MAJOR_VERSION@_vapi_VAPIDIRS = $(builddir)
+gimp_@GIMP_API_MAJOR_VERSION@_vapi_FILES = Gimp-@GIMP_API_VERSION@.gir
+
+gimp-$(GIMP_API_MAJOR_VERSION).deps: Makefile.am
+       $(AM_V_GEN) for pkg in $(gimp_@GIMP_API_MAJOR_VERSION@_vapi_DEPS); do \
+               echo $$pkg >> $@; \
+       done
+
+# gimp-ui VAPI
+gimp_ui_@GIMP_API_MAJOR_VERSION@_vapi_DEPS = \
+       babl-@BABL_MAJOR_MINOR_VERSION@ \
+       cairo \
+       gdk-pixbuf-2.0 \
+       gegl-@GEGL_MAJOR_MINOR_VERSION@ \
+       glib-2.0 \
+       gio-2.0 \
+       gtk+-3.0 \
+       gimp-@GIMP_API_MAJOR_VERSION@
+
+gimp_ui_@GIMP_API_MAJOR_VERSION@_vapi_GIRDIRS = $(builddir)
+gimp_ui_@GIMP_API_MAJOR_VERSION@_vapi_METADATADIRS = $(srcdir)
+gimp_ui_@GIMP_API_MAJOR_VERSION@_vapi_VAPIDIRS = $(builddir)
+gimp_ui_@GIMP_API_MAJOR_VERSION@_vapi_FILES = GimpUi-@GIMP_API_VERSION@.gir
+
+gimp-ui-$(GIMP_API_MAJOR_VERSION).deps: Makefile.am
+       $(AM_V_GEN) for pkg in $(gimp_ui_@GIMP_API_MAJOR_VERSION@_vapi_DEPS); do \
+               echo $$pkg >> $@; \
+       done
+
+vapidir = $(datadir)/vala/vapi
+vapi_DATA = \
+       gimp-@GIMP_API_MAJOR_VERSION@.vapi \
+       gimp-@GIMP_API_MAJOR_VERSION@.deps \
+       gimp-ui-@GIMP_API_MAJOR_VERSION@.vapi \
+       gimp-ui-@GIMP_API_MAJOR_VERSION@.deps
+
+CLEANFILES += $(vapi_DATA)
+
+EXTRA_DIST += \
+       GimpUi-@GIMP_API_VERSION@.metadata
+
+endif # ENABLE_VAPIGEN
diff --git a/libgimp/meson.build b/libgimp/meson.build
index 231578ce2e..3ac6a6b2c8 100644
--- a/libgimp/meson.build
+++ b/libgimp/meson.build
@@ -454,4 +454,29 @@ else
     include_directories: rootInclude,
     install: true,
   )
+
+  if have_vala
+    vapi_deps = [
+      'babl-0.1',
+      'cairo-1.0',
+      'gdk-pixbuf-2.0',
+      'gegl-0.4',
+      'gio-2.0',
+      'glib-2.0',
+      'gobject-2.0',
+      'gtk+-3.0',
+    ]
+
+    libgimp_vapi = gnome.generate_vapi('gimp-' + gimp_api_version,
+      sources: libgimp_gir[0],
+      packages: vapi_deps,
+      install: true,
+    )
+
+    libgimpui_vapi = gnome.generate_vapi('gimp-ui-' + gimp_api_version,
+      sources: libgimpui_gir[0],
+      packages: vapi_deps + [ libgimp_vapi ],
+      install: true,
+    )
+  endif
 endif
diff --git a/m4macros/Makefile.am b/m4macros/Makefile.am
index c79976280a..ed19e97a5a 100644
--- a/m4macros/Makefile.am
+++ b/m4macros/Makefile.am
@@ -11,7 +11,8 @@ uninstalled_m4 = \
        ax_prog_perl_version.m4         \
        detectcflags.m4                 \
        introspection.m4                \
-       python3dev.m4
+       python3dev.m4           \
+       vapigen.m4
 
 EXTRA_DIST = $(installed_m4) $(uninstalled_m4)
 
diff --git a/m4macros/vapigen.m4 b/m4macros/vapigen.m4
new file mode 100644
index 0000000000..f2df12f23f
--- /dev/null
+++ b/m4macros/vapigen.m4
@@ -0,0 +1,96 @@
+dnl vapigen.m4
+dnl
+dnl Copyright 2012 Evan Nemerson
+dnl
+dnl This library is free software; you can redistribute it and/or
+dnl modify it under the terms of the GNU Lesser General Public
+dnl License as published by the Free Software Foundation; either
+dnl version 2.1 of the License, or (at your option) any later version.
+dnl
+dnl This library is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+dnl Lesser General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU Lesser General Public
+dnl License along with this library; if not, write to the Free Software
+dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+
+# VAPIGEN_CHECK([VERSION], [API_VERSION], [FOUND-INTROSPECTION], [DEFAULT])
+# --------------------------------------
+# Check vapigen existence and version
+#
+# See http://live.gnome.org/Vala/UpstreamGuide for detailed documentation
+AC_DEFUN([VAPIGEN_CHECK],
+[
+  AC_BEFORE([GOBJECT_INTROSPECTION_CHECK],[$0])
+  AC_BEFORE([GOBJECT_INTROSPECTION_REQUIRE],[$0])
+
+  AC_ARG_ENABLE([vala],
+    [AS_HELP_STRING([--enable-vala[=@<:@no/auto/yes@:>@]],[build Vala bindings 
@<:@default=]ifelse($4,,auto,$4)[@:>@])],,[
+      AS_IF([test "x$4" = "x"], [
+          enable_vala=auto
+        ], [
+          enable_vala=$4
+        ])
+    ])
+
+  AS_CASE([$enable_vala], [no], [enable_vala=no],
+      [yes], [
+        AS_IF([test "x$3" != "xyes" -a "x$found_introspection" != "xyes"], [
+            AC_MSG_ERROR([Vala bindings require GObject Introspection])
+          ])
+      ], [auto], [
+        AS_IF([test "x$3" != "xyes" -a "x$found_introspection" != "xyes"], [
+            enable_vala=no
+          ])
+      ], [
+        AC_MSG_ERROR([Invalid argument passed to --enable-vala, should be one of @<:@no/auto/yes@:>@])
+      ])
+
+  AS_IF([test "x$2" = "x"], [
+      vapigen_pkg_name=vapigen
+    ], [
+      vapigen_pkg_name=vapigen-$2
+    ])
+  AS_IF([test "x$1" = "x"], [
+      vapigen_pkg="$vapigen_pkg_name"
+    ], [
+      vapigen_pkg="$vapigen_pkg_name >= $1"
+    ])
+
+  PKG_PROG_PKG_CONFIG
+
+  PKG_CHECK_EXISTS([$vapigen_pkg], [
+      AS_IF([test "$enable_vala" = "auto"], [
+          enable_vala=yes
+        ])
+    ], [
+      AS_CASE([$enable_vala], [yes], [
+          AC_MSG_ERROR([$vapigen_pkg not found])
+        ], [auto], [
+          enable_vala=no
+        ])
+    ])
+
+  AC_MSG_CHECKING([for vala])
+
+  AS_CASE([$enable_vala],
+    [yes], [
+      VAPIGEN=`$PKG_CONFIG --variable=vapigen vapigen`
+      VAPIGEN_MAKEFILE=`$PKG_CONFIG --variable=datadir vapigen`/vala/Makefile.vapigen
+      AS_IF([test "x$2" = "x"], [
+          VAPIGEN_VAPIDIR=`$PKG_CONFIG --variable=vapidir vapigen`
+        ], [
+          VAPIGEN_VAPIDIR=`$PKG_CONFIG --variable=vapidir_versioned vapigen`
+        ])
+    ])
+
+  AC_MSG_RESULT([$enable_vala])
+
+  AC_SUBST([VAPIGEN])
+  AC_SUBST([VAPIGEN_VAPIDIR])
+  AC_SUBST([VAPIGEN_MAKEFILE])
+
+  AM_CONDITIONAL(ENABLE_VAPIGEN, test "x$enable_vala" = "xyes")
+])
diff --git a/meson.build b/meson.build
index 956a13f363..1bc9fd3ca3 100644
--- a/meson.build
+++ b/meson.build
@@ -757,6 +757,22 @@ if libheif.version().version_compare('==1.5.0') or libheif.version().version_com
     warnings += libheif_warning
 endif
 
+have_vala = add_languages('vala', required: get_option('vala-plugins'))
+if have_vala
+  babl = declare_dependency(
+    dependencies: [
+      babl,
+      meson.get_compiler('vala').find_library('babl-0.1'),
+    ]
+  )
+
+  # TODO: remove this once we release 3.0
+  valac = meson.get_compiler('vala')
+  if valac.version().version_compare('>= 0.31.1')
+    add_project_arguments('--disable-since-check', language: 'vala')
+  endif
+endif
+
 webkit_minver = '2.20.3'
 webkit = dependency('webkit2gtk-4.0', version: '>=' + webkit_minver,
   required: get_option('webkit')
diff --git a/meson_options.txt b/meson_options.txt
index e59524d450..87ba670917 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -45,6 +45,7 @@ option('png',               type: 'feature', value: 'auto', description: 'PNG su
 option('print',             type: 'feature', value: 'auto', description: 'Print support')
 option('screenshot',        type: 'feature', value: 'auto', description: 'Screensh')
 option('tiff',              type: 'feature', value: 'auto', description: 'TIFF support')
+option('vala-plugins',      type: 'feature', value: 'auto', description: 'Build VAPI and Vala plugins')
 option('webkit',            type: 'feature', value: 'auto', description: 'Help browser and webpage plugins')
 option('webp',              type: 'feature', value: 'auto', description: 'Webp support')
 option('wmf',               type: 'feature', value: 'auto', description: 'Wmf support')
diff --git a/plug-ins/goat-exercises/Makefile.am b/plug-ins/goat-exercises/Makefile.am
index c0c3c84efb..a1e62486ab 100644
--- a/plug-ins/goat-exercises/Makefile.am
+++ b/plug-ins/goat-exercises/Makefile.am
@@ -82,6 +82,42 @@ goat_exercise_py3dir = $(gimpplugindir)/plug-ins/goat-exercise-py3
 goat_exercise_py3_SCRIPTS = goat-exercise-py3.py
 endif
 
+# Vala (compiled to C) version
+
+if ENABLE_VAPIGEN
+
+goat_exercise_vala_libexecdir = $(gimpplugindir)/plug-ins/goat-exercise-vala
+goat_exercise_vala_datadir    = $(goat_exercise_vala_libexecdir)
+
+goat_exercise_vala_libexec_PROGRAMS = goat-exercise-vala
+goat_exercise_vala_libexec_DATA = goat-exercise-vala.vala
+
+goat_exercise_vala_SOURCES = goat-exercise-vala.vala
+goat_exercise_vala_CFLAGS = -DGETTEXT_PACKAGE=\""$(GETTEXT_PACKAGE)"\"
+
+goat_exercise_vala_LDADD = \
+       $(libgimp)              \
+       $(libgimpmath)          \
+       $(libgimpconfig)        \
+       $(libgimpcolor)         \
+       $(libgimpbase)          \
+       $(libgimpui)            \
+       $(libgimpwidgets)       \
+       $(CAIRO_LIBS)           \
+       $(GDK_PIXBUF_LIBS)      \
+       $(GEGL_LIBS)            \
+       $(GTK_LIBS)             \
+       $(RT_LIBS)              \
+       $(INTLLIBS)             \
+       $(goat_exercise_RC)
+
+goat_exercise_vala_VALAFLAGS = \
+       --vapidir=$(abs_top_builddir)/libgimp           \
+       --pkg gimp-@GIMP_API_MAJOR_VERSION@             \
+       --pkg gimp-ui-@GIMP_API_MAJOR_VERSION@
+
+endif
+
 EXTRA_DIST = \
        goat-exercise-gjs.js    \
        goat-exercise-lua.lua   \
diff --git a/plug-ins/goat-exercises/goat-exercise-vala.vala b/plug-ins/goat-exercises/goat-exercise-vala.vala
new file mode 100755
index 0000000000..6a6b5e467a
--- /dev/null
+++ b/plug-ins/goat-exercises/goat-exercise-vala.vala
@@ -0,0 +1,161 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * hello-world.vala
+ * Copyright (C) Niels De Graef <nielsdegraef gmail com>
+ *
+ * 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/>.
+ */
+
+private const string PLUG_IN_PROC = "plug-in-goat-exercise-vala";
+private const string PLUG_IN_ROLE = "goat-exercise-vala";
+private const string PLUG_IN_BINARY = "goat-exercise-vala";
+private const string PLUG_IN_SOURCE = PLUG_IN_BINARY + ".vala";
+private const string URL = 
"https://gitlab.gnome.org/GNOME/gimp/blob/master/plug-ins/goat-exercises/goat-exercise-vala.vala";;
+
+public int main(string[] args) {
+  return Gimp.main(typeof(Goat), args);
+}
+
+public class Goat : Gimp.PlugIn {
+
+  public override GLib.List<string> query_procedures() {
+    GLib.List<string> procs = null;
+    procs.append(PLUG_IN_PROC);
+    return procs;
+  }
+
+  public override Gimp.Procedure create_procedure(string name) {
+    assert(name == PLUG_IN_PROC);
+
+    var procedure = new Gimp.ImageProcedure(this, name, Gimp.PDBProcType.PLUGIN, this.run);
+    procedure.set_image_types("RGB*, INDEXED*, GRAY*");
+    procedure.set_menu_label("Exercise a Vala goat");
+    procedure.set_documentation("Exercise a goat in the Vala language",
+                                "Takes a goat for a walk in Vala",
+                                PLUG_IN_PROC);
+    procedure.add_menu_path("<Image>/Filters/Development/Goat exercises/");
+    procedure.set_attribution("Niels De Graef", "Niels De Graef", "2020");
+    procedure.set_icon_name(Gimp.ICON_GEGL);
+
+    return procedure;
+  }
+
+  public Gimp.ValueArray run(Gimp.Procedure procedure,
+                             Gimp.RunMode run_mode,
+                             Gimp.Image image,
+                             Gimp.Drawable drawable,
+                             Gimp.ValueArray args) {
+    if (run_mode == Gimp.RunMode.INTERACTIVE) {
+      Gimp.ui_init(PLUG_IN_BINARY);
+
+      var dialog =
+          new Gimp.Dialog(_("Exercise a goat (Vala)"),
+                          PLUG_IN_ROLE,
+                          null,
+                          Gtk.DialogFlags.USE_HEADER_BAR,
+                          Gimp.standard_help_func,
+                          PLUG_IN_PROC,
+                          _("_Cancel"), Gtk.ResponseType.CANCEL,
+                          _("_Source"), Gtk.ResponseType.APPLY,
+                          _("_Run"), Gtk.ResponseType.OK,
+                          null);
+
+      var geometry = Gdk.Geometry();
+      geometry.min_aspect = 0.5;
+      geometry.max_aspect = 1.0;
+      dialog.set_geometry_hints(null, geometry, Gdk.WindowHints.ASPECT);
+
+      var box = new Gtk.Box(Gtk.Orientation.VERTICAL, 12);
+      box.border_width = 12;
+      dialog.get_content_area().add(box);
+      box.show();
+
+      var head_text =
+        _("This plug-in is an exercise in '%s' to demo plug-in creation.\nCheck out the last version of the 
source code online by clicking the \"Source\" button.")
+        .printf("Vala");
+
+      var label = new Gtk.Label(head_text);
+      box.pack_start(label, false, false, 1);
+      label.show();
+
+
+      string file = Path.build_filename(Gimp.PlugIn.directory(), "plug-ins", PLUG_IN_BINARY, PLUG_IN_SOURCE);
+      string contents;
+      try {
+        FileUtils.get_contents(file, out contents);
+      } catch (Error err) {
+        contents = "Couldn't get file contents: %s".printf(err.message);
+      }
+
+      var scrolled = new Gtk.ScrolledWindow(null, null);
+      scrolled.vexpand = true;
+      box.pack_start(scrolled, true, true, 1);
+      scrolled.show();
+
+      var view = new Gtk.TextView();
+      view.wrap_mode = Gtk.WrapMode.WORD;
+      view.editable = false;
+      view.buffer.text = contents;
+      scrolled.add(view);
+      view.show();
+
+      while (true) {
+        var response = dialog.run();
+
+        if (response == Gtk.ResponseType.OK) {
+          dialog.destroy();
+          break;
+        } else if (response == Gtk.ResponseType.APPLY) {
+          try {
+            Gtk.show_uri_on_window(dialog, URL, Gdk.CURRENT_TIME);
+          } catch (Error err) {
+            warning("Couldn't launch browser for %s: %s", URL, err.message);
+          }
+          continue;
+        } else {
+          dialog.destroy();
+          return procedure.new_return_values(Gimp.PDBStatusType.CANCEL, null);
+        }
+      }
+    }
+
+    int x, y, width, height;
+    if (!drawable.mask_intersect(out x, out y, out width, out height)) {
+      var error = new GLib.Error.literal(GLib.Quark.from_string("goat-error-quark"), 0,
+                         "No pixels to process in the selected area.");
+      return procedure.new_return_values(Gimp.PDBStatusType.CALLING_ERROR, error);
+    }
+
+    unowned string[]? argv = null;
+    Gegl.init(ref argv);
+
+    {
+      var buffer = drawable.get_buffer();
+      var shadow_buffer = drawable.get_shadow_buffer();
+      Gegl.render_op(buffer, shadow_buffer, "gegl:invert", null);
+      // We don't need this line, since shadow_buffer is unreffed
+      // at the end of this block.
+      // No block? Then you still need to uncomment the following line
+      // shadow_buffer.flush();
+    }
+
+    drawable.merge_shadow(true);
+    drawable.update(x, y, width, height);
+    Gimp.displays_flush();
+    Gegl.exit();
+
+    return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, null);
+  }
+}
diff --git a/plug-ins/goat-exercises/meson.build b/plug-ins/goat-exercises/meson.build
index f6779c887f..982400778d 100644
--- a/plug-ins/goat-exercises/meson.build
+++ b/plug-ins/goat-exercises/meson.build
@@ -35,6 +35,28 @@ install_data(
   install_dir: gimpplugindir /  'plug-ins' / plugin_name + '-c',
 )
 
+# Vala version
+
+if have_vala
+  goat_exercise_vala = executable('goat-exercise-vala',
+    'goat-exercise-vala.vala',
+    include_directories: [ rootInclude, ],
+    dependencies: [
+      libgimp_vapi, libgimpui_vapi, gtk3, gegl, math,
+    ],
+    c_args: [
+      '-DGETTEXT_PACKAGE="@0@"'.format(gettext_package),
+    ],
+    install: true,
+    install_dir: gimpplugindir /  'plug-ins' / plugin_name + '-vala',
+  )
+
+  install_data(
+    'goat-exercise-vala.vala',
+    install_dir: gimpplugindir /  'plug-ins' / plugin_name + '-vala',
+  )
+endif
+
 # Python 3 (pygobject) version.
 
 if have_python


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