diff options
Diffstat (limited to 'plug-ins/screenshot')
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 Binary files differnew file mode 100644 index 0000000..2357f84 --- /dev/null +++ b/plug-ins/screenshot/screenshot-win32-select.cur diff --git a/plug-ins/screenshot/screenshot-win32-small.ico b/plug-ins/screenshot/screenshot-win32-small.ico Binary files differnew file mode 100644 index 0000000..33f9a51 --- /dev/null +++ b/plug-ins/screenshot/screenshot-win32-small.ico 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 Binary files differnew file mode 100644 index 0000000..35ea973 --- /dev/null +++ b/plug-ins/screenshot/screenshot-win32.ico 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__ */ |