summaryrefslogtreecommitdiffstats
path: root/plug-ins/screenshot
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:23:22 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:23:22 +0000
commite42129241681dde7adae7d20697e7b421682fbb4 (patch)
treeaf1fe815a5e639e68e59fabd8395ec69458b3e5e /plug-ins/screenshot
parentInitial commit. (diff)
downloadgimp-upstream.tar.xz
gimp-upstream.zip
Adding upstream version 2.10.22.upstream/2.10.22upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'plug-ins/screenshot')
-rw-r--r--plug-ins/screenshot/Makefile.am75
-rw-r--r--plug-ins/screenshot/Makefile.in1037
-rw-r--r--plug-ins/screenshot/screenshot-freedesktop.c199
-rw-r--r--plug-ins/screenshot/screenshot-freedesktop.h32
-rw-r--r--plug-ins/screenshot/screenshot-gnome-shell.c209
-rw-r--r--plug-ins/screenshot/screenshot-gnome-shell.h32
-rw-r--r--plug-ins/screenshot/screenshot-icon.h80
-rw-r--r--plug-ins/screenshot/screenshot-kwin.c207
-rw-r--r--plug-ins/screenshot/screenshot-kwin.h32
-rw-r--r--plug-ins/screenshot/screenshot-osx.c159
-rw-r--r--plug-ins/screenshot/screenshot-osx.h36
-rw-r--r--plug-ins/screenshot/screenshot-win32-dwm-api.h72
-rw-r--r--plug-ins/screenshot/screenshot-win32-magnification-api.h154
-rw-r--r--plug-ins/screenshot/screenshot-win32-resource.h26
-rw-r--r--plug-ins/screenshot/screenshot-win32-select.curbin0 -> 326 bytes
-rw-r--r--plug-ins/screenshot/screenshot-win32-small.icobin0 -> 318 bytes
-rw-r--r--plug-ins/screenshot/screenshot-win32.c1278
-rw-r--r--plug-ins/screenshot/screenshot-win32.h44
-rw-r--r--plug-ins/screenshot/screenshot-win32.icobin0 -> 1590 bytes
-rw-r--r--plug-ins/screenshot/screenshot-win32.rc189
-rw-r--r--plug-ins/screenshot/screenshot-x11.c697
-rw-r--r--plug-ins/screenshot/screenshot-x11.h36
-rw-r--r--plug-ins/screenshot/screenshot.c881
-rw-r--r--plug-ins/screenshot/screenshot.h80
24 files changed, 5555 insertions, 0 deletions
diff --git a/plug-ins/screenshot/Makefile.am b/plug-ins/screenshot/Makefile.am
new file mode 100644
index 0000000..0d8d829
--- /dev/null
+++ b/plug-ins/screenshot/Makefile.am
@@ -0,0 +1,75 @@
+## Process this file with automake to produce Makefile.in
+
+libgimpui = $(top_builddir)/libgimp/libgimpui-$(GIMP_API_VERSION).la
+libgimpconfig = $(top_builddir)/libgimpconfig/libgimpconfig-$(GIMP_API_VERSION).la
+libgimpwidgets = $(top_builddir)/libgimpwidgets/libgimpwidgets-$(GIMP_API_VERSION).la
+libgimp = $(top_builddir)/libgimp/libgimp-$(GIMP_API_VERSION).la
+libgimpcolor = $(top_builddir)/libgimpcolor/libgimpcolor-$(GIMP_API_VERSION).la
+libgimpbase = $(top_builddir)/libgimpbase/libgimpbase-$(GIMP_API_VERSION).la
+libgimpmath = $(top_builddir)/libgimpmath/libgimpmath-$(GIMP_API_VERSION).la
+
+if OS_WIN32
+mwindows = -mwindows
+screenshot_RC = screenshot-win32-res.o
+endif
+
+AM_LDFLAGS = $(mwindows)
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ $(GTK_CFLAGS) \
+ $(GEGL_CFLAGS) \
+ $(XFIXES_CFLAGS) \
+ -I$(includedir)
+
+LDADD = \
+ $(libgimpui) \
+ $(libgimpwidgets) \
+ $(libgimpconfig) \
+ $(libgimp) \
+ $(libgimpcolor) \
+ $(libgimpmath) \
+ $(libgimpbase) \
+ $(GTK_LIBS) \
+ $(GEGL_LIBS) \
+ $(SCREENSHOT_LIBS) \
+ $(RT_LIBS) \
+ $(INTLLIBS) \
+ $(screenshot_RC)
+
+libexecdir = $(gimpplugindir)/plug-ins/screenshot
+
+libexec_PROGRAMS = screenshot
+
+EXTRA_PROGRAMS = screenshot
+
+screenshot_SOURCES = \
+ screenshot.c \
+ screenshot.h \
+ screenshot-freedesktop.c \
+ screenshot-freedesktop.h \
+ screenshot-gnome-shell.c \
+ screenshot-gnome-shell.h \
+ screenshot-icon.h \
+ screenshot-kwin.c \
+ screenshot-kwin.h \
+ screenshot-osx.c \
+ screenshot-osx.h \
+ screenshot-x11.c \
+ screenshot-x11.h \
+ screenshot-win32.rc \
+ screenshot-win32.c \
+ screenshot-win32.h \
+ screenshot-win32-dwm-api.h \
+ screenshot-win32-magnification-api.h \
+ screenshot-win32-resource.h
+
+EXTRA_DIST = \
+ screenshot-win32-select.cur \
+ screenshot-win32-small.ico \
+ screenshot-win32.ico
+
+if OS_WIN32
+screenshot-win32-res.o: screenshot-win32.rc screenshot-win32-select.cur screenshot-win32-small.ico screenshot-win32.ico
+ $(WINDRES) $(srcdir)/screenshot-win32.rc screenshot-win32-res.o
+endif
diff --git a/plug-ins/screenshot/Makefile.in b/plug-ins/screenshot/Makefile.in
new file mode 100644
index 0000000..43263d2
--- /dev/null
+++ b/plug-ins/screenshot/Makefile.in
@@ -0,0 +1,1037 @@
+# 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@
+libexec_PROGRAMS = screenshot$(EXEEXT)
+EXTRA_PROGRAMS = screenshot$(EXEEXT)
+subdir = plug-ins/screenshot
+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 =
+am__installdirs = "$(DESTDIR)$(libexecdir)"
+PROGRAMS = $(libexec_PROGRAMS)
+am_screenshot_OBJECTS = screenshot.$(OBJEXT) \
+ screenshot-freedesktop.$(OBJEXT) \
+ screenshot-gnome-shell.$(OBJEXT) screenshot-kwin.$(OBJEXT) \
+ screenshot-osx.$(OBJEXT) screenshot-x11.$(OBJEXT) \
+ screenshot-win32.$(OBJEXT)
+screenshot_OBJECTS = $(am_screenshot_OBJECTS)
+screenshot_LDADD = $(LDADD)
+am__DEPENDENCIES_1 =
+screenshot_DEPENDENCIES = $(libgimpui) $(libgimpwidgets) \
+ $(libgimpconfig) $(libgimp) $(libgimpcolor) $(libgimpmath) \
+ $(libgimpbase) $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(screenshot_RC)
+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 =
+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)/screenshot-freedesktop.Po \
+ ./$(DEPDIR)/screenshot-gnome-shell.Po \
+ ./$(DEPDIR)/screenshot-kwin.Po ./$(DEPDIR)/screenshot-osx.Po \
+ ./$(DEPDIR)/screenshot-win32.Po ./$(DEPDIR)/screenshot-x11.Po \
+ ./$(DEPDIR)/screenshot.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+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 = $(screenshot_SOURCES)
+DIST_SOURCES = $(screenshot_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 = $(gimpplugindir)/plug-ins/screenshot
+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@
+libgimpui = $(top_builddir)/libgimp/libgimpui-$(GIMP_API_VERSION).la
+libgimpconfig = $(top_builddir)/libgimpconfig/libgimpconfig-$(GIMP_API_VERSION).la
+libgimpwidgets = $(top_builddir)/libgimpwidgets/libgimpwidgets-$(GIMP_API_VERSION).la
+libgimp = $(top_builddir)/libgimp/libgimp-$(GIMP_API_VERSION).la
+libgimpcolor = $(top_builddir)/libgimpcolor/libgimpcolor-$(GIMP_API_VERSION).la
+libgimpbase = $(top_builddir)/libgimpbase/libgimpbase-$(GIMP_API_VERSION).la
+libgimpmath = $(top_builddir)/libgimpmath/libgimpmath-$(GIMP_API_VERSION).la
+@OS_WIN32_TRUE@mwindows = -mwindows
+@OS_WIN32_TRUE@screenshot_RC = screenshot-win32-res.o
+AM_LDFLAGS = $(mwindows)
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ $(GTK_CFLAGS) \
+ $(GEGL_CFLAGS) \
+ $(XFIXES_CFLAGS) \
+ -I$(includedir)
+
+LDADD = \
+ $(libgimpui) \
+ $(libgimpwidgets) \
+ $(libgimpconfig) \
+ $(libgimp) \
+ $(libgimpcolor) \
+ $(libgimpmath) \
+ $(libgimpbase) \
+ $(GTK_LIBS) \
+ $(GEGL_LIBS) \
+ $(SCREENSHOT_LIBS) \
+ $(RT_LIBS) \
+ $(INTLLIBS) \
+ $(screenshot_RC)
+
+screenshot_SOURCES = \
+ screenshot.c \
+ screenshot.h \
+ screenshot-freedesktop.c \
+ screenshot-freedesktop.h \
+ screenshot-gnome-shell.c \
+ screenshot-gnome-shell.h \
+ screenshot-icon.h \
+ screenshot-kwin.c \
+ screenshot-kwin.h \
+ screenshot-osx.c \
+ screenshot-osx.h \
+ screenshot-x11.c \
+ screenshot-x11.h \
+ screenshot-win32.rc \
+ screenshot-win32.c \
+ screenshot-win32.h \
+ screenshot-win32-dwm-api.h \
+ screenshot-win32-magnification-api.h \
+ screenshot-win32-resource.h
+
+EXTRA_DIST = \
+ screenshot-win32-select.cur \
+ screenshot-win32-small.ico \
+ screenshot-win32.ico
+
+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 plug-ins/screenshot/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu plug-ins/screenshot/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):
+install-libexecPROGRAMS: $(libexec_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-libexecPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files
+
+clean-libexecPROGRAMS:
+ @list='$(libexec_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+screenshot$(EXEEXT): $(screenshot_OBJECTS) $(screenshot_DEPENDENCIES) $(EXTRA_screenshot_DEPENDENCIES)
+ @rm -f screenshot$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(screenshot_OBJECTS) $(screenshot_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/screenshot-freedesktop.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/screenshot-gnome-shell.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/screenshot-kwin.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/screenshot-osx.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/screenshot-win32.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/screenshot-x11.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/screenshot.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 $(PROGRAMS)
+installdirs:
+ for dir in "$(DESTDIR)$(libexecdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+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:
+
+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-libexecPROGRAMS clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/screenshot-freedesktop.Po
+ -rm -f ./$(DEPDIR)/screenshot-gnome-shell.Po
+ -rm -f ./$(DEPDIR)/screenshot-kwin.Po
+ -rm -f ./$(DEPDIR)/screenshot-osx.Po
+ -rm -f ./$(DEPDIR)/screenshot-win32.Po
+ -rm -f ./$(DEPDIR)/screenshot-x11.Po
+ -rm -f ./$(DEPDIR)/screenshot.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-libexecPROGRAMS
+
+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)/screenshot-freedesktop.Po
+ -rm -f ./$(DEPDIR)/screenshot-gnome-shell.Po
+ -rm -f ./$(DEPDIR)/screenshot-kwin.Po
+ -rm -f ./$(DEPDIR)/screenshot-osx.Po
+ -rm -f ./$(DEPDIR)/screenshot-win32.Po
+ -rm -f ./$(DEPDIR)/screenshot-x11.Po
+ -rm -f ./$(DEPDIR)/screenshot.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: uninstall-libexecPROGRAMS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libexecPROGRAMS clean-libtool \
+ 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-libexecPROGRAMS \
+ 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 uninstall-libexecPROGRAMS
+
+.PRECIOUS: Makefile
+
+
+@OS_WIN32_TRUE@screenshot-win32-res.o: screenshot-win32.rc screenshot-win32-select.cur screenshot-win32-small.ico screenshot-win32.ico
+@OS_WIN32_TRUE@ $(WINDRES) $(srcdir)/screenshot-win32.rc screenshot-win32-res.o
+
+# 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/plug-ins/screenshot/screenshot-freedesktop.c b/plug-ins/screenshot/screenshot-freedesktop.c
new file mode 100644
index 0000000..206d70a
--- /dev/null
+++ b/plug-ins/screenshot/screenshot-freedesktop.c
@@ -0,0 +1,199 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * Screenshot plug-in
+ * Copyright 1998-2007 Sven Neumann <sven@gimp.org>
+ * Copyright 2003 Henrik Brix Andersen <brix@gimp.org>
+ * Copyright 2016 Michael Natterer <mitch@gimp.org>
+ * Copyright 2017 Jehan <jehan@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 <glib.h>
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "screenshot.h"
+#include "screenshot-freedesktop.h"
+
+
+static GDBusProxy *proxy = NULL;
+
+gboolean
+screenshot_freedesktop_available (void)
+{
+ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
+ NULL,
+ "org.freedesktop.portal.Desktop",
+ "/org/freedesktop/portal/desktop",
+ "org.freedesktop.portal.Screenshot",
+ NULL, NULL);
+
+ if (proxy)
+ {
+ GError *error = NULL;
+
+ g_dbus_proxy_call_sync (proxy, "org.freedesktop.DBus.Peer.Ping",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, NULL, &error);
+ if (! error)
+ return TRUE;
+
+ g_clear_error (&error);
+
+ g_object_unref (proxy);
+ proxy = NULL;
+ }
+
+ return FALSE;
+}
+
+ScreenshotCapabilities
+screenshot_freedesktop_get_capabilities (void)
+{
+ /* Portal has no capabilities other than root screenshot! */
+ return 0;
+}
+
+static void
+screenshot_freedesktop_dbus_signal (GDBusProxy *proxy,
+ gchar *sender_name,
+ gchar *signal_name,
+ GVariant *parameters,
+ gint32 *image_ID)
+{
+ if (g_strcmp0 (signal_name, "Response") == 0)
+ {
+ GVariant *results;
+ guint32 response;
+
+ g_variant_get (parameters, "(u@a{sv})",
+ &response,
+ &results);
+
+ /* Possible values:
+ * 0: Success, the request is carried out
+ * 1: The user cancelled the interaction
+ * 2: The user interaction was ended in some other way
+ * Cf. https://github.com/flatpak/xdg-desktop-portal/blob/master/data/org.freedesktop.portal.Request.xml
+ */
+ if (response == 0)
+ {
+ gchar *uri;
+
+ if (g_variant_lookup (results, "uri", "s", &uri))
+ {
+ GFile *file = g_file_new_for_uri (uri);
+ gchar *path = g_file_get_path (file);
+
+ *image_ID = gimp_file_load (GIMP_RUN_NONINTERACTIVE,
+ path, path);
+ gimp_image_set_filename (*image_ID, "screenshot.png");
+
+ /* Delete the actual file. */
+ g_file_delete (file, NULL, NULL);
+
+ g_object_unref (file);
+ g_free (path);
+ g_free (uri);
+ }
+ }
+
+ g_variant_unref (results);
+ /* Quit anyway. */
+ gtk_main_quit ();
+ }
+}
+
+GimpPDBStatusType
+screenshot_freedesktop_shoot (ScreenshotValues *shootvals,
+ GdkScreen *screen,
+ gint32 *image_ID,
+ GError **error)
+{
+ GVariant *retval;
+ gchar *opath = NULL;
+
+ if (shootvals->shoot_type != SHOOT_ROOT)
+ {
+ /* This should not happen. */
+ return GIMP_PDB_EXECUTION_ERROR;
+ }
+
+ if (shootvals->screenshot_delay > 0)
+ screenshot_delay (shootvals->screenshot_delay);
+
+ retval = g_dbus_proxy_call_sync (proxy, "Screenshot",
+ g_variant_new ("(sa{sv})", "", NULL),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, NULL, error);
+ g_object_unref (proxy);
+ proxy = NULL;
+ if (retval)
+ {
+ g_variant_get (retval, "(o)", &opath);
+ g_variant_unref (retval);
+ }
+
+ if (opath)
+ {
+ GDBusProxy *proxy2 = NULL;
+
+ proxy2 = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
+ NULL,
+ "org.freedesktop.portal.Desktop",
+ opath,
+ "org.freedesktop.portal.Request",
+ NULL, NULL);
+ *image_ID = 0;
+ g_signal_connect (proxy2, "g-signal",
+ G_CALLBACK (screenshot_freedesktop_dbus_signal),
+ image_ID);
+
+ gtk_main ();
+ g_object_unref (proxy2);
+ g_free (opath);
+
+ /* Signal got a response. */
+ if (*image_ID)
+ {
+ GimpColorProfile *profile;
+
+ /* Just assign profile of current monitor. This will work only
+ * as long as this is a single-display setup.
+ * We need to figure out how to do better color management for
+ * portal screenshots.
+ * TODO!
+ */
+ profile = gimp_screen_get_color_profile (screen,
+ shootvals->monitor);
+ if (profile)
+ {
+ gimp_image_set_color_profile (*image_ID, profile);
+ g_object_unref (profile);
+ }
+
+ return GIMP_PDB_SUCCESS;
+ }
+ }
+
+ return GIMP_PDB_EXECUTION_ERROR;
+}
diff --git a/plug-ins/screenshot/screenshot-freedesktop.h b/plug-ins/screenshot/screenshot-freedesktop.h
new file mode 100644
index 0000000..a3a366b
--- /dev/null
+++ b/plug-ins/screenshot/screenshot-freedesktop.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 __SCREENSHOT_FREEDESKTOP_H__
+#define __SCREENSHOT_FREEDESKTOP_H__
+
+
+gboolean screenshot_freedesktop_available (void);
+
+ScreenshotCapabilities screenshot_freedesktop_get_capabilities (void);
+
+GimpPDBStatusType screenshot_freedesktop_shoot (ScreenshotValues *shootvals,
+ GdkScreen *screen,
+ gint32 *image_ID,
+ GError **error);
+
+
+#endif /* __SCREENSHOT_FREEDESKTOP_H__ */
diff --git a/plug-ins/screenshot/screenshot-gnome-shell.c b/plug-ins/screenshot/screenshot-gnome-shell.c
new file mode 100644
index 0000000..8fd531a
--- /dev/null
+++ b/plug-ins/screenshot/screenshot-gnome-shell.c
@@ -0,0 +1,209 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * Screenshot plug-in
+ * Copyright 1998-2007 Sven Neumann <sven@gimp.org>
+ * Copyright 2003 Henrik Brix Andersen <brix@gimp.org>
+ * Copyright 2016 Michael Natterer <mitch@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <glib/gstdio.h> /* g_unlink() */
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "screenshot.h"
+#include "screenshot-gnome-shell.h"
+
+
+static GDBusProxy *proxy = NULL;
+
+
+gboolean
+screenshot_gnome_shell_available (void)
+{
+ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
+ NULL,
+ "org.gnome.Shell.Screenshot",
+ "/org/gnome/Shell/Screenshot",
+ "org.gnome.Shell.Screenshot",
+ NULL, NULL);
+
+ if (proxy)
+ {
+ GError *error = NULL;
+
+ g_dbus_proxy_call_sync (proxy, "org.freedesktop.DBus.Peer.Ping",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, NULL, &error);
+ if (! error)
+ return TRUE;
+
+ g_clear_error (&error);
+
+ g_object_unref (proxy);
+ proxy = NULL;
+ }
+
+ return FALSE;
+}
+
+ScreenshotCapabilities
+screenshot_gnome_shell_get_capabilities (void)
+{
+ return (SCREENSHOT_CAN_SHOOT_DECORATIONS |
+ SCREENSHOT_CAN_SHOOT_POINTER |
+ SCREENSHOT_CAN_SHOOT_REGION |
+ SCREENSHOT_CAN_SHOOT_WINDOW);
+}
+
+GimpPDBStatusType
+screenshot_gnome_shell_shoot (ScreenshotValues *shootvals,
+ GdkScreen *screen,
+ gint32 *image_ID,
+ GError **error)
+{
+ gchar *filename;
+ const gchar *method = NULL;
+ GVariant *args = NULL;
+ GVariant *retval;
+ gint monitor = shootvals->monitor;
+ gboolean success;
+
+ filename = gimp_temp_name ("png");
+
+ switch (shootvals->shoot_type)
+ {
+ case SHOOT_ROOT:
+ if (shootvals->screenshot_delay > 0)
+ screenshot_delay (shootvals->screenshot_delay);
+
+ method = "Screenshot";
+ args = g_variant_new ("(bbs)",
+ shootvals->show_cursor,
+ TRUE, /* flash */
+ filename);
+
+ /* FIXME: figure profile */
+ break;
+
+ case SHOOT_REGION:
+ if (shootvals->select_delay > 0)
+ screenshot_delay (shootvals->select_delay);
+
+ retval = g_dbus_proxy_call_sync (proxy, "SelectArea", NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, NULL, error);
+ if (! retval)
+ goto failure;
+
+ g_variant_get (retval, "(iiii)",
+ &shootvals->x1,
+ &shootvals->y1,
+ &shootvals->x2,
+ &shootvals->y2);
+ g_variant_unref (retval);
+
+ shootvals->x2 += shootvals->x1;
+ shootvals->y2 += shootvals->y1;
+
+ method = "ScreenshotArea";
+ args = g_variant_new ("(iiiibs)",
+ shootvals->x1,
+ shootvals->y1,
+ shootvals->x2 - shootvals->x1,
+ shootvals->y2 - shootvals->y1,
+ TRUE, /* flash */
+ filename);
+
+ monitor =
+ gdk_screen_get_monitor_at_point (screen,
+ (shootvals->x1 + shootvals->x2) / 2,
+ (shootvals->y1 + shootvals->y2) / 2);
+
+ if (shootvals->screenshot_delay > 0)
+ screenshot_delay (shootvals->screenshot_delay);
+ break;
+
+ case SHOOT_WINDOW:
+ if (shootvals->screenshot_delay > 0)
+ screenshot_delay (shootvals->screenshot_delay);
+
+ method = "ScreenshotWindow";
+ args = g_variant_new ("(bbbs)",
+ shootvals->decorate,
+ shootvals->show_cursor,
+ TRUE, /* flash */
+ filename);
+
+ /* FIXME: figure monitor */
+ break;
+ }
+
+ g_free (filename);
+ filename = NULL;
+
+ retval = g_dbus_proxy_call_sync (proxy, method, args,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, NULL, error);
+ if (! retval)
+ goto failure;
+
+ g_variant_get (retval, "(bs)",
+ &success,
+ &filename);
+
+ g_variant_unref (retval);
+
+ if (success && filename)
+ {
+ GimpColorProfile *profile;
+
+ *image_ID = gimp_file_load (GIMP_RUN_NONINTERACTIVE,
+ filename, filename);
+ gimp_image_set_filename (*image_ID, "screenshot.png");
+
+ profile = gimp_screen_get_color_profile (screen, monitor);
+
+ if (profile)
+ {
+ gimp_image_set_color_profile (*image_ID, profile);
+ g_object_unref (profile);
+ }
+
+ g_unlink (filename);
+ g_free (filename);
+
+ g_object_unref (proxy);
+ proxy = NULL;
+
+ return GIMP_PDB_SUCCESS;
+ }
+
+ failure:
+
+ g_free (filename);
+
+ g_object_unref (proxy);
+ proxy = NULL;
+
+ return GIMP_PDB_EXECUTION_ERROR;
+}
diff --git a/plug-ins/screenshot/screenshot-gnome-shell.h b/plug-ins/screenshot/screenshot-gnome-shell.h
new file mode 100644
index 0000000..05a26a2
--- /dev/null
+++ b/plug-ins/screenshot/screenshot-gnome-shell.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 __SCREENSHOT_GNOME_SHELL_H__
+#define __SCREENSHOT_GNOME_SHELL_H__
+
+
+gboolean screenshot_gnome_shell_available (void);
+
+ScreenshotCapabilities screenshot_gnome_shell_get_capabilities (void);
+
+GimpPDBStatusType screenshot_gnome_shell_shoot (ScreenshotValues *shootvals,
+ GdkScreen *screen,
+ gint32 *image_ID,
+ GError **error);
+
+
+#endif /* __SCREENSHOT_GNOME_SHELL_H__ */
diff --git a/plug-ins/screenshot/screenshot-icon.h b/plug-ins/screenshot/screenshot-icon.h
new file mode 100644
index 0000000..4e4de0c
--- /dev/null
+++ b/plug-ins/screenshot/screenshot-icon.h
@@ -0,0 +1,80 @@
+/* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */
+
+#ifdef __SUNPRO_C
+#pragma align 4 (screenshot_icon)
+#endif
+#ifdef __GNUC__
+static const guint8 screenshot_icon[] __attribute__ ((__aligned__ (4))) =
+#else
+static const guint8 screenshot_icon[] =
+#endif
+{ ""
+ /* Pixbuf magic (0x47646b50) */
+ "GdkP"
+ /* length: header (24) + pixel_data (1582) */
+ "\0\0\6F"
+ /* pixdata_type (0x2010002) */
+ "\2\1\0\2"
+ /* rowstride (88) */
+ "\0\0\0X"
+ /* width (22) */
+ "\0\0\0\26"
+ /* height (22) */
+ "\0\0\0\26"
+ /* pixel_data: */
+ "\213\0\0\0\0\1\242\242\242\5\203\242\242\242\31\221\0\0\0\0\2\27\27\26"
+ "D\40\40\40\372\203)))\375\2\32\32\32\362\26\26\25""0\217\0\0\0\0\2\2"
+ "\2\2\322\307\310\307\377\203\377\377\377\377\2\263\263\262\363\0\0\0"
+ "\314\217\0\0\0\0\2\6\6\6\334\206\207\205\377\202\252\253\251\377\3\252"
+ "\252\251\377ghe\376\1\1\1\320\217\0\0\0\0\2\11\11\11\346./-\345\202G"
+ "HE\25\3JKH\32""01/\364\5\5\5\333\212\0\0\0\0\17\26\26\25\31\26\26\25"
+ "0\26\26\25g\0\0\0\314+,+\331LMK\375EFD\362ffe\347iig\346lmk\346RSQ\362"
+ "\13\13\13\360\0\0\0\314\2\2\2\321\26\26\25V\203\0\0\0\0#\26\26\25\31"
+ "\26\26\25""0\26\26\25n\3\3\3\331\2\2\2\332JJI\355\215\215\215\372\246"
+ "\246\246\347\267\270\266\362\177\202~\377BC\77\377TUR\377\\]Y\377gid"
+ "\377[]X\377\204\206\204\374wxw\276\224\225\224\314LLK\343\26\26\25D\0"
+ "\0\0\0\26\26\25D\3\3\3\341\17\17\17\373ghg\377\237\240\236\377\273\274"
+ "\272\377\302\303\300\377\272\273\270\377\200\201\177\377zzz\377tws\377"
+ "\220\223\217\377\221\225\221\377\224\227\223\377\202\226\232\226\377"
+ "K\177\202}\377xyu\377\217\221\215\377\226\227\226\365\0\0\0\371\0\0\0"
+ "\0\2\2\2\330\257\261\257\377\275\276\273\377\262\263\260\377UWT\377Q"
+ "SP\377suq\377]^[\377\304\304\304\377\303\303\303\377kmi\377MNJ\377WZ"
+ "X\377[`_\377aeb\377gid\377}\200{\377SUQ\377FGE\377\200\201\200\377\12"
+ "\12\12\357\0\0\0\0\4\4\4\345xyv\377\241\242\236\377\210\212\205\377v"
+ "xt\377\220\222\217\377GIF\377+,)\377```\377jji\377UXV\377y\204\210\377"
+ "\203\215\220\377~\204\207\377flo\377PW\\\377SWU\377JLI\377452\377tut"
+ "\377\12\12\12\357\0\0\0\0\4\4\4\344opm\377\221\223\217\377}\177{\377"
+ "\215\217\213\377`b_\377()'\377*+)\377785\377VXV\377u~\202\377nsu\377"
+ "VYZ\377OST\377OQS\377JOP\377^cd\377698\377!\"!\377llk\377\12\12\12\357"
+ "\0\0\0\0\3\3\3\345npl\377\220\221\216\377\202UWS\377\24GIF\377\40!\37"
+ "\377*+)\3779:7\377^ce\377NRT\377UXY\377(,.\377\22\24\25\377!$&\377IL"
+ "M\3778=\77\377RVX\377''&\377klk\377\12\12\12\357\0\0\0\1\3\3\3\345no"
+ "l\377\220\221\216\377\202UWS\377\24GIF\377\40!\37\377*+)\3778:8\377T"
+ "XY\377289\377\23\25\26\377\16\16\16\377\1\1\1\377\2\2\2\377\24\25\25"
+ "\377.34\377289\377011\377aa`\377\11\11\11\360\0\0\0\3\3\3\3\345nol\377"
+ "\204\205\202\377\202UWS\377\24GIF\377\40!\37\377*+)\377\77BA\37728:\377"
+ "\34\40!\377\31\32\32\377\377\377\377\377hhh\377\40\40\40\377\22\22\22"
+ "\377.00\377.46\377:>\77\377`a`\377\11\11\10\361\0\0\0\7\3\3\3\345mok"
+ "\377z{x\377\202UWS\377\24GIF\377\40!\37\377*+)\377HJI\377.46\377\25\27"
+ "\30\377\40\40\40\377hhh\377\232\232\232\377}}}\377'''\3779;;\377/57\377"
+ "599\377``_\377\11\11\10\362\0\0\0\15\3\3\3\345lnk\377rsp\377\202UWS\377"
+ "\24GIF\377\40!\37\377,-*\377>@>\377.46\377\35\37\40\377\1\1\1\377888"
+ "\377\214\214\214\377\213\213\213\377AAA\377JKK\377/57\3776:;\377WXV\377"
+ "\6\6\6\364\0\0\0\21\0\0\0\371\201\202\177\377mok\377\202UWS\377iGIF\377"
+ "MNM\377RRR\372ghg\364[`b\377+/0\377\17\17\17\377\"\"\"\377'''\377HHH"
+ "\377\263\263\263\377SUU\377W\\^\377CFF\374<<<\376\20\20\17\317\0\0\0"
+ "\20\24\24\23]\4\4\4\353\177\177~\375|}z\373}~|\374hih\3769:9\371\0\0"
+ "\0\347\0\0\0\351\7\7\7\367.46\377256\377\40\40\40\377(((\377:::\377`"
+ "ab\3779>\77\377\11\13\13\376\0\0\0\353\0\0\0\300\14\14\13H\0\0\0\15\0"
+ "\0\0\4\23\23\22L\0\0\0\332\0\0\0\341\0\0\0\346\0\0\0\341\14\14\13{\0"
+ "\0\0V\0\0\0a\0\0\0l\10\11\11\371\\^_\377LOP\377ILL\377LOQ\377QUV\377"
+ "\16\17\17\377\34\37\40\244\0\0\0`\0\0\0""4\0\0\0\27\0\0\0\7\0\0\0\1\0"
+ "\0\0\3\0\0\0\10\0\0\0\21\0\0\0\34\0\0\0'\0\0\0""0\0\0\0""6\0\0\0=\0\0"
+ "\0A\0\0\0F\4\5\5\355\12\13\13\371\17\20\20\376\15\16\16\375\10\10\11"
+ "\365\7\10\11j\0\0\0G\0\0\0-\0\0\0\30\0\0\0\13\0\0\0\4\0\0\0\0\0\0\0\1"
+ "\0\0\0\2\0\0\0\4\0\0\0\11\0\0\0\16\0\0\0\23\0\0\0\31\0\0\0\35\0\0\0!"
+ "\0\0\0#\0\0\0$\0\0\0%\0\0\0$\0\0\0&\0\0\0%\0\0\0\36\0\0\0\27\0\0\0\20"
+ "\0\0\0\10\0\0\0\3\0\0\0\1\204\0\0\0\0\5\0\0\0\1\0\0\0\2\0\0\0\4\0\0\0"
+ "\5\0\0\0\6\202\0\0\0\10\11\0\0\0\11\0\0\0\7\0\0\0\10\0\0\0\5\0\0\0\7"
+ "\0\0\0\6\0\0\0\5\0\0\0\3\0\0\0\1\202\0\0\0\0"
+};
diff --git a/plug-ins/screenshot/screenshot-kwin.c b/plug-ins/screenshot/screenshot-kwin.c
new file mode 100644
index 0000000..21db1f3
--- /dev/null
+++ b/plug-ins/screenshot/screenshot-kwin.c
@@ -0,0 +1,207 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * Screenshot plug-in
+ * Copyright 1998-2007 Sven Neumann <sven@gimp.org>
+ * Copyright 2003 Henrik Brix Andersen <brix@gimp.org>
+ * Copyright 2016 Michael Natterer <mitch@gimp.org>
+ * Copyright 2017 Jehan <jehan@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 <glib.h>
+#include <glib/gstdio.h> /* g_unlink() */
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "screenshot.h"
+#include "screenshot-kwin.h"
+
+
+static GDBusProxy *proxy = NULL;
+
+
+gboolean
+screenshot_kwin_available (void)
+{
+ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
+ NULL,
+ "org.kde.KWin",
+ "/Screenshot",
+ "org.kde.kwin.Screenshot",
+ NULL, NULL);
+
+ if (proxy)
+ {
+ GError *error = NULL;
+
+ g_dbus_proxy_call_sync (proxy, "org.freedesktop.DBus.Peer.Ping",
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, NULL, &error);
+ if (! error)
+ return TRUE;
+
+ g_clear_error (&error);
+
+ g_object_unref (proxy);
+ proxy = NULL;
+ }
+
+ return FALSE;
+}
+
+ScreenshotCapabilities
+screenshot_kwin_get_capabilities (void)
+{
+ return (SCREENSHOT_CAN_SHOOT_DECORATIONS |
+ SCREENSHOT_CAN_SHOOT_POINTER |
+ SCREENSHOT_CAN_SHOOT_WINDOW |
+ SCREENSHOT_CAN_PICK_WINDOW);
+ /* TODO: SCREENSHOT_CAN_SHOOT_REGION.
+ * The KDE API has "screenshotArea" method but no method to get
+ * coordinates could be found. See below.
+ */
+}
+
+GimpPDBStatusType
+screenshot_kwin_shoot (ScreenshotValues *shootvals,
+ GdkScreen *screen,
+ gint32 *image_ID,
+ GError **error)
+{
+ gchar *filename = NULL;
+ const gchar *method = NULL;
+ GVariant *args = NULL;
+ GVariant *retval;
+ gint monitor = shootvals->monitor;
+ gint32 mask;
+
+ switch (shootvals->shoot_type)
+ {
+ case SHOOT_ROOT:
+ if (shootvals->screenshot_delay > 0)
+ screenshot_delay (shootvals->screenshot_delay);
+ else
+ {
+ /* As an exception, I force a delay of at least 0.5 seconds
+ * for KWin. Because of windows effect slowly fading out, the
+ * screenshot plug-in GUI was constantly visible (with
+ * transparency as it is fading out) in 0s-delay screenshots.
+ */
+ g_usleep (500000);
+ }
+
+ method = "screenshotFullscreen";
+ args = g_variant_new ("(b)", shootvals->show_cursor);
+
+ /* FIXME: figure profile */
+ break;
+
+ case SHOOT_REGION:
+ break;
+ /* FIXME: GNOME-shell has a "SelectArea" returning coordinates
+ * which can be fed to "ScreenshotArea". KDE has the equivalent
+ * "screenshotArea", but no "SelectArea" equivalent that I could
+ * find.
+ * Also at first, I expected "interactive" method to take care of
+ * the whole selecting-are-then-screenshotting workflow, but this
+ * is apparently only made to select interactively a specific
+ * window, not an area.
+ */
+ method = "screenshotArea";
+ args = g_variant_new ("(iiii)",
+ shootvals->x1,
+ shootvals->y1,
+ shootvals->x2 - shootvals->x1,
+ shootvals->y2 - shootvals->y1);
+ args = NULL;
+
+ break;
+
+ case SHOOT_WINDOW:
+ if (shootvals->select_delay > 0)
+ screenshot_delay (shootvals->select_delay);
+
+ /* XXX I expected "screenshotWindowUnderCursor" method to be the
+ * right one, but it returns nothing, nor is there a file
+ * descriptor in argument. So I don't understand how to grab the
+ * screenshot. Also "interactive" changes the cursor to a
+ * crosshair, waiting for click, which is more helpful than
+ * immediate screenshot under cursor.
+ */
+ method = "interactive";
+ mask = (shootvals->decorate ? 1 : 0) |
+ (shootvals->show_cursor ? 1 << 1 : 0);
+ args = g_variant_new ("(i)", mask);
+
+ /* FIXME: figure monitor */
+ break;
+ }
+
+ retval = g_dbus_proxy_call_sync (proxy, method, args,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, NULL, error);
+ if (! retval)
+ goto failure;
+
+ g_variant_get (retval, "(s)",
+ &filename);
+ g_variant_unref (retval);
+
+ if (filename)
+ {
+ GimpColorProfile *profile;
+
+ *image_ID = gimp_file_load (GIMP_RUN_NONINTERACTIVE,
+ filename, filename);
+ gimp_image_set_filename (*image_ID, "screenshot.png");
+
+ /* This is very wrong in multi-display setups since we have no
+ * idea which profile is to be used. Let's keep it anyway and
+ * assume always the monitor 0, which will still work in common
+ * cases.
+ */
+ profile = gimp_screen_get_color_profile (screen, monitor);
+
+ if (profile)
+ {
+ gimp_image_set_color_profile (*image_ID, profile);
+ g_object_unref (profile);
+ }
+
+ g_unlink (filename);
+ g_free (filename);
+
+ g_object_unref (proxy);
+ proxy = NULL;
+
+ return GIMP_PDB_SUCCESS;
+ }
+
+ failure:
+
+ if (filename)
+ g_free (filename);
+
+ g_object_unref (proxy);
+ proxy = NULL;
+
+ return GIMP_PDB_EXECUTION_ERROR;
+}
diff --git a/plug-ins/screenshot/screenshot-kwin.h b/plug-ins/screenshot/screenshot-kwin.h
new file mode 100644
index 0000000..85eb58c
--- /dev/null
+++ b/plug-ins/screenshot/screenshot-kwin.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 __SCREENSHOT_KWIN_H__
+#define __SCREENSHOT_KWIN_H__
+
+
+gboolean screenshot_kwin_available (void);
+
+ScreenshotCapabilities screenshot_kwin_get_capabilities (void);
+
+GimpPDBStatusType screenshot_kwin_shoot (ScreenshotValues *shootvals,
+ GdkScreen *screen,
+ gint32 *image_ID,
+ GError **error);
+
+
+#endif /* __SCREENSHOT_KWIN_H__ */
diff --git a/plug-ins/screenshot/screenshot-osx.c b/plug-ins/screenshot/screenshot-osx.c
new file mode 100644
index 0000000..dcd9372
--- /dev/null
+++ b/plug-ins/screenshot/screenshot-osx.c
@@ -0,0 +1,159 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * Screenshot plug-in
+ * Copyright 1998-2007 Sven Neumann <sven@gimp.org>
+ * Copyright 2003 Henrik Brix Andersen <brix@gimp.org>
+ * Copyright 2012 Simone Karin Lehmann - OS X patches
+ *
+ * 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"
+
+#ifdef PLATFORM_OSX
+
+#include <stdlib.h> /* for system() on OSX */
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gstdio.h> /* g_unlink() */
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "screenshot.h"
+#include "screenshot-osx.h"
+
+
+/*
+ * Mac OS X uses a rootless X server. This won't let us use
+ * gdk_pixbuf_get_from_drawable() and similar function on the root
+ * window to get the entire screen contents. With a native OS X build
+ * we have to do this without X as well.
+ *
+ * Since Mac OS X 10.2 a system utility for screencapturing is
+ * included. We can safely use this, since it's available on every OS
+ * X version GIMP is running on.
+ *
+ * The main drawbacks are that it's not possible to shoot windows or
+ * regions in scripts in noninteractive mode, and that windows always
+ * include decorations, since decorations are different between X11
+ * windows and native OS X app windows. But we can use this switch
+ * to capture the shadow of a window, which is indeed very Mac-ish.
+ *
+ * This routines works well with X11 and as a native build.
+ */
+
+gboolean
+screenshot_osx_available (void)
+{
+ return TRUE;
+}
+
+ScreenshotCapabilities
+screenshot_osx_get_capabilities (void)
+{
+ return (SCREENSHOT_CAN_SHOOT_DECORATIONS |
+ SCREENSHOT_CAN_SHOOT_POINTER |
+ SCREENSHOT_CAN_SHOOT_REGION |
+ SCREENSHOT_CAN_SHOOT_WINDOW |
+ SCREENSHOT_CAN_PICK_WINDOW |
+ SCREENSHOT_CAN_DELAY_WINDOW_SHOT);
+}
+
+GimpPDBStatusType
+screenshot_osx_shoot (ScreenshotValues *shootvals,
+ GdkScreen *screen,
+ gint32 *image_ID,
+ GError **error)
+{
+ const gchar *mode = " ";
+ const gchar *cursor = " ";
+ gchar *delay = NULL;
+ gchar *filename;
+ gchar *quoted;
+ gchar *command = NULL;
+
+ switch (shootvals->shoot_type)
+ {
+ case SHOOT_REGION:
+ if (shootvals->select_delay > 0)
+ screenshot_delay (shootvals->select_delay);
+
+ mode = "-is";
+ break;
+
+ case SHOOT_WINDOW:
+ if (shootvals->select_delay > 0)
+ screenshot_delay (shootvals->select_delay);
+
+ if (shootvals->decorate)
+ mode = "-iwo";
+ else
+ mode = "-iw";
+ if (shootvals->show_cursor)
+ cursor = "-C";
+ break;
+
+ case SHOOT_ROOT:
+ mode = " ";
+ if (shootvals->show_cursor)
+ cursor = "-C";
+ break;
+
+ default:
+ g_return_val_if_reached (GIMP_PDB_CALLING_ERROR);
+ break;
+ }
+
+ delay = g_strdup_printf ("-T %i", shootvals->screenshot_delay);
+
+ filename = gimp_temp_name ("png");
+ quoted = g_shell_quote (filename);
+
+ command = g_strjoin (" ",
+ "/usr/sbin/screencapture",
+ mode,
+ cursor,
+ delay,
+ quoted,
+ NULL);
+
+ g_free (quoted);
+ g_free (delay);
+
+ if (system ((const char *) command) == EXIT_SUCCESS)
+ {
+ /* don't attach a profile, screencapture attached one
+ */
+
+ *image_ID = gimp_file_load (GIMP_RUN_NONINTERACTIVE,
+ filename, filename);
+ gimp_image_set_filename (*image_ID, "screenshot.png");
+
+ g_unlink (filename);
+ g_free (filename);
+ g_free (command);
+
+ return GIMP_PDB_SUCCESS;
+ }
+
+ g_free (command);
+ g_free (filename);
+
+ return GIMP_PDB_EXECUTION_ERROR;
+}
+
+#endif /* PLATFORM_OSX */
diff --git a/plug-ins/screenshot/screenshot-osx.h b/plug-ins/screenshot/screenshot-osx.h
new file mode 100644
index 0000000..40a9875
--- /dev/null
+++ b/plug-ins/screenshot/screenshot-osx.h
@@ -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/>.
+ */
+
+#ifndef __SCREENSHOT_OSX_H__
+#define __SCREENSHOT_OSX_H__
+
+
+#ifdef PLATFORM_OSX
+
+gboolean screenshot_osx_available (void);
+
+ScreenshotCapabilities screenshot_osx_get_capabilities (void);
+
+GimpPDBStatusType screenshot_osx_shoot (ScreenshotValues *shootvals,
+ GdkScreen *screen,
+ gint32 *image_ID,
+ GError **error);
+
+#endif /* PLATFORM_OSX */
+
+
+#endif /* __SCREENSHOT_OSX_H__ */
diff --git a/plug-ins/screenshot/screenshot-win32-dwm-api.h b/plug-ins/screenshot/screenshot-win32-dwm-api.h
new file mode 100644
index 0000000..c99513f
--- /dev/null
+++ b/plug-ins/screenshot/screenshot-win32-dwm-api.h
@@ -0,0 +1,72 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * screenshot-win32-dwm-api.h
+ * Copyright (C) 2018 Gil Eliyahu <gileli121@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+void UnloadRequiredDwmFunctions (void);
+BOOL LoadRequiredDwmFunctions (void);
+
+typedef HRESULT (WINAPI* DWMGETWINDOWATTRIBUTE)(HWND, DWORD, _Out_ PVOID, DWORD);
+DWMGETWINDOWATTRIBUTE DwmGetWindowAttribute;
+
+typedef enum _DWMWINDOWATTRIBUTE {
+ DWMWA_NCRENDERING_ENABLED = 1,
+ DWMWA_NCRENDERING_POLICY,
+ DWMWA_TRANSITIONS_FORCEDISABLED,
+ DWMWA_ALLOW_NCPAINT,
+ DWMWA_CAPTION_BUTTON_BOUNDS,
+ DWMWA_NONCLIENT_RTL_LAYOUT,
+ DWMWA_FORCE_ICONIC_REPRESENTATION,
+ DWMWA_FLIP3D_POLICY,
+ DWMWA_EXTENDED_FRAME_BOUNDS,
+ DWMWA_HAS_ICONIC_BITMAP,
+ DWMWA_DISALLOW_PEEK,
+ DWMWA_EXCLUDED_FROM_PEEK,
+ DWMWA_CLOAK,
+ DWMWA_CLOAKED,
+ DWMWA_FREEZE_REPRESENTATION,
+ DWMWA_LAST
+} DWMWINDOWATTRIBUTE;
+
+static HMODULE dwmApi = NULL;
+
+void
+UnloadRequiredDwmFunctions (void)
+{
+ if (! dwmApi) return;
+ FreeLibrary(dwmApi);
+ dwmApi = NULL;
+}
+
+BOOL
+LoadRequiredDwmFunctions (void)
+{
+ if (dwmApi) return TRUE;
+
+ dwmApi = LoadLibrary ("dwmapi");
+ if (! dwmApi) return FALSE;
+
+ DwmGetWindowAttribute = (DWMGETWINDOWATTRIBUTE) GetProcAddress (dwmApi, "DwmGetWindowAttribute");
+ if (! DwmGetWindowAttribute)
+ {
+ UnloadRequiredDwmFunctions ();
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/plug-ins/screenshot/screenshot-win32-magnification-api.h b/plug-ins/screenshot/screenshot-win32-magnification-api.h
new file mode 100644
index 0000000..ff3a824
--- /dev/null
+++ b/plug-ins/screenshot/screenshot-win32-magnification-api.h
@@ -0,0 +1,154 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * Magnification-win32.h
+ * Copyright (C) 2018 Gil Eliyahu
+ *
+ * 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 <winapifamily.h>
+
+#pragma region Desktop Family
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+
+#ifndef __wincodec_h__
+#include <wincodec.h>
+#endif
+
+#define WC_MAGNIFIERA "Magnifier"
+#define WC_MAGNIFIERW L"Magnifier"
+
+#ifdef UNICODE
+#define WC_MAGNIFIER WC_MAGNIFIERW
+#else
+#define WC_MAGNIFIER WC_MAGNIFIERA
+#endif
+
+#else
+#define WC_MAGNIFIER "Magnifier"
+#endif
+
+/* Magnifier Window Styles */
+#define MS_SHOWMAGNIFIEDCURSOR 0x0001L
+#define MS_CLIPAROUNDCURSOR 0x0002L
+#define MS_INVERTCOLORS 0x0004L
+
+
+/* Filter Modes */
+#define MW_FILTERMODE_EXCLUDE 0
+#define MW_FILTERMODE_INCLUDE 1
+
+
+/* Structures */
+typedef struct tagMAGTRANSFORM
+{
+ float v[3][3];
+} MAGTRANSFORM, *PMAGTRANSFORM;
+
+typedef struct tagMAGIMAGEHEADER
+{
+ UINT width;
+ UINT height;
+ WICPixelFormatGUID format;
+ UINT stride;
+ UINT offset;
+ SIZE_T cbSize;
+} MAGIMAGEHEADER, *PMAGIMAGEHEADER;
+
+typedef struct tagMAGCOLOREFFECT
+{
+ float transform[5][5];
+} MAGCOLOREFFECT, *PMAGCOLOREFFECT;
+
+
+/* Proptypes for the public functions */
+typedef BOOL(WINAPI* MAGINITIALIZE)();
+MAGINITIALIZE MagInitialize;
+
+typedef BOOL(WINAPI* MAGUNINITIALIZE)();
+MAGUNINITIALIZE MagUninitialize;
+
+typedef BOOL(WINAPI* MAGSETWINDOWSOURCE)(HWND, RECT);
+MAGSETWINDOWSOURCE MagSetWindowSource;
+
+typedef BOOL(WINAPI* MAGSETWINDOWFILTERLIST)(HWND, DWORD, int, HWND*);
+MAGSETWINDOWFILTERLIST MagSetWindowFilterList;
+
+typedef BOOL(CALLBACK* MagImageScalingCallback)(HWND hwnd, void * srcdata, MAGIMAGEHEADER srcheader, void * destdata, MAGIMAGEHEADER destheader, RECT unclipped, RECT clipped, HRGN dirty);
+
+typedef BOOL(WINAPI* MAGSETIMAGESCALINGCALLBACK)(HWND, MagImageScalingCallback);
+MAGSETIMAGESCALINGCALLBACK MagSetImageScalingCallback;
+
+
+/* Library DLL */
+static HINSTANCE magnificationLibrary;
+
+
+void UnLoadMagnificationLibrary(void);
+BOOL LoadMagnificationLibrary(void);
+
+
+void UnLoadMagnificationLibrary()
+{
+ if (!magnificationLibrary) return;
+ FreeLibrary(magnificationLibrary);
+}
+
+
+
+BOOL LoadMagnificationLibrary()
+{
+ if (magnificationLibrary) return TRUE;
+
+ magnificationLibrary = LoadLibrary("Magnification");
+ if (!magnificationLibrary) return FALSE;
+
+ MagInitialize = (MAGINITIALIZE)GetProcAddress(magnificationLibrary,"MagInitialize");
+ if (!MagInitialize)
+ {
+ UnLoadMagnificationLibrary();
+ return FALSE;
+ }
+
+ MagUninitialize = (MAGUNINITIALIZE)GetProcAddress(magnificationLibrary, "MagUninitialize");
+ if (!MagUninitialize)
+ {
+ UnLoadMagnificationLibrary();
+ return FALSE;
+ }
+
+ MagSetWindowSource = (MAGSETWINDOWSOURCE)GetProcAddress(magnificationLibrary, "MagSetWindowSource");
+ if (!MagSetWindowSource)
+ {
+ UnLoadMagnificationLibrary();
+ return FALSE;
+ }
+
+ MagSetWindowFilterList = (MAGSETWINDOWFILTERLIST)GetProcAddress(magnificationLibrary, "MagSetWindowFilterList");
+ if (!MagSetWindowFilterList)
+ {
+ UnLoadMagnificationLibrary();
+ return FALSE;
+ }
+
+ MagSetImageScalingCallback = (MAGSETIMAGESCALINGCALLBACK)GetProcAddress(magnificationLibrary, "MagSetImageScalingCallback");
+ if (!MagSetImageScalingCallback)
+ {
+ UnLoadMagnificationLibrary();
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/plug-ins/screenshot/screenshot-win32-resource.h b/plug-ins/screenshot/screenshot-win32-resource.h
new file mode 100644
index 0000000..57b6ec2
--- /dev/null
+++ b/plug-ins/screenshot/screenshot-win32-resource.h
@@ -0,0 +1,26 @@
+/* {{NO_DEPENDENCIES}}
+ Microsoft Developer Studio generated include file.
+ Used by snappy.rc
+*/
+#define IDM_CAPTURE 100
+#define IDM_EXIT 101
+
+#define IDC_SELECT 102
+#define IDD_SELECT 103
+#define IDC_TEXT 1000
+#define IDC_GROUP 1001
+#define IDM_CAPTUREFULL 40003
+#define IDM_HOOK 40004
+#define IDM_UNHOOK 40005
+
+/* Next default values for new objects */
+
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 104
+#define _APS_NEXT_COMMAND_VALUE 40006
+#define _APS_NEXT_CONTROL_VALUE 1002
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/plug-ins/screenshot/screenshot-win32-select.cur b/plug-ins/screenshot/screenshot-win32-select.cur
new file mode 100644
index 0000000..2357f84
--- /dev/null
+++ b/plug-ins/screenshot/screenshot-win32-select.cur
Binary files differ
diff --git a/plug-ins/screenshot/screenshot-win32-small.ico b/plug-ins/screenshot/screenshot-win32-small.ico
new file mode 100644
index 0000000..33f9a51
--- /dev/null
+++ b/plug-ins/screenshot/screenshot-win32-small.ico
Binary files differ
diff --git a/plug-ins/screenshot/screenshot-win32.c b/plug-ins/screenshot/screenshot-win32.c
new file mode 100644
index 0000000..a9dd831
--- /dev/null
+++ b/plug-ins/screenshot/screenshot-win32.c
@@ -0,0 +1,1278 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * Screenshot plug-in
+ * Copyright 1998-2007 Sven Neumann <sven@gimp.org>
+ * Copyright 2003 Henrik Brix Andersen <brix@gimp.org>
+ * Copyright 2012 Simone Karin Lehmann - OS X patches
+ * Copyright 2018 Gil Eliyahu <gileli121@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <glib.h>
+
+#ifdef G_OS_WIN32
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Necessary in order to have SetProcessDPIAware() defined.
+ * This value of _WIN32_WINNT corresponds to Windows 7, which is our
+ * minimum supported platform.
+ */
+#ifdef _WIN32_WINNT
+#undef _WIN32_WINNT
+#endif
+#define _WIN32_WINNT 0x0601
+#include <windows.h>
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "screenshot.h"
+#include "screenshot-win32.h"
+#include "screenshot-win32-resource.h"
+
+#include "libgimp/stdplugins-intl.h"
+#include "screenshot-win32-magnification-api.h"
+#include "screenshot-win32-dwm-api.h"
+
+/*
+ * Application definitions
+ */
+#define SELECT_FRAME 0
+#define SELECT_CLIENT 1
+#define SELECT_WINDOW 2
+
+#define SHOW_WINDOW FALSE
+#define APP_NAME "plug_in_screenshot_win"
+#define WM_DOCAPTURE (WM_USER + 100)
+
+/* Prototypes */
+void setCaptureType (int capType);
+BOOL InitApplication (HINSTANCE hInstance);
+BOOL InitInstance (HINSTANCE hInstance,
+ int nCmdShow);
+int winsnapWinMain (void);
+
+/* File variables */
+static int captureType;
+static char buffer[512];
+static guchar *capBytes = NULL;
+static HWND mainHwnd = NULL;
+static HINSTANCE hInst = NULL;
+static HCURSOR selectCursor = 0;
+static ICONINFO iconInfo;
+static MAGIMAGEHEADER returnedSrcheader;
+static int rectScreensCount = 0;
+
+static gint32 *image_id;
+
+static void sendBMPToGimp (HBITMAP hBMP,
+ HDC hDC,
+ RECT rect);
+static int doWindowCapture (void);
+static gboolean doCapture (HWND selectedHwnd);
+static BOOL isWindowIsAboveCaptureRegion (HWND hwndWindow,
+ RECT rectCapture);
+static gboolean doCaptureMagnificationAPI (HWND selectedHwnd,
+ RECT rect);
+static void doCaptureMagnificationAPI_callback (HWND hwnd,
+ void *srcdata,
+ MAGIMAGEHEADER srcheader,
+ void *destdata,
+ MAGIMAGEHEADER destheader,
+ RECT unclipped,
+ RECT clipped,
+ HRGN dirty);
+static gboolean doCaptureBitBlt (HWND selectedHwnd,
+ RECT rect);
+
+BOOL CALLBACK dialogProc (HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
+
+/* Data structure holding data between runs */
+typedef struct {
+ gint root;
+ guint delay;
+ gint decor;
+} WinSnapValues;
+
+/* Default WinSnap values */
+static WinSnapValues winsnapvals =
+{
+ FALSE,
+ 0,
+ TRUE,
+};
+
+/* The dialog information */
+typedef struct {
+#ifdef CAN_SET_DECOR
+ GtkWidget *decor_button;
+#endif
+ GtkWidget *single_button;
+ GtkWidget *root_button;
+ GtkWidget *delay_spinner;
+} WinSnapInterface;
+
+/* We create a DIB section to hold the grabbed area. The scanlines in
+ * DIB sections are aligned on a LONG (four byte) boundary. Its pixel
+ * data is in RGB (BGR actually) format, three bytes per pixel.
+ *
+ * GIMP uses no alignment for its pixel regions. The GIMP image we
+ * create is of type RGB, i.e. three bytes per pixel, too. Thus in
+ * order to be able to quickly transfer all of the image at a time, we
+ * must use a DIB section and pixel region the scanline width in
+ * bytes of which is evenly divisible with both 3 and 4. I.e. it must
+ * be a multiple of 12 bytes, or in pixels, a multiple of four pixels.
+ */
+
+#define ROUND4(width) (((width-1)/4+1)*4)
+
+
+gboolean
+screenshot_win32_available (void)
+{
+ return TRUE;
+}
+
+ScreenshotCapabilities
+screenshot_win32_get_capabilities (void)
+{
+ return (SCREENSHOT_CAN_SHOOT_DECORATIONS |
+ SCREENSHOT_CAN_SHOOT_WINDOW);
+}
+
+GimpPDBStatusType
+screenshot_win32_shoot (ScreenshotValues *shootvals,
+ GdkScreen *screen,
+ gint32 *image_ID,
+ GError **error)
+{
+ GimpPDBStatusType status = GIMP_PDB_EXECUTION_ERROR;
+
+ /* leave "shootvals->monitor" alone until somebody patches the code
+ * to be able to get a monitor's color profile
+ */
+
+ image_id = image_ID;
+
+ winsnapvals.delay = shootvals->screenshot_delay;
+
+ if (shootvals->shoot_type == SHOOT_ROOT)
+ {
+ doCapture (0);
+
+ status = GIMP_PDB_SUCCESS;
+ }
+ else if (shootvals->shoot_type == SHOOT_WINDOW)
+ {
+ status = 0 == doWindowCapture () ? GIMP_PDB_CANCEL : GIMP_PDB_SUCCESS;
+ }
+ else if (shootvals->shoot_type == SHOOT_REGION)
+ {
+ /* FIXME */
+ }
+
+ if (status == GIMP_PDB_SUCCESS)
+ {
+ GimpColorProfile *profile;
+
+ /* XXX No idea if the "monitor" value is right at all, especially
+ * considering above comment. Just make so that it at least
+ * compiles!
+ */
+ profile = gimp_screen_get_color_profile (screen, shootvals->monitor);
+
+ if (profile)
+ {
+ gimp_image_set_color_profile (*image_ID, profile);
+ g_object_unref (profile);
+ }
+ }
+
+ return status;
+}
+
+
+
+
+
+/******************************************************************
+ * GIMP format and transfer functions
+ ******************************************************************/
+
+/*
+ * flipRedAndBlueBytes
+ *
+ * Microsoft has chosen to provide us a very nice (not!)
+ * interface for retrieving bitmap bits. DIBSections have
+ * RGB information as BGR instead. So, we have to swap
+ * the silly red and blue bytes before sending to the
+ * GIMP.
+ */
+static void
+flipRedAndBlueBytes (int width,
+ int height)
+{
+ int i, j;
+ guchar *bufp;
+ guchar temp;
+
+ j = 0;
+ while (j < height) {
+ i = width;
+ bufp = capBytes + j*ROUND4(width)*3;
+ while (i--) {
+ temp = bufp[2];
+ bufp[2] = bufp[0];
+ bufp[0] = temp;
+ bufp += 3;
+ }
+ j++;
+ }
+}
+
+/*
+ * rgbaToRgbBytes
+ *
+ * Convert rgba array to rgb array
+ */
+static void
+rgbaToRgbBytes (guchar *rgbBufp,
+ guchar *rgbaBufp,
+ int rgbaBufSize)
+{
+ int rgbPoint = 0, rgbaPoint;
+
+ for (rgbaPoint = 0; rgbaPoint < rgbaBufSize; rgbaPoint += 4)
+ {
+ rgbBufp[rgbPoint++] = rgbaBufp[rgbaPoint];
+ rgbBufp[rgbPoint++] = rgbaBufp[rgbaPoint + 1];
+ rgbBufp[rgbPoint++] = rgbaBufp[rgbaPoint + 2];
+ }
+}
+
+/*
+ * sendBMPToGIMP
+ *
+ * Take the captured data and send it across
+ * to GIMP.
+ */
+static void
+sendBMPToGimp (HBITMAP hBMP,
+ HDC hDC,
+ RECT rect)
+{
+ int width, height;
+ int imageType, layerType;
+ gint32 new_image_id;
+ gint32 layer_id;
+ GeglBuffer *buffer;
+ GeglRectangle *rectangle;
+
+ /* Our width and height */
+ width = (rect.right - rect.left);
+ height = (rect.bottom - rect.top);
+
+ /* Check that we got the memory */
+ if (!capBytes)
+ {
+ g_message (_("No data captured"));
+ return;
+ }
+
+ /* Flip the red and blue bytes */
+ flipRedAndBlueBytes (width, height);
+
+ /* Set up the image and layer types */
+ imageType = GIMP_RGB;
+ layerType = GIMP_RGB_IMAGE;
+
+ /* Create the GIMP image and layers */
+ new_image_id = gimp_image_new (width, height, imageType);
+ layer_id = gimp_layer_new (new_image_id, _("Background"),
+ ROUND4 (width), height,
+ layerType,
+ 100,
+ gimp_image_get_default_new_layer_mode (new_image_id));
+ gimp_image_insert_layer (new_image_id, layer_id, -1, 0);
+
+ /* make rectangle */
+ rectangle = g_new (GeglRectangle, 1);
+ rectangle->x = 0;
+ rectangle->y = 0;
+ rectangle->width = ROUND4(width);
+ rectangle->height = height;
+
+ /* get the buffer */
+ buffer = gimp_drawable_get_buffer (layer_id);
+
+ /* fill the buffer */
+ gegl_buffer_set (buffer, rectangle, 0, NULL, (guchar *) capBytes,
+ GEGL_AUTO_ROWSTRIDE);
+
+ /* flushing data */
+ gegl_buffer_flush (buffer);
+
+ /* Now resize the layer down to the correct size if necessary. */
+ if (width != ROUND4 (width))
+ {
+ gimp_layer_resize (layer_id, width, height, 0, 0);
+ gimp_image_resize (new_image_id, width, height, 0, 0);
+ }
+
+ *image_id = new_image_id;
+
+ return;
+}
+
+/*
+ * doNonRootWindowCapture
+ *
+ * Capture a selected window.
+ * ENTRY POINT FOR WINSNAP NONROOT
+ *
+ */
+static int
+doWindowCapture (void)
+{
+ /* Start up a standard Win32
+ * message handling loop for
+ * selection of the window
+ * to be captured
+ */
+ return winsnapWinMain ();
+}
+
+/******************************************************************
+ * Debug stuff
+ ******************************************************************/
+
+/*
+ * formatWindowsError
+ *
+ * Format the latest Windows error message into
+ * a readable string. Store in the provided
+ * buffer.
+ */
+static void
+formatWindowsError (char *buffer,
+ int buf_size)
+{
+ LPVOID lpMsgBuf;
+
+ /* Format the message */
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf, 0, NULL );
+
+ /* Copy to the buffer */
+ strncpy(buffer, lpMsgBuf, buf_size - 1);
+
+ LocalFree(lpMsgBuf);
+}
+
+/******************************************************************
+ * Bitmap capture and handling
+ ******************************************************************/
+
+/*
+ * primDoWindowCapture
+ *
+ * The primitive window capture functionality. Accepts
+ * the two device contexts and the rectangle to be
+ * captured.
+ */
+static HBITMAP
+primDoWindowCapture (HDC hdcWindow,
+ HDC hdcCompat,
+ RECT rect)
+{
+ HBITMAP hbmCopy;
+ HGDIOBJ oldObject;
+ BITMAPINFO bmi;
+
+ int width = (rect.right - rect.left);
+ int height = (rect.bottom - rect.top);
+
+ /* Create the bitmap info header */
+ bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = ROUND4(width);
+ bmi.bmiHeader.biHeight = -height;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 24;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biSizeImage = 0;
+ bmi.bmiHeader.biXPelsPerMeter =
+ bmi.bmiHeader.biYPelsPerMeter = 0;
+ bmi.bmiHeader.biClrUsed = 0;
+ bmi.bmiHeader.biClrImportant = 0;
+
+ /* Create the bitmap storage space */
+ hbmCopy = CreateDIBSection (hdcCompat,
+ (BITMAPINFO *) &bmi,
+ DIB_RGB_COLORS,
+ (void **)&capBytes, NULL, 0);
+ if (!hbmCopy)
+ {
+ formatWindowsError(buffer, sizeof buffer);
+ g_error("Error creating DIB section: %s", buffer);
+ return NULL;
+ }
+
+ /* Select the bitmap into the compatible DC. */
+ oldObject = SelectObject (hdcCompat, hbmCopy);
+ if (!oldObject)
+ {
+ formatWindowsError (buffer, sizeof buffer);
+ g_error ("Error selecting object: %s", buffer);
+ return NULL;
+ }
+
+ /* Copy the data from the application to the bitmap. Even if we did
+ * round up the width, BitBlt only the actual data.
+ */
+ if (!BitBlt(hdcCompat, 0,0,
+ width, height,
+ hdcWindow, rect.left, rect.top,
+ SRCCOPY))
+ {
+ formatWindowsError (buffer, sizeof buffer);
+ g_error ("Error copying bitmap: %s", buffer);
+ return NULL;
+ }
+
+ /* Restore the original object */
+ SelectObject (hdcCompat, oldObject);
+
+ return hbmCopy;
+}
+
+static BOOL CALLBACK
+GetAccurateWindowRect_MonitorEnumProc (HMONITOR hMonitor,
+ HDC hdcMonitor,
+ LPRECT lprcMonitor,
+ LPARAM dwData)
+{
+ RECT **rectScreens = (RECT**) dwData;
+
+ if (!lprcMonitor) return FALSE;
+
+ if (! (*rectScreens))
+ *rectScreens = (RECT*) g_malloc (sizeof (RECT)*(rectScreensCount+1));
+ else
+ *rectScreens = (RECT*) g_realloc (rectScreens,
+ sizeof (RECT)*(rectScreensCount+1));
+
+ if (*rectScreens == NULL)
+ {
+ rectScreensCount = 0;
+ return FALSE;
+ }
+
+ (*rectScreens)[rectScreensCount] = *lprcMonitor;
+
+ rectScreensCount++;
+
+ return TRUE;
+}
+
+static BOOL
+GetAccurateWindowRect (HWND hwndTarget,
+ RECT *outRect)
+{
+ HRESULT dwmResult;
+ WINDOWPLACEMENT windowplacment;
+
+ ZeroMemory (outRect, sizeof (RECT));
+
+ /* First we try to get the rect using the dwm api. it will also avoid us from doing more ugly fixes when the window is maximized */
+ if (LoadRequiredDwmFunctions ())
+ {
+ dwmResult = DwmGetWindowAttribute (hwndTarget, DWMWA_EXTENDED_FRAME_BOUNDS, (PVOID) outRect, sizeof (RECT));
+ UnloadRequiredDwmFunctions ();
+ if (dwmResult == S_OK) return TRUE;
+ }
+
+ /* In this case, we did not got the rect from the dwm api so we try to get the rect with the normal function */
+ if (GetWindowRect (hwndTarget, outRect))
+ {
+ /* If the window is maximized then we need and can fix the rect variable
+ * (we need to do this if the rect isn't coming from dwm api)
+ */
+ ZeroMemory (&windowplacment, sizeof (WINDOWPLACEMENT));
+ if (GetWindowPlacement (hwndTarget, &windowplacment) && windowplacment.showCmd == SW_SHOWMAXIMIZED)
+ {
+ RECT *rectScreens = NULL;
+ int xCenter;
+ int yCenter;
+ int i;
+
+ /* If this is not the first time we call this function for some
+ * reason then we reset the rectScreens count
+ */
+ if (rectScreensCount)
+ rectScreensCount = 0;
+
+ /* Get the screens rects */
+ EnumDisplayMonitors (NULL, NULL, GetAccurateWindowRect_MonitorEnumProc,
+ (LPARAM) &rectScreens);
+
+ /* If for some reason the array size is 0 then we fill it with the desktop rect */
+ if (! rectScreensCount)
+ {
+ rectScreens = (RECT*) g_malloc (sizeof (RECT));
+ if (! GetWindowRect (GetDesktopWindow (), rectScreens))
+ {
+ /* error: could not get rect screens */
+ g_free (rectScreens);
+ return FALSE;
+ }
+
+ rectScreensCount = 1;
+ }
+
+ xCenter = outRect->left + (outRect->right - outRect->left) / 2;
+ yCenter = outRect->top + (outRect->bottom - outRect->top) / 2;
+
+ /* find on which screen the window exist */
+ for (i = 0; i < rectScreensCount; i++)
+ if (xCenter > rectScreens[i].left && xCenter < rectScreens[i].right &&
+ yCenter > rectScreens[i].top && yCenter < rectScreens[i].bottom)
+ break;
+
+ if (i == rectScreensCount)
+ /* Error: did not found on which screen the window exist */
+ return FALSE;
+
+ if (rectScreens[i].left > outRect->left) outRect->left = rectScreens[i].left;
+ if (rectScreens[i].right < outRect->right) outRect->right = rectScreens[i].right;
+ if (rectScreens[i].top > outRect->top) outRect->top = rectScreens[i].top;
+ if (rectScreens[i].bottom < outRect->bottom) outRect->bottom = rectScreens[i].bottom;
+
+ g_free (rectScreens);
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * doCapture
+ *
+ * Do the capture. Accepts the window
+ * handle to be captured or the NULL value
+ * to specify the root window.
+ */
+static gboolean
+doCapture (HWND selectedHwnd)
+{
+ RECT rect;
+
+ /* Try and get everything out of the way before the
+ * capture.
+ */
+ Sleep (500 + winsnapvals.delay * 1000);
+
+ /* Are we capturing a window or the whole screen */
+ if (selectedHwnd)
+ {
+ if (! GetAccurateWindowRect (selectedHwnd, &rect))
+ /* For some reason it works only if we return here TRUE. strange... */
+ return TRUE;
+
+ /* First try to capture the window with the magnification api.
+ * This will solve the bug https://bugzilla.gnome.org/show_bug.cgi?id=793722/
+ */
+
+ if (! doCaptureMagnificationAPI (selectedHwnd, rect))
+ {
+ /* If for some reason this capture method failed then
+ * capture the window with the normal method:
+ */
+ HWND previousHwnd = GetForegroundWindow ();
+ gboolean success;
+
+ SetForegroundWindow (selectedHwnd);
+ BringWindowToTop (selectedHwnd);
+
+ success = doCaptureBitBlt (selectedHwnd, rect);
+
+ if (previousHwnd)
+ SetForegroundWindow (previousHwnd);
+
+ return success;
+ }
+
+ return TRUE;
+
+ }
+ else
+ {
+ /* Get the screen's rectangle */
+ rect.top = GetSystemMetrics (SM_YVIRTUALSCREEN);
+ rect.bottom = GetSystemMetrics (SM_YVIRTUALSCREEN) + GetSystemMetrics (SM_CYVIRTUALSCREEN);
+ rect.left = GetSystemMetrics (SM_XVIRTUALSCREEN);
+ rect.right = GetSystemMetrics (SM_XVIRTUALSCREEN) + GetSystemMetrics (SM_CXVIRTUALSCREEN);
+
+ return doCaptureBitBlt (selectedHwnd, rect);
+
+ }
+
+ return FALSE; /* we should never get here... */
+}
+
+static gboolean
+doCaptureBitBlt (HWND selectedHwnd,
+ RECT rect)
+{
+
+ HDC hdcSrc;
+ HDC hdcCompat;
+ HBITMAP hbm;
+
+ /* Get the device context for the whole screen
+ * even if we just want to capture a window.
+ * this will allow to capture applications that
+ * don't render to their main window's device
+ * context (e.g. browsers).
+ */
+ hdcSrc = CreateDC (TEXT("DISPLAY"), NULL, NULL, NULL);
+
+ if (!hdcSrc)
+ {
+ formatWindowsError(buffer, sizeof buffer);
+ g_error ("Error getting device context: %s", buffer);
+ return FALSE;
+ }
+ hdcCompat = CreateCompatibleDC (hdcSrc);
+ if (!hdcCompat)
+ {
+ formatWindowsError (buffer, sizeof buffer);
+ g_error ("Error getting compat device context: %s", buffer);
+ return FALSE;
+ }
+
+ /* Do the window capture */
+ hbm = primDoWindowCapture (hdcSrc, hdcCompat, rect);
+ if (!hbm)
+ return FALSE;
+
+ /* Release the device context */
+ ReleaseDC(selectedHwnd, hdcSrc);
+
+ if (hbm == NULL) return FALSE;
+
+ sendBMPToGimp (hbm, hdcCompat, rect);
+
+ return TRUE;
+
+}
+
+static void
+doCaptureMagnificationAPI_callback (HWND hwnd,
+ void *srcdata,
+ MAGIMAGEHEADER srcheader,
+ void *destdata,
+ MAGIMAGEHEADER destheader,
+ RECT unclipped,
+ RECT clipped,
+ HRGN dirty)
+{
+ if (!srcdata) return;
+ capBytes = (guchar*) malloc (sizeof (guchar)*srcheader.cbSize);
+ rgbaToRgbBytes (capBytes, srcdata, srcheader.cbSize);
+ returnedSrcheader = srcheader;
+}
+
+static BOOL
+isWindowIsAboveCaptureRegion (HWND hwndWindow,
+ RECT rectCapture)
+{
+ RECT rectWindow;
+ ZeroMemory (&rectWindow, sizeof (RECT));
+ if (!GetWindowRect (hwndWindow, &rectWindow)) return FALSE;
+ if (
+ (
+ (rectWindow.left >= rectCapture.left && rectWindow.left < rectCapture.right)
+ ||
+ (rectWindow.right <= rectCapture.right && rectWindow.right > rectCapture.left)
+ ||
+ (rectWindow.left <= rectCapture.left && rectWindow.right >= rectCapture.right)
+ )
+ &&
+ (
+ (rectWindow.top >= rectCapture.top && rectWindow.top < rectCapture.bottom)
+ ||
+ (rectWindow.bottom <= rectCapture.bottom && rectWindow.bottom > rectCapture.top)
+ ||
+ (rectWindow.top <= rectCapture.top && rectWindow.bottom >= rectCapture.bottom)
+ )
+ )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static gboolean
+doCaptureMagnificationAPI (HWND selectedHwnd,
+ RECT rect)
+{
+ HWND hwndMag;
+ HWND hwndHost;
+ HWND nextWindow;
+ HWND excludeWins[24];
+ RECT round4Rect;
+ int excludeWinsCount = 0;
+
+ if (!LoadMagnificationLibrary ()) return FALSE;
+
+ if (!MagInitialize ()) return FALSE;
+
+ round4Rect = rect;
+ round4Rect.right = round4Rect.left + ROUND4(round4Rect.right - round4Rect.left);
+
+ /* Create the host window that will store the mag child window */
+ hwndHost = CreateWindowEx (0x08000000 | 0x080000 | 0x80 | 0x20, APP_NAME, NULL, 0x80000000,
+ 0, 0, 0, 0, NULL, NULL, GetModuleHandle (NULL), NULL);
+
+ if (!hwndHost)
+ {
+ MagUninitialize ();
+ return FALSE;
+ }
+
+ SetLayeredWindowAttributes (hwndHost, (COLORREF)0, (BYTE)255, (DWORD)0x02);
+
+ /* Create the mag child window inside the host window */
+ hwndMag = CreateWindow (WC_MAGNIFIER, TEXT ("MagnifierWindow"),
+ WS_CHILD /*| MS_SHOWMAGNIFIEDCURSOR*/ /*| WS_VISIBLE*/,
+ 0, 0, round4Rect.right - round4Rect.left, round4Rect.bottom - round4Rect.top,
+ hwndHost, NULL, GetModuleHandle (NULL), NULL);
+
+ /* Set the callback function that will be called by the api to get the pixels */
+ if (!MagSetImageScalingCallback (hwndMag, (MagImageScalingCallback)doCaptureMagnificationAPI_callback))
+ {
+ DestroyWindow (hwndHost);
+ MagUninitialize ();
+ return FALSE;
+ }
+
+ /* Add only windows that above the target window */
+ for (nextWindow = GetNextWindow (selectedHwnd, GW_HWNDPREV); nextWindow != NULL; nextWindow = GetNextWindow (nextWindow, GW_HWNDPREV))
+ if (isWindowIsAboveCaptureRegion (nextWindow, rect))
+ {
+ excludeWins[excludeWinsCount++] = nextWindow;
+ /* This api can't work with more than 24 windows. we stop on the 24 window */
+ if (excludeWinsCount >= 24) break;
+ }
+
+ if (excludeWinsCount)
+ MagSetWindowFilterList (hwndMag, MW_FILTERMODE_EXCLUDE, excludeWinsCount, excludeWins);
+
+ /* Call the api to capture the window */
+ capBytes = NULL;
+
+ if (!MagSetWindowSource (hwndMag, round4Rect) || !capBytes)
+ {
+ DestroyWindow (hwndHost);
+ MagUninitialize ();
+ return FALSE;
+ }
+
+ /* Send it to Gimp */
+ sendBMPToGimp (NULL, NULL, rect);
+
+ DestroyWindow (hwndHost);
+ MagUninitialize ();
+
+ return TRUE;
+}
+
+/******************************************************************
+ * Win32 entry point and setup...
+ ******************************************************************/
+
+#define DINV 3
+
+/*
+ * highlightWindowFrame
+ *
+ * Highlight (or unhighlight) the specified
+ * window handle's frame.
+ */
+static void
+highlightWindowFrame (HWND hWnd)
+{
+ HDC hdc;
+ RECT rc;
+
+ if (!IsWindow (hWnd))
+ return;
+
+ hdc = GetWindowDC (hWnd);
+ GetWindowRect (hWnd, &rc);
+ OffsetRect (&rc, -rc.left, -rc.top);
+
+ if (!IsRectEmpty (&rc))
+ {
+ PatBlt (hdc, rc.left, rc.top, rc.right-rc.left, DINV, DSTINVERT);
+ PatBlt (hdc, rc.left, rc.bottom-DINV, DINV, -(rc.bottom-rc.top-2*DINV),
+ DSTINVERT);
+ PatBlt (hdc, rc.right-DINV, rc.top+DINV, DINV, rc.bottom-rc.top-2*DINV,
+ DSTINVERT);
+ PatBlt (hdc, rc.right, rc.bottom-DINV, -(rc.right-rc.left), DINV,
+ DSTINVERT);
+ }
+
+ ReleaseDC (hWnd, hdc);
+ UpdateWindow (hWnd);
+}
+
+/*
+ * setCaptureType
+ *
+ * Set the capture type. Should be one of:
+ * SELECT_FRAME
+ * SELECT_CLIENT
+ * SELECT_WINDOW
+ */
+void
+setCaptureType (int capType)
+{
+ captureType = capType;
+}
+
+/*
+ * myWindowFromPoint
+ *
+ * Map to the appropriate window from the
+ * specified point. The chosen window is
+ * based on the current capture type.
+ */
+static HWND
+myWindowFromPoint (POINT pt)
+{
+ HWND myHwnd;
+ HWND nextHwnd;
+
+ switch (captureType)
+ {
+ case SELECT_FRAME:
+ case SELECT_CLIENT:
+ nextHwnd = WindowFromPoint (pt);
+
+ do {
+ myHwnd = nextHwnd;
+ nextHwnd = GetParent (myHwnd);
+ } while (nextHwnd);
+
+ return myHwnd;
+ break;
+
+ case SELECT_WINDOW:
+ return WindowFromPoint (pt);
+ break;
+ }
+
+ return WindowFromPoint (pt);
+}
+
+/*
+ * dialogProc
+ *
+ * The window procedure for the window
+ * selection dialog box.
+ */
+BOOL CALLBACK
+dialogProc (HWND hwndDlg,
+ UINT msg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ static int mouseCaptured;
+ static int buttonDown;
+ static HCURSOR oldCursor;
+ static RECT bitmapRect;
+ static HWND highlightedHwnd = NULL;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ int nonclientHeight;
+ HWND hwndGroup;
+ RECT dlgRect;
+ RECT clientRect;
+ RECT groupRect;
+ BITMAP bm;
+
+ /* Set the mouse capture flag */
+ buttonDown = 0;
+ mouseCaptured = 0;
+
+ /* Calculate the bitmap dimensions */
+ GetObject (iconInfo.hbmMask, sizeof(BITMAP), (VOID *)&bm);
+
+ /* Calculate the dialog window dimensions */
+ GetWindowRect (hwndDlg, &dlgRect);
+
+ /* Calculate the group box dimensions */
+ hwndGroup = GetDlgItem(hwndDlg, IDC_GROUP);
+ GetWindowRect (hwndGroup, &groupRect);
+ OffsetRect (&groupRect, -dlgRect.left, -dlgRect.top);
+
+ /* The client's rectangle */
+ GetClientRect (hwndDlg, &clientRect);
+
+ /* The non-client height */
+ nonclientHeight = (dlgRect.bottom - dlgRect.top) -
+ (clientRect.bottom - clientRect.top);
+
+ /* Calculate the bitmap rectangle */
+ bitmapRect.top = ((groupRect.top + groupRect.bottom) / 2) -
+ (bm.bmHeight / 2);
+ bitmapRect.top -= nonclientHeight;
+ bitmapRect.bottom = bitmapRect.top + bm.bmHeight;
+ bitmapRect.left = ((groupRect.left + groupRect.right) / 2) - (bm.bmWidth / 2);
+ bitmapRect.right = bitmapRect.left + bm.bmWidth;
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ /* Track the button down state */
+ buttonDown = 1;
+ break;
+
+ case WM_LBUTTONUP:
+ buttonDown = 0;
+
+ /* If we have mouse captured
+ * we do this stuff.
+ */
+ if (mouseCaptured)
+ {
+ HWND selectedHwnd;
+ POINT cursorPos;
+
+ /* Release the capture */
+ mouseCaptured = 0;
+ SetCursor (oldCursor);
+ ReleaseCapture ();
+
+ /* Remove the highlight */
+ if (highlightedHwnd)
+ highlightWindowFrame (highlightedHwnd);
+ RedrawWindow (hwndDlg, NULL, NULL, RDW_INVALIDATE);
+
+ /* Return the selected window */
+ GetCursorPos (&cursorPos);
+ selectedHwnd = myWindowFromPoint (cursorPos);
+ EndDialog (hwndDlg, (INT_PTR) selectedHwnd);
+ }
+ break;
+
+ case WM_MOUSEMOVE:
+ /* If the mouse is captured, show
+ * the window which is tracking
+ * under the mouse position.
+ */
+ if (mouseCaptured)
+ {
+ HWND currentHwnd;
+ POINT cursorPos;
+
+ /* Get the window */
+ GetCursorPos (&cursorPos);
+ currentHwnd = myWindowFromPoint (cursorPos);
+
+ /* Do the highlighting */
+ if (highlightedHwnd != currentHwnd)
+ {
+ if (highlightedHwnd)
+ highlightWindowFrame (highlightedHwnd);
+ if (currentHwnd)
+ highlightWindowFrame (currentHwnd);
+ highlightedHwnd = currentHwnd;
+ }
+ /* If the mouse has not been captured,
+ * try to figure out if we should capture
+ * the mouse.
+ */
+ }
+ else if (buttonDown)
+ {
+ POINT cursorPos;
+
+ /* Get the current client position */
+ GetCursorPos (&cursorPos);
+ ScreenToClient (hwndDlg, &cursorPos);
+
+ /* Check if within the rectangle formed
+ * by the bitmap
+ */
+ if (PtInRect (&bitmapRect, cursorPos)) {
+ mouseCaptured = 1;
+ oldCursor = SetCursor (selectCursor);
+ SetCapture (hwndDlg);
+ RedrawWindow (hwndDlg, NULL, NULL, RDW_INVALIDATE | RDW_ERASE);
+ }
+ }
+
+ break;
+
+ case WM_PAINT:
+ {
+ HDC hDC;
+ PAINTSTRUCT ps;
+
+ /* If the mouse is not captured draw
+ * the cursor image
+ */
+ if (!mouseCaptured)
+ {
+ hDC = BeginPaint (hwndDlg, &ps);
+ DrawIconEx (hDC, bitmapRect.left, bitmapRect.top, selectCursor,
+ 0, 0, 0, NULL, DI_NORMAL);
+ EndPaint (hwndDlg, &ps);
+ }
+ }
+ break;
+
+ case WM_COMMAND:
+ /* Handle the cancel button */
+ switch (LOWORD (wParam))
+ {
+ case IDCANCEL:
+ EndDialog (hwndDlg, 0);
+ return TRUE;
+ break;
+ }
+
+ }
+
+ return FALSE;
+}
+
+///* Don't use the normal WinMain from gimp.h */
+//#define WinMain WinMain_no_thanks
+//MAIN()
+//#undef WinMain
+
+/*
+ * WinMain
+ *
+ * The standard gimp plug-in WinMain won't quite cut it for
+ * this plug-in.
+ */
+//int APIENTRY
+//WinMain(HINSTANCE hInstance,
+// HINSTANCE hPrevInstance,
+// LPSTR lpCmdLine,
+// int nCmdShow)
+//{
+// /*
+// * Normally, we would do all of the Windows-ish set up of
+// * the window classes and stuff here in WinMain. But,
+// * the only time we really need the window and message
+// * queues is during the plug-in run. So, all of that will
+// * be done during run(). This avoids all of the Windows
+// * setup stuff for the query(). Stash the instance handle now
+// * so it is available from the run() procedure.
+// */
+// hInst = hInstance;
+//
+// /*
+// * Now, call gimp_main... This is what the normal WinMain()
+// * would do.
+// */
+//// return gimp_main(&PLUG_IN_INFO, __argc, __argv);
+//}
+
+/*
+ * InitApplication
+ *
+ * Initialize window data and register the window class
+ */
+BOOL
+InitApplication (HINSTANCE hInstance)
+{
+ WNDCLASS wc;
+ BOOL retValue;
+
+ /* Get some resources */
+#ifdef _MSC_VER
+ /* For some reason this works only with MSVC */
+ selectCursor = LoadCursor (hInstance, MAKEINTRESOURCE(IDC_SELECT));
+#else
+ selectCursor = LoadCursor (NULL, IDC_CROSS);
+#endif
+ GetIconInfo (selectCursor, &iconInfo);
+
+ /*
+ * Fill in window class structure with parameters to describe
+ * the main window.
+ */
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = (WNDPROC) WndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = hInstance;
+ wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
+ wc.hCursor = LoadCursor (NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
+ wc.lpszClassName = APP_NAME;
+ wc.lpszMenuName = NULL;
+
+ /* Register the window class and stash success/failure code. */
+ retValue = RegisterClass (&wc);
+
+ /* Log error */
+ if (!retValue)
+ {
+ formatWindowsError (buffer, sizeof buffer);
+ g_error ("Error registering class: %s", buffer);
+ return retValue;
+ }
+
+ return retValue;
+}
+
+/*
+ * InitInstance
+ *
+ * Create the main window for the application.
+ */
+BOOL
+InitInstance (HINSTANCE hInstance,
+ int nCmdShow)
+{
+ HINSTANCE User32Library = LoadLibrary ("user32.dll");
+
+ if (User32Library)
+ {
+ typedef BOOL (WINAPI* SET_PROC_DPI_AWARE)();
+ SET_PROC_DPI_AWARE SetProcessDPIAware;
+
+ /* This line fix bug: https://bugzilla.gnome.org/show_bug.cgi?id=796121#c4 */
+ SetProcessDPIAware = (SET_PROC_DPI_AWARE) GetProcAddress (User32Library,
+ "SetProcessDPIAware");
+ if (SetProcessDPIAware)
+ SetProcessDPIAware();
+
+ FreeLibrary (User32Library);
+ }
+
+ /* Create our window */
+ mainHwnd = CreateWindow (APP_NAME, APP_NAME, WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
+ NULL, NULL, hInstance, NULL);
+
+ if (!mainHwnd)
+ {
+ return (FALSE);
+ }
+
+ ShowWindow (mainHwnd, nCmdShow);
+ UpdateWindow (mainHwnd);
+
+ return TRUE;
+}
+
+/*
+ * winsnapWinMain
+ *
+ * This is the function that represents the code that
+ * would normally reside in WinMain (see above). This
+ * function will get called during run() in order to set
+ * up the windowing environment necessary for WinSnap to
+ * operate.
+ */
+int
+winsnapWinMain (void)
+{
+ MSG msg;
+
+ /* Perform instance initialization */
+ if (!InitApplication (hInst))
+ return (FALSE);
+
+ /* Perform application initialization */
+ if (!InitInstance (hInst, SHOW_WINDOW))
+ return (FALSE);
+
+ /* Main message loop */
+ while (GetMessage (&msg, NULL, 0, 0))
+ {
+ TranslateMessage (&msg);
+ DispatchMessage (&msg);
+ }
+
+ return (msg.wParam);
+}
+
+/*
+ * WndProc
+ *
+ * Process window message for the main window.
+ */
+LRESULT CALLBACK
+WndProc (HWND hwnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ HWND selectedHwnd;
+
+ switch (message)
+ {
+
+ case WM_CREATE:
+ /* The window is created... Send the capture message */
+ PostMessage (hwnd, WM_DOCAPTURE, 0, 0);
+ break;
+
+ case WM_DOCAPTURE:
+ /* Get the selected window handle */
+ selectedHwnd = (HWND) DialogBox (hInst, MAKEINTRESOURCE(IDD_SELECT),
+ hwnd, (DLGPROC) dialogProc);
+ if (selectedHwnd)
+ doCapture (selectedHwnd);
+
+ PostQuitMessage (selectedHwnd != NULL);
+
+ break;
+
+ case WM_DESTROY:
+ PostQuitMessage (0);
+ break;
+
+ default:
+ return (DefWindowProc (hwnd, message, wParam, lParam));
+ }
+
+ return 0;
+}
+
+#endif /* G_OS_WIN32 */
diff --git a/plug-ins/screenshot/screenshot-win32.h b/plug-ins/screenshot/screenshot-win32.h
new file mode 100644
index 0000000..d84be25
--- /dev/null
+++ b/plug-ins/screenshot/screenshot-win32.h
@@ -0,0 +1,44 @@
+/* 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 __SCREENSHOT_WIN32_H__
+#define __SCREENSHOT_WIN32_H__
+
+
+#ifdef G_OS_WIN32
+
+#define IDC_STATIC -1
+
+#define IDS_APP_TITLE 500
+#define IDS_DISPLAYCHANGED 501
+#define IDS_VER_INFO_LANG 502
+#define IDS_VERSION_ERROR 503
+#define IDS_NO_HELP 504
+
+gboolean screenshot_win32_available (void);
+
+ScreenshotCapabilities screenshot_win32_get_capabilities (void);
+
+GimpPDBStatusType screenshot_win32_shoot (ScreenshotValues *shootvals,
+ GdkScreen *screen,
+ gint32 *image_ID,
+ GError **error);
+
+#endif /* G_OS_WIN32 */
+
+
+#endif /* __SCREENSHOT_WIN32_H__ */
diff --git a/plug-ins/screenshot/screenshot-win32.ico b/plug-ins/screenshot/screenshot-win32.ico
new file mode 100644
index 0000000..35ea973
--- /dev/null
+++ b/plug-ins/screenshot/screenshot-win32.ico
Binary files differ
diff --git a/plug-ins/screenshot/screenshot-win32.rc b/plug-ins/screenshot/screenshot-win32.rc
new file mode 100644
index 0000000..0272e93
--- /dev/null
+++ b/plug-ins/screenshot/screenshot-win32.rc
@@ -0,0 +1,189 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "screenshot-win32-resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+#include "screenshot-win32.h"
+#include "winver.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(65001)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+SNAPPY ICON DISCARDABLE "screenshot-win32.ico"
+SMALL ICON DISCARDABLE "screenshot-win32-small.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+SNAPPY MENU DISCARDABLE
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&Capture", IDM_CAPTURE
+ MENUITEM "Capture Fullscreen", IDM_CAPTUREFULL
+ MENUITEM SEPARATOR
+ MENUITEM "Begin Hook", IDM_HOOK
+ MENUITEM "End Hook", IDM_UNHOOK
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", IDM_EXIT
+ END
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""screenshot-win32.h""\r\n"
+ "#include ""winver.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Cursor
+//
+
+IDC_SELECT CURSOR DISCARDABLE "screenshot-win32-select.cur"
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "000004b0"
+ BEGIN
+ VALUE "Comments", "\0"
+ VALUE "CompanyName", "SeteraSoft\0"
+ VALUE "FileDescription", "snappy\0"
+ VALUE "FileVersion", "1, 0, 0, 1\0"
+ VALUE "InternalName", "snappy\0"
+ VALUE "LegalCopyright", "Copyright © 1999\0"
+ VALUE "LegalTrademarks", "\0"
+ VALUE "OriginalFilename", "snappy.exe\0"
+ VALUE "PrivateBuild", "\0"
+ VALUE "ProductName", "SeteraSoft snappy\0"
+ VALUE "ProductVersion", "1, 0, 0, 1\0"
+ VALUE "SpecialBuild", "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0, 1200
+ END
+END
+
+#endif // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_SELECT DIALOG DISCARDABLE 0, 0, 141, 95
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Select Window"
+FONT 8, "MS Sans Serif"
+BEGIN
+ PUSHBUTTON "Cancel",IDCANCEL,44,74,50,14
+ CTEXT "Drag crosshair to select window",IDC_TEXT,7,7,127,8
+ GROUPBOX "",IDC_GROUP,51,25,37,37,NOT WS_VISIBLE
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_SELECT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 134
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 88
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/plug-ins/screenshot/screenshot-x11.c b/plug-ins/screenshot/screenshot-x11.c
new file mode 100644
index 0000000..820ec04
--- /dev/null
+++ b/plug-ins/screenshot/screenshot-x11.c
@@ -0,0 +1,697 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * Screenshot plug-in
+ * Copyright 1998-2007 Sven Neumann <sven@gimp.org>
+ * Copyright 2003 Henrik Brix Andersen <brix@gimp.org>
+ * Copyright 2012 Simone Karin Lehmann - OS X patches
+ *
+ * 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 <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#ifdef GDK_WINDOWING_X11
+
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdkx.h>
+
+#ifdef HAVE_X11_EXTENSIONS_SHAPE_H
+#include <X11/extensions/shape.h>
+#endif
+
+#ifdef HAVE_X11_XMU_WINUTIL_H
+#include <X11/Xmu/WinUtil.h>
+#endif
+
+#ifdef HAVE_XFIXES
+#include <X11/extensions/Xfixes.h>
+#endif
+
+#include "screenshot.h"
+#include "screenshot-x11.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+
+static guint32 select_window (ScreenshotValues *shootvals,
+ GdkScreen *screen);
+static gint32 create_image (cairo_surface_t *surface,
+ cairo_region_t *shape,
+ const gchar *name);
+
+
+/* Allow the user to select a window or a region with the mouse */
+
+static guint32
+select_window (ScreenshotValues *shootvals,
+ GdkScreen *screen)
+{
+ Display *x_dpy = GDK_SCREEN_XDISPLAY (screen);
+ gint x_scr = GDK_SCREEN_XNUMBER (screen);
+ Window x_root = RootWindow (x_dpy, x_scr);
+ Window x_win = None;
+ GC x_gc = NULL;
+ Cursor x_cursor = XCreateFontCursor (x_dpy, GDK_CROSSHAIR);
+ GdkKeymap *keymap;
+ GdkKeymapKey *keys = NULL;
+ gint status;
+ gint num_keys;
+ gint i;
+ gint buttons = 0;
+ gint mask = ButtonPressMask | ButtonReleaseMask;
+ gboolean cancel = FALSE;
+
+ if (shootvals->shoot_type == SHOOT_REGION)
+ mask |= PointerMotionMask;
+
+ status = XGrabPointer (x_dpy, x_root, False,
+ mask, GrabModeSync, GrabModeAsync,
+ x_root, x_cursor, CurrentTime);
+
+ if (status != GrabSuccess)
+ {
+ gint x, y;
+ guint xmask;
+
+ /* if we can't grab the pointer, return the window under the pointer */
+ XQueryPointer (x_dpy, x_root, &x_root, &x_win, &x, &y, &x, &y, &xmask);
+
+ if (x_win == None || x_win == x_root)
+ g_message (_("Error selecting the window"));
+ }
+
+ if (shootvals->shoot_type == SHOOT_REGION)
+ {
+ XGCValues gc_values;
+
+ gc_values.function = GXxor;
+ gc_values.plane_mask = AllPlanes;
+ gc_values.foreground = WhitePixel (x_dpy, x_scr);
+ gc_values.background = BlackPixel (x_dpy, x_scr);
+ gc_values.line_width = 0;
+ gc_values.line_style = LineSolid;
+ gc_values.fill_style = FillSolid;
+ gc_values.cap_style = CapButt;
+ gc_values.join_style = JoinMiter;
+ gc_values.graphics_exposures = FALSE;
+ gc_values.clip_x_origin = 0;
+ gc_values.clip_y_origin = 0;
+ gc_values.clip_mask = None;
+ gc_values.subwindow_mode = IncludeInferiors;
+
+ x_gc = XCreateGC (x_dpy, x_root,
+ GCFunction | GCPlaneMask | GCForeground | GCLineWidth |
+ GCLineStyle | GCCapStyle | GCJoinStyle |
+ GCGraphicsExposures | GCBackground | GCFillStyle |
+ GCClipXOrigin | GCClipYOrigin | GCClipMask |
+ GCSubwindowMode,
+ &gc_values);
+ }
+
+ keymap = gdk_keymap_get_for_display (gdk_screen_get_display (screen));
+
+ if (gdk_keymap_get_entries_for_keyval (keymap, GDK_KEY_Escape,
+ &keys, &num_keys))
+ {
+ gdk_error_trap_push ();
+
+#define X_GRAB_KEY(index, modifiers) \
+ XGrabKey (x_dpy, keys[index].keycode, modifiers, x_root, False, \
+ GrabModeAsync, GrabModeAsync)
+
+ for (i = 0; i < num_keys; i++)
+ {
+ X_GRAB_KEY (i, 0);
+ X_GRAB_KEY (i, LockMask); /* CapsLock */
+ X_GRAB_KEY (i, Mod2Mask); /* NumLock */
+ X_GRAB_KEY (i, Mod5Mask); /* ScrollLock */
+ X_GRAB_KEY (i, LockMask | Mod2Mask); /* CapsLock + NumLock */
+ X_GRAB_KEY (i, LockMask | Mod5Mask); /* CapsLock + ScrollLock */
+ X_GRAB_KEY (i, Mod2Mask | Mod5Mask); /* NumLock + ScrollLock */
+ X_GRAB_KEY (i, LockMask | Mod2Mask | Mod5Mask); /* all */
+ }
+
+#undef X_GRAB_KEY
+
+ gdk_flush ();
+
+ if (gdk_error_trap_pop ())
+ {
+ /* ignore errors */
+ }
+ }
+
+ while (! cancel && ((x_win == None) || (buttons != 0)))
+ {
+ XEvent x_event;
+ gint x, y, w, h;
+
+ XAllowEvents (x_dpy, SyncPointer, CurrentTime);
+ XWindowEvent (x_dpy, x_root, mask | KeyPressMask, &x_event);
+
+ switch (x_event.type)
+ {
+ case ButtonPress:
+ if (x_win == None)
+ {
+ x_win = x_event.xbutton.subwindow;
+
+ if (x_win == None)
+ x_win = x_root;
+#ifdef HAVE_X11_XMU_WINUTIL_H
+ else if (! shootvals->decorate)
+ x_win = XmuClientWindow (x_dpy, x_win);
+#endif
+
+ shootvals->x2 = shootvals->x1 = x_event.xbutton.x_root;
+ shootvals->y2 = shootvals->y1 = x_event.xbutton.y_root;
+ }
+
+ buttons++;
+ break;
+
+ case ButtonRelease:
+ if (buttons > 0)
+ buttons--;
+
+ if (! buttons && shootvals->shoot_type == SHOOT_REGION)
+ {
+ x = MIN (shootvals->x1, shootvals->x2);
+ y = MIN (shootvals->y1, shootvals->y2);
+ w = ABS (shootvals->x2 - shootvals->x1);
+ h = ABS (shootvals->y2 - shootvals->y1);
+
+ if (w > 0 && h > 0)
+ XDrawRectangle (x_dpy, x_root, x_gc, x, y, w, h);
+
+ shootvals->x2 = x_event.xbutton.x_root;
+ shootvals->y2 = x_event.xbutton.y_root;
+ }
+ break;
+
+ case MotionNotify:
+ if (buttons > 0)
+ {
+ x = MIN (shootvals->x1, shootvals->x2);
+ y = MIN (shootvals->y1, shootvals->y2);
+ w = ABS (shootvals->x2 - shootvals->x1);
+ h = ABS (shootvals->y2 - shootvals->y1);
+
+ if (w > 0 && h > 0)
+ XDrawRectangle (x_dpy, x_root, x_gc, x, y, w, h);
+
+ shootvals->x2 = x_event.xmotion.x_root;
+ shootvals->y2 = x_event.xmotion.y_root;
+
+ x = MIN (shootvals->x1, shootvals->x2);
+ y = MIN (shootvals->y1, shootvals->y2);
+ w = ABS (shootvals->x2 - shootvals->x1);
+ h = ABS (shootvals->y2 - shootvals->y1);
+
+ if (w > 0 && h > 0)
+ XDrawRectangle (x_dpy, x_root, x_gc, x, y, w, h);
+ }
+ break;
+
+ case KeyPress:
+ {
+ guint *keyvals;
+ gint n;
+
+ if (gdk_keymap_get_entries_for_keycode (NULL, x_event.xkey.keycode,
+ NULL, &keyvals, &n))
+ {
+ gint i;
+
+ for (i = 0; i < n && ! cancel; i++)
+ if (keyvals[i] == GDK_KEY_Escape)
+ cancel = TRUE;
+
+ g_free (keyvals);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (keys)
+ {
+#define X_UNGRAB_KEY(index, modifiers) \
+ XUngrabKey (x_dpy, keys[index].keycode, modifiers, x_root)
+
+ for (i = 0; i < num_keys; i++)
+ {
+ X_UNGRAB_KEY (i, 0);
+ X_UNGRAB_KEY (i, LockMask); /* CapsLock */
+ X_UNGRAB_KEY (i, Mod2Mask); /* NumLock */
+ X_UNGRAB_KEY (i, Mod5Mask); /* ScrollLock */
+ X_UNGRAB_KEY (i, LockMask | Mod2Mask); /* CapsLock + NumLock */
+ X_UNGRAB_KEY (i, LockMask | Mod5Mask); /* CapsLock + ScrollLock */
+ X_UNGRAB_KEY (i, Mod2Mask | Mod5Mask); /* NumLock + ScrollLock */
+ X_UNGRAB_KEY (i, LockMask | Mod2Mask | Mod5Mask); /* all */
+ }
+#undef X_UNGRAB_KEY
+
+ g_free (keys);
+ }
+
+ if (status == GrabSuccess)
+ XUngrabPointer (x_dpy, CurrentTime);
+
+ XFreeCursor (x_dpy, x_cursor);
+
+ if (x_gc != NULL)
+ XFreeGC (x_dpy, x_gc);
+
+ return x_win;
+}
+
+static gchar *
+window_get_utf8_property (GdkDisplay *display,
+ guint32 window,
+ const gchar *name)
+{
+ gchar *retval = NULL;
+ Atom utf8_string;
+ Atom type = None;
+ guchar *val = NULL;
+ gulong nitems = 0;
+ gulong after = 0;
+ gint format = 0;
+
+ utf8_string = gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING");
+
+ XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), window,
+ gdk_x11_get_xatom_by_name_for_display (display, name),
+ 0, G_MAXLONG, False, utf8_string,
+ &type, &format, &nitems, &after, &val);
+
+ if (type != utf8_string || format != 8 || nitems == 0)
+ {
+ if (val)
+ XFree (val);
+ return NULL;
+ }
+
+ if (g_utf8_validate ((const gchar *) val, nitems, NULL))
+ retval = g_strndup ((const gchar *) val, nitems);
+
+ XFree (val);
+
+ return retval;
+}
+
+static gchar *
+window_get_title (GdkDisplay *display,
+ guint window)
+{
+#ifdef HAVE_X11_XMU_WINUTIL_H
+ window = XmuClientWindow (GDK_DISPLAY_XDISPLAY (display), window);
+#endif
+
+ return window_get_utf8_property (display, window, "_NET_WM_NAME");
+}
+
+static cairo_region_t *
+window_get_shape (GdkScreen *screen,
+ guint32 window)
+{
+ cairo_region_t *shape = NULL;
+
+#if defined(HAVE_X11_EXTENSIONS_SHAPE_H)
+ XRectangle *rects;
+ gint rect_count;
+ gint rect_order;
+
+ rects = XShapeGetRectangles (GDK_SCREEN_XDISPLAY (screen), window,
+ ShapeBounding,
+ &rect_count, &rect_order);
+
+ if (rects)
+ {
+ if (rect_count > 1)
+ {
+ gint i;
+
+ shape = cairo_region_create ();
+
+ for (i = 0; i < rect_count; i++)
+ {
+ cairo_rectangle_int_t rect = { rects[i].x,
+ rects[i].y,
+ rects[i].width,
+ rects[i].height };
+
+ cairo_region_union_rectangle (shape, &rect);
+ }
+ }
+
+ XFree (rects);
+ }
+#endif
+
+ return shape;
+}
+
+static void
+image_select_shape (gint32 image,
+ cairo_region_t *shape)
+{
+ gint num_rects;
+ gint i;
+
+ gimp_selection_none (image);
+
+ num_rects = cairo_region_num_rectangles (shape);
+
+ for (i = 0; i < num_rects; i++)
+ {
+ cairo_rectangle_int_t rect;
+
+ cairo_region_get_rectangle (shape, i, &rect);
+
+ gimp_image_select_rectangle (image, GIMP_CHANNEL_OP_ADD,
+ rect.x, rect.y,
+ rect.width, rect.height);
+ }
+
+ gimp_selection_invert (image);
+}
+
+
+/* Create a GimpImage from a GdkPixbuf */
+
+static gint32
+create_image (cairo_surface_t *surface,
+ cairo_region_t *shape,
+ const gchar *name)
+{
+ gint32 image;
+ gint32 layer;
+ gdouble xres, yres;
+ gint width, height;
+
+ gimp_progress_init (_("Importing screenshot"));
+
+ width = cairo_image_surface_get_width (surface);
+ height = cairo_image_surface_get_height (surface);
+
+ image = gimp_image_new (width, height, GIMP_RGB);
+ gimp_image_undo_disable (image);
+
+ gimp_get_monitor_resolution (&xres, &yres);
+ gimp_image_set_resolution (image, xres, yres);
+
+ layer = gimp_layer_new_from_surface (image,
+ name ? name : _("Screenshot"),
+ surface,
+ 0.0, 1.0);
+ gimp_image_insert_layer (image, layer, -1, 0);
+
+ if (shape && ! cairo_region_is_empty (shape))
+ {
+ image_select_shape (image, shape);
+
+ if (! gimp_selection_is_empty (image))
+ {
+ gimp_layer_add_alpha (layer);
+ gimp_drawable_edit_clear (layer);
+ gimp_selection_none (image);
+ }
+ }
+
+ gimp_image_undo_enable (image);
+
+ return image;
+}
+
+static void
+add_cursor_image (gint32 image,
+ GdkDisplay *display)
+{
+#ifdef HAVE_XFIXES
+ XFixesCursorImage *cursor;
+ GeglBuffer *buffer;
+ GeglBufferIterator *iter;
+ GeglRectangle *roi;
+ gint32 layer;
+ gint32 active;
+
+ cursor = XFixesGetCursorImage (GDK_DISPLAY_XDISPLAY (display));
+
+ if (!cursor)
+ return;
+
+ active = gimp_image_get_active_layer (image);
+
+ layer = gimp_layer_new (image, _("Mouse Pointer"),
+ cursor->width, cursor->height,
+ GIMP_RGBA_IMAGE,
+ 100.0,
+ gimp_image_get_default_new_layer_mode (image));
+
+ buffer = gimp_drawable_get_buffer (layer);
+
+ iter = gegl_buffer_iterator_new (buffer,
+ GEGL_RECTANGLE (0, 0,
+ gimp_drawable_width (layer),
+ gimp_drawable_height (layer)),
+ 0, babl_format ("R'G'B'A u8"),
+ GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE, 1);
+ roi = &iter->items[0].roi;
+
+ while (gegl_buffer_iterator_next (iter))
+ {
+ const gulong *src = cursor->pixels + roi->y * cursor->width + roi->x;
+ guchar *dest = iter->items[0].data;
+ gint x, y;
+
+ for (y = 0; y < roi->height; y++)
+ {
+ const gulong *s = src;
+ guchar *d = dest;
+
+ for (x = 0; x < roi->width; x++)
+ {
+ /* the cursor pixels are pre-multiplied ARGB */
+ guint a = (*s >> 24) & 0xff;
+ guint r = (*s >> 16) & 0xff;
+ guint g = (*s >> 8) & 0xff;
+ guint b = (*s >> 0) & 0xff;
+
+ d[0] = a ? (r * 255) / a : r;
+ d[1] = a ? (g * 255) / a : g;
+ d[2] = a ? (b * 255) / a : b;
+ d[3] = a;
+
+ s++;
+ d += 4;
+ }
+
+ src += cursor->width;
+ dest += 4 * roi->width;
+ }
+ }
+
+ g_object_unref (buffer);
+
+ gimp_image_insert_layer (image, layer, -1, -1);
+ gimp_layer_set_offsets (layer,
+ cursor->x - cursor->xhot, cursor->y - cursor->yhot);
+
+ gimp_image_set_active_layer (image, active);
+#endif
+}
+
+
+/* The main Screenshot function */
+
+gboolean
+screenshot_x11_available (void)
+{
+ return TRUE;
+}
+
+ScreenshotCapabilities
+screenshot_x11_get_capabilities (void)
+{
+ ScreenshotCapabilities capabilities = SCREENSHOT_CAN_PICK_NONINTERACTIVELY;
+
+#ifdef HAVE_X11_XMU_WINUTIL_H
+ capabilities |= SCREENSHOT_CAN_SHOOT_DECORATIONS;
+#endif
+
+#ifdef HAVE_XFIXES
+ capabilities |= SCREENSHOT_CAN_SHOOT_POINTER;
+#endif
+
+ capabilities |= SCREENSHOT_CAN_SHOOT_REGION |
+ SCREENSHOT_CAN_SHOOT_WINDOW |
+ SCREENSHOT_CAN_PICK_WINDOW |
+ SCREENSHOT_CAN_DELAY_WINDOW_SHOT;
+
+ return capabilities;
+}
+
+GimpPDBStatusType
+screenshot_x11_shoot (ScreenshotValues *shootvals,
+ GdkScreen *screen,
+ gint32 *image_ID,
+ GError **error)
+{
+ GdkDisplay *display;
+ GdkWindow *window;
+ cairo_surface_t *screenshot;
+ cairo_region_t *shape = NULL;
+ cairo_t *cr;
+ GimpColorProfile *profile;
+ GdkRectangle rect;
+ GdkRectangle screen_rect;
+ gchar *name = NULL;
+ gint screen_x;
+ gint screen_y;
+ gint monitor = shootvals->monitor;
+ gint x, y;
+
+ /* use default screen if we are running non-interactively */
+ if (screen == NULL)
+ screen = gdk_screen_get_default ();
+
+ if (shootvals->shoot_type != SHOOT_ROOT && ! shootvals->window_id)
+ {
+ if (shootvals->select_delay > 0)
+ screenshot_delay (shootvals->select_delay);
+
+ shootvals->window_id = select_window (shootvals, screen);
+
+ if (! shootvals->window_id)
+ return GIMP_PDB_CANCEL;
+ }
+
+ if (shootvals->screenshot_delay > 0)
+ screenshot_delay (shootvals->screenshot_delay);
+
+ display = gdk_screen_get_display (screen);
+
+ screen_rect.x = 0;
+ screen_rect.y = 0;
+ screen_rect.width = gdk_screen_get_width (screen);
+ screen_rect.height = gdk_screen_get_height (screen);
+
+ if (shootvals->shoot_type == SHOOT_REGION)
+ {
+ rect.x = MIN (shootvals->x1, shootvals->x2);
+ rect.y = MIN (shootvals->y1, shootvals->y2);
+ rect.width = ABS (shootvals->x2 - shootvals->x1);
+ rect.height = ABS (shootvals->y2 - shootvals->y1);
+
+ monitor = gdk_screen_get_monitor_at_point (screen,
+ rect.x + rect.width / 2,
+ rect.y + rect.height / 2);
+ }
+ else
+ {
+ if (shootvals->shoot_type == SHOOT_ROOT)
+ {
+ window = gdk_screen_get_root_window (screen);
+
+ /* FIXME: figure monitor */
+ }
+ else
+ {
+ window = gdk_x11_window_foreign_new_for_display (display,
+ shootvals->window_id);
+
+ monitor = gdk_screen_get_monitor_at_window (screen, window);
+ }
+
+ if (! window)
+ {
+ g_set_error_literal (error, 0, 0, _("Specified window not found"));
+ return GIMP_PDB_EXECUTION_ERROR;
+ }
+
+ rect.width = gdk_window_get_width (window);
+ rect.height = gdk_window_get_height (window);
+ gdk_window_get_origin (window, &x, &y);
+
+ rect.x = x;
+ rect.y = y;
+ }
+
+ if (! gdk_rectangle_intersect (&rect, &screen_rect, &rect))
+ return GIMP_PDB_EXECUTION_ERROR;
+
+ window = gdk_screen_get_root_window (screen);
+ gdk_window_get_origin (window, &screen_x, &screen_y);
+
+ screenshot = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
+ rect.width, rect.height);
+
+ cr = cairo_create (screenshot);
+
+ gdk_cairo_set_source_window (cr, window,
+ - (rect.x - screen_x),
+ - (rect.y - screen_y));
+ cairo_paint (cr);
+
+ cairo_destroy (cr);
+
+ gdk_display_beep (display);
+
+ if (shootvals->shoot_type == SHOOT_WINDOW)
+ {
+ name = window_get_title (display, shootvals->window_id);
+
+ shape = window_get_shape (screen, shootvals->window_id);
+
+ if (shape)
+ cairo_region_translate (shape, x - rect.x, y - rect.y);
+ }
+
+ *image_ID = create_image (screenshot, shape, name);
+
+ cairo_surface_destroy (screenshot);
+
+ if (shape)
+ cairo_region_destroy (shape);
+
+ g_free (name);
+
+ /* FIXME: Some time might have passed until we get here.
+ * The cursor image should be grabbed together with the screenshot.
+ */
+ if ((shootvals->shoot_type == SHOOT_ROOT ||
+ shootvals->shoot_type == SHOOT_WINDOW) && shootvals->show_cursor)
+ add_cursor_image (*image_ID, display);
+
+ profile = gimp_screen_get_color_profile (screen, monitor);
+
+ if (profile)
+ {
+ gimp_image_set_color_profile (*image_ID, profile);
+ g_object_unref (profile);
+ }
+
+ return GIMP_PDB_SUCCESS;
+}
+
+#endif /* GDK_WINDOWING_X11 */
diff --git a/plug-ins/screenshot/screenshot-x11.h b/plug-ins/screenshot/screenshot-x11.h
new file mode 100644
index 0000000..9e988b1
--- /dev/null
+++ b/plug-ins/screenshot/screenshot-x11.h
@@ -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/>.
+ */
+
+#ifndef __SCREENSHOT_X11_H__
+#define __SCREENSHOT_X11_H__
+
+
+#ifdef GDK_WINDOWING_X11
+
+gboolean screenshot_x11_available (void);
+
+ScreenshotCapabilities screenshot_x11_get_capabilities (void);
+
+GimpPDBStatusType screenshot_x11_shoot (ScreenshotValues *shootvals,
+ GdkScreen *screen,
+ gint32 *image_ID,
+ GError **error);
+
+#endif /* GDK_WINDOWING_X11 */
+
+
+#endif /* __SCREENSHOT_X11_H__ */
diff --git a/plug-ins/screenshot/screenshot.c b/plug-ins/screenshot/screenshot.c
new file mode 100644
index 0000000..c8f205c
--- /dev/null
+++ b/plug-ins/screenshot/screenshot.c
@@ -0,0 +1,881 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * Screenshot plug-in
+ * Copyright 1998-2007 Sven Neumann <sven@gimp.org>
+ * Copyright 2003 Henrik Brix Andersen <brix@gimp.org>
+ * Copyright 2012 Simone Karin Lehmann - OS X patches
+ * Copyright 2016 Michael Natterer <mitch@gimp.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "screenshot.h"
+#include "screenshot-freedesktop.h"
+#include "screenshot-gnome-shell.h"
+#include "screenshot-icon.h"
+#include "screenshot-kwin.h"
+#include "screenshot-osx.h"
+#include "screenshot-x11.h"
+#include "screenshot-win32.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+
+/* Defines */
+
+#define PLUG_IN_PROC "plug-in-screenshot"
+#define PLUG_IN_BINARY "screenshot"
+#define PLUG_IN_ROLE "gimp-screenshot"
+
+#ifdef __GNUC__
+#ifdef GDK_NATIVE_WINDOW_POINTER
+#if GLIB_SIZEOF_VOID_P != 4
+#warning window_id does not fit in PDB_INT32
+#endif
+#endif
+#endif
+
+
+static void query (void);
+static void run (const gchar *name,
+ gint nparams,
+ const GimpParam *param,
+ gint *nreturn_vals,
+ GimpParam **return_vals);
+
+static GimpPDBStatusType shoot (GdkScreen *screen,
+ gint32 *image_ID,
+ GError **error);
+
+static gboolean shoot_dialog (GdkScreen **screen);
+static gboolean shoot_quit_timeout (gpointer data);
+static gboolean shoot_delay_timeout (gpointer data);
+
+
+/* Global Variables */
+
+static ScreenshotBackend backend = SCREENSHOT_BACKEND_NONE;
+static ScreenshotCapabilities capabilities = 0;
+static GtkWidget *select_delay_table = NULL;
+static GtkWidget *shot_delay_table = NULL;
+
+static ScreenshotValues shootvals =
+{
+ SHOOT_WINDOW, /* root window */
+ TRUE, /* include WM decorations */
+ 0, /* window ID */
+ 0, /* monitor */
+ 0, /* select delay */
+ 0, /* screenshot delay */
+ 0, /* coords of region dragged out by pointer */
+ 0,
+ 0,
+ 0,
+ FALSE, /* show cursor */
+ SCREENSHOT_PROFILE_POLICY_MONITOR
+};
+
+const GimpPlugInInfo PLUG_IN_INFO =
+{
+ NULL, /* init_proc */
+ NULL, /* quit_proc */
+ query, /* query_proc */
+ run /* run_proc */
+};
+
+
+/* Functions */
+
+MAIN ()
+
+static void
+query (void)
+{
+ static const GimpParamDef args[] =
+ {
+ { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
+ { GIMP_PDB_INT32, "shoot-type", "The Shoot type { SHOOT-WINDOW (0), SHOOT-ROOT (1), SHOOT-REGION (2) }" },
+ { GIMP_PDB_INT32, "window-id", "Window id for SHOOT-WINDOW" },
+ { GIMP_PDB_INT32, "x1", "Region left x coord for SHOOT-REGION" },
+ { GIMP_PDB_INT32, "y1", "Region top y coord for SHOOT-REGION" },
+ { GIMP_PDB_INT32, "x2", "Region right x coord for SHOOT-REGION" },
+ { GIMP_PDB_INT32, "y2", "Region bottom y coord for SHOOT-REGION" }
+ };
+
+ static const GimpParamDef return_vals[] =
+ {
+ { GIMP_PDB_IMAGE, "image", "Output image" }
+ };
+
+ gimp_install_procedure (PLUG_IN_PROC,
+ N_("Create an image from an area of the screen"),
+ "The plug-in takes screenshots of an "
+ "interactively selected window or of the desktop, "
+ "either the whole desktop or an interactively "
+ "selected region. When called non-interactively, it "
+ "may grab the root window or use the window-id "
+ "passed as a parameter. The last four parameters "
+ "are optional and can be used to specify the corners "
+ "of the region to be grabbed."
+ "On Mac OS X or on gnome-shell, "
+ "when called non-interactively, the plug-in"
+ "only can take screenshots of the entire root window."
+ "Grabbing a window or a region is not supported"
+ "non-interactively. To grab a region or a particular"
+ "window, you need to use the interactive mode."
+ ,
+ "Sven Neumann <sven@gimp.org>, "
+ "Henrik Brix Andersen <brix@gimp.org>,"
+ "Simone Karin Lehmann",
+ "1998 - 2008",
+ "v1.1 (2008/04)",
+ N_("_Screenshot..."),
+ NULL,
+ GIMP_PLUGIN,
+ G_N_ELEMENTS (args),
+ G_N_ELEMENTS (return_vals),
+ args, return_vals);
+
+ gimp_plugin_menu_register (PLUG_IN_PROC, "<Image>/File/Create/Acquire");
+ gimp_plugin_icon_register (PLUG_IN_PROC, GIMP_ICON_TYPE_INLINE_PIXBUF,
+ screenshot_icon);
+}
+
+static void
+run (const gchar *name,
+ gint nparams,
+ const GimpParam *param,
+ gint *nreturn_vals,
+ GimpParam **return_vals)
+{
+ static GimpParam values[2];
+ GimpPDBStatusType status = GIMP_PDB_SUCCESS;
+ GimpRunMode run_mode;
+ GdkScreen *screen = NULL;
+ gint32 image_ID;
+ GError *error = NULL;
+
+ INIT_I18N ();
+ gegl_init (NULL, NULL);
+
+ run_mode = param[0].data.d_int32;
+
+ *nreturn_vals = 1;
+ *return_vals = values;
+
+ values[0].type = GIMP_PDB_STATUS;
+ values[0].data.d_status = status;
+
+#ifdef PLATFORM_OSX
+ if (! backend && screenshot_osx_available ())
+ {
+ backend = SCREENSHOT_BACKEND_OSX;
+ capabilities = screenshot_osx_get_capabilities ();
+
+ /* on OS X, this just means shoot the shadow, default to nope */
+ shootvals.decorate = FALSE;
+ }
+#endif
+
+#ifdef G_OS_WIN32
+ if (! backend && screenshot_win32_available ())
+ {
+ backend = SCREENSHOT_BACKEND_WIN32;
+ capabilities = screenshot_win32_get_capabilities ();
+ }
+#endif
+
+ if (! backend && screenshot_gnome_shell_available ())
+ {
+ backend = SCREENSHOT_BACKEND_GNOME_SHELL;
+ capabilities = screenshot_gnome_shell_get_capabilities ();
+ }
+ else if (! backend && screenshot_kwin_available ())
+ {
+ backend = SCREENSHOT_BACKEND_KWIN;
+ capabilities = screenshot_kwin_get_capabilities ();
+ }
+
+#ifdef GDK_WINDOWING_X11
+ if (! backend && screenshot_x11_available ())
+ {
+ backend = SCREENSHOT_BACKEND_X11;
+ capabilities = screenshot_x11_get_capabilities ();
+ }
+#endif
+ else if (! backend && screenshot_freedesktop_available ())
+ {
+ backend = SCREENSHOT_BACKEND_FREEDESKTOP;
+ capabilities = screenshot_freedesktop_get_capabilities ();
+ }
+
+ /* how are we running today? */
+ switch (run_mode)
+ {
+ case GIMP_RUN_INTERACTIVE:
+ /* Possibly retrieve data from a previous run */
+ gimp_get_data (PLUG_IN_PROC, &shootvals);
+ shootvals.window_id = 0;
+
+ if ((shootvals.shoot_type == SHOOT_WINDOW &&
+ ! (capabilities & SCREENSHOT_CAN_SHOOT_WINDOW)) ||
+ (shootvals.shoot_type == SHOOT_REGION &&
+ ! (capabilities & SCREENSHOT_CAN_SHOOT_REGION)))
+ {
+ /* Shoot root is the only type of shoot which is definitely
+ * shared by all screenshot backends (basically just snap the
+ * whole display setup).
+ */
+ shootvals.shoot_type = SHOOT_ROOT;
+ }
+
+ /* Get information from the dialog */
+ if (! shoot_dialog (&screen))
+ status = GIMP_PDB_CANCEL;
+ break;
+
+ case GIMP_RUN_NONINTERACTIVE:
+ if (nparams == 3 || nparams == 7)
+ {
+ shootvals.shoot_type = param[1].data.d_int32;
+ shootvals.window_id = param[2].data.d_int32;
+ shootvals.select_delay = 0;
+
+ if (shootvals.shoot_type < SHOOT_WINDOW ||
+ shootvals.shoot_type > SHOOT_REGION)
+ {
+ status = GIMP_PDB_CALLING_ERROR;
+ }
+ else if (shootvals.shoot_type == SHOOT_REGION)
+ {
+ if (nparams == 7)
+ {
+ shootvals.x1 = param[3].data.d_int32;
+ shootvals.y1 = param[4].data.d_int32;
+ shootvals.x2 = param[5].data.d_int32;
+ shootvals.y2 = param[6].data.d_int32;
+ }
+ else
+ {
+ status = GIMP_PDB_CALLING_ERROR;
+ }
+ }
+ }
+ else
+ {
+ status = GIMP_PDB_CALLING_ERROR;
+ }
+
+ if (status == GIMP_PDB_SUCCESS)
+ {
+ if (! gdk_init_check (NULL, NULL))
+ status = GIMP_PDB_CALLING_ERROR;
+
+ if (! (capabilities & SCREENSHOT_CAN_PICK_NONINTERACTIVELY))
+ {
+ if (shootvals.shoot_type == SHOOT_WINDOW ||
+ shootvals.shoot_type == SHOOT_REGION)
+ {
+ status = GIMP_PDB_CALLING_ERROR;
+ }
+ }
+ }
+ break;
+
+ case GIMP_RUN_WITH_LAST_VALS:
+ /* Possibly retrieve data from a previous run */
+ gimp_get_data (PLUG_IN_PROC, &shootvals);
+ break;
+
+ default:
+ break;
+ }
+
+ if (status == GIMP_PDB_SUCCESS)
+ {
+ status = shoot (screen, &image_ID, &error);
+ }
+
+ if (status == GIMP_PDB_SUCCESS)
+ {
+ gchar *comment = gimp_get_default_comment ();
+
+ gimp_image_undo_disable (image_ID);
+
+ if (shootvals.profile_policy == SCREENSHOT_PROFILE_POLICY_SRGB)
+ {
+ GimpColorProfile *srgb_profile = gimp_color_profile_new_rgb_srgb ();
+
+ gimp_image_convert_color_profile (image_ID,
+ srgb_profile,
+ GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
+ TRUE);
+ g_object_unref (srgb_profile);
+ }
+
+ if (comment)
+ {
+ GimpParasite *parasite;
+
+ parasite = gimp_parasite_new ("gimp-comment",
+ GIMP_PARASITE_PERSISTENT,
+ strlen (comment) + 1, comment);
+
+ gimp_image_attach_parasite (image_ID, parasite);
+ gimp_parasite_free (parasite);
+
+ g_free (comment);
+ }
+
+ gimp_image_undo_enable (image_ID);
+
+ if (run_mode == GIMP_RUN_INTERACTIVE)
+ {
+ /* Store variable states for next run */
+ gimp_set_data (PLUG_IN_PROC, &shootvals, sizeof (ScreenshotValues));
+
+ gimp_display_new (image_ID);
+
+ /* Give some sort of feedback that the shot is done */
+ if (shootvals.select_delay > 0)
+ {
+ gdk_display_beep (gdk_screen_get_display (screen));
+ gdk_flush (); /* flush so the beep makes it to the server */
+ }
+ }
+
+ *nreturn_vals = 2;
+
+ values[1].type = GIMP_PDB_IMAGE;
+ values[1].data.d_image = image_ID;
+ }
+
+ if (status != GIMP_PDB_SUCCESS && error)
+ {
+ *nreturn_vals = 2;
+ values[1].type = GIMP_PDB_STRING;
+ values[1].data.d_string = error->message;
+ }
+
+ values[0].data.d_status = status;
+}
+
+
+/* The main Screenshot function */
+
+static GimpPDBStatusType
+shoot (GdkScreen *screen,
+ gint32 *image_ID,
+ GError **error)
+{
+#ifdef PLATFORM_OSX
+ if (backend == SCREENSHOT_BACKEND_OSX)
+ return screenshot_osx_shoot (&shootvals, screen, image_ID, error);
+#endif
+
+#ifdef G_OS_WIN32
+ if (backend == SCREENSHOT_BACKEND_WIN32)
+ return screenshot_win32_shoot (&shootvals, screen, image_ID, error);
+#endif
+
+ if (backend == SCREENSHOT_BACKEND_FREEDESKTOP)
+ return screenshot_freedesktop_shoot (&shootvals, screen, image_ID, error);
+ else if (backend == SCREENSHOT_BACKEND_GNOME_SHELL)
+ return screenshot_gnome_shell_shoot (&shootvals, screen, image_ID, error);
+ else if (backend == SCREENSHOT_BACKEND_KWIN)
+ return screenshot_kwin_shoot (&shootvals, screen, image_ID, error);
+
+#ifdef GDK_WINDOWING_X11
+ if (backend == SCREENSHOT_BACKEND_X11)
+ return screenshot_x11_shoot (&shootvals, screen, image_ID, error);
+#endif
+
+ return GIMP_PDB_CALLING_ERROR; /* silence compiler */
+}
+
+
+/* Screenshot dialog */
+
+static void
+shoot_dialog_add_hint (GtkNotebook *notebook,
+ ShootType type,
+ const gchar *hint)
+{
+ GtkWidget *label;
+
+ label = g_object_new (GTK_TYPE_LABEL,
+ "label", hint,
+ "wrap", TRUE,
+ "justify", GTK_JUSTIFY_LEFT,
+ "xalign", 0.0,
+ "yalign", 0.0,
+ NULL);
+ gimp_label_set_attributes (GTK_LABEL (label),
+ PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
+ -1);
+
+ gtk_notebook_insert_page (notebook, label, NULL, type);
+ gtk_widget_show (label);
+}
+
+static void
+shoot_radio_button_toggled (GtkWidget *widget,
+ GtkWidget *notebook)
+{
+ gimp_radio_button_update (widget, &shootvals.shoot_type);
+
+ if (select_delay_table)
+ {
+ if (shootvals.shoot_type == SHOOT_ROOT ||
+ (shootvals.shoot_type == SHOOT_WINDOW &&
+ ! (capabilities & SCREENSHOT_CAN_PICK_WINDOW)))
+ {
+ gtk_widget_hide (select_delay_table);
+ }
+ else
+ {
+ gtk_widget_show (select_delay_table);
+ }
+ }
+ if (shot_delay_table)
+ {
+ if (shootvals.shoot_type == SHOOT_WINDOW &&
+ (capabilities & SCREENSHOT_CAN_PICK_WINDOW) &&
+ ! (capabilities & SCREENSHOT_CAN_DELAY_WINDOW_SHOT))
+ {
+ gtk_widget_hide (shot_delay_table);
+ }
+ else
+ {
+ gtk_widget_show (shot_delay_table);
+ }
+ }
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), shootvals.shoot_type);
+}
+
+static gboolean
+shoot_dialog (GdkScreen **screen)
+{
+ GtkWidget *dialog;
+ GtkWidget *main_vbox;
+ GtkWidget *notebook1;
+ GtkWidget *notebook2;
+ GtkWidget *frame;
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *label;
+ GtkWidget *button;
+ GtkWidget *toggle;
+ GtkWidget *spinner;
+ GtkWidget *table;
+ GSList *radio_group = NULL;
+ GtkAdjustment *adj;
+ gboolean run;
+ GtkWidget *cursor_toggle = NULL;
+
+ gimp_ui_init (PLUG_IN_BINARY, FALSE);
+
+ dialog = gimp_dialog_new (_("Screenshot"), PLUG_IN_ROLE,
+ NULL, 0,
+ gimp_standard_help_func, PLUG_IN_PROC,
+
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ _("S_nap"), GTK_RESPONSE_OK,
+
+ NULL);
+
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+ GTK_RESPONSE_OK,
+ GTK_RESPONSE_CANCEL,
+ -1);
+
+ main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
+ gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
+ main_vbox, FALSE, FALSE, 0);
+ gtk_widget_show (main_vbox);
+
+
+ /* Create delay hints notebooks early */
+ notebook1 = g_object_new (GTK_TYPE_NOTEBOOK,
+ "show-border", FALSE,
+ "show-tabs", FALSE,
+ NULL);
+ notebook2 = g_object_new (GTK_TYPE_NOTEBOOK,
+ "show-border", FALSE,
+ "show-tabs", FALSE,
+ NULL);
+
+ /* Area */
+ frame = gimp_frame_new (_("Area"));
+ gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
+ gtk_widget_show (frame);
+
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_container_add (GTK_CONTAINER (frame), vbox);
+ gtk_widget_show (vbox);
+
+ /* Single window */
+ if (capabilities & SCREENSHOT_CAN_SHOOT_WINDOW)
+ {
+ button = gtk_radio_button_new_with_mnemonic (radio_group,
+ _("Take a screenshot of "
+ "a single _window"));
+ radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
+ gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+ gtk_widget_show (button);
+
+ g_object_set_data (G_OBJECT (button), "gimp-item-data",
+ GINT_TO_POINTER (SHOOT_WINDOW));
+
+ g_signal_connect (button, "toggled",
+ G_CALLBACK (shoot_radio_button_toggled),
+ notebook1);
+ g_signal_connect (button, "toggled",
+ G_CALLBACK (shoot_radio_button_toggled),
+ notebook2);
+
+ /* Window decorations */
+ if (capabilities & SCREENSHOT_CAN_SHOOT_DECORATIONS)
+ {
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+ gtk_widget_show (hbox);
+
+ toggle = gtk_check_button_new_with_mnemonic (_("Include window _decoration"));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
+ shootvals.decorate);
+ gtk_box_pack_start (GTK_BOX (hbox), toggle, TRUE, TRUE, 24);
+ gtk_widget_show (toggle);
+
+ g_signal_connect (toggle, "toggled",
+ G_CALLBACK (gimp_toggle_button_update),
+ &shootvals.decorate);
+
+ g_object_bind_property (button, "active",
+ toggle, "sensitive",
+ G_BINDING_SYNC_CREATE);
+ }
+ /* Mouse pointer */
+ if (capabilities & SCREENSHOT_CAN_SHOOT_POINTER)
+ {
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+ gtk_widget_show (hbox);
+
+ cursor_toggle = gtk_check_button_new_with_mnemonic (_("Include _mouse pointer"));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cursor_toggle),
+ shootvals.show_cursor);
+ gtk_box_pack_start (GTK_BOX (hbox), cursor_toggle, TRUE, TRUE, 24);
+ gtk_widget_show (cursor_toggle);
+
+ g_signal_connect (cursor_toggle, "toggled",
+ G_CALLBACK (gimp_toggle_button_update),
+ &shootvals.show_cursor);
+
+ g_object_bind_property (button, "active",
+ cursor_toggle, "sensitive",
+ G_BINDING_SYNC_CREATE);
+ }
+
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
+ shootvals.shoot_type == SHOOT_WINDOW);
+ }
+
+ /* Whole screen */
+ button = gtk_radio_button_new_with_mnemonic (radio_group,
+ _("Take a screenshot of "
+ "the entire _screen"));
+ radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
+ gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+ gtk_widget_show (button);
+
+ g_object_set_data (G_OBJECT (button), "gimp-item-data",
+ GINT_TO_POINTER (SHOOT_ROOT));
+
+ g_signal_connect (button, "toggled",
+ G_CALLBACK (shoot_radio_button_toggled),
+ notebook1);
+ g_signal_connect (button, "toggled",
+ G_CALLBACK (shoot_radio_button_toggled),
+ notebook2);
+
+ /* Mouse pointer */
+ if (capabilities & SCREENSHOT_CAN_SHOOT_POINTER)
+ {
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+ gtk_widget_show (hbox);
+
+ toggle = gtk_check_button_new_with_mnemonic (_("Include _mouse pointer"));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
+ shootvals.show_cursor);
+ gtk_box_pack_start (GTK_BOX (hbox), toggle, TRUE, TRUE, 24);
+ gtk_widget_show (toggle);
+
+ g_signal_connect (toggle, "toggled",
+ G_CALLBACK (gimp_toggle_button_update),
+ &shootvals.show_cursor);
+
+ if (cursor_toggle)
+ {
+ g_object_bind_property (cursor_toggle, "active",
+ toggle, "active",
+ G_BINDING_BIDIRECTIONAL);
+ }
+ g_object_bind_property (button, "active",
+ toggle, "sensitive",
+ G_BINDING_SYNC_CREATE);
+ }
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
+ shootvals.shoot_type == SHOOT_ROOT);
+
+ /* Dragged region */
+ if (capabilities & SCREENSHOT_CAN_SHOOT_REGION)
+ {
+ button = gtk_radio_button_new_with_mnemonic (radio_group,
+ _("Select a _region to grab"));
+ radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
+ shootvals.shoot_type == SHOOT_REGION);
+ gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+ gtk_widget_show (button);
+
+ g_object_set_data (G_OBJECT (button), "gimp-item-data",
+ GINT_TO_POINTER (SHOOT_REGION));
+
+ g_signal_connect (button, "toggled",
+ G_CALLBACK (shoot_radio_button_toggled),
+ notebook1);
+ g_signal_connect (button, "toggled",
+ G_CALLBACK (shoot_radio_button_toggled),
+ notebook2);
+ }
+
+ frame = gimp_frame_new (_("Delay"));
+ gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
+ gtk_widget_show (frame);
+
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
+ gtk_container_add (GTK_CONTAINER (frame), vbox);
+ gtk_widget_show (vbox);
+
+ /* Selection delay */
+ table = gtk_table_new (2, 3, FALSE);
+ select_delay_table = table;
+ gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
+ /* Check if this delay must be hidden from start. */
+ if (shootvals.shoot_type == SHOOT_REGION ||
+ (shootvals.shoot_type == SHOOT_WINDOW &&
+ capabilities & SCREENSHOT_CAN_PICK_WINDOW))
+ {
+ gtk_widget_show (select_delay_table);
+ }
+
+ label = gtk_label_new (_("Selection delay: "));
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
+ GTK_SHRINK, GTK_SHRINK, 0, 0);
+ gtk_widget_show (label);
+
+ adj = (GtkAdjustment *)
+ gtk_adjustment_new (shootvals.select_delay,
+ 0.0, 100.0, 1.0, 5.0, 0.0);
+ spinner = gimp_spin_button_new (adj, 0, 0);
+ gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinner), TRUE);
+ gtk_table_attach (GTK_TABLE (table), spinner, 1, 2, 0, 1,
+ GTK_SHRINK, GTK_SHRINK, 0, 0);
+ gtk_widget_show (spinner);
+
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (gimp_int_adjustment_update),
+ &shootvals.select_delay);
+
+ /* translators: this is the unit label of a spinbutton */
+ label = gtk_label_new (_("seconds"));
+ gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
+ GTK_EXPAND | GTK_FILL, GTK_SHRINK, 1.0, 0);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.1, 0.5);
+ gtk_widget_show (label);
+
+ /* Selection delay hints */
+ gtk_table_attach (GTK_TABLE (table), notebook1, 0, 3, 1, 2,
+ GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
+ gtk_widget_show (notebook1);
+
+ /* No selection delay for full-screen. */
+ shoot_dialog_add_hint (GTK_NOTEBOOK (notebook1), SHOOT_ROOT, "");
+ shoot_dialog_add_hint (GTK_NOTEBOOK (notebook1), SHOOT_REGION,
+ _("After the delay, drag your mouse to select "
+ "the region for the screenshot."));
+#ifdef G_OS_WIN32
+ shoot_dialog_add_hint (GTK_NOTEBOOK (notebook1), SHOOT_WINDOW,
+ _("Click in a window to snap it after delay."));
+#else
+ if (capabilities & SCREENSHOT_CAN_PICK_WINDOW)
+ {
+ shoot_dialog_add_hint (GTK_NOTEBOOK (notebook1), SHOOT_WINDOW,
+ _("At the end of the delay, click in a window "
+ "to snap it."));
+ }
+ else
+ {
+ shoot_dialog_add_hint (GTK_NOTEBOOK (notebook1), SHOOT_WINDOW, "");
+ }
+#endif
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook1), shootvals.shoot_type);
+
+ /* Screenshot delay */
+ table = gtk_table_new (2, 3, FALSE);
+ shot_delay_table = table;
+ gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
+ if (shootvals.shoot_type != SHOOT_WINDOW ||
+ ! (capabilities & SCREENSHOT_CAN_PICK_WINDOW) ||
+ (capabilities & SCREENSHOT_CAN_DELAY_WINDOW_SHOT))
+ {
+ gtk_widget_show (table);
+ }
+
+ label = gtk_label_new_with_mnemonic (_("Screenshot dela_y: "));
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
+ GTK_SHRINK, GTK_SHRINK, 0, 0);
+ gtk_widget_show (label);
+
+ adj = (GtkAdjustment *)
+ gtk_adjustment_new (shootvals.screenshot_delay,
+ 0.0, 100.0, 1.0, 5.0, 0.0);
+ spinner = gimp_spin_button_new (adj, 0, 0);
+ gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinner), TRUE);
+ gtk_table_attach (GTK_TABLE (table), spinner, 1, 2, 0, 1,
+ GTK_SHRINK, GTK_SHRINK, 0, 0);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (spinner));
+ gtk_widget_show (spinner);
+
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (gimp_int_adjustment_update),
+ &shootvals.screenshot_delay);
+
+ /* translators: this is the unit label of a spinbutton */
+ label = gtk_label_new (_("seconds"));
+ gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
+ GTK_EXPAND | GTK_FILL, GTK_SHRINK, 1.0, 0);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.1, 0.5);
+ gtk_widget_show (label);
+
+ /* Screenshot delay hints */
+ gtk_table_attach (GTK_TABLE (table), notebook2, 0, 3, 1, 2,
+ GTK_EXPAND | GTK_FILL, GTK_SHRINK, 0, 0);
+ gtk_widget_show (notebook2);
+
+ shoot_dialog_add_hint (GTK_NOTEBOOK (notebook2), SHOOT_ROOT,
+ _("After the delay, the screenshot is taken."));
+ shoot_dialog_add_hint (GTK_NOTEBOOK (notebook2), SHOOT_REGION,
+ _("Once the region is selected, it will be "
+ "captured after this delay."));
+ if (capabilities & SCREENSHOT_CAN_PICK_WINDOW)
+ {
+ shoot_dialog_add_hint (GTK_NOTEBOOK (notebook2), SHOOT_WINDOW,
+ _("Once the window is selected, it will be "
+ "captured after this delay."));
+ }
+ else
+ {
+ shoot_dialog_add_hint (GTK_NOTEBOOK (notebook2), SHOOT_WINDOW,
+ _("After the delay, the active window "
+ "will be captured."));
+ }
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook2), shootvals.shoot_type);
+
+ /* Color profile */
+ frame = gimp_int_radio_group_new (TRUE,
+ _("Color Profile"),
+ G_CALLBACK (gimp_radio_button_update),
+ &shootvals.profile_policy,
+ shootvals.profile_policy,
+
+ _("Tag image with _monitor profile"),
+ SCREENSHOT_PROFILE_POLICY_MONITOR,
+ NULL,
+
+ _("Convert image to sR_GB"),
+ SCREENSHOT_PROFILE_POLICY_SRGB,
+ NULL,
+
+ NULL);
+ gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
+ gtk_widget_show (frame);
+
+
+ gtk_widget_show (dialog);
+
+ run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
+
+ if (run)
+ {
+ /* get the screen on which we are running */
+ *screen = gtk_widget_get_screen (dialog);
+ }
+
+ gtk_widget_destroy (dialog);
+
+ if (run)
+ {
+ /* A short timeout to give the server a chance to
+ * redraw the area that was obscured by our dialog.
+ */
+ g_timeout_add (100, shoot_quit_timeout, NULL);
+ gtk_main ();
+ }
+
+ return run;
+}
+
+static gboolean
+shoot_quit_timeout (gpointer data)
+{
+ gtk_main_quit ();
+
+ return FALSE;
+}
+
+
+static gboolean
+shoot_delay_timeout (gpointer data)
+{
+ gint *seconds_left = data;
+
+ (*seconds_left)--;
+
+ if (!*seconds_left)
+ gtk_main_quit ();
+
+ return *seconds_left;
+}
+
+
+/* public functions */
+
+void
+screenshot_delay (gint seconds)
+{
+ g_timeout_add (1000, shoot_delay_timeout, &seconds);
+ gtk_main ();
+}
diff --git a/plug-ins/screenshot/screenshot.h b/plug-ins/screenshot/screenshot.h
new file mode 100644
index 0000000..13e51fa
--- /dev/null
+++ b/plug-ins/screenshot/screenshot.h
@@ -0,0 +1,80 @@
+/* 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 __SCREENSHOT_H__
+#define __SCREENSHOT_H__
+
+
+typedef enum
+{
+ SCREENSHOT_BACKEND_NONE,
+ SCREENSHOT_BACKEND_OSX,
+ SCREENSHOT_BACKEND_WIN32,
+ SCREENSHOT_BACKEND_FREEDESKTOP,
+ SCREENSHOT_BACKEND_GNOME_SHELL,
+ SCREENSHOT_BACKEND_KWIN,
+ SCREENSHOT_BACKEND_X11
+} ScreenshotBackend;
+
+typedef enum
+{
+ SCREENSHOT_CAN_SHOOT_DECORATIONS = 0x1 << 0,
+ SCREENSHOT_CAN_SHOOT_POINTER = 0x1 << 1,
+ SCREENSHOT_CAN_PICK_NONINTERACTIVELY = 0x1 << 2,
+ SCREENSHOT_CAN_SHOOT_REGION = 0x1 << 3,
+ /* SHOOT_WINDOW mode only: it window selection requires active click. */
+ SCREENSHOT_CAN_PICK_WINDOW = 0x1 << 4,
+ /* SHOOT_WINDOW + SCREENSHOT_CAN_PICK_WINDOW only: if a delay can be
+ * inserted in-between selection click and actual snapshot. */
+ SCREENSHOT_CAN_DELAY_WINDOW_SHOT = 0x1 << 5,
+ SCREENSHOT_CAN_SHOOT_WINDOW = 0x1 << 6
+} ScreenshotCapabilities;
+
+typedef enum
+{
+ SCREENSHOT_PROFILE_POLICY_MONITOR,
+ SCREENSHOT_PROFILE_POLICY_SRGB
+} ScreenshotProfilePolicy;
+
+typedef enum
+{
+ SHOOT_WINDOW,
+ SHOOT_ROOT,
+ SHOOT_REGION
+} ShootType;
+
+typedef struct
+{
+ ShootType shoot_type;
+ gboolean decorate;
+ guint window_id;
+ gint monitor;
+ guint select_delay;
+ guint screenshot_delay;
+ gint x1;
+ gint y1;
+ gint x2;
+ gint y2;
+ gboolean show_cursor;
+ ScreenshotProfilePolicy profile_policy;
+} ScreenshotValues;
+
+
+void screenshot_delay (gint seconds);
+
+
+#endif /* __SCREENSHOT_H__ */