diff options
Diffstat (limited to 'app/plug-in')
59 files changed, 15322 insertions, 0 deletions
diff --git a/app/plug-in/Makefile.am b/app/plug-in/Makefile.am new file mode 100644 index 0000000..852fdbb --- /dev/null +++ b/app/plug-in/Makefile.am @@ -0,0 +1,106 @@ +## Process this file with automake to produce Makefile.in + +AM_CPPFLAGS = \ + -DG_LOG_DOMAIN=\"Gimp-Plug-In\" \ + -I$(top_builddir) \ + -I$(top_srcdir) \ + -I$(top_builddir)/app \ + -I$(top_srcdir)/app \ + $(CAIRO_CFLAGS) \ + $(GEGL_CFLAGS) \ + $(GDK_PIXBUF_CFLAGS) \ + -I$(includedir) + +noinst_LIBRARIES = libappplug-in.a + +libappplug_in_a_SOURCES = \ + plug-in-enums.c \ + plug-in-enums.h \ + plug-in-types.h \ + \ + gimpenvirontable.c \ + gimpenvirontable.h \ + gimpinterpreterdb.c \ + gimpinterpreterdb.h \ + gimpplugindebug.c \ + gimpplugindebug.h \ + gimpplugin.c \ + gimpplugin.h \ + gimpplugin-cleanup.c \ + gimpplugin-cleanup.h \ + gimpplugin-context.c \ + gimpplugin-context.h \ + gimpplugin-message.c \ + gimpplugin-message.h \ + gimpplugin-progress.c \ + gimpplugin-progress.h \ + gimpplugindef.c \ + gimpplugindef.h \ + gimppluginerror.c \ + gimppluginerror.h \ + gimppluginmanager.c \ + gimppluginmanager.h \ + gimppluginmanager-call.c \ + gimppluginmanager-call.h \ + gimppluginmanager-data.c \ + gimppluginmanager-data.h \ + gimppluginmanager-file.c \ + gimppluginmanager-file.h \ + gimppluginmanager-file-procedure.c \ + gimppluginmanager-file-procedure.h \ + gimppluginmanager-help-domain.c \ + gimppluginmanager-help-domain.h \ + gimppluginmanager-locale-domain.c \ + gimppluginmanager-locale-domain.h \ + gimppluginmanager-menu-branch.c \ + gimppluginmanager-menu-branch.h \ + gimppluginmanager-query.c \ + gimppluginmanager-query.h \ + gimppluginmanager-restore.c \ + gimppluginmanager-restore.h \ + gimppluginprocedure.c \ + gimppluginprocedure.h \ + gimppluginprocframe.c \ + gimppluginprocframe.h \ + gimppluginshm.c \ + gimppluginshm.h \ + gimptemporaryprocedure.c \ + gimptemporaryprocedure.h \ + \ + plug-in-menu-path.c \ + plug-in-menu-path.h \ + plug-in-params.c \ + plug-in-params.h \ + plug-in-rc.c \ + plug-in-rc.h + +# +# rules to generate built sources +# +# setup autogeneration dependencies +gen_sources = xgen-pec +CLEANFILES = $(EXTRA_PROGRAMS) $(gen_sources) + +xgen-pec: $(srcdir)/plug-in-enums.h $(GIMP_MKENUMS) Makefile.am + $(AM_V_GEN) $(GIMP_MKENUMS) \ + --fhead "#include \"config.h\"\n#include <gio/gio.h>\n#include \"libgimpbase/gimpbase.h\"\n#include \"plug-in-enums.h\"\n#include \"gimp-intl.h\"" \ + --fprod "\n/* enumerations from \"@basename@\" */" \ + --vhead "GType\n@enum_name@_get_type (void)\n{\n static const G@Type@Value values[] =\n {" \ + --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \ + --vtail " { 0, NULL, NULL }\n };\n" \ + --dhead " static const Gimp@Type@Desc descs[] =\n {" \ + --dprod " { @VALUENAME@, @valuedesc@, @valuehelp@ },@if ('@valueabbrev@' ne 'NULL')@\n /* Translators: this is an abbreviated version of @valueudesc@.\n Keep it short. */\n { @VALUENAME@, @valueabbrev@, NULL },@endif@" \ + --dtail " { 0, NULL, NULL }\n };\n\n static GType type = 0;\n\n if (G_UNLIKELY (! type))\n {\n type = g_@type@_register_static (\"@EnumName@\", values);\n gimp_type_set_translation_context (type, \"@enumnick@\");\n gimp_@type@_set_value_descriptions (type, descs);\n }\n\n return type;\n}\n" \ + $< > $@ + +# copy the generated enum file back to the source directory only if it's +# changed; otherwise, only update its timestamp, so that the recipe isn't +# executed again on the next build, however, allow this to (harmlessly) fail, +# to support building from a read-only source tree. +$(srcdir)/plug-in-enums.c: xgen-pec + $(AM_V_GEN) if ! cmp -s $< $@; then \ + cp $< $@; \ + else \ + touch $@ 2> /dev/null \ + || true; \ + fi diff --git a/app/plug-in/Makefile.in b/app/plug-in/Makefile.in new file mode 100644 index 0000000..20f9a6e --- /dev/null +++ b/app/plug-in/Makefile.in @@ -0,0 +1,1125 @@ +# Makefile.in generated by automake 1.16.2 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2020 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = app/plug-in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4macros/gtk-doc.m4 \ + $(top_srcdir)/m4macros/intltool.m4 \ + $(top_srcdir)/m4macros/libtool.m4 \ + $(top_srcdir)/m4macros/ltoptions.m4 \ + $(top_srcdir)/m4macros/ltsugar.m4 \ + $(top_srcdir)/m4macros/ltversion.m4 \ + $(top_srcdir)/m4macros/lt~obsolete.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/m4macros/alsa.m4 \ + $(top_srcdir)/m4macros/ax_compare_version.m4 \ + $(top_srcdir)/m4macros/ax_cxx_compile_stdcxx.m4 \ + $(top_srcdir)/m4macros/ax_gcc_func_attribute.m4 \ + $(top_srcdir)/m4macros/ax_prog_cc_for_build.m4 \ + $(top_srcdir)/m4macros/ax_prog_perl_version.m4 \ + $(top_srcdir)/m4macros/detectcflags.m4 \ + $(top_srcdir)/m4macros/pythondev.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +AM_V_AR = $(am__v_AR_@AM_V@) +am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) +am__v_AR_0 = @echo " AR " $@; +am__v_AR_1 = +libappplug_in_a_AR = $(AR) $(ARFLAGS) +libappplug_in_a_LIBADD = +am_libappplug_in_a_OBJECTS = plug-in-enums.$(OBJEXT) \ + gimpenvirontable.$(OBJEXT) gimpinterpreterdb.$(OBJEXT) \ + gimpplugindebug.$(OBJEXT) gimpplugin.$(OBJEXT) \ + gimpplugin-cleanup.$(OBJEXT) gimpplugin-context.$(OBJEXT) \ + gimpplugin-message.$(OBJEXT) gimpplugin-progress.$(OBJEXT) \ + gimpplugindef.$(OBJEXT) gimppluginerror.$(OBJEXT) \ + gimppluginmanager.$(OBJEXT) gimppluginmanager-call.$(OBJEXT) \ + gimppluginmanager-data.$(OBJEXT) \ + gimppluginmanager-file.$(OBJEXT) \ + gimppluginmanager-file-procedure.$(OBJEXT) \ + gimppluginmanager-help-domain.$(OBJEXT) \ + gimppluginmanager-locale-domain.$(OBJEXT) \ + gimppluginmanager-menu-branch.$(OBJEXT) \ + gimppluginmanager-query.$(OBJEXT) \ + gimppluginmanager-restore.$(OBJEXT) \ + gimppluginprocedure.$(OBJEXT) gimppluginprocframe.$(OBJEXT) \ + gimppluginshm.$(OBJEXT) gimptemporaryprocedure.$(OBJEXT) \ + plug-in-menu-path.$(OBJEXT) plug-in-params.$(OBJEXT) \ + plug-in-rc.$(OBJEXT) +libappplug_in_a_OBJECTS = $(am_libappplug_in_a_OBJECTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/gimpenvirontable.Po \ + ./$(DEPDIR)/gimpinterpreterdb.Po \ + ./$(DEPDIR)/gimpplugin-cleanup.Po \ + ./$(DEPDIR)/gimpplugin-context.Po \ + ./$(DEPDIR)/gimpplugin-message.Po \ + ./$(DEPDIR)/gimpplugin-progress.Po ./$(DEPDIR)/gimpplugin.Po \ + ./$(DEPDIR)/gimpplugindebug.Po ./$(DEPDIR)/gimpplugindef.Po \ + ./$(DEPDIR)/gimppluginerror.Po \ + ./$(DEPDIR)/gimppluginmanager-call.Po \ + ./$(DEPDIR)/gimppluginmanager-data.Po \ + ./$(DEPDIR)/gimppluginmanager-file-procedure.Po \ + ./$(DEPDIR)/gimppluginmanager-file.Po \ + ./$(DEPDIR)/gimppluginmanager-help-domain.Po \ + ./$(DEPDIR)/gimppluginmanager-locale-domain.Po \ + ./$(DEPDIR)/gimppluginmanager-menu-branch.Po \ + ./$(DEPDIR)/gimppluginmanager-query.Po \ + ./$(DEPDIR)/gimppluginmanager-restore.Po \ + ./$(DEPDIR)/gimppluginmanager.Po \ + ./$(DEPDIR)/gimppluginprocedure.Po \ + ./$(DEPDIR)/gimppluginprocframe.Po \ + ./$(DEPDIR)/gimppluginshm.Po \ + ./$(DEPDIR)/gimptemporaryprocedure.Po \ + ./$(DEPDIR)/plug-in-enums.Po ./$(DEPDIR)/plug-in-menu-path.Po \ + ./$(DEPDIR)/plug-in-params.Po ./$(DEPDIR)/plug-in-rc.Po +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libappplug_in_a_SOURCES) +DIST_SOURCES = $(libappplug_in_a_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +AA_LIBS = @AA_LIBS@ +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +ALL_LINGUAS = @ALL_LINGUAS@ +ALSA_CFLAGS = @ALSA_CFLAGS@ +ALSA_LIBS = @ALSA_LIBS@ +ALTIVEC_EXTRA_CFLAGS = @ALTIVEC_EXTRA_CFLAGS@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APPSTREAM_UTIL = @APPSTREAM_UTIL@ +AR = @AR@ +AS = @AS@ +ATK_CFLAGS = @ATK_CFLAGS@ +ATK_LIBS = @ATK_LIBS@ +ATK_REQUIRED_VERSION = @ATK_REQUIRED_VERSION@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BABL_CFLAGS = @BABL_CFLAGS@ +BABL_LIBS = @BABL_LIBS@ +BABL_REQUIRED_VERSION = @BABL_REQUIRED_VERSION@ +BUG_REPORT_URL = @BUG_REPORT_URL@ +BUILD_EXEEXT = @BUILD_EXEEXT@ +BUILD_OBJEXT = @BUILD_OBJEXT@ +BZIP2_LIBS = @BZIP2_LIBS@ +CAIRO_CFLAGS = @CAIRO_CFLAGS@ +CAIRO_LIBS = @CAIRO_LIBS@ +CAIRO_PDF_CFLAGS = @CAIRO_PDF_CFLAGS@ +CAIRO_PDF_LIBS = @CAIRO_PDF_LIBS@ +CAIRO_PDF_REQUIRED_VERSION = @CAIRO_PDF_REQUIRED_VERSION@ +CAIRO_REQUIRED_VERSION = @CAIRO_REQUIRED_VERSION@ +CATALOGS = @CATALOGS@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CC_VERSION = @CC_VERSION@ +CFLAGS = @CFLAGS@ +CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ +CPP_FOR_BUILD = @CPP_FOR_BUILD@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIRNAME = @DATADIRNAME@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DESKTOP_DATADIR = @DESKTOP_DATADIR@ +DESKTOP_FILE_VALIDATE = @DESKTOP_FILE_VALIDATE@ +DLLTOOL = @DLLTOOL@ +DOC_SHOOTER = @DOC_SHOOTER@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILE_AA = @FILE_AA@ +FILE_EXR = @FILE_EXR@ +FILE_HEIF = @FILE_HEIF@ +FILE_JP2_LOAD = @FILE_JP2_LOAD@ +FILE_MNG = @FILE_MNG@ +FILE_PDF_SAVE = @FILE_PDF_SAVE@ +FILE_PS = @FILE_PS@ +FILE_WMF = @FILE_WMF@ +FILE_XMC = @FILE_XMC@ +FILE_XPM = @FILE_XPM@ +FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@ +FONTCONFIG_LIBS = @FONTCONFIG_LIBS@ +FONTCONFIG_REQUIRED_VERSION = @FONTCONFIG_REQUIRED_VERSION@ +FREETYPE2_REQUIRED_VERSION = @FREETYPE2_REQUIRED_VERSION@ +FREETYPE_CFLAGS = @FREETYPE_CFLAGS@ +FREETYPE_LIBS = @FREETYPE_LIBS@ +GDBUS_CODEGEN = @GDBUS_CODEGEN@ +GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@ +GDK_PIXBUF_CSOURCE = @GDK_PIXBUF_CSOURCE@ +GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@ +GDK_PIXBUF_REQUIRED_VERSION = @GDK_PIXBUF_REQUIRED_VERSION@ +GEGL = @GEGL@ +GEGL_CFLAGS = @GEGL_CFLAGS@ +GEGL_LIBS = @GEGL_LIBS@ +GEGL_MAJOR_MINOR_VERSION = @GEGL_MAJOR_MINOR_VERSION@ +GEGL_REQUIRED_VERSION = @GEGL_REQUIRED_VERSION@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GEXIV2_CFLAGS = @GEXIV2_CFLAGS@ +GEXIV2_LIBS = @GEXIV2_LIBS@ +GEXIV2_REQUIRED_VERSION = @GEXIV2_REQUIRED_VERSION@ +GIMP_API_VERSION = @GIMP_API_VERSION@ +GIMP_APP_VERSION = @GIMP_APP_VERSION@ +GIMP_BINARY_AGE = @GIMP_BINARY_AGE@ +GIMP_COMMAND = @GIMP_COMMAND@ +GIMP_DATA_VERSION = @GIMP_DATA_VERSION@ +GIMP_FULL_NAME = @GIMP_FULL_NAME@ +GIMP_INTERFACE_AGE = @GIMP_INTERFACE_AGE@ +GIMP_MAJOR_VERSION = @GIMP_MAJOR_VERSION@ +GIMP_MICRO_VERSION = @GIMP_MICRO_VERSION@ +GIMP_MINOR_VERSION = @GIMP_MINOR_VERSION@ +GIMP_MKENUMS = @GIMP_MKENUMS@ +GIMP_MODULES = @GIMP_MODULES@ +GIMP_PACKAGE_REVISION = @GIMP_PACKAGE_REVISION@ +GIMP_PKGCONFIG_VERSION = @GIMP_PKGCONFIG_VERSION@ +GIMP_PLUGINS = @GIMP_PLUGINS@ +GIMP_PLUGIN_VERSION = @GIMP_PLUGIN_VERSION@ +GIMP_REAL_VERSION = @GIMP_REAL_VERSION@ +GIMP_SYSCONF_VERSION = @GIMP_SYSCONF_VERSION@ +GIMP_TOOL_VERSION = @GIMP_TOOL_VERSION@ +GIMP_UNSTABLE = @GIMP_UNSTABLE@ +GIMP_USER_VERSION = @GIMP_USER_VERSION@ +GIMP_VERSION = @GIMP_VERSION@ +GIO_CFLAGS = @GIO_CFLAGS@ +GIO_LIBS = @GIO_LIBS@ +GIO_UNIX_CFLAGS = @GIO_UNIX_CFLAGS@ +GIO_UNIX_LIBS = @GIO_UNIX_LIBS@ +GIO_WINDOWS_CFLAGS = @GIO_WINDOWS_CFLAGS@ +GIO_WINDOWS_LIBS = @GIO_WINDOWS_LIBS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@ +GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ +GLIB_LIBS = @GLIB_LIBS@ +GLIB_MKENUMS = @GLIB_MKENUMS@ +GLIB_REQUIRED_VERSION = @GLIB_REQUIRED_VERSION@ +GMODULE_NO_EXPORT_CFLAGS = @GMODULE_NO_EXPORT_CFLAGS@ +GMODULE_NO_EXPORT_LIBS = @GMODULE_NO_EXPORT_LIBS@ +GMOFILES = @GMOFILES@ +GMSGFMT = @GMSGFMT@ +GOBJECT_QUERY = @GOBJECT_QUERY@ +GREP = @GREP@ +GS_LIBS = @GS_LIBS@ +GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@ +GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ +GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ +GTKDOC_MKPDF = @GTKDOC_MKPDF@ +GTKDOC_REBASE = @GTKDOC_REBASE@ +GTK_CFLAGS = @GTK_CFLAGS@ +GTK_LIBS = @GTK_LIBS@ +GTK_MAC_INTEGRATION_CFLAGS = @GTK_MAC_INTEGRATION_CFLAGS@ +GTK_MAC_INTEGRATION_LIBS = @GTK_MAC_INTEGRATION_LIBS@ +GTK_REQUIRED_VERSION = @GTK_REQUIRED_VERSION@ +GTK_UPDATE_ICON_CACHE = @GTK_UPDATE_ICON_CACHE@ +GUDEV_CFLAGS = @GUDEV_CFLAGS@ +GUDEV_LIBS = @GUDEV_LIBS@ +HARFBUZZ_CFLAGS = @HARFBUZZ_CFLAGS@ +HARFBUZZ_LIBS = @HARFBUZZ_LIBS@ +HARFBUZZ_REQUIRED_VERSION = @HARFBUZZ_REQUIRED_VERSION@ +HAVE_CXX14 = @HAVE_CXX14@ +HAVE_FINITE = @HAVE_FINITE@ +HAVE_ISFINITE = @HAVE_ISFINITE@ +HAVE_VFORK = @HAVE_VFORK@ +HOST_GLIB_COMPILE_RESOURCES = @HOST_GLIB_COMPILE_RESOURCES@ +HTML_DIR = @HTML_DIR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INSTOBJEXT = @INSTOBJEXT@ +INTLLIBS = @INTLLIBS@ +INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ +INTLTOOL_MERGE = @INTLTOOL_MERGE@ +INTLTOOL_PERL = @INTLTOOL_PERL@ +INTLTOOL_REQUIRED_VERSION = @INTLTOOL_REQUIRED_VERSION@ +INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ +INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@ +INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@ +INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@ +INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +ISO_CODES_LOCALEDIR = @ISO_CODES_LOCALEDIR@ +ISO_CODES_LOCATION = @ISO_CODES_LOCATION@ +JPEG_LIBS = @JPEG_LIBS@ +JSON_GLIB_CFLAGS = @JSON_GLIB_CFLAGS@ +JSON_GLIB_LIBS = @JSON_GLIB_LIBS@ +LCMS_CFLAGS = @LCMS_CFLAGS@ +LCMS_LIBS = @LCMS_LIBS@ +LCMS_REQUIRED_VERSION = @LCMS_REQUIRED_VERSION@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ +LIBBACKTRACE_LIBS = @LIBBACKTRACE_LIBS@ +LIBHEIF_CFLAGS = @LIBHEIF_CFLAGS@ +LIBHEIF_LIBS = @LIBHEIF_LIBS@ +LIBHEIF_REQUIRED_VERSION = @LIBHEIF_REQUIRED_VERSION@ +LIBLZMA_REQUIRED_VERSION = @LIBLZMA_REQUIRED_VERSION@ +LIBMYPAINT_CFLAGS = @LIBMYPAINT_CFLAGS@ +LIBMYPAINT_LIBS = @LIBMYPAINT_LIBS@ +LIBMYPAINT_REQUIRED_VERSION = @LIBMYPAINT_REQUIRED_VERSION@ +LIBOBJS = @LIBOBJS@ +LIBPNG_REQUIRED_VERSION = @LIBPNG_REQUIRED_VERSION@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@ +LIBUNWIND_LIBS = @LIBUNWIND_LIBS@ +LIBUNWIND_REQUIRED_VERSION = @LIBUNWIND_REQUIRED_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_CURRENT_MINUS_AGE = @LT_CURRENT_MINUS_AGE@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LT_VERSION_INFO = @LT_VERSION_INFO@ +LZMA_CFLAGS = @LZMA_CFLAGS@ +LZMA_LIBS = @LZMA_LIBS@ +MAIL = @MAIL@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MIME_INFO_CFLAGS = @MIME_INFO_CFLAGS@ +MIME_INFO_LIBS = @MIME_INFO_LIBS@ +MIME_TYPES = @MIME_TYPES@ +MKDIR_P = @MKDIR_P@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MMX_EXTRA_CFLAGS = @MMX_EXTRA_CFLAGS@ +MNG_CFLAGS = @MNG_CFLAGS@ +MNG_LIBS = @MNG_LIBS@ +MSGFMT = @MSGFMT@ +MSGFMT_OPTS = @MSGFMT_OPTS@ +MSGMERGE = @MSGMERGE@ +MYPAINT_BRUSHES_CFLAGS = @MYPAINT_BRUSHES_CFLAGS@ +MYPAINT_BRUSHES_LIBS = @MYPAINT_BRUSHES_LIBS@ +NATIVE_GLIB_CFLAGS = @NATIVE_GLIB_CFLAGS@ +NATIVE_GLIB_LIBS = @NATIVE_GLIB_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENEXR_CFLAGS = @OPENEXR_CFLAGS@ +OPENEXR_LIBS = @OPENEXR_LIBS@ +OPENEXR_REQUIRED_VERSION = @OPENEXR_REQUIRED_VERSION@ +OPENJPEG_CFLAGS = @OPENJPEG_CFLAGS@ +OPENJPEG_LIBS = @OPENJPEG_LIBS@ +OPENJPEG_REQUIRED_VERSION = @OPENJPEG_REQUIRED_VERSION@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PANGOCAIRO_CFLAGS = @PANGOCAIRO_CFLAGS@ +PANGOCAIRO_LIBS = @PANGOCAIRO_LIBS@ +PANGOCAIRO_REQUIRED_VERSION = @PANGOCAIRO_REQUIRED_VERSION@ +PATHSEP = @PATHSEP@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PERL_REQUIRED_VERSION = @PERL_REQUIRED_VERSION@ +PERL_VERSION = @PERL_VERSION@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PNG_CFLAGS = @PNG_CFLAGS@ +PNG_LIBS = @PNG_LIBS@ +POFILES = @POFILES@ +POPPLER_CFLAGS = @POPPLER_CFLAGS@ +POPPLER_DATA_CFLAGS = @POPPLER_DATA_CFLAGS@ +POPPLER_DATA_LIBS = @POPPLER_DATA_LIBS@ +POPPLER_DATA_REQUIRED_VERSION = @POPPLER_DATA_REQUIRED_VERSION@ +POPPLER_LIBS = @POPPLER_LIBS@ +POPPLER_REQUIRED_VERSION = @POPPLER_REQUIRED_VERSION@ +POSUB = @POSUB@ +PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ +PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ +PYBIN_PATH = @PYBIN_PATH@ +PYCAIRO_CFLAGS = @PYCAIRO_CFLAGS@ +PYCAIRO_LIBS = @PYCAIRO_LIBS@ +PYGIMP_EXTRA_CFLAGS = @PYGIMP_EXTRA_CFLAGS@ +PYGTK_CFLAGS = @PYGTK_CFLAGS@ +PYGTK_CODEGEN = @PYGTK_CODEGEN@ +PYGTK_DEFSDIR = @PYGTK_DEFSDIR@ +PYGTK_LIBS = @PYGTK_LIBS@ +PYLINK_LIBS = @PYLINK_LIBS@ +PYTHON = @PYTHON@ +PYTHON2_REQUIRED_VERSION = @PYTHON2_REQUIRED_VERSION@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_INCLUDES = @PYTHON_INCLUDES@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +RSVG_REQUIRED_VERSION = @RSVG_REQUIRED_VERSION@ +RT_LIBS = @RT_LIBS@ +SCREENSHOT_LIBS = @SCREENSHOT_LIBS@ +SED = @SED@ +SENDMAIL = @SENDMAIL@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOCKET_LIBS = @SOCKET_LIBS@ +SSE2_EXTRA_CFLAGS = @SSE2_EXTRA_CFLAGS@ +SSE4_1_EXTRA_CFLAGS = @SSE4_1_EXTRA_CFLAGS@ +SSE_EXTRA_CFLAGS = @SSE_EXTRA_CFLAGS@ +STRIP = @STRIP@ +SVG_CFLAGS = @SVG_CFLAGS@ +SVG_LIBS = @SVG_LIBS@ +SYMPREFIX = @SYMPREFIX@ +TIFF_LIBS = @TIFF_LIBS@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WEBKIT_CFLAGS = @WEBKIT_CFLAGS@ +WEBKIT_LIBS = @WEBKIT_LIBS@ +WEBKIT_REQUIRED_VERSION = @WEBKIT_REQUIRED_VERSION@ +WEBPDEMUX_CFLAGS = @WEBPDEMUX_CFLAGS@ +WEBPDEMUX_LIBS = @WEBPDEMUX_LIBS@ +WEBPMUX_CFLAGS = @WEBPMUX_CFLAGS@ +WEBPMUX_LIBS = @WEBPMUX_LIBS@ +WEBP_CFLAGS = @WEBP_CFLAGS@ +WEBP_LIBS = @WEBP_LIBS@ +WEBP_REQUIRED_VERSION = @WEBP_REQUIRED_VERSION@ +WEB_PAGE = @WEB_PAGE@ +WIN32_LARGE_ADDRESS_AWARE = @WIN32_LARGE_ADDRESS_AWARE@ +WINDRES = @WINDRES@ +WMF_CFLAGS = @WMF_CFLAGS@ +WMF_CONFIG = @WMF_CONFIG@ +WMF_LIBS = @WMF_LIBS@ +WMF_REQUIRED_VERSION = @WMF_REQUIRED_VERSION@ +XDG_EMAIL = @XDG_EMAIL@ +XFIXES_CFLAGS = @XFIXES_CFLAGS@ +XFIXES_LIBS = @XFIXES_LIBS@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_REQUIRED_VERSION = @XGETTEXT_REQUIRED_VERSION@ +XMC_CFLAGS = @XMC_CFLAGS@ +XMC_LIBS = @XMC_LIBS@ +XMKMF = @XMKMF@ +XMLLINT = @XMLLINT@ +XMU_LIBS = @XMU_LIBS@ +XPM_LIBS = @XPM_LIBS@ +XSLTPROC = @XSLTPROC@ +XVFB_RUN = @XVFB_RUN@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +Z_LIBS = @Z_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CC_FOR_BUILD = @ac_ct_CC_FOR_BUILD@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gimpdatadir = @gimpdatadir@ +gimpdir = @gimpdir@ +gimplocaledir = @gimplocaledir@ +gimpplugindir = @gimpplugindir@ +gimpsysconfdir = @gimpsysconfdir@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +intltool__v_merge_options_ = @intltool__v_merge_options_@ +intltool__v_merge_options_0 = @intltool__v_merge_options_0@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +manpage_gimpdir = @manpage_gimpdir@ +mkdir_p = @mkdir_p@ +ms_librarian = @ms_librarian@ +mypaint_brushes_dir = @mypaint_brushes_dir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CPPFLAGS = \ + -DG_LOG_DOMAIN=\"Gimp-Plug-In\" \ + -I$(top_builddir) \ + -I$(top_srcdir) \ + -I$(top_builddir)/app \ + -I$(top_srcdir)/app \ + $(CAIRO_CFLAGS) \ + $(GEGL_CFLAGS) \ + $(GDK_PIXBUF_CFLAGS) \ + -I$(includedir) + +noinst_LIBRARIES = libappplug-in.a +libappplug_in_a_SOURCES = \ + plug-in-enums.c \ + plug-in-enums.h \ + plug-in-types.h \ + \ + gimpenvirontable.c \ + gimpenvirontable.h \ + gimpinterpreterdb.c \ + gimpinterpreterdb.h \ + gimpplugindebug.c \ + gimpplugindebug.h \ + gimpplugin.c \ + gimpplugin.h \ + gimpplugin-cleanup.c \ + gimpplugin-cleanup.h \ + gimpplugin-context.c \ + gimpplugin-context.h \ + gimpplugin-message.c \ + gimpplugin-message.h \ + gimpplugin-progress.c \ + gimpplugin-progress.h \ + gimpplugindef.c \ + gimpplugindef.h \ + gimppluginerror.c \ + gimppluginerror.h \ + gimppluginmanager.c \ + gimppluginmanager.h \ + gimppluginmanager-call.c \ + gimppluginmanager-call.h \ + gimppluginmanager-data.c \ + gimppluginmanager-data.h \ + gimppluginmanager-file.c \ + gimppluginmanager-file.h \ + gimppluginmanager-file-procedure.c \ + gimppluginmanager-file-procedure.h \ + gimppluginmanager-help-domain.c \ + gimppluginmanager-help-domain.h \ + gimppluginmanager-locale-domain.c \ + gimppluginmanager-locale-domain.h \ + gimppluginmanager-menu-branch.c \ + gimppluginmanager-menu-branch.h \ + gimppluginmanager-query.c \ + gimppluginmanager-query.h \ + gimppluginmanager-restore.c \ + gimppluginmanager-restore.h \ + gimppluginprocedure.c \ + gimppluginprocedure.h \ + gimppluginprocframe.c \ + gimppluginprocframe.h \ + gimppluginshm.c \ + gimppluginshm.h \ + gimptemporaryprocedure.c \ + gimptemporaryprocedure.h \ + \ + plug-in-menu-path.c \ + plug-in-menu-path.h \ + plug-in-params.c \ + plug-in-params.h \ + plug-in-rc.c \ + plug-in-rc.h + + +# +# rules to generate built sources +# +# setup autogeneration dependencies +gen_sources = xgen-pec +CLEANFILES = $(EXTRA_PROGRAMS) $(gen_sources) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu app/plug-in/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu app/plug-in/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +libappplug-in.a: $(libappplug_in_a_OBJECTS) $(libappplug_in_a_DEPENDENCIES) $(EXTRA_libappplug_in_a_DEPENDENCIES) + $(AM_V_at)-rm -f libappplug-in.a + $(AM_V_AR)$(libappplug_in_a_AR) libappplug-in.a $(libappplug_in_a_OBJECTS) $(libappplug_in_a_LIBADD) + $(AM_V_at)$(RANLIB) libappplug-in.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpenvirontable.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpinterpreterdb.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpplugin-cleanup.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpplugin-context.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpplugin-message.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpplugin-progress.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpplugin.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpplugindebug.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpplugindef.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimppluginerror.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimppluginmanager-call.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimppluginmanager-data.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimppluginmanager-file-procedure.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimppluginmanager-file.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimppluginmanager-help-domain.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimppluginmanager-locale-domain.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimppluginmanager-menu-branch.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimppluginmanager-query.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimppluginmanager-restore.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimppluginmanager.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimppluginprocedure.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimppluginprocframe.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimppluginshm.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimptemporaryprocedure.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plug-in-enums.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plug-in-menu-path.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plug-in-params.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plug-in-rc.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/gimpenvirontable.Po + -rm -f ./$(DEPDIR)/gimpinterpreterdb.Po + -rm -f ./$(DEPDIR)/gimpplugin-cleanup.Po + -rm -f ./$(DEPDIR)/gimpplugin-context.Po + -rm -f ./$(DEPDIR)/gimpplugin-message.Po + -rm -f ./$(DEPDIR)/gimpplugin-progress.Po + -rm -f ./$(DEPDIR)/gimpplugin.Po + -rm -f ./$(DEPDIR)/gimpplugindebug.Po + -rm -f ./$(DEPDIR)/gimpplugindef.Po + -rm -f ./$(DEPDIR)/gimppluginerror.Po + -rm -f ./$(DEPDIR)/gimppluginmanager-call.Po + -rm -f ./$(DEPDIR)/gimppluginmanager-data.Po + -rm -f ./$(DEPDIR)/gimppluginmanager-file-procedure.Po + -rm -f ./$(DEPDIR)/gimppluginmanager-file.Po + -rm -f ./$(DEPDIR)/gimppluginmanager-help-domain.Po + -rm -f ./$(DEPDIR)/gimppluginmanager-locale-domain.Po + -rm -f ./$(DEPDIR)/gimppluginmanager-menu-branch.Po + -rm -f ./$(DEPDIR)/gimppluginmanager-query.Po + -rm -f ./$(DEPDIR)/gimppluginmanager-restore.Po + -rm -f ./$(DEPDIR)/gimppluginmanager.Po + -rm -f ./$(DEPDIR)/gimppluginprocedure.Po + -rm -f ./$(DEPDIR)/gimppluginprocframe.Po + -rm -f ./$(DEPDIR)/gimppluginshm.Po + -rm -f ./$(DEPDIR)/gimptemporaryprocedure.Po + -rm -f ./$(DEPDIR)/plug-in-enums.Po + -rm -f ./$(DEPDIR)/plug-in-menu-path.Po + -rm -f ./$(DEPDIR)/plug-in-params.Po + -rm -f ./$(DEPDIR)/plug-in-rc.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/gimpenvirontable.Po + -rm -f ./$(DEPDIR)/gimpinterpreterdb.Po + -rm -f ./$(DEPDIR)/gimpplugin-cleanup.Po + -rm -f ./$(DEPDIR)/gimpplugin-context.Po + -rm -f ./$(DEPDIR)/gimpplugin-message.Po + -rm -f ./$(DEPDIR)/gimpplugin-progress.Po + -rm -f ./$(DEPDIR)/gimpplugin.Po + -rm -f ./$(DEPDIR)/gimpplugindebug.Po + -rm -f ./$(DEPDIR)/gimpplugindef.Po + -rm -f ./$(DEPDIR)/gimppluginerror.Po + -rm -f ./$(DEPDIR)/gimppluginmanager-call.Po + -rm -f ./$(DEPDIR)/gimppluginmanager-data.Po + -rm -f ./$(DEPDIR)/gimppluginmanager-file-procedure.Po + -rm -f ./$(DEPDIR)/gimppluginmanager-file.Po + -rm -f ./$(DEPDIR)/gimppluginmanager-help-domain.Po + -rm -f ./$(DEPDIR)/gimppluginmanager-locale-domain.Po + -rm -f ./$(DEPDIR)/gimppluginmanager-menu-branch.Po + -rm -f ./$(DEPDIR)/gimppluginmanager-query.Po + -rm -f ./$(DEPDIR)/gimppluginmanager-restore.Po + -rm -f ./$(DEPDIR)/gimppluginmanager.Po + -rm -f ./$(DEPDIR)/gimppluginprocedure.Po + -rm -f ./$(DEPDIR)/gimppluginprocframe.Po + -rm -f ./$(DEPDIR)/gimppluginshm.Po + -rm -f ./$(DEPDIR)/gimptemporaryprocedure.Po + -rm -f ./$(DEPDIR)/plug-in-enums.Po + -rm -f ./$(DEPDIR)/plug-in-menu-path.Po + -rm -f ./$(DEPDIR)/plug-in-params.Po + -rm -f ./$(DEPDIR)/plug-in-rc.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-noinstLIBRARIES \ + cscopelist-am ctags ctags-am distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +xgen-pec: $(srcdir)/plug-in-enums.h $(GIMP_MKENUMS) Makefile.am + $(AM_V_GEN) $(GIMP_MKENUMS) \ + --fhead "#include \"config.h\"\n#include <gio/gio.h>\n#include \"libgimpbase/gimpbase.h\"\n#include \"plug-in-enums.h\"\n#include \"gimp-intl.h\"" \ + --fprod "\n/* enumerations from \"@basename@\" */" \ + --vhead "GType\n@enum_name@_get_type (void)\n{\n static const G@Type@Value values[] =\n {" \ + --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \ + --vtail " { 0, NULL, NULL }\n };\n" \ + --dhead " static const Gimp@Type@Desc descs[] =\n {" \ + --dprod " { @VALUENAME@, @valuedesc@, @valuehelp@ },@if ('@valueabbrev@' ne 'NULL')@\n /* Translators: this is an abbreviated version of @valueudesc@.\n Keep it short. */\n { @VALUENAME@, @valueabbrev@, NULL },@endif@" \ + --dtail " { 0, NULL, NULL }\n };\n\n static GType type = 0;\n\n if (G_UNLIKELY (! type))\n {\n type = g_@type@_register_static (\"@EnumName@\", values);\n gimp_type_set_translation_context (type, \"@enumnick@\");\n gimp_@type@_set_value_descriptions (type, descs);\n }\n\n return type;\n}\n" \ + $< > $@ + +# copy the generated enum file back to the source directory only if it's +# changed; otherwise, only update its timestamp, so that the recipe isn't +# executed again on the next build, however, allow this to (harmlessly) fail, +# to support building from a read-only source tree. +$(srcdir)/plug-in-enums.c: xgen-pec + $(AM_V_GEN) if ! cmp -s $< $@; then \ + cp $< $@; \ + else \ + touch $@ 2> /dev/null \ + || true; \ + fi + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/app/plug-in/gimpenvirontable.c b/app/plug-in/gimpenvirontable.c new file mode 100644 index 0000000..82f2840 --- /dev/null +++ b/app/plug-in/gimpenvirontable.c @@ -0,0 +1,518 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpenvirontable.c + * (C) 2002 Manish Singh <yosh@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" + +#include <string.h> + +#include <gio/gio.h> + +#include "libgimpbase/gimpbase.h" +#include "libgimpconfig/gimpconfig.h" + +#include "plug-in-types.h" + +#include "gimpenvirontable.h" + +#include "gimp-intl.h" + + +typedef struct _GimpEnvironValue GimpEnvironValue; + +struct _GimpEnvironValue +{ + gchar *value; + gchar *separator; +}; + + +static void gimp_environ_table_finalize (GObject *object); + +static void gimp_environ_table_load_env_file (GimpEnvironTable *environ_table, + GFile *file); +static gboolean gimp_environ_table_legal_name (gchar *name); + +static void gimp_environ_table_populate (GimpEnvironTable *environ_table); +static void gimp_environ_table_populate_one (const gchar *name, + GimpEnvironValue *val, + GPtrArray *env_array); +static gboolean gimp_environ_table_pass_through (GimpEnvironTable *environ_table, + const gchar *name); + +static void gimp_environ_table_clear_vars (GimpEnvironTable *environ_table); +static void gimp_environ_table_clear_internal (GimpEnvironTable *environ_table); +static void gimp_environ_table_clear_envp (GimpEnvironTable *environ_table); + +static void gimp_environ_table_free_value (GimpEnvironValue *val); + + +G_DEFINE_TYPE (GimpEnvironTable, gimp_environ_table, G_TYPE_OBJECT) + +#define parent_class gimp_environ_table_parent_class + + +static void +gimp_environ_table_class_init (GimpEnvironTableClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = gimp_environ_table_finalize; +} + +static void +gimp_environ_table_init (GimpEnvironTable *environ_table) +{ +} + +static void +gimp_environ_table_finalize (GObject *object) +{ + GimpEnvironTable *environ_table = GIMP_ENVIRON_TABLE (object); + + gimp_environ_table_clear_all (environ_table); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +GimpEnvironTable * +gimp_environ_table_new (gboolean verbose) +{ + GimpEnvironTable *table = g_object_new (GIMP_TYPE_ENVIRON_TABLE, NULL); + + table->verbose = verbose; + + return table; +} + +static guint +gimp_environ_table_str_hash (gconstpointer v) +{ +#ifdef G_OS_WIN32 + gchar *p = g_ascii_strup ((const gchar *) v, -1); + guint retval = g_str_hash (p); + + g_free (p); + + return retval; +#else + return g_str_hash (v); +#endif +} + +static gboolean +gimp_environ_table_str_equal (gconstpointer v1, + gconstpointer v2) +{ +#ifdef G_OS_WIN32 + gchar *string1 = g_ascii_strup ((const gchar *) v1, -1); + gchar *string2 = g_ascii_strup ((const gchar *) v2, -1); + gboolean retval = g_str_equal (string1, string2); + + g_free (string1); + g_free (string2); + + return retval; +#else + return g_str_equal (v1, v2); +#endif +} + +void +gimp_environ_table_load (GimpEnvironTable *environ_table, + GList *path) +{ + GList *list; + + g_return_if_fail (GIMP_IS_ENVIRON_TABLE (environ_table)); + + gimp_environ_table_clear (environ_table); + + environ_table->vars = + g_hash_table_new_full (gimp_environ_table_str_hash, + gimp_environ_table_str_equal, + g_free, + (GDestroyNotify) gimp_environ_table_free_value); + + for (list = path; list; list = g_list_next (list)) + { + GFile *dir = list->data; + GFileEnumerator *enumerator; + + enumerator = + g_file_enumerate_children (dir, + G_FILE_ATTRIBUTE_STANDARD_NAME "," + G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN "," + G_FILE_ATTRIBUTE_STANDARD_TYPE, + G_FILE_QUERY_INFO_NONE, + NULL, NULL); + + if (enumerator) + { + GFileInfo *info; + + while ((info = g_file_enumerator_next_file (enumerator, + NULL, NULL))) + { + if (! g_file_info_get_is_hidden (info) && + g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR) + { + GFile *file = g_file_enumerator_get_child (enumerator, info); + + gimp_environ_table_load_env_file (environ_table, file); + + g_object_unref (file); + } + + g_object_unref (info); + } + + g_object_unref (enumerator); + } + } +} + +void +gimp_environ_table_add (GimpEnvironTable *environ_table, + const gchar *name, + const gchar *value, + const gchar *separator) +{ + GimpEnvironValue *val; + + g_return_if_fail (GIMP_IS_ENVIRON_TABLE (environ_table)); + + gimp_environ_table_clear_envp (environ_table); + + if (! environ_table->internal) + environ_table->internal = + g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, + (GDestroyNotify) gimp_environ_table_free_value); + + val = g_slice_new (GimpEnvironValue); + + val->value = g_strdup (value); + val->separator = g_strdup (separator); + + g_hash_table_insert (environ_table->internal, g_strdup (name), val); +} + +void +gimp_environ_table_remove (GimpEnvironTable *environ_table, + const gchar *name) +{ + g_return_if_fail (GIMP_IS_ENVIRON_TABLE (environ_table)); + + if (! environ_table->internal) + return; + + gimp_environ_table_clear_envp (environ_table); + + g_hash_table_remove (environ_table->internal, name); + + if (g_hash_table_size (environ_table->internal) == 0) + gimp_environ_table_clear_internal (environ_table); +} + +void +gimp_environ_table_clear (GimpEnvironTable *environ_table) +{ + g_return_if_fail (GIMP_IS_ENVIRON_TABLE (environ_table)); + + gimp_environ_table_clear_envp (environ_table); + + gimp_environ_table_clear_vars (environ_table); +} + +void +gimp_environ_table_clear_all (GimpEnvironTable *environ_table) +{ + g_return_if_fail (GIMP_IS_ENVIRON_TABLE (environ_table)); + + gimp_environ_table_clear_envp (environ_table); + + gimp_environ_table_clear_vars (environ_table); + gimp_environ_table_clear_internal (environ_table); +} + +gchar ** +gimp_environ_table_get_envp (GimpEnvironTable *environ_table) +{ + g_return_val_if_fail (GIMP_IS_ENVIRON_TABLE (environ_table), NULL); + + /* Hmm.. should we return a copy here in the future? Not thread safe atm, + * but the rest of it isn't either. + */ + + if (! environ_table->envp) + gimp_environ_table_populate (environ_table); + + return environ_table->envp; +} + + +/* private */ + +static void +gimp_environ_table_load_env_file (GimpEnvironTable *environ_table, + GFile *file) +{ + GInputStream *input; + GDataInputStream *data_input; + gchar *buffer; + gsize buffer_len; + GError *error = NULL; + + if (environ_table->verbose) + g_print ("Parsing '%s'\n", gimp_file_get_utf8_name (file)); + + input = G_INPUT_STREAM (g_file_read (file, NULL, &error)); + if (! input) + { + g_message (_("Could not open '%s' for reading: %s"), + gimp_file_get_utf8_name (file), + error->message); + g_clear_error (&error); + return; + } + + data_input = g_data_input_stream_new (input); + g_object_unref (input); + + while ((buffer = g_data_input_stream_read_line (data_input, &buffer_len, + NULL, &error))) + { + gchar *name; + gchar *value; + gchar *separator; + gchar *p; + gchar *q; + + /* Skip comments */ + if (buffer[0] == '#') + { + g_free (buffer); + continue; + } + + p = strchr (buffer, '='); + if (! p) + { + g_free (buffer); + continue; + } + + *p = '\0'; + + name = buffer; + value = p + 1; + + if (name[0] == '\0') + { + g_message (_("Empty variable name in environment file %s"), + gimp_file_get_utf8_name (file)); + g_free (buffer); + continue; + } + + separator = NULL; + + q = strchr (name, ' '); + if (q) + { + *q = '\0'; + + separator = name; + name = q + 1; + } + + if (! gimp_environ_table_legal_name (name)) + { + g_message (_("Illegal variable name in environment file %s: %s"), + gimp_file_get_utf8_name (file), name); + g_free (buffer); + continue; + } + + if (! g_hash_table_lookup (environ_table->vars, name)) + { + GimpEnvironValue *val = g_slice_new (GimpEnvironValue); + + val->value = gimp_config_path_expand (value, FALSE, NULL); + val->separator = g_strdup (separator); + + g_hash_table_insert (environ_table->vars, g_strdup (name), val); + } + + g_free (buffer); + } + + if (error) + { + g_message (_("Error reading '%s': %s"), + gimp_file_get_utf8_name (file), + error->message); + g_clear_error (&error); + } + + g_object_unref (data_input); +} + +static gboolean +gimp_environ_table_legal_name (gchar *name) +{ + gchar *s; + + if (! g_ascii_isalpha (*name) && (*name != '_')) + return FALSE; + + for (s = name + 1; *s; s++) + if (! g_ascii_isalnum (*s) && (*s != '_')) + return FALSE; + + return TRUE; +} + +static void +gimp_environ_table_populate (GimpEnvironTable *environ_table) +{ + gchar **env = g_listenv (); + gchar **var; + GPtrArray *env_array; + + var = env; + env_array = g_ptr_array_new (); + + while (*var) + { + /* g_listenv() only returns the names of environment variables + * that are correctly specified (name=value) in the environ + * array (Unix) or the process environment string table (Win32). + */ + + if (gimp_environ_table_pass_through (environ_table, *var)) + g_ptr_array_add (env_array, g_strconcat (*var, "=", g_getenv (*var), NULL)); + + var++; + } + + g_strfreev (env); + + if (environ_table->vars) + g_hash_table_foreach (environ_table->vars, + (GHFunc) gimp_environ_table_populate_one, + env_array); + + if (environ_table->internal) + g_hash_table_foreach (environ_table->internal, + (GHFunc) gimp_environ_table_populate_one, + env_array); + + g_ptr_array_add (env_array, NULL); + + environ_table->envp = (gchar **) g_ptr_array_free (env_array, FALSE); + +#ifdef ENVP_DEBUG + var = environ_table->envp; + + g_print ("GimpEnvironTable:\n"); + while (*var) + { + g_print ("%s\n", *var); + var++; + } +#endif /* ENVP_DEBUG */ +} + +static void +gimp_environ_table_populate_one (const gchar *name, + GimpEnvironValue *val, + GPtrArray *env_array) +{ + const gchar *old; + gchar *var = NULL; + + if (val->separator) + { + old = g_getenv (name); + + if (old) + var = g_strconcat (name, "=", val->value, val->separator, old, NULL); + } + + if (! var) + var = g_strconcat (name, "=", val->value, NULL); + + g_ptr_array_add (env_array, var); +} + +static gboolean +gimp_environ_table_pass_through (GimpEnvironTable *environ_table, + const gchar *name) +{ + gboolean vars, internal; + + vars = environ_table->vars && + g_hash_table_lookup (environ_table->vars, name); + + internal = environ_table->internal && + g_hash_table_lookup (environ_table->internal, name); + + return (!vars && !internal); +} + +static void +gimp_environ_table_clear_vars (GimpEnvironTable *environ_table) +{ + if (environ_table->vars) + { + g_hash_table_destroy (environ_table->vars); + environ_table->vars = NULL; + } +} + +static void +gimp_environ_table_clear_internal (GimpEnvironTable *environ_table) +{ + if (environ_table->internal) + { + g_hash_table_destroy (environ_table->internal); + environ_table->internal = NULL; + } +} + +static void +gimp_environ_table_clear_envp (GimpEnvironTable *environ_table) +{ + if (environ_table->envp) + { + g_strfreev (environ_table->envp); + environ_table->envp = NULL; + } +} + +static void +gimp_environ_table_free_value (GimpEnvironValue *val) +{ + g_free (val->value); + g_free (val->separator); + + g_slice_free (GimpEnvironValue, val); +} diff --git a/app/plug-in/gimpenvirontable.h b/app/plug-in/gimpenvirontable.h new file mode 100644 index 0000000..c77710d --- /dev/null +++ b/app/plug-in/gimpenvirontable.h @@ -0,0 +1,72 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpenvirontable.h + * (C) 2002 Manish Singh <yosh@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/>. + */ + +#ifndef __GIMP_ENVIRON_TABLE_H__ +#define __GIMP_ENVIRON_TABLE_H__ + + +#define GIMP_TYPE_ENVIRON_TABLE (gimp_environ_table_get_type ()) +#define GIMP_ENVIRON_TABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_ENVIRON_TABLE, GimpEnvironTable)) +#define GIMP_ENVIRON_TABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_ENVIRON_TABLE, GimpEnvironTableClass)) +#define GIMP_IS_ENVIRON_TABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_ENVIRON_TABLE)) +#define GIMP_IS_ENVIRON_TABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_ENVIRON_TABLE)) +#define GIMP_ENVIRON_TABLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_ENVIRON_TABLE, GimpEnvironTableClass)) + + +typedef struct _GimpEnvironTableClass GimpEnvironTableClass; + +struct _GimpEnvironTable +{ + GObject parent_instance; + + gboolean verbose; + + GHashTable *vars; + GHashTable *internal; + + gchar **envp; +}; + +struct _GimpEnvironTableClass +{ + GObjectClass parent_class; +}; + + +GType gimp_environ_table_get_type (void) G_GNUC_CONST; +GimpEnvironTable * gimp_environ_table_new (gboolean verbose); + +void gimp_environ_table_load (GimpEnvironTable *environ_table, + GList *path); + +void gimp_environ_table_add (GimpEnvironTable *environ_table, + const gchar *name, + const gchar *value, + const gchar *separator); +void gimp_environ_table_remove (GimpEnvironTable *environ_table, + const gchar *name); + +void gimp_environ_table_clear (GimpEnvironTable *environ_table); +void gimp_environ_table_clear_all (GimpEnvironTable *environ_table); + +gchar ** gimp_environ_table_get_envp (GimpEnvironTable *environ_table); + + +#endif /* __GIMP_ENVIRON_TABLE_H__ */ diff --git a/app/plug-in/gimpinterpreterdb.c b/app/plug-in/gimpinterpreterdb.c new file mode 100644 index 0000000..14b1f79 --- /dev/null +++ b/app/plug-in/gimpinterpreterdb.c @@ -0,0 +1,874 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpinterpreterdb.c + * (C) 2005 Manish Singh <yosh@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/>. + */ + +/* + * The binfmt_misc bits are derived from linux/fs/binfmt_misc.c + * Copyright (C) 1997 Richard Günther + */ + +/* + * The sh-bang code is derived from linux/fs/binfmt_script.c + * Copyright (C) 1996 Martin von Löwis + * original #!-checking implemented by tytso. + */ + +#include "config.h" + +#include <stdlib.h> +#include <string.h> + +#include <gio/gio.h> + +#include "libgimpbase/gimpbase.h" + +#include "plug-in-types.h" + +#include "gimpinterpreterdb.h" + +#include "gimp-intl.h" + + +#define BUFSIZE 4096 + + +typedef struct _GimpInterpreterMagic GimpInterpreterMagic; + +struct _GimpInterpreterMagic +{ + gulong offset; + gchar *magic; + gchar *mask; + guint size; + gchar *program; +}; + + +static void gimp_interpreter_db_finalize (GObject *object); + +static void gimp_interpreter_db_load_interp_file (GimpInterpreterDB *db, + GFile *file); + +static void gimp_interpreter_db_add_program (GimpInterpreterDB *db, + GFile *file, + gchar *buffer); +static void gimp_interpreter_db_add_binfmt_misc (GimpInterpreterDB *db, + GFile *file, + gchar *buffer); + +static gboolean gimp_interpreter_db_add_extension (GFile *file, + GimpInterpreterDB *db, + gchar **tokens); +static gboolean gimp_interpreter_db_add_magic (GimpInterpreterDB *db, + gchar **tokens); + +static void gimp_interpreter_db_clear_magics (GimpInterpreterDB *db); + +static void gimp_interpreter_db_resolve_programs (GimpInterpreterDB *db); + + +G_DEFINE_TYPE (GimpInterpreterDB, gimp_interpreter_db, G_TYPE_OBJECT) + +#define parent_class gimp_interpreter_db_parent_class + + +static void +gimp_interpreter_db_class_init (GimpInterpreterDBClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = gimp_interpreter_db_finalize; +} + +static void +gimp_interpreter_db_init (GimpInterpreterDB *db) +{ +} + +static void +gimp_interpreter_db_finalize (GObject *object) +{ + GimpInterpreterDB *db = GIMP_INTERPRETER_DB (object); + + gimp_interpreter_db_clear (db); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +GimpInterpreterDB * +gimp_interpreter_db_new (gboolean verbose) +{ + GimpInterpreterDB *db = g_object_new (GIMP_TYPE_INTERPRETER_DB, NULL); + + db->verbose = verbose; + + return db; +} + +void +gimp_interpreter_db_load (GimpInterpreterDB *db, + GList *path) +{ + GList *list; + + g_return_if_fail (GIMP_IS_INTERPRETER_DB (db)); + + gimp_interpreter_db_clear (db); + + db->programs = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_free); + + db->extensions = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_free); + + db->magic_names = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, NULL); + + db->extension_names = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, NULL); + + for (list = path; list; list = g_list_next (list)) + { + GFile *dir = list->data; + GFileEnumerator *enumerator; + + enumerator = + g_file_enumerate_children (dir, + G_FILE_ATTRIBUTE_STANDARD_NAME "," + G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN "," + G_FILE_ATTRIBUTE_STANDARD_TYPE, + G_FILE_QUERY_INFO_NONE, + NULL, NULL); + + if (enumerator) + { + GFileInfo *info; + + while ((info = g_file_enumerator_next_file (enumerator, + NULL, NULL))) + { + if (! g_file_info_get_is_hidden (info) && + g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR) + { + GFile *file = g_file_enumerator_get_child (enumerator, info); + + gimp_interpreter_db_load_interp_file (db, file); + + g_object_unref (file); + } + + g_object_unref (info); + } + + g_object_unref (enumerator); + } + } + + gimp_interpreter_db_resolve_programs (db); +} + +void +gimp_interpreter_db_clear (GimpInterpreterDB *db) +{ + g_return_if_fail (GIMP_IS_INTERPRETER_DB (db)); + + if (db->magic_names) + { + g_hash_table_destroy (db->magic_names); + db->magic_names = NULL; + } + + if (db->extension_names) + { + g_hash_table_destroy (db->extension_names); + db->extension_names = NULL; + } + + if (db->programs) + { + g_hash_table_destroy (db->programs); + db->programs = NULL; + } + + if (db->extensions) + { + g_hash_table_destroy (db->extensions); + db->extensions = NULL; + } + + gimp_interpreter_db_clear_magics (db); +} + +static void +gimp_interpreter_db_load_interp_file (GimpInterpreterDB *db, + GFile *file) +{ + GInputStream *input; + GDataInputStream *data_input; + gchar *buffer; + gsize buffer_len; + GError *error = NULL; + + if (db->verbose) + g_print ("Parsing '%s'\n", gimp_file_get_utf8_name (file)); + + input = G_INPUT_STREAM (g_file_read (file, NULL, &error)); + if (! input) + { + g_message (_("Could not open '%s' for reading: %s"), + gimp_file_get_utf8_name (file), + error->message); + g_clear_error (&error); + return; + } + + data_input = g_data_input_stream_new (input); + g_object_unref (input); + + while ((buffer = g_data_input_stream_read_line (data_input, &buffer_len, + NULL, &error))) + { + /* Skip comments */ + if (buffer[0] == '#') + { + g_free (buffer); + continue; + } + + if (g_ascii_isalnum (buffer[0]) || (buffer[0] == '/')) + { + gimp_interpreter_db_add_program (db, file, buffer); + } + else if (! g_ascii_isspace (buffer[0]) && (buffer[0] != '\0')) + { + gimp_interpreter_db_add_binfmt_misc (db, file, buffer); + } + + g_free (buffer); + } + + if (error) + { + g_message (_("Error reading '%s': %s"), + gimp_file_get_utf8_name (file), + error->message); + g_clear_error (&error); + } + + g_object_unref (data_input); +} + +static void +gimp_interpreter_db_add_program (GimpInterpreterDB *db, + GFile *file, + gchar *buffer) +{ + gchar *name; + gchar *program; + gchar *p; + + p = strchr (buffer, '='); + if (! p) + return; + + *p = '\0'; + + name = buffer; + program = p + 1; + + if (! g_file_test (program, G_FILE_TEST_IS_EXECUTABLE)) + { + gchar *prog; + + prog = g_find_program_in_path (program); + if (! prog || ! g_file_test (prog, G_FILE_TEST_IS_EXECUTABLE)) + { + g_message (_("Bad interpreter referenced in interpreter file %s: %s"), + gimp_file_get_utf8_name (file), + gimp_filename_to_utf8 (program)); + if (prog) + g_free (prog); + return; + } + program = prog; + } + else + program = g_strdup (program); + + if (! g_hash_table_lookup (db->programs, name)) + g_hash_table_insert (db->programs, g_strdup (name), program); +} + +static void +gimp_interpreter_db_add_binfmt_misc (GimpInterpreterDB *db, + GFile *file, + gchar *buffer) +{ + gchar **tokens = NULL; + gchar *name, *type, *program; + gsize count; + gchar del[2]; + + count = strlen (buffer); + + if ((count < 10) || (count > 255)) + goto bail; + + buffer = g_strndup (buffer, count + 9); + + del[0] = *buffer; + del[1] = '\0'; + + memset (buffer + count, del[0], 8); + + tokens = g_strsplit (buffer + 1, del, -1); + + g_free (buffer); + + name = tokens[0]; + type = tokens[1]; + program = tokens[5]; + + if ((name[0] == '\0') || (program[0] == '\0') || + (type[0] == '\0') || (type[1] != '\0')) + goto bail; + + switch (type[0]) + { + case 'E': + if (! gimp_interpreter_db_add_extension (file, db, tokens)) + goto bail; + break; + + case 'M': + if (! gimp_interpreter_db_add_magic (db, tokens)) + goto bail; + break; + + default: + goto bail; + } + + goto out; + +bail: + g_message (_("Bad binary format string in interpreter file %s"), + gimp_file_get_utf8_name (file)); + +out: + g_strfreev (tokens); +} + +static gboolean +gimp_interpreter_db_add_extension (GFile *file, + GimpInterpreterDB *db, + gchar **tokens) +{ + const gchar *name = tokens[0]; + const gchar *extension = tokens[3]; + const gchar *program = tokens[5]; + + if (! g_hash_table_lookup (db->extension_names, name)) + { + gchar *prog; + + if (extension[0] == '\0' || extension[0] == '/') + return FALSE; + + if (! g_file_test (program, G_FILE_TEST_IS_EXECUTABLE)) + { + prog = g_find_program_in_path (program); + if (! prog || ! g_file_test (prog, G_FILE_TEST_IS_EXECUTABLE)) + { + g_message (_("Bad interpreter referenced in interpreter file %s: %s"), + gimp_file_get_utf8_name (file), + gimp_filename_to_utf8 (program)); + if (prog) + g_free (prog); + return FALSE; + } + } + else + prog = g_strdup (program); + + g_hash_table_insert (db->extensions, g_strdup (extension), prog); + g_hash_table_insert (db->extension_names, g_strdup (name), prog); + } + + return TRUE; +} + +static gboolean +scanarg (const gchar *s) +{ + gchar c; + + while ((c = *s++) != '\0') + { + if (c == '\\' && *s == 'x') + { + s++; + + if (! g_ascii_isxdigit (*s++)) + return FALSE; + + if (! g_ascii_isxdigit (*s++)) + return FALSE; + } + } + + return TRUE; +} + +static guint +unquote (gchar *from) +{ + gchar *s = from; + gchar *p = from; + gchar c; + + while ((c = *s++) != '\0') + { + if (c == '\\' && *s == 'x') + { + s++; + *p = g_ascii_xdigit_value (*s++) << 4; + *p++ |= g_ascii_xdigit_value (*s++); + continue; + } + + *p++ = c; + } + + return p - from; +} + +static gboolean +gimp_interpreter_db_add_magic (GimpInterpreterDB *db, + gchar **tokens) +{ + GimpInterpreterMagic *interp_magic; + gchar *name, *num, *magic, *mask, *program; + gulong offset; + guint size; + + name = tokens[0]; + num = tokens[2]; + magic = tokens[3]; + mask = tokens[4]; + program = tokens[5]; + + if (! g_hash_table_lookup (db->magic_names, name)) + { + if (num[0] != '\0') + { + offset = strtoul (num, &num, 10); + + if (num[0] != '\0') + return FALSE; + + if (offset > (BUFSIZE / 4)) + return FALSE; + } + else + { + offset = 0; + } + + if (! scanarg (magic)) + return FALSE; + + if (! scanarg (mask)) + return FALSE; + + size = unquote (magic); + + if ((size + offset) > (BUFSIZE / 2)) + return FALSE; + + if (mask[0] == '\0') + mask = NULL; + else if (unquote (mask) != size) + return FALSE; + + interp_magic = g_slice_new (GimpInterpreterMagic); + + interp_magic->offset = offset; + interp_magic->magic = g_memdup (magic, size); + interp_magic->mask = g_memdup (mask, size); + interp_magic->size = size; + interp_magic->program = g_strdup (program); + + db->magics = g_slist_append (db->magics, interp_magic); + + g_hash_table_insert (db->magic_names, g_strdup (name), interp_magic); + } + + return TRUE; +} + +static void +gimp_interpreter_db_clear_magics (GimpInterpreterDB *db) +{ + GimpInterpreterMagic *magic; + GSList *list, *last; + + list = db->magics; + db->magics = NULL; + + while (list) + { + magic = list->data; + + g_free (magic->magic); + g_free (magic->mask); + g_free (magic->program); + + g_slice_free (GimpInterpreterMagic, magic); + + last = list; + list = list->next; + + g_slist_free_1 (last); + } +} + +#ifdef INTERP_DEBUG +static void +print_kv (gpointer key, + gpointer value, + gpointer user_data) +{ + g_print ("%s: %s\n", (gchar *) key, (gchar *) value); +} + +static gchar * +quote (gchar *s, + guint size) +{ + GString *d; + guint i; + + if (s == NULL) + return "(null)"; + + d = g_string_sized_new (size * 4); + + for (i = 0; i < size; i++) + g_string_append_printf (d, "\\x%02x", ((guint) s[i]) & 0xff); + + return g_string_free (d, FALSE); +} +#endif + +static gboolean +resolve_program (gpointer key, + gpointer value, + gpointer user_data) +{ + GimpInterpreterDB *db = user_data; + gchar *program; + + program = g_hash_table_lookup (db->programs, value); + + if (program != NULL) + { + g_free (value); + value = g_strdup (program); + } + + g_hash_table_insert (db->extensions, key, value); + + return TRUE; +} + +static void +gimp_interpreter_db_resolve_programs (GimpInterpreterDB *db) +{ + GSList *list; + GHashTable *extensions; + + for (list = db->magics; list; list = list->next) + { + GimpInterpreterMagic *magic = list->data; + const gchar *program; + + program = g_hash_table_lookup (db->programs, magic->program); + + if (program != NULL) + { + g_free (magic->program); + magic->program = g_strdup (program); + } + } + + extensions = db->extensions; + db->extensions = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_free); + + g_hash_table_foreach_steal (extensions, resolve_program, db); + + g_hash_table_destroy (extensions); + +#ifdef INTERP_DEBUG + g_print ("Programs:\n"); + g_hash_table_foreach (db->programs, print_kv, NULL); + + g_print ("\nExtensions:\n"); + g_hash_table_foreach (db->extensions, print_kv, NULL); + + g_print ("\nMagics:\n"); + + list = db->magics; + + while (list) + { + GimpInterpreterMagic *magic; + + magic = list->data; + g_print ("program: %s, offset: %lu, magic: %s, mask: %s\n", + magic->program, magic->offset, + quote (magic->magic, magic->size), + quote (magic->mask, magic->size)); + + list = list->next; + } + + g_print ("\n"); +#endif +} + +static gchar * +resolve_extension (GimpInterpreterDB *db, + const gchar *program_path) +{ + gchar *filename; + gchar *p; + const gchar *program; + + filename = g_path_get_basename (program_path); + + p = strrchr (filename, '.'); + if (! p) + { + g_free (filename); + return NULL; + } + + program = g_hash_table_lookup (db->extensions, p + 1); + + g_free (filename); + + return g_strdup (program); +} + +static gchar * +resolve_sh_bang (GimpInterpreterDB *db, + const gchar *program_path, + gchar *buffer, + gssize len, + gchar **interp_arg) +{ + gchar *cp; + gchar *name; + gchar *program; + + cp = strchr (buffer, '\n'); + if (! cp) + cp = buffer + len - 1; + + *cp = '\0'; + + while (cp > buffer) + { + cp--; + if ((*cp == ' ') || (*cp == '\t') || (*cp == '\r')) + *cp = '\0'; + else + break; + } + + for (cp = buffer + 2; (*cp == ' ') || (*cp == '\t'); cp++); + + if (*cp == '\0') + return NULL; + + name = cp; + + for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) + /* nothing */ ; + + while ((*cp == ' ') || (*cp == '\t')) + *cp++ = '\0'; + + if (*cp) + { + if (strcmp ("/usr/bin/env", name) == 0) + { + program = g_hash_table_lookup (db->programs, cp); + + if (program) + { + /* Shift program name and arguments to the right, if and + * only if we recorded a specific interpreter for such + * script. Otherwise let `env` tool do its job. + */ + name = cp; + + for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) + ; + + while ((*cp == ' ') || (*cp == '\t')) + *cp++ = '\0'; + } + } + + if (*cp) + *interp_arg = g_strdup (cp); + } + + program = g_hash_table_lookup (db->programs, name); + if (! program) + program = name; + + return g_strdup (program); +} + +static gchar * +resolve_magic (GimpInterpreterDB *db, + const gchar *program_path, + gchar *buffer) +{ + GSList *list; + GimpInterpreterMagic *magic; + gchar *s; + guint i; + + list = db->magics; + + while (list) + { + magic = list->data; + + s = buffer + magic->offset; + + if (magic->mask) + { + for (i = 0; i < magic->size; i++) + if ((*s++ ^ magic->magic[i]) & magic->mask[i]) + break; + } + else + { + for (i = 0; i < magic->size; i++) + if ((*s++ ^ magic->magic[i])) + break; + } + + if (i == magic->size) + return g_strdup (magic->program); + + list = list->next; + } + + return NULL; +} + +gchar * +gimp_interpreter_db_resolve (GimpInterpreterDB *db, + const gchar *program_path, + gchar **interp_arg) +{ + GFile *file; + GInputStream *input; + gchar *program = NULL; + + g_return_val_if_fail (GIMP_IS_INTERPRETER_DB (db), NULL); + g_return_val_if_fail (program_path != NULL, NULL); + g_return_val_if_fail (interp_arg != NULL, NULL); + + *interp_arg = NULL; + + file = g_file_new_for_path (program_path); + input = G_INPUT_STREAM (g_file_read (file, NULL, NULL)); + g_object_unref (file); + + if (input) + { + gsize bytes_read; + gchar buffer[BUFSIZE]; + + memset (buffer, 0, sizeof (buffer)); + g_input_stream_read_all (input, buffer, + sizeof (buffer) - 1, /* leave one nul at the end */ + &bytes_read, NULL, NULL); + g_object_unref (input); + + if (bytes_read) + { + if (bytes_read > 3 && buffer[0] == '#' && buffer[1] == '!') + program = resolve_sh_bang (db, program_path, buffer, bytes_read, interp_arg); + + if (! program) + program = resolve_magic (db, program_path, buffer); + } + } + + if (! program) + program = resolve_extension (db, program_path); + + return program; +} + +static void +collect_extensions (const gchar *ext, + const gchar *program G_GNUC_UNUSED, + GString *str) +{ + if (str->len) + g_string_append_c (str, G_SEARCHPATH_SEPARATOR); + + g_string_append_c (str, '.'); + g_string_append (str, ext); +} + +/** + * gimp_interpreter_db_get_extensions: + * @db: + * + * Return value: a newly allocated string with all registered file + * extensions separated by %G_SEARCHPATH_SEPARATOR; + * or %NULL if no extensions are registered + **/ +gchar * +gimp_interpreter_db_get_extensions (GimpInterpreterDB *db) +{ + GString *str; + + g_return_val_if_fail (GIMP_IS_INTERPRETER_DB (db), NULL); + + if (g_hash_table_size (db->extensions) == 0) + return NULL; + + str = g_string_new (NULL); + + g_hash_table_foreach (db->extensions, (GHFunc) collect_extensions, str); + + return g_string_free (str, FALSE); +} diff --git a/app/plug-in/gimpinterpreterdb.h b/app/plug-in/gimpinterpreterdb.h new file mode 100644 index 0000000..4c77acc --- /dev/null +++ b/app/plug-in/gimpinterpreterdb.h @@ -0,0 +1,70 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpinterpreterdb.h + * (C) 2005 Manish Singh <yosh@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/>. + */ + +#ifndef __GIMP_INTERPRETER_DB_H__ +#define __GIMP_INTERPRETER_DB_H__ + + +#define GIMP_TYPE_INTERPRETER_DB (gimp_interpreter_db_get_type ()) +#define GIMP_INTERPRETER_DB(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_INTERPRETER_DB, GimpInterpreterDB)) +#define GIMP_INTERPRETER_DB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_INTERPRETER_DB, GimpInterpreterDBClass)) +#define GIMP_IS_INTERPRETER_DB(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_INTERPRETER_DB)) +#define GIMP_IS_INTERPRETER_DB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_INTERPRETER_DB)) +#define GIMP_INTERPRETER_DB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_INTERPRETER_DB, GimpInterpreterDBClass)) + + +typedef struct _GimpInterpreterDBClass GimpInterpreterDBClass; + +struct _GimpInterpreterDB +{ + GObject parent_instance; + + gboolean verbose; + + GHashTable *programs; + + GSList *magics; + GHashTable *magic_names; + + GHashTable *extensions; + GHashTable *extension_names; +}; + +struct _GimpInterpreterDBClass +{ + GObjectClass parent_class; +}; + + +GType gimp_interpreter_db_get_type (void) G_GNUC_CONST; +GimpInterpreterDB * gimp_interpreter_db_new (gboolean verbose); + +void gimp_interpreter_db_load (GimpInterpreterDB *db, + GList *path); + +void gimp_interpreter_db_clear (GimpInterpreterDB *db); + +gchar * gimp_interpreter_db_resolve (GimpInterpreterDB *db, + const gchar *program_path, + gchar **interp_arg); +gchar * gimp_interpreter_db_get_extensions (GimpInterpreterDB *db); + + +#endif /* __GIMP_INTERPRETER_DB_H__ */ diff --git a/app/plug-in/gimpplugin-cleanup.c b/app/plug-in/gimpplugin-cleanup.c new file mode 100644 index 0000000..8c8d6d6 --- /dev/null +++ b/app/plug-in/gimpplugin-cleanup.c @@ -0,0 +1,578 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpplugin-cleanup.c + * + * 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" + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "plug-in-types.h" + +#include "core/gimp.h" +#include "core/gimpcontainer.h" +#include "core/gimpdrawable.h" +#include "core/gimpdrawable-shadow.h" +#include "core/gimpimage.h" +#include "core/gimpimage-undo.h" +#include "core/gimpundostack.h" + +#include "gimpplugin.h" +#include "gimpplugin-cleanup.h" +#include "gimppluginmanager.h" +#include "gimppluginprocedure.h" + +#include "gimp-log.h" + + +typedef struct _GimpPlugInCleanupImage GimpPlugInCleanupImage; + +struct _GimpPlugInCleanupImage +{ + GimpImage *image; + gint image_ID; + + gint undo_group_count; + gint layers_freeze_count; + gint channels_freeze_count; + gint vectors_freeze_count; +}; + + +typedef struct _GimpPlugInCleanupItem GimpPlugInCleanupItem; + +struct _GimpPlugInCleanupItem +{ + GimpItem *item; + gint item_ID; + + gboolean shadow_buffer; +}; + + +/* local function prototypes */ + +static GimpPlugInCleanupImage * + gimp_plug_in_cleanup_image_new (GimpPlugInProcFrame *proc_frame, + GimpImage *image); +static void gimp_plug_in_cleanup_image_free (GimpPlugInProcFrame *proc_frame, + GimpPlugInCleanupImage *cleanup); +static gboolean + gimp_plug_in_cleanup_image_is_clean (GimpPlugInCleanupImage *cleanup); +static GimpPlugInCleanupImage * + gimp_plug_in_cleanup_image_get (GimpPlugInProcFrame *proc_frame, + GimpImage *image); +static void gimp_plug_in_cleanup_image (GimpPlugInProcFrame *proc_frame, + GimpPlugInCleanupImage *cleanup); + +static GimpPlugInCleanupItem * + gimp_plug_in_cleanup_item_new (GimpPlugInProcFrame *proc_frame, + GimpItem *item); +static void gimp_plug_in_cleanup_item_free (GimpPlugInProcFrame *proc_frame, + GimpPlugInCleanupItem *cleanup); +static gboolean + gimp_plug_in_cleanup_item_is_clean (GimpPlugInCleanupItem *cleanup); +static GimpPlugInCleanupItem * + gimp_plug_in_cleanup_item_get (GimpPlugInProcFrame *proc_frame, + GimpItem *item); +static void gimp_plug_in_cleanup_item (GimpPlugInProcFrame *proc_frame, + GimpPlugInCleanupItem *cleanup); + + +/* public functions */ + +gboolean +gimp_plug_in_cleanup_undo_group_start (GimpPlugIn *plug_in, + GimpImage *image) +{ + GimpPlugInProcFrame *proc_frame; + GimpPlugInCleanupImage *cleanup; + + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), FALSE); + g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + cleanup = gimp_plug_in_cleanup_image_get (proc_frame, image); + + if (! cleanup) + cleanup = gimp_plug_in_cleanup_image_new (proc_frame, image); + + cleanup->undo_group_count++; + + return TRUE; +} + +gboolean +gimp_plug_in_cleanup_undo_group_end (GimpPlugIn *plug_in, + GimpImage *image) +{ + GimpPlugInProcFrame *proc_frame; + GimpPlugInCleanupImage *cleanup; + + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), FALSE); + g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + cleanup = gimp_plug_in_cleanup_image_get (proc_frame, image); + + if (! cleanup) + return FALSE; + + if (cleanup->undo_group_count > 0) + { + cleanup->undo_group_count--; + + if (gimp_plug_in_cleanup_image_is_clean (cleanup)) + gimp_plug_in_cleanup_image_free (proc_frame, cleanup); + + return TRUE; + } + + return FALSE; +} + +gboolean +gimp_plug_in_cleanup_layers_freeze (GimpPlugIn *plug_in, + GimpImage *image) +{ + GimpPlugInProcFrame *proc_frame; + GimpPlugInCleanupImage *cleanup; + + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), FALSE); + g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + cleanup = gimp_plug_in_cleanup_image_get (proc_frame, image); + + if (! cleanup) + cleanup = gimp_plug_in_cleanup_image_new (proc_frame, image); + + cleanup->layers_freeze_count++; + + return TRUE; +} + +gboolean +gimp_plug_in_cleanup_layers_thaw (GimpPlugIn *plug_in, + GimpImage *image) +{ + GimpPlugInProcFrame *proc_frame; + GimpPlugInCleanupImage *cleanup; + + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), FALSE); + g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + cleanup = gimp_plug_in_cleanup_image_get (proc_frame, image); + + if (! cleanup) + return FALSE; + + if (cleanup->layers_freeze_count > 0) + { + cleanup->layers_freeze_count--; + + if (gimp_plug_in_cleanup_image_is_clean (cleanup)) + gimp_plug_in_cleanup_image_free (proc_frame, cleanup); + + return TRUE; + } + + return FALSE; +} + +gboolean +gimp_plug_in_cleanup_channels_freeze (GimpPlugIn *plug_in, + GimpImage *image) +{ + GimpPlugInProcFrame *proc_frame; + GimpPlugInCleanupImage *cleanup; + + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), FALSE); + g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + cleanup = gimp_plug_in_cleanup_image_get (proc_frame, image); + + if (! cleanup) + cleanup = gimp_plug_in_cleanup_image_new (proc_frame, image); + + cleanup->channels_freeze_count++; + + return TRUE; +} + +gboolean +gimp_plug_in_cleanup_channels_thaw (GimpPlugIn *plug_in, + GimpImage *image) +{ + GimpPlugInProcFrame *proc_frame; + GimpPlugInCleanupImage *cleanup; + + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), FALSE); + g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + cleanup = gimp_plug_in_cleanup_image_get (proc_frame, image); + + if (! cleanup) + return FALSE; + + if (cleanup->channels_freeze_count > 0) + { + cleanup->channels_freeze_count--; + + if (gimp_plug_in_cleanup_image_is_clean (cleanup)) + gimp_plug_in_cleanup_image_free (proc_frame, cleanup); + + return TRUE; + } + + return FALSE; +} + +gboolean +gimp_plug_in_cleanup_vectors_freeze (GimpPlugIn *plug_in, + GimpImage *image) +{ + GimpPlugInProcFrame *proc_frame; + GimpPlugInCleanupImage *cleanup; + + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), FALSE); + g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + cleanup = gimp_plug_in_cleanup_image_get (proc_frame, image); + + if (! cleanup) + cleanup = gimp_plug_in_cleanup_image_new (proc_frame, image); + + cleanup->vectors_freeze_count++; + + return TRUE; +} + +gboolean +gimp_plug_in_cleanup_vectors_thaw (GimpPlugIn *plug_in, + GimpImage *image) +{ + GimpPlugInProcFrame *proc_frame; + GimpPlugInCleanupImage *cleanup; + + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), FALSE); + g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + cleanup = gimp_plug_in_cleanup_image_get (proc_frame, image); + + if (! cleanup) + return FALSE; + + if (cleanup->vectors_freeze_count > 0) + { + cleanup->vectors_freeze_count--; + + if (gimp_plug_in_cleanup_image_is_clean (cleanup)) + gimp_plug_in_cleanup_image_free (proc_frame, cleanup); + + return TRUE; + } + + return FALSE; +} + +gboolean +gimp_plug_in_cleanup_add_shadow (GimpPlugIn *plug_in, + GimpDrawable *drawable) +{ + GimpPlugInProcFrame *proc_frame; + GimpPlugInCleanupItem *cleanup; + + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), FALSE); + g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE); + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + cleanup = gimp_plug_in_cleanup_item_get (proc_frame, GIMP_ITEM (drawable)); + + if (! cleanup) + cleanup = gimp_plug_in_cleanup_item_new (proc_frame, GIMP_ITEM (drawable)); + + cleanup->shadow_buffer = TRUE; + + return TRUE; +} + +gboolean +gimp_plug_in_cleanup_remove_shadow (GimpPlugIn *plug_in, + GimpDrawable *drawable) +{ + GimpPlugInProcFrame *proc_frame; + GimpPlugInCleanupItem *cleanup; + + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), FALSE); + g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE); + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + cleanup = gimp_plug_in_cleanup_item_get (proc_frame, GIMP_ITEM (drawable)); + + if (! cleanup) + return FALSE; + + if (cleanup->shadow_buffer) + { + cleanup->shadow_buffer = FALSE; + + if (gimp_plug_in_cleanup_item_is_clean (cleanup)) + gimp_plug_in_cleanup_item_free (proc_frame, cleanup); + + return TRUE; + } + + return FALSE; +} + +void +gimp_plug_in_cleanup (GimpPlugIn *plug_in, + GimpPlugInProcFrame *proc_frame) +{ + g_return_if_fail (GIMP_IS_PLUG_IN (plug_in)); + g_return_if_fail (proc_frame != NULL); + + while (proc_frame->image_cleanups) + { + GimpPlugInCleanupImage *cleanup = proc_frame->image_cleanups->data; + + if (gimp_image_get_by_ID (plug_in->manager->gimp, + cleanup->image_ID) == cleanup->image) + { + gimp_plug_in_cleanup_image (proc_frame, cleanup); + } + + gimp_plug_in_cleanup_image_free (proc_frame, cleanup); + } + + while (proc_frame->item_cleanups) + { + GimpPlugInCleanupItem *cleanup = proc_frame->item_cleanups->data; + + if (gimp_item_get_by_ID (plug_in->manager->gimp, + cleanup->item_ID) == cleanup->item) + { + gimp_plug_in_cleanup_item (proc_frame, cleanup); + } + + gimp_plug_in_cleanup_item_free (proc_frame, cleanup); + } +} + + +/* private functions */ + +static GimpPlugInCleanupImage * +gimp_plug_in_cleanup_image_new (GimpPlugInProcFrame *proc_frame, + GimpImage *image) +{ + GimpPlugInCleanupImage *cleanup = g_slice_new0 (GimpPlugInCleanupImage); + + cleanup->image = image; + cleanup->image_ID = gimp_image_get_ID (image); + + proc_frame->image_cleanups = g_list_prepend (proc_frame->image_cleanups, + cleanup); + + return cleanup; +} + +static void +gimp_plug_in_cleanup_image_free (GimpPlugInProcFrame *proc_frame, + GimpPlugInCleanupImage *cleanup) +{ + proc_frame->image_cleanups = g_list_remove (proc_frame->image_cleanups, + cleanup); + + g_slice_free (GimpPlugInCleanupImage, cleanup); +} + +static gboolean +gimp_plug_in_cleanup_image_is_clean (GimpPlugInCleanupImage *cleanup) +{ + if (cleanup->undo_group_count > 0) + return FALSE; + + if (cleanup->layers_freeze_count > 0) + return FALSE; + + if (cleanup->channels_freeze_count > 0) + return FALSE; + + if (cleanup->vectors_freeze_count > 0) + return FALSE; + + return TRUE; +} + +static GimpPlugInCleanupImage * +gimp_plug_in_cleanup_image_get (GimpPlugInProcFrame *proc_frame, + GimpImage *image) +{ + GList *list; + + for (list = proc_frame->image_cleanups; list; list = g_list_next (list)) + { + GimpPlugInCleanupImage *cleanup = list->data; + + if (cleanup->image == image) + return cleanup; + } + + return NULL; +} + +static void +gimp_plug_in_cleanup_image (GimpPlugInProcFrame *proc_frame, + GimpPlugInCleanupImage *cleanup) +{ + GimpImage *image = cleanup->image; + GimpContainer *container; + + if (cleanup->undo_group_count > 0) + { + g_message ("Plug-in '%s' left image undo in inconsistent state, " + "closing open undo groups.", + gimp_procedure_get_label (proc_frame->procedure)); + + while (cleanup->undo_group_count--) + if (! gimp_image_undo_group_end (image)) + break; + } + + container = gimp_image_get_layers (image); + + if (cleanup->layers_freeze_count > 0) + { + g_message ("Plug-in '%s' left image's layers frozen, " + "thawing layers.", + gimp_procedure_get_label (proc_frame->procedure)); + + while (cleanup->layers_freeze_count-- > 0 && + gimp_container_frozen (container)) + { + gimp_container_thaw (container); + } + } + + container = gimp_image_get_channels (image); + + if (cleanup->channels_freeze_count > 0) + { + g_message ("Plug-in '%s' left image's channels frozen, " + "thawing channels.", + gimp_procedure_get_label (proc_frame->procedure)); + + while (cleanup->channels_freeze_count-- > 0 && + gimp_container_frozen (container)) + { + gimp_container_thaw (container); + } + } + + container = gimp_image_get_vectors (image); + + if (cleanup->vectors_freeze_count > 0) + { + g_message ("Plug-in '%s' left image's vectors frozen, " + "thawing vectors.", + gimp_procedure_get_label (proc_frame->procedure)); + + while (cleanup->vectors_freeze_count > 0 && + gimp_container_frozen (container)) + { + gimp_container_thaw (container); + } + } +} + +static GimpPlugInCleanupItem * +gimp_plug_in_cleanup_item_new (GimpPlugInProcFrame *proc_frame, + GimpItem *item) +{ + GimpPlugInCleanupItem *cleanup = g_slice_new0 (GimpPlugInCleanupItem); + + cleanup->item = item; + cleanup->item_ID = gimp_item_get_ID (item); + + proc_frame->item_cleanups = g_list_remove (proc_frame->item_cleanups, + cleanup); + + return cleanup; +} + +static void +gimp_plug_in_cleanup_item_free (GimpPlugInProcFrame *proc_frame, + GimpPlugInCleanupItem *cleanup) +{ + proc_frame->item_cleanups = g_list_remove (proc_frame->item_cleanups, + cleanup); + + g_slice_free (GimpPlugInCleanupItem, cleanup); +} + +static gboolean +gimp_plug_in_cleanup_item_is_clean (GimpPlugInCleanupItem *cleanup) +{ + if (cleanup->shadow_buffer) + return FALSE; + + return TRUE; +} + +static GimpPlugInCleanupItem * +gimp_plug_in_cleanup_item_get (GimpPlugInProcFrame *proc_frame, + GimpItem *item) +{ + GList *list; + + for (list = proc_frame->item_cleanups; list; list = g_list_next (list)) + { + GimpPlugInCleanupItem *cleanup = list->data; + + if (cleanup->item == item) + return cleanup; + } + + return NULL; +} + +static void +gimp_plug_in_cleanup_item (GimpPlugInProcFrame *proc_frame, + GimpPlugInCleanupItem *cleanup) +{ + GimpItem *item = cleanup->item; + + if (cleanup->shadow_buffer) + { + GIMP_LOG (SHADOW_TILES, + "Freeing shadow buffer of drawable '%s' on behalf of '%s'.", + gimp_object_get_name (item), + gimp_procedure_get_label (proc_frame->procedure)); + + gimp_drawable_free_shadow_buffer (GIMP_DRAWABLE (item)); + + cleanup->shadow_buffer = FALSE; + } +} diff --git a/app/plug-in/gimpplugin-cleanup.h b/app/plug-in/gimpplugin-cleanup.h new file mode 100644 index 0000000..cb3b22d --- /dev/null +++ b/app/plug-in/gimpplugin-cleanup.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpplugin-cleanup.h + * + * 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/>. + */ + +#ifndef __GIMP_PLUG_IN_CLEANUP_H__ +#define __GIMP_PLUG_IN_CLEANUP_H__ + + +gboolean gimp_plug_in_cleanup_undo_group_start (GimpPlugIn *plug_in, + GimpImage *image); +gboolean gimp_plug_in_cleanup_undo_group_end (GimpPlugIn *plug_in, + GimpImage *image); + +gboolean gimp_plug_in_cleanup_layers_freeze (GimpPlugIn *plug_in, + GimpImage *image); +gboolean gimp_plug_in_cleanup_layers_thaw (GimpPlugIn *plug_in, + GimpImage *image); + +gboolean gimp_plug_in_cleanup_channels_freeze (GimpPlugIn *plug_in, + GimpImage *image); +gboolean gimp_plug_in_cleanup_channels_thaw (GimpPlugIn *plug_in, + GimpImage *image); + +gboolean gimp_plug_in_cleanup_vectors_freeze (GimpPlugIn *plug_in, + GimpImage *image); +gboolean gimp_plug_in_cleanup_vectors_thaw (GimpPlugIn *plug_in, + GimpImage *image); + +gboolean gimp_plug_in_cleanup_add_shadow (GimpPlugIn *plug_in, + GimpDrawable *drawable); +gboolean gimp_plug_in_cleanup_remove_shadow (GimpPlugIn *plug_in, + GimpDrawable *drawable); + +void gimp_plug_in_cleanup (GimpPlugIn *plug_in, + GimpPlugInProcFrame *proc_frame); + + +#endif /* __GIMP_PLUG_IN_CLEANUP_H__ */ diff --git a/app/plug-in/gimpplugin-context.c b/app/plug-in/gimpplugin-context.c new file mode 100644 index 0000000..6817695 --- /dev/null +++ b/app/plug-in/gimpplugin-context.c @@ -0,0 +1,81 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpplugin-context.c + * + * 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" + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "plug-in-types.h" + +#include "core/gimp.h" + +#include "pdb/gimppdbcontext.h" + +#include "gimpplugin.h" +#include "gimpplugin-context.h" +#include "gimppluginmanager.h" + + +gboolean +gimp_plug_in_context_push (GimpPlugIn *plug_in) +{ + GimpPlugInProcFrame *proc_frame; + GimpContext *parent; + GimpContext *context; + + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), FALSE); + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + + if (proc_frame->context_stack) + parent = proc_frame->context_stack->data; + else + parent = proc_frame->main_context; + + context = gimp_pdb_context_new (plug_in->manager->gimp, parent, FALSE); + + proc_frame->context_stack = g_list_prepend (proc_frame->context_stack, + context); + + return TRUE; +} + +gboolean +gimp_plug_in_context_pop (GimpPlugIn *plug_in) +{ + GimpPlugInProcFrame *proc_frame; + + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), FALSE); + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + + if (proc_frame->context_stack) + { + GimpContext *context = proc_frame->context_stack->data; + + proc_frame->context_stack = g_list_remove (proc_frame->context_stack, + context); + g_object_unref (context); + + return TRUE; + } + + return FALSE; +} diff --git a/app/plug-in/gimpplugin-context.h b/app/plug-in/gimpplugin-context.h new file mode 100644 index 0000000..8e46a20 --- /dev/null +++ b/app/plug-in/gimpplugin-context.h @@ -0,0 +1,28 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpplugin-context.h + * + * 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/>. + */ + +#ifndef __GIMP_PLUG_IN_CONTEXT_H__ +#define __GIMP_PLUG_IN_CONTEXT_H__ + + +gboolean gimp_plug_in_context_push (GimpPlugIn *plug_in); +gboolean gimp_plug_in_context_pop (GimpPlugIn *plug_in); + + +#endif /* __GIMP_PLUG_IN_CONTEXT_H__ */ diff --git a/app/plug-in/gimpplugin-message.c b/app/plug-in/gimpplugin-message.c new file mode 100644 index 0000000..b27035e --- /dev/null +++ b/app/plug-in/gimpplugin-message.c @@ -0,0 +1,1063 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpplugin-message.c + * + * 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" + +#include <string.h> + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpbase/gimpbase.h" +#include "libgimpbase/gimpprotocol.h" +#include "libgimpbase/gimpwire.h" + +#include "plug-in-types.h" + +#include "gegl/gimp-babl.h" +#include "gegl/gimp-babl-compat.h" +#include "gegl/gimp-gegl-tile-compat.h" + +#include "core/gimp.h" +#include "core/gimpdrawable.h" +#include "core/gimpdrawable-shadow.h" + +#include "pdb/gimp-pdb-compat.h" +#include "pdb/gimppdb.h" +#include "pdb/gimppdberror.h" + +#include "gimpplugin.h" +#include "gimpplugin-cleanup.h" +#include "gimpplugin-message.h" +#include "gimppluginmanager.h" +#include "gimpplugindef.h" +#include "gimppluginshm.h" +#include "gimptemporaryprocedure.h" +#include "plug-in-params.h" + +#include "gimp-intl.h" + + +/* local function prototypes */ + +static void gimp_plug_in_handle_quit (GimpPlugIn *plug_in); +static void gimp_plug_in_handle_tile_request (GimpPlugIn *plug_in, + GPTileReq *request); +static void gimp_plug_in_handle_tile_put (GimpPlugIn *plug_in, + GPTileReq *request); +static void gimp_plug_in_handle_tile_get (GimpPlugIn *plug_in, + GPTileReq *request); +static void gimp_plug_in_handle_proc_run (GimpPlugIn *plug_in, + GPProcRun *proc_run); +static void gimp_plug_in_handle_proc_return (GimpPlugIn *plug_in, + GPProcReturn *proc_return); +static void gimp_plug_in_handle_temp_proc_return (GimpPlugIn *plug_in, + GPProcReturn *proc_return); +static void gimp_plug_in_handle_proc_install (GimpPlugIn *plug_in, + GPProcInstall *proc_install); +static void gimp_plug_in_handle_proc_uninstall (GimpPlugIn *plug_in, + GPProcUninstall *proc_uninstall); +static void gimp_plug_in_handle_extension_ack (GimpPlugIn *plug_in); +static void gimp_plug_in_handle_has_init (GimpPlugIn *plug_in); + + +/* public functions */ + +void +gimp_plug_in_handle_message (GimpPlugIn *plug_in, + GimpWireMessage *msg) +{ + g_return_if_fail (GIMP_IS_PLUG_IN (plug_in)); + g_return_if_fail (plug_in->open == TRUE); + g_return_if_fail (msg != NULL); + + switch (msg->type) + { + case GP_QUIT: + gimp_plug_in_handle_quit (plug_in); + break; + + case GP_CONFIG: + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n\n" + "sent a CONFIG message. This should not happen.", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file)); + gimp_plug_in_close (plug_in, TRUE); + break; + + case GP_TILE_REQ: + gimp_plug_in_handle_tile_request (plug_in, msg->data); + break; + + case GP_TILE_ACK: + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n\n" + "sent a TILE_ACK message. This should not happen.", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file)); + gimp_plug_in_close (plug_in, TRUE); + break; + + case GP_TILE_DATA: + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n\n" + "sent a TILE_DATA message. This should not happen.", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file)); + gimp_plug_in_close (plug_in, TRUE); + break; + + case GP_PROC_RUN: + gimp_plug_in_handle_proc_run (plug_in, msg->data); + break; + + case GP_PROC_RETURN: + gimp_plug_in_handle_proc_return (plug_in, msg->data); + break; + + case GP_TEMP_PROC_RUN: + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n\n" + "sent a TEMP_PROC_RUN message. This should not happen.", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file)); + gimp_plug_in_close (plug_in, TRUE); + break; + + case GP_TEMP_PROC_RETURN: + gimp_plug_in_handle_temp_proc_return (plug_in, msg->data); + break; + + case GP_PROC_INSTALL: + gimp_plug_in_handle_proc_install (plug_in, msg->data); + break; + + case GP_PROC_UNINSTALL: + gimp_plug_in_handle_proc_uninstall (plug_in, msg->data); + break; + + case GP_EXTENSION_ACK: + gimp_plug_in_handle_extension_ack (plug_in); + break; + + case GP_HAS_INIT: + gimp_plug_in_handle_has_init (plug_in); + break; + } +} + + +/* private functions */ + +static void +gimp_plug_in_handle_quit (GimpPlugIn *plug_in) +{ + gimp_plug_in_close (plug_in, FALSE); +} + +static void +gimp_plug_in_handle_tile_request (GimpPlugIn *plug_in, + GPTileReq *request) +{ + g_return_if_fail (request != NULL); + + if (request->drawable_ID == -1) + gimp_plug_in_handle_tile_put (plug_in, request); + else + gimp_plug_in_handle_tile_get (plug_in, request); +} + +static void +gimp_plug_in_handle_tile_put (GimpPlugIn *plug_in, + GPTileReq *request) +{ + GPTileData tile_data; + GPTileData *tile_info; + GimpWireMessage msg; + GimpDrawable *drawable; + GeglBuffer *buffer; + const Babl *format; + GeglRectangle tile_rect; + + tile_data.drawable_ID = -1; + tile_data.tile_num = 0; + tile_data.shadow = 0; + tile_data.bpp = 0; + tile_data.width = 0; + tile_data.height = 0; + tile_data.use_shm = (plug_in->manager->shm != NULL); + tile_data.data = NULL; + + if (! gp_tile_data_write (plug_in->my_write, &tile_data, plug_in)) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "%s: ERROR", G_STRFUNC); + gimp_plug_in_close (plug_in, TRUE); + return; + } + + if (! gimp_wire_read_msg (plug_in->my_read, &msg, plug_in)) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "%s: ERROR", G_STRFUNC); + gimp_plug_in_close (plug_in, TRUE); + return; + } + + if (msg.type != GP_TILE_DATA) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "expected tile data and received: %d", msg.type); + gimp_plug_in_close (plug_in, TRUE); + return; + } + + tile_info = msg.data; + + drawable = (GimpDrawable *) gimp_item_get_by_ID (plug_in->manager->gimp, + tile_info->drawable_ID); + + if (! GIMP_IS_DRAWABLE (drawable)) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n\n" + "tried writing to invalid drawable %d (killing)", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + tile_info->drawable_ID); + gimp_plug_in_close (plug_in, TRUE); + return; + } + else if (gimp_item_is_removed (GIMP_ITEM (drawable))) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n\n" + "tried writing to drawable %d which was removed " + "from the image (killing)", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + tile_info->drawable_ID); + gimp_plug_in_close (plug_in, TRUE); + return; + } + + if (tile_info->shadow) + { + + /* don't check whether the drawable is a group or locked here, + * the plugin will get a proper error message when it tries to + * merge the shadow tiles, which is much better than just + * killing it. + */ + buffer = gimp_drawable_get_shadow_buffer (drawable); + + gimp_plug_in_cleanup_add_shadow (plug_in, drawable); + } + else + { + if (gimp_item_is_content_locked (GIMP_ITEM (drawable))) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n\n" + "tried writing to a locked drawable %d (killing)", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + tile_info->drawable_ID); + gimp_plug_in_close (plug_in, TRUE); + return; + } + else if (gimp_viewable_get_children (GIMP_VIEWABLE (drawable))) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n\n" + "tried writing to a group layer %d (killing)", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + tile_info->drawable_ID); + gimp_plug_in_close (plug_in, TRUE); + return; + } + + buffer = gimp_drawable_get_buffer (drawable); + } + + if (! gimp_gegl_buffer_get_tile_rect (buffer, + GIMP_PLUG_IN_TILE_WIDTH, + GIMP_PLUG_IN_TILE_HEIGHT, + tile_info->tile_num, + &tile_rect)) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n\n" + "requested invalid tile (killing)", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file)); + gimp_plug_in_close (plug_in, TRUE); + return; + } + + format = gegl_buffer_get_format (buffer); + + if (! gimp_plug_in_precision_enabled (plug_in)) + { + format = gimp_babl_compat_u8_format (format); + } + + if (tile_data.use_shm) + { + gegl_buffer_set (buffer, &tile_rect, 0, format, + gimp_plug_in_shm_get_addr (plug_in->manager->shm), + GEGL_AUTO_ROWSTRIDE); + } + else + { + gegl_buffer_set (buffer, &tile_rect, 0, format, + tile_info->data, + GEGL_AUTO_ROWSTRIDE); + } + + gimp_wire_destroy (&msg); + + if (! gp_tile_ack_write (plug_in->my_write, plug_in)) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "%s: ERROR", G_STRFUNC); + gimp_plug_in_close (plug_in, TRUE); + return; + } +} + +static void +gimp_plug_in_handle_tile_get (GimpPlugIn *plug_in, + GPTileReq *request) +{ + GPTileData tile_data; + GimpWireMessage msg; + GimpDrawable *drawable; + GeglBuffer *buffer; + const Babl *format; + GeglRectangle tile_rect; + gint tile_size; + + drawable = (GimpDrawable *) gimp_item_get_by_ID (plug_in->manager->gimp, + request->drawable_ID); + + if (! GIMP_IS_DRAWABLE (drawable)) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n\n" + "tried reading from invalid drawable %d (killing)", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + request->drawable_ID); + gimp_plug_in_close (plug_in, TRUE); + return; + } + else if (gimp_item_is_removed (GIMP_ITEM (drawable))) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n\n" + "tried reading from drawable %d which was removed " + "from the image (killing)", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + request->drawable_ID); + gimp_plug_in_close (plug_in, TRUE); + return; + } + + if (request->shadow) + { + buffer = gimp_drawable_get_shadow_buffer (drawable); + + gimp_plug_in_cleanup_add_shadow (plug_in, drawable); + } + else + { + buffer = gimp_drawable_get_buffer (drawable); + } + + if (! gimp_gegl_buffer_get_tile_rect (buffer, + GIMP_PLUG_IN_TILE_WIDTH, + GIMP_PLUG_IN_TILE_HEIGHT, + request->tile_num, + &tile_rect)) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n\n" + "requested invalid tile (killing)", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file)); + gimp_plug_in_close (plug_in, TRUE); + return; + } + + format = gegl_buffer_get_format (buffer); + + if (! gimp_plug_in_precision_enabled (plug_in)) + { + format = gimp_babl_compat_u8_format (format); + } + + tile_size = (babl_format_get_bytes_per_pixel (format) * + tile_rect.width * tile_rect.height); + + tile_data.drawable_ID = request->drawable_ID; + tile_data.tile_num = request->tile_num; + tile_data.shadow = request->shadow; + tile_data.bpp = babl_format_get_bytes_per_pixel (format); + tile_data.width = tile_rect.width; + tile_data.height = tile_rect.height; + tile_data.use_shm = (plug_in->manager->shm != NULL); + + if (tile_data.use_shm) + { + gegl_buffer_get (buffer, &tile_rect, 1.0, format, + gimp_plug_in_shm_get_addr (plug_in->manager->shm), + GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); + } + else + { + tile_data.data = g_malloc (tile_size); + + gegl_buffer_get (buffer, &tile_rect, 1.0, format, + tile_data.data, + GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); + } + + if (! gp_tile_data_write (plug_in->my_write, &tile_data, plug_in)) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "%s: ERROR", G_STRFUNC); + gimp_plug_in_close (plug_in, TRUE); + return; + } + + if (! gimp_wire_read_msg (plug_in->my_read, &msg, plug_in)) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "%s: ERROR", G_STRFUNC); + gimp_plug_in_close (plug_in, TRUE); + return; + } + + if (msg.type != GP_TILE_ACK) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "expected tile ack and received: %d", msg.type); + gimp_plug_in_close (plug_in, TRUE); + return; + } + + gimp_wire_destroy (&msg); +} + +static void +gimp_plug_in_handle_proc_error (GimpPlugIn *plug_in, + GimpPlugInProcFrame *proc_frame, + const gchar *name, + const GError *error) +{ + switch (proc_frame->error_handler) + { + case GIMP_PDB_ERROR_HANDLER_INTERNAL: + if (error->domain == GIMP_PDB_ERROR) + { + gimp_message (plug_in->manager->gimp, + G_OBJECT (proc_frame->progress), + GIMP_MESSAGE_ERROR, + _("Calling error for procedure '%s':\n" + "%s"), + name, error->message); + } + else + { + gimp_message (plug_in->manager->gimp, + G_OBJECT (proc_frame->progress), + GIMP_MESSAGE_ERROR, + _("Execution error for procedure '%s':\n" + "%s"), + name, error->message); + } + break; + + case GIMP_PDB_ERROR_HANDLER_PLUGIN: + /* the plug-in is responsible for handling this error */ + break; + } +} + +static void +gimp_plug_in_handle_proc_run (GimpPlugIn *plug_in, + GPProcRun *proc_run) +{ + GimpPlugInProcFrame *proc_frame; + gchar *canonical; + const gchar *proc_name = NULL; + GimpProcedure *procedure; + GimpValueArray *args = NULL; + GimpValueArray *return_vals = NULL; + GError *error = NULL; + + g_return_if_fail (proc_run != NULL); + g_return_if_fail (proc_run->name != NULL); + + canonical = gimp_canonicalize_identifier (proc_run->name); + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + + procedure = gimp_pdb_lookup_procedure (plug_in->manager->gimp->pdb, + canonical); + + if (! procedure) + { + proc_name = gimp_pdb_lookup_compat_proc_name (plug_in->manager->gimp->pdb, + canonical); + + if (proc_name) + { + procedure = gimp_pdb_lookup_procedure (plug_in->manager->gimp->pdb, + proc_name); + + if (plug_in->manager->gimp->pdb_compat_mode == GIMP_PDB_COMPAT_WARN) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_WARNING, + "Plug-in \"%s\"\n(%s)\n" + "called deprecated procedure '%s'.\n" + "It should call '%s' instead!", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + canonical, proc_name); + } + } + } + else if (procedure->deprecated) + { + if (plug_in->manager->gimp->pdb_compat_mode == GIMP_PDB_COMPAT_WARN) + { + if (! strcmp (procedure->deprecated, "NONE")) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_WARNING, + "Plug-in \"%s\"\n(%s)\n" + "called deprecated procedure '%s'.", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + canonical); + } + else + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_WARNING, + "WARNING: Plug-in \"%s\"\n(%s)\n" + "called deprecated procedure '%s'.\n" + "It should call '%s' instead!", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + canonical, procedure->deprecated); + } + } + } + + if (! proc_name) + proc_name = canonical; + + args = plug_in_params_to_args (procedure ? procedure->args : NULL, + procedure ? procedure->num_args : 0, + proc_run->params, proc_run->nparams, + FALSE, FALSE); + + /* Execute the procedure even if gimp_pdb_lookup_procedure() + * returned NULL, gimp_pdb_execute_procedure_by_name_args() will + * return appropriate error return_vals. + */ + gimp_plug_in_manager_plug_in_push (plug_in->manager, plug_in); + return_vals = gimp_pdb_execute_procedure_by_name_args (plug_in->manager->gimp->pdb, + proc_frame->context_stack ? + proc_frame->context_stack->data : + proc_frame->main_context, + proc_frame->progress, + &error, + proc_name, + args); + gimp_plug_in_manager_plug_in_pop (plug_in->manager); + + gimp_value_array_unref (args); + + if (error) + { + gimp_plug_in_handle_proc_error (plug_in, proc_frame, + canonical, error); + g_error_free (error); + } + + g_free (canonical); + + /* Don't bother to send the return value if executing the procedure + * closed the plug-in (e.g. if the procedure is gimp-quit) + */ + if (plug_in->open) + { + GPProcReturn proc_return; + + /* Return the name we got called with, *not* proc_name or canonical, + * since proc_name may have been remapped by gimp->procedural_compat_ht + * and canonical may be different too. + */ + proc_return.name = proc_run->name; + proc_return.nparams = gimp_value_array_length (return_vals); + proc_return.params = plug_in_args_to_params (return_vals, FALSE); + + if (! gp_proc_return_write (plug_in->my_write, &proc_return, plug_in)) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "%s: ERROR", G_STRFUNC); + gimp_plug_in_close (plug_in, TRUE); + } + + g_free (proc_return.params); + } + + gimp_value_array_unref (return_vals); +} + +static void +gimp_plug_in_handle_proc_return (GimpPlugIn *plug_in, + GPProcReturn *proc_return) +{ + GimpPlugInProcFrame *proc_frame = &plug_in->main_proc_frame; + + g_return_if_fail (proc_return != NULL); + + proc_frame->return_vals = + plug_in_params_to_args (proc_frame->procedure->values, + proc_frame->procedure->num_values, + proc_return->params, + proc_return->nparams, + TRUE, TRUE); + + if (proc_frame->main_loop) + { + g_main_loop_quit (proc_frame->main_loop); + } + else + { + /* the plug-in is run asynchronously, so display its error + * messages here because nobody else will do it + */ + gimp_plug_in_procedure_handle_return_values (GIMP_PLUG_IN_PROCEDURE (proc_frame->procedure), + plug_in->manager->gimp, + proc_frame->progress, + proc_frame->return_vals); + } + + gimp_plug_in_close (plug_in, FALSE); +} + +static void +gimp_plug_in_handle_temp_proc_return (GimpPlugIn *plug_in, + GPProcReturn *proc_return) +{ + g_return_if_fail (proc_return != NULL); + + if (plug_in->temp_proc_frames) + { + GimpPlugInProcFrame *proc_frame = plug_in->temp_proc_frames->data; + + proc_frame->return_vals = + plug_in_params_to_args (proc_frame->procedure->values, + proc_frame->procedure->num_values, + proc_return->params, + proc_return->nparams, + TRUE, TRUE); + + gimp_plug_in_main_loop_quit (plug_in); + gimp_plug_in_proc_frame_pop (plug_in); + } + else + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n\n" + "sent a TEMP_PROC_RETURN message while not running " + "a temporary procedure. This should not happen.", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file)); + gimp_plug_in_close (plug_in, TRUE); + } +} + +static void +gimp_plug_in_handle_proc_install (GimpPlugIn *plug_in, + GPProcInstall *proc_install) +{ + GimpPlugInProcedure *proc = NULL; + GimpProcedure *procedure = NULL; + gchar *canonical; + gboolean null_name = FALSE; + gboolean valid_utf8 = FALSE; + gint i; + + g_return_if_fail (proc_install != NULL); + g_return_if_fail (proc_install->name != NULL); + + canonical = gimp_canonicalize_identifier (proc_install->name); + + /* Sanity check for array arguments */ + + for (i = 1; i < proc_install->nparams; i++) + { + if ((proc_install->params[i].type == GIMP_PDB_INT32ARRAY || + proc_install->params[i].type == GIMP_PDB_INT8ARRAY || + proc_install->params[i].type == GIMP_PDB_FLOATARRAY || + proc_install->params[i].type == GIMP_PDB_STRINGARRAY || + proc_install->params[i].type == GIMP_PDB_COLORARRAY) + && + proc_install->params[i - 1].type != GIMP_PDB_INT32) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n\n" + "attempted to install procedure \"%s\" " + "which fails to comply with the array parameter " + "passing standard. Argument %d is noncompliant.", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + canonical, i); + g_free (canonical); + return; + } + } + + /* Sanity check strings for UTF-8 validity */ + +#define VALIDATE(str) (g_utf8_validate ((str), -1, NULL)) +#define VALIDATE_OR_NULL(str) ((str) == NULL || g_utf8_validate ((str), -1, NULL)) + + if (VALIDATE_OR_NULL (proc_install->menu_path) && + VALIDATE (canonical) && + VALIDATE_OR_NULL (proc_install->blurb) && + VALIDATE_OR_NULL (proc_install->help) && + VALIDATE_OR_NULL (proc_install->author) && + VALIDATE_OR_NULL (proc_install->copyright) && + VALIDATE_OR_NULL (proc_install->date)) + { + null_name = FALSE; + valid_utf8 = TRUE; + + for (i = 0; i < proc_install->nparams && valid_utf8 && !null_name; i++) + { + if (! proc_install->params[i].name) + { + null_name = TRUE; + } + else if (! (VALIDATE (proc_install->params[i].name) && + VALIDATE_OR_NULL (proc_install->params[i].description))) + { + valid_utf8 = FALSE; + } + } + + for (i = 0; i < proc_install->nreturn_vals && valid_utf8 && !null_name; i++) + { + if (! proc_install->return_vals[i].name) + { + null_name = TRUE; + } + else if (! (VALIDATE (proc_install->return_vals[i].name) && + VALIDATE_OR_NULL (proc_install->return_vals[i].description))) + { + valid_utf8 = FALSE; + } + } + } + +#undef VALIDATE +#undef VALIDATE_OR_NULL + + if (null_name) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n\n" + "attempted to install procedure \"%s\" with a " + "NULL parameter name.", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + canonical); + g_free (canonical); + return; + } + + if (! valid_utf8) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n\n" + "attempted to install procedure \"%s\" with " + "invalid UTF-8 strings.", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + canonical); + g_free (canonical); + return; + } + + if (proc_install->menu_path && strlen (proc_install->menu_path) && + proc_install->menu_path[0] == '<') + { + g_printerr ("Plug-in \"%s\"\n(%s) " + "is installing procedure \"%s\" with a full " + "menu path \"%s\" as menu label, this deprecated and will " + "be an error in GIMP 3.0\n", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + canonical, + proc_install->menu_path); + } + + /* Create the procedure object */ + + switch (proc_install->type) + { + case GIMP_PLUGIN: + case GIMP_EXTENSION: + procedure = gimp_plug_in_procedure_new (proc_install->type, + plug_in->file); + break; + + case GIMP_TEMPORARY: + procedure = gimp_temporary_procedure_new (plug_in); + break; + } + + proc = GIMP_PLUG_IN_PROCEDURE (procedure); + + proc->mtime = time (NULL); + proc->installed_during_init = (plug_in->call_mode == GIMP_PLUG_IN_CALL_INIT); + + gimp_object_take_name (GIMP_OBJECT (procedure), canonical); + gimp_procedure_set_strings (procedure, + proc_install->name, + proc_install->blurb, + proc_install->help, + proc_install->author, + proc_install->copyright, + proc_install->date, + NULL); + + gimp_plug_in_procedure_set_image_types (proc, proc_install->image_types); + + for (i = 0; i < proc_install->nparams; i++) + { + GParamSpec *pspec; + gboolean name_valid; + + pspec = gimp_pdb_compat_param_spec (plug_in->manager->gimp, + proc_install->params[i].type, + proc_install->params[i].name, + proc_install->params[i].description, + &name_valid); + + gimp_procedure_add_argument (procedure, pspec); + + if (pspec && ! name_valid) + { + switch (plug_in->manager->gimp->pdb_compat_mode) + { + case GIMP_PDB_COMPAT_ON: + break; + + case GIMP_PDB_COMPAT_WARN: + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_WARNING, + "Plug-in \"%s\"\n(%s)\n" + "attempted to install procedure \"%s\" " + "with invalid parameter name \"%s\".\n" + "This is deprecated.\n" + "The parameter name was changed to \"%s\".", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + gimp_object_get_name (proc), + proc_install->params[i].name, + pspec->name); + break; + + case GIMP_PDB_COMPAT_OFF: + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n" + "attempted to install procedure \"%s\" " + "with invalid parameter name \"%s\".\n" + "This is not allowed.", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + gimp_object_get_name (proc), + proc_install->params[i].name); + + g_object_unref (proc); + + return; + } + } + } + + for (i = 0; i < proc_install->nreturn_vals; i++) + { + GParamSpec *pspec; + gboolean name_valid; + + pspec = gimp_pdb_compat_param_spec (plug_in->manager->gimp, + proc_install->return_vals[i].type, + proc_install->return_vals[i].name, + proc_install->return_vals[i].description, + &name_valid); + + gimp_procedure_add_return_value (procedure, pspec); + + if (pspec && ! name_valid) + { + switch (plug_in->manager->gimp->pdb_compat_mode) + { + case GIMP_PDB_COMPAT_ON: + break; + + case GIMP_PDB_COMPAT_WARN: + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_WARNING, + "Plug-in \"%s\"\n(%s)\n" + "attempted to install procedure \"%s\" " + "with invalid return-value name \"%s\".\n" + "This is deprecated.\n" + "The return-value name was changed to \"%s\".", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + gimp_object_get_name (proc), + proc_install->return_vals[i].name, + pspec->name); + break; + + case GIMP_PDB_COMPAT_OFF: + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n" + "attempted to install procedure \"%s\" " + "with invalid return-value name \"%s\".\n" + "This is not allowed.", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + gimp_object_get_name (proc), + proc_install->return_vals[i].name); + + g_object_unref (proc); + + return; + } + } + } + + /* Sanity check menu path */ + + if (proc_install->menu_path && strlen (proc_install->menu_path)) + { + if (proc_install->menu_path[0] == '<') + { + GError *error = NULL; + + if (! gimp_plug_in_procedure_add_menu_path (proc, + proc_install->menu_path, + &error)) + { + gimp_message_literal (plug_in->manager->gimp, + NULL, GIMP_MESSAGE_WARNING, + error->message); + g_clear_error (&error); + } + } + else + { + proc->menu_label = g_strdup (proc_install->menu_path); + } + } + + /* Install the procedure */ + + switch (proc_install->type) + { + case GIMP_PLUGIN: + case GIMP_EXTENSION: + gimp_plug_in_def_add_procedure (plug_in->plug_in_def, proc); + break; + + case GIMP_TEMPORARY: + gimp_plug_in_add_temp_proc (plug_in, GIMP_TEMPORARY_PROCEDURE (proc)); + break; + } + + g_object_unref (proc); +} + +static void +gimp_plug_in_handle_proc_uninstall (GimpPlugIn *plug_in, + GPProcUninstall *proc_uninstall) +{ + GimpPlugInProcedure *proc; + gchar *canonical; + + g_return_if_fail (proc_uninstall != NULL); + g_return_if_fail (proc_uninstall->name != NULL); + + canonical = gimp_canonicalize_identifier (proc_uninstall->name); + + proc = gimp_plug_in_procedure_find (plug_in->temp_procedures, canonical); + + if (proc) + gimp_plug_in_remove_temp_proc (plug_in, GIMP_TEMPORARY_PROCEDURE (proc)); + + g_free (canonical); +} + +static void +gimp_plug_in_handle_extension_ack (GimpPlugIn *plug_in) +{ + if (plug_in->ext_main_loop) + { + g_main_loop_quit (plug_in->ext_main_loop); + } + else + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n\n" + "sent an EXTENSION_ACK message while not being started " + "as an extension. This should not happen.", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file)); + gimp_plug_in_close (plug_in, TRUE); + } +} + +static void +gimp_plug_in_handle_has_init (GimpPlugIn *plug_in) +{ + if (plug_in->call_mode == GIMP_PLUG_IN_CALL_QUERY) + { + gimp_plug_in_def_set_has_init (plug_in->plug_in_def, TRUE); + } + else + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n\n" + "sent an HAS_INIT message while not in query(). " + "This should not happen.", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file)); + gimp_plug_in_close (plug_in, TRUE); + } +} diff --git a/app/plug-in/gimpplugin-message.h b/app/plug-in/gimpplugin-message.h new file mode 100644 index 0000000..1dd301f --- /dev/null +++ b/app/plug-in/gimpplugin-message.h @@ -0,0 +1,28 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpplugin-message.h + * + * 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/>. + */ + +#ifndef __GIMP_PLUG_IN_MESSAGE_H__ +#define __GIMP_PLUG_IN_MESSAGE_H__ + + +void gimp_plug_in_handle_message (GimpPlugIn *plug_in, + GimpWireMessage *msg); + + +#endif /* __GIMP_PLUG_IN_MESSAGE_H__ */ diff --git a/app/plug-in/gimpplugin-progress.c b/app/plug-in/gimpplugin-progress.c new file mode 100644 index 0000000..ddf2ef5 --- /dev/null +++ b/app/plug-in/gimpplugin-progress.c @@ -0,0 +1,366 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpplugin-progress.c + * + * 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" + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "plug-in-types.h" + +#include "core/gimp.h" +#include "core/gimpparamspecs.h" +#include "core/gimppdbprogress.h" +#include "core/gimpprogress.h" + +#include "pdb/gimppdb.h" +#include "pdb/gimppdberror.h" + +#include "gimpplugin.h" +#include "gimpplugin-progress.h" +#include "gimppluginmanager.h" +#include "gimptemporaryprocedure.h" + +#include "gimp-intl.h" + + +/* local function prototypes */ + +static void gimp_plug_in_progress_cancel_callback (GimpProgress *progress, + GimpPlugIn *plug_in); + + +/* public functions */ + +gint +gimp_plug_in_progress_attach (GimpProgress *progress) +{ + gint attach_count; + + g_return_val_if_fail (GIMP_IS_PROGRESS (progress), 0); + + attach_count = + GPOINTER_TO_INT (g_object_get_data (G_OBJECT (progress), + "plug-in-progress-attach-count")); + + attach_count++; + + g_object_set_data (G_OBJECT (progress), "plug-in-progress-attach-count", + GINT_TO_POINTER (attach_count)); + + return attach_count; +} + +gint +gimp_plug_in_progress_detach (GimpProgress *progress) +{ + gint attach_count; + + g_return_val_if_fail (GIMP_IS_PROGRESS (progress), 0); + + attach_count = + GPOINTER_TO_INT (g_object_get_data (G_OBJECT (progress), + "plug-in-progress-attach-count")); + + attach_count--; + + g_object_set_data (G_OBJECT (progress), "plug-in-progress-attach-count", + GINT_TO_POINTER (attach_count)); + + return attach_count; +} + +void +gimp_plug_in_progress_start (GimpPlugIn *plug_in, + const gchar *message, + GimpObject *display) +{ + GimpPlugInProcFrame *proc_frame; + + g_return_if_fail (GIMP_IS_PLUG_IN (plug_in)); + g_return_if_fail (display == NULL || GIMP_IS_OBJECT (display)); + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + + if (! proc_frame->progress) + { + proc_frame->progress = gimp_new_progress (plug_in->manager->gimp, + display); + + if (proc_frame->progress) + { + proc_frame->progress_created = TRUE; + + g_object_ref (proc_frame->progress); + + gimp_plug_in_progress_attach (proc_frame->progress); + } + } + + if (proc_frame->progress) + { + if (! proc_frame->progress_cancel_id) + { + g_object_add_weak_pointer (G_OBJECT (proc_frame->progress), + (gpointer) &proc_frame->progress); + + proc_frame->progress_cancel_id = + g_signal_connect (proc_frame->progress, "cancel", + G_CALLBACK (gimp_plug_in_progress_cancel_callback), + plug_in); + } + + if (gimp_progress_is_active (proc_frame->progress)) + { + if (message) + gimp_progress_set_text_literal (proc_frame->progress, message); + + if (gimp_progress_get_value (proc_frame->progress) > 0.0) + gimp_progress_set_value (proc_frame->progress, 0.0); + } + else + { + gimp_progress_start (proc_frame->progress, TRUE, + "%s", message ? message : ""); + } + } +} + +void +gimp_plug_in_progress_end (GimpPlugIn *plug_in, + GimpPlugInProcFrame *proc_frame) +{ + g_return_if_fail (GIMP_IS_PLUG_IN (plug_in)); + g_return_if_fail (proc_frame != NULL); + + if (proc_frame->progress) + { + if (proc_frame->progress_cancel_id) + { + g_signal_handler_disconnect (proc_frame->progress, + proc_frame->progress_cancel_id); + proc_frame->progress_cancel_id = 0; + + g_object_remove_weak_pointer (G_OBJECT (proc_frame->progress), + (gpointer) &proc_frame->progress); + } + + if (gimp_plug_in_progress_detach (proc_frame->progress) < 1 && + gimp_progress_is_active (proc_frame->progress)) + { + gimp_progress_end (proc_frame->progress); + } + + if (proc_frame->progress_created) + { + gimp_free_progress (plug_in->manager->gimp, proc_frame->progress); + g_clear_object (&proc_frame->progress); + } + } +} + +void +gimp_plug_in_progress_set_text (GimpPlugIn *plug_in, + const gchar *message) +{ + GimpPlugInProcFrame *proc_frame; + + g_return_if_fail (GIMP_IS_PLUG_IN (plug_in)); + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + + if (proc_frame->progress) + gimp_progress_set_text_literal (proc_frame->progress, message); +} + +void +gimp_plug_in_progress_set_value (GimpPlugIn *plug_in, + gdouble percentage) +{ + GimpPlugInProcFrame *proc_frame; + + g_return_if_fail (GIMP_IS_PLUG_IN (plug_in)); + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + + if (! proc_frame->progress || + ! gimp_progress_is_active (proc_frame->progress) || + ! proc_frame->progress_cancel_id) + { + gimp_plug_in_progress_start (plug_in, NULL, NULL); + } + + if (proc_frame->progress && gimp_progress_is_active (proc_frame->progress)) + gimp_progress_set_value (proc_frame->progress, percentage); +} + +void +gimp_plug_in_progress_pulse (GimpPlugIn *plug_in) +{ + GimpPlugInProcFrame *proc_frame; + + g_return_if_fail (GIMP_IS_PLUG_IN (plug_in)); + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + + if (! proc_frame->progress || + ! gimp_progress_is_active (proc_frame->progress) || + ! proc_frame->progress_cancel_id) + { + gimp_plug_in_progress_start (plug_in, NULL, NULL); + } + + if (proc_frame->progress && gimp_progress_is_active (proc_frame->progress)) + gimp_progress_pulse (proc_frame->progress); +} + +guint32 +gimp_plug_in_progress_get_window_id (GimpPlugIn *plug_in) +{ + GimpPlugInProcFrame *proc_frame; + + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), 0); + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + + if (proc_frame->progress) + return gimp_progress_get_window_id (proc_frame->progress); + + return 0; +} + +gboolean +gimp_plug_in_progress_install (GimpPlugIn *plug_in, + const gchar *progress_callback) +{ + GimpPlugInProcFrame *proc_frame; + GimpProcedure *procedure; + + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), FALSE); + g_return_val_if_fail (progress_callback != NULL, FALSE); + + procedure = gimp_pdb_lookup_procedure (plug_in->manager->gimp->pdb, + progress_callback); + + if (! GIMP_IS_TEMPORARY_PROCEDURE (procedure) || + GIMP_TEMPORARY_PROCEDURE (procedure)->plug_in != plug_in || + procedure->num_args != 3 || + ! GIMP_IS_PARAM_SPEC_INT32 (procedure->args[0]) || + ! G_IS_PARAM_SPEC_STRING (procedure->args[1]) || + ! G_IS_PARAM_SPEC_DOUBLE (procedure->args[2])) + { + return FALSE; + } + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + + if (proc_frame->progress) + { + gimp_plug_in_progress_end (plug_in, proc_frame); + + g_clear_object (&proc_frame->progress); + } + + proc_frame->progress = g_object_new (GIMP_TYPE_PDB_PROGRESS, + "pdb", plug_in->manager->gimp->pdb, + "context", proc_frame->main_context, + "callback-name", progress_callback, + NULL); + + gimp_plug_in_progress_attach (proc_frame->progress); + + return TRUE; +} + +gboolean +gimp_plug_in_progress_uninstall (GimpPlugIn *plug_in, + const gchar *progress_callback) +{ + GimpPlugInProcFrame *proc_frame; + + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), FALSE); + g_return_val_if_fail (progress_callback != NULL, FALSE); + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + + if (GIMP_IS_PDB_PROGRESS (proc_frame->progress)) + { + gimp_plug_in_progress_end (plug_in, proc_frame); + + g_clear_object (&proc_frame->progress); + + return TRUE; + } + + return FALSE; +} + +gboolean +gimp_plug_in_progress_cancel (GimpPlugIn *plug_in, + const gchar *progress_callback) +{ + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), FALSE); + g_return_val_if_fail (progress_callback != NULL, FALSE); + + return FALSE; +} + + +/* private functions */ + +static GimpValueArray * +get_cancel_return_values (GimpProcedure *procedure) +{ + GimpValueArray *return_vals; + GError *error; + + error = g_error_new_literal (GIMP_PDB_ERROR, GIMP_PDB_ERROR_CANCELLED, + _("Cancelled")); + return_vals = gimp_procedure_get_return_values (procedure, FALSE, error); + g_error_free (error); + + return return_vals; +} + +static void +gimp_plug_in_progress_cancel_callback (GimpProgress *progress, + GimpPlugIn *plug_in) +{ + GimpPlugInProcFrame *proc_frame = &plug_in->main_proc_frame; + GList *list; + + if (proc_frame->main_loop) + { + proc_frame->return_vals = + get_cancel_return_values (proc_frame->procedure); + } + + for (list = plug_in->temp_proc_frames; list; list = g_list_next (list)) + { + proc_frame = list->data; + + if (proc_frame->main_loop) + { + proc_frame->return_vals = + get_cancel_return_values (proc_frame->procedure); + } + } + + gimp_plug_in_close (plug_in, TRUE); +} diff --git a/app/plug-in/gimpplugin-progress.h b/app/plug-in/gimpplugin-progress.h new file mode 100644 index 0000000..56e5285 --- /dev/null +++ b/app/plug-in/gimpplugin-progress.h @@ -0,0 +1,47 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpplugin-progress.h + * + * 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/>. + */ + +#ifndef __GIMP_PLUG_IN_PROGRESS_H__ +#define __GIMP_PLUG_IN_PROGRESS_H__ + + +gint gimp_plug_in_progress_attach (GimpProgress *progress); +gint gimp_plug_in_progress_detach (GimpProgress *progress); + +void gimp_plug_in_progress_start (GimpPlugIn *plug_in, + const gchar *message, + GimpObject *display); +void gimp_plug_in_progress_end (GimpPlugIn *plug_in, + GimpPlugInProcFrame *proc_frame); +void gimp_plug_in_progress_set_text (GimpPlugIn *plug_in, + const gchar *message); +void gimp_plug_in_progress_set_value (GimpPlugIn *plug_in, + gdouble percentage); +void gimp_plug_in_progress_pulse (GimpPlugIn *plug_in); +guint32 gimp_plug_in_progress_get_window_id (GimpPlugIn *plug_in); + +gboolean gimp_plug_in_progress_install (GimpPlugIn *plug_in, + const gchar *progress_callback); +gboolean gimp_plug_in_progress_uninstall (GimpPlugIn *plug_in, + const gchar *progress_callback); +gboolean gimp_plug_in_progress_cancel (GimpPlugIn *plug_in, + const gchar *progress_callback); + + +#endif /* __GIMP_PLUG_IN_PROGRESS_H__ */ diff --git a/app/plug-in/gimpplugin.c b/app/plug-in/gimpplugin.c new file mode 100644 index 0000000..fc18486 --- /dev/null +++ b/app/plug-in/gimpplugin.c @@ -0,0 +1,1060 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpplugin.c + * + * 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" + +#ifndef _WIN32 +#define _GNU_SOURCE +#endif + +#include <errno.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif + +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN) + +#define STRICT +#include <windows.h> +#include <process.h> + +#ifdef G_OS_WIN32 +#include <fcntl.h> +#include <io.h> + +#ifndef pipe +#define pipe(fds) _pipe(fds, 4096, _O_BINARY) +#endif + +#endif + +#ifdef G_WITH_CYGWIN +#define O_TEXT 0x0100 /* text file */ +#define _O_TEXT 0x0100 /* text file */ +#define O_BINARY 0x0200 /* binary file */ +#define _O_BINARY 0x0200 /* binary file */ +#endif + +#endif /* G_OS_WIN32 || G_WITH_CYGWIN */ + +#include "libgimpbase/gimpbase.h" +#include "libgimpbase/gimpprotocol.h" +#include "libgimpbase/gimpwire.h" + +#include "plug-in-types.h" + +#include "core/gimp.h" +#include "core/gimp-spawn.h" +#include "core/gimpprogress.h" + +#include "pdb/gimppdbcontext.h" + +#include "gimpenvirontable.h" +#include "gimpinterpreterdb.h" +#include "gimpplugin.h" +#include "gimpplugin-message.h" +#include "gimpplugin-progress.h" +#include "gimpplugindebug.h" +#include "gimpplugindef.h" +#include "gimppluginmanager.h" +#include "gimppluginmanager-help-domain.h" +#include "gimppluginmanager-locale-domain.h" +#include "gimptemporaryprocedure.h" +#include "plug-in-params.h" + +#include "gimp-intl.h" + + +static void gimp_plug_in_finalize (GObject *object); + +static gboolean gimp_plug_in_recv_message (GIOChannel *channel, + GIOCondition cond, + gpointer data); +static gboolean gimp_plug_in_write (GIOChannel *channel, + const guint8 *buf, + gulong count, + gpointer data); +static gboolean gimp_plug_in_flush (GIOChannel *channel, + gpointer data); + +#if defined G_OS_WIN32 && defined WIN32_32BIT_DLL_FOLDER +static void gimp_plug_in_set_dll_directory (const gchar *path); +#endif + + + +G_DEFINE_TYPE (GimpPlugIn, gimp_plug_in, GIMP_TYPE_OBJECT) + +#define parent_class gimp_plug_in_parent_class + + +static void +gimp_plug_in_class_init (GimpPlugInClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gimp_plug_in_finalize; + + /* initialize the gimp protocol library and set the read and + * write handlers. + */ + gp_init (); + gimp_wire_set_writer (gimp_plug_in_write); + gimp_wire_set_flusher (gimp_plug_in_flush); +} + +static void +gimp_plug_in_init (GimpPlugIn *plug_in) +{ + plug_in->manager = NULL; + plug_in->file = NULL; + + plug_in->call_mode = GIMP_PLUG_IN_CALL_NONE; + plug_in->open = FALSE; + plug_in->hup = FALSE; + plug_in->pid = 0; + + plug_in->my_read = NULL; + plug_in->my_write = NULL; + plug_in->his_read = NULL; + plug_in->his_write = NULL; + + plug_in->input_id = 0; + plug_in->write_buffer_index = 0; + + plug_in->temp_procedures = NULL; + + plug_in->ext_main_loop = NULL; + + plug_in->temp_proc_frames = NULL; + + plug_in->plug_in_def = NULL; +} + +static void +gimp_plug_in_finalize (GObject *object) +{ + GimpPlugIn *plug_in = GIMP_PLUG_IN (object); + + g_clear_object (&plug_in->file); + + gimp_plug_in_proc_frame_dispose (&plug_in->main_proc_frame, plug_in); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gboolean +gimp_plug_in_recv_message (GIOChannel *channel, + GIOCondition cond, + gpointer data) +{ + GimpPlugIn *plug_in = data; + gboolean got_message = FALSE; + +#ifdef G_OS_WIN32 + /* Workaround for GLib bug #137968: sometimes we are called for no + * reason... + */ + if (cond == 0) + return TRUE; +#endif + + if (plug_in->my_read == NULL) + return TRUE; + + g_object_ref (plug_in); + + if (cond & (G_IO_IN | G_IO_PRI)) + { + GimpWireMessage msg; + + memset (&msg, 0, sizeof (GimpWireMessage)); + + if (! gimp_wire_read_msg (plug_in->my_read, &msg, plug_in)) + { + gimp_plug_in_close (plug_in, TRUE); + } + else + { + gimp_plug_in_handle_message (plug_in, &msg); + gimp_wire_destroy (&msg); + got_message = TRUE; + } + } + + if (cond & (G_IO_ERR | G_IO_HUP)) + { + if (cond & G_IO_HUP) + plug_in->hup = TRUE; + + if (plug_in->open) + gimp_plug_in_close (plug_in, TRUE); + } + + if (! got_message) + { + GimpPlugInProcFrame *frame = gimp_plug_in_get_proc_frame (plug_in); + GimpProgress *progress = frame ? frame->progress : NULL; + + gimp_message (plug_in->manager->gimp, G_OBJECT (progress), + GIMP_MESSAGE_ERROR, + _("Plug-in crashed: \"%s\"\n(%s)\n\n" + "The dying plug-in may have messed up GIMP's internal " + "state. You may want to save your images and restart " + "GIMP to be on the safe side."), + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file)); + } + + g_object_unref (plug_in); + + return TRUE; +} + +static gboolean +gimp_plug_in_write (GIOChannel *channel, + const guint8 *buf, + gulong count, + gpointer data) +{ + GimpPlugIn *plug_in = data; + gulong bytes; + + while (count > 0) + { + if ((plug_in->write_buffer_index + count) >= WRITE_BUFFER_SIZE) + { + bytes = WRITE_BUFFER_SIZE - plug_in->write_buffer_index; + memcpy (&plug_in->write_buffer[plug_in->write_buffer_index], + buf, bytes); + plug_in->write_buffer_index += bytes; + if (! gimp_wire_flush (channel, plug_in)) + return FALSE; + } + else + { + bytes = count; + memcpy (&plug_in->write_buffer[plug_in->write_buffer_index], + buf, bytes); + plug_in->write_buffer_index += bytes; + } + + buf += bytes; + count -= bytes; + } + + return TRUE; +} + +static gboolean +gimp_plug_in_flush (GIOChannel *channel, + gpointer data) +{ + GimpPlugIn *plug_in = data; + + if (plug_in->write_buffer_index > 0) + { + GIOStatus status; + GError *error = NULL; + gint count; + gsize bytes; + + count = 0; + while (count != plug_in->write_buffer_index) + { + do + { + bytes = 0; + status = g_io_channel_write_chars (channel, + &plug_in->write_buffer[count], + (plug_in->write_buffer_index - count), + &bytes, + &error); + } + while (status == G_IO_STATUS_AGAIN); + + if (status != G_IO_STATUS_NORMAL) + { + if (error) + { + g_warning ("%s: plug_in_flush(): error: %s", + gimp_filename_to_utf8 (g_get_prgname ()), + error->message); + g_error_free (error); + } + else + { + g_warning ("%s: plug_in_flush(): error", + gimp_filename_to_utf8 (g_get_prgname ())); + } + + return FALSE; + } + + count += bytes; + } + + plug_in->write_buffer_index = 0; + } + + return TRUE; +} + +#if defined G_OS_WIN32 && defined WIN32_32BIT_DLL_FOLDER +static void +gimp_plug_in_set_dll_directory (const gchar *path) +{ + const gchar *install_dir; + gchar *bin_dir; + LPWSTR w_bin_dir; + DWORD BinaryType; + int n; + + w_bin_dir = NULL; + install_dir = gimp_installation_directory (); + if (path && + GetBinaryTypeA (path, &BinaryType) && + BinaryType == SCS_32BIT_BINARY) + bin_dir = g_build_filename (install_dir, WIN32_32BIT_DLL_FOLDER, NULL); + else + bin_dir = g_build_filename (install_dir, "bin", NULL); + + n = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, + bin_dir, -1, NULL, 0); + if (n == 0) + goto out; + + w_bin_dir = g_malloc_n (n + 1, sizeof (wchar_t)); + n = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, + bin_dir, -1, + w_bin_dir, (n + 1) * sizeof (wchar_t)); + if (n == 0) + goto out; + + SetDllDirectoryW (w_bin_dir); + +out: + if (w_bin_dir) + g_free ((void*) w_bin_dir); + g_free (bin_dir); +} +#endif + + +/* public functions */ + +GimpPlugIn * +gimp_plug_in_new (GimpPlugInManager *manager, + GimpContext *context, + GimpProgress *progress, + GimpPlugInProcedure *procedure, + GFile *file) +{ + GimpPlugIn *plug_in; + + g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), NULL); + g_return_val_if_fail (GIMP_IS_PDB_CONTEXT (context), NULL); + g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL); + g_return_val_if_fail (procedure == NULL || + GIMP_IS_PLUG_IN_PROCEDURE (procedure), NULL); + g_return_val_if_fail (file == NULL || G_IS_FILE (file), NULL); + g_return_val_if_fail ((procedure != NULL || file != NULL) && + ! (procedure != NULL && file != NULL), NULL); + + plug_in = g_object_new (GIMP_TYPE_PLUG_IN, NULL); + + if (! file) + file = gimp_plug_in_procedure_get_file (procedure); + + gimp_object_take_name (GIMP_OBJECT (plug_in), + g_path_get_basename (gimp_file_get_utf8_name (file))); + + plug_in->manager = manager; + plug_in->file = g_object_ref (file); + + gimp_plug_in_proc_frame_init (&plug_in->main_proc_frame, + context, progress, procedure); + + return plug_in; +} + +gboolean +gimp_plug_in_open (GimpPlugIn *plug_in, + GimpPlugInCallMode call_mode, + gboolean synchronous) +{ + gchar *progname; + gint my_read[2]; + gint my_write[2]; + gchar **envp; + const gchar *args[9]; + gchar **argv; + gint argc; + gchar *interp, *interp_arg; + gchar *his_read_fd, *his_write_fd; + const gchar *mode; + gchar *stm; + GError *error = NULL; + gboolean debug; + guint debug_flag; + guint spawn_flags; + + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), FALSE); + g_return_val_if_fail (plug_in->call_mode == GIMP_PLUG_IN_CALL_NONE, FALSE); + + /* Open two pipes. (Bidirectional communication). + */ + if ((pipe (my_read) == -1) || (pipe (my_write) == -1)) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Unable to run plug-in \"%s\"\n(%s)\n\npipe() failed: %s", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + g_strerror (errno)); + return FALSE; + } + +#if defined(G_WITH_CYGWIN) + /* Set to binary mode */ + setmode (my_read[0], _O_BINARY); + setmode (my_write[0], _O_BINARY); + setmode (my_read[1], _O_BINARY); + setmode (my_write[1], _O_BINARY); +#endif + + /* Prevent the plug-in from inheriting our end of the pipes */ + gimp_spawn_set_cloexec (my_read[0]); + gimp_spawn_set_cloexec (my_write[1]); + +#ifdef G_OS_WIN32 + plug_in->my_read = g_io_channel_win32_new_fd (my_read[0]); + plug_in->my_write = g_io_channel_win32_new_fd (my_write[1]); + plug_in->his_read = g_io_channel_win32_new_fd (my_write[0]); + plug_in->his_write = g_io_channel_win32_new_fd (my_read[1]); +#else + plug_in->my_read = g_io_channel_unix_new (my_read[0]); + plug_in->my_write = g_io_channel_unix_new (my_write[1]); + plug_in->his_read = g_io_channel_unix_new (my_write[0]); + plug_in->his_write = g_io_channel_unix_new (my_read[1]); +#endif + + g_io_channel_set_encoding (plug_in->my_read, NULL, NULL); + g_io_channel_set_encoding (plug_in->my_write, NULL, NULL); + g_io_channel_set_encoding (plug_in->his_read, NULL, NULL); + g_io_channel_set_encoding (plug_in->his_write, NULL, NULL); + + g_io_channel_set_buffered (plug_in->my_read, FALSE); + g_io_channel_set_buffered (plug_in->my_write, FALSE); + g_io_channel_set_buffered (plug_in->his_read, FALSE); + g_io_channel_set_buffered (plug_in->his_write, FALSE); + + g_io_channel_set_close_on_unref (plug_in->my_read, TRUE); + g_io_channel_set_close_on_unref (plug_in->my_write, TRUE); + g_io_channel_set_close_on_unref (plug_in->his_read, TRUE); + g_io_channel_set_close_on_unref (plug_in->his_write, TRUE); + + /* Remember the file descriptors for the pipes. + */ + his_read_fd = g_strdup_printf ("%d", + g_io_channel_unix_get_fd (plug_in->his_read)); + his_write_fd = g_strdup_printf ("%d", + g_io_channel_unix_get_fd (plug_in->his_write)); + + switch (call_mode) + { + case GIMP_PLUG_IN_CALL_QUERY: + mode = "-query"; + debug_flag = GIMP_DEBUG_WRAP_QUERY; + break; + + case GIMP_PLUG_IN_CALL_INIT: + mode = "-init"; + debug_flag = GIMP_DEBUG_WRAP_INIT; + break; + + case GIMP_PLUG_IN_CALL_RUN: + mode = "-run"; + debug_flag = GIMP_DEBUG_WRAP_RUN; + break; + + default: + gimp_assert_not_reached (); + } + + stm = g_strdup_printf ("%d", plug_in->manager->gimp->stack_trace_mode); + + progname = g_file_get_path (plug_in->file); + + interp = gimp_interpreter_db_resolve (plug_in->manager->interpreter_db, + progname, &interp_arg); + + argc = 0; + + if (interp) + args[argc++] = interp; + + if (interp_arg) + args[argc++] = interp_arg; + + args[argc++] = progname; + args[argc++] = "-gimp"; + args[argc++] = his_read_fd; + args[argc++] = his_write_fd; + args[argc++] = mode; + args[argc++] = stm; + args[argc++] = NULL; + + argv = (gchar **) args; + envp = gimp_environ_table_get_envp (plug_in->manager->environ_table); + spawn_flags = (G_SPAWN_LEAVE_DESCRIPTORS_OPEN | + G_SPAWN_DO_NOT_REAP_CHILD | + G_SPAWN_CHILD_INHERITS_STDIN); + + debug = FALSE; + + if (plug_in->manager->debug) + { + gchar **debug_argv = gimp_plug_in_debug_argv (plug_in->manager->debug, + progname, + debug_flag, args); + + if (debug_argv) + { + debug = TRUE; + argv = debug_argv; + spawn_flags |= G_SPAWN_SEARCH_PATH; + } + } + + /* Fork another process. We'll remember the process id so that we + * can later use it to kill the filter if necessary. + */ +#if defined G_OS_WIN32 && defined WIN32_32BIT_DLL_FOLDER + gimp_plug_in_set_dll_directory (argv[0]); +#endif + if (! gimp_spawn_async (argv, envp, spawn_flags, &plug_in->pid, &error)) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Unable to run plug-in \"%s\"\n(%s)\n\n%s", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + error->message); + g_clear_error (&error); + goto cleanup; + } + + g_clear_pointer (&plug_in->his_read, g_io_channel_unref); + g_clear_pointer (&plug_in->his_write, g_io_channel_unref); + + if (! synchronous) + { + GSource *source; + + source = g_io_create_watch (plug_in->my_read, + G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP); + + g_source_set_callback (source, + (GSourceFunc) gimp_plug_in_recv_message, plug_in, + NULL); + + g_source_set_can_recurse (source, TRUE); + + plug_in->input_id = g_source_attach (source, NULL); + g_source_unref (source); + } + + plug_in->open = TRUE; + plug_in->call_mode = call_mode; + + gimp_plug_in_manager_add_open_plug_in (plug_in->manager, plug_in); + + cleanup: + +#if defined G_OS_WIN32 && defined WIN32_32BIT_DLL_FOLDER + gimp_plug_in_set_dll_directory (NULL); +#endif + + if (debug) + g_free (argv); + + g_free (his_read_fd); + g_free (his_write_fd); + g_free (stm); + g_free (interp); + g_free (interp_arg); + g_free (progname); + + return plug_in->open; +} + +void +gimp_plug_in_close (GimpPlugIn *plug_in, + gboolean kill_it) +{ + g_return_if_fail (GIMP_IS_PLUG_IN (plug_in)); + g_return_if_fail (plug_in->open); + + plug_in->open = FALSE; + + if (plug_in->pid) + { +#ifndef G_OS_WIN32 + gint status; +#endif + + /* Ask the filter to exit gracefully, + but not if it is closed because of a broken pipe. */ + if (kill_it && ! plug_in->hup) + { + gp_quit_write (plug_in->my_write, plug_in); + + /* give the plug-in some time (10 ms) */ + g_usleep (10000); + } + + /* If necessary, kill the filter. */ + +#ifndef G_OS_WIN32 + + if (kill_it) + { + if (plug_in->manager->gimp->be_verbose) + g_print ("Terminating plug-in: '%s'\n", + gimp_file_get_utf8_name (plug_in->file)); + + /* If the plug-in opened a process group, kill the group instead + * of only the plug-in, so we kill the plug-in's children too + */ + if (getpgid (0) != getpgid (plug_in->pid)) + status = kill (- plug_in->pid, SIGKILL); + else + status = kill (plug_in->pid, SIGKILL); + } + + /* Wait for the process to exit. This will happen + * immediately if it was just killed. + */ + waitpid (plug_in->pid, &status, 0); + +#else /* G_OS_WIN32 */ + + if (kill_it) + { + /* Trying to avoid TerminateProcess (does mostly work). + * Otherwise some of our needed DLLs may get into an + * unstable state (see Win32 API docs). + */ + DWORD dwExitCode = STILL_ACTIVE; + DWORD dwTries = 10; + + while (dwExitCode == STILL_ACTIVE && + GetExitCodeProcess ((HANDLE) plug_in->pid, &dwExitCode) && + (dwTries > 0)) + { + Sleep (10); + dwTries--; + } + + if (dwExitCode == STILL_ACTIVE) + { + if (plug_in->manager->gimp->be_verbose) + g_print ("Terminating plug-in: '%s'\n", + gimp_file_get_utf8_name (plug_in->file)); + + TerminateProcess ((HANDLE) plug_in->pid, 0); + } + } + +#endif /* G_OS_WIN32 */ + + g_spawn_close_pid (plug_in->pid); + plug_in->pid = 0; + } + + /* Remove the input handler. */ + if (plug_in->input_id) + { + g_source_remove (plug_in->input_id); + plug_in->input_id = 0; + } + + /* Close the pipes. */ + g_clear_pointer (&plug_in->my_read, g_io_channel_unref); + g_clear_pointer (&plug_in->my_write, g_io_channel_unref); + g_clear_pointer (&plug_in->his_read, g_io_channel_unref); + g_clear_pointer (&plug_in->his_write, g_io_channel_unref); + + gimp_wire_clear_error (); + + while (plug_in->temp_proc_frames) + { + GimpPlugInProcFrame *proc_frame = plug_in->temp_proc_frames->data; + +#ifdef GIMP_UNSTABLE + g_printerr ("plug-in '%s' aborted before sending its " + "temporary procedure return values\n", + gimp_object_get_name (plug_in)); +#endif + + if (proc_frame->main_loop && + g_main_loop_is_running (proc_frame->main_loop)) + { + g_main_loop_quit (proc_frame->main_loop); + } + + /* pop the frame here, because normally this only happens in + * gimp_plug_in_handle_temp_proc_return(), which can't + * be called after plug_in_close() + */ + gimp_plug_in_proc_frame_pop (plug_in); + } + + if (plug_in->main_proc_frame.main_loop && + g_main_loop_is_running (plug_in->main_proc_frame.main_loop)) + { +#ifdef GIMP_UNSTABLE + g_printerr ("plug-in '%s' aborted before sending its " + "procedure return values\n", + gimp_object_get_name (plug_in)); +#endif + + g_main_loop_quit (plug_in->main_proc_frame.main_loop); + } + + if (plug_in->ext_main_loop && + g_main_loop_is_running (plug_in->ext_main_loop)) + { +#ifdef GIMP_UNSTABLE + g_printerr ("extension '%s' aborted before sending its " + "extension_ack message\n", + gimp_object_get_name (plug_in)); +#endif + + g_main_loop_quit (plug_in->ext_main_loop); + } + + /* Unregister any temporary procedures. */ + while (plug_in->temp_procedures) + gimp_plug_in_remove_temp_proc (plug_in, plug_in->temp_procedures->data); + + gimp_plug_in_manager_remove_open_plug_in (plug_in->manager, plug_in); +} + +GimpPlugInProcFrame * +gimp_plug_in_get_proc_frame (GimpPlugIn *plug_in) +{ + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), NULL); + + if (plug_in->temp_proc_frames) + return plug_in->temp_proc_frames->data; + else + return &plug_in->main_proc_frame; +} + +GimpPlugInProcFrame * +gimp_plug_in_proc_frame_push (GimpPlugIn *plug_in, + GimpContext *context, + GimpProgress *progress, + GimpTemporaryProcedure *procedure) +{ + GimpPlugInProcFrame *proc_frame; + + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), NULL); + g_return_val_if_fail (GIMP_IS_PDB_CONTEXT (context), NULL); + g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL); + g_return_val_if_fail (GIMP_IS_TEMPORARY_PROCEDURE (procedure), NULL); + + proc_frame = gimp_plug_in_proc_frame_new (context, progress, + GIMP_PLUG_IN_PROCEDURE (procedure)); + + plug_in->temp_proc_frames = g_list_prepend (plug_in->temp_proc_frames, + proc_frame); + + return proc_frame; +} + +void +gimp_plug_in_proc_frame_pop (GimpPlugIn *plug_in) +{ + GimpPlugInProcFrame *proc_frame; + + g_return_if_fail (GIMP_IS_PLUG_IN (plug_in)); + g_return_if_fail (plug_in->temp_proc_frames != NULL); + + proc_frame = (GimpPlugInProcFrame *) plug_in->temp_proc_frames->data; + + gimp_plug_in_proc_frame_unref (proc_frame, plug_in); + + plug_in->temp_proc_frames = g_list_remove (plug_in->temp_proc_frames, + proc_frame); +} + +void +gimp_plug_in_main_loop (GimpPlugIn *plug_in) +{ + GimpPlugInProcFrame *proc_frame; + + g_return_if_fail (GIMP_IS_PLUG_IN (plug_in)); + g_return_if_fail (plug_in->temp_proc_frames != NULL); + + proc_frame = (GimpPlugInProcFrame *) plug_in->temp_proc_frames->data; + + g_return_if_fail (proc_frame->main_loop == NULL); + + proc_frame->main_loop = g_main_loop_new (NULL, FALSE); + + gimp_threads_leave (plug_in->manager->gimp); + g_main_loop_run (proc_frame->main_loop); + gimp_threads_enter (plug_in->manager->gimp); + + g_clear_pointer (&proc_frame->main_loop, g_main_loop_unref); +} + +void +gimp_plug_in_main_loop_quit (GimpPlugIn *plug_in) +{ + GimpPlugInProcFrame *proc_frame; + + g_return_if_fail (GIMP_IS_PLUG_IN (plug_in)); + g_return_if_fail (plug_in->temp_proc_frames != NULL); + + proc_frame = (GimpPlugInProcFrame *) plug_in->temp_proc_frames->data; + + g_return_if_fail (proc_frame->main_loop != NULL); + + g_main_loop_quit (proc_frame->main_loop); +} + +const gchar * +gimp_plug_in_get_undo_desc (GimpPlugIn *plug_in) +{ + GimpPlugInProcFrame *proc_frame; + const gchar *undo_desc = NULL; + + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), NULL); + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + + if (proc_frame && proc_frame->procedure) + undo_desc = gimp_procedure_get_label (proc_frame->procedure); + + return undo_desc ? undo_desc : gimp_object_get_name (plug_in); +} + +/* called from the PDB (gimp_plugin_menu_register) */ +gboolean +gimp_plug_in_menu_register (GimpPlugIn *plug_in, + const gchar *proc_name, + const gchar *menu_path) +{ + GimpPlugInProcedure *proc = NULL; + GError *error = NULL; + + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), FALSE); + g_return_val_if_fail (proc_name != NULL, FALSE); + g_return_val_if_fail (menu_path != NULL, FALSE); + + if (plug_in->plug_in_def) + proc = gimp_plug_in_procedure_find (plug_in->plug_in_def->procedures, + proc_name); + + if (! proc) + proc = gimp_plug_in_procedure_find (plug_in->temp_procedures, proc_name); + + if (! proc) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n" + "attempted to register the menu item \"%s\" " + "for the procedure \"%s\".\n" + "It has however not installed that procedure. This " + "is not allowed.", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + menu_path, proc_name); + + return FALSE; + } + + switch (GIMP_PROCEDURE (proc)->proc_type) + { + case GIMP_INTERNAL: + return FALSE; + + case GIMP_PLUGIN: + case GIMP_EXTENSION: + if (plug_in->call_mode != GIMP_PLUG_IN_CALL_QUERY && + plug_in->call_mode != GIMP_PLUG_IN_CALL_INIT) + return FALSE; + + case GIMP_TEMPORARY: + break; + } + + if (! proc->menu_label) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n" + "attempted to register the menu item \"%s\" " + "for procedure \"%s\".\n" + "The menu label given in gimp_install_procedure() " + "already contained a path. To make this work, " + "pass just the menu's label to " + "gimp_install_procedure().", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + menu_path, proc_name); + + return FALSE; + } + + if (! strlen (proc->menu_label)) + { + gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "Plug-in \"%s\"\n(%s)\n" + "attempted to register the procedure \"%s\" " + "in the menu \"%s\", but the procedure has no label. " + "This is not allowed.", + gimp_object_get_name (plug_in), + gimp_file_get_utf8_name (plug_in->file), + proc_name, menu_path); + + return FALSE; + } + + if (! gimp_plug_in_procedure_add_menu_path (proc, menu_path, &error)) + { + gimp_message_literal (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR, + error->message); + g_clear_error (&error); + + return FALSE; + } + + return TRUE; +} + +void +gimp_plug_in_add_temp_proc (GimpPlugIn *plug_in, + GimpTemporaryProcedure *proc) +{ + GimpPlugInProcedure *overridden; + const gchar *locale_domain; + const gchar *help_domain; + + g_return_if_fail (GIMP_IS_PLUG_IN (plug_in)); + g_return_if_fail (GIMP_IS_TEMPORARY_PROCEDURE (proc)); + + overridden = gimp_plug_in_procedure_find (plug_in->temp_procedures, + gimp_object_get_name (proc)); + + if (overridden) + gimp_plug_in_remove_temp_proc (plug_in, + GIMP_TEMPORARY_PROCEDURE (overridden)); + + locale_domain = gimp_plug_in_manager_get_locale_domain (plug_in->manager, + plug_in->file, + NULL); + help_domain = gimp_plug_in_manager_get_help_domain (plug_in->manager, + plug_in->file, + NULL); + + gimp_plug_in_procedure_set_locale_domain (GIMP_PLUG_IN_PROCEDURE (proc), + locale_domain); + gimp_plug_in_procedure_set_help_domain (GIMP_PLUG_IN_PROCEDURE (proc), + help_domain); + + plug_in->temp_procedures = g_slist_prepend (plug_in->temp_procedures, + g_object_ref (proc)); + gimp_plug_in_manager_add_temp_proc (plug_in->manager, proc); +} + +void +gimp_plug_in_remove_temp_proc (GimpPlugIn *plug_in, + GimpTemporaryProcedure *proc) +{ + g_return_if_fail (GIMP_IS_PLUG_IN (plug_in)); + g_return_if_fail (GIMP_IS_TEMPORARY_PROCEDURE (proc)); + + plug_in->temp_procedures = g_slist_remove (plug_in->temp_procedures, proc); + + gimp_plug_in_manager_remove_temp_proc (plug_in->manager, proc); + g_object_unref (proc); +} + +void +gimp_plug_in_set_error_handler (GimpPlugIn *plug_in, + GimpPDBErrorHandler handler) +{ + GimpPlugInProcFrame *proc_frame; + + g_return_if_fail (GIMP_IS_PLUG_IN (plug_in)); + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + + if (proc_frame) + proc_frame->error_handler = handler; +} + +GimpPDBErrorHandler +gimp_plug_in_get_error_handler (GimpPlugIn *plug_in) +{ + GimpPlugInProcFrame *proc_frame; + + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), + GIMP_PDB_ERROR_HANDLER_INTERNAL); + + proc_frame = gimp_plug_in_get_proc_frame (plug_in); + + if (proc_frame) + return proc_frame->error_handler; + + return GIMP_PDB_ERROR_HANDLER_INTERNAL; +} + +void +gimp_plug_in_enable_precision (GimpPlugIn *plug_in) +{ + g_return_if_fail (GIMP_IS_PLUG_IN (plug_in)); + + plug_in->precision = TRUE; +} + +gboolean +gimp_plug_in_precision_enabled (GimpPlugIn *plug_in) +{ + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), FALSE); + + return plug_in->precision; +} diff --git a/app/plug-in/gimpplugin.h b/app/plug-in/gimpplugin.h new file mode 100644 index 0000000..15326a0 --- /dev/null +++ b/app/plug-in/gimpplugin.h @@ -0,0 +1,127 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpplugin.h + * + * 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/>. + */ + +#ifndef __GIMP_PLUG_IN_H__ +#define __GIMP_PLUG_IN_H__ + + +#include "core/gimpobject.h" +#include "gimppluginprocframe.h" + + +#define WRITE_BUFFER_SIZE 512 + + +#define GIMP_TYPE_PLUG_IN (gimp_plug_in_get_type ()) +#define GIMP_PLUG_IN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_PLUG_IN, GimpPlugIn)) +#define GIMP_PLUG_IN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_PLUG_IN, GimpPlugInClass)) +#define GIMP_IS_PLUG_IN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_PLUG_IN)) +#define GIMP_IS_PLUG_IN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_PLUG_IN)) + + +typedef struct _GimpPlugInClass GimpPlugInClass; + +struct _GimpPlugIn +{ + GimpObject parent_instance; + + GimpPlugInManager *manager; + GFile *file; /* Plug-in's full path name */ + + GimpPlugInCallMode call_mode; /* QUERY, INIT or RUN */ + guint open : 1; /* Is the plug-in open? */ + guint hup : 1; /* Did we receive a G_IO_HUP */ + guint precision : 1; /* True drawable precision enabled */ + GPid pid; /* Plug-in's process id */ + + GIOChannel *my_read; /* App's read and write channels */ + GIOChannel *my_write; + GIOChannel *his_read; /* Plug-in's read and write channels */ + GIOChannel *his_write; + + guint input_id; /* Id of input proc */ + + gchar write_buffer[WRITE_BUFFER_SIZE]; /* Buffer for writing */ + gint write_buffer_index; /* Buffer index */ + + GSList *temp_procedures; /* Temporary procedures */ + + GMainLoop *ext_main_loop; /* for waiting for extension_ack */ + + GimpPlugInProcFrame main_proc_frame; + + GList *temp_proc_frames; + + GimpPlugInDef *plug_in_def; /* Valid during query() and init() */ +}; + +struct _GimpPlugInClass +{ + GimpObjectClass parent_class; +}; + + +GType gimp_plug_in_get_type (void) G_GNUC_CONST; + +GimpPlugIn * gimp_plug_in_new (GimpPlugInManager *manager, + GimpContext *context, + GimpProgress *progress, + GimpPlugInProcedure *procedure, + GFile *file); + +gboolean gimp_plug_in_open (GimpPlugIn *plug_in, + GimpPlugInCallMode call_mode, + gboolean synchronous); +void gimp_plug_in_close (GimpPlugIn *plug_in, + gboolean kill_it); + +GimpPlugInProcFrame * + gimp_plug_in_get_proc_frame (GimpPlugIn *plug_in); + +GimpPlugInProcFrame * + gimp_plug_in_proc_frame_push (GimpPlugIn *plug_in, + GimpContext *context, + GimpProgress *progress, + GimpTemporaryProcedure *procedure); +void gimp_plug_in_proc_frame_pop (GimpPlugIn *plug_in); + +void gimp_plug_in_main_loop (GimpPlugIn *plug_in); +void gimp_plug_in_main_loop_quit (GimpPlugIn *plug_in); + +const gchar * gimp_plug_in_get_undo_desc (GimpPlugIn *plug_in); + +gboolean gimp_plug_in_menu_register (GimpPlugIn *plug_in, + const gchar *proc_name, + const gchar *menu_path); + +void gimp_plug_in_add_temp_proc (GimpPlugIn *plug_in, + GimpTemporaryProcedure *procedure); +void gimp_plug_in_remove_temp_proc (GimpPlugIn *plug_in, + GimpTemporaryProcedure *procedure); + +void gimp_plug_in_set_error_handler (GimpPlugIn *plug_in, + GimpPDBErrorHandler handler); +GimpPDBErrorHandler + gimp_plug_in_get_error_handler (GimpPlugIn *plug_in); + +void gimp_plug_in_enable_precision (GimpPlugIn *plug_in); +gboolean gimp_plug_in_precision_enabled (GimpPlugIn *plug_in); + + +#endif /* __GIMP_PLUG_IN_H__ */ diff --git a/app/plug-in/gimpplugindebug.c b/app/plug-in/gimpplugindebug.c new file mode 100644 index 0000000..81c1060 --- /dev/null +++ b/app/plug-in/gimpplugindebug.c @@ -0,0 +1,142 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpplugindebug.c + * + * 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" + +#include <string.h> + +#include <glib-object.h> + +#include "plug-in-types.h" + +#include "gimpplugindebug.h" + + +struct _GimpPlugInDebug +{ + gchar *name; + guint flags; + gchar **args; +}; + + +static const GDebugKey gimp_debug_wrap_keys[] = +{ + { "query", GIMP_DEBUG_WRAP_QUERY }, + { "init", GIMP_DEBUG_WRAP_INIT }, + { "run", GIMP_DEBUG_WRAP_RUN }, + { "on", GIMP_DEBUG_WRAP_DEFAULT } +}; + + +GimpPlugInDebug * +gimp_plug_in_debug_new (void) +{ + GimpPlugInDebug *debug; + const gchar *wrap, *wrapper; + gchar *debug_string; + gchar **args; + GError *error = NULL; + + wrap = g_getenv ("GIMP_PLUGIN_DEBUG_WRAP"); + wrapper = g_getenv ("GIMP_PLUGIN_DEBUG_WRAPPER"); + + if (!(wrap && wrapper)) + return NULL; + + if (!g_shell_parse_argv (wrapper, NULL, &args, &error)) + { + g_warning ("Unable to parse debug wrapper: \"%s\"\n%s", + wrapper, error->message); + g_error_free (error); + return NULL; + } + + debug = g_slice_new (GimpPlugInDebug); + + debug->args = args; + + debug_string = strchr (wrap, ','); + + if (debug_string) + { + debug->name = g_strndup (wrap, debug_string - wrap); + debug->flags = g_parse_debug_string (debug_string + 1, + gimp_debug_wrap_keys, + G_N_ELEMENTS (gimp_debug_wrap_keys)); + } + else + { + debug->name = g_strdup (wrap); + debug->flags = GIMP_DEBUG_WRAP_DEFAULT; + } + + return debug; +} + +void +gimp_plug_in_debug_free (GimpPlugInDebug *debug) +{ + g_return_if_fail (debug != NULL); + + if (debug->name) + g_free (debug->name); + + if (debug->args) + g_strfreev (debug->args); + + g_slice_free (GimpPlugInDebug, debug); +} + +gchar ** +gimp_plug_in_debug_argv (GimpPlugInDebug *debug, + const gchar *name, + GimpDebugWrapFlag flag, + const gchar **args) +{ + GPtrArray *argv; + gchar **arg; + gchar *basename; + + g_return_val_if_fail (debug != NULL, NULL); + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (args != NULL, NULL); + + basename = g_path_get_basename (name); + + if (!(debug->flags & flag) || (strcmp (debug->name, basename) != 0)) + { + g_free (basename); + return NULL; + } + + g_free (basename); + + argv = g_ptr_array_sized_new (8); + + for (arg = debug->args; *arg != NULL; arg++) + g_ptr_array_add (argv, *arg); + + for (arg = (gchar **) args; *arg != NULL; arg++) + g_ptr_array_add (argv, *arg); + + g_ptr_array_add (argv, NULL); + + return (gchar **) g_ptr_array_free (argv, FALSE); +} diff --git a/app/plug-in/gimpplugindebug.h b/app/plug-in/gimpplugindebug.h new file mode 100644 index 0000000..ec5bc33 --- /dev/null +++ b/app/plug-in/gimpplugindebug.h @@ -0,0 +1,43 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpplugindebug.h + * + * 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/>. + */ + +#ifndef __GIMP_PLUG_IN_DEBUG_H__ +#define __GIMP_PLUG_IN_DEBUG_H__ + + +typedef enum +{ + GIMP_DEBUG_WRAP_QUERY = 1 << 0, + GIMP_DEBUG_WRAP_INIT = 1 << 1, + GIMP_DEBUG_WRAP_RUN = 1 << 2, + + GIMP_DEBUG_WRAP_DEFAULT = GIMP_DEBUG_WRAP_RUN +} GimpDebugWrapFlag; + + +GimpPlugInDebug * gimp_plug_in_debug_new (void); +void gimp_plug_in_debug_free (GimpPlugInDebug *debug); + +gchar ** gimp_plug_in_debug_argv (GimpPlugInDebug *debug, + const gchar *name, + GimpDebugWrapFlag flag, + const gchar **args); + + +#endif /* __GIMP_PLUG_IN_DEBUG_H__ */ diff --git a/app/plug-in/gimpplugindef.c b/app/plug-in/gimpplugindef.c new file mode 100644 index 0000000..83f6378 --- /dev/null +++ b/app/plug-in/gimpplugindef.c @@ -0,0 +1,235 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpplugindef.c + * + * 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" + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "plug-in-types.h" + +#include "core/gimp-memsize.h" + +#include "gimpplugindef.h" +#include "gimppluginprocedure.h" + + +static void gimp_plug_in_def_finalize (GObject *object); + +static gint64 gimp_plug_in_def_get_memsize (GimpObject *object, + gint64 *gui_size); + + +G_DEFINE_TYPE (GimpPlugInDef, gimp_plug_in_def, GIMP_TYPE_OBJECT) + +#define parent_class gimp_plug_in_def_parent_class + + +static void +gimp_plug_in_def_class_init (GimpPlugInDefClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass); + + object_class->finalize = gimp_plug_in_def_finalize; + + gimp_object_class->get_memsize = gimp_plug_in_def_get_memsize; +} + +static void +gimp_plug_in_def_init (GimpPlugInDef *def) +{ +} + +static void +gimp_plug_in_def_finalize (GObject *object) +{ + GimpPlugInDef *plug_in_def = GIMP_PLUG_IN_DEF (object); + + g_object_unref (plug_in_def->file); + g_free (plug_in_def->locale_domain_name); + g_free (plug_in_def->locale_domain_path); + g_free (plug_in_def->help_domain_name); + g_free (plug_in_def->help_domain_uri); + + g_slist_free_full (plug_in_def->procedures, (GDestroyNotify) g_object_unref); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gint64 +gimp_plug_in_def_get_memsize (GimpObject *object, + gint64 *gui_size) +{ + GimpPlugInDef *plug_in_def = GIMP_PLUG_IN_DEF (object); + gint64 memsize = 0; + + memsize += gimp_g_object_get_memsize (G_OBJECT (plug_in_def->file)); + memsize += gimp_string_get_memsize (plug_in_def->locale_domain_name); + memsize += gimp_string_get_memsize (plug_in_def->locale_domain_path); + memsize += gimp_string_get_memsize (plug_in_def->help_domain_name); + memsize += gimp_string_get_memsize (plug_in_def->help_domain_uri); + + memsize += gimp_g_slist_get_memsize (plug_in_def->procedures, 0); + + return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object, + gui_size); +} + + +/* public functions */ + +GimpPlugInDef * +gimp_plug_in_def_new (GFile *file) +{ + GimpPlugInDef *plug_in_def; + + g_return_val_if_fail (G_IS_FILE (file), NULL); + + plug_in_def = g_object_new (GIMP_TYPE_PLUG_IN_DEF, NULL); + + plug_in_def->file = g_object_ref (file); + + return plug_in_def; +} + +void +gimp_plug_in_def_add_procedure (GimpPlugInDef *plug_in_def, + GimpPlugInProcedure *proc) +{ + GimpPlugInProcedure *overridden; + + g_return_if_fail (GIMP_IS_PLUG_IN_DEF (plug_in_def)); + g_return_if_fail (GIMP_IS_PLUG_IN_PROCEDURE (proc)); + + overridden = gimp_plug_in_procedure_find (plug_in_def->procedures, + gimp_object_get_name (proc)); + + if (overridden) + gimp_plug_in_def_remove_procedure (plug_in_def, overridden); + + proc->mtime = plug_in_def->mtime; + + gimp_plug_in_procedure_set_locale_domain (proc, + plug_in_def->locale_domain_name); + gimp_plug_in_procedure_set_help_domain (proc, + plug_in_def->help_domain_name); + + plug_in_def->procedures = g_slist_append (plug_in_def->procedures, + g_object_ref (proc)); +} + +void +gimp_plug_in_def_remove_procedure (GimpPlugInDef *plug_in_def, + GimpPlugInProcedure *proc) +{ + g_return_if_fail (GIMP_IS_PLUG_IN_DEF (plug_in_def)); + g_return_if_fail (GIMP_IS_PLUG_IN_PROCEDURE (proc)); + + plug_in_def->procedures = g_slist_remove (plug_in_def->procedures, proc); + g_object_unref (proc); +} + +void +gimp_plug_in_def_set_locale_domain (GimpPlugInDef *plug_in_def, + const gchar *domain_name, + const gchar *domain_path) +{ + GSList *list; + + g_return_if_fail (GIMP_IS_PLUG_IN_DEF (plug_in_def)); + + if (plug_in_def->locale_domain_name) + g_free (plug_in_def->locale_domain_name); + plug_in_def->locale_domain_name = g_strdup (domain_name); + + if (plug_in_def->locale_domain_path) + g_free (plug_in_def->locale_domain_path); + plug_in_def->locale_domain_path = g_strdup (domain_path); + + for (list = plug_in_def->procedures; list; list = g_slist_next (list)) + { + GimpPlugInProcedure *procedure = list->data; + + gimp_plug_in_procedure_set_locale_domain (procedure, + plug_in_def->locale_domain_name); + } +} + +void +gimp_plug_in_def_set_help_domain (GimpPlugInDef *plug_in_def, + const gchar *domain_name, + const gchar *domain_uri) +{ + GSList *list; + + g_return_if_fail (GIMP_IS_PLUG_IN_DEF (plug_in_def)); + + if (plug_in_def->help_domain_name) + g_free (plug_in_def->help_domain_name); + plug_in_def->help_domain_name = g_strdup (domain_name); + + if (plug_in_def->help_domain_uri) + g_free (plug_in_def->help_domain_uri); + plug_in_def->help_domain_uri = g_strdup (domain_uri); + + for (list = plug_in_def->procedures; list; list = g_slist_next (list)) + { + GimpPlugInProcedure *procedure = list->data; + + gimp_plug_in_procedure_set_help_domain (procedure, + plug_in_def->help_domain_name); + } +} + +void +gimp_plug_in_def_set_mtime (GimpPlugInDef *plug_in_def, + gint64 mtime) +{ + GSList *list; + + g_return_if_fail (GIMP_IS_PLUG_IN_DEF (plug_in_def)); + + plug_in_def->mtime = mtime; + + for (list = plug_in_def->procedures; list; list = g_slist_next (list)) + { + GimpPlugInProcedure *proc = list->data; + + proc->mtime = plug_in_def->mtime; + } +} + +void +gimp_plug_in_def_set_needs_query (GimpPlugInDef *plug_in_def, + gboolean needs_query) +{ + g_return_if_fail (GIMP_IS_PLUG_IN_DEF (plug_in_def)); + + plug_in_def->needs_query = needs_query ? TRUE : FALSE; +} + +void +gimp_plug_in_def_set_has_init (GimpPlugInDef *plug_in_def, + gboolean has_init) +{ + g_return_if_fail (GIMP_IS_PLUG_IN_DEF (plug_in_def)); + + plug_in_def->has_init = has_init ? TRUE : FALSE; +} diff --git a/app/plug-in/gimpplugindef.h b/app/plug-in/gimpplugindef.h new file mode 100644 index 0000000..d819e1a --- /dev/null +++ b/app/plug-in/gimpplugindef.h @@ -0,0 +1,82 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpplugindef.h + * + * 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/>. + */ + +#ifndef __GIMP_PLUG_IN_DEF_H__ +#define __GIMP_PLUG_IN_DEF_H__ + + +#include "core/gimpobject.h" + + +#define GIMP_TYPE_PLUG_IN_DEF (gimp_plug_in_def_get_type ()) +#define GIMP_PLUG_IN_DEF(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_PLUG_IN_DEF, GimpPlugInDef)) +#define GIMP_PLUG_IN_DEF_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_PLUG_IN_DEF, GimpPlugInDefClass)) +#define GIMP_IS_PLUG_IN_DEF(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_PLUG_IN_DEF)) +#define GIMP_IS_PLUG_IN_DEF_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_PLUG_IN_DEF)) + + +typedef struct _GimpPlugInDefClass GimpPlugInDefClass; + +struct _GimpPlugInDef +{ + GimpObject parent_instance; + + GFile *file; + GSList *procedures; + gchar *locale_domain_name; + gchar *locale_domain_path; + gchar *help_domain_name; + gchar *help_domain_uri; + gint64 mtime; + gboolean needs_query; /* Does the plug-in need to be queried ? */ + gboolean has_init; /* Does the plug-in need to be initialized ? */ +}; + +struct _GimpPlugInDefClass +{ + GimpObjectClass parent_class; +}; + + +GType gimp_plug_in_def_get_type (void) G_GNUC_CONST; + +GimpPlugInDef * gimp_plug_in_def_new (GFile *file); + +void gimp_plug_in_def_add_procedure (GimpPlugInDef *plug_in_def, + GimpPlugInProcedure *proc); +void gimp_plug_in_def_remove_procedure (GimpPlugInDef *plug_in_def, + GimpPlugInProcedure *proc); + +void gimp_plug_in_def_set_locale_domain (GimpPlugInDef *plug_in_def, + const gchar *domain_name, + const gchar *domain_path); + +void gimp_plug_in_def_set_help_domain (GimpPlugInDef *plug_in_def, + const gchar *domain_name, + const gchar *domain_uri); + +void gimp_plug_in_def_set_mtime (GimpPlugInDef *plug_in_def, + gint64 mtime); +void gimp_plug_in_def_set_needs_query (GimpPlugInDef *plug_in_def, + gboolean needs_query); +void gimp_plug_in_def_set_has_init (GimpPlugInDef *plug_in_def, + gboolean has_init); + + +#endif /* __GIMP_PLUG_IN_DEF_H__ */ diff --git a/app/plug-in/gimppluginerror.c b/app/plug-in/gimppluginerror.c new file mode 100644 index 0000000..e73e1e5 --- /dev/null +++ b/app/plug-in/gimppluginerror.c @@ -0,0 +1,36 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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" + +#include <glib-object.h> + +#include "gimppluginerror.h" + + +/** + * gimp_plug_in_error_quark: + * + * This function is never called directly. Use GIMP_PLUG_IN_ERROR() instead. + * + * Return value: the #GQuark that defines the GimpPlugIn error domain. + **/ +GQuark +gimp_plug_in_error_quark (void) +{ + return g_quark_from_static_string ("gimp-plug-in-error-quark"); +} diff --git a/app/plug-in/gimppluginerror.h b/app/plug-in/gimppluginerror.h new file mode 100644 index 0000000..7cf7eb2 --- /dev/null +++ b/app/plug-in/gimppluginerror.h @@ -0,0 +1,35 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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/>. + */ + +#ifndef __GIMP_PLUG_IN_ERROR_H__ +#define __GIMP_PLUG_IN_ERROR_H__ + + +typedef enum +{ + GIMP_PLUG_IN_FAILED, /* generic error condition */ + GIMP_PLUG_IN_EXECUTION_FAILED, + GIMP_PLUG_IN_NOT_FOUND +} GimpPlugInErrorCode; + + +#define GIMP_PLUG_IN_ERROR (gimp_plug_in_error_quark ()) + +GQuark gimp_plug_in_error_quark (void) G_GNUC_CONST; + + +#endif /* __GIMP_PLUG_IN_ERROR_H__ */ diff --git a/app/plug-in/gimppluginmanager-call.c b/app/plug-in/gimppluginmanager-call.c new file mode 100644 index 0000000..47791e6 --- /dev/null +++ b/app/plug-in/gimppluginmanager-call.c @@ -0,0 +1,375 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimppluginmanager-call.c + * + * 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" + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#ifdef G_OS_WIN32 +#include <windows.h> +#endif + +#include "libgimpbase/gimpbase.h" +#include "libgimpbase/gimpprotocol.h" +#include "libgimpbase/gimpwire.h" + +#include "plug-in-types.h" + +#include "config/gimpguiconfig.h" + +#include "core/gimp.h" +#include "core/gimpprogress.h" + +#include "pdb/gimppdbcontext.h" + +#include "gimpplugin.h" +#include "gimpplugin-message.h" +#include "gimpplugindef.h" +#include "gimppluginerror.h" +#include "gimppluginmanager.h" +#define __YES_I_NEED_GIMP_PLUG_IN_MANAGER_CALL__ +#include "gimppluginmanager-call.h" +#include "gimppluginshm.h" +#include "gimptemporaryprocedure.h" +#include "plug-in-params.h" + +#include "gimp-intl.h" + + +static void +gimp_allow_set_foreground_window (GimpPlugIn *plug_in) +{ +#ifdef G_OS_WIN32 + AllowSetForegroundWindow (GetProcessId (plug_in->pid)); +#endif +} + +/* public functions */ + +void +gimp_plug_in_manager_call_query (GimpPlugInManager *manager, + GimpContext *context, + GimpPlugInDef *plug_in_def) +{ + GimpPlugIn *plug_in; + + g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager)); + g_return_if_fail (GIMP_IS_PDB_CONTEXT (context)); + g_return_if_fail (GIMP_IS_PLUG_IN_DEF (plug_in_def)); + + plug_in = gimp_plug_in_new (manager, context, NULL, + NULL, plug_in_def->file); + + if (plug_in) + { + plug_in->plug_in_def = plug_in_def; + + if (gimp_plug_in_open (plug_in, GIMP_PLUG_IN_CALL_QUERY, TRUE)) + { + while (plug_in->open) + { + GimpWireMessage msg; + + if (! gimp_wire_read_msg (plug_in->my_read, &msg, plug_in)) + { + gimp_plug_in_close (plug_in, TRUE); + } + else + { + gimp_plug_in_handle_message (plug_in, &msg); + gimp_wire_destroy (&msg); + } + } + } + + g_object_unref (plug_in); + } +} + +void +gimp_plug_in_manager_call_init (GimpPlugInManager *manager, + GimpContext *context, + GimpPlugInDef *plug_in_def) +{ + GimpPlugIn *plug_in; + + g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager)); + g_return_if_fail (GIMP_IS_PDB_CONTEXT (context)); + g_return_if_fail (GIMP_IS_PLUG_IN_DEF (plug_in_def)); + + plug_in = gimp_plug_in_new (manager, context, NULL, + NULL, plug_in_def->file); + + if (plug_in) + { + plug_in->plug_in_def = plug_in_def; + + if (gimp_plug_in_open (plug_in, GIMP_PLUG_IN_CALL_INIT, TRUE)) + { + while (plug_in->open) + { + GimpWireMessage msg; + + if (! gimp_wire_read_msg (plug_in->my_read, &msg, plug_in)) + { + gimp_plug_in_close (plug_in, TRUE); + } + else + { + gimp_plug_in_handle_message (plug_in, &msg); + gimp_wire_destroy (&msg); + } + } + } + + g_object_unref (plug_in); + } +} + +GimpValueArray * +gimp_plug_in_manager_call_run (GimpPlugInManager *manager, + GimpContext *context, + GimpProgress *progress, + GimpPlugInProcedure *procedure, + GimpValueArray *args, + gboolean synchronous, + GimpObject *display) +{ + GimpValueArray *return_vals = NULL; + GimpPlugIn *plug_in; + + g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), NULL); + g_return_val_if_fail (GIMP_IS_PDB_CONTEXT (context), NULL); + g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL); + g_return_val_if_fail (GIMP_IS_PLUG_IN_PROCEDURE (procedure), NULL); + g_return_val_if_fail (args != NULL, NULL); + g_return_val_if_fail (display == NULL || GIMP_IS_OBJECT (display), NULL); + + plug_in = gimp_plug_in_new (manager, context, progress, procedure, NULL); + + if (plug_in) + { + GimpCoreConfig *core_config = manager->gimp->config; + GimpGeglConfig *gegl_config = GIMP_GEGL_CONFIG (core_config); + GimpDisplayConfig *display_config = GIMP_DISPLAY_CONFIG (core_config); + GimpGuiConfig *gui_config = GIMP_GUI_CONFIG (core_config); + GPConfig config; + GPProcRun proc_run; + gint display_ID; + GObject *screen; + gint monitor; + GFile *icon_theme_dir; + + if (! gimp_plug_in_open (plug_in, GIMP_PLUG_IN_CALL_RUN, FALSE)) + { + const gchar *name = gimp_object_get_name (plug_in); + GError *error = g_error_new (GIMP_PLUG_IN_ERROR, + GIMP_PLUG_IN_EXECUTION_FAILED, + _("Failed to run plug-in \"%s\""), + name); + + g_object_unref (plug_in); + + return_vals = gimp_procedure_get_return_values (GIMP_PROCEDURE (procedure), + FALSE, error); + g_error_free (error); + + return return_vals; + } + + display_ID = display ? gimp_get_display_ID (manager->gimp, display) : -1; + + icon_theme_dir = gimp_get_icon_theme_dir (manager->gimp); + + config.version = GIMP_PROTOCOL_VERSION; + config.tile_width = GIMP_PLUG_IN_TILE_WIDTH; + config.tile_height = GIMP_PLUG_IN_TILE_HEIGHT; + config.shm_ID = (manager->shm ? + gimp_plug_in_shm_get_ID (manager->shm) : -1); + config.check_size = display_config->transparency_size; + config.check_type = display_config->transparency_type; + config.show_help_button = (gui_config->use_help && + gui_config->show_help_button); + config.use_cpu_accel = manager->gimp->use_cpu_accel; + config.use_opencl = gegl_config->use_opencl; + config.export_profile = core_config->export_color_profile; + config.export_exif = core_config->export_metadata_exif; + config.export_xmp = core_config->export_metadata_xmp; + config.export_iptc = core_config->export_metadata_iptc; + config.show_tooltips = gui_config->show_tooltips; + config.min_colors = 144; + config.gdisp_ID = display_ID; + config.app_name = (gchar *) g_get_application_name (); + config.wm_class = (gchar *) gimp_get_program_class (manager->gimp); + config.display_name = gimp_get_display_name (manager->gimp, + display_ID, + &screen, &monitor); + config.monitor_number = monitor; + config.timestamp = gimp_get_user_time (manager->gimp); + config.icon_theme_dir = icon_theme_dir ? + g_file_get_path (icon_theme_dir) : + NULL; + config.tile_cache_size = gegl_config->tile_cache_size; + config.swap_path = gegl_config->swap_path; + config.num_processors = gegl_config->num_processors; + config.swap_compression = gegl_config->swap_compression; + + proc_run.name = GIMP_PROCEDURE (procedure)->original_name; + proc_run.nparams = gimp_value_array_length (args); + proc_run.params = plug_in_args_to_params (args, FALSE); + + if (! gp_config_write (plug_in->my_write, &config, plug_in) || + ! gp_proc_run_write (plug_in->my_write, &proc_run, plug_in) || + ! gimp_wire_flush (plug_in->my_write, plug_in)) + { + const gchar *name = gimp_object_get_name (plug_in); + GError *error = g_error_new (GIMP_PLUG_IN_ERROR, + GIMP_PLUG_IN_EXECUTION_FAILED, + _("Failed to run plug-in \"%s\""), + name); + + g_free (config.display_name); + g_free (config.icon_theme_dir); + g_free (proc_run.params); + + g_object_unref (plug_in); + + return_vals = gimp_procedure_get_return_values (GIMP_PROCEDURE (procedure), + FALSE, error); + g_error_free (error); + + return return_vals; + } + + g_free (config.display_name); + g_free (config.icon_theme_dir); + g_free (proc_run.params); + + /* If this is an extension, + * wait for an installation-confirmation message + */ + if (GIMP_PROCEDURE (procedure)->proc_type == GIMP_EXTENSION) + { + plug_in->ext_main_loop = g_main_loop_new (NULL, FALSE); + + gimp_threads_leave (manager->gimp); + g_main_loop_run (plug_in->ext_main_loop); + gimp_threads_enter (manager->gimp); + + /* main_loop is quit in gimp_plug_in_handle_extension_ack() */ + + g_clear_pointer (&plug_in->ext_main_loop, g_main_loop_unref); + } + + /* If this plug-in is requested to run synchronously, + * wait for its return values + */ + if (synchronous) + { + GimpPlugInProcFrame *proc_frame = &plug_in->main_proc_frame; + + proc_frame->main_loop = g_main_loop_new (NULL, FALSE); + + gimp_threads_leave (manager->gimp); + g_main_loop_run (proc_frame->main_loop); + gimp_threads_enter (manager->gimp); + + /* main_loop is quit in gimp_plug_in_handle_proc_return() */ + + g_clear_pointer (&proc_frame->main_loop, g_main_loop_unref); + + return_vals = gimp_plug_in_proc_frame_get_return_values (proc_frame); + } + + g_object_unref (plug_in); + } + + return return_vals; +} + +GimpValueArray * +gimp_plug_in_manager_call_run_temp (GimpPlugInManager *manager, + GimpContext *context, + GimpProgress *progress, + GimpTemporaryProcedure *procedure, + GimpValueArray *args) +{ + GimpValueArray *return_vals = NULL; + GimpPlugIn *plug_in; + + g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), NULL); + g_return_val_if_fail (GIMP_IS_PDB_CONTEXT (context), NULL); + g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL); + g_return_val_if_fail (GIMP_IS_TEMPORARY_PROCEDURE (procedure), NULL); + g_return_val_if_fail (args != NULL, NULL); + + plug_in = procedure->plug_in; + + if (plug_in) + { + GimpPlugInProcFrame *proc_frame; + GPProcRun proc_run; + + proc_frame = gimp_plug_in_proc_frame_push (plug_in, context, progress, + procedure); + + proc_run.name = GIMP_PROCEDURE (procedure)->original_name; + proc_run.nparams = gimp_value_array_length (args); + proc_run.params = plug_in_args_to_params (args, FALSE); + + if (! gp_temp_proc_run_write (plug_in->my_write, &proc_run, plug_in) || + ! gimp_wire_flush (plug_in->my_write, plug_in)) + { + const gchar *name = gimp_object_get_name (plug_in); + GError *error = g_error_new (GIMP_PLUG_IN_ERROR, + GIMP_PLUG_IN_EXECUTION_FAILED, + _("Failed to run plug-in \"%s\""), + name); + + g_free (proc_run.params); + gimp_plug_in_proc_frame_pop (plug_in); + + return_vals = gimp_procedure_get_return_values (GIMP_PROCEDURE (procedure), + FALSE, error); + g_error_free (error); + + return return_vals; + } + gimp_allow_set_foreground_window (plug_in); + + g_free (proc_run.params); + + g_object_ref (plug_in); + gimp_plug_in_proc_frame_ref (proc_frame); + + gimp_plug_in_main_loop (plug_in); + + /* main_loop is quit and proc_frame is popped in + * gimp_plug_in_handle_temp_proc_return() + */ + + return_vals = gimp_plug_in_proc_frame_get_return_values (proc_frame); + + gimp_plug_in_proc_frame_unref (proc_frame, plug_in); + g_object_unref (plug_in); + } + + return return_vals; +} diff --git a/app/plug-in/gimppluginmanager-call.h b/app/plug-in/gimppluginmanager-call.h new file mode 100644 index 0000000..c456ab3 --- /dev/null +++ b/app/plug-in/gimppluginmanager-call.h @@ -0,0 +1,59 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimppluginmanager-call.h + * + * 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/>. + */ + +#ifndef __GIMP_PLUG_IN_MANAGER_CALL_H__ +#define __GIMP_PLUG_IN_MANAGER_CALL_H__ + +#ifndef __YES_I_NEED_GIMP_PLUG_IN_MANAGER_CALL__ +#error Do not use gimp_plug_in_manager_call_run*(), use gimp_procedure_execute*() instead. +#endif + + +/* Call the plug-in's query() function + */ +void gimp_plug_in_manager_call_query (GimpPlugInManager *manager, + GimpContext *context, + GimpPlugInDef *plug_in_def); + +/* Call the plug-in's init() function + */ +void gimp_plug_in_manager_call_init (GimpPlugInManager *manager, + GimpContext *context, + GimpPlugInDef *plug_in_def); + +/* Run a plug-in as if it were a procedure database procedure + */ +GimpValueArray * gimp_plug_in_manager_call_run (GimpPlugInManager *manager, + GimpContext *context, + GimpProgress *progress, + GimpPlugInProcedure *procedure, + GimpValueArray *args, + gboolean synchronous, + GimpObject *display); + +/* Run a temp plug-in proc as if it were a procedure database procedure + */ +GimpValueArray * gimp_plug_in_manager_call_run_temp (GimpPlugInManager *manager, + GimpContext *context, + GimpProgress *progress, + GimpTemporaryProcedure *procedure, + GimpValueArray *args); + + +#endif /* __GIMP_PLUG_IN_MANAGER_CALL_H__ */ diff --git a/app/plug-in/gimppluginmanager-data.c b/app/plug-in/gimppluginmanager-data.c new file mode 100644 index 0000000..08047b1 --- /dev/null +++ b/app/plug-in/gimppluginmanager-data.c @@ -0,0 +1,133 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimppluginmanager-data.c + * + * 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" + +#include <string.h> + +#include <gio/gio.h> + +#include "plug-in-types.h" + +#include "gimppluginmanager.h" +#include "gimppluginmanager-data.h" + + +typedef struct _GimpPlugInData GimpPlugInData; + +struct _GimpPlugInData +{ + gchar *identifier; + gint32 bytes; + guint8 *data; +}; + + +/* public functions */ + +void +gimp_plug_in_manager_data_free (GimpPlugInManager *manager) +{ + g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager)); + + if (manager->data_list) + { + GList *list; + + for (list = manager->data_list; + list; + list = g_list_next (list)) + { + GimpPlugInData *data = list->data; + + g_free (data->identifier); + g_free (data->data); + g_slice_free (GimpPlugInData, data); + } + + g_list_free (manager->data_list); + manager->data_list = NULL; + } +} + +void +gimp_plug_in_manager_set_data (GimpPlugInManager *manager, + const gchar *identifier, + gint32 bytes, + const guint8 *data) +{ + GimpPlugInData *plug_in_data; + GList *list; + + g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager)); + g_return_if_fail (identifier != NULL); + g_return_if_fail (bytes > 0); + g_return_if_fail (data != NULL); + + for (list = manager->data_list; list; list = g_list_next (list)) + { + plug_in_data = list->data; + + if (! strcmp (plug_in_data->identifier, identifier)) + break; + } + + /* If there isn't already data with the specified identifier, create one */ + if (list == NULL) + { + plug_in_data = g_slice_new0 (GimpPlugInData); + plug_in_data->identifier = g_strdup (identifier); + + manager->data_list = g_list_prepend (manager->data_list, plug_in_data); + } + else + { + g_free (plug_in_data->data); + } + + plug_in_data->bytes = bytes; + plug_in_data->data = g_memdup (data, bytes); +} + +const guint8 * +gimp_plug_in_manager_get_data (GimpPlugInManager *manager, + const gchar *identifier, + gint32 *bytes) +{ + GList *list; + + g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), NULL); + g_return_val_if_fail (identifier != NULL, NULL); + g_return_val_if_fail (bytes != NULL, NULL); + + *bytes = 0; + + for (list = manager->data_list; list; list = g_list_next (list)) + { + GimpPlugInData *plug_in_data = list->data; + + if (! strcmp (plug_in_data->identifier, identifier)) + { + *bytes = plug_in_data->bytes; + return plug_in_data->data; + } + } + + return NULL; +} diff --git a/app/plug-in/gimppluginmanager-data.h b/app/plug-in/gimppluginmanager-data.h new file mode 100644 index 0000000..1a88f32 --- /dev/null +++ b/app/plug-in/gimppluginmanager-data.h @@ -0,0 +1,35 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimppluginmanager-data.h + * + * 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/>. + */ + +#ifndef __GIMP_PLUG_IN_MANAGER_DATA_H__ +#define __GIMP_PLUG_IN_MANAGER_DATA_H__ + + +void gimp_plug_in_manager_data_free (GimpPlugInManager *manager); + +void gimp_plug_in_manager_set_data (GimpPlugInManager *manager, + const gchar *identifier, + gint32 bytes, + const guint8 *data); +const guint8 * gimp_plug_in_manager_get_data (GimpPlugInManager *manager, + const gchar *identifier, + gint32 *bytes); + + +#endif /* __GIMP_PLUG_IN_MANAGER_DATA_H__ */ diff --git a/app/plug-in/gimppluginmanager-file-procedure.c b/app/plug-in/gimppluginmanager-file-procedure.c new file mode 100644 index 0000000..ec11ef6 --- /dev/null +++ b/app/plug-in/gimppluginmanager-file-procedure.c @@ -0,0 +1,716 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995, 1996, 1997 Spencer Kimball and Peter Mattis + * Copyright (C) 1997 Josh MacDonald + * + * gimppluginmanager-file-procedure.c + * + * 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" + +#include <errno.h> +#include <stdlib.h> + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpbase/gimpbase.h" + +#include "plug-in-types.h" + +#include "core/gimp-utils.h" + +#include "gimppluginmanager-file-procedure.h" +#include "gimppluginprocedure.h" + +#include "gimp-log.h" + +#include "gimp-intl.h" + + +typedef enum +{ + /* positive values indicate the length of a matching magic */ + + FILE_MATCH_NONE = 0, + FILE_MATCH_SIZE = -1 +} FileMatchType; + + +/* local function prototypes */ + +static GimpPlugInProcedure * file_proc_find_by_prefix (GSList *procs, + GFile *file, + gboolean skip_magic); +static GimpPlugInProcedure * file_proc_find_by_extension (GSList *procs, + GFile *file, + gboolean skip_magic); +static GimpPlugInProcedure * file_proc_find_by_name (GSList *procs, + GFile *file, + gboolean skip_magic); + +static void file_convert_string (const gchar *instr, + gchar *outmem, + gint maxmem, + gint *nmem); +static FileMatchType file_check_single_magic (const gchar *offset, + const gchar *type, + const gchar *value, + const guchar *file_head, + gint headsize, + GFile *file, + GInputStream *input); +static FileMatchType file_check_magic_list (GSList *magics_list, + const guchar *head, + gint headsize, + GFile *file, + GInputStream *input); + + +/* public functions */ + +GimpPlugInProcedure * +file_procedure_find (GSList *procs, + GFile *file, + GError **error) +{ + GimpPlugInProcedure *file_proc; + GimpPlugInProcedure *size_matched_proc = NULL; + gint size_match_count = 0; + + g_return_val_if_fail (procs != NULL, NULL); + g_return_val_if_fail (G_IS_FILE (file), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* First, check magicless prefixes/suffixes */ + file_proc = file_proc_find_by_name (procs, file, TRUE); + + if (file_proc) + return file_proc; + + /* Then look for magics, but not on remote files */ + if (g_file_is_native (file)) + { + GSList *list; + GInputStream *input = NULL; + gboolean opened = FALSE; + gsize head_size = 0; + guchar head[256]; + FileMatchType best_match_val = FILE_MATCH_NONE; + GimpPlugInProcedure *best_file_proc = NULL; + + for (list = procs; list; list = g_slist_next (list)) + { + file_proc = list->data; + + if (file_proc->magics_list) + { + if (G_UNLIKELY (! opened)) + { + input = G_INPUT_STREAM (g_file_read (file, NULL, error)); + + if (input) + { + g_input_stream_read_all (input, + head, sizeof (head), + &head_size, NULL, error); + + if (head_size < 4) + { + g_object_unref (input); + input = NULL; + } + else + { + GDataInputStream *data_input; + + data_input = g_data_input_stream_new (input); + g_object_unref (input); + input = G_INPUT_STREAM (data_input); + } + } + + opened = TRUE; + } + + if (head_size >= 4) + { + FileMatchType match_val; + + match_val = file_check_magic_list (file_proc->magics_list, + head, head_size, + file, input); + + if (match_val == FILE_MATCH_SIZE) + { + /* Use it only if no other magic matches */ + size_match_count++; + size_matched_proc = file_proc; + } + else if (match_val != FILE_MATCH_NONE) + { + GIMP_LOG (MAGIC_MATCH, + "magic match %d on %s\n", + match_val, + gimp_object_get_name (file_proc)); + + if (match_val > best_match_val) + { + best_match_val = match_val; + best_file_proc = file_proc; + } + } + } + } + } + + if (input) + g_object_unref (input); + + if (best_file_proc) + { + GIMP_LOG (MAGIC_MATCH, + "best magic match on %s\n", + gimp_object_get_name (best_file_proc)); + + return best_file_proc; + } + } + + if (size_match_count == 1) + return size_matched_proc; + + /* As a last resort, try matching by name, not skipping magic procs */ + file_proc = file_proc_find_by_name (procs, file, FALSE); + + if (file_proc) + { + /* we found a procedure, clear error that might have been set */ + g_clear_error (error); + } + else + { + /* set an error message unless one was already set */ + if (error && *error == NULL) + g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + _("Unknown file type")); + } + + return file_proc; +} + +GimpPlugInProcedure * +file_procedure_find_by_prefix (GSList *procs, + GFile *file) +{ + g_return_val_if_fail (G_IS_FILE (file), NULL); + + return file_proc_find_by_prefix (procs, file, FALSE); +} + +GimpPlugInProcedure * +file_procedure_find_by_extension (GSList *procs, + GFile *file) +{ + g_return_val_if_fail (G_IS_FILE (file), NULL); + + return file_proc_find_by_extension (procs, file, FALSE); +} + +GimpPlugInProcedure * +file_procedure_find_by_mime_type (GSList *procs, + const gchar *mime_type) +{ + GSList *list; + + g_return_val_if_fail (mime_type != NULL, NULL); + + for (list = procs; list; list = g_slist_next (list)) + { + GimpPlugInProcedure *proc = list->data; + GSList *mime; + + for (mime = proc->mime_types_list; mime; mime = g_slist_next (mime)) + { + if (! strcmp (mime_type, mime->data)) + return proc; + } + } + + return NULL; +} + + +/* private functions */ + +static GimpPlugInProcedure * +file_proc_find_by_prefix (GSList *procs, + GFile *file, + gboolean skip_magic) +{ + gchar *uri = g_file_get_uri (file); + GSList *p; + + for (p = procs; p; p = g_slist_next (p)) + { + GimpPlugInProcedure *proc = p->data; + GSList *prefixes; + + if (skip_magic && proc->magics_list) + continue; + + for (prefixes = proc->prefixes_list; + prefixes; + prefixes = g_slist_next (prefixes)) + { + if (g_str_has_prefix (uri, prefixes->data)) + { + g_free (uri); + return proc; + } + } + } + + g_free (uri); + + return NULL; +} + +static GimpPlugInProcedure * +file_proc_find_by_extension (GSList *procs, + GFile *file, + gboolean skip_magic) +{ + gchar *ext = gimp_file_get_extension (file); + + if (ext) + { + GSList *p; + + for (p = procs; p; p = g_slist_next (p)) + { + GimpPlugInProcedure *proc = p->data; + + if (skip_magic && proc->magics_list) + continue; + + if (g_slist_find_custom (proc->extensions_list, + ext + 1, + (GCompareFunc) g_ascii_strcasecmp)) + { + g_free (ext); + + return proc; + } + } + + g_free (ext); + } + + return NULL; +} + +static GimpPlugInProcedure * +file_proc_find_by_name (GSList *procs, + GFile *file, + gboolean skip_magic) +{ + GimpPlugInProcedure *proc; + + proc = file_proc_find_by_prefix (procs, file, skip_magic); + + if (! proc) + proc = file_proc_find_by_extension (procs, file, skip_magic); + + return proc; +} + +static void +file_convert_string (const gchar *instr, + gchar *outmem, + gint maxmem, + gint *nmem) +{ + /* Convert a string in C-notation to array of char */ + const guchar *uin = (const guchar *) instr; + guchar *uout = (guchar *) outmem; + guchar tmp[5], *tmpptr; + guint k; + + while ((*uin != '\0') && ((((gchar *) uout) - outmem) < maxmem)) + { + if (*uin != '\\') /* Not an escaped character ? */ + { + *(uout++) = *(uin++); + continue; + } + + if (*(++uin) == '\0') + { + *(uout++) = '\\'; + break; + } + + switch (*uin) + { + case '0': case '1': case '2': case '3': /* octal */ + for (tmpptr = tmp; (tmpptr - tmp) <= 3;) + { + *(tmpptr++) = *(uin++); + if ( (*uin == '\0') || (!g_ascii_isdigit (*uin)) + || (*uin == '8') || (*uin == '9')) + break; + } + + *tmpptr = '\0'; + sscanf ((gchar *) tmp, "%o", &k); + *(uout++) = k; + break; + + case 'a': *(uout++) = '\a'; uin++; break; + case 'b': *(uout++) = '\b'; uin++; break; + case 't': *(uout++) = '\t'; uin++; break; + case 'n': *(uout++) = '\n'; uin++; break; + case 'v': *(uout++) = '\v'; uin++; break; + case 'f': *(uout++) = '\f'; uin++; break; + case 'r': *(uout++) = '\r'; uin++; break; + + default : *(uout++) = *(uin++); break; + } + } + + *nmem = ((gchar *) uout) - outmem; +} + +static FileMatchType +file_check_single_magic (const gchar *offset, + const gchar *type, + const gchar *value, + const guchar *file_head, + gint headsize, + GFile *file, + GInputStream *input) + +{ + FileMatchType found = FILE_MATCH_NONE; + glong offs; + gulong num_testval; + gulong num_operator_val; + gint numbytes, k; + const gchar *num_operator_ptr; + gchar num_operator; + + /* Check offset */ + if (sscanf (offset, "%ld", &offs) != 1) + return FILE_MATCH_NONE; + + /* Check type of test */ + num_operator_ptr = NULL; + num_operator = '\0'; + + if (g_str_has_prefix (type, "byte")) + { + numbytes = 1; + num_operator_ptr = type + strlen ("byte"); + } + else if (g_str_has_prefix (type, "short")) + { + numbytes = 2; + num_operator_ptr = type + strlen ("short"); + } + else if (g_str_has_prefix (type, "long")) + { + numbytes = 4; + num_operator_ptr = type + strlen ("long"); + } + else if (g_str_has_prefix (type, "size")) + { + numbytes = 5; + } + else if (strcmp (type, "string") == 0) + { + numbytes = 0; + } + else + { + return FILE_MATCH_NONE; + } + + /* Check numerical operator value if present */ + if (num_operator_ptr && (*num_operator_ptr == '&')) + { + if (g_ascii_isdigit (num_operator_ptr[1])) + { + if (num_operator_ptr[1] != '0') /* decimal */ + sscanf (num_operator_ptr+1, "%lu", &num_operator_val); + else if (num_operator_ptr[2] == 'x') /* hexadecimal */ + sscanf (num_operator_ptr+3, "%lx", &num_operator_val); + else /* octal */ + sscanf (num_operator_ptr+2, "%lo", &num_operator_val); + + num_operator = *num_operator_ptr; + } + } + + if (numbytes > 0) + { + /* Numerical test */ + + gchar num_test = '='; + gulong fileval = 0; + + /* Check test value */ + if ((value[0] == '>') || (value[0] == '<')) + { + num_test = value[0]; + value++; + } + + errno = 0; + num_testval = strtol (value, NULL, 0); + + if (errno != 0) + return FILE_MATCH_NONE; + + if (numbytes == 5) + { + /* Check for file size */ + + GFileInfo *info = g_file_query_info (file, + G_FILE_ATTRIBUTE_STANDARD_SIZE, + G_FILE_QUERY_INFO_NONE, + NULL, NULL); + if (! info) + return FILE_MATCH_NONE; + + fileval = g_file_info_get_size (info); + g_object_unref (info); + } + else if (offs >= 0 && + (offs + numbytes <= headsize)) + { + /* We have it in memory */ + + for (k = 0; k < numbytes; k++) + fileval = (fileval << 8) | (glong) file_head[offs + k]; + } + else + { + /* Read it from file */ + + if (! g_seekable_seek (G_SEEKABLE (input), offs, + (offs >= 0) ? G_SEEK_SET : G_SEEK_END, + NULL, NULL)) + return FILE_MATCH_NONE; + + for (k = 0; k < numbytes; k++) + { + guchar byte; + GError *error = NULL; + + byte = g_data_input_stream_read_byte (G_DATA_INPUT_STREAM (input), + NULL, &error); + if (error) + { + g_clear_error (&error); + return FILE_MATCH_NONE; + } + + fileval = (fileval << 8) | byte; + } + } + + if (num_operator == '&') + fileval &= num_operator_val; + + if (num_test == '<') + { + if (fileval < num_testval) + found = numbytes; + } + else if (num_test == '>') + { + if (fileval > num_testval) + found = numbytes; + } + else + { + if (fileval == num_testval) + found = numbytes; + } + + if (found && (numbytes == 5)) + found = FILE_MATCH_SIZE; + } + else if (numbytes == 0) + { + /* String test */ + + gchar mem_testval[256]; + + file_convert_string (value, + mem_testval, sizeof (mem_testval), + &numbytes); + + if (numbytes <= 0) + return FILE_MATCH_NONE; + + if (offs >= 0 && + (offs + numbytes <= headsize)) + { + /* We have it in memory */ + + if (memcmp (mem_testval, file_head + offs, numbytes) == 0) + found = numbytes; + } + else + { + /* Read it from file */ + + if (! g_seekable_seek (G_SEEKABLE (input), offs, + (offs >= 0) ? G_SEEK_SET : G_SEEK_END, + NULL, NULL)) + return FILE_MATCH_NONE; + + for (k = 0; k < numbytes; k++) + { + guchar byte; + GError *error = NULL; + + byte = g_data_input_stream_read_byte (G_DATA_INPUT_STREAM (input), + NULL, &error); + if (error) + { + g_clear_error (&error); + + return FILE_MATCH_NONE; + } + + if (byte != mem_testval[k]) + return FILE_MATCH_NONE; + } + + found = numbytes; + } + } + + return found; +} + +static FileMatchType +file_check_magic_list (GSList *magics_list, + const guchar *head, + gint headsize, + GFile *file, + GInputStream *input) + +{ + gboolean and = FALSE; + gboolean found = FALSE; + FileMatchType best_match_val = FILE_MATCH_NONE; + FileMatchType match_val = FILE_MATCH_NONE; + + for (; magics_list; magics_list = magics_list->next) + { + const gchar *offset; + const gchar *type; + const gchar *value; + FileMatchType single_match_val = FILE_MATCH_NONE; + + if ((offset = magics_list->data) == NULL) return FILE_MATCH_NONE; + if ((magics_list = magics_list->next) == NULL) return FILE_MATCH_NONE; + if ((type = magics_list->data) == NULL) return FILE_MATCH_NONE; + if ((magics_list = magics_list->next) == NULL) return FILE_MATCH_NONE; + if ((value = magics_list->data) == NULL) return FILE_MATCH_NONE; + + single_match_val = file_check_single_magic (offset, type, value, + head, headsize, + file, input); + + if (and) + found = found && (single_match_val != FILE_MATCH_NONE); + else + found = (single_match_val != FILE_MATCH_NONE); + + if (found) + { + if (match_val == FILE_MATCH_NONE) + { + /* if we have no match yet, this is it in any case */ + + match_val = single_match_val; + } + else if (single_match_val != FILE_MATCH_NONE) + { + /* else if we have a match on this one, combine it with the + * existing return value + */ + + if (single_match_val == FILE_MATCH_SIZE) + { + /* if we already have a magic match, simply increase + * that by one to indicate "better match", not perfect + * but better than losing the additional size match + * entirely + */ + if (match_val != FILE_MATCH_SIZE) + match_val += 1; + } + else + { + /* if we already have a magic match, simply add to its + * length; otherwise if we already have a size match, + * combine it with this match, see comment above + */ + if (match_val != FILE_MATCH_SIZE) + match_val += single_match_val; + else + match_val = single_match_val + 1; + } + } + } + else + { + match_val = FILE_MATCH_NONE; + } + + and = (strchr (offset, '&') != NULL); + + if (! and) + { + /* when done with this 'and' list, update best_match_val */ + + if (best_match_val == FILE_MATCH_NONE) + { + /* if we have no best match yet, this is it */ + + best_match_val = match_val; + } + else if (match_val != FILE_MATCH_NONE) + { + /* otherwise if this was a match, update the best match, note + * that by using MAX we will not overwrite a magic match + * with a size match + */ + + best_match_val = MAX (best_match_val, match_val); + } + + match_val = FILE_MATCH_NONE; + } + } + + return best_match_val; +} diff --git a/app/plug-in/gimppluginmanager-file-procedure.h b/app/plug-in/gimppluginmanager-file-procedure.h new file mode 100644 index 0000000..3508551 --- /dev/null +++ b/app/plug-in/gimppluginmanager-file-procedure.h @@ -0,0 +1,37 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimppluginmanager-file-procedure.h + * + * 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/>. + */ + +#ifndef __GIMP_PLUG_IN_MANAGER_FILE_PROCEDURE_H__ +#define __GIMP_PLUG_IN_MANAGER_FILE_PROCEDURE_H__ + + + +GimpPlugInProcedure *file_procedure_find (GSList *procs, + GFile *file, + GError **error); +GimpPlugInProcedure *file_procedure_find_by_prefix (GSList *procs, + GFile *file); +GimpPlugInProcedure *file_procedure_find_by_extension (GSList *procs, + GFile *file); + +GimpPlugInProcedure *file_procedure_find_by_mime_type (GSList *procs, + const gchar *mime_type); + + +#endif /* __GIMP_PLUG_IN_MANAGER_FILE_PROCEDURE_H__ */ diff --git a/app/plug-in/gimppluginmanager-file.c b/app/plug-in/gimppluginmanager-file.c new file mode 100644 index 0000000..4da5e55 --- /dev/null +++ b/app/plug-in/gimppluginmanager-file.c @@ -0,0 +1,451 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimppluginmanager-file.c + * + * 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" + +#include <string.h> + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "plug-in-types.h" + +#include "core/gimp.h" +#include "core/gimpparamspecs.h" + +#include "gimpplugin.h" +#include "gimpplugindef.h" +#include "gimppluginmanager.h" +#include "gimppluginmanager-file.h" +#include "gimppluginmanager-file-procedure.h" +#include "gimppluginprocedure.h" + + +static gboolean file_procedure_in_group (GimpPlugInProcedure *file_proc, + GimpFileProcedureGroup group); + + +/* public functions */ + +gboolean +gimp_plug_in_manager_register_load_handler (GimpPlugInManager *manager, + const gchar *name, + const gchar *extensions, + const gchar *prefixes, + const gchar *magics) +{ + GimpPlugInProcedure *file_proc; + GimpProcedure *procedure; + GSList *list; + + g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), FALSE); + g_return_val_if_fail (name != NULL, FALSE); + + if (manager->current_plug_in && manager->current_plug_in->plug_in_def) + list = manager->current_plug_in->plug_in_def->procedures; + else + list = manager->plug_in_procedures; + + file_proc = gimp_plug_in_procedure_find (list, name); + + if (! file_proc) + { + gimp_message (manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "attempt to register nonexistent load handler \"%s\"", + name); + return FALSE; + } + + procedure = GIMP_PROCEDURE (file_proc); + + if ((procedure->num_args < 3) || + (procedure->num_values < 1) || + ! GIMP_IS_PARAM_SPEC_INT32 (procedure->args[0]) || + ! G_IS_PARAM_SPEC_STRING (procedure->args[1]) || + ! G_IS_PARAM_SPEC_STRING (procedure->args[2]) || + ! GIMP_IS_PARAM_SPEC_IMAGE_ID (procedure->values[0])) + { + gimp_message (manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "load handler \"%s\" does not take the standard " + "load handler args", name); + return FALSE; + } + + gimp_plug_in_procedure_set_file_proc (file_proc, + extensions, prefixes, magics); + + if (! g_slist_find (manager->load_procs, file_proc)) + manager->load_procs = g_slist_prepend (manager->load_procs, file_proc); + + return TRUE; +} + +gboolean +gimp_plug_in_manager_register_save_handler (GimpPlugInManager *manager, + const gchar *name, + const gchar *extensions, + const gchar *prefixes) +{ + GimpPlugInProcedure *file_proc; + GimpProcedure *procedure; + GSList *list; + + g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), FALSE); + g_return_val_if_fail (name != NULL, FALSE); + + if (manager->current_plug_in && manager->current_plug_in->plug_in_def) + list = manager->current_plug_in->plug_in_def->procedures; + else + list = manager->plug_in_procedures; + + file_proc = gimp_plug_in_procedure_find (list, name); + + if (! file_proc) + { + gimp_message (manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "attempt to register nonexistent save handler \"%s\"", + name); + return FALSE; + } + + procedure = GIMP_PROCEDURE (file_proc); + + if ((procedure->num_args < 5) || + ! GIMP_IS_PARAM_SPEC_INT32 (procedure->args[0]) || + ! GIMP_IS_PARAM_SPEC_IMAGE_ID (procedure->args[1]) || + ! GIMP_IS_PARAM_SPEC_DRAWABLE_ID (procedure->args[2]) || + ! G_IS_PARAM_SPEC_STRING (procedure->args[3]) || + ! G_IS_PARAM_SPEC_STRING (procedure->args[4])) + { + gimp_message (manager->gimp, NULL, GIMP_MESSAGE_ERROR, + "save handler \"%s\" does not take the standard " + "save handler args", name); + return FALSE; + } + + gimp_plug_in_procedure_set_file_proc (file_proc, + extensions, prefixes, NULL); + + if (file_procedure_in_group (file_proc, GIMP_FILE_PROCEDURE_GROUP_SAVE)) + { + if (! g_slist_find (manager->save_procs, file_proc)) + manager->save_procs = g_slist_prepend (manager->save_procs, file_proc); + } + + if (file_procedure_in_group (file_proc, GIMP_FILE_PROCEDURE_GROUP_EXPORT)) + { + if (! g_slist_find (manager->export_procs, file_proc)) + manager->export_procs = g_slist_prepend (manager->export_procs, file_proc); + } + + return TRUE; +} + +gboolean +gimp_plug_in_manager_register_priority (GimpPlugInManager *manager, + const gchar *name, + gint priority) +{ + GimpPlugInProcedure *file_proc; + GSList *list; + + g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), FALSE); + g_return_val_if_fail (name != NULL, FALSE); + + if (manager->current_plug_in && manager->current_plug_in->plug_in_def) + list = manager->current_plug_in->plug_in_def->procedures; + else + list = manager->plug_in_procedures; + + file_proc = gimp_plug_in_procedure_find (list, name); + + if (! file_proc) + return FALSE; + + gimp_plug_in_procedure_set_priority (file_proc, priority); + + return TRUE; +} + +gboolean +gimp_plug_in_manager_register_mime_types (GimpPlugInManager *manager, + const gchar *name, + const gchar *mime_types) +{ + GimpPlugInProcedure *file_proc; + GSList *list; + + g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), FALSE); + g_return_val_if_fail (name != NULL, FALSE); + g_return_val_if_fail (mime_types != NULL, FALSE); + + if (manager->current_plug_in && manager->current_plug_in->plug_in_def) + list = manager->current_plug_in->plug_in_def->procedures; + else + list = manager->plug_in_procedures; + + file_proc = gimp_plug_in_procedure_find (list, name); + + if (! file_proc) + return FALSE; + + gimp_plug_in_procedure_set_mime_types (file_proc, mime_types); + + return TRUE; +} + +gboolean +gimp_plug_in_manager_register_handles_uri (GimpPlugInManager *manager, + const gchar *name) +{ + GimpPlugInProcedure *file_proc; + GSList *list; + + g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), FALSE); + g_return_val_if_fail (name != NULL, FALSE); + + if (manager->current_plug_in && manager->current_plug_in->plug_in_def) + list = manager->current_plug_in->plug_in_def->procedures; + else + list = manager->plug_in_procedures; + + file_proc = gimp_plug_in_procedure_find (list, name); + + if (! file_proc) + return FALSE; + + gimp_plug_in_procedure_set_handles_uri (file_proc); + + return TRUE; +} + +gboolean +gimp_plug_in_manager_register_handles_raw (GimpPlugInManager *manager, + const gchar *name) +{ + GimpPlugInProcedure *file_proc; + GSList *list; + + g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), FALSE); + g_return_val_if_fail (name != NULL, FALSE); + + if (manager->current_plug_in && manager->current_plug_in->plug_in_def) + list = manager->current_plug_in->plug_in_def->procedures; + else + list = manager->plug_in_procedures; + + file_proc = gimp_plug_in_procedure_find (list, name); + + if (! file_proc) + return FALSE; + + gimp_plug_in_procedure_set_handles_raw (file_proc); + + return TRUE; +} + +gboolean +gimp_plug_in_manager_register_thumb_loader (GimpPlugInManager *manager, + const gchar *load_proc, + const gchar *thumb_proc) +{ + GimpPlugInProcedure *file_proc; + GSList *list; + + g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), FALSE); + g_return_val_if_fail (load_proc, FALSE); + g_return_val_if_fail (thumb_proc, FALSE); + + if (manager->current_plug_in && manager->current_plug_in->plug_in_def) + list = manager->current_plug_in->plug_in_def->procedures; + else + list = manager->plug_in_procedures; + + file_proc = gimp_plug_in_procedure_find (list, load_proc); + + if (! file_proc) + return FALSE; + + gimp_plug_in_procedure_set_thumb_loader (file_proc, thumb_proc); + + return TRUE; +} + +GSList * +gimp_plug_in_manager_get_file_procedures (GimpPlugInManager *manager, + GimpFileProcedureGroup group) +{ + g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), NULL); + + switch (group) + { + case GIMP_FILE_PROCEDURE_GROUP_NONE: + return NULL; + + case GIMP_FILE_PROCEDURE_GROUP_OPEN: + return manager->display_load_procs; + + case GIMP_FILE_PROCEDURE_GROUP_SAVE: + return manager->display_save_procs; + + case GIMP_FILE_PROCEDURE_GROUP_EXPORT: + return manager->display_export_procs; + + default: + g_return_val_if_reached (NULL); + } +} + +GimpPlugInProcedure * +gimp_plug_in_manager_file_procedure_find (GimpPlugInManager *manager, + GimpFileProcedureGroup group, + GFile *file, + GError **error) +{ + g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), NULL); + g_return_val_if_fail (G_IS_FILE (file), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + switch (group) + { + case GIMP_FILE_PROCEDURE_GROUP_OPEN: + return file_procedure_find (manager->load_procs, file, error); + + case GIMP_FILE_PROCEDURE_GROUP_SAVE: + return file_procedure_find (manager->save_procs, file, error); + + case GIMP_FILE_PROCEDURE_GROUP_EXPORT: + return file_procedure_find (manager->export_procs, file, error); + + default: + g_return_val_if_reached (NULL); + } +} + +GimpPlugInProcedure * +gimp_plug_in_manager_file_procedure_find_by_prefix (GimpPlugInManager *manager, + GimpFileProcedureGroup group, + GFile *file) +{ + g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), NULL); + g_return_val_if_fail (G_IS_FILE (file), NULL); + + switch (group) + { + case GIMP_FILE_PROCEDURE_GROUP_OPEN: + return file_procedure_find_by_prefix (manager->load_procs, file); + + case GIMP_FILE_PROCEDURE_GROUP_SAVE: + return file_procedure_find_by_prefix (manager->save_procs, file); + + case GIMP_FILE_PROCEDURE_GROUP_EXPORT: + return file_procedure_find_by_prefix (manager->export_procs, file); + + default: + g_return_val_if_reached (NULL); + } +} + +GimpPlugInProcedure * +gimp_plug_in_manager_file_procedure_find_by_extension (GimpPlugInManager *manager, + GimpFileProcedureGroup group, + GFile *file) +{ + g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), NULL); + g_return_val_if_fail (G_IS_FILE (file), NULL); + + switch (group) + { + case GIMP_FILE_PROCEDURE_GROUP_OPEN: + return file_procedure_find_by_extension (manager->load_procs, file); + + case GIMP_FILE_PROCEDURE_GROUP_SAVE: + return file_procedure_find_by_extension (manager->save_procs, file); + + case GIMP_FILE_PROCEDURE_GROUP_EXPORT: + return file_procedure_find_by_extension (manager->export_procs, file); + + default: + g_return_val_if_reached (NULL); + } +} + +GimpPlugInProcedure * +gimp_plug_in_manager_file_procedure_find_by_mime_type (GimpPlugInManager *manager, + GimpFileProcedureGroup group, + const gchar *mime_type) +{ + g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), NULL); + g_return_val_if_fail (mime_type != NULL, NULL); + + switch (group) + { + case GIMP_FILE_PROCEDURE_GROUP_OPEN: + return file_procedure_find_by_mime_type (manager->load_procs, mime_type); + + case GIMP_FILE_PROCEDURE_GROUP_SAVE: + return file_procedure_find_by_mime_type (manager->save_procs, mime_type); + + case GIMP_FILE_PROCEDURE_GROUP_EXPORT: + return file_procedure_find_by_mime_type (manager->export_procs, mime_type); + + default: + g_return_val_if_reached (NULL); + } +} + + +/* private functions */ + +static gboolean +file_procedure_in_group (GimpPlugInProcedure *file_proc, + GimpFileProcedureGroup group) +{ + const gchar *name = gimp_object_get_name (file_proc); + gboolean is_xcf_save = FALSE; + gboolean is_filter = FALSE; + + is_xcf_save = (strcmp (name, "gimp-xcf-save") == 0); + + is_filter = (strcmp (name, "file-gz-save") == 0 || + strcmp (name, "file-bz2-save") == 0 || + strcmp (name, "file-xz-save") == 0); + + switch (group) + { + case GIMP_FILE_PROCEDURE_GROUP_NONE: + return FALSE; + + case GIMP_FILE_PROCEDURE_GROUP_SAVE: + /* Only .xcf shall pass */ + return is_xcf_save || is_filter; + + case GIMP_FILE_PROCEDURE_GROUP_EXPORT: + /* Anything but .xcf shall pass */ + return ! is_xcf_save; + + case GIMP_FILE_PROCEDURE_GROUP_OPEN: + /* No filter applied for Open */ + return TRUE; + + default: + case GIMP_FILE_PROCEDURE_GROUP_ANY: + return TRUE; + } +} diff --git a/app/plug-in/gimppluginmanager-file.h b/app/plug-in/gimppluginmanager-file.h new file mode 100644 index 0000000..8408218 --- /dev/null +++ b/app/plug-in/gimppluginmanager-file.h @@ -0,0 +1,75 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimppluginmanager-file.h + * + * 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/>. + */ + +#ifndef __GIMP_PLUG_IN_MANAGER_FILE_H__ +#define __GIMP_PLUG_IN_MANAGER_FILE_H__ + + +gboolean gimp_plug_in_manager_register_load_handler (GimpPlugInManager *manager, + const gchar *name, + const gchar *extensions, + const gchar *prefixes, + const gchar *magics); +gboolean gimp_plug_in_manager_register_save_handler (GimpPlugInManager *manager, + const gchar *name, + const gchar *extensions, + const gchar *prefixes); + +gboolean gimp_plug_in_manager_register_priority (GimpPlugInManager *manager, + const gchar *name, + gint priority); + + +gboolean gimp_plug_in_manager_register_mime_types (GimpPlugInManager *manager, + const gchar *name, + const gchar *mime_types); + +gboolean gimp_plug_in_manager_register_handles_uri (GimpPlugInManager *manager, + const gchar *name); + +gboolean gimp_plug_in_manager_register_handles_raw (GimpPlugInManager *manager, + const gchar *name); + +gboolean gimp_plug_in_manager_register_thumb_loader (GimpPlugInManager *manager, + const gchar *load_proc, + const gchar *thumb_proc); + +GSList * gimp_plug_in_manager_get_file_procedures (GimpPlugInManager *manager, + GimpFileProcedureGroup group); + +GimpPlugInProcedure * +gimp_plug_in_manager_file_procedure_find (GimpPlugInManager *manager, + GimpFileProcedureGroup group, + GFile *file, + GError **error); +GimpPlugInProcedure * +gimp_plug_in_manager_file_procedure_find_by_prefix (GimpPlugInManager *manager, + GimpFileProcedureGroup group, + GFile *file); +GimpPlugInProcedure * +gimp_plug_in_manager_file_procedure_find_by_extension (GimpPlugInManager *manager, + GimpFileProcedureGroup group, + GFile *file); +GimpPlugInProcedure * +gimp_plug_in_manager_file_procedure_find_by_mime_type (GimpPlugInManager *manager, + GimpFileProcedureGroup group, + const gchar *mime_type); + + +#endif /* __GIMP_PLUG_IN_MANAGER_FILE_H__ */ diff --git a/app/plug-in/gimppluginmanager-help-domain.c b/app/plug-in/gimppluginmanager-help-domain.c new file mode 100644 index 0000000..96ea41b --- /dev/null +++ b/app/plug-in/gimppluginmanager-help-domain.c @@ -0,0 +1,160 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimppluginmanager-help-domain.c + * + * 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" + +#include <string.h> + +#include <gio/gio.h> + +#include "plug-in-types.h" + +#include "gimppluginmanager.h" +#include "gimppluginmanager-help-domain.h" + + +typedef struct _GimpPlugInHelpDomain GimpPlugInHelpDomain; + +struct _GimpPlugInHelpDomain +{ + GFile *file; + gchar *domain_name; + gchar *domain_uri; +}; + + +void +gimp_plug_in_manager_help_domain_exit (GimpPlugInManager *manager) +{ + GSList *list; + + g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager)); + + for (list = manager->help_domains; list; list = list->next) + { + GimpPlugInHelpDomain *domain = list->data; + + g_object_unref (domain->file); + g_free (domain->domain_name); + g_free (domain->domain_uri); + g_slice_free (GimpPlugInHelpDomain, domain); + } + + g_slist_free (manager->help_domains); + manager->help_domains = NULL; +} + +void +gimp_plug_in_manager_add_help_domain (GimpPlugInManager *manager, + GFile *file, + const gchar *domain_name, + const gchar *domain_uri) +{ + GimpPlugInHelpDomain *domain; + + g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager)); + g_return_if_fail (G_IS_FILE (file)); + g_return_if_fail (domain_name != NULL); + + domain = g_slice_new (GimpPlugInHelpDomain); + + domain->file = g_object_ref (file); + domain->domain_name = g_strdup (domain_name); + domain->domain_uri = g_strdup (domain_uri); + + manager->help_domains = g_slist_prepend (manager->help_domains, domain); + +#ifdef VERBOSE + g_print ("added help domain \"%s\" for base uri \"%s\"\n", + domain->domain_name ? domain->domain_name : "(null)", + domain->domain_uri ? domain->domain_uri : "(null)"); +#endif +} + +const gchar * +gimp_plug_in_manager_get_help_domain (GimpPlugInManager *manager, + GFile *file, + const gchar **domain_uri) +{ + GSList *list; + + g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), NULL); + g_return_val_if_fail (file == NULL || G_IS_FILE (file), NULL); + + if (domain_uri) + *domain_uri = NULL; + + /* A NULL prog_name is GIMP itself, return the default domain */ + if (! file) + return NULL; + + for (list = manager->help_domains; list; list = list->next) + { + GimpPlugInHelpDomain *domain = list->data; + + if (domain && domain->file && + g_file_equal (domain->file, file)) + { + if (domain_uri && domain->domain_uri) + *domain_uri = domain->domain_uri; + + return domain->domain_name; + } + } + + return NULL; +} + +gint +gimp_plug_in_manager_get_help_domains (GimpPlugInManager *manager, + gchar ***help_domains, + gchar ***help_uris) +{ + gint n_domains; + + g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), 0); + g_return_val_if_fail (help_domains != NULL, 0); + g_return_val_if_fail (help_uris != NULL, 0); + + n_domains = g_slist_length (manager->help_domains); + + if (n_domains > 0) + { + GSList *list; + gint i; + + *help_domains = g_new0 (gchar *, n_domains + 1); + *help_uris = g_new0 (gchar *, n_domains + 1); + + for (list = manager->help_domains, i = 0; list; list = list->next, i++) + { + GimpPlugInHelpDomain *domain = list->data; + + (*help_domains)[i] = g_strdup (domain->domain_name); + (*help_uris)[i] = g_strdup (domain->domain_uri); + } + } + else + { + *help_domains = NULL; + *help_uris = NULL; + } + + return n_domains; +} diff --git a/app/plug-in/gimppluginmanager-help-domain.h b/app/plug-in/gimppluginmanager-help-domain.h new file mode 100644 index 0000000..e4f8972 --- /dev/null +++ b/app/plug-in/gimppluginmanager-help-domain.h @@ -0,0 +1,43 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimppluginmanager-help-domain.h + * + * 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/>. + */ + +#ifndef __GIMP_PLUG_IN_MANAGER_HELP_DOMAIN_H__ +#define __GIMP_PLUG_IN_MANAGER_HELP_DOMAIN_H__ + + +void gimp_plug_in_manager_help_domain_exit (GimpPlugInManager *manager); + +/* Add a help domain */ +void gimp_plug_in_manager_add_help_domain (GimpPlugInManager *manager, + GFile *file, + const gchar *domain_name, + const gchar *domain_uri); + +/* Retrieve a plug-ins help domain */ +const gchar * gimp_plug_in_manager_get_help_domain (GimpPlugInManager *manager, + GFile *file, + const gchar **help_uri); + +/* Retrieve all help domains */ +gint gimp_plug_in_manager_get_help_domains (GimpPlugInManager *manager, + gchar ***help_domains, + gchar ***help_uris); + + +#endif /* __GIMP_PLUG_IN_MANAGER_HELP_DOMAIN_H__ */ diff --git a/app/plug-in/gimppluginmanager-locale-domain.c b/app/plug-in/gimppluginmanager-locale-domain.c new file mode 100644 index 0000000..ae0433b --- /dev/null +++ b/app/plug-in/gimppluginmanager-locale-domain.c @@ -0,0 +1,180 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimppluginmanager-locale-domain.c + * + * 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" + +#include <string.h> + +#include <gio/gio.h> + +#include "libgimpbase/gimpbase.h" + +#include "plug-in-types.h" + +#include "gimppluginmanager.h" +#include "gimppluginmanager-locale-domain.h" + + +#define STD_PLUG_INS_LOCALE_DOMAIN GETTEXT_PACKAGE "-std-plug-ins" + + +typedef struct _GimpPlugInLocaleDomain GimpPlugInLocaleDomain; + +struct _GimpPlugInLocaleDomain +{ + GFile *file; + gchar *domain_name; + gchar *domain_path; +}; + + +void +gimp_plug_in_manager_locale_domain_exit (GimpPlugInManager *manager) +{ + GSList *list; + + g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager)); + + for (list = manager->locale_domains; list; list = list->next) + { + GimpPlugInLocaleDomain *domain = list->data; + + g_object_unref (domain->file); + g_free (domain->domain_name); + g_free (domain->domain_path); + g_slice_free (GimpPlugInLocaleDomain, domain); + } + + g_slist_free (manager->locale_domains); + manager->locale_domains = NULL; +} + +void +gimp_plug_in_manager_add_locale_domain (GimpPlugInManager *manager, + GFile *file, + const gchar *domain_name, + const gchar *domain_path) +{ + GimpPlugInLocaleDomain *domain; + + g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager)); + g_return_if_fail (G_IS_FILE (file)); + g_return_if_fail (domain_name != NULL); + + domain = g_slice_new (GimpPlugInLocaleDomain); + + domain->file = g_object_ref (file); + domain->domain_name = g_strdup (domain_name); + domain->domain_path = g_strdup (domain_path); + + manager->locale_domains = g_slist_prepend (manager->locale_domains, domain); + +#ifdef VERBOSE + g_print ("added locale domain \"%s\" for path \"%s\"\n", + domain->domain_name ? domain->domain_name : "(null)", + domain->domain_path ? + gimp_filename_to_utf8 (domain->domain_path) : "(null)"); +#endif +} + +const gchar * +gimp_plug_in_manager_get_locale_domain (GimpPlugInManager *manager, + GFile *file, + const gchar **domain_path) +{ + GSList *list; + + g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), NULL); + g_return_val_if_fail (file == NULL || G_IS_FILE (file), NULL); + + if (domain_path) + *domain_path = gimp_locale_directory (); + + /* A NULL prog_name is GIMP itself, return the default domain */ + if (! file) + return NULL; + + for (list = manager->locale_domains; list; list = list->next) + { + GimpPlugInLocaleDomain *domain = list->data; + + if (domain && domain->file && + g_file_equal (domain->file, file)) + { + if (domain_path && domain->domain_path) + *domain_path = domain->domain_path; + + return domain->domain_name; + } + } + + return STD_PLUG_INS_LOCALE_DOMAIN; +} + +gint +gimp_plug_in_manager_get_locale_domains (GimpPlugInManager *manager, + gchar ***locale_domains, + gchar ***locale_paths) +{ + GSList *list; + GSList *unique = NULL; + gint n_domains; + gint i; + + g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), 0); + g_return_val_if_fail (locale_domains != NULL, 0); + g_return_val_if_fail (locale_paths != NULL, 0); + + for (list = manager->locale_domains; list; list = list->next) + { + GimpPlugInLocaleDomain *domain = list->data; + GSList *tmp; + + for (tmp = unique; tmp; tmp = tmp->next) + if (! strcmp (domain->domain_name, (const gchar *) tmp->data)) + break; + + if (! tmp) + unique = g_slist_prepend (unique, domain); + } + + unique = g_slist_reverse (unique); + + n_domains = g_slist_length (unique) + 1; + + *locale_domains = g_new0 (gchar *, n_domains + 1); + *locale_paths = g_new0 (gchar *, n_domains + 1); + + (*locale_domains)[0] = g_strdup (STD_PLUG_INS_LOCALE_DOMAIN); + (*locale_paths)[0] = g_strdup (gimp_locale_directory ()); + + for (list = unique, i = 1; list; list = list->next, i++) + { + GimpPlugInLocaleDomain *domain = list->data; + + (*locale_domains)[i] = g_strdup (domain->domain_name); + (*locale_paths)[i] = (domain->domain_path ? + g_strdup (domain->domain_path) : + g_strdup (gimp_locale_directory ())); + } + + g_slist_free (unique); + + return n_domains; +} diff --git a/app/plug-in/gimppluginmanager-locale-domain.h b/app/plug-in/gimppluginmanager-locale-domain.h new file mode 100644 index 0000000..2061ebe --- /dev/null +++ b/app/plug-in/gimppluginmanager-locale-domain.h @@ -0,0 +1,43 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimppluginmanager-locale-domain.h + * + * 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/>. + */ + +#ifndef __GIMP_PLUG_IN_MANAGER_LOCALE_DOMAIN_H__ +#define __GIMP_PLUG_IN_MANAGER_LOCALE_DOMAIN_H__ + + +void gimp_plug_in_manager_locale_domain_exit (GimpPlugInManager *manager); + +/* Add a locale domain */ +void gimp_plug_in_manager_add_locale_domain (GimpPlugInManager *manager, + GFile *file, + const gchar *domain_name, + const gchar *domain_path); + +/* Retrieve a plug-ins locale domain */ +const gchar * gimp_plug_in_manager_get_locale_domain (GimpPlugInManager *manager, + GFile *file, + const gchar **locale_path); + +/* Retrieve all locale domains */ +gint gimp_plug_in_manager_get_locale_domains (GimpPlugInManager *manager, + gchar ***locale_domains, + gchar ***locale_paths); + + +#endif /* __GIMP_PLUG_IN_MANAGER_LOCALE_DOMAIN_H__ */ diff --git a/app/plug-in/gimppluginmanager-menu-branch.c b/app/plug-in/gimppluginmanager-menu-branch.c new file mode 100644 index 0000000..c15d374 --- /dev/null +++ b/app/plug-in/gimppluginmanager-menu-branch.c @@ -0,0 +1,92 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimppluginmanager-menu-branch.c + * + * 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" + +#include <gio/gio.h> + +#include "plug-in-types.h" + +#include "gimppluginmanager.h" +#include "gimppluginmanager-menu-branch.h" +#include "plug-in-menu-path.h" + + +/* public functions */ + +void +gimp_plug_in_manager_menu_branch_exit (GimpPlugInManager *manager) +{ + GSList *list; + + g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager)); + + for (list = manager->menu_branches; list; list = list->next) + { + GimpPlugInMenuBranch *branch = list->data; + + g_object_unref (branch->file); + g_free (branch->menu_path); + g_free (branch->menu_label); + g_slice_free (GimpPlugInMenuBranch, branch); + } + + g_slist_free (manager->menu_branches); + manager->menu_branches = NULL; +} + +void +gimp_plug_in_manager_add_menu_branch (GimpPlugInManager *manager, + GFile *file, + const gchar *menu_path, + const gchar *menu_label) +{ + GimpPlugInMenuBranch *branch; + + g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager)); + g_return_if_fail (G_IS_FILE (file)); + g_return_if_fail (menu_path != NULL); + g_return_if_fail (menu_label != NULL); + + branch = g_slice_new (GimpPlugInMenuBranch); + + branch->file = g_object_ref (file); + branch->menu_path = plug_in_menu_path_map (menu_path, menu_label); + branch->menu_label = g_strdup (menu_label); + + manager->menu_branches = g_slist_append (manager->menu_branches, branch); + + g_signal_emit_by_name (manager, "menu-branch-added", + branch->file, + branch->menu_path, + branch->menu_label); + +#ifdef VERBOSE + g_print ("added menu branch \"%s\" at path \"%s\"\n", + branch->menu_label, branch->menu_path); +#endif +} + +GSList * +gimp_plug_in_manager_get_menu_branches (GimpPlugInManager *manager) +{ + g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), NULL); + + return manager->menu_branches; +} diff --git a/app/plug-in/gimppluginmanager-menu-branch.h b/app/plug-in/gimppluginmanager-menu-branch.h new file mode 100644 index 0000000..e092d01 --- /dev/null +++ b/app/plug-in/gimppluginmanager-menu-branch.h @@ -0,0 +1,42 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimppluginmanager-menu-branch.h + * + * 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/>. + */ + +#ifndef __GIMP_PLUG_IN_MANAGER_MENU_BRANCH_H__ +#define __GIMP_PLUG_IN_MANAGER_MENU_BRANCH_H__ + + +struct _GimpPlugInMenuBranch +{ + GFile *file; + gchar *menu_path; + gchar *menu_label; +}; + + +void gimp_plug_in_manager_menu_branch_exit (GimpPlugInManager *manager); + +/* Add a menu branch */ +void gimp_plug_in_manager_add_menu_branch (GimpPlugInManager *manager, + GFile *file, + const gchar *menu_path, + const gchar *menu_label); +GSList * gimp_plug_in_manager_get_menu_branches (GimpPlugInManager *manager); + + +#endif /* __GIMP_PLUG_IN_MANAGER_MENU_BRANCH_H__ */ diff --git a/app/plug-in/gimppluginmanager-query.c b/app/plug-in/gimppluginmanager-query.c new file mode 100644 index 0000000..861a89a --- /dev/null +++ b/app/plug-in/gimppluginmanager-query.c @@ -0,0 +1,162 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995-2003 Spencer Kimball and Peter Mattis + * + * plug-ins-query.c + * + * 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" + +#include <string.h> + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpbase/gimpbase.h" + +#include "plug-in-types.h" + +#include "gimppluginmanager.h" +#include "gimppluginmanager-query.h" +#include "gimppluginprocedure.h" + + +static gboolean +match_string (GRegex *regex, + gchar *string) +{ + return g_regex_match (regex, string, 0, NULL); +} + +gint +gimp_plug_in_manager_query (GimpPlugInManager *manager, + const gchar *search_str, + gchar ***menu_strs, + gchar ***accel_strs, + gchar ***prog_strs, + gchar ***types_strs, + gchar ***realname_strs, + gint32 **time_ints) +{ + gint32 num_plugins = 0; + GSList *list; + GSList *matched = NULL; + gint i = 0; + GRegex *sregex = NULL; + + g_return_val_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager), 0); + g_return_val_if_fail (menu_strs != NULL, 0); + g_return_val_if_fail (accel_strs != NULL, 0); + g_return_val_if_fail (prog_strs != NULL, 0); + g_return_val_if_fail (types_strs != NULL, 0); + g_return_val_if_fail (realname_strs != NULL, 0); + g_return_val_if_fail (time_ints != NULL, 0); + + *menu_strs = NULL; + *accel_strs = NULL; + *prog_strs = NULL; + *types_strs = NULL; + *realname_strs = NULL; + *time_ints = NULL; + + if (search_str && ! strlen (search_str)) + search_str = NULL; + + if (search_str) + { + sregex = g_regex_new (search_str, G_REGEX_CASELESS | G_REGEX_OPTIMIZE, 0, + NULL); + if (! sregex) + return 0; + } + + /* count number of plugin entries, then allocate arrays of correct size + * where we can store the strings. + */ + + for (list = manager->plug_in_procedures; list; list = g_slist_next (list)) + { + GimpPlugInProcedure *proc = list->data; + + if (proc->file && proc->menu_paths) + { + gchar *name; + + if (proc->menu_label) + { + name = proc->menu_label; + } + else + { + name = strrchr (proc->menu_paths->data, '/'); + + if (name) + name = name + 1; + else + name = proc->menu_paths->data; + } + + name = gimp_strip_uline (name); + + if (! search_str || match_string (sregex, name)) + { + num_plugins++; + matched = g_slist_prepend (matched, proc); + } + + g_free (name); + } + } + + *menu_strs = g_new (gchar *, num_plugins); + *accel_strs = g_new (gchar *, num_plugins); + *prog_strs = g_new (gchar *, num_plugins); + *types_strs = g_new (gchar *, num_plugins); + *realname_strs = g_new (gchar *, num_plugins); + *time_ints = g_new (gint, num_plugins); + + matched = g_slist_reverse (matched); + + for (list = matched; list; list = g_slist_next (list)) + { + GimpPlugInProcedure *proc = list->data; + gchar *name; + + if (proc->menu_label) + name = g_strdup_printf ("%s/%s", + (gchar *) proc->menu_paths->data, + proc->menu_label); + else + name = g_strdup (proc->menu_paths->data); + + (*menu_strs)[i] = gimp_strip_uline (name); + (*accel_strs)[i] = NULL; + (*prog_strs)[i] = g_file_get_path (proc->file); + (*types_strs)[i] = g_strdup (proc->image_types); + (*realname_strs)[i] = g_strdup (gimp_object_get_name (proc)); + (*time_ints)[i] = proc->mtime; + + g_free (name); + + i++; + } + + g_slist_free (matched); + + if (sregex) + g_regex_unref (sregex); + + return num_plugins; +} diff --git a/app/plug-in/gimppluginmanager-query.h b/app/plug-in/gimppluginmanager-query.h new file mode 100644 index 0000000..94b78c8 --- /dev/null +++ b/app/plug-in/gimppluginmanager-query.h @@ -0,0 +1,34 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimppluginmanager-query.h + * + * 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/>. + */ + +#ifndef __GIMP_PLUG_IN_MANAGER_QUERY_H__ +#define __GIMP_PLUG_IN_MANAGER_QUERY_H__ + + +gint gimp_plug_in_manager_query (GimpPlugInManager *manager, + const gchar *search_str, + gchar ***menu_strs, + gchar ***accel_strs, + gchar ***prog_strs, + gchar ***types_strs, + gchar ***realname_strs, + gint32 **time_ints); + + +#endif /* __GIMP_PLUG_IN_MANAGER_QUERY_H__ */ diff --git a/app/plug-in/gimppluginmanager-restore.c b/app/plug-in/gimppluginmanager-restore.c new file mode 100644 index 0000000..a1f37ec --- /dev/null +++ b/app/plug-in/gimppluginmanager-restore.c @@ -0,0 +1,1065 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995-2002 Spencer Kimball, Peter Mattis, and others + * + * gimppluginmanager-restore.c + * + * 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" + +#include <string.h> + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpbase/gimpbase.h" +#include "libgimpconfig/gimpconfig.h" + +#include "plug-in-types.h" + +#include "config/gimpcoreconfig.h" + +#include "core/gimp.h" +#include "core/gimp-utils.h" + +#include "pdb/gimppdb.h" +#include "pdb/gimppdbcontext.h" + +#include "gimpinterpreterdb.h" +#include "gimpplugindef.h" +#include "gimppluginmanager.h" +#define __YES_I_NEED_GIMP_PLUG_IN_MANAGER_CALL__ +#include "gimppluginmanager-call.h" +#include "gimppluginmanager-help-domain.h" +#include "gimppluginmanager-locale-domain.h" +#include "gimppluginmanager-restore.h" +#include "gimppluginprocedure.h" +#include "plug-in-rc.h" + +#include "gimp-intl.h" + + +static void gimp_plug_in_manager_search (GimpPlugInManager *manager, + GimpInitStatusFunc status_callback); +static void gimp_plug_in_manager_search_directory (GimpPlugInManager *manager, + GFile *directory); +static GFile * gimp_plug_in_manager_get_pluginrc (GimpPlugInManager *manager); +static void gimp_plug_in_manager_read_pluginrc (GimpPlugInManager *manager, + GFile *file, + GimpInitStatusFunc status_callback); +static void gimp_plug_in_manager_query_new (GimpPlugInManager *manager, + GimpContext *context, + GimpInitStatusFunc status_callback); +static void gimp_plug_in_manager_init_plug_ins (GimpPlugInManager *manager, + GimpContext *context, + GimpInitStatusFunc status_callback); +static void gimp_plug_in_manager_run_extensions (GimpPlugInManager *manager, + GimpContext *context, + GimpInitStatusFunc status_callback); +static void gimp_plug_in_manager_bind_text_domains (GimpPlugInManager *manager); +static void gimp_plug_in_manager_add_from_file (GimpPlugInManager *manager, + GFile *file, + guint64 mtime); +static void gimp_plug_in_manager_add_from_rc (GimpPlugInManager *manager, + GimpPlugInDef *plug_in_def); +static void gimp_plug_in_manager_add_to_db (GimpPlugInManager *manager, + GimpContext *context, + GimpPlugInProcedure *proc); +static void gimp_plug_in_manager_sort_file_procs (GimpPlugInManager *manager); +static gint gimp_plug_in_manager_file_proc_compare (gconstpointer a, + gconstpointer b, + gpointer data); + + + +void +gimp_plug_in_manager_restore (GimpPlugInManager *manager, + GimpContext *context, + GimpInitStatusFunc status_callback) +{ + Gimp *gimp; + GFile *pluginrc; + GSList *list; + GError *error = NULL; + + g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager)); + g_return_if_fail (GIMP_IS_CONTEXT (context)); + g_return_if_fail (status_callback != NULL); + + gimp = manager->gimp; + + /* need a GimpPDBContext for calling gimp_plug_in_manager_run_foo() */ + context = gimp_pdb_context_new (gimp, context, TRUE); + + /* search for binaries in the plug-in directory path */ + gimp_plug_in_manager_search (manager, status_callback); + + /* read the pluginrc file for cached data */ + pluginrc = gimp_plug_in_manager_get_pluginrc (manager); + + gimp_plug_in_manager_read_pluginrc (manager, pluginrc, status_callback); + + /* query any plug-ins that changed since we last wrote out pluginrc */ + gimp_plug_in_manager_query_new (manager, context, status_callback); + + /* initialize the plug-ins */ + gimp_plug_in_manager_init_plug_ins (manager, context, status_callback); + + /* add the procedures to manager->plug_in_procedures */ + for (list = manager->plug_in_defs; list; list = list->next) + { + GimpPlugInDef *plug_in_def = list->data; + GSList *list2; + + for (list2 = plug_in_def->procedures; list2; list2 = list2->next) + { + gimp_plug_in_manager_add_procedure (manager, list2->data); + } + } + + /* write the pluginrc file if necessary */ + if (manager->write_pluginrc) + { + if (gimp->be_verbose) + g_print ("Writing '%s'\n", gimp_file_get_utf8_name (pluginrc)); + + if (! plug_in_rc_write (manager->plug_in_defs, pluginrc, &error)) + { + gimp_message_literal (gimp, + NULL, GIMP_MESSAGE_ERROR, error->message); + g_clear_error (&error); + } + + manager->write_pluginrc = FALSE; + } + + g_object_unref (pluginrc); + + /* create locale and help domain lists */ + for (list = manager->plug_in_defs; list; list = list->next) + { + GimpPlugInDef *plug_in_def = list->data; + + if (plug_in_def->locale_domain_name) + gimp_plug_in_manager_add_locale_domain (manager, + plug_in_def->file, + plug_in_def->locale_domain_name, + plug_in_def->locale_domain_path); + else + /* set the default plug-in locale domain */ + gimp_plug_in_def_set_locale_domain (plug_in_def, + gimp_plug_in_manager_get_locale_domain (manager, + plug_in_def->file, + NULL), + NULL); + + if (plug_in_def->help_domain_name) + gimp_plug_in_manager_add_help_domain (manager, + plug_in_def->file, + plug_in_def->help_domain_name, + plug_in_def->help_domain_uri); + } + + /* we're done with the plug-in-defs */ + g_slist_free_full (manager->plug_in_defs, (GDestroyNotify) g_object_unref); + manager->plug_in_defs = NULL; + + /* bind plug-in text domains */ + gimp_plug_in_manager_bind_text_domains (manager); + + /* add the plug-in procs to the procedure database */ + for (list = manager->plug_in_procedures; list; list = list->next) + { + gimp_plug_in_manager_add_to_db (manager, context, list->data); + } + + /* sort the load, save and export procedures, make the raw handler list */ + gimp_plug_in_manager_sort_file_procs (manager); + + gimp_plug_in_manager_run_extensions (manager, context, status_callback); + + g_object_unref (context); +} + + +/* search for binaries in the plug-in directory path */ +static void +gimp_plug_in_manager_search (GimpPlugInManager *manager, + GimpInitStatusFunc status_callback) +{ + const gchar *path_str; + GList *path; + GList *list; + +#ifdef G_OS_WIN32 + const gchar *pathext = g_getenv ("PATHEXT"); + + /* On Windows, we need to add the known file extensions in PATHEXT. */ + if (pathext) + { + gchar *exts; + + exts = gimp_interpreter_db_get_extensions (manager->interpreter_db); + + if (exts) + { + gchar *value; + + value = g_strconcat (pathext, G_SEARCHPATH_SEPARATOR_S, exts, NULL); + + g_setenv ("PATHEXT", value, TRUE); + + g_free (value); + g_free (exts); + } + } +#endif /* G_OS_WIN32 */ + + status_callback (_("Searching plug-ins"), "", 0.0); + + /* Give automatic tests a chance to use plug-ins from the build + * dir + */ + path_str = g_getenv ("GIMP_TESTING_PLUGINDIRS"); + if (! path_str) + path_str = manager->gimp->config->plug_in_path; + + path = gimp_config_path_expand_to_files (path_str, NULL); + + for (list = path; list; list = g_list_next (list)) + { + gimp_plug_in_manager_search_directory (manager, list->data); + } + + g_list_free_full (path, (GDestroyNotify) g_object_unref); +} + +static void +gimp_plug_in_manager_search_directory (GimpPlugInManager *manager, + GFile *directory) +{ + GFileEnumerator *enumerator; + + enumerator = g_file_enumerate_children (directory, + G_FILE_ATTRIBUTE_STANDARD_NAME "," + G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN "," + G_FILE_ATTRIBUTE_TIME_MODIFIED, + G_FILE_QUERY_INFO_NONE, + NULL, NULL); + if (enumerator) + { + GFileInfo *info; + + while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL))) + { + GFile *child; + + if (g_file_info_get_is_hidden (info)) + { + g_object_unref (info); + continue; + } + + child = g_file_enumerator_get_child (enumerator, info); + + if (gimp_file_is_executable (child)) + { + guint64 mtime; + + mtime = g_file_info_get_attribute_uint64 (info, + G_FILE_ATTRIBUTE_TIME_MODIFIED); + + gimp_plug_in_manager_add_from_file (manager, child, mtime); + } + else if (g_file_query_file_type (child, + G_FILE_QUERY_INFO_NONE, + NULL) == G_FILE_TYPE_DIRECTORY) + { + /* Search in subdirectory the first executable file with + * the same name as the directory (except extension). + * We don't search recursively, but only at a single + * level and assume that there can be only 1 plugin + * inside a directory. + */ + GFileEnumerator *enumerator2; + + enumerator2 = g_file_enumerate_children (child, + G_FILE_ATTRIBUTE_STANDARD_NAME "," + G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN "," + G_FILE_ATTRIBUTE_TIME_MODIFIED, + G_FILE_QUERY_INFO_NONE, + NULL, NULL); + if (enumerator2) + { + GFileInfo *info2; + + while ((info2 = g_file_enumerator_next_file (enumerator2, NULL, NULL))) + { + GFile *child2; + gchar *file_name; + char *ext; + + if (g_file_info_get_is_hidden (info2)) + { + g_object_unref (info2); + continue; + } + + child2 = g_file_enumerator_get_child (enumerator2, info2); + file_name = g_strdup (g_file_info_get_name (info2)); + + ext = strrchr (file_name, '.'); + if (ext) + *ext = '\0'; + + if (g_strcmp0 (file_name, g_file_info_get_name (info)) == 0 && + gimp_file_is_executable (child2)) + { + guint64 mtime; + + mtime = g_file_info_get_attribute_uint64 (info2, + G_FILE_ATTRIBUTE_TIME_MODIFIED); + + gimp_plug_in_manager_add_from_file (manager, child2, mtime); + + g_free (file_name); + g_object_unref (child2); + g_object_unref (info2); + break; + } + + g_free (file_name); + g_object_unref (child2); + g_object_unref (info2); + } + + g_object_unref (enumerator2); + } + } + + g_object_unref (child); + g_object_unref (info); + } + + g_object_unref (enumerator); + } +} + +static GFile * +gimp_plug_in_manager_get_pluginrc (GimpPlugInManager *manager) +{ + Gimp *gimp = manager->gimp; + GFile *pluginrc; + + if (gimp->config->plug_in_rc_path) + { + gchar *path = gimp_config_path_expand (gimp->config->plug_in_rc_path, + TRUE, NULL); + + if (g_path_is_absolute (path)) + pluginrc = g_file_new_for_path (path); + else + pluginrc = gimp_directory_file (path, NULL); + + g_free (path); + } + else + { + pluginrc = gimp_directory_file ("pluginrc", NULL); + } + + return pluginrc; +} + +/* read the pluginrc file for cached data */ +static void +gimp_plug_in_manager_read_pluginrc (GimpPlugInManager *manager, + GFile *pluginrc, + GimpInitStatusFunc status_callback) +{ + GSList *rc_defs; + GError *error = NULL; + + status_callback (_("Resource configuration"), + gimp_file_get_utf8_name (pluginrc), 0.0); + + if (manager->gimp->be_verbose) + g_print ("Parsing '%s'\n", gimp_file_get_utf8_name (pluginrc)); + + rc_defs = plug_in_rc_parse (manager->gimp, pluginrc, &error); + + if (rc_defs) + { + GSList *list; + + for (list = rc_defs; list; list = g_slist_next (list)) + gimp_plug_in_manager_add_from_rc (manager, list->data); /* consumes list->data */ + + g_slist_free (rc_defs); + } + else if (error) + { + if (error->code != GIMP_CONFIG_ERROR_OPEN_ENOENT) + gimp_message_literal (manager->gimp, NULL, GIMP_MESSAGE_ERROR, + error->message); + + g_clear_error (&error); + } +} + +/* query any plug-ins that changed since we last wrote out pluginrc */ +static void +gimp_plug_in_manager_query_new (GimpPlugInManager *manager, + GimpContext *context, + GimpInitStatusFunc status_callback) +{ + GSList *list; + gint n_plugins; + + status_callback (_("Querying new Plug-ins"), "", 0.0); + + for (list = manager->plug_in_defs, n_plugins = 0; list; list = list->next) + { + GimpPlugInDef *plug_in_def = list->data; + + if (plug_in_def->needs_query) + n_plugins++; + } + + if (n_plugins) + { + gint nth; + + manager->write_pluginrc = TRUE; + + for (list = manager->plug_in_defs, nth = 0; list; list = list->next) + { + GimpPlugInDef *plug_in_def = list->data; + + if (plug_in_def->needs_query) + { + gchar *basename; + + basename = + g_path_get_basename (gimp_file_get_utf8_name (plug_in_def->file)); + status_callback (NULL, basename, + (gdouble) nth++ / (gdouble) n_plugins); + g_free (basename); + + if (manager->gimp->be_verbose) + g_print ("Querying plug-in: '%s'\n", + gimp_file_get_utf8_name (plug_in_def->file)); + + gimp_plug_in_manager_call_query (manager, context, plug_in_def); + } + } + } + + status_callback (NULL, "", 1.0); +} + +/* initialize the plug-ins */ +static void +gimp_plug_in_manager_init_plug_ins (GimpPlugInManager *manager, + GimpContext *context, + GimpInitStatusFunc status_callback) +{ + GSList *list; + gint n_plugins; + + status_callback (_("Initializing Plug-ins"), "", 0.0); + + for (list = manager->plug_in_defs, n_plugins = 0; list; list = list->next) + { + GimpPlugInDef *plug_in_def = list->data; + + if (plug_in_def->has_init) + n_plugins++; + } + + if (n_plugins) + { + gint nth; + + for (list = manager->plug_in_defs, nth = 0; list; list = list->next) + { + GimpPlugInDef *plug_in_def = list->data; + + if (plug_in_def->has_init) + { + gchar *basename; + + basename = + g_path_get_basename (gimp_file_get_utf8_name (plug_in_def->file)); + status_callback (NULL, basename, + (gdouble) nth++ / (gdouble) n_plugins); + g_free (basename); + + if (manager->gimp->be_verbose) + g_print ("Initializing plug-in: '%s'\n", + gimp_file_get_utf8_name (plug_in_def->file)); + + gimp_plug_in_manager_call_init (manager, context, plug_in_def); + } + } + } + + status_callback (NULL, "", 1.0); +} + +/* run automatically started extensions */ +static void +gimp_plug_in_manager_run_extensions (GimpPlugInManager *manager, + GimpContext *context, + GimpInitStatusFunc status_callback) +{ + Gimp *gimp = manager->gimp; + GSList *list; + GList *extensions = NULL; + gint n_extensions; + + /* build list of automatically started extensions */ + for (list = manager->plug_in_procedures; list; list = list->next) + { + GimpPlugInProcedure *proc = list->data; + + if (proc->file && + GIMP_PROCEDURE (proc)->proc_type == GIMP_EXTENSION && + GIMP_PROCEDURE (proc)->num_args == 0) + { + extensions = g_list_prepend (extensions, proc); + } + } + + extensions = g_list_reverse (extensions); + n_extensions = g_list_length (extensions); + + /* run the available extensions */ + if (extensions) + { + GList *list; + gint nth; + + status_callback (_("Starting Extensions"), "", 0.0); + + for (list = extensions, nth = 0; list; list = g_list_next (list), nth++) + { + GimpPlugInProcedure *proc = list->data; + GimpValueArray *args; + GError *error = NULL; + + if (gimp->be_verbose) + g_print ("Starting extension: '%s'\n", gimp_object_get_name (proc)); + + status_callback (NULL, gimp_object_get_name (proc), + (gdouble) nth / (gdouble) n_extensions); + + args = gimp_value_array_new (0); + + gimp_procedure_execute_async (GIMP_PROCEDURE (proc), + gimp, context, NULL, + args, NULL, &error); + + gimp_value_array_unref (args); + + if (error) + { + gimp_message_literal (gimp, NULL, GIMP_MESSAGE_ERROR, + error->message); + g_clear_error (&error); + } + } + + g_list_free (extensions); + + status_callback (NULL, "", 1.0); + } +} + +static void +gimp_plug_in_manager_bind_text_domains (GimpPlugInManager *manager) +{ + gchar **locale_domains; + gchar **locale_paths; + gint n_domains; + gint i; + + n_domains = gimp_plug_in_manager_get_locale_domains (manager, + &locale_domains, + &locale_paths); + + for (i = 0; i < n_domains; i++) + { + bindtextdomain (locale_domains[i], locale_paths[i]); +#ifdef HAVE_BIND_TEXTDOMAIN_CODESET + bind_textdomain_codeset (locale_domains[i], "UTF-8"); +#endif + } + + g_strfreev (locale_domains); + g_strfreev (locale_paths); +} + +/** + * gimp_plug_in_manager_ignore_plugin_basename: + * @basename: Basename to test with + * + * Checks the environment variable + * GIMP_TESTING_PLUGINDIRS_BASENAME_IGNORES for file basenames. + * + * Returns: %TRUE if @basename was in GIMP_TESTING_PLUGINDIRS_BASENAME_IGNORES + **/ +static gboolean +gimp_plug_in_manager_ignore_plugin_basename (const gchar *plugin_basename) +{ + const gchar *ignore_basenames_string; + GList *ignore_basenames; + GList *iter; + gboolean ignore = FALSE; + + ignore_basenames_string = g_getenv ("GIMP_TESTING_PLUGINDIRS_BASENAME_IGNORES"); + ignore_basenames = gimp_path_parse (ignore_basenames_string, + 256 /*max_paths*/, + FALSE /*check*/, + NULL /*check_failed*/); + + for (iter = ignore_basenames; iter; iter = g_list_next (iter)) + { + const gchar *ignore_basename = iter->data; + + if (g_ascii_strcasecmp (ignore_basename, plugin_basename) == 0) + { + ignore = TRUE; + break; + } + } + + gimp_path_free (ignore_basenames); + + return ignore; +} + +static void +gimp_plug_in_manager_add_from_file (GimpPlugInManager *manager, + GFile *file, + guint64 mtime) +{ + GimpPlugInDef *plug_in_def; + GSList *list; + gchar *filename; + gchar *basename; + + filename = g_file_get_path (file); + basename = g_path_get_basename (filename); + g_free (filename); + + /* When we scan build dirs for plug-ins, there will be some + * executable files that are not plug-ins that we want to ignore, + * for example plug-ins/common/mkgen.pl if + * GIMP_TESTING_PLUGINDIRS=plug-ins/common + */ + if (gimp_plug_in_manager_ignore_plugin_basename (basename)) + { + g_free (basename); + return; + } + + for (list = manager->plug_in_defs; list; list = list->next) + { + gchar *path; + gchar *plug_in_name; + + plug_in_def = list->data; + + path = g_file_get_path (plug_in_def->file); + plug_in_name = g_path_get_basename (path); + g_free (path); + + if (g_ascii_strcasecmp (basename, plug_in_name) == 0) + { + g_printerr ("Skipping duplicate plug-in: '%s'\n", + gimp_file_get_utf8_name (file)); + + g_free (plug_in_name); + g_free (basename); + + return; + } + + g_free (plug_in_name); + } + + g_free (basename); + + plug_in_def = gimp_plug_in_def_new (file); + + gimp_plug_in_def_set_mtime (plug_in_def, mtime); + gimp_plug_in_def_set_needs_query (plug_in_def, TRUE); + + manager->plug_in_defs = g_slist_prepend (manager->plug_in_defs, plug_in_def); +} + +static void +gimp_plug_in_manager_add_from_rc (GimpPlugInManager *manager, + GimpPlugInDef *plug_in_def) +{ + GSList *list; + gchar *path1; + gchar *basename1; + + g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager)); + g_return_if_fail (plug_in_def != NULL); + g_return_if_fail (plug_in_def->file != NULL); + + path1 = g_file_get_path (plug_in_def->file); + + if (! g_path_is_absolute (path1)) + { + g_warning ("plug_ins_def_add_from_rc: filename not absolute (skipping)"); + g_object_unref (plug_in_def); + g_free (path1); + return; + } + + basename1 = g_path_get_basename (path1); + + /* If this is a file load or save plugin, make sure we have + * something for one of the extensions, prefixes, or magic number. + * Other bits of code rely on detecting file plugins by the + * presence of one of these things, but the raw plug-in needs to be + * able to register no extensions, prefixes or magics. + */ + for (list = plug_in_def->procedures; list; list = list->next) + { + GimpPlugInProcedure *proc = list->data; + + if (! proc->extensions && + ! proc->prefixes && + ! proc->magics && + proc->menu_paths && + (g_str_has_prefix (proc->menu_paths->data, "<Load>") || + g_str_has_prefix (proc->menu_paths->data, "<Save>"))) + { + proc->extensions = g_strdup (""); + } + } + + /* Check if the entry mentioned in pluginrc matches an executable + * found in the plug_in_path. + */ + for (list = manager->plug_in_defs; list; list = list->next) + { + GimpPlugInDef *ondisk_plug_in_def = list->data; + gchar *path2; + gchar *basename2; + + path2 = g_file_get_path (ondisk_plug_in_def->file); + + basename2 = g_path_get_basename (path2); + + g_free (path2); + + if (! strcmp (basename1, basename2)) + { + if (g_file_equal (plug_in_def->file, + ondisk_plug_in_def->file) && + (plug_in_def->mtime == ondisk_plug_in_def->mtime)) + { + /* Use pluginrc entry, deleting on-disk entry */ + list->data = plug_in_def; + g_object_unref (ondisk_plug_in_def); + } + else + { + /* Use on-disk entry, deleting pluginrc entry */ + g_object_unref (plug_in_def); + } + + g_free (basename2); + g_free (basename1); + g_free (path1); + + return; + } + + g_free (basename2); + } + + g_free (basename1); + g_free (path1); + + manager->write_pluginrc = TRUE; + + if (manager->gimp->be_verbose) + { + g_printerr ("pluginrc lists '%s', but it wasn't found\n", + gimp_file_get_utf8_name (plug_in_def->file)); + } + + g_object_unref (plug_in_def); +} + + +static void +gimp_plug_in_manager_add_to_db (GimpPlugInManager *manager, + GimpContext *context, + GimpPlugInProcedure *proc) +{ + gimp_pdb_register_procedure (manager->gimp->pdb, GIMP_PROCEDURE (proc)); + + if (proc->file_proc) + { + GimpValueArray *return_vals; + GError *error = NULL; + + if (proc->image_types) + { + return_vals = + gimp_pdb_execute_procedure_by_name (manager->gimp->pdb, + context, NULL, &error, + "gimp-register-save-handler", + G_TYPE_STRING, gimp_object_get_name (proc), + G_TYPE_STRING, proc->extensions, + G_TYPE_STRING, proc->prefixes, + G_TYPE_NONE); + } + else + { + return_vals = + gimp_pdb_execute_procedure_by_name (manager->gimp->pdb, + context, NULL, &error, + "gimp-register-magic-load-handler", + G_TYPE_STRING, gimp_object_get_name (proc), + G_TYPE_STRING, proc->extensions, + G_TYPE_STRING, proc->prefixes, + G_TYPE_STRING, proc->magics, + G_TYPE_NONE); + } + + gimp_value_array_unref (return_vals); + + if (error) + { + gimp_message_literal (manager->gimp, NULL, GIMP_MESSAGE_ERROR, + error->message); + g_error_free (error); + } + } +} + +static void +gimp_plug_in_manager_sort_file_procs (GimpPlugInManager *manager) +{ + GimpCoreConfig *config = manager->gimp->config; + GFile *config_plug_in = NULL; + GFile *raw_plug_in = NULL; + GSList *list; + + manager->load_procs = + g_slist_sort_with_data (manager->load_procs, + gimp_plug_in_manager_file_proc_compare, + GINT_TO_POINTER (FALSE)); + manager->save_procs = + g_slist_sort_with_data (manager->save_procs, + gimp_plug_in_manager_file_proc_compare, + GINT_TO_POINTER (FALSE)); + manager->export_procs = + g_slist_sort_with_data (manager->export_procs, + gimp_plug_in_manager_file_proc_compare, + GINT_TO_POINTER (FALSE)); + + g_clear_pointer (&manager->display_load_procs, g_slist_free); + g_clear_pointer (&manager->display_save_procs, g_slist_free); + g_clear_pointer (&manager->display_export_procs, g_slist_free); + + manager->display_load_procs = g_slist_copy (manager->load_procs); + manager->display_save_procs = g_slist_copy (manager->save_procs); + manager->display_export_procs = g_slist_copy (manager->export_procs); + + manager->display_load_procs = + g_slist_sort_with_data (manager->display_load_procs, + gimp_plug_in_manager_file_proc_compare, + GINT_TO_POINTER (TRUE)); + manager->display_save_procs = + g_slist_sort_with_data (manager->display_save_procs, + gimp_plug_in_manager_file_proc_compare, + GINT_TO_POINTER (TRUE)); + manager->display_export_procs = + g_slist_sort_with_data (manager->display_export_procs, + gimp_plug_in_manager_file_proc_compare, + GINT_TO_POINTER (TRUE)); + + g_clear_pointer (&manager->raw_load_procs, g_slist_free); + g_clear_pointer (&manager->display_raw_load_procs, g_slist_free); + + if (config->import_raw_plug_in) + { + /* remember the configured raw loader, unless it's the placeholder */ + if (! strstr (config->import_raw_plug_in, "file-raw-placeholder")) + config_plug_in = + gimp_file_new_for_config_path (config->import_raw_plug_in, + NULL); + } + + /* make the list of raw loaders, and remember the one configured in + * config if found + */ + for (list = manager->load_procs; list; list = g_slist_next (list)) + { + GimpPlugInProcedure *file_proc = list->data; + + if (file_proc->handles_raw) + { + GFile *file; + + manager->raw_load_procs = g_slist_prepend (manager->raw_load_procs, + file_proc); + + file = gimp_plug_in_procedure_get_file (file_proc); + + if (! raw_plug_in && + config_plug_in && + g_file_equal (config_plug_in, file)) + { + raw_plug_in = file; + } + } + } + + manager->raw_load_procs = g_slist_reverse (manager->raw_load_procs); + manager->display_raw_load_procs = g_slist_copy (manager->raw_load_procs); + manager->display_raw_load_procs = + g_slist_sort_with_data (manager->display_raw_load_procs, + gimp_plug_in_manager_file_proc_compare, + GINT_TO_POINTER (TRUE)); + + if (config_plug_in) + g_object_unref (config_plug_in); + + /* if no raw loader was configured, or the configured raw loader + * wasn't found, default to the first loader that is not the + * placeholder, if any + */ + if (! raw_plug_in && manager->raw_load_procs) + { + gchar *path; + + for (list = manager->raw_load_procs; list; list = g_slist_next (list)) + { + GimpPlugInProcedure *file_proc = list->data; + + raw_plug_in = gimp_plug_in_procedure_get_file (file_proc); + + path = gimp_file_get_config_path (raw_plug_in, NULL); + + if (! strstr (path, "file-raw-placeholder")) + break; + + g_free (path); + path = NULL; + + raw_plug_in = NULL; + } + + if (! raw_plug_in) + { + raw_plug_in = + gimp_plug_in_procedure_get_file (manager->raw_load_procs->data); + + path = gimp_file_get_config_path (raw_plug_in, NULL); + } + + g_object_set (config, + "import-raw-plug-in", path, + NULL); + + g_free (path); + } + + /* finally, remove all raw loaders except the configured one from + * the list of load_procs + */ + list = manager->load_procs; + while (list) + { + GimpPlugInProcedure *file_proc = list->data; + + list = g_slist_next (list); + + if (file_proc->handles_raw && + ! g_file_equal (gimp_plug_in_procedure_get_file (file_proc), + raw_plug_in)) + { + manager->load_procs = + g_slist_remove (manager->load_procs, file_proc); + manager->display_load_procs = + g_slist_remove (manager->display_load_procs, file_proc); + } + } +} + +static gint +gimp_plug_in_manager_file_proc_compare (gconstpointer a, + gconstpointer b, + gpointer data) +{ + GimpPlugInProcedure *proc_a = GIMP_PLUG_IN_PROCEDURE (a); + GimpPlugInProcedure *proc_b = GIMP_PLUG_IN_PROCEDURE (b); + gboolean display = GPOINTER_TO_INT (data); + const gchar *label_a; + const gchar *label_b; + + if (g_str_has_prefix (gimp_file_get_utf8_name (proc_a->file), + "gimp-xcf")) + { + if (! g_str_has_prefix (gimp_file_get_utf8_name (proc_b->file), + "gimp-xcf")) + { + return -1; + } + } + else if (g_str_has_prefix (gimp_file_get_utf8_name (proc_b->file), + "gimp-xcf")) + { + return 1; + } + + if (! display && proc_a->priority != proc_b->priority) + return proc_a->priority - proc_b->priority; + + label_a = gimp_procedure_get_label (GIMP_PROCEDURE (proc_a)); + label_b = gimp_procedure_get_label (GIMP_PROCEDURE (proc_b)); + + if (label_a) + { + if (label_b) + { + gint comp = g_utf8_collate (label_a, label_b); + + if (comp) + return comp; + } + else + { + return -1; + } + } + else if (label_b) + { + return 1; + } + + return strcmp (gimp_object_get_name (proc_a), gimp_object_get_name (proc_b)); +} diff --git a/app/plug-in/gimppluginmanager-restore.h b/app/plug-in/gimppluginmanager-restore.h new file mode 100644 index 0000000..0389dcf --- /dev/null +++ b/app/plug-in/gimppluginmanager-restore.h @@ -0,0 +1,29 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis + * + * gimppluginmanager-restore.h + * + * 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/>. + */ + +#ifndef __GIMP_PLUG_IN_MANAGER_RESTORE_H__ +#define __GIMP_PLUG_IN_MANAGER_RESTORE_H__ + + +void gimp_plug_in_manager_restore (GimpPlugInManager *manager, + GimpContext *context, + GimpInitStatusFunc status_callback); + + +#endif /* __GIMP_PLUG_IN_MANAGER_RESTORE_H__ */ diff --git a/app/plug-in/gimppluginmanager.c b/app/plug-in/gimppluginmanager.c new file mode 100644 index 0000000..d8952a2 --- /dev/null +++ b/app/plug-in/gimppluginmanager.c @@ -0,0 +1,426 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995-2002 Spencer Kimball, Peter Mattis, and others + * + * gimppluginmanager.c + * + * 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" + +#include <string.h> + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpbase/gimpbase.h" +#include "libgimpconfig/gimpconfig.h" + +#include "plug-in-types.h" + +#include "config/gimpcoreconfig.h" + +#include "core/gimp.h" +#include "core/gimp-filter-history.h" +#include "core/gimp-memsize.h" +#include "core/gimpmarshal.h" + +#include "pdb/gimppdb.h" + +#include "gimpenvirontable.h" +#include "gimpinterpreterdb.h" +#include "gimpplugin.h" +#include "gimpplugindebug.h" +#include "gimpplugindef.h" +#include "gimppluginmanager.h" +#include "gimppluginmanager-data.h" +#include "gimppluginmanager-help-domain.h" +#include "gimppluginmanager-locale-domain.h" +#include "gimppluginmanager-menu-branch.h" +#include "gimppluginshm.h" +#include "gimptemporaryprocedure.h" + +#include "gimp-intl.h" + + +enum +{ + PLUG_IN_OPENED, + PLUG_IN_CLOSED, + MENU_BRANCH_ADDED, + LAST_SIGNAL +}; + + +static void gimp_plug_in_manager_finalize (GObject *object); + +static gint64 gimp_plug_in_manager_get_memsize (GimpObject *object, + gint64 *gui_size); + + +G_DEFINE_TYPE (GimpPlugInManager, gimp_plug_in_manager, GIMP_TYPE_OBJECT) + +#define parent_class gimp_plug_in_manager_parent_class + +static guint manager_signals[LAST_SIGNAL] = { 0, }; + + +static void +gimp_plug_in_manager_class_init (GimpPlugInManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass); + + manager_signals[PLUG_IN_OPENED] = + g_signal_new ("plug-in-opened", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GimpPlugInManagerClass, + plug_in_opened), + NULL, NULL, + gimp_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + GIMP_TYPE_PLUG_IN); + + manager_signals[PLUG_IN_CLOSED] = + g_signal_new ("plug-in-closed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GimpPlugInManagerClass, + plug_in_closed), + NULL, NULL, + gimp_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + GIMP_TYPE_PLUG_IN); + + manager_signals[MENU_BRANCH_ADDED] = + g_signal_new ("menu-branch-added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GimpPlugInManagerClass, + menu_branch_added), + NULL, NULL, + gimp_marshal_VOID__OBJECT_STRING_STRING, + G_TYPE_NONE, 1, + G_TYPE_FILE, + G_TYPE_STRING, + G_TYPE_STRING); + + object_class->finalize = gimp_plug_in_manager_finalize; + + gimp_object_class->get_memsize = gimp_plug_in_manager_get_memsize; +} + +static void +gimp_plug_in_manager_init (GimpPlugInManager *manager) +{ +} + +static void +gimp_plug_in_manager_finalize (GObject *object) +{ + GimpPlugInManager *manager = GIMP_PLUG_IN_MANAGER (object); + + g_clear_pointer (&manager->load_procs, g_slist_free); + g_clear_pointer (&manager->save_procs, g_slist_free); + g_clear_pointer (&manager->export_procs, g_slist_free); + g_clear_pointer (&manager->raw_load_procs, g_slist_free); + + g_clear_pointer (&manager->display_load_procs, g_slist_free); + g_clear_pointer (&manager->display_save_procs, g_slist_free); + g_clear_pointer (&manager->display_export_procs, g_slist_free); + g_clear_pointer (&manager->display_raw_load_procs, g_slist_free); + + if (manager->plug_in_procedures) + { + g_slist_free_full (manager->plug_in_procedures, + (GDestroyNotify) g_object_unref); + manager->plug_in_procedures = NULL; + } + + if (manager->plug_in_defs) + { + g_slist_free_full (manager->plug_in_defs, + (GDestroyNotify) g_object_unref); + manager->plug_in_defs = NULL; + } + + g_clear_object (&manager->environ_table); + g_clear_object (&manager->interpreter_db); + + g_clear_pointer (&manager->debug, gimp_plug_in_debug_free); + + gimp_plug_in_manager_menu_branch_exit (manager); + gimp_plug_in_manager_locale_domain_exit (manager); + gimp_plug_in_manager_help_domain_exit (manager); + gimp_plug_in_manager_data_free (manager); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gint64 +gimp_plug_in_manager_get_memsize (GimpObject *object, + gint64 *gui_size) +{ + GimpPlugInManager *manager = GIMP_PLUG_IN_MANAGER (object); + gint64 memsize = 0; + + memsize += gimp_g_slist_get_memsize_foreach (manager->plug_in_defs, + (GimpMemsizeFunc) + gimp_object_get_memsize, + gui_size); + + memsize += gimp_g_slist_get_memsize (manager->plug_in_procedures, 0); + memsize += gimp_g_slist_get_memsize (manager->load_procs, 0); + memsize += gimp_g_slist_get_memsize (manager->save_procs, 0); + memsize += gimp_g_slist_get_memsize (manager->export_procs, 0); + memsize += gimp_g_slist_get_memsize (manager->raw_load_procs, 0); + memsize += gimp_g_slist_get_memsize (manager->display_load_procs, 0); + memsize += gimp_g_slist_get_memsize (manager->display_save_procs, 0); + memsize += gimp_g_slist_get_memsize (manager->display_export_procs, 0); + memsize += gimp_g_slist_get_memsize (manager->display_raw_load_procs, 0); + + memsize += gimp_g_slist_get_memsize (manager->menu_branches, 0 /* FIXME */); + memsize += gimp_g_slist_get_memsize (manager->locale_domains, 0 /* FIXME */); + memsize += gimp_g_slist_get_memsize (manager->help_domains, 0 /* FIXME */); + + memsize += gimp_g_slist_get_memsize_foreach (manager->open_plug_ins, + (GimpMemsizeFunc) + gimp_object_get_memsize, + gui_size); + memsize += gimp_g_slist_get_memsize (manager->plug_in_stack, 0); + + memsize += 0; /* FIXME manager->shm */ + memsize += /* FIXME */ gimp_g_object_get_memsize (G_OBJECT (manager->interpreter_db)); + memsize += /* FIXME */ gimp_g_object_get_memsize (G_OBJECT (manager->environ_table)); + memsize += 0; /* FIXME manager->plug_in_debug */ + memsize += gimp_g_list_get_memsize (manager->data_list, 0 /* FIXME */); + + return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object, + gui_size); +} + +GimpPlugInManager * +gimp_plug_in_manager_new (Gimp *gimp) +{ + GimpPlugInManager *manager; + + manager = g_object_new (GIMP_TYPE_PLUG_IN_MANAGER, NULL); + + manager->gimp = gimp; + manager->interpreter_db = gimp_interpreter_db_new (gimp->be_verbose); + manager->environ_table = gimp_environ_table_new (gimp->be_verbose); + + return manager; +} + +void +gimp_plug_in_manager_initialize (GimpPlugInManager *manager, + GimpInitStatusFunc status_callback) +{ + GimpCoreConfig *config; + GList *path; + + g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager)); + g_return_if_fail (status_callback != NULL); + + config = manager->gimp->config; + + status_callback (NULL, _("Plug-in Interpreters"), 0.8); + + path = gimp_config_path_expand_to_files (config->interpreter_path, NULL); + gimp_interpreter_db_load (manager->interpreter_db, path); + g_list_free_full (path, (GDestroyNotify) g_object_unref); + + status_callback (NULL, _("Plug-in Environment"), 0.9); + + path = gimp_config_path_expand_to_files (config->environ_path, NULL); + gimp_environ_table_load (manager->environ_table, path); + g_list_free_full (path, (GDestroyNotify) g_object_unref); + + /* allocate a piece of shared memory for use in transporting tiles + * to plug-ins. if we can't allocate a piece of shared memory then + * we'll fall back on sending the data over the pipe. + */ + if (manager->gimp->use_shm) + manager->shm = gimp_plug_in_shm_new (); + + manager->debug = gimp_plug_in_debug_new (); +} + +void +gimp_plug_in_manager_exit (GimpPlugInManager *manager) +{ + g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager)); + + while (manager->open_plug_ins) + gimp_plug_in_close (manager->open_plug_ins->data, TRUE); + + /* need to detach from shared memory, we can't rely on exit() + * cleaning up behind us (see bug #609026) + */ + if (manager->shm) + { + gimp_plug_in_shm_free (manager->shm); + manager->shm = NULL; + } +} + +void +gimp_plug_in_manager_add_procedure (GimpPlugInManager *manager, + GimpPlugInProcedure *procedure) +{ + GSList *list; + + g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager)); + g_return_if_fail (GIMP_IS_PLUG_IN_PROCEDURE (procedure)); + + for (list = manager->plug_in_procedures; list; list = list->next) + { + GimpPlugInProcedure *tmp_proc = list->data; + + if (strcmp (gimp_object_get_name (procedure), + gimp_object_get_name (tmp_proc)) == 0) + { + GSList *list2; + + list->data = g_object_ref (procedure); + + g_printerr ("Removing duplicate PDB procedure '%s' " + "registered by '%s'\n", + gimp_object_get_name (tmp_proc), + gimp_file_get_utf8_name (tmp_proc->file)); + + /* search the plugin list to see if any plugins had references to + * the tmp_proc. + */ + for (list2 = manager->plug_in_defs; list2; list2 = list2->next) + { + GimpPlugInDef *plug_in_def = list2->data; + + if (g_slist_find (plug_in_def->procedures, tmp_proc)) + gimp_plug_in_def_remove_procedure (plug_in_def, tmp_proc); + } + + /* also remove it from the lists of load, save and export procs */ + manager->load_procs = g_slist_remove (manager->load_procs, tmp_proc); + manager->save_procs = g_slist_remove (manager->save_procs, tmp_proc); + manager->export_procs = g_slist_remove (manager->export_procs, tmp_proc); + manager->raw_load_procs = g_slist_remove (manager->raw_load_procs, tmp_proc); + manager->display_load_procs = g_slist_remove (manager->display_load_procs, tmp_proc); + manager->display_save_procs = g_slist_remove (manager->display_save_procs, tmp_proc); + manager->display_export_procs = g_slist_remove (manager->display_export_procs, tmp_proc); + manager->display_raw_load_procs = g_slist_remove (manager->display_raw_load_procs, tmp_proc); + + /* and from the history */ + gimp_filter_history_remove (manager->gimp, GIMP_PROCEDURE (tmp_proc)); + + g_object_unref (tmp_proc); + + return; + } + } + + manager->plug_in_procedures = g_slist_prepend (manager->plug_in_procedures, + g_object_ref (procedure)); +} + +void +gimp_plug_in_manager_add_temp_proc (GimpPlugInManager *manager, + GimpTemporaryProcedure *procedure) +{ + g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager)); + g_return_if_fail (GIMP_IS_TEMPORARY_PROCEDURE (procedure)); + + gimp_pdb_register_procedure (manager->gimp->pdb, GIMP_PROCEDURE (procedure)); + + manager->plug_in_procedures = g_slist_prepend (manager->plug_in_procedures, + g_object_ref (procedure)); +} + +void +gimp_plug_in_manager_remove_temp_proc (GimpPlugInManager *manager, + GimpTemporaryProcedure *procedure) +{ + g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager)); + g_return_if_fail (GIMP_IS_TEMPORARY_PROCEDURE (procedure)); + + manager->plug_in_procedures = g_slist_remove (manager->plug_in_procedures, + procedure); + + gimp_filter_history_remove (manager->gimp, + GIMP_PROCEDURE (procedure)); + + gimp_pdb_unregister_procedure (manager->gimp->pdb, + GIMP_PROCEDURE (procedure)); + + g_object_unref (procedure); +} + +void +gimp_plug_in_manager_add_open_plug_in (GimpPlugInManager *manager, + GimpPlugIn *plug_in) +{ + g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager)); + g_return_if_fail (GIMP_IS_PLUG_IN (plug_in)); + + manager->open_plug_ins = g_slist_prepend (manager->open_plug_ins, + g_object_ref (plug_in)); + + g_signal_emit (manager, manager_signals[PLUG_IN_OPENED], 0, + plug_in); +} + +void +gimp_plug_in_manager_remove_open_plug_in (GimpPlugInManager *manager, + GimpPlugIn *plug_in) +{ + g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager)); + g_return_if_fail (GIMP_IS_PLUG_IN (plug_in)); + + manager->open_plug_ins = g_slist_remove (manager->open_plug_ins, plug_in); + + g_signal_emit (manager, manager_signals[PLUG_IN_CLOSED], 0, + plug_in); + + g_object_unref (plug_in); +} + +void +gimp_plug_in_manager_plug_in_push (GimpPlugInManager *manager, + GimpPlugIn *plug_in) +{ + g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager)); + g_return_if_fail (GIMP_IS_PLUG_IN (plug_in)); + + manager->current_plug_in = plug_in; + + manager->plug_in_stack = g_slist_prepend (manager->plug_in_stack, + manager->current_plug_in); +} + +void +gimp_plug_in_manager_plug_in_pop (GimpPlugInManager *manager) +{ + g_return_if_fail (GIMP_IS_PLUG_IN_MANAGER (manager)); + + if (manager->current_plug_in) + manager->plug_in_stack = g_slist_remove (manager->plug_in_stack, + manager->plug_in_stack->data); + + if (manager->plug_in_stack) + manager->current_plug_in = manager->plug_in_stack->data; + else + manager->current_plug_in = NULL; +} diff --git a/app/plug-in/gimppluginmanager.h b/app/plug-in/gimppluginmanager.h new file mode 100644 index 0000000..11f80b1 --- /dev/null +++ b/app/plug-in/gimppluginmanager.h @@ -0,0 +1,118 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis + * + * gimppluginmanager.h + * + * 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/>. + */ + +#ifndef __GIMP_PLUG_IN_MANAGER_H__ +#define __GIMP_PLUG_IN_MANAGER_H__ + + +#include "core/gimpobject.h" + + +#define GIMP_TYPE_PLUG_IN_MANAGER (gimp_plug_in_manager_get_type ()) +#define GIMP_PLUG_IN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_PLUG_IN_MANAGER, GimpPlugInManager)) +#define GIMP_PLUG_IN_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_PLUG_IN_MANAGER, GimpPlugInManagerClass)) +#define GIMP_IS_PLUG_IN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_PLUG_IN_MANAGER)) +#define GIMP_IS_PLUG_IN_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_PLUG_IN_MANAGER)) + + +typedef struct _GimpPlugInManagerClass GimpPlugInManagerClass; + +struct _GimpPlugInManager +{ + GimpObject parent_instance; + + Gimp *gimp; + + GSList *plug_in_defs; + gboolean write_pluginrc; + + GSList *plug_in_procedures; + + GSList *load_procs; + GSList *save_procs; + GSList *export_procs; + GSList *raw_load_procs; + + GSList *display_load_procs; + GSList *display_save_procs; + GSList *display_export_procs; + GSList *display_raw_load_procs; + + GSList *menu_branches; + GSList *locale_domains; + GSList *help_domains; + + GimpPlugIn *current_plug_in; + GSList *open_plug_ins; + GSList *plug_in_stack; + + GimpPlugInShm *shm; + GimpInterpreterDB *interpreter_db; + GimpEnvironTable *environ_table; + GimpPlugInDebug *debug; + GList *data_list; +}; + +struct _GimpPlugInManagerClass +{ + GimpObjectClass parent_class; + + void (* plug_in_opened) (GimpPlugInManager *manager, + GimpPlugIn *plug_in); + void (* plug_in_closed) (GimpPlugInManager *manager, + GimpPlugIn *plug_in); + + void (* menu_branch_added) (GimpPlugInManager *manager, + GFile *file, + const gchar *menu_path, + const gchar *menu_label); +}; + + +GType gimp_plug_in_manager_get_type (void) G_GNUC_CONST; + +GimpPlugInManager * gimp_plug_in_manager_new (Gimp *gimp); + +void gimp_plug_in_manager_initialize (GimpPlugInManager *manager, + GimpInitStatusFunc status_callback); +void gimp_plug_in_manager_exit (GimpPlugInManager *manager); + +/* Register a plug-in. This function is public for file load-save + * handlers, which are organized around the plug-in data structure. + * This could all be done a little better, but oh well. -josh + */ +void gimp_plug_in_manager_add_procedure (GimpPlugInManager *manager, + GimpPlugInProcedure *procedure); + +void gimp_plug_in_manager_add_temp_proc (GimpPlugInManager *manager, + GimpTemporaryProcedure *procedure); +void gimp_plug_in_manager_remove_temp_proc (GimpPlugInManager *manager, + GimpTemporaryProcedure *procedure); + +void gimp_plug_in_manager_add_open_plug_in (GimpPlugInManager *manager, + GimpPlugIn *plug_in); +void gimp_plug_in_manager_remove_open_plug_in (GimpPlugInManager *manager, + GimpPlugIn *plug_in); + +void gimp_plug_in_manager_plug_in_push (GimpPlugInManager *manager, + GimpPlugIn *plug_in); +void gimp_plug_in_manager_plug_in_pop (GimpPlugInManager *manager); + + +#endif /* __GIMP_PLUG_IN_MANAGER_H__ */ diff --git a/app/plug-in/gimppluginprocedure.c b/app/plug-in/gimppluginprocedure.c new file mode 100644 index 0000000..db7d240 --- /dev/null +++ b/app/plug-in/gimppluginprocedure.c @@ -0,0 +1,1293 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimppluginprocedure.c + * + * 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" + +#include <string.h> + +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpbase/gimpbase.h" + +#include "plug-in-types.h" + +#include "gegl/gimp-babl-compat.h" + +#include "core/gimp.h" +#include "core/gimp-memsize.h" +#include "core/gimpdrawable.h" +#include "core/gimpmarshal.h" +#include "core/gimpparamspecs.h" + +#include "file/file-utils.h" + +#define __YES_I_NEED_GIMP_PLUG_IN_MANAGER_CALL__ +#include "gimppluginmanager-call.h" + +#include "gimppluginerror.h" +#include "gimppluginprocedure.h" +#include "plug-in-menu-path.h" + +#include "gimp-intl.h" + + +enum +{ + MENU_PATH_ADDED, + LAST_SIGNAL +}; + + +static void gimp_plug_in_procedure_finalize (GObject *object); + +static gint64 gimp_plug_in_procedure_get_memsize (GimpObject *object, + gint64 *gui_size); + +static gchar * gimp_plug_in_procedure_get_description (GimpViewable *viewable, + gchar **tooltip); + +static const gchar * gimp_plug_in_procedure_get_label (GimpProcedure *procedure); +static const gchar * gimp_plug_in_procedure_get_menu_label + (GimpProcedure *procedure); +static const gchar * gimp_plug_in_procedure_get_blurb (GimpProcedure *procedure); +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); +static GimpValueArray * gimp_plug_in_procedure_execute (GimpProcedure *procedure, + Gimp *gimp, + GimpContext *context, + GimpProgress *progress, + GimpValueArray *args, + GError **error); +static void gimp_plug_in_procedure_execute_async (GimpProcedure *procedure, + Gimp *gimp, + GimpContext *context, + GimpProgress *progress, + GimpValueArray *args, + GimpObject *display); + +static GFile * gimp_plug_in_procedure_real_get_file (GimpPlugInProcedure *procedure); + +static gboolean gimp_plug_in_procedure_validate_args (GimpPlugInProcedure *proc, + Gimp *gimp, + GimpValueArray *args, + GError **error); + + +G_DEFINE_TYPE (GimpPlugInProcedure, gimp_plug_in_procedure, + GIMP_TYPE_PROCEDURE) + +#define parent_class gimp_plug_in_procedure_parent_class + +static guint gimp_plug_in_procedure_signals[LAST_SIGNAL] = { 0 }; + + +static void +gimp_plug_in_procedure_class_init (GimpPlugInProcedureClass *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); + + gimp_plug_in_procedure_signals[MENU_PATH_ADDED] = + g_signal_new ("menu-path-added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GimpPlugInProcedureClass, menu_path_added), + NULL, NULL, + gimp_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + object_class->finalize = gimp_plug_in_procedure_finalize; + + gimp_object_class->get_memsize = gimp_plug_in_procedure_get_memsize; + + viewable_class->default_icon_name = "system-run"; + viewable_class->get_description = gimp_plug_in_procedure_get_description; + + proc_class->get_label = gimp_plug_in_procedure_get_label; + proc_class->get_menu_label = gimp_plug_in_procedure_get_menu_label; + proc_class->get_blurb = gimp_plug_in_procedure_get_blurb; + proc_class->get_help_id = gimp_plug_in_procedure_get_help_id; + proc_class->get_sensitive = gimp_plug_in_procedure_get_sensitive; + proc_class->execute = gimp_plug_in_procedure_execute; + proc_class->execute_async = gimp_plug_in_procedure_execute_async; + + klass->get_file = gimp_plug_in_procedure_real_get_file; + klass->menu_path_added = NULL; +} + +static void +gimp_plug_in_procedure_init (GimpPlugInProcedure *proc) +{ + GIMP_PROCEDURE (proc)->proc_type = GIMP_PLUGIN; + + proc->icon_data_length = -1; +} + +static void +gimp_plug_in_procedure_finalize (GObject *object) +{ + GimpPlugInProcedure *proc = GIMP_PLUG_IN_PROCEDURE (object); + + g_object_unref (proc->file); + g_free (proc->menu_label); + + g_list_free_full (proc->menu_paths, (GDestroyNotify) g_free); + + g_free (proc->label); + g_free (proc->help_id); + + g_free (proc->icon_data); + g_free (proc->image_types); + g_free (proc->image_types_tooltip); + + g_free (proc->extensions); + g_free (proc->prefixes); + g_free (proc->magics); + g_free (proc->mime_types); + + g_slist_free_full (proc->extensions_list, (GDestroyNotify) g_free); + g_slist_free_full (proc->prefixes_list, (GDestroyNotify) g_free); + g_slist_free_full (proc->magics_list, (GDestroyNotify) g_free); + g_slist_free_full (proc->mime_types_list, (GDestroyNotify) g_free); + + g_free (proc->thumb_loader); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gint64 +gimp_plug_in_procedure_get_memsize (GimpObject *object, + gint64 *gui_size) +{ + GimpPlugInProcedure *proc = GIMP_PLUG_IN_PROCEDURE (object); + gint64 memsize = 0; + GList *list; + GSList *slist; + + memsize += gimp_g_object_get_memsize (G_OBJECT (proc->file)); + memsize += gimp_string_get_memsize (proc->menu_label); + + for (list = proc->menu_paths; list; list = g_list_next (list)) + memsize += sizeof (GList) + gimp_string_get_memsize (list->data); + + switch (proc->icon_type) + { + case GIMP_ICON_TYPE_ICON_NAME: + case GIMP_ICON_TYPE_IMAGE_FILE: + memsize += gimp_string_get_memsize ((const gchar *) proc->icon_data); + break; + + case GIMP_ICON_TYPE_INLINE_PIXBUF: + memsize += proc->icon_data_length; + break; + } + + memsize += gimp_string_get_memsize (proc->extensions); + memsize += gimp_string_get_memsize (proc->prefixes); + memsize += gimp_string_get_memsize (proc->magics); + memsize += gimp_string_get_memsize (proc->mime_types); + memsize += gimp_string_get_memsize (proc->thumb_loader); + + for (slist = proc->extensions_list; slist; slist = g_slist_next (slist)) + memsize += sizeof (GSList) + gimp_string_get_memsize (slist->data); + + for (slist = proc->prefixes_list; slist; slist = g_slist_next (slist)) + memsize += sizeof (GSList) + gimp_string_get_memsize (slist->data); + + for (slist = proc->magics_list; slist; slist = g_slist_next (slist)) + memsize += sizeof (GSList) + gimp_string_get_memsize (slist->data); + + for (slist = proc->mime_types_list; slist; slist = g_slist_next (slist)) + memsize += sizeof (GSList) + gimp_string_get_memsize (slist->data); + + return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object, + gui_size); +} + +static gchar * +gimp_plug_in_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_plug_in_procedure_get_label (GimpProcedure *procedure) +{ + GimpPlugInProcedure *proc = GIMP_PLUG_IN_PROCEDURE (procedure); + const gchar *path; + gchar *stripped; + gchar *ellipsis; + gchar *label; + + if (proc->label) + return proc->label; + + if (proc->menu_label) + path = dgettext (gimp_plug_in_procedure_get_locale_domain (proc), + proc->menu_label); + else if (proc->menu_paths) + path = dgettext (gimp_plug_in_procedure_get_locale_domain (proc), + proc->menu_paths->data); + else + return NULL; + + stripped = gimp_strip_uline (path); + + if (proc->menu_label) + label = g_strdup (stripped); + else + label = g_path_get_basename (stripped); + + g_free (stripped); + + 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_plug_in_procedure_get_menu_label (GimpProcedure *procedure) +{ + GimpPlugInProcedure *proc = GIMP_PLUG_IN_PROCEDURE (procedure); + + if (proc->menu_label) + { + return dgettext (gimp_plug_in_procedure_get_locale_domain (proc), + proc->menu_label); + } + else if (proc->menu_paths) + { + const gchar *translated; + + translated = dgettext (gimp_plug_in_procedure_get_locale_domain (proc), + proc->menu_paths->data); + + translated = strrchr (translated, '/'); + + if (translated) + return translated + 1; + } + + return GIMP_PROCEDURE_CLASS (parent_class)->get_menu_label (procedure); +} + +static const gchar * +gimp_plug_in_procedure_get_blurb (GimpProcedure *procedure) +{ + GimpPlugInProcedure *proc = GIMP_PLUG_IN_PROCEDURE (procedure); + + /* do not to pass the empty string to gettext() */ + if (procedure->blurb && strlen (procedure->blurb)) + return dgettext (gimp_plug_in_procedure_get_locale_domain (proc), + procedure->blurb); + + return NULL; +} + +static const gchar * +gimp_plug_in_procedure_get_help_id (GimpProcedure *procedure) +{ + GimpPlugInProcedure *proc = GIMP_PLUG_IN_PROCEDURE (procedure); + const gchar *domain; + + if (proc->help_id) + return proc->help_id; + + domain = gimp_plug_in_procedure_get_help_domain (proc); + + if (domain) + proc->help_id = g_strconcat (domain, "?", gimp_object_get_name (proc), NULL); + else + proc->help_id = g_strdup (gimp_object_get_name (proc)); + + return proc->help_id; +} + +static gboolean +gimp_plug_in_procedure_get_sensitive (GimpProcedure *procedure, + GimpObject *object, + const gchar **tooltip) +{ + GimpPlugInProcedure *proc = GIMP_PLUG_IN_PROCEDURE (procedure); + GimpDrawable *drawable; + GimpImageType image_type = -1; + gboolean sensitive = FALSE; + + g_return_val_if_fail (object == NULL || GIMP_IS_DRAWABLE (object), FALSE); + + drawable = GIMP_DRAWABLE (object); + + if (drawable) + { + const Babl *format = gimp_drawable_get_format (drawable); + + image_type = gimp_babl_format_get_image_type (format); + } + + switch (image_type) + { + case GIMP_RGB_IMAGE: + sensitive = proc->image_types_val & GIMP_PLUG_IN_RGB_IMAGE; + break; + case GIMP_RGBA_IMAGE: + sensitive = proc->image_types_val & GIMP_PLUG_IN_RGBA_IMAGE; + break; + case GIMP_GRAY_IMAGE: + sensitive = proc->image_types_val & GIMP_PLUG_IN_GRAY_IMAGE; + break; + case GIMP_GRAYA_IMAGE: + sensitive = proc->image_types_val & GIMP_PLUG_IN_GRAYA_IMAGE; + break; + case GIMP_INDEXED_IMAGE: + sensitive = proc->image_types_val & GIMP_PLUG_IN_INDEXED_IMAGE; + break; + case GIMP_INDEXEDA_IMAGE: + sensitive = proc->image_types_val & GIMP_PLUG_IN_INDEXEDA_IMAGE; + break; + default: + break; + } + + if (! sensitive) + *tooltip = proc->image_types_tooltip; + + return sensitive ? TRUE : FALSE; +} + +static GimpValueArray * +gimp_plug_in_procedure_execute (GimpProcedure *procedure, + Gimp *gimp, + GimpContext *context, + GimpProgress *progress, + GimpValueArray *args, + GError **error) +{ + GimpPlugInProcedure *plug_in_procedure = GIMP_PLUG_IN_PROCEDURE (procedure); + GError *pdb_error = NULL; + + if (! gimp_plug_in_procedure_validate_args (plug_in_procedure, gimp, + args, &pdb_error)) + { + GimpValueArray *return_vals; + + return_vals = gimp_procedure_get_return_values (procedure, FALSE, + pdb_error); + g_propagate_error (error, pdb_error); + + return return_vals; + } + + if (procedure->proc_type == GIMP_INTERNAL) + return GIMP_PROCEDURE_CLASS (parent_class)->execute (procedure, gimp, + context, progress, + args, error); + + return gimp_plug_in_manager_call_run (gimp->plug_in_manager, + context, progress, + GIMP_PLUG_IN_PROCEDURE (procedure), + args, TRUE, NULL); +} + +static void +gimp_plug_in_procedure_execute_async (GimpProcedure *procedure, + Gimp *gimp, + GimpContext *context, + GimpProgress *progress, + GimpValueArray *args, + GimpObject *display) +{ + GimpPlugInProcedure *plug_in_procedure = GIMP_PLUG_IN_PROCEDURE (procedure); + GError *error = NULL; + + if (gimp_plug_in_procedure_validate_args (plug_in_procedure, gimp, + args, &error)) + { + GimpValueArray *return_vals; + + return_vals = gimp_plug_in_manager_call_run (gimp->plug_in_manager, + context, progress, + plug_in_procedure, + args, FALSE, display); + + if (return_vals) + { + gimp_plug_in_procedure_handle_return_values (plug_in_procedure, + gimp, progress, + return_vals); + gimp_value_array_unref (return_vals); + } + } + else + { + gimp_message_literal (gimp, G_OBJECT (progress), GIMP_MESSAGE_ERROR, + error->message); + g_error_free (error); + } +} + +static GFile * +gimp_plug_in_procedure_real_get_file (GimpPlugInProcedure *procedure) +{ + return procedure->file; +} + +static gboolean +gimp_plug_in_procedure_validate_args (GimpPlugInProcedure *proc, + Gimp *gimp, + GimpValueArray *args, + GError **error) +{ + if (proc->file_proc && proc->handles_uri) + { + /* for file procedures that handle URIs, make sure that the + * passed string actually is an URI, not just a file path + * (bug 758685) + */ + GimpProcedure *procedure = GIMP_PROCEDURE (proc); + GValue *uri_value = NULL; + + if ((procedure->num_args >= 3) && + (procedure->num_values >= 1) && + GIMP_IS_PARAM_SPEC_INT32 (procedure->args[0]) && + G_IS_PARAM_SPEC_STRING (procedure->args[1]) && + G_IS_PARAM_SPEC_STRING (procedure->args[2]) && + GIMP_IS_PARAM_SPEC_IMAGE_ID (procedure->values[0])) + { + uri_value = gimp_value_array_index (args, 1); + } + else if ((procedure->num_args >= 5) && + GIMP_IS_PARAM_SPEC_INT32 (procedure->args[0]) && + GIMP_IS_PARAM_SPEC_IMAGE_ID (procedure->args[1]) && + GIMP_IS_PARAM_SPEC_DRAWABLE_ID (procedure->args[2]) && + G_IS_PARAM_SPEC_STRING (procedure->args[3]) && + G_IS_PARAM_SPEC_STRING (procedure->args[4])) + { + uri_value = gimp_value_array_index (args, 3); + } + + if (uri_value) + { + GFile *file; + + file = file_utils_filename_to_file (gimp, + g_value_get_string (uri_value), + error); + + if (! file) + return FALSE; + + g_value_take_string (uri_value, g_file_get_uri (file)); + g_object_unref (file); + } + } + + return TRUE; +} + + +/* public functions */ + +GimpProcedure * +gimp_plug_in_procedure_new (GimpPDBProcType proc_type, + GFile *file) +{ + GimpPlugInProcedure *proc; + + g_return_val_if_fail (proc_type == GIMP_PLUGIN || + proc_type == GIMP_EXTENSION, NULL); + g_return_val_if_fail (G_IS_FILE (file), NULL); + + proc = g_object_new (GIMP_TYPE_PLUG_IN_PROCEDURE, NULL); + + proc->file = g_object_ref (file); + + GIMP_PROCEDURE (proc)->proc_type = proc_type; + + return GIMP_PROCEDURE (proc); +} + +GimpPlugInProcedure * +gimp_plug_in_procedure_find (GSList *list, + const gchar *proc_name) +{ + GSList *l; + + for (l = list; l; l = g_slist_next (l)) + { + GimpObject *object = l->data; + + if (! strcmp (proc_name, gimp_object_get_name (object))) + return GIMP_PLUG_IN_PROCEDURE (object); + } + + return NULL; +} + +GFile * +gimp_plug_in_procedure_get_file (GimpPlugInProcedure *proc) +{ + g_return_val_if_fail (GIMP_IS_PLUG_IN_PROCEDURE (proc), NULL); + + return GIMP_PLUG_IN_PROCEDURE_GET_CLASS (proc)->get_file (proc); +} + +void +gimp_plug_in_procedure_set_locale_domain (GimpPlugInProcedure *proc, + const gchar *locale_domain) +{ + g_return_if_fail (GIMP_IS_PLUG_IN_PROCEDURE (proc)); + + proc->locale_domain = locale_domain ? g_quark_from_string (locale_domain) : 0; +} + +const gchar * +gimp_plug_in_procedure_get_locale_domain (GimpPlugInProcedure *proc) +{ + g_return_val_if_fail (GIMP_IS_PLUG_IN_PROCEDURE (proc), NULL); + + return g_quark_to_string (proc->locale_domain); +} + +void +gimp_plug_in_procedure_set_help_domain (GimpPlugInProcedure *proc, + const gchar *help_domain) +{ + g_return_if_fail (GIMP_IS_PLUG_IN_PROCEDURE (proc)); + + proc->help_domain = help_domain ? g_quark_from_string (help_domain) : 0; +} + +const gchar * +gimp_plug_in_procedure_get_help_domain (GimpPlugInProcedure *proc) +{ + g_return_val_if_fail (GIMP_IS_PLUG_IN_PROCEDURE (proc), NULL); + + return g_quark_to_string (proc->help_domain); +} + +gboolean +gimp_plug_in_procedure_add_menu_path (GimpPlugInProcedure *proc, + const gchar *menu_path, + GError **error) +{ + GimpProcedure *procedure; + gchar *basename = NULL; + const gchar *required = NULL; + gchar *p; + gchar *mapped_path; + + g_return_val_if_fail (GIMP_IS_PLUG_IN_PROCEDURE (proc), FALSE); + g_return_val_if_fail (menu_path != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + procedure = GIMP_PROCEDURE (proc); + + p = strchr (menu_path, '>'); + if (p == NULL || (*(++p) && *p != '/')) + { + basename = g_path_get_basename (gimp_file_get_utf8_name (proc->file)); + + g_set_error (error, GIMP_PLUG_IN_ERROR, GIMP_PLUG_IN_FAILED, + "Plug-in \"%s\"\n(%s)\n" + "attempted to install procedure \"%s\"\n" + "in the invalid menu location \"%s\".\n" + "The menu path must look like either \"<Prefix>\" " + "or \"<Prefix>/path/to/item\".", + basename, gimp_file_get_utf8_name (proc->file), + gimp_object_get_name (proc), + menu_path); + goto failure; + } + + if (g_str_has_prefix (menu_path, "<Toolbox>") || + g_str_has_prefix (menu_path, "<Image>")) + { + if ((procedure->num_args < 1) || + ! GIMP_IS_PARAM_SPEC_INT32 (procedure->args[0])) + { + required = "INT32"; + goto failure; + } + } + else if (g_str_has_prefix (menu_path, "<Layers>")) + { + if ((procedure->num_args < 3) || + ! GIMP_IS_PARAM_SPEC_INT32 (procedure->args[0]) || + ! GIMP_IS_PARAM_SPEC_IMAGE_ID (procedure->args[1]) || + ! (G_TYPE_FROM_INSTANCE (procedure->args[2]) + == GIMP_TYPE_PARAM_LAYER_ID || + G_TYPE_FROM_INSTANCE (procedure->args[2]) + == GIMP_TYPE_PARAM_DRAWABLE_ID)) + { + required = "INT32, IMAGE, (LAYER | DRAWABLE)"; + goto failure; + } + } + else if (g_str_has_prefix (menu_path, "<Channels>")) + { + if ((procedure->num_args < 3) || + ! GIMP_IS_PARAM_SPEC_INT32 (procedure->args[0]) || + ! GIMP_IS_PARAM_SPEC_IMAGE_ID (procedure->args[1]) || + ! (G_TYPE_FROM_INSTANCE (procedure->args[2]) + == GIMP_TYPE_PARAM_CHANNEL_ID || + G_TYPE_FROM_INSTANCE (procedure->args[2]) + == GIMP_TYPE_PARAM_DRAWABLE_ID)) + { + required = "INT32, IMAGE, (CHANNEL | DRAWABLE)"; + goto failure; + } + } + else if (g_str_has_prefix (menu_path, "<Vectors>")) + { + if ((procedure->num_args < 3) || + ! GIMP_IS_PARAM_SPEC_INT32 (procedure->args[0]) || + ! GIMP_IS_PARAM_SPEC_IMAGE_ID (procedure->args[1]) || + ! GIMP_IS_PARAM_SPEC_VECTORS_ID (procedure->args[2])) + { + required = "INT32, IMAGE, VECTORS"; + goto failure; + } + } + else if (g_str_has_prefix (menu_path, "<Colormap>")) + { + if ((procedure->num_args < 2) || + ! GIMP_IS_PARAM_SPEC_INT32 (procedure->args[0]) || + ! GIMP_IS_PARAM_SPEC_IMAGE_ID (procedure->args[1])) + { + required = "INT32, IMAGE"; + goto failure; + } + } + else if (g_str_has_prefix (menu_path, "<Load>")) + { + if ((procedure->num_args < 3) || + ! GIMP_IS_PARAM_SPEC_INT32 (procedure->args[0]) || + ! G_IS_PARAM_SPEC_STRING (procedure->args[1]) || + ! G_IS_PARAM_SPEC_STRING (procedure->args[2])) + { + required = "INT32, STRING, STRING"; + goto failure; + } + + if ((procedure->num_values < 1) || + ! GIMP_IS_PARAM_SPEC_IMAGE_ID (procedure->values[0])) + { + required = "IMAGE"; + goto failure; + } + } + else if (g_str_has_prefix (menu_path, "<Save>")) + { + if ((procedure->num_args < 5) || + ! GIMP_IS_PARAM_SPEC_INT32 (procedure->args[0]) || + ! GIMP_IS_PARAM_SPEC_IMAGE_ID (procedure->args[1]) || + ! GIMP_IS_PARAM_SPEC_DRAWABLE_ID (procedure->args[2]) || + ! G_IS_PARAM_SPEC_STRING (procedure->args[3]) || + ! G_IS_PARAM_SPEC_STRING (procedure->args[4])) + { + required = "INT32, IMAGE, DRAWABLE, STRING, STRING"; + goto failure; + } + } + else if (g_str_has_prefix (menu_path, "<Brushes>") || + g_str_has_prefix (menu_path, "<Dynamics>") || + g_str_has_prefix (menu_path, "<MyPaintBrushes>") || + g_str_has_prefix (menu_path, "<Gradients>") || + g_str_has_prefix (menu_path, "<Palettes>") || + g_str_has_prefix (menu_path, "<Patterns>") || + g_str_has_prefix (menu_path, "<ToolPresets>") || + g_str_has_prefix (menu_path, "<Fonts>") || + g_str_has_prefix (menu_path, "<Buffers>")) + { + if ((procedure->num_args < 1) || + ! GIMP_IS_PARAM_SPEC_INT32 (procedure->args[0])) + { + required = "INT32"; + goto failure; + } + } + else + { + basename = g_path_get_basename (gimp_file_get_utf8_name (proc->file)); + + g_set_error (error, GIMP_PLUG_IN_ERROR, GIMP_PLUG_IN_FAILED, + "Plug-in \"%s\"\n(%s)\n" + "attempted to install procedure \"%s\" " + "in the invalid menu location \"%s\".\n" + "Use either \"<Image>\", " + "\"<Layers>\", \"<Channels>\", \"<Vectors>\", " + "\"<Colormap>\", \"<Brushes>\", \"<Dynamics>\", " + "\"<MyPaintBrushes>\", \"<Gradients>\", \"<Palettes>\", " + "\"<Patterns>\", \"<ToolPresets>\", \"<Fonts>\" " + "or \"<Buffers>\".", + basename, gimp_file_get_utf8_name (proc->file), + gimp_object_get_name (proc), + menu_path); + goto failure; + } + + g_free (basename); + + mapped_path = plug_in_menu_path_map (menu_path, NULL); + + proc->menu_paths = g_list_append (proc->menu_paths, mapped_path); + + g_signal_emit (proc, gimp_plug_in_procedure_signals[MENU_PATH_ADDED], 0, + mapped_path); + + return TRUE; + + failure: + if (required) + { + gchar *prefix = g_strdup (menu_path); + + p = strchr (prefix, '>') + 1; + *p = '\0'; + + basename = g_path_get_basename (gimp_file_get_utf8_name (proc->file)); + + g_set_error (error, GIMP_PLUG_IN_ERROR, GIMP_PLUG_IN_FAILED, + "Plug-in \"%s\"\n(%s)\n\n" + "attempted to install %s procedure \"%s\" " + "which does not take the standard %s plug-in's " + "arguments: (%s).", + basename, gimp_file_get_utf8_name (proc->file), + prefix, gimp_object_get_name (proc), prefix, + required); + + g_free (prefix); + } + + g_free (basename); + + return FALSE; +} + +void +gimp_plug_in_procedure_set_icon (GimpPlugInProcedure *proc, + GimpIconType icon_type, + const guint8 *icon_data, + gint icon_data_length) +{ + guint8 *data_copy = NULL; + + g_return_if_fail (GIMP_IS_PLUG_IN_PROCEDURE (proc)); + + switch (icon_type) + { + case GIMP_ICON_TYPE_ICON_NAME: + data_copy = (guint8 *) g_strdup ((gchar *) icon_data); + break; + + case GIMP_ICON_TYPE_INLINE_PIXBUF: + data_copy = g_memdup (icon_data, icon_data_length); + break; + + case GIMP_ICON_TYPE_IMAGE_FILE: + data_copy = (guint8 *) g_strdup ((gchar *) icon_data); + break; + + default: + g_return_if_reached (); + } + + gimp_plug_in_procedure_take_icon (proc, icon_type, + data_copy, icon_data_length); +} + +void +gimp_plug_in_procedure_take_icon (GimpPlugInProcedure *proc, + GimpIconType icon_type, + guint8 *icon_data, + gint icon_data_length) +{ + const gchar *icon_name = NULL; + GdkPixbuf *icon_pixbuf = NULL; + GError *error = NULL; + + g_return_if_fail (GIMP_IS_PLUG_IN_PROCEDURE (proc)); + + if (proc->icon_data) + { + g_free (proc->icon_data); + proc->icon_data_length = -1; + proc->icon_data = NULL; + } + + proc->icon_type = icon_type; + + switch (proc->icon_type) + { + case GIMP_ICON_TYPE_ICON_NAME: + proc->icon_data_length = -1; + proc->icon_data = icon_data; + + icon_name = (const gchar *) proc->icon_data; + break; + + case GIMP_ICON_TYPE_INLINE_PIXBUF: + proc->icon_data_length = icon_data_length; + proc->icon_data = icon_data; + + icon_pixbuf = gdk_pixbuf_new_from_inline (proc->icon_data_length, + proc->icon_data, TRUE, &error); + break; + + case GIMP_ICON_TYPE_IMAGE_FILE: + proc->icon_data_length = -1; + proc->icon_data = icon_data; + + icon_pixbuf = gdk_pixbuf_new_from_file ((gchar *) proc->icon_data, + &error); + break; + } + + if (! icon_pixbuf && error) + { + g_printerr ("gimp_plug_in_procedure_take_icon: %s\n", error->message); + g_clear_error (&error); + } + + gimp_viewable_set_icon_name (GIMP_VIEWABLE (proc), icon_name); + g_object_set (proc, "icon-pixbuf", icon_pixbuf, NULL); + + if (icon_pixbuf) + g_object_unref (icon_pixbuf); +} + +static GimpPlugInImageType +image_types_parse (const gchar *name, + const gchar *image_types) +{ + const gchar *type_spec = image_types; + GimpPlugInImageType types = 0; + + /* If the plug_in registers with image_type == NULL or "", return 0 + * By doing so it won't be touched by plug_in_set_menu_sensitivity() + */ + if (! image_types) + return types; + + while (*image_types) + { + while (*image_types && + ((*image_types == ' ') || + (*image_types == '\t') || + (*image_types == ','))) + image_types++; + + if (*image_types) + { + if (g_str_has_prefix (image_types, "RGBA")) + { + types |= GIMP_PLUG_IN_RGBA_IMAGE; + image_types += strlen ("RGBA"); + } + else if (g_str_has_prefix (image_types, "RGB*")) + { + types |= GIMP_PLUG_IN_RGB_IMAGE | GIMP_PLUG_IN_RGBA_IMAGE; + image_types += strlen ("RGB*"); + } + else if (g_str_has_prefix (image_types, "RGB")) + { + types |= GIMP_PLUG_IN_RGB_IMAGE; + image_types += strlen ("RGB"); + } + else if (g_str_has_prefix (image_types, "GRAYA")) + { + types |= GIMP_PLUG_IN_GRAYA_IMAGE; + image_types += strlen ("GRAYA"); + } + else if (g_str_has_prefix (image_types, "GRAY*")) + { + types |= GIMP_PLUG_IN_GRAY_IMAGE | GIMP_PLUG_IN_GRAYA_IMAGE; + image_types += strlen ("GRAY*"); + } + else if (g_str_has_prefix (image_types, "GRAY")) + { + types |= GIMP_PLUG_IN_GRAY_IMAGE; + image_types += strlen ("GRAY"); + } + else if (g_str_has_prefix (image_types, "INDEXEDA")) + { + types |= GIMP_PLUG_IN_INDEXEDA_IMAGE; + image_types += strlen ("INDEXEDA"); + } + else if (g_str_has_prefix (image_types, "INDEXED*")) + { + types |= GIMP_PLUG_IN_INDEXED_IMAGE | GIMP_PLUG_IN_INDEXEDA_IMAGE; + image_types += strlen ("INDEXED*"); + } + else if (g_str_has_prefix (image_types, "INDEXED")) + { + types |= GIMP_PLUG_IN_INDEXED_IMAGE; + image_types += strlen ("INDEXED"); + } + else if (g_str_has_prefix (image_types, "*")) + { + types |= (GIMP_PLUG_IN_RGB_IMAGE | GIMP_PLUG_IN_RGBA_IMAGE | + GIMP_PLUG_IN_GRAY_IMAGE | GIMP_PLUG_IN_GRAYA_IMAGE | + GIMP_PLUG_IN_INDEXED_IMAGE | GIMP_PLUG_IN_INDEXEDA_IMAGE); + image_types += strlen ("*"); + } + else + { + g_printerr ("%s: image-type contains unrecognizable parts:" + "'%s'\n", name, type_spec); + + /* skip to next token */ + while (*image_types && + *image_types != ' ' && + *image_types != '\t' && + *image_types != ',') + { + image_types++; + } + } + } + } + + return types; +} + +void +gimp_plug_in_procedure_set_image_types (GimpPlugInProcedure *proc, + const gchar *image_types) +{ + GList *types = NULL; + + g_return_if_fail (GIMP_IS_PLUG_IN_PROCEDURE (proc)); + + if (proc->image_types) + g_free (proc->image_types); + + proc->image_types = g_strdup (image_types); + proc->image_types_val = image_types_parse (gimp_object_get_name (proc), + proc->image_types); + + g_clear_pointer (&proc->image_types_tooltip, g_free); + + if (proc->image_types_val & + (GIMP_PLUG_IN_RGB_IMAGE | GIMP_PLUG_IN_RGBA_IMAGE)) + { + if ((proc->image_types_val & GIMP_PLUG_IN_RGB_IMAGE) && + (proc->image_types_val & GIMP_PLUG_IN_RGBA_IMAGE)) + { + types = g_list_prepend (types, _("RGB")); + } + else if (proc->image_types_val & GIMP_PLUG_IN_RGB_IMAGE) + { + types = g_list_prepend (types, _("RGB without alpha")); + } + else + { + types = g_list_prepend (types, _("RGB with alpha")); + } + } + + if (proc->image_types_val & + (GIMP_PLUG_IN_GRAY_IMAGE | GIMP_PLUG_IN_GRAYA_IMAGE)) + { + if ((proc->image_types_val & GIMP_PLUG_IN_GRAY_IMAGE) && + (proc->image_types_val & GIMP_PLUG_IN_GRAYA_IMAGE)) + { + types = g_list_prepend (types, _("Grayscale")); + } + else if (proc->image_types_val & GIMP_PLUG_IN_GRAY_IMAGE) + { + types = g_list_prepend (types, _("Grayscale without alpha")); + } + else + { + types = g_list_prepend (types, _("Grayscale with alpha")); + } + } + + if (proc->image_types_val & + (GIMP_PLUG_IN_INDEXED_IMAGE | GIMP_PLUG_IN_INDEXEDA_IMAGE)) + { + if ((proc->image_types_val & GIMP_PLUG_IN_INDEXED_IMAGE) && + (proc->image_types_val & GIMP_PLUG_IN_INDEXEDA_IMAGE)) + { + types = g_list_prepend (types, _("Indexed")); + } + else if (proc->image_types_val & GIMP_PLUG_IN_INDEXED_IMAGE) + { + types = g_list_prepend (types, _("Indexed without alpha")); + } + else + { + types = g_list_prepend (types, _("Indexed with alpha")); + } + } + + if (types) + { + GString *string; + GList *list; + + 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"); + + for (list = types; list; list = g_list_next (list)) + { + g_string_append (string, list->data); + + if (list->next) + g_string_append (string, ", "); + else + g_string_append (string, "."); + } + + g_list_free (types); + + proc->image_types_tooltip = g_string_free (string, FALSE); + } +} + +static GSList * +extensions_parse (gchar *extensions) +{ + GSList *list = NULL; + + /* extensions can be NULL. Avoid calling strtok if it is. */ + if (extensions) + { + gchar *extension; + gchar *next_token; + + /* work on a copy */ + extensions = g_strdup (extensions); + + next_token = extensions; + extension = strtok (next_token, " \t,"); + + while (extension) + { + list = g_slist_prepend (list, g_strdup (extension)); + extension = strtok (NULL, " \t,"); + } + + g_free (extensions); + } + + return g_slist_reverse (list); +} + +void +gimp_plug_in_procedure_set_file_proc (GimpPlugInProcedure *proc, + const gchar *extensions, + const gchar *prefixes, + const gchar *magics) +{ + GSList *list; + + g_return_if_fail (GIMP_IS_PLUG_IN_PROCEDURE (proc)); + + proc->file_proc = TRUE; + + /* extensions */ + + if (proc->extensions != extensions) + { + if (proc->extensions) + g_free (proc->extensions); + + proc->extensions = g_strdup (extensions); + } + + if (proc->extensions_list) + g_slist_free_full (proc->extensions_list, (GDestroyNotify) g_free); + + proc->extensions_list = extensions_parse (proc->extensions); + + /* prefixes */ + + if (proc->prefixes != prefixes) + { + if (proc->prefixes) + g_free (proc->prefixes); + + proc->prefixes = g_strdup (prefixes); + } + + if (proc->prefixes_list) + g_slist_free_full (proc->prefixes_list, (GDestroyNotify) g_free); + + proc->prefixes_list = extensions_parse (proc->prefixes); + + /* don't allow "file:" to be registered as prefix */ + for (list = proc->prefixes_list; list; list = g_slist_next (list)) + { + const gchar *prefix = list->data; + + if (prefix && strcmp (prefix, "file:") == 0) + { + g_free (list->data); + proc->prefixes_list = g_slist_delete_link (proc->prefixes_list, list); + break; + } + } + + /* magics */ + + if (proc->magics != magics) + { + if (proc->magics) + g_free (proc->magics); + + proc->magics = g_strdup (magics); + } + + if (proc->magics_list) + g_slist_free_full (proc->magics_list, (GDestroyNotify) g_free); + + proc->magics_list = extensions_parse (proc->magics); +} + +void +gimp_plug_in_procedure_set_priority (GimpPlugInProcedure *proc, + gint priority) +{ + g_return_if_fail (GIMP_IS_PLUG_IN_PROCEDURE (proc)); + + proc->priority = priority; +} + +void +gimp_plug_in_procedure_set_mime_types (GimpPlugInProcedure *proc, + const gchar *mime_types) +{ + g_return_if_fail (GIMP_IS_PLUG_IN_PROCEDURE (proc)); + + if (proc->mime_types != mime_types) + { + if (proc->mime_types) + g_free (proc->mime_types); + + proc->mime_types = g_strdup (mime_types); + } + + if (proc->mime_types_list) + g_slist_free_full (proc->mime_types_list, (GDestroyNotify) g_free); + + proc->mime_types_list = extensions_parse (proc->mime_types); +} + +void +gimp_plug_in_procedure_set_handles_uri (GimpPlugInProcedure *proc) +{ + g_return_if_fail (GIMP_IS_PLUG_IN_PROCEDURE (proc)); + + proc->handles_uri = TRUE; +} + +void +gimp_plug_in_procedure_set_handles_raw (GimpPlugInProcedure *proc) +{ + g_return_if_fail (GIMP_IS_PLUG_IN_PROCEDURE (proc)); + + proc->handles_raw = TRUE; +} + +void +gimp_plug_in_procedure_set_thumb_loader (GimpPlugInProcedure *proc, + const gchar *thumb_loader) +{ + g_return_if_fail (GIMP_IS_PLUG_IN_PROCEDURE (proc)); + + if (proc->thumb_loader) + g_free (proc->thumb_loader); + + proc->thumb_loader = g_strdup (thumb_loader); +} + +void +gimp_plug_in_procedure_handle_return_values (GimpPlugInProcedure *proc, + Gimp *gimp, + GimpProgress *progress, + GimpValueArray *return_vals) +{ + g_return_if_fail (GIMP_IS_PLUG_IN_PROCEDURE (proc)); + g_return_if_fail (return_vals != NULL); + + if (gimp_value_array_length (return_vals) == 0 || + G_VALUE_TYPE (gimp_value_array_index (return_vals, 0)) != + GIMP_TYPE_PDB_STATUS_TYPE) + { + return; + } + + switch (g_value_get_enum (gimp_value_array_index (return_vals, 0))) + { + case GIMP_PDB_SUCCESS: + break; + + case GIMP_PDB_CALLING_ERROR: + if (gimp_value_array_length (return_vals) > 1 && + G_VALUE_HOLDS_STRING (gimp_value_array_index (return_vals, 1))) + { + gimp_message (gimp, G_OBJECT (progress), GIMP_MESSAGE_ERROR, + _("Calling error for '%s':\n" + "%s"), + gimp_procedure_get_label (GIMP_PROCEDURE (proc)), + g_value_get_string (gimp_value_array_index (return_vals, 1))); + } + break; + + case GIMP_PDB_EXECUTION_ERROR: + if (gimp_value_array_length (return_vals) > 1 && + G_VALUE_HOLDS_STRING (gimp_value_array_index (return_vals, 1))) + { + gimp_message (gimp, G_OBJECT (progress), GIMP_MESSAGE_ERROR, + _("Execution error for '%s':\n" + "%s"), + gimp_procedure_get_label (GIMP_PROCEDURE (proc)), + g_value_get_string (gimp_value_array_index (return_vals, 1))); + } + break; + } +} diff --git a/app/plug-in/gimppluginprocedure.h b/app/plug-in/gimppluginprocedure.h new file mode 100644 index 0000000..e462040 --- /dev/null +++ b/app/plug-in/gimppluginprocedure.h @@ -0,0 +1,140 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimppluginprocedure.h + * + * 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/>. + */ + +#ifndef __GIMP_PLUG_IN_PROCEDURE_H__ +#define __GIMP_PLUG_IN_PROCEDURE_H__ + + +#include "pdb/gimpprocedure.h" + + +#define GIMP_TYPE_PLUG_IN_PROCEDURE (gimp_plug_in_procedure_get_type ()) +#define GIMP_PLUG_IN_PROCEDURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_PLUG_IN_PROCEDURE, GimpPlugInProcedure)) +#define GIMP_PLUG_IN_PROCEDURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_PLUG_IN_PROCEDURE, GimpPlugInProcedureClass)) +#define GIMP_IS_PLUG_IN_PROCEDURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_PLUG_IN_PROCEDURE)) +#define GIMP_IS_PLUG_IN_PROCEDURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_PLUG_IN_PROCEDURE)) +#define GIMP_PLUG_IN_PROCEDURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_PLUG_IN_PROCEDURE, GimpPlugInProcedureClass)) + + +typedef struct _GimpPlugInProcedureClass GimpPlugInProcedureClass; + +struct _GimpPlugInProcedure +{ + GimpProcedure parent_instance; + + /* common members */ + GFile *file; + GQuark locale_domain; + GQuark help_domain; + gchar *menu_label; + GList *menu_paths; + gchar *label; + gchar *help_id; + GimpIconType icon_type; + gint icon_data_length; + guint8 *icon_data; + gchar *image_types; + GimpPlugInImageType image_types_val; + gchar *image_types_tooltip; + gint64 mtime; + gboolean installed_during_init; + + /* file proc specific members */ + gboolean file_proc; + gchar *extensions; + gchar *prefixes; + gchar *magics; + gint priority; + gchar *mime_types; + gboolean handles_uri; + gboolean handles_raw; + GSList *extensions_list; + GSList *prefixes_list; + GSList *magics_list; + GSList *mime_types_list; + gchar *thumb_loader; +}; + +struct _GimpPlugInProcedureClass +{ + GimpProcedureClass parent_class; + + /* virtual functions */ + GFile * (* get_file) (GimpPlugInProcedure *procedure); + + /* signals */ + void (* menu_path_added) (GimpPlugInProcedure *procedure, + const gchar *menu_path); +}; + + +GType gimp_plug_in_procedure_get_type (void) G_GNUC_CONST; + +GimpProcedure * gimp_plug_in_procedure_new (GimpPDBProcType proc_type, + GFile *file); + +GimpPlugInProcedure * gimp_plug_in_procedure_find (GSList *list, + const gchar *proc_name); + +GFile * gimp_plug_in_procedure_get_file (GimpPlugInProcedure *proc); + +void gimp_plug_in_procedure_set_locale_domain (GimpPlugInProcedure *proc, + const gchar *locale_domain); +const gchar * gimp_plug_in_procedure_get_locale_domain (GimpPlugInProcedure *proc); + +void gimp_plug_in_procedure_set_help_domain (GimpPlugInProcedure *proc, + const gchar *help_domain); +const gchar * gimp_plug_in_procedure_get_help_domain (GimpPlugInProcedure *proc); + +gboolean gimp_plug_in_procedure_add_menu_path (GimpPlugInProcedure *proc, + const gchar *menu_path, + GError **error); + +void gimp_plug_in_procedure_set_icon (GimpPlugInProcedure *proc, + GimpIconType type, + const guint8 *data, + gint data_length); +void gimp_plug_in_procedure_take_icon (GimpPlugInProcedure *proc, + GimpIconType type, + guint8 *data, + gint data_length); + +void gimp_plug_in_procedure_set_image_types (GimpPlugInProcedure *proc, + const gchar *image_types); +void gimp_plug_in_procedure_set_file_proc (GimpPlugInProcedure *proc, + const gchar *extensions, + const gchar *prefixes, + const gchar *magics); +void gimp_plug_in_procedure_set_priority (GimpPlugInProcedure *proc, + gint priority); +void gimp_plug_in_procedure_set_mime_types (GimpPlugInProcedure *proc, + const gchar *mime_ypes); +void gimp_plug_in_procedure_set_handles_uri (GimpPlugInProcedure *proc); +void gimp_plug_in_procedure_set_handles_raw (GimpPlugInProcedure *proc); +void gimp_plug_in_procedure_set_thumb_loader (GimpPlugInProcedure *proc, + const gchar *thumbnailer); + +void gimp_plug_in_procedure_handle_return_values (GimpPlugInProcedure *proc, + Gimp *gimp, + GimpProgress *progress, + + GimpValueArray *return_vals); + + +#endif /* __GIMP_PLUG_IN_PROCEDURE_H__ */ diff --git a/app/plug-in/gimppluginprocframe.c b/app/plug-in/gimppluginprocframe.c new file mode 100644 index 0000000..10445ef --- /dev/null +++ b/app/plug-in/gimppluginprocframe.c @@ -0,0 +1,200 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimppluginprocframe.c + * + * 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" + +#include <string.h> + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpbase/gimpbase.h" + +#include "plug-in-types.h" + +#include "core/gimpprogress.h" + +#include "pdb/gimppdbcontext.h" +#include "pdb/gimppdberror.h" + +#include "gimpplugin.h" +#include "gimpplugin-cleanup.h" +#include "gimpplugin-progress.h" +#include "gimppluginprocedure.h" + +#include "gimp-intl.h" + + +/* public functions */ + +GimpPlugInProcFrame * +gimp_plug_in_proc_frame_new (GimpContext *context, + GimpProgress *progress, + GimpPlugInProcedure *procedure) +{ + GimpPlugInProcFrame *proc_frame; + + g_return_val_if_fail (GIMP_IS_PDB_CONTEXT (context), NULL); + g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL); + g_return_val_if_fail (GIMP_IS_PLUG_IN_PROCEDURE (procedure), NULL); + + proc_frame = g_slice_new0 (GimpPlugInProcFrame); + + proc_frame->ref_count = 1; + + gimp_plug_in_proc_frame_init (proc_frame, context, progress, procedure); + + return proc_frame; +} + +void +gimp_plug_in_proc_frame_init (GimpPlugInProcFrame *proc_frame, + GimpContext *context, + GimpProgress *progress, + GimpPlugInProcedure *procedure) +{ + g_return_if_fail (proc_frame != NULL); + g_return_if_fail (GIMP_IS_PDB_CONTEXT (context)); + g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); + g_return_if_fail (procedure == NULL || + GIMP_IS_PLUG_IN_PROCEDURE (procedure)); + + proc_frame->main_context = g_object_ref (context); + proc_frame->context_stack = NULL; + proc_frame->procedure = procedure ? g_object_ref (GIMP_PROCEDURE (procedure)) : NULL; + proc_frame->main_loop = NULL; + proc_frame->return_vals = NULL; + proc_frame->progress = progress ? g_object_ref (progress) : NULL; + proc_frame->progress_created = FALSE; + proc_frame->progress_cancel_id = 0; + proc_frame->error_handler = GIMP_PDB_ERROR_HANDLER_INTERNAL; + + if (progress) + gimp_plug_in_progress_attach (progress); +} + +void +gimp_plug_in_proc_frame_dispose (GimpPlugInProcFrame *proc_frame, + GimpPlugIn *plug_in) +{ + g_return_if_fail (proc_frame != NULL); + g_return_if_fail (GIMP_IS_PLUG_IN (plug_in)); + + if (proc_frame->progress) + { + gimp_plug_in_progress_end (plug_in, proc_frame); + + g_clear_object (&proc_frame->progress); + } + + if (proc_frame->context_stack) + { + g_list_free_full (proc_frame->context_stack, + (GDestroyNotify) g_object_unref); + proc_frame->context_stack = NULL; + } + + g_clear_object (&proc_frame->main_context); + g_clear_pointer (&proc_frame->return_vals, gimp_value_array_unref); + g_clear_pointer (&proc_frame->main_loop, g_main_loop_unref); + + if (proc_frame->image_cleanups || proc_frame->item_cleanups) + gimp_plug_in_cleanup (plug_in, proc_frame); + + g_clear_object (&proc_frame->procedure); +} + +GimpPlugInProcFrame * +gimp_plug_in_proc_frame_ref (GimpPlugInProcFrame *proc_frame) +{ + g_return_val_if_fail (proc_frame != NULL, NULL); + + proc_frame->ref_count++; + + return proc_frame; +} + +void +gimp_plug_in_proc_frame_unref (GimpPlugInProcFrame *proc_frame, + GimpPlugIn *plug_in) +{ + g_return_if_fail (proc_frame != NULL); + g_return_if_fail (GIMP_IS_PLUG_IN (plug_in)); + + proc_frame->ref_count--; + + if (proc_frame->ref_count < 1) + { + gimp_plug_in_proc_frame_dispose (proc_frame, plug_in); + g_slice_free (GimpPlugInProcFrame, proc_frame); + } +} + +GimpValueArray * +gimp_plug_in_proc_frame_get_return_values (GimpPlugInProcFrame *proc_frame) +{ + GimpValueArray *return_vals; + + g_return_val_if_fail (proc_frame != NULL, NULL); + + if (proc_frame->return_vals) + { + if (gimp_value_array_length (proc_frame->return_vals) >= + proc_frame->procedure->num_values + 1) + { + return_vals = proc_frame->return_vals; + } + else + { + /* Allocate new return values of the correct size. */ + return_vals = gimp_procedure_get_return_values (proc_frame->procedure, + TRUE, NULL); + + /* Copy all of the arguments we can. */ + memcpy (gimp_value_array_index (return_vals, 0), + gimp_value_array_index (proc_frame->return_vals, 0), + sizeof (GValue) * + gimp_value_array_length (proc_frame->return_vals)); + + /* Free the old arguments. */ + memset (gimp_value_array_index (proc_frame->return_vals, 0), 0, + sizeof (GValue) * + gimp_value_array_length (proc_frame->return_vals)); + gimp_value_array_unref (proc_frame->return_vals); + } + + /* We have consumed any saved values, so clear them. */ + proc_frame->return_vals = NULL; + } + else + { + GimpProcedure *procedure = proc_frame->procedure; + GError *error; + + error = g_error_new (GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_RETURN_VALUE, + _("Procedure '%s' returned no return values"), + gimp_object_get_name (procedure)); + + return_vals = gimp_procedure_get_return_values (procedure, FALSE, + error); + g_error_free (error); + } + + return return_vals; +} diff --git a/app/plug-in/gimppluginprocframe.h b/app/plug-in/gimppluginprocframe.h new file mode 100644 index 0000000..1f21b8e --- /dev/null +++ b/app/plug-in/gimppluginprocframe.h @@ -0,0 +1,67 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimppluginprocframe.h + * + * 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/>. + */ + +#ifndef __GIMP_PLUG_IN_PROC_FRAME_H__ +#define __GIMP_PLUG_IN_PROC_FRAME_H__ + + +struct _GimpPlugInProcFrame +{ + gint ref_count; + + GimpContext *main_context; + GList *context_stack; + + GimpProcedure *procedure; + GMainLoop *main_loop; + + GimpValueArray *return_vals; + + GimpProgress *progress; + gboolean progress_created; + gulong progress_cancel_id; + + GimpPDBErrorHandler error_handler; + + /* lists of things to clean up on dispose */ + GList *image_cleanups; + GList *item_cleanups; +}; + + +GimpPlugInProcFrame * gimp_plug_in_proc_frame_new (GimpContext *context, + GimpProgress *progress, + GimpPlugInProcedure *procedure); +void gimp_plug_in_proc_frame_init (GimpPlugInProcFrame *proc_frame, + GimpContext *context, + GimpProgress *progress, + GimpPlugInProcedure *procedure); + +void gimp_plug_in_proc_frame_dispose (GimpPlugInProcFrame *proc_frame, + GimpPlugIn *plug_in); + +GimpPlugInProcFrame * gimp_plug_in_proc_frame_ref (GimpPlugInProcFrame *proc_frame); +void gimp_plug_in_proc_frame_unref (GimpPlugInProcFrame *proc_frame, + GimpPlugIn *plug_in); + +GimpValueArray * gimp_plug_in_proc_frame_get_return_values + (GimpPlugInProcFrame *proc_frame); + + +#endif /* __GIMP_PLUG_IN_PROC_FRAME_H__ */ diff --git a/app/plug-in/gimppluginshm.c b/app/plug-in/gimppluginshm.c new file mode 100644 index 0000000..8f92905 --- /dev/null +++ b/app/plug-in/gimppluginshm.c @@ -0,0 +1,301 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimppluginhsm.c + * + * 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" + +#include <sys/types.h> + +#include <errno.h> + +#if defined(USE_SYSV_SHM) + +#ifdef HAVE_IPC_H +#include <sys/ipc.h> +#endif + +#ifdef HAVE_SHM_H +#include <sys/shm.h> +#endif + +#elif defined(USE_POSIX_SHM) + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <fcntl.h> +#include <sys/mman.h> + +#endif /* USE_POSIX_SHM */ + +#include <gio/gio.h> +#include <gegl.h> + +#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN) + +#define STRICT +#include <windows.h> +#include <process.h> + +#ifdef G_OS_WIN32 +#include <fcntl.h> +#include <io.h> +#endif + +#define USE_WIN32_SHM 1 + +#endif /* G_OS_WIN32 || G_WITH_CYGWIN */ + +#include "plug-in-types.h" + +#include "core/gimp-utils.h" + +#include "gimppluginshm.h" + +#include "gimp-log.h" + + +#define TILE_MAP_SIZE (GIMP_PLUG_IN_TILE_WIDTH * GIMP_PLUG_IN_TILE_HEIGHT * 32) + +#define ERRMSG_SHM_DISABLE "Disabling shared memory tile transport" + + +struct _GimpPlugInShm +{ + gint shm_ID; + guchar *shm_addr; + +#if defined(USE_WIN32_SHM) + HANDLE shm_handle; +#endif +}; + + +GimpPlugInShm * +gimp_plug_in_shm_new (void) +{ + /* allocate a piece of shared memory for use in transporting tiles + * to plug-ins. if we can't allocate a piece of shared memory then + * we'll fall back on sending the data over the pipe. + */ + + GimpPlugInShm *shm = g_slice_new0 (GimpPlugInShm); + + shm->shm_ID = -1; + +#if defined(USE_SYSV_SHM) + + /* Use SysV shared memory mechanisms for transferring tile data. */ + { + shm->shm_ID = shmget (IPC_PRIVATE, TILE_MAP_SIZE, IPC_CREAT | 0600); + + if (shm->shm_ID != -1) + { + shm->shm_addr = (guchar *) shmat (shm->shm_ID, NULL, 0); + + if (shm->shm_addr == (guchar *) -1) + { + g_printerr ("shmat() failed: %s\n" ERRMSG_SHM_DISABLE, + g_strerror (errno)); + shmctl (shm->shm_ID, IPC_RMID, NULL); + shm->shm_ID = -1; + } + +#ifdef IPC_RMID_DEFERRED_RELEASE + if (shm->shm_addr != (guchar *) -1) + shmctl (shm->shm_ID, IPC_RMID, NULL); +#endif + } + else + { + g_printerr ("shmget() failed: %s\n" ERRMSG_SHM_DISABLE, + g_strerror (errno)); + } + } + +#elif defined(USE_WIN32_SHM) + + /* Use Win32 shared memory mechanisms for transferring tile data. */ + { + gint pid; + gchar fileMapName[MAX_PATH]; + + /* Our shared memory id will be our process ID */ + pid = GetCurrentProcessId (); + + /* From the id, derive the file map name */ + g_snprintf (fileMapName, sizeof (fileMapName), "GIMP%d.SHM", pid); + + /* Create the file mapping into paging space */ + shm->shm_handle = CreateFileMapping (INVALID_HANDLE_VALUE, NULL, + PAGE_READWRITE, 0, + TILE_MAP_SIZE, + fileMapName); + + if (shm->shm_handle) + { + /* Map the shared memory into our address space for use */ + shm->shm_addr = (guchar *) MapViewOfFile (shm->shm_handle, + FILE_MAP_ALL_ACCESS, + 0, 0, TILE_MAP_SIZE); + + /* Verify that we mapped our view */ + if (shm->shm_addr) + { + shm->shm_ID = pid; + } + else + { + g_printerr ("MapViewOfFile error: %d... " ERRMSG_SHM_DISABLE, + GetLastError ()); + } + } + else + { + g_printerr ("CreateFileMapping error: %d... " ERRMSG_SHM_DISABLE, + GetLastError ()); + } + } + +#elif defined(USE_POSIX_SHM) + + /* Use POSIX shared memory mechanisms for transferring tile data. */ + { + gint pid; + gchar shm_handle[32]; + gint shm_fd; + + /* Our shared memory id will be our process ID */ + pid = gimp_get_pid (); + + /* From the id, derive the file map name */ + g_snprintf (shm_handle, sizeof (shm_handle), "/gimp-shm-%d", pid); + + /* Create the file mapping into paging space */ + shm_fd = shm_open (shm_handle, O_RDWR | O_CREAT, 0600); + + if (shm_fd != -1) + { + if (ftruncate (shm_fd, TILE_MAP_SIZE) != -1) + { + /* Map the shared memory into our address space for use */ + shm->shm_addr = (guchar *) mmap (NULL, TILE_MAP_SIZE, + PROT_READ | PROT_WRITE, MAP_SHARED, + shm_fd, 0); + + /* Verify that we mapped our view */ + if (shm->shm_addr != MAP_FAILED) + { + shm->shm_ID = pid; + } + else + { + g_printerr ("mmap() failed: %s\n" ERRMSG_SHM_DISABLE, + g_strerror (errno)); + + shm_unlink (shm_handle); + } + } + else + { + g_printerr ("ftruncate() failed: %s\n" ERRMSG_SHM_DISABLE, + g_strerror (errno)); + + shm_unlink (shm_handle); + } + + close (shm_fd); + } + else + { + g_printerr ("shm_open() failed: %s\n" ERRMSG_SHM_DISABLE, + g_strerror (errno)); + } + } + +#endif + + if (shm->shm_ID == -1) + { + g_slice_free (GimpPlugInShm, shm); + shm = NULL; + } + else + { + GIMP_LOG (SHM, "attached shared memory segment ID = %d", shm->shm_ID); + } + + return shm; +} + +void +gimp_plug_in_shm_free (GimpPlugInShm *shm) +{ + g_return_if_fail (shm != NULL); + + if (shm->shm_ID != -1) + { + +#if defined (USE_SYSV_SHM) + + shmdt (shm->shm_addr); + +#ifndef IPC_RMID_DEFERRED_RELEASE + shmctl (shm->shm_ID, IPC_RMID, NULL); +#endif + +#elif defined(USE_WIN32_SHM) + + if (shm->shm_handle) + CloseHandle (shm->shm_handle); + +#elif defined(USE_POSIX_SHM) + + gchar shm_handle[32]; + + munmap (shm->shm_addr, TILE_MAP_SIZE); + + g_snprintf (shm_handle, sizeof (shm_handle), "/gimp-shm-%d", + shm->shm_ID); + + shm_unlink (shm_handle); + +#endif + + GIMP_LOG (SHM, "detached shared memory segment ID = %d", shm->shm_ID); + } + + g_slice_free (GimpPlugInShm, shm); +} + +gint +gimp_plug_in_shm_get_ID (GimpPlugInShm *shm) +{ + g_return_val_if_fail (shm != NULL, -1); + + return shm->shm_ID; +} + +guchar * +gimp_plug_in_shm_get_addr (GimpPlugInShm *shm) +{ + g_return_val_if_fail (shm != NULL, NULL); + + return shm->shm_addr; +} diff --git a/app/plug-in/gimppluginshm.h b/app/plug-in/gimppluginshm.h new file mode 100644 index 0000000..ee89918 --- /dev/null +++ b/app/plug-in/gimppluginshm.h @@ -0,0 +1,31 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimppluginshm.h + * + * 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/>. + */ + +#ifndef __GIMP_PLUG_IN_SHM_H__ +#define __GIMP_PLUG_IN_SHM_H__ + + +GimpPlugInShm * gimp_plug_in_shm_new (void); +void gimp_plug_in_shm_free (GimpPlugInShm *shm); + +gint gimp_plug_in_shm_get_ID (GimpPlugInShm *shm); +guchar * gimp_plug_in_shm_get_addr (GimpPlugInShm *shm); + + +#endif /* __GIMP_PLUG_IN_SHM_H__ */ diff --git a/app/plug-in/gimptemporaryprocedure.c b/app/plug-in/gimptemporaryprocedure.c new file mode 100644 index 0000000..5b03d05 --- /dev/null +++ b/app/plug-in/gimptemporaryprocedure.c @@ -0,0 +1,156 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimptemporaryprocedure.c + * + * 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" + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpbase/gimpbase.h" + +#include "plug-in-types.h" + +#include "core/gimp.h" + +#include "gimpplugin.h" +#define __YES_I_NEED_GIMP_PLUG_IN_MANAGER_CALL__ +#include "gimppluginmanager-call.h" +#include "gimptemporaryprocedure.h" + +#include "gimp-intl.h" + + +static void gimp_temporary_procedure_finalize (GObject *object); + +static GimpValueArray * gimp_temporary_procedure_execute (GimpProcedure *procedure, + Gimp *gimp, + GimpContext *context, + GimpProgress *progress, + GimpValueArray *args, + GError **error); +static void gimp_temporary_procedure_execute_async (GimpProcedure *procedure, + Gimp *gimp, + GimpContext *context, + GimpProgress *progress, + GimpValueArray *args, + GimpObject *display); + +static GFile * gimp_temporary_procedure_get_file (GimpPlugInProcedure *procedure); + + +G_DEFINE_TYPE (GimpTemporaryProcedure, gimp_temporary_procedure, + GIMP_TYPE_PLUG_IN_PROCEDURE) + +#define parent_class gimp_temporary_procedure_parent_class + + +static void +gimp_temporary_procedure_class_init (GimpTemporaryProcedureClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpProcedureClass *proc_class = GIMP_PROCEDURE_CLASS (klass); + GimpPlugInProcedureClass *plug_class = GIMP_PLUG_IN_PROCEDURE_CLASS (klass); + + object_class->finalize = gimp_temporary_procedure_finalize; + + proc_class->execute = gimp_temporary_procedure_execute; + proc_class->execute_async = gimp_temporary_procedure_execute_async; + + plug_class->get_file = gimp_temporary_procedure_get_file; +} + +static void +gimp_temporary_procedure_init (GimpTemporaryProcedure *proc) +{ + GIMP_PROCEDURE (proc)->proc_type = GIMP_TEMPORARY; +} + +static void +gimp_temporary_procedure_finalize (GObject *object) +{ + /* GimpTemporaryProcedure *proc = GIMP_TEMPORARY_PROCEDURE (object); */ + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static GimpValueArray * +gimp_temporary_procedure_execute (GimpProcedure *procedure, + Gimp *gimp, + GimpContext *context, + GimpProgress *progress, + GimpValueArray *args, + GError **error) +{ + return gimp_plug_in_manager_call_run_temp (gimp->plug_in_manager, + context, progress, + GIMP_TEMPORARY_PROCEDURE (procedure), + args); +} + +static void +gimp_temporary_procedure_execute_async (GimpProcedure *procedure, + Gimp *gimp, + GimpContext *context, + GimpProgress *progress, + GimpValueArray *args, + GimpObject *display) +{ + GimpTemporaryProcedure *temp_procedure = GIMP_TEMPORARY_PROCEDURE (procedure); + GimpValueArray *return_vals; + + return_vals = gimp_plug_in_manager_call_run_temp (gimp->plug_in_manager, + context, progress, + temp_procedure, + args); + + if (return_vals) + { + GimpPlugInProcedure *proc = GIMP_PLUG_IN_PROCEDURE (procedure); + + gimp_plug_in_procedure_handle_return_values (proc, + gimp, progress, + return_vals); + gimp_value_array_unref (return_vals); + } +} + +static GFile * +gimp_temporary_procedure_get_file (GimpPlugInProcedure *procedure) +{ + return GIMP_TEMPORARY_PROCEDURE (procedure)->plug_in->file; +} + + +/* public functions */ + +GimpProcedure * +gimp_temporary_procedure_new (GimpPlugIn *plug_in) +{ + GimpTemporaryProcedure *proc; + + g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), NULL); + + proc = g_object_new (GIMP_TYPE_TEMPORARY_PROCEDURE, NULL); + + proc->plug_in = plug_in; + + GIMP_PLUG_IN_PROCEDURE (proc)->file = g_file_new_for_path ("none"); + + return GIMP_PROCEDURE (proc); +} diff --git a/app/plug-in/gimptemporaryprocedure.h b/app/plug-in/gimptemporaryprocedure.h new file mode 100644 index 0000000..3df53c8 --- /dev/null +++ b/app/plug-in/gimptemporaryprocedure.h @@ -0,0 +1,55 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimptemporaryprocedure.h + * + * 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/>. + */ + +#ifndef __GIMP_TEMPORARY_PROCEDURE_H__ +#define __GIMP_TEMPORARY_PROCEDURE_H__ + + +#include "gimppluginprocedure.h" + + +#define GIMP_TYPE_TEMPORARY_PROCEDURE (gimp_temporary_procedure_get_type ()) +#define GIMP_TEMPORARY_PROCEDURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_TEMPORARY_PROCEDURE, GimpTemporaryProcedure)) +#define GIMP_TEMPORARY_PROCEDURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_TEMPORARY_PROCEDURE, GimpTemporaryProcedureClass)) +#define GIMP_IS_TEMPORARY_PROCEDURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_TEMPORARY_PROCEDURE)) +#define GIMP_IS_TEMPORARY_PROCEDURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_TEMPORARY_PROCEDURE)) +#define GIMP_TEMPORARY_PROCEDURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_TEMPORARY_PROCEDURE, GimpTemporaryProcedureClass)) + + +typedef struct _GimpTemporaryProcedureClass GimpTemporaryProcedureClass; + +struct _GimpTemporaryProcedure +{ + GimpPlugInProcedure parent_instance; + + GimpPlugIn *plug_in; +}; + +struct _GimpTemporaryProcedureClass +{ + GimpPlugInProcedureClass parent_class; +}; + + +GType gimp_temporary_procedure_get_type (void) G_GNUC_CONST; + +GimpProcedure * gimp_temporary_procedure_new (GimpPlugIn *plug_in); + + +#endif /* __GIMP_TEMPORARY_PROCEDURE_H__ */ diff --git a/app/plug-in/plug-in-enums.c b/app/plug-in/plug-in-enums.c new file mode 100644 index 0000000..4f062bb --- /dev/null +++ b/app/plug-in/plug-in-enums.c @@ -0,0 +1,118 @@ + +/* Generated data (by gimp-mkenums) */ + +#include "config.h" +#include <gio/gio.h> +#include "libgimpbase/gimpbase.h" +#include "plug-in-enums.h" +#include "gimp-intl.h" + +/* enumerations from "plug-in-enums.h" */ +GType +gimp_plug_in_image_type_get_type (void) +{ + static const GFlagsValue values[] = + { + { GIMP_PLUG_IN_RGB_IMAGE, "GIMP_PLUG_IN_RGB_IMAGE", "rgb-image" }, + { GIMP_PLUG_IN_GRAY_IMAGE, "GIMP_PLUG_IN_GRAY_IMAGE", "gray-image" }, + { GIMP_PLUG_IN_INDEXED_IMAGE, "GIMP_PLUG_IN_INDEXED_IMAGE", "indexed-image" }, + { GIMP_PLUG_IN_RGBA_IMAGE, "GIMP_PLUG_IN_RGBA_IMAGE", "rgba-image" }, + { GIMP_PLUG_IN_GRAYA_IMAGE, "GIMP_PLUG_IN_GRAYA_IMAGE", "graya-image" }, + { GIMP_PLUG_IN_INDEXEDA_IMAGE, "GIMP_PLUG_IN_INDEXEDA_IMAGE", "indexeda-image" }, + { 0, NULL, NULL } + }; + + static const GimpFlagsDesc descs[] = + { + { GIMP_PLUG_IN_RGB_IMAGE, "GIMP_PLUG_IN_RGB_IMAGE", NULL }, + { GIMP_PLUG_IN_GRAY_IMAGE, "GIMP_PLUG_IN_GRAY_IMAGE", NULL }, + { GIMP_PLUG_IN_INDEXED_IMAGE, "GIMP_PLUG_IN_INDEXED_IMAGE", NULL }, + { GIMP_PLUG_IN_RGBA_IMAGE, "GIMP_PLUG_IN_RGBA_IMAGE", NULL }, + { GIMP_PLUG_IN_GRAYA_IMAGE, "GIMP_PLUG_IN_GRAYA_IMAGE", NULL }, + { GIMP_PLUG_IN_INDEXEDA_IMAGE, "GIMP_PLUG_IN_INDEXEDA_IMAGE", NULL }, + { 0, NULL, NULL } + }; + + static GType type = 0; + + if (G_UNLIKELY (! type)) + { + type = g_flags_register_static ("GimpPlugInImageType", values); + gimp_type_set_translation_context (type, "plug-in-image-type"); + gimp_flags_set_value_descriptions (type, descs); + } + + return type; +} + +GType +gimp_plug_in_call_mode_get_type (void) +{ + static const GEnumValue values[] = + { + { GIMP_PLUG_IN_CALL_NONE, "GIMP_PLUG_IN_CALL_NONE", "none" }, + { GIMP_PLUG_IN_CALL_RUN, "GIMP_PLUG_IN_CALL_RUN", "run" }, + { GIMP_PLUG_IN_CALL_QUERY, "GIMP_PLUG_IN_CALL_QUERY", "query" }, + { GIMP_PLUG_IN_CALL_INIT, "GIMP_PLUG_IN_CALL_INIT", "init" }, + { 0, NULL, NULL } + }; + + static const GimpEnumDesc descs[] = + { + { GIMP_PLUG_IN_CALL_NONE, "GIMP_PLUG_IN_CALL_NONE", NULL }, + { GIMP_PLUG_IN_CALL_RUN, "GIMP_PLUG_IN_CALL_RUN", NULL }, + { GIMP_PLUG_IN_CALL_QUERY, "GIMP_PLUG_IN_CALL_QUERY", NULL }, + { GIMP_PLUG_IN_CALL_INIT, "GIMP_PLUG_IN_CALL_INIT", NULL }, + { 0, NULL, NULL } + }; + + static GType type = 0; + + if (G_UNLIKELY (! type)) + { + type = g_enum_register_static ("GimpPlugInCallMode", values); + gimp_type_set_translation_context (type, "plug-in-call-mode"); + gimp_enum_set_value_descriptions (type, descs); + } + + return type; +} + +GType +gimp_file_procedure_group_get_type (void) +{ + static const GEnumValue values[] = + { + { GIMP_FILE_PROCEDURE_GROUP_NONE, "GIMP_FILE_PROCEDURE_GROUP_NONE", "none" }, + { GIMP_FILE_PROCEDURE_GROUP_ANY, "GIMP_FILE_PROCEDURE_GROUP_ANY", "any" }, + { GIMP_FILE_PROCEDURE_GROUP_OPEN, "GIMP_FILE_PROCEDURE_GROUP_OPEN", "open" }, + { GIMP_FILE_PROCEDURE_GROUP_SAVE, "GIMP_FILE_PROCEDURE_GROUP_SAVE", "save" }, + { GIMP_FILE_PROCEDURE_GROUP_EXPORT, "GIMP_FILE_PROCEDURE_GROUP_EXPORT", "export" }, + { 0, NULL, NULL } + }; + + static const GimpEnumDesc descs[] = + { + { GIMP_FILE_PROCEDURE_GROUP_NONE, "GIMP_FILE_PROCEDURE_GROUP_NONE", NULL }, + { GIMP_FILE_PROCEDURE_GROUP_ANY, "GIMP_FILE_PROCEDURE_GROUP_ANY", NULL }, + { GIMP_FILE_PROCEDURE_GROUP_OPEN, "GIMP_FILE_PROCEDURE_GROUP_OPEN", NULL }, + { GIMP_FILE_PROCEDURE_GROUP_SAVE, "GIMP_FILE_PROCEDURE_GROUP_SAVE", NULL }, + { GIMP_FILE_PROCEDURE_GROUP_EXPORT, "GIMP_FILE_PROCEDURE_GROUP_EXPORT", NULL }, + { 0, NULL, NULL } + }; + + static GType type = 0; + + if (G_UNLIKELY (! type)) + { + type = g_enum_register_static ("GimpFileProcedureGroup", values); + gimp_type_set_translation_context (type, "file-procedure-group"); + gimp_enum_set_value_descriptions (type, descs); + } + + return type; +} + + +/* Generated data ends here */ + diff --git a/app/plug-in/plug-in-enums.h b/app/plug-in/plug-in-enums.h new file mode 100644 index 0000000..c5b6775 --- /dev/null +++ b/app/plug-in/plug-in-enums.h @@ -0,0 +1,64 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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/>. + */ + +#ifndef __PLUG_IN_ENUMS_H__ +#define __PLUG_IN_ENUMS_H__ + + +#define GIMP_TYPE_PLUG_IN_IMAGE_TYPE (gimp_plug_in_image_type_get_type ()) + +GType gimp_plug_in_image_type_get_type (void) G_GNUC_CONST; + +typedef enum +{ + GIMP_PLUG_IN_RGB_IMAGE = 1 << 0, + GIMP_PLUG_IN_GRAY_IMAGE = 1 << 1, + GIMP_PLUG_IN_INDEXED_IMAGE = 1 << 2, + GIMP_PLUG_IN_RGBA_IMAGE = 1 << 3, + GIMP_PLUG_IN_GRAYA_IMAGE = 1 << 4, + GIMP_PLUG_IN_INDEXEDA_IMAGE = 1 << 5 +} GimpPlugInImageType; + + +#define GIMP_TYPE_PLUG_CALL_MODE (gimp_plug_in_call_mode_get_type ()) + +GType gimp_plug_in_call_mode_get_type (void) G_GNUC_CONST; + +typedef enum +{ + GIMP_PLUG_IN_CALL_NONE, + GIMP_PLUG_IN_CALL_RUN, + GIMP_PLUG_IN_CALL_QUERY, + GIMP_PLUG_IN_CALL_INIT +} GimpPlugInCallMode; + + +#define GIMP_TYPE_FILE_PROCEDURE_GROUP (gimp_file_procedure_group_get_type ()) + +GType gimp_file_procedure_group_get_type (void) G_GNUC_CONST; + +typedef enum +{ + GIMP_FILE_PROCEDURE_GROUP_NONE, + GIMP_FILE_PROCEDURE_GROUP_ANY, + GIMP_FILE_PROCEDURE_GROUP_OPEN, + GIMP_FILE_PROCEDURE_GROUP_SAVE, + GIMP_FILE_PROCEDURE_GROUP_EXPORT +} GimpFileProcedureGroup; + + +#endif /* __PLUG_IN_ENUMS_H__ */ diff --git a/app/plug-in/plug-in-menu-path.c b/app/plug-in/plug-in-menu-path.c new file mode 100644 index 0000000..fa6fa16 --- /dev/null +++ b/app/plug-in/plug-in-menu-path.c @@ -0,0 +1,141 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * plug-in-menu-path.c + * + * 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" + +#include <string.h> + +#include <gio/gio.h> + +#include "libgimpbase/gimpbase.h" + +#include "plug-in-types.h" + +#include "plug-in-menu-path.h" + + +typedef struct _MenuPathMapping MenuPathMapping; + +struct _MenuPathMapping +{ + const gchar *orig_path; + const gchar *label; + const gchar *mapped_path; +}; + + +static const MenuPathMapping menu_path_mappings[] = +{ + { "<Toolbox>/Xtns/Languages", NULL, "<Image>/Filters/Languages" }, + { "<Toolbox>/Xtns/Extensions", NULL, "<Image>/Filters/Extensions" }, + + { "<Toolbox>/Xtns/Buttons", NULL, "<Image>/File/Create/Buttons" }, + { "<Toolbox>/Xtns/Logos", NULL, "<Image>/File/Create/Logos" }, + { "<Toolbox>/Xtns/Misc", NULL, "<Image>/File/Create/Misc" }, + { "<Toolbox>/Xtns/Patterns", NULL, "<Image>/File/Create/Patterns" }, + { "<Toolbox>/Xtns/Web Page Themes", NULL, "<Image>/File/Create/Web Page Themes" }, + + { "<Toolbox>/Xtns", "Buttons", "<Image>/File/Create" }, + { "<Toolbox>/Xtns", "Logos", "<Image>/File/Create" }, + { "<Toolbox>/Xtns", "Misc", "<Image>/File/Create" }, + { "<Toolbox>/Xtns", "Patterns", "<Image>/File/Create" }, + { "<Toolbox>/Xtns", "Web Page Themes", "<Image>/File/Create" }, + + { "<Toolbox>/Xtns", NULL, "<Image>/Filters/Extensions" }, + { "<Toolbox>/Help", NULL, "<Image>/Help" }, + + { "<Toolbox>/File/Acquire", NULL, "<Image>/File/Create/Acquire" }, + { "<Toolbox>", NULL, "<Image>" }, + { "<Image>/File/Acquire", NULL, "<Image>/File/Create/Acquire" }, + { "<Image>/File/New", NULL, "<Image>/File/Create" }, + { "<Image>/Image/Mode/Color Profile", NULL, "<Image>/Image/Color Management" }, + { NULL, NULL, NULL } +}; + + +gchar * +plug_in_menu_path_map (const gchar *menu_path, + const gchar *menu_label) +{ + const MenuPathMapping *mapping; + gchar *stripped_label = NULL; + + g_return_val_if_fail (menu_path != NULL, NULL); + + if (menu_label) + stripped_label = gimp_strip_uline (menu_label); + + for (mapping = menu_path_mappings; mapping->orig_path; mapping++) + { + if (g_str_has_prefix (menu_path, mapping->orig_path)) + { + gint orig_len = strlen (mapping->orig_path); + gchar *mapped_path; + + /* if the mapping has a label, only map if the passed label + * is identical and the paths' lengths match exactly. + */ + if (mapping->label && + (! stripped_label || + strlen (menu_path) != orig_len || + strcmp (mapping->label, stripped_label))) + { + continue; + } + + if (strlen (menu_path) > orig_len) + mapped_path = g_strconcat (mapping->mapped_path, + menu_path + orig_len, + NULL); + else + mapped_path = g_strdup (mapping->mapped_path); + +#if GIMP_UNSTABLE + { + gchar *orig; + gchar *mapped; + + if (menu_label) + { + orig = g_strdup_printf ("%s/%s", menu_path, stripped_label); + mapped = g_strdup_printf ("%s/%s", mapped_path, stripped_label); + } + else + { + orig = g_strdup (menu_path); + mapped = g_strdup (mapped_path); + } + + g_printerr (" mapped '%s' to '%s'\n", orig, mapped); + + g_free (orig); + g_free (mapped); + } +#endif + + g_free (stripped_label); + + return mapped_path; + } + } + + g_free (stripped_label); + + return g_strdup (menu_path); +} diff --git a/app/plug-in/plug-in-menu-path.h b/app/plug-in/plug-in-menu-path.h new file mode 100644 index 0000000..b222c06 --- /dev/null +++ b/app/plug-in/plug-in-menu-path.h @@ -0,0 +1,28 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * plug-in-menu-path.h + * + * 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/>. + */ + +#ifndef __PLUG_IN_MENU_PATH_H__ +#define __PLUG_IN_MENU_PATH_H__ + + +gchar * plug_in_menu_path_map (const gchar *menu_path, + const gchar *menu_label); + + +#endif /* __PLUG_IN_MENU_PATH_H__ */ diff --git a/app/plug-in/plug-in-params.c b/app/plug-in/plug-in-params.c new file mode 100644 index 0000000..3f781b2 --- /dev/null +++ b/app/plug-in/plug-in-params.c @@ -0,0 +1,442 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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" + +#include <cairo.h> +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpbase/gimpbase.h" +#include "libgimpbase/gimpprotocol.h" +#include "libgimpcolor/gimpcolor.h" + +#include "plug-in-types.h" + +#include "core/gimpparamspecs.h" + +#include "pdb/gimp-pdb-compat.h" + +#include "plug-in-params.h" + + +GimpValueArray * +plug_in_params_to_args (GParamSpec **pspecs, + gint n_pspecs, + GPParam *params, + gint n_params, + gboolean return_values, + gboolean full_copy) +{ + GimpValueArray *args; + gint i; + + g_return_val_if_fail ((pspecs != NULL && n_pspecs > 0) || + (pspecs == NULL && n_pspecs == 0), NULL); + g_return_val_if_fail ((params != NULL && n_params > 0) || + (params == NULL && n_params == 0), NULL); + + args = gimp_value_array_new (n_params); + + for (i = 0; i < n_params; i++) + { + GValue value = G_VALUE_INIT; + GType type; + gint count; + + /* first get the fallback compat GType that matches the pdb type */ + type = gimp_pdb_compat_arg_type_to_gtype (params[i].type); + + /* then try to try to be more specific by looking at the param + * spec (return values have one additional value (the status), + * skip that, it's not in the array of param specs) + */ + if (i > 0 || ! return_values) + { + gint pspec_index = i; + + if (return_values) + pspec_index--; + + /* are there param specs left? */ + if (pspec_index < n_pspecs) + { + GType pspec_gtype; + GimpPDBArgType pspec_arg_type; + + pspec_gtype = G_PARAM_SPEC_VALUE_TYPE (pspecs[pspec_index]); + pspec_arg_type = gimp_pdb_compat_arg_type_from_gtype (pspec_gtype); + + /* if the param spec's GType, mapped to a pdb type, matches + * the passed pdb type, use the param spec's GType + */ + if (pspec_arg_type == params[i].type) + type = pspec_gtype; + } + } + + g_value_init (&value, type); + + switch (gimp_pdb_compat_arg_type_from_gtype (type)) + { + case GIMP_PDB_INT32: + if (G_VALUE_HOLDS_INT (&value)) + g_value_set_int (&value, params[i].data.d_int32); + else if (G_VALUE_HOLDS_UINT (&value)) + g_value_set_uint (&value, params[i].data.d_int32); + else if (G_VALUE_HOLDS_ENUM (&value)) + g_value_set_enum (&value, params[i].data.d_int32); + else if (G_VALUE_HOLDS_BOOLEAN (&value)) + g_value_set_boolean (&value, params[i].data.d_int32 ? TRUE : FALSE); + else + { + g_printerr ("%s: unhandled GIMP_PDB_INT32 type: %s\n", + G_STRFUNC, g_type_name (G_VALUE_TYPE (&value))); + g_return_val_if_reached (args); + } + break; + + case GIMP_PDB_INT16: + g_value_set_int (&value, params[i].data.d_int16); + break; + + case GIMP_PDB_INT8: + g_value_set_uint (&value, params[i].data.d_int8); + break; + + case GIMP_PDB_FLOAT: + g_value_set_double (&value, params[i].data.d_float); + break; + + case GIMP_PDB_STRING: + if (full_copy) + g_value_set_string (&value, params[i].data.d_string); + else + g_value_set_static_string (&value, params[i].data.d_string); + break; + + case GIMP_PDB_INT32ARRAY: + count = g_value_get_int (gimp_value_array_index (args, i - 1)); + if (full_copy) + gimp_value_set_int32array (&value, + params[i].data.d_int32array, + count); + else + gimp_value_set_static_int32array (&value, + params[i].data.d_int32array, + count); + break; + + case GIMP_PDB_INT16ARRAY: + count = g_value_get_int (gimp_value_array_index (args, i - 1)); + if (full_copy) + gimp_value_set_int16array (&value, + params[i].data.d_int16array, + count); + else + gimp_value_set_static_int16array (&value, + params[i].data.d_int16array, + count); + break; + + case GIMP_PDB_INT8ARRAY: + count = g_value_get_int (gimp_value_array_index (args, i - 1)); + if (full_copy) + gimp_value_set_int8array (&value, + params[i].data.d_int8array, + count); + else + gimp_value_set_static_int8array (&value, + params[i].data.d_int8array, + count); + break; + + case GIMP_PDB_FLOATARRAY: + count = g_value_get_int (gimp_value_array_index (args, i - 1)); + if (full_copy) + gimp_value_set_floatarray (&value, + params[i].data.d_floatarray, + count); + else + gimp_value_set_static_floatarray (&value, + params[i].data.d_floatarray, + count); + break; + + case GIMP_PDB_STRINGARRAY: + count = g_value_get_int (gimp_value_array_index (args, i - 1)); + if (full_copy) + gimp_value_set_stringarray (&value, + (const gchar **) params[i].data.d_stringarray, + count); + else + gimp_value_set_static_stringarray (&value, + (const gchar **) params[i].data.d_stringarray, + count); + break; + + case GIMP_PDB_COLOR: + gimp_value_set_rgb (&value, ¶ms[i].data.d_color); + break; + + case GIMP_PDB_ITEM: + g_value_set_int (&value, params[i].data.d_item); + break; + + case GIMP_PDB_DISPLAY: + g_value_set_int (&value, params[i].data.d_display); + break; + + case GIMP_PDB_IMAGE: + g_value_set_int (&value, params[i].data.d_image); + break; + + case GIMP_PDB_LAYER: + g_value_set_int (&value, params[i].data.d_layer); + break; + + case GIMP_PDB_CHANNEL: + g_value_set_int (&value, params[i].data.d_channel); + break; + + case GIMP_PDB_DRAWABLE: + g_value_set_int (&value, params[i].data.d_drawable); + break; + + case GIMP_PDB_SELECTION: + g_value_set_int (&value, params[i].data.d_selection); + break; + + case GIMP_PDB_COLORARRAY: + count = g_value_get_int (gimp_value_array_index (args, i - 1)); + if (full_copy) + gimp_value_set_colorarray (&value, + params[i].data.d_colorarray, + count); + else + gimp_value_set_static_colorarray (&value, + params[i].data.d_colorarray, + count); + break; + + case GIMP_PDB_VECTORS: + g_value_set_int (&value, params[i].data.d_vectors); + break; + + case GIMP_PDB_PARASITE: + if (full_copy) + g_value_set_boxed (&value, ¶ms[i].data.d_parasite); + else + g_value_set_static_boxed (&value, ¶ms[i].data.d_parasite); + break; + + case GIMP_PDB_STATUS: + g_value_set_enum (&value, params[i].data.d_status); + break; + + case GIMP_PDB_END: + break; + } + + gimp_value_array_append (args, &value); + g_value_unset (&value); + } + + return args; +} + +GPParam * +plug_in_args_to_params (GimpValueArray *args, + gboolean full_copy) +{ + GPParam *params; + gint length; + gint i; + + g_return_val_if_fail (args != NULL, NULL); + + params = g_new0 (GPParam, gimp_value_array_length (args)); + + length = gimp_value_array_length (args); + + for (i = 0; i < length; i++) + { + GValue *value = gimp_value_array_index (args, i); + + params[i].type = + gimp_pdb_compat_arg_type_from_gtype (G_VALUE_TYPE (value)); + + switch (params[i].type) + { + case GIMP_PDB_INT32: + if (G_VALUE_HOLDS_INT (value)) + params[i].data.d_int32 = g_value_get_int (value); + else if (G_VALUE_HOLDS_UINT (value)) + params[i].data.d_int32 = g_value_get_uint (value); + else if (G_VALUE_HOLDS_ENUM (value)) + params[i].data.d_int32 = g_value_get_enum (value); + else if (G_VALUE_HOLDS_BOOLEAN (value)) + params[i].data.d_int32 = g_value_get_boolean (value); + else + { + g_printerr ("%s: unhandled GIMP_PDB_INT32 type: %s\n", + G_STRFUNC, g_type_name (G_VALUE_TYPE (value))); + g_return_val_if_reached (params); + } + break; + + case GIMP_PDB_INT16: + params[i].data.d_int16 = g_value_get_int (value); + break; + + case GIMP_PDB_INT8: + params[i].data.d_int8 = g_value_get_uint (value); + break; + + case GIMP_PDB_FLOAT: + params[i].data.d_float = g_value_get_double (value); + break; + + case GIMP_PDB_STRING: + if (full_copy) + params[i].data.d_string = g_value_dup_string (value); + else + params[i].data.d_string = (gchar *) g_value_get_string (value); + break; + + case GIMP_PDB_INT32ARRAY: + if (full_copy) + params[i].data.d_int32array = gimp_value_dup_int32array (value); + else + params[i].data.d_int32array = (gint32 *) gimp_value_get_int32array (value); + break; + + case GIMP_PDB_INT16ARRAY: + if (full_copy) + params[i].data.d_int16array = gimp_value_dup_int16array (value); + else + params[i].data.d_int16array = (gint16 *) gimp_value_get_int16array (value); + break; + + case GIMP_PDB_INT8ARRAY: + if (full_copy) + params[i].data.d_int8array = gimp_value_dup_int8array (value); + else + params[i].data.d_int8array = (guint8 *) gimp_value_get_int8array (value); + break; + + case GIMP_PDB_FLOATARRAY: + if (full_copy) + params[i].data.d_floatarray = gimp_value_dup_floatarray (value); + else + params[i].data.d_floatarray = (gdouble *) gimp_value_get_floatarray (value); + break; + + case GIMP_PDB_STRINGARRAY: + if (full_copy) + params[i].data.d_stringarray = gimp_value_dup_stringarray (value); + else + params[i].data.d_stringarray = (gchar **) gimp_value_get_stringarray (value); + break; + + case GIMP_PDB_COLOR: + gimp_value_get_rgb (value, ¶ms[i].data.d_color); + break; + + case GIMP_PDB_ITEM: + params[i].data.d_item = g_value_get_int (value); + break; + + case GIMP_PDB_DISPLAY: + params[i].data.d_display = g_value_get_int (value); + break; + + case GIMP_PDB_IMAGE: + params[i].data.d_image = g_value_get_int (value); + break; + + case GIMP_PDB_LAYER: + params[i].data.d_layer = g_value_get_int (value); + break; + + case GIMP_PDB_CHANNEL: + params[i].data.d_channel = g_value_get_int (value); + break; + + case GIMP_PDB_DRAWABLE: + params[i].data.d_drawable = g_value_get_int (value); + break; + + case GIMP_PDB_SELECTION: + params[i].data.d_selection = g_value_get_int (value); + break; + + case GIMP_PDB_COLORARRAY: + if (full_copy) + params[i].data.d_colorarray = gimp_value_dup_colorarray (value); + else + params[i].data.d_colorarray = (GimpRGB *) gimp_value_get_colorarray (value); + break; + + case GIMP_PDB_VECTORS: + params[i].data.d_vectors = g_value_get_int (value); + break; + + case GIMP_PDB_PARASITE: + { + GimpParasite *parasite = (full_copy ? + g_value_dup_boxed (value) : + g_value_get_boxed (value)); + + if (parasite) + { + params[i].data.d_parasite.name = parasite->name; + params[i].data.d_parasite.flags = parasite->flags; + params[i].data.d_parasite.size = parasite->size; + params[i].data.d_parasite.data = parasite->data; + + if (full_copy) + { + parasite->name = NULL; + parasite->flags = 0; + parasite->size = 0; + parasite->data = NULL; + + gimp_parasite_free (parasite); + } + } + else + { + params[i].data.d_parasite.name = NULL; + params[i].data.d_parasite.flags = 0; + params[i].data.d_parasite.size = 0; + params[i].data.d_parasite.data = NULL; + } + } + break; + + case GIMP_PDB_STATUS: + params[i].data.d_status = g_value_get_enum (value); + break; + + case GIMP_PDB_END: + break; + } + } + + return params; +} diff --git a/app/plug-in/plug-in-params.h b/app/plug-in/plug-in-params.h new file mode 100644 index 0000000..0b8df27 --- /dev/null +++ b/app/plug-in/plug-in-params.h @@ -0,0 +1,32 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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/>. + */ + +#ifndef __PLUG_IN_PARAMS_H__ +#define __PLUG_IN_PARAMS_H__ + + +GimpValueArray * plug_in_params_to_args (GParamSpec **pspecs, + gint n_pspecs, + GPParam *params, + gint n_params, + gboolean return_values, + gboolean full_copy); +GPParam * plug_in_args_to_params (GimpValueArray *args, + gboolean full_copy); + + +#endif /* __PLUG_IN_PARAMS_H__ */ diff --git a/app/plug-in/plug-in-rc.c b/app/plug-in/plug-in-rc.c new file mode 100644 index 0000000..42cfe3d --- /dev/null +++ b/app/plug-in/plug-in-rc.c @@ -0,0 +1,1137 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * plug-in-rc.c + * Copyright (C) 2001 Sven Neumann <sven@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" + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpbase/gimpbase.h" +#include "libgimpbase/gimpprotocol.h" +#include "libgimpconfig/gimpconfig.h" + +#include "plug-in-types.h" + +#include "core/gimp.h" + +#include "pdb/gimp-pdb-compat.h" + +#include "gimpplugindef.h" +#include "gimppluginprocedure.h" +#include "plug-in-rc.h" + +#include "gimp-intl.h" + + +#define PLUG_IN_RC_FILE_VERSION 5 + + +/* + * All deserialize functions return G_TOKEN_LEFT_PAREN on success, + * or the GTokenType they would have expected but didn't get, + * or G_TOKEN_ERROR if the function already set an error itself. + */ + +static GTokenType plug_in_def_deserialize (Gimp *gimp, + GScanner *scanner, + GSList **plug_in_defs); +static GTokenType plug_in_procedure_deserialize (GScanner *scanner, + Gimp *gimp, + GFile *file, + GimpPlugInProcedure **proc); +static GTokenType plug_in_menu_path_deserialize (GScanner *scanner, + GimpPlugInProcedure *proc); +static GTokenType plug_in_icon_deserialize (GScanner *scanner, + GimpPlugInProcedure *proc); +static GTokenType plug_in_file_proc_deserialize (GScanner *scanner, + GimpPlugInProcedure *proc); +static GTokenType plug_in_proc_arg_deserialize (GScanner *scanner, + Gimp *gimp, + GimpProcedure *procedure, + gboolean return_value); +static GTokenType plug_in_locale_def_deserialize (GScanner *scanner, + GimpPlugInDef *plug_in_def); +static GTokenType plug_in_help_def_deserialize (GScanner *scanner, + GimpPlugInDef *plug_in_def); +static GTokenType plug_in_has_init_deserialize (GScanner *scanner, + GimpPlugInDef *plug_in_def); + + +enum +{ + PROTOCOL_VERSION = 1, + FILE_VERSION, + PLUG_IN_DEF, + PROC_DEF, + LOCALE_DEF, + HELP_DEF, + HAS_INIT, + PROC_ARG, + MENU_PATH, + ICON, + LOAD_PROC, + SAVE_PROC, + EXTENSIONS, + PREFIXES, + MAGICS, + PRIORITY, + MIME_TYPES, + HANDLES_URI, + HANDLES_RAW, + THUMB_LOADER +}; + + +GSList * +plug_in_rc_parse (Gimp *gimp, + GFile *file, + GError **error) +{ + GScanner *scanner; + GEnumClass *enum_class; + GSList *plug_in_defs = NULL; + gint protocol_version = GIMP_PROTOCOL_VERSION; + gint file_version = PLUG_IN_RC_FILE_VERSION; + GTokenType token; + + g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); + g_return_val_if_fail (G_IS_FILE (file), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + scanner = gimp_scanner_new_gfile (file, error); + + if (! scanner) + return NULL; + + enum_class = g_type_class_ref (GIMP_TYPE_ICON_TYPE); + + g_scanner_scope_add_symbol (scanner, 0, + "protocol-version", + GINT_TO_POINTER (PROTOCOL_VERSION)); + g_scanner_scope_add_symbol (scanner, 0, + "file-version", + GINT_TO_POINTER (FILE_VERSION)); + g_scanner_scope_add_symbol (scanner, 0, + "plug-in-def", GINT_TO_POINTER (PLUG_IN_DEF)); + + g_scanner_scope_add_symbol (scanner, PLUG_IN_DEF, + "proc-def", GINT_TO_POINTER (PROC_DEF)); + g_scanner_scope_add_symbol (scanner, PLUG_IN_DEF, + "locale-def", GINT_TO_POINTER (LOCALE_DEF)); + g_scanner_scope_add_symbol (scanner, PLUG_IN_DEF, + "help-def", GINT_TO_POINTER (HELP_DEF)); + g_scanner_scope_add_symbol (scanner, PLUG_IN_DEF, + "has-init", GINT_TO_POINTER (HAS_INIT)); + g_scanner_scope_add_symbol (scanner, PLUG_IN_DEF, + "proc-arg", GINT_TO_POINTER (PROC_ARG)); + g_scanner_scope_add_symbol (scanner, PLUG_IN_DEF, + "menu-path", GINT_TO_POINTER (MENU_PATH)); + g_scanner_scope_add_symbol (scanner, PLUG_IN_DEF, + "icon", GINT_TO_POINTER (ICON)); + g_scanner_scope_add_symbol (scanner, PLUG_IN_DEF, + "load-proc", GINT_TO_POINTER (LOAD_PROC)); + g_scanner_scope_add_symbol (scanner, PLUG_IN_DEF, + "save-proc", GINT_TO_POINTER (SAVE_PROC)); + + g_scanner_scope_add_symbol (scanner, LOAD_PROC, + "extensions", GINT_TO_POINTER (EXTENSIONS)); + g_scanner_scope_add_symbol (scanner, LOAD_PROC, + "prefixes", GINT_TO_POINTER (PREFIXES)); + g_scanner_scope_add_symbol (scanner, LOAD_PROC, + "magics", GINT_TO_POINTER (MAGICS)); + g_scanner_scope_add_symbol (scanner, LOAD_PROC, + "priority", GINT_TO_POINTER (PRIORITY)); + g_scanner_scope_add_symbol (scanner, LOAD_PROC, + "mime-types", GINT_TO_POINTER (MIME_TYPES)); + g_scanner_scope_add_symbol (scanner, LOAD_PROC, + "handles-uri", GINT_TO_POINTER (HANDLES_URI)); + g_scanner_scope_add_symbol (scanner, LOAD_PROC, + "handles-raw", GINT_TO_POINTER (HANDLES_RAW)); + g_scanner_scope_add_symbol (scanner, LOAD_PROC, + "thumb-loader", GINT_TO_POINTER (THUMB_LOADER)); + + g_scanner_scope_add_symbol (scanner, SAVE_PROC, + "extensions", GINT_TO_POINTER (EXTENSIONS)); + g_scanner_scope_add_symbol (scanner, SAVE_PROC, + "prefixes", GINT_TO_POINTER (PREFIXES)); + g_scanner_scope_add_symbol (scanner, SAVE_PROC, + "priority", GINT_TO_POINTER (PRIORITY)); + g_scanner_scope_add_symbol (scanner, SAVE_PROC, + "mime-types", GINT_TO_POINTER (MIME_TYPES)); + g_scanner_scope_add_symbol (scanner, SAVE_PROC, + "handles-uri", GINT_TO_POINTER (HANDLES_URI)); + + token = G_TOKEN_LEFT_PAREN; + + while (protocol_version == GIMP_PROTOCOL_VERSION && + file_version == PLUG_IN_RC_FILE_VERSION && + g_scanner_peek_next_token (scanner) == token) + { + token = g_scanner_get_next_token (scanner); + + switch (token) + { + case G_TOKEN_LEFT_PAREN: + token = G_TOKEN_SYMBOL; + break; + + case G_TOKEN_SYMBOL: + switch (GPOINTER_TO_INT (scanner->value.v_symbol)) + { + case PROTOCOL_VERSION: + token = G_TOKEN_INT; + if (gimp_scanner_parse_int (scanner, &protocol_version)) + token = G_TOKEN_RIGHT_PAREN; + break; + + case FILE_VERSION: + token = G_TOKEN_INT; + if (gimp_scanner_parse_int (scanner, &file_version)) + token = G_TOKEN_RIGHT_PAREN; + break; + + case PLUG_IN_DEF: + g_scanner_set_scope (scanner, PLUG_IN_DEF); + token = plug_in_def_deserialize (gimp, scanner, &plug_in_defs); + g_scanner_set_scope (scanner, 0); + break; + default: + break; + } + break; + + case G_TOKEN_RIGHT_PAREN: + token = G_TOKEN_LEFT_PAREN; + break; + + default: /* do nothing */ + break; + } + } + + if (protocol_version != GIMP_PROTOCOL_VERSION || + file_version != PLUG_IN_RC_FILE_VERSION || + token != G_TOKEN_LEFT_PAREN) + { + if (protocol_version != GIMP_PROTOCOL_VERSION) + { + g_set_error (error, + GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_VERSION, + _("Skipping '%s': wrong GIMP protocol version."), + gimp_file_get_utf8_name (file)); + } + else if (file_version != PLUG_IN_RC_FILE_VERSION) + { + g_set_error (error, + GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_VERSION, + _("Skipping '%s': wrong pluginrc file format version."), + gimp_file_get_utf8_name (file)); + } + else if (token != G_TOKEN_ERROR) + { + g_scanner_get_next_token (scanner); + g_scanner_unexp_token (scanner, token, NULL, NULL, NULL, + _("fatal parse error"), TRUE); + } + + g_slist_free_full (plug_in_defs, (GDestroyNotify) g_object_unref); + plug_in_defs = NULL; + } + + g_type_class_unref (enum_class); + + gimp_scanner_destroy (scanner); + + return g_slist_reverse (plug_in_defs); +} + +static GTokenType +plug_in_def_deserialize (Gimp *gimp, + GScanner *scanner, + GSList **plug_in_defs) +{ + GimpPlugInDef *plug_in_def; + GimpPlugInProcedure *proc = NULL; + gchar *path; + GFile *file; + gint64 mtime; + GTokenType token; + GError *error = NULL; + + if (! gimp_scanner_parse_string (scanner, &path)) + return G_TOKEN_STRING; + + if (! (path && *path)) + { + g_scanner_error (scanner, "plug-in filename is empty"); + return G_TOKEN_ERROR; + } + + file = gimp_file_new_for_config_path (path, &error); + g_free (path); + + if (! file) + { + g_scanner_error (scanner, + "unable to parse plug-in filename: %s", + error->message); + g_clear_error (&error); + return G_TOKEN_ERROR; + } + + plug_in_def = gimp_plug_in_def_new (file); + g_object_unref (file); + + if (! gimp_scanner_parse_int64 (scanner, &mtime)) + { + g_object_unref (plug_in_def); + return G_TOKEN_INT; + } + + plug_in_def->mtime = mtime; + + token = G_TOKEN_LEFT_PAREN; + + while (g_scanner_peek_next_token (scanner) == token) + { + token = g_scanner_get_next_token (scanner); + + switch (token) + { + case G_TOKEN_LEFT_PAREN: + token = G_TOKEN_SYMBOL; + break; + + case G_TOKEN_SYMBOL: + switch (GPOINTER_TO_INT (scanner->value.v_symbol)) + { + case PROC_DEF: + token = plug_in_procedure_deserialize (scanner, gimp, + plug_in_def->file, + &proc); + + if (token == G_TOKEN_LEFT_PAREN) + gimp_plug_in_def_add_procedure (plug_in_def, proc); + + if (proc) + g_object_unref (proc); + break; + + case LOCALE_DEF: + token = plug_in_locale_def_deserialize (scanner, plug_in_def); + break; + + case HELP_DEF: + token = plug_in_help_def_deserialize (scanner, plug_in_def); + break; + + case HAS_INIT: + token = plug_in_has_init_deserialize (scanner, plug_in_def); + break; + + default: + break; + } + break; + + case G_TOKEN_RIGHT_PAREN: + token = G_TOKEN_LEFT_PAREN; + break; + + default: + break; + } + } + + if (token == G_TOKEN_LEFT_PAREN) + { + token = G_TOKEN_RIGHT_PAREN; + + if (gimp_scanner_parse_token (scanner, token)) + { + *plug_in_defs = g_slist_prepend (*plug_in_defs, plug_in_def); + return G_TOKEN_LEFT_PAREN; + } + } + + g_object_unref (plug_in_def); + + return token; +} + +static GTokenType +plug_in_procedure_deserialize (GScanner *scanner, + Gimp *gimp, + GFile *file, + GimpPlugInProcedure **proc) +{ + GimpProcedure *procedure; + GTokenType token; + gchar *str; + gint proc_type; + gint n_args; + gint n_return_vals; + gint n_menu_paths; + gint i; + + if (! gimp_scanner_parse_string (scanner, &str)) + return G_TOKEN_STRING; + + if (! (str && *str)) + { + g_scanner_error (scanner, "procedure name is empty"); + return G_TOKEN_ERROR; + } + + if (! gimp_scanner_parse_int (scanner, &proc_type)) + { + g_free (str); + return G_TOKEN_INT; + } + + if (proc_type != GIMP_PLUGIN && + proc_type != GIMP_EXTENSION) + { + g_free (str); + g_scanner_error (scanner, "procedure type %d is out of range", + proc_type); + return G_TOKEN_ERROR; + } + + procedure = gimp_plug_in_procedure_new (proc_type, file); + + *proc = GIMP_PLUG_IN_PROCEDURE (procedure); + + gimp_object_take_name (GIMP_OBJECT (procedure), + gimp_canonicalize_identifier (str)); + + procedure->original_name = str; + + if (! gimp_scanner_parse_string (scanner, &procedure->blurb)) + return G_TOKEN_STRING; + if (! gimp_scanner_parse_string (scanner, &procedure->help)) + return G_TOKEN_STRING; + if (! gimp_scanner_parse_string (scanner, &procedure->author)) + return G_TOKEN_STRING; + if (! gimp_scanner_parse_string (scanner, &procedure->copyright)) + return G_TOKEN_STRING; + if (! gimp_scanner_parse_string (scanner, &procedure->date)) + return G_TOKEN_STRING; + if (! gimp_scanner_parse_string (scanner, &(*proc)->menu_label)) + return G_TOKEN_STRING; + + if (! gimp_scanner_parse_int (scanner, &n_menu_paths)) + return G_TOKEN_INT; + + for (i = 0; i < n_menu_paths; i++) + { + token = plug_in_menu_path_deserialize (scanner, *proc); + if (token != G_TOKEN_LEFT_PAREN) + return token; + } + + token = plug_in_icon_deserialize (scanner, *proc); + if (token != G_TOKEN_LEFT_PAREN) + return token; + + token = plug_in_file_proc_deserialize (scanner, *proc); + if (token != G_TOKEN_LEFT_PAREN) + return token; + + if (! gimp_scanner_parse_string (scanner, &str)) + return G_TOKEN_STRING; + + gimp_plug_in_procedure_set_image_types (*proc, str); + g_free (str); + + if (! gimp_scanner_parse_int (scanner, (gint *) &n_args)) + return G_TOKEN_INT; + if (! gimp_scanner_parse_int (scanner, (gint *) &n_return_vals)) + return G_TOKEN_INT; + + for (i = 0; i < n_args; i++) + { + token = plug_in_proc_arg_deserialize (scanner, gimp, procedure, FALSE); + if (token != G_TOKEN_LEFT_PAREN) + return token; + } + + for (i = 0; i < n_return_vals; i++) + { + token = plug_in_proc_arg_deserialize (scanner, gimp, procedure, TRUE); + if (token != G_TOKEN_LEFT_PAREN) + return token; + } + + if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN)) + return G_TOKEN_RIGHT_PAREN; + + return G_TOKEN_LEFT_PAREN; +} + +static GTokenType +plug_in_menu_path_deserialize (GScanner *scanner, + GimpPlugInProcedure *proc) +{ + gchar *menu_path; + + if (! gimp_scanner_parse_token (scanner, G_TOKEN_LEFT_PAREN)) + return G_TOKEN_LEFT_PAREN; + + if (! gimp_scanner_parse_token (scanner, G_TOKEN_SYMBOL) || + GPOINTER_TO_INT (scanner->value.v_symbol) != MENU_PATH) + return G_TOKEN_SYMBOL; + + if (! gimp_scanner_parse_string (scanner, &menu_path)) + return G_TOKEN_STRING; + + proc->menu_paths = g_list_append (proc->menu_paths, menu_path); + + if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN)) + return G_TOKEN_RIGHT_PAREN; + + return G_TOKEN_LEFT_PAREN; +} + +static GTokenType +plug_in_icon_deserialize (GScanner *scanner, + GimpPlugInProcedure *proc) +{ + GEnumClass *enum_class; + GEnumValue *enum_value; + GimpIconType icon_type; + gint icon_data_length; + gchar *icon_name; + guint8 *icon_data; + + if (! gimp_scanner_parse_token (scanner, G_TOKEN_LEFT_PAREN)) + return G_TOKEN_LEFT_PAREN; + + if (! gimp_scanner_parse_token (scanner, G_TOKEN_SYMBOL) || + GPOINTER_TO_INT (scanner->value.v_symbol) != ICON) + return G_TOKEN_SYMBOL; + + enum_class = g_type_class_peek (GIMP_TYPE_ICON_TYPE); + + switch (g_scanner_peek_next_token (scanner)) + { + case G_TOKEN_IDENTIFIER: + g_scanner_get_next_token (scanner); + + enum_value = g_enum_get_value_by_nick (G_ENUM_CLASS (enum_class), + scanner->value.v_identifier); + if (!enum_value) + enum_value = g_enum_get_value_by_name (G_ENUM_CLASS (enum_class), + scanner->value.v_identifier); + + if (!enum_value) + { + g_scanner_error (scanner, + _("invalid value '%s' for icon type"), + scanner->value.v_identifier); + return G_TOKEN_NONE; + } + break; + + case G_TOKEN_INT: + g_scanner_get_next_token (scanner); + + enum_value = g_enum_get_value (enum_class, + (gint) scanner->value.v_int64); + + if (!enum_value) + { + g_scanner_error (scanner, + _("invalid value '%ld' for icon type"), + (glong) scanner->value.v_int64); + return G_TOKEN_NONE; + } + break; + + default: + return G_TOKEN_IDENTIFIER; + } + + icon_type = enum_value->value; + + if (! gimp_scanner_parse_int (scanner, &icon_data_length)) + return G_TOKEN_INT; + + switch (icon_type) + { + case GIMP_ICON_TYPE_ICON_NAME: + case GIMP_ICON_TYPE_IMAGE_FILE: + icon_data_length = -1; + + if (! gimp_scanner_parse_string_no_validate (scanner, &icon_name)) + return G_TOKEN_STRING; + + icon_data = (guint8 *) icon_name; + break; + + case GIMP_ICON_TYPE_INLINE_PIXBUF: + if (icon_data_length < 0) + return G_TOKEN_STRING; + + if (! gimp_scanner_parse_data (scanner, icon_data_length, &icon_data)) + return G_TOKEN_STRING; + break; + } + + gimp_plug_in_procedure_take_icon (proc, icon_type, + icon_data, icon_data_length); + + if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN)) + return G_TOKEN_RIGHT_PAREN; + + return G_TOKEN_LEFT_PAREN; +} + +static GTokenType +plug_in_file_proc_deserialize (GScanner *scanner, + GimpPlugInProcedure *proc) +{ + GTokenType token; + gint symbol; + + if (! gimp_scanner_parse_token (scanner, G_TOKEN_LEFT_PAREN)) + return G_TOKEN_LEFT_PAREN; + + if (! gimp_scanner_parse_token (scanner, G_TOKEN_SYMBOL)) + return G_TOKEN_SYMBOL; + + symbol = GPOINTER_TO_INT (scanner->value.v_symbol); + if (symbol != LOAD_PROC && symbol != SAVE_PROC) + return G_TOKEN_SYMBOL; + + proc->file_proc = TRUE; + + g_scanner_set_scope (scanner, symbol); + + while (g_scanner_peek_next_token (scanner) == G_TOKEN_LEFT_PAREN) + { + token = g_scanner_get_next_token (scanner); + + if (token != G_TOKEN_LEFT_PAREN) + return token; + + if (! gimp_scanner_parse_token (scanner, G_TOKEN_SYMBOL)) + return G_TOKEN_SYMBOL; + + symbol = GPOINTER_TO_INT (scanner->value.v_symbol); + + switch (symbol) + { + case EXTENSIONS: + { + gchar *extensions; + + if (! gimp_scanner_parse_string (scanner, &extensions)) + return G_TOKEN_STRING; + + g_free (proc->extensions); + proc->extensions = extensions; + } + break; + + case PREFIXES: + { + gchar *prefixes; + + if (! gimp_scanner_parse_string (scanner, &prefixes)) + return G_TOKEN_STRING; + + g_free (proc->prefixes); + proc->prefixes = prefixes; + } + break; + + case MAGICS: + { + gchar *magics; + + if (! gimp_scanner_parse_string_no_validate (scanner, &magics)) + return G_TOKEN_STRING; + + g_free (proc->magics); + proc->magics = magics; + } + break; + + case PRIORITY: + { + gint priority; + + if (! gimp_scanner_parse_int (scanner, &priority)) + return G_TOKEN_INT; + + gimp_plug_in_procedure_set_priority (proc, priority); + } + break; + + case MIME_TYPES: + { + gchar *mime_types; + + if (! gimp_scanner_parse_string (scanner, &mime_types)) + return G_TOKEN_STRING; + + gimp_plug_in_procedure_set_mime_types (proc, mime_types); + + g_free (mime_types); + } + break; + + case HANDLES_URI: + gimp_plug_in_procedure_set_handles_uri (proc); + break; + + case HANDLES_RAW: + gimp_plug_in_procedure_set_handles_raw (proc); + break; + + case THUMB_LOADER: + { + gchar *thumb_loader; + + if (! gimp_scanner_parse_string (scanner, &thumb_loader)) + return G_TOKEN_STRING; + + gimp_plug_in_procedure_set_thumb_loader (proc, thumb_loader); + + g_free (thumb_loader); + } + break; + + default: + return G_TOKEN_SYMBOL; + } + if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN)) + return G_TOKEN_RIGHT_PAREN; + } + + if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN)) + return G_TOKEN_RIGHT_PAREN; + + g_scanner_set_scope (scanner, PLUG_IN_DEF); + + return G_TOKEN_LEFT_PAREN; +} + +static GTokenType +plug_in_proc_arg_deserialize (GScanner *scanner, + Gimp *gimp, + GimpProcedure *procedure, + gboolean return_value) +{ + GTokenType token; + gint arg_type; + gchar *name = NULL; + gchar *desc = NULL; + GParamSpec *pspec; + + if (! gimp_scanner_parse_token (scanner, G_TOKEN_LEFT_PAREN)) + { + token = G_TOKEN_LEFT_PAREN; + goto error; + } + + if (! gimp_scanner_parse_token (scanner, G_TOKEN_SYMBOL) || + GPOINTER_TO_INT (scanner->value.v_symbol) != PROC_ARG) + { + token = G_TOKEN_SYMBOL; + goto error; + } + + if (! gimp_scanner_parse_int (scanner, (gint *) &arg_type)) + { + token = G_TOKEN_INT; + goto error; + } + if (! gimp_scanner_parse_string (scanner, &name)) + { + token = G_TOKEN_STRING; + goto error; + } + if (! gimp_scanner_parse_string (scanner, &desc)) + { + token = G_TOKEN_STRING; + goto error; + } + + if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN)) + { + token = G_TOKEN_RIGHT_PAREN; + goto error; + } + + token = G_TOKEN_LEFT_PAREN; + + pspec = gimp_pdb_compat_param_spec (gimp, arg_type, name, desc, NULL); + + if (return_value) + gimp_procedure_add_return_value (procedure, pspec); + else + gimp_procedure_add_argument (procedure, pspec); + + error: + + g_free (name); + g_free (desc); + + return token; +} + +static GTokenType +plug_in_locale_def_deserialize (GScanner *scanner, + GimpPlugInDef *plug_in_def) +{ + gchar *domain_name; + gchar *domain_path = NULL; + gchar *expanded_path = NULL; + + if (! gimp_scanner_parse_string (scanner, &domain_name)) + return G_TOKEN_STRING; + + if (gimp_scanner_parse_string (scanner, &domain_path)) + expanded_path = gimp_config_path_expand (domain_path, TRUE, NULL); + + gimp_plug_in_def_set_locale_domain (plug_in_def, domain_name, expanded_path); + + g_free (domain_name); + g_free (domain_path); + g_free (expanded_path); + + if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN)) + return G_TOKEN_RIGHT_PAREN; + + return G_TOKEN_LEFT_PAREN; +} + +static GTokenType +plug_in_help_def_deserialize (GScanner *scanner, + GimpPlugInDef *plug_in_def) +{ + gchar *domain_name; + gchar *domain_uri; + + if (! gimp_scanner_parse_string (scanner, &domain_name)) + return G_TOKEN_STRING; + + if (! gimp_scanner_parse_string (scanner, &domain_uri)) + domain_uri = NULL; + + gimp_plug_in_def_set_help_domain (plug_in_def, domain_name, domain_uri); + + g_free (domain_name); + g_free (domain_uri); + + if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN)) + return G_TOKEN_RIGHT_PAREN; + + return G_TOKEN_LEFT_PAREN; +} + +static GTokenType +plug_in_has_init_deserialize (GScanner *scanner, + GimpPlugInDef *plug_in_def) +{ + gimp_plug_in_def_set_has_init (plug_in_def, TRUE); + + if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN)) + return G_TOKEN_RIGHT_PAREN; + + return G_TOKEN_LEFT_PAREN; +} + + +/* serialize functions */ + +gboolean +plug_in_rc_write (GSList *plug_in_defs, + GFile *file, + GError **error) +{ + GimpConfigWriter *writer; + GEnumClass *enum_class; + GSList *list; + + writer = gimp_config_writer_new_gfile (file, + FALSE, + "GIMP pluginrc\n\n" + "This file can safely be removed and " + "will be automatically regenerated by " + "querying the installed plug-ins.", + error); + if (!writer) + return FALSE; + + enum_class = g_type_class_ref (GIMP_TYPE_ICON_TYPE); + + gimp_config_writer_open (writer, "protocol-version"); + gimp_config_writer_printf (writer, "%d", GIMP_PROTOCOL_VERSION); + gimp_config_writer_close (writer); + + gimp_config_writer_open (writer, "file-version"); + gimp_config_writer_printf (writer, "%d", PLUG_IN_RC_FILE_VERSION); + gimp_config_writer_close (writer); + + gimp_config_writer_linefeed (writer); + + for (list = plug_in_defs; list; list = list->next) + { + GimpPlugInDef *plug_in_def = list->data; + + if (plug_in_def->procedures) + { + GSList *list2; + gchar *path; + + path = gimp_file_get_config_path (plug_in_def->file, NULL); + if (! path) + continue; + + gimp_config_writer_open (writer, "plug-in-def"); + gimp_config_writer_string (writer, path); + gimp_config_writer_printf (writer, "%"G_GINT64_FORMAT, + plug_in_def->mtime); + + g_free (path); + + for (list2 = plug_in_def->procedures; list2; list2 = list2->next) + { + GimpPlugInProcedure *proc = list2->data; + GimpProcedure *procedure = GIMP_PROCEDURE (proc); + GEnumValue *enum_value; + GList *list3; + gint i; + + if (proc->installed_during_init) + continue; + + gimp_config_writer_open (writer, "proc-def"); + gimp_config_writer_printf (writer, "\"%s\" %d", + procedure->original_name, + procedure->proc_type); + gimp_config_writer_linefeed (writer); + gimp_config_writer_string (writer, procedure->blurb); + gimp_config_writer_linefeed (writer); + gimp_config_writer_string (writer, procedure->help); + gimp_config_writer_linefeed (writer); + gimp_config_writer_string (writer, procedure->author); + gimp_config_writer_linefeed (writer); + gimp_config_writer_string (writer, procedure->copyright); + gimp_config_writer_linefeed (writer); + gimp_config_writer_string (writer, procedure->date); + gimp_config_writer_linefeed (writer); + gimp_config_writer_string (writer, proc->menu_label); + gimp_config_writer_linefeed (writer); + + gimp_config_writer_printf (writer, "%d", + g_list_length (proc->menu_paths)); + for (list3 = proc->menu_paths; list3; list3 = list3->next) + { + gimp_config_writer_open (writer, "menu-path"); + gimp_config_writer_string (writer, list3->data); + gimp_config_writer_close (writer); + } + + gimp_config_writer_open (writer, "icon"); + enum_value = g_enum_get_value (enum_class, proc->icon_type); + gimp_config_writer_identifier (writer, enum_value->value_nick); + gimp_config_writer_printf (writer, "%d", + proc->icon_data_length); + + switch (proc->icon_type) + { + case GIMP_ICON_TYPE_ICON_NAME: + case GIMP_ICON_TYPE_IMAGE_FILE: + gimp_config_writer_string (writer, (gchar *) proc->icon_data); + break; + + case GIMP_ICON_TYPE_INLINE_PIXBUF: + gimp_config_writer_data (writer, proc->icon_data_length, + proc->icon_data); + break; + } + + gimp_config_writer_close (writer); + + if (proc->file_proc) + { + gimp_config_writer_open (writer, + proc->image_types ? + "save-proc" : "load-proc"); + + if (proc->extensions && *proc->extensions) + { + gimp_config_writer_open (writer, "extensions"); + gimp_config_writer_string (writer, proc->extensions); + gimp_config_writer_close (writer); + } + + if (proc->prefixes && *proc->prefixes) + { + gimp_config_writer_open (writer, "prefixes"); + gimp_config_writer_string (writer, proc->prefixes); + gimp_config_writer_close (writer); + } + + if (proc->magics && *proc->magics) + { + gimp_config_writer_open (writer, "magics"); + gimp_config_writer_string (writer, proc->magics); + gimp_config_writer_close (writer); + } + + if (proc->priority) + { + gimp_config_writer_open (writer, "priority"); + gimp_config_writer_printf (writer, "%d", proc->priority); + gimp_config_writer_close (writer); + } + + if (proc->mime_types && *proc->mime_types) + { + gimp_config_writer_open (writer, "mime-types"); + gimp_config_writer_string (writer, proc->mime_types); + gimp_config_writer_close (writer); + } + + if (proc->priority) + { + gimp_config_writer_open (writer, "priority"); + gimp_config_writer_printf (writer, "%d", proc->priority); + gimp_config_writer_close (writer); + } + + if (proc->handles_uri) + { + gimp_config_writer_open (writer, "handles-uri"); + gimp_config_writer_close (writer); + } + + if (proc->handles_raw && ! proc->image_types) + { + gimp_config_writer_open (writer, "handles-raw"); + gimp_config_writer_close (writer); + } + + if (proc->thumb_loader) + { + gimp_config_writer_open (writer, "thumb-loader"); + gimp_config_writer_string (writer, proc->thumb_loader); + gimp_config_writer_close (writer); + } + + gimp_config_writer_close (writer); + } + + gimp_config_writer_linefeed (writer); + + gimp_config_writer_string (writer, proc->image_types); + gimp_config_writer_linefeed (writer); + + gimp_config_writer_printf (writer, "%d %d", + procedure->num_args, + procedure->num_values); + + for (i = 0; i < procedure->num_args; i++) + { + GParamSpec *pspec = procedure->args[i]; + + gimp_config_writer_open (writer, "proc-arg"); + gimp_config_writer_printf (writer, "%d", + gimp_pdb_compat_arg_type_from_gtype (G_PARAM_SPEC_VALUE_TYPE (pspec))); + + gimp_config_writer_string (writer, + g_param_spec_get_name (pspec)); + gimp_config_writer_string (writer, + g_param_spec_get_blurb (pspec)); + + gimp_config_writer_close (writer); + } + + for (i = 0; i < procedure->num_values; i++) + { + GParamSpec *pspec = procedure->values[i]; + + gimp_config_writer_open (writer, "proc-arg"); + gimp_config_writer_printf (writer, "%d", + gimp_pdb_compat_arg_type_from_gtype (G_PARAM_SPEC_VALUE_TYPE (pspec))); + + gimp_config_writer_string (writer, + g_param_spec_get_name (pspec)); + gimp_config_writer_string (writer, + g_param_spec_get_blurb (pspec)); + + gimp_config_writer_close (writer); + } + + gimp_config_writer_close (writer); + } + + if (plug_in_def->locale_domain_name) + { + gimp_config_writer_open (writer, "locale-def"); + gimp_config_writer_string (writer, + plug_in_def->locale_domain_name); + + if (plug_in_def->locale_domain_path) + { + path = gimp_config_path_unexpand (plug_in_def->locale_domain_path, + TRUE, NULL); + if (path) + { + gimp_config_writer_string (writer, path); + g_free (path); + } + } + + gimp_config_writer_close (writer); + } + + if (plug_in_def->help_domain_name) + { + gimp_config_writer_open (writer, "help-def"); + gimp_config_writer_string (writer, + plug_in_def->help_domain_name); + + if (plug_in_def->help_domain_uri) + gimp_config_writer_string (writer, + plug_in_def->help_domain_uri); + + gimp_config_writer_close (writer); + } + + if (plug_in_def->has_init) + { + gimp_config_writer_open (writer, "has-init"); + gimp_config_writer_close (writer); + } + + gimp_config_writer_close (writer); + } + } + + g_type_class_unref (enum_class); + + return gimp_config_writer_finish (writer, "end of pluginrc", error); +} diff --git a/app/plug-in/plug-in-rc.h b/app/plug-in/plug-in-rc.h new file mode 100644 index 0000000..5a54b0b --- /dev/null +++ b/app/plug-in/plug-in-rc.h @@ -0,0 +1,33 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * plug-in-rc.h + * Copyright (C) 2001 Sven Neumann <sven@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/>. + */ + +#ifndef __PLUG_IN_RC_H__ +#define __PLUG_IN_RC_H__ + + +GSList * plug_in_rc_parse (Gimp *gimp, + GFile *file, + GError **error); +gboolean plug_in_rc_write (GSList *plug_in_defs, + GFile *file, + GError **error); + + +#endif /* __PLUG_IN_RC_H__ */ diff --git a/app/plug-in/plug-in-types.h b/app/plug-in/plug-in-types.h new file mode 100644 index 0000000..70d7ca0 --- /dev/null +++ b/app/plug-in/plug-in-types.h @@ -0,0 +1,40 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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/>. + */ + +#ifndef __PLUG_IN_TYPES_H__ +#define __PLUG_IN_TYPES_H__ + + +#include "core/core-types.h" + +#include "plug-in/plug-in-enums.h" + + +#define GIMP_PLUG_IN_TILE_WIDTH 128 +#define GIMP_PLUG_IN_TILE_HEIGHT 128 + + +typedef struct _GimpPlugIn GimpPlugIn; +typedef struct _GimpPlugInDebug GimpPlugInDebug; +typedef struct _GimpPlugInDef GimpPlugInDef; +typedef struct _GimpPlugInManager GimpPlugInManager; +typedef struct _GimpPlugInMenuBranch GimpPlugInMenuBranch; +typedef struct _GimpPlugInProcFrame GimpPlugInProcFrame; +typedef struct _GimpPlugInShm GimpPlugInShm; + + +#endif /* __PLUG_IN_TYPES_H__ */ |