diff -Nru scrot-1.6/acinclude.m4 scrot-1.7/acinclude.m4 --- scrot-1.6/acinclude.m4 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/acinclude.m4 1970-01-01 00:00:00.000000000 +0000 @@ -1,136 +0,0 @@ -dnl @synopsis AC_PATH_GENERIC(LIBRARY [, MINIMUM-VERSION [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) -dnl -dnl Runs a LIBRARY-config script and defines LIBRARY_CFLAGS and LIBRARY_LIBS -dnl -dnl The script must support `--cflags' and `--libs' args. -dnl If MINIMUM-VERSION is specified, the script must also support the -dnl `--version' arg. -dnl If the `--with-library-[exec-]prefix' arguments to ./configure are given, -dnl it must also support `--prefix' and `--exec-prefix'. -dnl (In other words, it must be like gtk-config.) -dnl -dnl For example: -dnl -dnl AC_PATH_GENERIC(Foo, 1.0.0) -dnl -dnl would run `foo-config --version' and check that it is at least 1.0.0 -dnl -dnl If so, the following would then be defined: -dnl -dnl FOO_CFLAGS to `foo-config --cflags` -dnl FOO_LIBS to `foo-config --libs` -dnl -dnl At present there is no support for additional "MODULES" (see AM_PATH_GTK) -dnl (shamelessly stolen from gtk.m4 and then hacked around a fair amount) -dnl -dnl @author Angus Lees -dnl @version $Id: acinclude.m4,v 1.1 2001/08/08 20:23:52 gilbertt Exp $ - -AC_DEFUN([AC_PATH_GENERIC], -[dnl -dnl we're going to need uppercase, lowercase and user-friendly versions of the -dnl string `LIBRARY' -pushdef([UP], translit([$1], [a-z], [A-Z]))dnl -pushdef([DOWN], translit([$1], [A-Z], [a-z]))dnl - -dnl -dnl Get the cflags and libraries from the LIBRARY-config script -dnl -AC_ARG_WITH(DOWN-prefix,[ --with-]DOWN[-prefix=PFX Prefix where $1 is installed (optional)], - DOWN[]_config_prefix="$withval", DOWN[]_config_prefix="") -AC_ARG_WITH(DOWN-exec-prefix,[ --with-]DOWN[-exec-prefix=PFX Exec prefix where $1 is installed (optional)], - DOWN[]_config_exec_prefix="$withval", DOWN[]_config_exec_prefix="") - - if test x$DOWN[]_config_exec_prefix != x ; then - DOWN[]_config_args="$DOWN[]_config_args --exec-prefix=$DOWN[]_config_exec_prefix" - if test x${UP[]_CONFIG+set} != xset ; then - UP[]_CONFIG=$DOWN[]_config_exec_prefix/bin/DOWN-config - fi - fi - if test x$DOWN[]_config_prefix != x ; then - DOWN[]_config_args="$DOWN[]_config_args --prefix=$DOWN[]_config_prefix" - if test x${UP[]_CONFIG+set} != xset ; then - UP[]_CONFIG=$DOWN[]_config_prefix/bin/DOWN-config - fi - fi - - AC_PATH_PROG(UP[]_CONFIG, DOWN-config, no) - ifelse([$2], , - AC_MSG_CHECKING(for $1), - AC_MSG_CHECKING(for $1 - version >= $2) - ) - no_[]DOWN="" - if test "$UP[]_CONFIG" = "no" ; then - no_[]DOWN=yes - else - UP[]_CFLAGS="`$UP[]_CONFIG $DOWN[]_config_args --cflags`" - UP[]_LIBS="`$UP[]_CONFIG $DOWN[]_config_args --libs`" - ifelse([$2], , ,[ - DOWN[]_config_major_version=`$UP[]_CONFIG $DOWN[]_config_args \ - --version | sed 's/[[^0-9]]*\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` - DOWN[]_config_minor_version=`$UP[]_CONFIG $DOWN[]_config_args \ - --version | sed 's/[[^0-9]]*\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` - DOWN[]_config_micro_version=`$UP[]_CONFIG $DOWN[]_config_args \ - --version | sed 's/[[^0-9]]*\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` - DOWN[]_wanted_major_version="regexp($2, [\<\([0-9]*\)], [\1])" - DOWN[]_wanted_minor_version="regexp($2, [\<\([0-9]*\)\.\([0-9]*\)], [\2])" - DOWN[]_wanted_micro_version="regexp($2, [\<\([0-9]*\).\([0-9]*\).\([0-9]*\)], [\3])" - - # Compare wanted version to what config script returned. - # If I knew what library was being run, i'd probably also compile - # a test program at this point (which also extracted and tested - # the version in some library-specific way) - if test "$DOWN[]_config_major_version" -lt \ - "$DOWN[]_wanted_major_version" \ - -o \( "$DOWN[]_config_major_version" -eq \ - "$DOWN[]_wanted_major_version" \ - -a "$DOWN[]_config_minor_version" -lt \ - "$DOWN[]_wanted_minor_version" \) \ - -o \( "$DOWN[]_config_major_version" -eq \ - "$DOWN[]_wanted_major_version" \ - -a "$DOWN[]_config_minor_version" -eq \ - "$DOWN[]_wanted_minor_version" \ - -a "$DOWN[]_config_micro_version" -lt \ - "$DOWN[]_wanted_micro_version" \) ; then - # older version found - no_[]DOWN=yes - echo -n "*** An old version of $1 " - echo -n "($DOWN[]_config_major_version" - echo -n ".$DOWN[]_config_minor_version" - echo ".$DOWN[]_config_micro_version) was found." - echo -n "*** You need a version of $1 newer than " - echo -n "$DOWN[]_wanted_major_version" - echo -n ".$DOWN[]_wanted_minor_version" - echo ".$DOWN[]_wanted_micro_version." - echo "***" - echo "*** If you have already installed a sufficiently new version, this error" - echo "*** probably means that the wrong copy of the DOWN-config shell script is" - echo "*** being found. The easiest way to fix this is to remove the old version" - echo "*** of $1, but you can also set the UP[]_CONFIG environment to point to the" - echo "*** correct copy of DOWN-config. (In this case, you will have to" - echo "*** modify your LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf" - echo "*** so that the correct libraries are found at run-time)" - fi - ]) - fi - if test "x$no_[]DOWN" = x ; then - AC_MSG_RESULT(yes) - ifelse([$3], , :, [$3]) - else - AC_MSG_RESULT(no) - if test "$UP[]_CONFIG" = "no" ; then - echo "*** The DOWN-config script installed by $1 could not be found" - echo "*** If $1 was installed in PREFIX, make sure PREFIX/bin is in" - echo "*** your path, or set the UP[]_CONFIG environment variable to the" - echo "*** full path to DOWN-config." - fi - UP[]_CFLAGS="" - UP[]_LIBS="" - ifelse([$4], , :, [$4]) - fi - AC_SUBST(UP[]_CFLAGS) - AC_SUBST(UP[]_LIBS) - - popdef([UP]) - popdef([DOWN]) -]) diff -Nru scrot-1.6/AUTHORS scrot-1.7/AUTHORS --- scrot-1.6/AUTHORS 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/AUTHORS 2021-11-10 02:08:36.000000000 +0000 @@ -3,7 +3,7 @@ Since 2019, this source code is being maintained by: -Daniel T. Borelli +Daniel T. Borelli Guilherme Janczak Joao Eriberto Mota Filho and some people sending patches! diff -Nru scrot-1.6/autogen.sh scrot-1.7/autogen.sh --- scrot-1.6/autogen.sh 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/autogen.sh 2021-11-10 02:08:36.000000000 +0000 @@ -31,7 +31,7 @@ # Use clean option -if [ "$1" = "clean" -a ! -e Makefile ] +if [ "$1" = "clean" ] && [ ! -e Makefile ] then echo "Vanishing the code" rm -rf aclocal.m4 autom4te.cache/ compile configure depcomp install-sh \ @@ -40,7 +40,7 @@ fi # Do not use clean option -if [ "$1" = "clean" -a -e Makefile ] +if [ "$1" = "clean" ] && [ -e Makefile ] then echo "I can not clean. Use '$ make distclean'." exit 0 diff -Nru scrot-1.6/ChangeLog scrot-1.7/ChangeLog --- scrot-1.6/ChangeLog 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/ChangeLog 2021-11-10 02:08:36.000000000 +0000 @@ -1,3 +1,57 @@ +Tue Nov 09 20:41:00 -03:00 2021 Joao Eriberto Mota Filho +Version 1.7 + + [ a1346054 ] + + * Fixed: code style, add missing final newline. + * Fixed: autogen.sh: fix some shellcheck issues. + + [ c0dev0id ] + + * Replace insecure c-strings functions (following libbsd integration). + + [ Daniel T. Borelli ] alias @daltomi + + * New option: --select=hole (-shole), hole selection area. + * New option: --select=hide (-shide), hide selection area, support image. + * New option: --select=blur (-sblur), blur selection area. + * New option: (-) add redirection to standard output (format PNG). + * Improvement option: --stack, add an optional join direction (v/h). + * Fixed: free memory image and font resources. + * Bug fixed: segfault if mouse cursor image was not obtained. + * Use err/warn functions (following libbsd integration). + * Others various code improvement. + + [ Guilherme Janczak ] alias @guijan + + * Added new library dependency: libbsd. + * Autotools: added option --without-libbsd. + * Improvement: Autotools: remove unused files, remove obsolete macros, assume + C89 functions exist, delete scrot.spec. + * Improvement: remove unused C macro, use strndup function, use designated + initializers (C99). + * Improvement: Doc: polish the txt2man manual, CONTRIBUTING.md, TODO.md. + * Others various code improvement. + + [ IFo Hancroft ] alias @ifohancroft + + * New option: --file (-F), provide the filename as an option. + * Fixed: code style guideline violations (WebKit). + * Use strlcpy/strlcat (following libbsd integration). + + [ Joao Eriberto Mota Filho ] alias @eribertomota + + * Fixed a mistake in README.md. + + [ Peter Wu ] alias @peterwu + + * Convert all source files to the WebKit style. + + [ Wilson Smith ] alias @0wsmith + + * New option: --ignorekeyboard (-i), Don't exit for keyboard input. ESC still + exits. + Sun Jul 25 23:30:00 -03:00 2021 Joao Eriberto Mota Filho Version 1.6 @@ -233,13 +287,13 @@ "First, specifying -t would break the $f param to -exec. Second, the thumbnail and the screenshot got different timestamps. Third, one weren't able to specify geometry with -t. - + I fixed those and added, $m ( mini, instead of $t as it was taken ) so that one can do. - + $ scrot -t 91x0 -e 'echo $f,$m' 2003-03-08-104735_800x600_scrot.png,2003-03-08-104735_91x68_scrot-thumb.png` - + About the geometry, having either the width or height set to 0 makes it fill in the other pertaining the aspect ratio. " @@ -315,7 +369,7 @@ scrot '%Y-%m-%d_&wx&h.png' -e 'mv &f ~/shots/' This would create a file called something like 2000-10-30_2560x1024.png and move it to your shots directory. - + Sun Oct 29 01:02:16 2000 Tom Gilbert @@ -343,4 +397,3 @@ Thu Oct 26 14:09:52 2000 Tom Gilbert * Created scrot. - diff -Nru scrot-1.6/.cirrus.yml scrot-1.7/.cirrus.yml --- scrot-1.6/.cirrus.yml 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/.cirrus.yml 2021-11-10 02:08:36.000000000 +0000 @@ -48,20 +48,12 @@ install_script: - apk add autoconf autoconf-archive automake make pkgconfig clang gcc xorg-server-dev libxcomposite-dev libxext-dev libxfixes-dev - imlib2-dev musl-dev + imlib2-dev musl-dev bsd-compat-headers << : *common_script task: matrix: - container: - image: debian:oldstable - env: - OS: debian-oldstable - - container: - image: debian:stable - env: - OS: debian-stable - - container: image: debian:testing env: OS: debian-testing @@ -79,7 +71,7 @@ - apt-get update - apt-get install -y autoconf autoconf-archive make pkg-config clang gcc libx11-dev libxcomposite-dev libxext-dev libxfixes-dev - libimlib2-dev + libimlib2-dev libbsd-dev << : *common_script task: diff -Nru scrot-1.6/configure.ac scrot-1.7/configure.ac --- scrot-1.6/configure.ac 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/configure.ac 2021-11-10 02:08:36.000000000 +0000 @@ -1,15 +1,14 @@ dnl Process this file with autoconf to create configure. -AC_INIT([scrot], [1.6], [https://github.com/resurrecting-open-source-projects/scrot/issues], +AC_INIT([scrot], [1.7], [https://github.com/resurrecting-open-source-projects/scrot/issues], [],[https://github.com/resurrecting-open-source-projects/scrot]) AC_CONFIG_SRCDIR([src/main.c]) AM_INIT_AUTOMAKE(dist-bzip2) -AC_CONFIG_HEADER([src/config.h]) +AC_CONFIG_HEADERS([src/config.h]) AX_PREFIX_CONFIG_H([src/scrot_config.h]) # Checks for programs. AC_PROG_CC -AM_PROG_CC_STDC AC_PROG_INSTALL AC_PROG_MAKE_SET @@ -22,25 +21,29 @@ PKG_CHECK_MODULES([XFIXES], [xfixes]) PKG_CHECK_MODULES([IMLIB2], [imlib2]) +AC_ARG_WITH([libbsd], + AS_HELP_STRING([--without-libbsd], [Error when BSD functions are not found])) +AC_CHECK_FUNCS([strlcpy strlcat err errx],, [LIBBSD_NEEDED=yes]) +AS_IF([test "x$LIBBSD_NEEDED" = "xyes"], [ + AS_IF([test "x$with_libbsd" = "xno"], [ + AC_MSG_ERROR([BSD functions not found and --without-libbsd was used]) + ]) + PKG_CHECK_MODULES([LIBBSD], [libbsd-overlay],, + [AC_MSG_ERROR([BSD functions not found, libbsd is required])]) +]) + +AC_SUBST([LIBS], ["$X11_LIBS $XCOMPOSITE_LIBS $XEXT_LIBS $XFIXES_LIBS \ + $IMLIB2_LIBS $LIBBSD_LIBS $LIBS"]) +AC_SUBST([CPPFLAGS], ["$X11_CFLAGS $XCOMPOSITE_CFLAGS $XEXT_CFLAGS \ + $XFIXES_CFLAGS $IMLIB2_CFLAGS $LIBBSD_CFLAGS $CPPFLAGS"]) + # Checks for header files. -AC_PATH_X AC_CHECK_HEADERS([stdint.h sys/time.h unistd.h]) -# Checks for typedefs, structures, and compiler characteristics. -AC_CHECK_HEADER_STDBOOL -AC_C_INLINE -AC_C_CONST -AC_TYPE_SIZE_T -AC_CHECK_TYPES([ptrdiff_t]) - # Required: Checks for library functions. -AC_FUNC_MALLOC -AC_CHECK_FUNCS([getopt_long getsubopt atexit gethostname memset select strchr strdup strerror strpbrk strrchr strtol],, +AC_CHECK_FUNCS([getopt_long getsubopt gethostname select strdup strerror strndup strtol],, AC_MSG_ERROR([required functions are not present.])) -# Optional: Checks for library functions. -AC_CHECK_FUNCS([strndup]) - m4_pattern_forbid([^AX_],[=> GNU autoconf-archive not present. <=]) AC_CONFIG_FILES([Makefile src/Makefile]) diff -Nru scrot-1.6/CONTRIBUTING.md scrot-1.7/CONTRIBUTING.md --- scrot-1.6/CONTRIBUTING.md 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/CONTRIBUTING.md 2021-11-10 02:08:36.000000000 +0000 @@ -1,28 +1,40 @@ -## HOW TO CONTRIBUTE TO SCROT DEVELOPMENT +# CONTRIBUTING TO SCROT DEVELOPMENT -scrot is available at https://github.com/resurrecting-open-source-projects/scrot +#### Changes are to be sent as [pull requests on GitHub](https://github.com/resurrecting-open-source-projects/scrot/pulls). -If you are interested in contribute to scrot development, please, follow -the following steps: +## Setting up the development machine -1. Send a patch that fix an issue or that implement a new feature. - Alternatively, you can do a 'pull request'[1] in GitHub. +scrot aims to build with no modifications on all the free unix systems. The +master branch is also kept in working order at all times. Our builds are tested +all the way back to [Debian oldstable](https://wiki.debian.org/DebianOldStable), +so a scrot developer shouldn't need to build the latest git versions of the +dependencies to start hacking. - [1] https://help.github.com/articles/about-pull-requests +You will want to install the dependencies listed in the `Building` section of +[README.md](README.md). Look for the text `install_script` in the +[.cirrus.yml](.cirrus.yml) CI definitions for example package manager +invocations on many operating systems. -2. Ask for join to the scrot project in GitHub, if you want to work - officially. Note that this second step is not compulsory. However, - to accept you in project, is needed a minimum previous collaboration. +## Style +scrot is primarily written in C99 with +[POSIX 2008](https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/) +extensions. You're also free to make use of any documented function from our +libraries. Make sure to use +[libbsd functions](https://manpages.debian.org/unstable/libbsd-dev/libbsd.7.en.html) +where they're safer, cleaner or more convenient. -To find issues and bugs to fix, you can check these addresses: +scrot follows +[WebKit's code style guidelines](https://webkit.org/code-style-guidelines/) +with additional restrictions: +- No explicit casts. +- Use the identifier and not the type as the argument to the `sizeof` operator. - - https://github.com/resurrecting-open-source-projects/scrot - - https://bugs.debian.org/cgi-bin/pkgreport.cgi?dist=unstable;package=scrot - - https://bugs.launchpad.net/ubuntu/+source/scrot/+bugs - - https://apps.fedoraproject.org/packages/scrot/bugs - - https://bugs.gentoo.org/buglist.cgi?quicksearch=scrot +When in doubt, make use of the `clang-format` source code formatter-it comes +with the WebKit style by default. -If you want to join, please make a contact. +## Low-hanging fruit - -- Eriberto, Tue, 12 Feb 2019 22:50:53 -0200. +Ongoing tasks will be written to [TODO.md](TODO.md). + +Regular contributors can ask to join the scrot project on GitHub. diff -Nru scrot-1.6/debian/changelog scrot-1.7/debian/changelog --- scrot-1.6/debian/changelog 2021-08-15 16:55:35.000000000 +0000 +++ scrot-1.7/debian/changelog 2021-11-10 17:50:35.000000000 +0000 @@ -1,3 +1,16 @@ +scrot (1.7-1) unstable; urgency=medium + + * New upstream version 1.7. + * debian/control: + - Added libbsd-dev to Build-Depends field. + - Bumped Standards-Version to 4.6.0.1. + - Minor change in long description. + * debian/copyright: updated rights for upstream. + * debian/patches/010_update-autoconf-rules.patch: removed because the + upstream fixed the source code. Thanks. + + -- Joao Eriberto Mota Filho Wed, 10 Nov 2021 14:50:35 -0300 + scrot (1.6-1) unstable; urgency=medium * New upstream version 1.6. diff -Nru scrot-1.6/debian/control scrot-1.7/debian/control --- scrot-1.6/debian/control 2021-07-26 20:25:16.000000000 +0000 +++ scrot-1.7/debian/control 2021-11-10 17:50:35.000000000 +0000 @@ -2,9 +2,10 @@ Section: graphics Priority: optional Maintainer: Joao Eriberto Mota Filho -Standards-Version: 4.5.1 +Standards-Version: 4.6.0.1 Build-Depends: debhelper-compat (= 13), autoconf-archive, + libbsd-dev, libimlib2-dev, libxcomposite-dev, libxfixes-dev, @@ -26,6 +27,7 @@ - The screenshot's quality is configurable. - It is possible to capture a specific window or a rectangular area on the screen. + - Other features. . Because scrot is a command line utility, it can easily be scripted and put to novel uses. For instance, scrot can be used to monitor a diff -Nru scrot-1.6/debian/copyright scrot-1.7/debian/copyright --- scrot-1.6/debian/copyright 2021-07-26 19:56:53.000000000 +0000 +++ scrot-1.7/debian/copyright 2021-11-10 17:50:35.000000000 +0000 @@ -12,10 +12,10 @@ 2009 George Danchev 2009 James Cameron 2010 Ibragimov Rinat - 2016-2020 Joao Eriberto Mota Filho + 2016-2021 Joao Eriberto Mota Filho 2017 Stoney Sauce 2019 Daniel Lublin - 2019-2021 Daniel T. Borelli + 2019-2021 Daniel T. Borelli 2019 Jade Auer 2020 blockparole 2020 Cungsten Tarbide @@ -27,7 +27,10 @@ 2021 c0dev0id 2021 Christopher R. Nelson 2021 Guilherme Janczak + 2021 IFo Hancroft 2021 Martin C + 2021 Peter Wu + 2021 Wilson Smith <01wsmith+gh@gmail.com> License: MIT-advertising Files: autogen.sh diff -Nru scrot-1.6/debian/patches/010_update-autoconf-rules.patch scrot-1.7/debian/patches/010_update-autoconf-rules.patch --- scrot-1.6/debian/patches/010_update-autoconf-rules.patch 2021-08-15 16:55:35.000000000 +0000 +++ scrot-1.7/debian/patches/010_update-autoconf-rules.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -Description: update to autoconf >= 2.70 -Author: Joao Eriberto Mota Filho -Forwarded: https://github.com/resurrecting-open-source-projects/scrot/pull/135 -Last-Update: 2021-08-15 -Index: scrot/configure.ac -=================================================================== ---- scrot.orig/configure.ac -+++ scrot/configure.ac -@@ -4,12 +4,11 @@ AC_INIT([scrot], [1.6], [https://github. - [],[https://github.com/resurrecting-open-source-projects/scrot]) - AC_CONFIG_SRCDIR([src/main.c]) - AM_INIT_AUTOMAKE(dist-bzip2) --AC_CONFIG_HEADER([src/config.h]) -+AC_CONFIG_HEADERS([src/config.h]) - AX_PREFIX_CONFIG_H([src/scrot_config.h]) - - # Checks for programs. - AC_PROG_CC --AM_PROG_CC_STDC - AC_PROG_INSTALL - AC_PROG_MAKE_SET - diff -Nru scrot-1.6/debian/patches/series scrot-1.7/debian/patches/series --- scrot-1.6/debian/patches/series 2021-08-15 16:55:35.000000000 +0000 +++ scrot-1.7/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -010_update-autoconf-rules.patch diff -Nru scrot-1.6/doc/UPDATE-CHECK scrot-1.7/doc/UPDATE-CHECK --- scrot-1.6/doc/UPDATE-CHECK 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/doc/UPDATE-CHECK 2021-11-10 02:08:36.000000000 +0000 @@ -1,11 +1,12 @@ -When updating, change the following files (if needed): +To release a new version: -- ChangeLog -- Check for spelling errors in ChangeLog, manpage and README. -- Check final manpage with man command. +- Update rights +- Update changeLog +- Check for spelling errors in ChangeLog, manpage and README - man/create-man.sh (DATE, version) -- Generate a new manpage. -- README -- configure.ac (VERSION) +- Generate a new manpage +- Check final manpage with man command +- Update README +- Update configure.ac (VERSION) - Test in Debian Sid -- Generate extra tarballs via 'make dist' and upload to GitHub. +- Generate extra tarballs via 'make dist' and upload to GitHub diff -Nru scrot-1.6/.github/workflows/full-check.yml scrot-1.7/.github/workflows/full-check.yml --- scrot-1.6/.github/workflows/full-check.yml 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/.github/workflows/full-check.yml 2021-11-10 02:08:36.000000000 +0000 @@ -1,6 +1,7 @@ # Copyright 2020 Daniel T. Borelli # Copyright 2020 Jeroen Roovers # Copyright 2020 Joao Eriberto Mota Filho +# Copyright 2021 Guilherme Janczak name: full-check @@ -14,7 +15,7 @@ steps: - uses: actions/checkout@v2 - name: install_dependencies - run: sudo apt install autoconf-archive giblib-dev libimlib2-dev libtool libxcomposite-dev libxfixes-dev + run: sudo apt install autoconf-archive libimlib2-dev libxcomposite-dev libxfixes-dev libbsd-dev - name: first_build run: | ./autogen.sh @@ -22,7 +23,7 @@ make sudo make install sudo make uninstall - make distclean + make distclean - name: second_build run: | ./autogen.sh diff -Nru scrot-1.6/.gitignore scrot-1.7/.gitignore --- scrot-1.6/.gitignore 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/.gitignore 2021-11-10 02:08:36.000000000 +0000 @@ -1,19 +1,20 @@ -*.gz *.bz2 +*.gz *.in +Makefile aclocal.m4 autom4te.cache compile +compile_commands.json +config.* configure depcomp install-sh missing -Makefile -config.* +src/*.o src/.deps src/Makefile src/config.h +src/scrot src/scrot_config.h src/stamp-h1 -src/*.o -src/scrot diff -Nru scrot-1.6/Makefile.am scrot-1.7/Makefile.am --- scrot-1.6/Makefile.am 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/Makefile.am 2021-11-10 02:08:36.000000000 +0000 @@ -2,7 +2,8 @@ # gilbertt@linuxbrit.co.uk, # scrot_sucks@linuxbrit.co.uk> # Copyright 2015-2019 Joao Eriberto Mota Filho -# Copyright 2019-2020 Daniel T. Borelli +# Copyright 2019-2021 Daniel T. Borelli +# Copyright 2021 Guilherme Janczak # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to @@ -26,22 +27,17 @@ ## Process this file with automake to produce Makefile.in -AUTOMAKE_OPTIONS = 1.4 foreign +AUTOMAKE_OPTIONS = 1.10 foreign # A list of all the files in the current directory which can be regenerated MAINTAINERCLEANFILES = Makefile.in -AM_LDFLAGS = -L/usr/X11R6/lib -L/usr/lib -L/usr/local/lib -AM_CPPFLAGS = -I/usr/X11R6/include \ -$(X_CFLAGS) -I$(prefix)/include -I$(includedir) -I. - man_MANS = man/scrot.1 docs_DATA = README.md AUTHORS ChangeLog doc/scrot.png docsdir = $(prefix)/share/doc/scrot -EXTRA_DIST = \ -scrot.spec man/scrot.1 $(docs_DATA) +EXTRA_DIST = man/scrot.1 $(docs_DATA) SUBDIRS = src diff -Nru scrot-1.6/man/create-man.sh scrot-1.7/man/create-man.sh --- scrot-1.6/man/create-man.sh 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/man/create-man.sh 2021-11-10 02:08:36.000000000 +0000 @@ -16,9 +16,9 @@ #-------------------------------------------------------- # Put here all data for your first manpage (in T2M lines) -T2M_DATE="25 Jul 2021" +T2M_DATE="09 Nov 2021" T2M_NAME=scrot -T2M_VERSION=1.6 +T2M_VERSION=1.7 T2M_LEVEL=1 T2M_DESC="command line screen capture utility" create-man diff -Nru scrot-1.6/man/scrot.1 scrot-1.7/man/scrot.1 --- scrot-1.6/man/scrot.1 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/man/scrot.1 2021-11-10 02:08:36.000000000 +0000 @@ -1,156 +1,175 @@ .\" Text automatically generated by txt2man -.TH scrot 1 "25 Jul 2021" "scrot-1.6" "command line screen capture utility" +.TH scrot 1 "09 Nov 2021" "scrot-1.7" "command line screen capture utility" .SH NAME \fBscrot \fP- command line screen capture utility \fB .SH SYNOPSIS .nf .fam C -\fBscrot\fP [\fIoptions\fP] [\fIfile\fP] +\fBscrot\fP [\fB-bcfhikmopsuvz\fP] [\fB-a\fP \fIX,Y,W,H\fP] [\fB-C\fP \fINAME\fP] [\fB-D\fP \fIDISPLAY\fP] [\fB-d\fP \fISEC\fP] [\fB-e\fP \fICMD\fP] + [\fB-F\fP \fIFILE\fP] [\fB-l\fP \fISTYLE\fP] [\fB-n\fP \fIOPTS\fP] [\fB-q\fP \fINUM\fP] [\fB-S\fP \fICMD\fP] [\fB-t\fP \fINUM\fP | \fIGEOM\fP] [\fIFILE\fP] .fam T .fi .fam T .fi .SH DESCRIPTION -\fBscrot\fP (SCReenshOT) is a simple command line screen capture -utility that uses imlib2 to grab and save images. Multiple -image formats are supported through imlib2's dynamic saver -modules. +\fBscrot\fP (SCReenshOT) is a simple command line screen capture utility, it uses +imlib2 to grab and save images. .PP -Some features of the \fBscrot\fP: +\fBscrot\fP has many useful features: .RS .IP \(bu 3 -support to multiple image formats (JPG, PNG, GIF, etc.). +Support for multiple image formats: JPG, PNG, GIF, and others. .IP \(bu 3 -optimization of the screen shots image quality. +The screenshot's quality is configurable. .IP \(bu 3 -capture a specific window or a rectangular area on the -screen with the help of switch. +It is possible to capture a specific window or a rectangular area on the +screen. .RE .PP -\fBscrot\fP also can be used to monitor a desktop PC in admin absent -and register unwanted activities. +Because \fBscrot\fP is a command line utility, it can easily be scripted and put to +novel uses. For instance, \fBscrot\fP can be used to monitor an X server in absence. +.PP +\fBscrot\fP is free software under the MIT-advertising license. .SH OPTIONS .TP .B -\fB-h\fP, \fB--help\fP -Display help output and exit. +\fB-a\fP, \fB--autoselect\fP \fIX,Y,W,H\fP +Non-interactively choose a rectangle starting at +position X,Y and of W by H resolution. .TP .B -\fB-v\fP, \fB--version\fP -Output version information and exit. +\fB-b\fP, \fB--border\fP +When selecting a window, grab the WM's border too. +Use with \fB-s\fP to raise the focus of the window. .TP .B -\fB-D\fP, \fB--display\fP -Specify the display to use; see \fBX\fP(7). +\fB-C\fP, \fB--class\fP \fINAME\fP +\fINAME\fP is a window class name. Associative with \fB-k\fP. .TP .B -\fB-a\fP, \fB--autoselect\fP -Non-interactively choose a rectangle of x,y,w,h. +\fB-c\fP, \fB--count\fP +Display a countdown when used with \fB-d\fP. .TP .B -\fB-b\fP, \fB--border\fP -When selecting a window, grab wm border too. -Use with \fB--select\fP to raise the focus of the window. +\fB-D\fP, \fB--display\fP \fIDISPLAY\fP +\fIDISPLAY\fP is the display to use; see \fBX\fP(7). .TP .B -\fB-c\fP, \fB--count\fP -Display a countdown when used with delay. +\fB-d\fP, \fB--delay\fP \fISEC\fP +Wait \fISEC\fP seconds before taking a shot. .TP .B -\fB-d\fP, \fB--delay\fP NUM -Wait NUM seconds before taking a shot. +\fB-e\fP, \fB--exec\fP \fICMD\fP +Execute \fICMD\fP on the saved image. .TP .B -\fB-e\fP, \fB--exec\fP APP -Exec APP on the saved image. +\fB-F\fP, \fB--file\fP +File name. See SPECIAL STRINGS. .TP .B -\fB-q\fP, \fB--quality\fP NUM -Image quality (1-100) high value means high size, low -compression. Default: 75. (Effect differs depending on -\fIfile\fP format chosen). +\fB-f\fP, \fB--freeze\fP +Freeze the screen when \fB-s\fP is used. .TP .B -\fB-m\fP, \fB--multidisp\fP -For multiple heads, grab shot from each and join them -together. +\fB-h\fP, \fB--help\fP +Display help and exit. .TP .B -\fB-s\fP, \fB--select\fP -Interactively select a window or rectangle -with the mouse (use the arrow keys to resize). -See \fB-l\fP and \fB-f\fP \fIoptions\fP. +\fB-i\fP, \fB--ignorekeyboard\fP +Don't exit for keyboard input. ESC still exits. .TP .B -\fB-l\fP, \fB--line\fP -Indicates the style of the line when the \fB-s\fP option is used. -See SELECTION STYLE. +\fB-k\fP, \fB--stack\fP OPT +Capture stack/overlapped windows and join them. A +running Composite Manager is needed. OPT it's optional +join letter: v/h (vertical/horizontal). Default: h .TP .B -\fB-f\fP, \fB--freeze\fP -Freeze the screen when the \fB-s\fP option is used. +\fB-l\fP, \fB--line\fP \fISTYLE\fP +\fISTYLE\fP indicates the style of the line when the \fB-s\fP +option is used; see SELECTION \fISTYLE\fP. .TP .B -\fB-u\fP, \fB--focused\fP -Use the currently focused window. +\fB-m\fP, \fB--multidisp\fP +For multiple heads, screenshot all of them in order. .TP .B -\fB-t\fP, \fB--thumb\fP NUM|GEOM -Generate thumbnail too. NUM is the percentage of the -original size for the thumbnail to be. Alternatively, -a GEOMetry can be specified, example: 300x200. +\fB-n\fP, \fB--note\fP \fIOPTS\fP +\fIOPTS\fP is a collection of options which specify notes +to bake into the image. See NOTE FORMAT. .TP .B -\fB-z\fP, \fB--silent\fP -Prevent beeping. +\fB-o\fP, \fB--overwrite\fP +By default \fBscrot\fP does not overwrite the output +\fIFILE\fP, use this option to enable it. .TP .B \fB-p\fP, \fB--pointer\fP Capture the mouse pointer. .TP .B -\fB-o\fP, \fB--overwrite\fP -By default \fBscrot\fP does not overwrite the files, use this option to allow it. +\fB-q\fP, \fB--quality\fP \fINUM\fP +\fINUM\fP must be between 1 and 100. For lossless output +formats, a higher value represents better but slower +compression. For lossy output formats, a higher +value represents higher quality and larger +file size. Default: 75. .TP .B -\fB-n\fP, \fB--note\fP -Draw a text note. See NOTE FORMAT. +\fB-S\fP, \fB--script\fP \fICMD\fP +\fICMD\fP is an imlib2 script. .TP .B -\fB-k\fP, \fB--stack\fP -Capture stack/overlapped windows and join them together. -A running Composite Manager is needed. +\fB-s\fP, \fB--select\fP OPT +Interactively select a window or rectangle with the +mouse, use the arrow keys to resize. See the \fB-l\fP and +\fB-f\fP options. OPT it's optional; see SELECTION MODE .TP .B -\fB-C\fP, \fB--class\fP NAME -Window class name. Associative with \fIoptions\fP: \fB-k\fP. +\fB-t\fP, \fB--thumb\fP \fINUM\fP | \fIGEOM\fP +Also generate a thumbnail. The argument is the +resolution of the thumbnail, it may be a percentage +\fINUM\fP or a resolution \fIGEOM\fP. Examples: 10, 25, 320x240, +500x200. .TP .B -\fB-S\fP, \fB--script\fP CMD -Imlib2 script commands. +\fB-u\fP, \fB--focused\fP +Use the currently focused window. +.TP +.B +\fB-v\fP, \fB--version\fP +Output version information and exit. +.TP +.B +\fB-z\fP, \fB--silent\fP +Prevent beeping. +.TP +.B +- +Redirection to standard output. The output image +format is PNG. .SH SPECIAL STRINGS -Both the \fB--exec\fP and filename parameters can take format specifiers that are -expanded by \fBscrot\fP when encountered. There are two types of format specifier. -Characters preceded by a '%' are interpreted by \fBstrftime\fP(2). See man strftime -for examples. These \fIoptions\fP may be used to refer to the current date and -time. The second kind are internal to \fBscrot\fP and are prefixed by '$' The -following specifiers are recognised: +\fB-e\fP, \fB-F\fP and \fIFILE\fP parameters can take format specifiers that are expanded +by \fBscrot\fP when encountered. There are two types of format specifier: +Characters preceded by a '%' are interpreted by \fBstrftime\fP(2). The second kind +are internal to \fBscrot\fP and are prefixed by '$'. The following specifiers are +recognised by \fBscrot\fP: .PP .nf .fam C - $a hostname - $f image path/filename (ignored when used in the filename) - $m thumb image path/filename (ignored when used in the filename) - $n image name (ignored when used in the filename) - $s image size (bytes) (ignored when used in the filename) - $p image pixel size - $w image width - $h image height - $t image format (ignored when used in the filename) - $$ print a literal '$' - \\n print a newline (ignored when used in the filename) + $$ A literal '$'. + $a The system's hostname. + $f The image's full path (ignored when used in the filename). + $h The image's height. + $m The thumbnail's full path (ignored when used in the filename). + $n The image's basename (ignored when used in the filename). + $p The image's pixel size. + $s The image's size in bytes (ignored when used in the filename). + $t The image's file format (ignored when used in the filename). + $w The image's width. + \\n A literal newline (ignored when used in the filename). .fam T .fi @@ -158,43 +177,85 @@ .PP .nf .fam C - $ scrot '%Y-%m-%d_$wx$h.png' -e 'mv $f ~/shots/' + $ scrot '%Y-%m-%d_$wx$h.png' -e 'optipng $f' .fam T .fi -This would create a \fIfile\fP called something like 2000-10-30_2560x1024.png -and move it to your shots directory. -.SH SELECTION STYLE -When using \fB--select\fP you can indicate the style of the line with \fB--line\fP. -.PP -The following specifiers are recognised: +This would create a PNG file with a name similar to 2000-10-30_2560x1024.png +and optimize it with \fBoptipng\fP(1). +.SH SELECTION MODE +When using \fB-s\fP, optionally you can indicate the action to perform with the selection area. +Some actions allow optional parameters too. .PP .nf .fam C - style=(solid,dash),width=(range 1 to 8),color="value", - opacity=(range 10 to 100),mode=(edge,classic) + capture Capture the selection area, this action is by default and + does not need to be specified. + + hole Highlight the selected area overshadowing the rest of the capture. + + hide,IMAGE Hide the selection area by drawing an area of color (or image) over it. + Optionally indicate name of the image to use as cover. + Image has priority over color. + + blur,AMOUNT Blurs the selection area. + Optionally you can specify the amount of blur. + Amount,range: 1..30, default: 18 .fam T .fi -The default style is: +In modes 'hole' and 'hide' the color of the area is indicated by 'color' property of the +line style and the opacity of the color (or image) is indicated by property 'opacity', SELECTION \fISTYLE\fP +.PP +If the 'hide' mode uses an image that does not have an alpha channel, the opacity parameter +will be ignored and it will be drawn fully opaque. +.PP +Examples: .PP .nf .fam C - mode=classic,style=solid,width=1,opacity=100 + $ scrot --select=hide + $ scrot -shole --line color="Dark Salmon",opacity=200 + $ scrot -sblur,10 + $ scrot -shide,stamp.png --line opacity=120 .fam T .fi -Mode 'edge' ignore: style, \fB--freeze\fP -.PP -Mode 'classic' ignore: opacity +.SH SELECTION STYLE +When using \fB-s\fP, you can indicate the style of the line with \fB-l\fP. .PP -The 'opacity' specifier is only effective if a Composite Manager is running. +\fB-l\fP takes a comma-separated list of specifiers as argument: .PP -For the color you can use a name or a hexadecimal value. +.nf +.fam C + style=STYLE STYLE is either "solid" or "dash" without quotes. + + width=NUM NUM is a pixel count between 1 and 8 inclusive. + + color="COLOR" Color is a hexadecimal HTML color code or the name of + a color. HTML color codes are composed of a pound + sign '#' followed by a sequence of 3 2-digit + hexadecimal numbers which represent red, green, and + blue respectively. Examples: #FF0000 (red), #E0FFFF + (light cyan), #000000 (black). + + opacity=NUM NUM is between 0 and 255 inclusive. 255 means + 100% opaque, 0 means 100% transparent. For the + opacity of the line this is only effective if a + Composite Manager is running. + + mode=MODE MODE is either "edge" or "classic" without quotes. + edge is the new selection, classic uses the old one. + "edge" ignores the style specifier and the -f flag, + "classic" ignores the opacity specifier. + +.fam T +.fi +Without the \fB-l\fP option, a default style is used: .PP .nf .fam C - color="red" or color="#ff0000" + mode=classic,style=solid,width=1,opacity=100 .fam T .fi @@ -202,21 +263,21 @@ .PP .nf .fam C - $ scrot --line style=dash,width=3,color="red" --select + $ scrot -l style=dash,width=3,color="red" -s .fam T .fi .SH NOTE FORMAT -The following specifiers are recognised for the option \fB--note\fP: +The \fB-n\fP option's argument is more arguments: .PP .nf .fam C - -f 'FontName/size' - -t 'text' - -x position (optional) - -y position (optional) - -c color(RGBA) (optional) - -a angle (optional) + -f 'FontName/size' + -t 'text' + -x position (optional) + -y position (optional) + -c color(RGBA, range 0..255) (optional) + -a angle (optional) .fam T .fi @@ -224,13 +285,13 @@ .PP .nf .fam C - $ scrot --note "-f '/usr/share/fonts/TTF/DroidSans-Bold/40' -x 10 -y 20 -c 255,0,0,255 -t 'Hi'" + $ scrot -n "-f '/usr/share/fonts/TTF/DroidSans-Bold/40' -x 10 + -y 20 -c 255,0,0,255 -t 'Hi'" .fam T .fi .SH AUTHOR -\fBscrot\fP was originally developed by Tom Gilbert under MIT-advertising license -and is maintained by some people. +\fBscrot\fP was originally developed by Tom Gilbert. .PP -Currently, source code and newer versions are available at -https://github.com/resurrecting-open-source-projects/\fBscrot\fP +Currently, source code is maintained by volunteers. Newer versions +are available at https://github.com/resurrecting-open-source-projects/\fBscrot\fP diff -Nru scrot-1.6/man/scrot.txt scrot-1.7/man/scrot.txt --- scrot-1.6/man/scrot.txt 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/man/scrot.txt 2021-11-10 02:08:36.000000000 +0000 @@ -2,128 +2,175 @@ scrot - command line screen capture utility SYNOPSIS - scrot [options] [file] + scrot [-bcfhikmopsuvz] [-a X,Y,W,H] [-C NAME] [-D DISPLAY] [-d SEC] [-e CMD] + [-F FILE] [-l STYLE] [-n OPTS] [-q NUM] [-S CMD] [-t NUM | GEOM] [FILE] DESCRIPTION - scrot (SCReenshOT) is a simple command line screen capture - utility that uses imlib2 to grab and save images. Multiple - image formats are supported through imlib2's dynamic saver - modules. - - Some features of the scrot: - - support to multiple image formats (JPG, PNG, GIF, etc.). - - optimization of the screen shots image quality. - - capture a specific window or a rectangular area on the - screen with the help of switch. + scrot (SCReenshOT) is a simple command line screen capture utility, it uses + imlib2 to grab and save images. - scrot also can be used to monitor a desktop PC in admin absent - and register unwanted activities. + scrot has many useful features: + - Support for multiple image formats: JPG, PNG, GIF, and others. + - The screenshot's quality is configurable. + - It is possible to capture a specific window or a rectangular area on the + screen. + + Because scrot is a command line utility, it can easily be scripted and put to + novel uses. For instance, scrot can be used to monitor an X server in absence. + + scrot is free software under the MIT-advertising license. OPTIONS - -h, --help Display help output and exit. - -v, --version Output version information and exit. - -D, --display Specify the display to use; see X(7). - -a, --autoselect Non-interactively choose a rectangle of x,y,w,h. - -b, --border When selecting a window, grab wm border too. - Use with --select to raise the focus of the window. - -c, --count Display a countdown when used with delay. - -d, --delay NUM Wait NUM seconds before taking a shot. - -e, --exec APP Exec APP on the saved image. - -q, --quality NUM Image quality (1-100) high value means high size, low - compression. Default: 75. (Effect differs depending on - file format chosen). - -m, --multidisp For multiple heads, grab shot from each and join them - together. - -s, --select Interactively select a window or rectangle - with the mouse (use the arrow keys to resize). - See -l and -f options. - -l, --line Indicates the style of the line when the -s option is used. - See SELECTION STYLE. - -f, --freeze Freeze the screen when the -s option is used. - -u, --focused Use the currently focused window. - -t, --thumb NUM|GEOM Generate thumbnail too. NUM is the percentage of the - original size for the thumbnail to be. Alternatively, - a GEOMetry can be specified, example: 300x200. - -z, --silent Prevent beeping. - -p, --pointer Capture the mouse pointer. - - -o, --overwrite By default scrot does not overwrite the files, use this option to allow it. - -n, --note Draw a text note. See NOTE FORMAT. - -k, --stack Capture stack/overlapped windows and join them together. - A running Composite Manager is needed. - -C, --class NAME Window class name. Associative with options: -k. - -S, --script CMD Imlib2 script commands. + -a, --autoselect X,Y,W,H Non-interactively choose a rectangle starting at + position X,Y and of W by H resolution. + -b, --border When selecting a window, grab the WM's border too. + Use with -s to raise the focus of the window. + -C, --class NAME NAME is a window class name. Associative with -k. + -c, --count Display a countdown when used with -d. + -D, --display DISPLAY DISPLAY is the display to use; see X(7). + -d, --delay SEC Wait SEC seconds before taking a shot. + -e, --exec CMD Execute CMD on the saved image. + -F, --file File name. See SPECIAL STRINGS. + -f, --freeze Freeze the screen when -s is used. + -h, --help Display help and exit. + -i, --ignorekeyboard Don't exit for keyboard input. ESC still exits. + -k, --stack OPT Capture stack/overlapped windows and join them. A + running Composite Manager is needed. OPT it's optional + join letter: v/h (vertical/horizontal). Default: h + -l, --line STYLE STYLE indicates the style of the line when the -s + option is used; see SELECTION STYLE. + -m, --multidisp For multiple heads, screenshot all of them in order. + -n, --note OPTS OPTS is a collection of options which specify notes + to bake into the image. See NOTE FORMAT. + -o, --overwrite By default scrot does not overwrite the output + FILE, use this option to enable it. + -p, --pointer Capture the mouse pointer. + -q, --quality NUM NUM must be between 1 and 100. For lossless output + formats, a higher value represents better but slower + compression. For lossy output formats, a higher + value represents higher quality and larger + file size. Default: 75. + -S, --script CMD CMD is an imlib2 script. + -s, --select OPT Interactively select a window or rectangle with the + mouse, use the arrow keys to resize. See the -l and + -f options. OPT it's optional; see SELECTION MODE + -t, --thumb NUM | GEOM Also generate a thumbnail. The argument is the + resolution of the thumbnail, it may be a percentage + NUM or a resolution GEOM. Examples: 10, 25, 320x240, + 500x200. + -u, --focused Use the currently focused window. + -v, --version Output version information and exit. + -z, --silent Prevent beeping. + - Redirection to standard output. The output image + format is PNG. SPECIAL STRINGS - Both the --exec and filename parameters can take format specifiers that are - expanded by scrot when encountered. There are two types of format specifier. - Characters preceded by a '%' are interpreted by strftime(2). See man strftime - for examples. These options may be used to refer to the current date and - time. The second kind are internal to scrot and are prefixed by '$' The - following specifiers are recognised: - - $a hostname - $f image path/filename (ignored when used in the filename) - $m thumb image path/filename (ignored when used in the filename) - $n image name (ignored when used in the filename) - $s image size (bytes) (ignored when used in the filename) - $p image pixel size - $w image width - $h image height - $t image format (ignored when used in the filename) - $$ print a literal '$' - \\n print a newline (ignored when used in the filename) + -e, -F and FILE parameters can take format specifiers that are expanded + by scrot when encountered. There are two types of format specifier: + Characters preceded by a '%' are interpreted by strftime(2). The second kind + are internal to scrot and are prefixed by '$'. The following specifiers are + recognised by scrot: + + $$ A literal '$'. + $a The system's hostname. + $f The image's full path (ignored when used in the filename). + $h The image's height. + $m The thumbnail's full path (ignored when used in the filename). + $n The image's basename (ignored when used in the filename). + $p The image's pixel size. + $s The image's size in bytes (ignored when used in the filename). + $t The image's file format (ignored when used in the filename). + $w The image's width. + \\n A literal newline (ignored when used in the filename). Example: - $ scrot '%Y-%m-%d_$wx$h.png' -e 'mv $f ~/shots/' + $ scrot '%Y-%m-%d_$wx$h.png' -e 'optipng $f' - This would create a file called something like 2000-10-30_2560x1024.png - and move it to your shots directory. + This would create a PNG file with a name similar to 2000-10-30_2560x1024.png + and optimize it with optipng(1). -SELECTION STYLE - When using --select you can indicate the style of the line with --line. +SELECTION MODE + When using -s, optionally you can indicate the action to perform with the selection area. + Some actions allow optional parameters too. - The following specifiers are recognised: + capture Capture the selection area, this action is by default and + does not need to be specified. - style=(solid,dash),width=(range 1 to 8),color="value", - opacity=(range 10 to 100),mode=(edge,classic) + hole Highlight the selected area overshadowing the rest of the capture. - The default style is: + hide,IMAGE Hide the selection area by drawing an area of color (or image) over it. + Optionally indicate name of the image to use as cover. + Image has priority over color. - mode=classic,style=solid,width=1,opacity=100 + blur,AMOUNT Blurs the selection area. + Optionally you can specify the amount of blur. + Amount,range: 1..30, default: 18 + + In modes 'hole' and 'hide' the color of the area is indicated by 'color' property of the + line style and the opacity of the color (or image) is indicated by property 'opacity', SELECTION STYLE + + If the 'hide' mode uses an image that does not have an alpha channel, the opacity parameter + will be ignored and it will be drawn fully opaque. + + Examples: - Mode 'edge' ignore: style, --freeze + $ scrot --select=hide + $ scrot -shole --line color="Dark Salmon",opacity=200 + $ scrot -sblur,10 + $ scrot -shide,stamp.png --line opacity=120 - Mode 'classic' ignore: opacity +SELECTION STYLE + When using -s, you can indicate the style of the line with -l. + + -l takes a comma-separated list of specifiers as argument: + + style=STYLE STYLE is either "solid" or "dash" without quotes. + + width=NUM NUM is a pixel count between 1 and 8 inclusive. - The 'opacity' specifier is only effective if a Composite Manager is running. + color="COLOR" Color is a hexadecimal HTML color code or the name of + a color. HTML color codes are composed of a pound + sign '#' followed by a sequence of 3 2-digit + hexadecimal numbers which represent red, green, and + blue respectively. Examples: #FF0000 (red), #E0FFFF + (light cyan), #000000 (black). - For the color you can use a name or a hexadecimal value. + opacity=NUM NUM is between 0 and 255 inclusive. 255 means + 100% opaque, 0 means 100% transparent. For the + opacity of the line this is only effective if a + Composite Manager is running. - color="red" or color="#ff0000" + mode=MODE MODE is either "edge" or "classic" without quotes. + edge is the new selection, classic uses the old one. + "edge" ignores the style specifier and the -f flag, + "classic" ignores the opacity specifier. + + Without the -l option, a default style is used: + + mode=classic,style=solid,width=1,opacity=100 Example: - $ scrot --line style=dash,width=3,color="red" --select + $ scrot -l style=dash,width=3,color="red" -s NOTE FORMAT - The following specifiers are recognised for the option --note: + The -n option's argument is more arguments: - -f 'FontName/size' - -t 'text' - -x position (optional) - -y position (optional) - -c color(RGBA) (optional) - -a angle (optional) + -f 'FontName/size' + -t 'text' + -x position (optional) + -y position (optional) + -c color(RGBA, range 0..255) (optional) + -a angle (optional) Example: - $ scrot --note "-f '/usr/share/fonts/TTF/DroidSans-Bold/40' -x 10 -y 20 -c 255,0,0,255 -t 'Hi'" + $ scrot -n "-f '/usr/share/fonts/TTF/DroidSans-Bold/40' -x 10 + -y 20 -c 255,0,0,255 -t 'Hi'" AUTHOR - scrot was originally developed by Tom Gilbert under MIT-advertising license - and is maintained by some people. + scrot was originally developed by Tom Gilbert. - Currently, source code and newer versions are available at - https://github.com/resurrecting-open-source-projects/scrot + Currently, source code is maintained by volunteers. Newer versions + are available at https://github.com/resurrecting-open-source-projects/scrot diff -Nru scrot-1.6/README.md scrot-1.7/README.md --- scrot-1.6/README.md 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/README.md 2021-11-10 02:08:36.000000000 +0000 @@ -25,7 +25,7 @@ The original scrot went unmaintained; the source of the last version, 0.8, was [imported from Debian](https://snapshot.debian.org/package/scrot/). After, -patches from Debian and elsewhere were applied to create the 0.9 release-the +patches from Debian and elsewhere were applied to create the 0.9 release. The details of our releases are registered in the [ChangeLog](ChangeLog) file. Now, scrot is maintained by volunteers under [Resurrecting Open Source Projects](https://github.com/resurrecting-open-source-projects). @@ -39,6 +39,7 @@ - [autoconf-archive](https://www.gnu.org/software/autoconf-archive/) (build time only) - [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/) (build time only) - [imlib2](https://sourceforge.net/projects/enlightenment/files/imlib2-src/) +- [libbsd](https://libbsd.freedesktop.org/wiki/) (if `./configure --without-libbsd; make` fails) - X [(e.g. X.Org)](https://www.x.org/wiki/) - libXcomposite [(can be found in X.Org)](https://gitlab.freedesktop.org/xorg/lib/libxcomposite) - libXext [(can be found in X.Org)](https://gitlab.freedesktop.org/xorg/lib/libxext) diff -Nru scrot-1.6/scrot.spec scrot-1.7/scrot.spec --- scrot-1.6/scrot.spec 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/scrot.spec 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -Summary: @PACKAGE@ - command line screen capture utility -Name: @PACKAGE@ -Version: @VERSION@ -Release: @RELEASE@ -License: MIT -URL: @PACKAGE_URL@ - -%description -scrot (SCReenshOT) is a simple command line screen capture -utility that uses imlib2 to grab and save images. Multiple -image formats are supported through imlib2's dynamic saver -modules. - -Some features of the scrot: -- support to multiple image formats (JPG, PNG, GIF, etc.). -- optimization of the screen shots image quality. -- capture a specific window or a rectangular area on the - screen with the help of switch. - -scrot also can be used to monitor a desktop PC in admin absent -and register unwanted activities. diff -Nru scrot-1.6/src/imlib.c scrot-1.7/src/imlib.c --- scrot-1.6/src/imlib.c 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/src/imlib.c 2021-11-10 02:08:36.000000000 +0000 @@ -1,10 +1,11 @@ /* imlib.c Copyright 1999-2000 Tom Gilbert -Copyright 2020 Daniel T. Borelli +Copyright 2020-2021 Daniel T. Borelli Copyright 2020 ideal Copyright 2020 Sean Brennan Copyright 2021 Christopher R. Nelson +Copyright 2021 Peter Wu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -27,43 +28,46 @@ */ -#include "scrot.h" #include "options.h" +#include "scrot.h" -Display *disp = NULL; -Visual *vis = NULL; -Screen *scr = NULL; +Display* disp = NULL; +Visual* vis = NULL; +Screen* scr = NULL; Colormap cm; int depth; Window root = 0; - -void -init_x_and_imlib(char *dispstr, int screen_num) +void initXAndImlib(char* dispStr, int screenNumber) { - disp = XOpenDisplay(dispstr); - if (!disp) { - fprintf(stderr, "Can't open X display. It *is* running, yeah? ["); - fprintf(stderr, "%s", dispstr ? dispstr : - (getenv("DISPLAY") ? getenv("DISPLAY") : "NULL")); - fprintf(stderr, "]\n"); - exit(EXIT_FAILURE); - } - - if (screen_num) - scr = ScreenOfDisplay(disp, screen_num); - else - scr = ScreenOfDisplay(disp, DefaultScreen(disp)); - - vis = DefaultVisual(disp, XScreenNumberOfScreen(scr)); - depth = DefaultDepth(disp, XScreenNumberOfScreen(scr)); - cm = DefaultColormap(disp, XScreenNumberOfScreen(scr)); - root = RootWindow(disp, XScreenNumberOfScreen(scr)); - - imlib_context_set_drawable(root); - imlib_context_set_display(disp); - imlib_context_set_visual(vis); - imlib_context_set_colormap(cm); - imlib_context_set_color_modifier(NULL); - imlib_context_set_operation(IMLIB_OP_COPY); + disp = XOpenDisplay(dispStr); + if (!disp) { + + char const* const format = "Can't open X display. It *is* running, " + "yeah? [%s]"; + + char const* env = NULL; + + char const* const value = dispStr ? dispStr : + (env = getenv("DISPLAY")) ? env : "NULL"; + + errx(EXIT_FAILURE, format, value); + } + + if (screenNumber) + scr = ScreenOfDisplay(disp, screenNumber); + else + scr = ScreenOfDisplay(disp, DefaultScreen(disp)); + + vis = DefaultVisual(disp, XScreenNumberOfScreen(scr)); + depth = DefaultDepth(disp, XScreenNumberOfScreen(scr)); + cm = DefaultColormap(disp, XScreenNumberOfScreen(scr)); + root = RootWindow(disp, XScreenNumberOfScreen(scr)); + + imlib_context_set_drawable(root); + imlib_context_set_display(disp); + imlib_context_set_visual(vis); + imlib_context_set_colormap(cm); + imlib_context_set_color_modifier(NULL); + imlib_context_set_operation(IMLIB_OP_COPY); } diff -Nru scrot-1.6/src/main.c scrot-1.7/src/main.c --- scrot-1.6/src/main.c 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/src/main.c 2021-11-10 02:08:36.000000000 +0000 @@ -6,7 +6,7 @@ Copyright 2009 James Cameron Copyright 2010 Ibragimov Rinat Copyright 2017 Stoney Sauce -Copyright 2019-2021 Daniel T. Borelli +Copyright 2019-2021 Daniel T. Borelli Copyright 2019 Jade Auer Copyright 2020 blockparole Copyright 2020 Cungsten Tarbide @@ -16,6 +16,8 @@ Copyright 2021 c0dev0id Copyright 2021 Christopher R. Nelson Copyright 2021 Guilherme Janczak +Copyright 2021 IFo Hancroft +Copyright 2021 Peter Wu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -39,281 +41,245 @@ */ #include "scrot.h" -#include "options.h" -#include "slist.h" #include - /* atexit register func. */ -static void uninit_x_and_imlib(void) +static void uninitXAndImlib(void) { - if (disp) { - XCloseDisplay(disp); - disp = NULL; - } -} + if (opt.note) + scrotNoteFree(); + if (disp) { + XCloseDisplay(disp); + disp = NULL; + } +} // It assumes that the local variable 'main.c:Imlib_Image image' is in context -static void apply_filter_if_required(void) +static void applyFilterIfRequired(void) { - if (opt.script != NULL) { - imlib_apply_filter(opt.script); - } -} - -int -main(int argc, - char **argv) -{ - Imlib_Image image; - Imlib_Image thumbnail; - Imlib_Load_Error err; - char *filename_im = NULL, *filename_thumb = NULL; - - char *have_extension = NULL; - - time_t t; - struct tm *tm; - - init_parse_options(argc, argv); - - init_x_and_imlib(opt.display, 0); - - atexit(uninit_x_and_imlib); - - if (!opt.output_file) { - opt.output_file = strdup("%Y-%m-%d-%H%M%S_$wx$h_scrot.png"); - opt.thumb_file = strdup("%Y-%m-%d-%H%M%S_$wx$h_scrot-thumb.png"); - } else { - scrot_have_file_extension(opt.output_file, &have_extension); - } - - - if (opt.focused) - image = scrot_grab_focused(); - else if (opt.select) - image = scrot_sel_and_grab_image(); - else if (opt.autoselect) - image = scrot_grab_autoselect(); - else - { - scrot_do_delay(); - if (opt.multidisp) { - image = scrot_grab_shot_multi(); - } else if (opt.stack) { - image = scrot_grab_stack_windows(); - } else { - image = scrot_grab_shot(); - } - } + if (opt.script) + imlib_apply_filter(opt.script); +} - if (opt.note != NULL) - scrot_note_draw(image); +int main(int argc, char** argv) +{ + Imlib_Image image; + Imlib_Image thumbnail; + Imlib_Load_Error imErr; + char* filenameIM = NULL; + char* filenameThumb = NULL; - if (!image) { - fprintf(stderr, "no image grabbed: %s", strerror(errno)); - exit(EXIT_FAILURE); - } - - time(&t); /* Get the time directly after the screenshot */ - tm = localtime(&t); - - imlib_context_set_image(image); - imlib_image_attach_data_value("quality", NULL, opt.quality, NULL); - - if (!have_extension) { - imlib_image_set_format("png"); - } - - filename_im = im_printf(opt.output_file, tm, NULL, NULL, image); - scrot_check_if_overwrite_file(&filename_im); - - apply_filter_if_required(); - - imlib_save_image_with_error_return(filename_im, &err); - if (err) { - fprintf(stderr, "Saving to file %s failed: %s\n", filename_im, strerror(errno)); - exit(EXIT_FAILURE); - } - if (opt.thumb) - { - int cwidth, cheight; - int twidth, theight; - - cwidth = imlib_image_get_width(); - cheight = imlib_image_get_height(); - - /* Geometry based thumb size */ - if (opt.thumb_width || opt.thumb_height) - { - if (!opt.thumb_width) - { - twidth = cwidth * opt.thumb_height / cheight; - theight = opt.thumb_height; - } - else if (!opt.thumb_height) - { - twidth = opt.thumb_width; - theight = cheight * opt.thumb_width / cwidth; - } - else - { - twidth = opt.thumb_width; - theight = opt.thumb_height; - } - } - else - { - twidth = cwidth * opt.thumb / 100; - theight = cheight * opt.thumb / 100; - } + char* haveExtension = NULL; - imlib_context_set_anti_alias(1); - thumbnail = - imlib_create_cropped_scaled_image(0, 0, cwidth, cheight, - twidth, theight); - if (thumbnail == NULL) { - fprintf(stderr, "Unable to create scaled Image: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - else - { - if (opt.note != NULL) - scrot_note_draw(image); + time_t t; + struct tm* tm; + + optionsParse(argc, argv); + + initXAndImlib(opt.display, 0); + + atexit(uninitXAndImlib); - scrot_have_file_extension(opt.thumb_file, &have_extension); + if (!opt.outputFile) { + opt.outputFile = strdup("%Y-%m-%d-%H%M%S_$wx$h_scrot.png"); + opt.thumbFile = strdup("%Y-%m-%d-%H%M%S_$wx$h_scrot-thumb.png"); + } else { + if (opt.thumb) + opt.thumbFile = optionsNameThumbnail(opt.outputFile); + scrotHaveFileExtension(opt.outputFile, &haveExtension); + } + + if (opt.focused) + image = scrotGrabFocused(); + else if (opt.selection.mode & SELECTION_MODE_ANY) + image = scrotSelectionSelectMode(); + else if (opt.autoselect) + image = scrotGrabAutoselect(); + else { + scrotDoDelay(); + if (opt.multidisp) + image = scrotGrabShotMulti(); + else if (opt.stack) + image = scrotGrabStackWindows(); + else + image = scrotGrabShot(); + } + + if (!image) + err(EXIT_FAILURE, "no image grabbed"); + + if (opt.note) + scrotNoteDraw(image); + + time(&t); /* Get the time directly after the screenshot */ + tm = localtime(&t); - if (!have_extension) { - imlib_context_set_image(thumbnail); + imlib_context_set_image(image); + imlib_image_attach_data_value("quality", NULL, opt.quality, NULL); + + if (!haveExtension) imlib_image_set_format("png"); - } - filename_thumb = im_printf(opt.thumb_file, tm, NULL, NULL, thumbnail); - scrot_check_if_overwrite_file(&filename_thumb); + filenameIM = imPrintf(opt.outputFile, tm, NULL, NULL, image); + scrotCheckIfOverwriteFile(&filenameIM); - apply_filter_if_required(); + applyFilterIfRequired(); - imlib_save_image_with_error_return(filename_thumb, &err); - if (err) { - fprintf(stderr, "Saving thumbnail %s failed: %s\n", filename_thumb, strerror(errno)); - exit(EXIT_FAILURE); - } + imlib_save_image_with_error_return(filenameIM, &imErr); + if (imErr) + err(EXIT_FAILURE, "Saving to file %s failed", filenameIM); + + if (opt.thumb) { + int cwidth, cheight; + int twidth, theight; + + cwidth = imlib_image_get_width(); + cheight = imlib_image_get_height(); + + /* Geometry based thumb size */ + if (opt.thumbWidth || opt.thumbHeight) { + if (!opt.thumbWidth) { + twidth = cwidth * opt.thumbHeight / cheight; + theight = opt.thumbHeight; + } else if (!opt.thumbHeight) { + twidth = opt.thumbWidth; + theight = cheight * opt.thumbWidth / cwidth; + } else { + twidth = opt.thumbWidth; + theight = opt.thumbHeight; + } + } else { + twidth = cwidth * opt.thumb / 100; + theight = cheight * opt.thumb / 100; + } + + imlib_context_set_anti_alias(1); + thumbnail = imlib_create_cropped_scaled_image(0, 0, cwidth, cheight, + twidth, theight); + if (!thumbnail) + err(EXIT_FAILURE, "unable to create thumbnail"); + else { + scrotHaveFileExtension(opt.thumbFile, &haveExtension); + imlib_context_set_image(thumbnail); + if (!haveExtension) + imlib_image_set_format("png"); + + filenameThumb = imPrintf(opt.thumbFile, tm, NULL, NULL, thumbnail); + scrotCheckIfOverwriteFile(&filenameThumb); + imlib_save_image_with_error_return(filenameThumb, &imErr); + imlib_free_image_and_decache(); + + if (imErr) + err(EXIT_FAILURE, "Saving thumbnail %s failed", filenameThumb); + } } - } - if (opt.exec) - scrot_exec_app(image, tm, filename_im, filename_thumb); - imlib_free_image_and_decache(); - - return 0; -} - -void -scrot_do_delay(void) -{ - if (opt.delay) { - if (opt.countdown) { - int i; - - printf("Taking shot in %d.. ", opt.delay); - fflush(stdout); - sleep(1); - for (i = opt.delay - 1; i > 0; i--) { - printf("%d.. ", i); - fflush(stdout); - sleep(1); - } - printf("0.\n"); - fflush(stdout); - } else - sleep(opt.delay); - } + if (opt.exec) + scrotExecApp(image, tm, filenameIM, filenameThumb); + + imlib_context_set_image(image); + imlib_free_image_and_decache(); + + return 0; } -size_t scrot_have_file_extension(char const *filename, char **ext) +void scrotDoDelay(void) +{ + if (opt.delay) { + if (opt.countdown) { + int i; + + printf("Taking shot in %d.. ", opt.delay); + fflush(stdout); + sleep(1); + for (i = opt.delay - 1; i > 0; i--) { + printf("%d.. ", i); + fflush(stdout); + sleep(1); + } + printf("0.\n"); + fflush(stdout); + } else + sleep(opt.delay); + } +} + +size_t scrotHaveFileExtension(char const* filename, char** ext) { *ext = strrchr(filename, '.'); - if (*ext) { + if (*ext) return strlen(*ext); - } return 0; } - -void scrot_check_if_overwrite_file(char **filename) +void scrotCheckIfOverwriteFile(char** filename) { - char *curfile = *filename; + if (opt.overwrite) + return; - if (opt.overwrite == 1) return; + if (access(*filename, F_OK) == -1) + return; - if (access(curfile, F_OK) == -1) return; + const size_t maxCounter = 999; + size_t counter = 0; + char* ext = NULL; + size_t extLength = 0; + const size_t slen = strlen(*filename); + size_t nalloc = slen + 4 + 1; // _000 + NUL byte + char fmt[5]; + char* newName = NULL; - const size_t max_counter = 999; - size_t counter = 0; - char *ext = NULL; - size_t ext_len = 0; - const size_t slen = strlen(curfile); - size_t nalloc = slen + 4 + 1; // _000 + NUL byte - char fmt[5]; - char *newname = NULL; + extLength = scrotHaveFileExtension(*filename, &ext); - ext_len = scrot_have_file_extension(curfile, &ext); + if (ext) + nalloc += extLength; // .ext - if (ext) - nalloc += ext_len; // .ext + newName = calloc(nalloc, sizeof(*newName)); + memcpy(newName, *filename, slen); - newname = calloc(nalloc, sizeof(char)); + do { + char* ptr = newName + slen; - if (ext) - // exclude ext - memcpy(newname, curfile, slen - ext_len); - else - memcpy(newname, curfile, slen); + snprintf(fmt, sizeof(fmt), "_%03zu", counter++); - do { - snprintf(fmt, 5, "_%03zu", counter++); + if(ext) { + ptr -= extLength; + memcpy(ptr, fmt, sizeof(fmt)); + memcpy(ptr + sizeof(fmt) - 1, ext, extLength); + } else + memcpy(ptr, fmt, sizeof(fmt)); + } while ((counter < maxCounter) && !access(newName, F_OK)); - if (!ext) { - strncpy(newname + slen, fmt, 5); - } else { - strncpy((newname + slen) - ext_len, fmt, 5); - strncat(newname, ext, ext_len); - } - curfile = newname; - } while ((counter < max_counter) && (access(curfile, F_OK) == 0)); + assert(newName[nalloc - 1] == '\0'); - free(*filename); - *filename = newname; + free(*filename); + *filename = newName; - if (counter == max_counter) { - fprintf(stderr, "scrot can no longer generate new file names.\n" - "The last attempt is %s\n", newname); - free(newname); - exit(EXIT_FAILURE); - } + if (counter == maxCounter) { + errx(EXIT_FAILURE, "scrot can no longer generate new file names.\n" + "The last attempt is %s", newName); + } } - -int scrot_match_window_class_name(Window target) +int scrotMatchWindowClassName(Window target) { assert(disp != NULL); const int NOT_MATCH = 0; const int MATCH = 1; - /* By default all class names match since window_class_name by default is NULL*/ + /* By default all class names match since windowClassName by default is NULL*/ int retval = MATCH; - if (opt.window_class_name == NULL) { + if (!opt.windowClassName) return retval; - } XClassHint classHint; - retval = NOT_MATCH; // window_class_name != NULL, by default NOT_MATCH + retval = NOT_MATCH; // windowClassName != NULL, by default NOT_MATCH if (XGetClassHint(disp, target, &classHint) != BadWindow) { - retval = options_cmp_window_class_name(classHint.res_class); + retval = optionsCompareWindowClassName(classHint.res_class); XFree(classHint.res_name); XFree(classHint.res_class); } @@ -321,734 +287,533 @@ return retval; } +void scrotGrabMousePointer(const Imlib_Image image, + const int xOffset, const int yOffset) +{ + XFixesCursorImage* xcim = XFixesGetCursorImage(disp); -void -scrot_grab_mouse_pointer(const Imlib_Image image, - const int ix_off, const int iy_off) -{ - XFixesCursorImage *xcim = XFixesGetCursorImage(disp); - - const unsigned short width = xcim->width; - const unsigned short height = xcim->height; - const int x = (xcim->x - xcim->xhot) - ix_off; - const int y = (xcim->y - xcim->yhot) - iy_off; - DATA32 *pixels = NULL; + if (!xcim) { + warnx("Failed to get mouse cursor image."); + return; + } + + const unsigned short width = xcim->width; + const unsigned short height = xcim->height; + const int x = (xcim->x - xcim->xhot) - xOffset; + const int y = (xcim->y - xcim->yhot) - yOffset; + DATA32* pixels = NULL; #ifdef __i386__ - pixels = (DATA32*)xcim->pixels; + pixels = (DATA32*)xcim->pixels; #else - DATA32 data[width * height * 4]; + DATA32 data[width * height * 4]; - unsigned int i; - for (i = 0; i < (width * height); i++) - ((DATA32*)data)[i] = (DATA32)xcim->pixels[i]; + unsigned int i; + for (i = 0; i < (width * height); i++) + data[i] = (DATA32)xcim->pixels[i]; - pixels = data; + pixels = data; #endif - Imlib_Image imcursor = imlib_create_image_using_data(width, height, pixels); + Imlib_Image imcursor = imlib_create_image_using_data(width, height, pixels); - XFree(xcim); + XFree(xcim); - if (!imcursor) { - fprintf(stderr, "scrot_grab_mouse_pointer: Failed create image using data.\n"); - exit(EXIT_FAILURE); - } + if (!imcursor) + errx(EXIT_FAILURE, "scrotGrabMousePointer: Failed create image using data."); - imlib_context_set_image(imcursor); - imlib_image_set_has_alpha(1); - imlib_context_set_image(image); - imlib_blend_image_onto_image(imcursor, 0, 0, 0, width, height, x, y, width, height); - imlib_context_set_image(imcursor); - imlib_free_image(); + imlib_context_set_image(imcursor); + imlib_image_set_has_alpha(1); + imlib_context_set_image(image); + imlib_blend_image_onto_image(imcursor, 0, 0, 0, width, height, x, y, width, height); + imlib_context_set_image(imcursor); + imlib_free_image(); } - -Imlib_Image -scrot_grab_shot(void) +Imlib_Image scrotGrabShot(void) { - Imlib_Image im; + Imlib_Image im; - if (! opt.silent) XBell(disp, 0); + if (!opt.silent) + XBell(disp, 0); - im = - imlib_create_image_from_drawable(0, 0, 0, scr->width, - scr->height, 1); - if (opt.pointer == 1) - scrot_grab_mouse_pointer(im, 0, 0); + im = imlib_create_image_from_drawable(0, 0, 0, scr->width, + scr->height, 1); + if (opt.pointer) + scrotGrabMousePointer(im, 0, 0); - return im; + return im; } -void -scrot_exec_app(Imlib_Image image, struct tm *tm, - char *filename_im, char *filename_thumb) +void scrotExecApp(Imlib_Image image, struct tm* tm, + char* filenameIM, char* filenameThumb) { - char *execstr; - int ret; + char* execStr; + int ret; - execstr = im_printf(opt.exec, tm, filename_im, filename_thumb, image); + execStr = imPrintf(opt.exec, tm, filenameIM, filenameThumb, image); - errno = 0; + errno = 0; - ret = system(execstr); + ret = system(execStr); - if (ret == -1) { - fprintf(stderr, "The child process could not be created: %s\n", strerror(errno)); - } else if (WEXITSTATUS(ret) == 127) { - fprintf(stderr, "scrot could not execute the command: %s.\n", execstr); - } + if (ret == -1) + warn("The child process could not be created"); + else if (WEXITSTATUS(ret) == 127) + warnx("scrot could not execute the command: %s", execStr); - exit(0); + exit(0); } -Imlib_Image -scrot_grab_focused(void) +Imlib_Image scrotGrabFocused(void) { - Imlib_Image im = NULL; - int rx = 0, ry = 0, rw = 0, rh = 0; - Window target = None; - int ignored; + Imlib_Image im = NULL; + int rx = 0, ry = 0, rw = 0, rh = 0; + Window target = None; + int ignored; - scrot_do_delay(); - XGetInputFocus(disp, &target, &ignored); - if (!scrot_get_geometry(target, &rx, &ry, &rw, &rh)) return NULL; - scrot_nice_clip(&rx, &ry, &rw, &rh); - im = imlib_create_image_from_drawable(0, rx, ry, rw, rh, 1); - if (opt.pointer == 1) - scrot_grab_mouse_pointer(im, rx, ry); - return im; + scrotDoDelay(); + XGetInputFocus(disp, &target, &ignored); + if (!scrotGetGeometry(target, &rx, &ry, &rw, &rh)) + return NULL; + scrotNiceClip(&rx, &ry, &rw, &rh); + im = imlib_create_image_from_drawable(0, rx, ry, rw, rh, 1); + if (opt.pointer) + scrotGrabMousePointer(im, rx, ry); + return im; } -Imlib_Image -scrot_sel_and_grab_image(void) +Imlib_Image scrotGrabAutoselect(void) { - Imlib_Image im = NULL; - static int xfd = 0; - static int fdsize = 0; - XEvent ev; - fd_set fdset; - int count = 0, done = 0; - int rx = 0, ry = 0, rw = 0, rh = 0, btn_pressed = 0; - Window target = None; - Status ret; - - scrot_selection_create(); + Imlib_Image im = NULL; + int rx = opt.autoselectX, ry = opt.autoselectY, rw = opt.autoselectW, rh = opt.autoselectH; - xfd = ConnectionNumber(disp); - fdsize = xfd + 1; + scrotDoDelay(); + scrotNiceClip(&rx, &ry, &rw, &rh); + im = imlib_create_image_from_drawable(0, rx, ry, rw, rh, 1); + if (opt.pointer) + scrotGrabMousePointer(im, rx, ry); + return im; +} - ret = XGrabKeyboard(disp, root, False, GrabModeAsync, GrabModeAsync, CurrentTime); - if (ret == AlreadyGrabbed) { - int attempts = 20; - struct timespec delay = {0, 50 * 1000L * 1000L}; - do { - nanosleep(&delay, NULL); - ret = XGrabKeyboard(disp, root, False, GrabModeAsync, GrabModeAsync, CurrentTime); - } while (--attempts > 0 && ret == AlreadyGrabbed); - } - if (ret != GrabSuccess) { - fprintf(stderr, "failed to grab keyboard\n"); - scrot_selection_destroy(); - exit(EXIT_FAILURE); - } - - - while (1) { - /* handle events here */ - while (!done && XPending(disp)) { - XNextEvent(disp, &ev); - switch (ev.type) { - case MotionNotify: - if (btn_pressed) { - scrot_selection_motion_draw(rx, ry, ev.xbutton.x, ev.xbutton.y); - } - break; - case ButtonPress: - btn_pressed = 1; - rx = ev.xbutton.x; - ry = ev.xbutton.y; - target = scrot_get_window(disp, ev.xbutton.subwindow, ev.xbutton.x, ev.xbutton.y); - if (target == None) - target = root; - break; - case ButtonRelease: - done = 1; - break; - case KeyPress: - - if (!btn_pressed) { -key_abort_shot: - fprintf(stderr, "Key was pressed, aborting shot\n"); - done = 2; - break; - } - - KeySym *keysym = NULL; - int keycode; /*dummy*/ - - keysym = XGetKeyboardMapping(disp, ev.xkey.keycode, 1, &keycode); - - if (keysym == NULL) break; - - switch (*keysym) { - case XK_Right: - if (++rx > scr->width) rx = scr->width; - break; - case XK_Left: - if (--rx < 0 ) rx = 0; - break; - case XK_Down: - if (++ry > scr->height) ry = scr->height; - break; - case XK_Up: - if (--ry < 0 ) ry = 0; - break; - default: - goto key_abort_shot; - } - XFree(keysym); - scrot_selection_motion_draw(rx, ry, ev.xbutton.x, ev.xbutton.y); - break; - case KeyRelease: - /* ignore */ - break; - default: - break; - } +/* Clip rectangle nicely */ +void scrotNiceClip(int* rx, int* ry, int* rw, int* rh) +{ + if (*rx < 0) { + *rw += *rx; + *rx = 0; } - if (done) - break; - - /* now block some */ - FD_ZERO(&fdset); - FD_SET(xfd, &fdset); - errno = 0; - count = select(fdsize, &fdset, NULL, NULL, NULL); - if ((count < 0) - && ((errno == ENOMEM) || (errno == EINVAL) || (errno == EBADF))) { - fprintf(stderr, "Connection to X display lost\n"); - scrot_selection_destroy(); - exit(EXIT_FAILURE); + if (*ry < 0) { + *rh += *ry; + *ry = 0; } - } - scrot_selection_draw(); - - XUngrabKeyboard(disp, CurrentTime); - - bool const isAreaSelect = (bool)(scrot_selection_get_rect()->w > 5); + if ((*rx + *rw) > scr->width) + *rw = scr->width - *rx; + if ((*ry + *rh) > scr->height) + *rh = scr->height - *ry; +} - scrot_selection_destroy(); +static Bool scrotXEventVisibility(Display* dpy, XEvent* ev, XPointer arg) +{ + (void)dpy; // unused + Window* win = (Window*)arg; + return (ev->xvisibility.window == *win); +} - if (done < 2) { - scrot_do_delay(); - if (isAreaSelect) { - /* if a rect has been drawn, it's an area selection */ - rw = ev.xbutton.x - rx; - rh = ev.xbutton.y - ry; - - if ((ev.xbutton.x + 1) == WidthOfScreen(scr)) { - ++rw; - } - - if ((ev.xbutton.y + 1) == HeightOfScreen(scr)) { - ++rh; - } - - if (rw < 0) { - rx += rw; - rw = 0 - rw; - } - if (rh < 0) { - ry += rh; - rh = 0 - rh; - } - - // Not record pointer if there is a selection area because it is busy on that, - // unless the delay option is used - if (opt.delay == 0) { - opt.pointer = 0; - } +/* Get geometry of window and use that */ +int scrotGetGeometry(Window target, int* rx, int* ry, int* rw, int* rh) +{ + Window child; + XWindowAttributes attr; + int stat, frames = 0; - } else { - /* else it's a window click */ - if (!scrot_get_geometry(target, &rx, &ry, &rw, &rh)) return NULL; + /* Get windowmanager frame of window */ + if (target != root) { + unsigned int d; + int x; + int status; + + status = XGetGeometry(disp, target, &root, &x, &x, &d, &d, &d, &d); + if (status) { + Window rt, *children, parent; + XEvent ev; + + for (;;) { + /* Find window manager frame. */ + status = XQueryTree(disp, target, &rt, &parent, &children, &d); + if (status && (children != None)) + XFree(children); + if (!status || (parent == None) || (parent == rt)) + break; + target = parent; + ++frames; + } + /* Get client window. */ + if (!opt.border) + target = scrotGetClientWindow(disp, target); + XRaiseWindow(disp, target); + + /* Give the WM time to update the hidden area of the window. + Some windows never send the event, a time limit is placed. + */ + XSelectInput(disp, target, FocusChangeMask); + + struct timespec delay = {0, 10000000L}; // 10ms + + for (short i = 0; i < 30; ++i) { + if (XCheckIfEvent(disp, &ev, &scrotXEventVisibility, (XPointer)&target)) + break; + nanosleep(&delay, NULL); + } + } } - scrot_nice_clip(&rx, &ry, &rw, &rh); - - if (! opt.silent) XBell(disp, 0); - im = imlib_create_image_from_drawable(0, rx, ry, rw, rh, 1); + stat = XGetWindowAttributes(disp, target, &attr); + if (!stat || (attr.map_state != IsViewable)) + return 0; + *rw = attr.width; + *rh = attr.height; + XTranslateCoordinates(disp, target, root, 0, 0, rx, ry, &child); - if (opt.pointer == 1) - scrot_grab_mouse_pointer(im, rx, ry); - } - return im; -} - -Imlib_Image -scrot_grab_autoselect(void) -{ - Imlib_Image im = NULL; - int rx = opt.autoselect_x, ry = opt.autoselect_y, rw = opt.autoselect_w, rh = opt.autoselect_h; - - scrot_do_delay(); - scrot_nice_clip(&rx, &ry, &rw, &rh); - im = imlib_create_image_from_drawable(0, rx, ry, rw, rh, 1); - if (opt.pointer == 1) - scrot_grab_mouse_pointer(im, rx, ry); - return im; -} - -/* clip rectangle nicely */ -void -scrot_nice_clip(int *rx, - int *ry, - int *rw, - int *rh) -{ - if (*rx < 0) { - *rw += *rx; - *rx = 0; - } - if (*ry < 0) { - *rh += *ry; - *ry = 0; - } - if ((*rx + *rw) > scr->width) - *rw = scr->width - *rx; - if ((*ry + *rh) > scr->height) - *rh = scr->height - *ry; + /* Special case when the TWM emulates the border directly on the window. */ + if (opt.border == 1 && frames < 2 && attr.border_width > 0) { + *rw += attr.border_width * 2; + *rh += attr.border_width * 2; + *rx -= attr.border_width; + *ry -= attr.border_width; + } + return 1; } -static Bool scrot_xevent_visibility(Display *dpy, XEvent *ev, XPointer arg) +Window scrotGetWindow(Display* display, Window window, int x, int y) { - (void) dpy; // unused - Window *win = (Window*)arg; - return (ev->xvisibility.window == *win); -} + Window source, target; -/* get geometry of window and use that */ -int -scrot_get_geometry(Window target, - int *rx, - int *ry, - int *rw, - int *rh) -{ - Window child; - XWindowAttributes attr; - int stat, frames = 0; - - /* get windowmanager frame of window */ - if (target != root) { - unsigned int d; - int x; - int status; - - status = XGetGeometry(disp, target, &root, &x, &x, &d, &d, &d, &d); - if (status != 0) { - Window rt, *children, parent; - XEvent ev; - - for (;;) { - /* Find window manager frame. */ - status = XQueryTree(disp, target, &rt, &parent, &children, &d); - if (status && (children != None)) { - XFree((char *) children); - } - if (!status || (parent == None) || (parent == rt)) { + int status, xOffset, yOffset; + + source = root; + target = window; + if (window == None) + window = root; + while (1) { + status = XTranslateCoordinates(display, source, window, x, y, &xOffset, + &yOffset, &target); + if (!status) break; - } - target = parent; - ++frames; - } - /* Get client window. */ - if (!opt.border) { - target = scrot_get_client_window(disp, target); - } - XRaiseWindow(disp, target); - - /* Give the WM time to update the hidden area of the window. - Some windows never send the event, a time limit is placed. - */ - XSelectInput(disp, target, FocusChangeMask); - for(short i = 0; i < 30; ++i) { - if (XCheckIfEvent(disp, &ev, &scrot_xevent_visibility, (XPointer)&target) == True) { + if (target == None) break; - } - usleep(2000); - } + source = window; + window = target; + x = xOffset; + y = yOffset; } - } - stat = XGetWindowAttributes(disp, target, &attr); - if ((stat == False) || (attr.map_state != IsViewable)) - return 0; - *rw = attr.width; - *rh = attr.height; - XTranslateCoordinates(disp, target, root, 0, 0, rx, ry, &child); - - /* Special case when the TWM emulates the border directly on the window. */ - if (opt.border == 1 && frames < 2 && attr.border_width > 0) { - *rw += attr.border_width * 2; - *rh += attr.border_width * 2; - *rx -= attr.border_width; - *ry -= attr.border_width; - } - return 1; -} - -Window -scrot_get_window(Display * display, - Window window, - int x, - int y) -{ - Window source, target; - - int status, x_offset, y_offset; - - source = root; - target = window; - if (window == None) - window = root; - while (1) { - status = - XTranslateCoordinates(display, source, window, x, y, &x_offset, - &y_offset, &target); - if (status != True) - break; if (target == None) - break; - source = window; - window = target; - x = x_offset; - y = y_offset; - } - if (target == None) - target = window; - return (target); + target = window; + return target; } +char* imPrintf(char* str, struct tm* tm, char* filenameIM, char* filenameThumb, Imlib_Image im) +{ + char* c; + char buf[20]; + char ret[4096]; + char strf[4096]; + char* tmp; + struct stat st; -char * -im_printf(char *str, struct tm *tm, - char *filename_im, - char *filename_thumb, - Imlib_Image im) -{ - char *c; - char buf[20]; - char ret[4096]; - char strf[4096]; - char *tmp; - struct stat st; - - ret[0] = '\0'; - - if (strftime(strf, 4095, str, tm) == 0) { - fprintf(stderr, "strftime returned 0\n"); - exit(EXIT_FAILURE); - } - - imlib_context_set_image(im); - for (c = strf; *c != '\0'; c++) { - if (*c == '$') { - c++; - switch (*c) { - case 'a': - gethostname(buf, sizeof(buf)); - strcat(ret, buf); - break; - case 'f': - if (filename_im) - strcat(ret, filename_im); - break; - case 'm': /* t was already taken, so m as in mini */ - if (filename_thumb) - strcat(ret, filename_thumb); - break; - case 'n': - if (filename_im) { - tmp = strrchr(filename_im, '/'); - if (tmp) - strcat(ret, tmp + 1); - else - strcat(ret, filename_im); - } - break; - case 'w': - snprintf(buf, sizeof(buf), "%d", imlib_image_get_width()); - strcat(ret, buf); - break; - case 'h': - snprintf(buf, sizeof(buf), "%d", imlib_image_get_height()); - strcat(ret, buf); - break; - case 's': - if (filename_im) { - if (!stat(filename_im, &st)) { - int size; - - size = st.st_size; - snprintf(buf, sizeof(buf), "%d", size); - strcat(ret, buf); - } else - strcat(ret, "[err]"); - } - break; - case 'p': - snprintf(buf, sizeof(buf), "%d", - imlib_image_get_width() * - imlib_image_get_height()); - strcat(ret, buf); - break; - case 't': - tmp = imlib_image_format(); - if (tmp) { - strcat(ret, tmp); - } - break; - case '$': - strcat(ret, "$"); - break; - default: - strncat(ret, c, 1); - break; - } - } else if (*c == '\\') { - c++; - switch (*c) { - case 'n': - if (filename_im) - strcat(ret, "\n"); - break; - default: - strncat(ret, c, 1); - break; - } - } else { - const size_t len = strlen(ret); - ret[len] = *c; - ret[len + 1] = '\0'; - } - } - return strdup(ret); -} - -Window -scrot_get_client_window(Display * display, - Window target) -{ - Atom state; - Atom type = None; - int format, status; - unsigned char *data; - unsigned long after, items; - Window client; + ret[0] = '\0'; - state = XInternAtom(display, "WM_STATE", True); - if (state == None) - return target; - status = - XGetWindowProperty(display, target, state, 0L, 0L, False, - (Atom) AnyPropertyType, &type, &format, &items, &after, - &data); - if ((status == Success) && (type != None)) - return target; - client = scrot_find_window_by_property(display, target, state); - if (!client) - return target; - return client; -} + if (strftime(strf, 4095, str, tm) == 0) + errx(EXIT_FAILURE, "strftime returned 0"); -Window -scrot_find_window_by_property(Display * display, - const Window window, - const Atom property) -{ - Atom type = None; - int format, status; - unsigned char *data; - unsigned int i, number_children; - unsigned long after, number_items; - Window child = None, *children, parent, root; - - status = - XQueryTree(display, window, &root, &parent, &children, &number_children); - if (!status) - return None; - for (i = 0; (i < number_children) && (child == None); i++) { - status = - XGetWindowProperty(display, children[i], property, 0L, 0L, False, - (Atom) AnyPropertyType, &type, &format, - &number_items, &after, &data); - if (data) - XFree(data); - if ((status == Success) && (type != (Atom) NULL)) - child = children[i]; - } - for (i = 0; (i < number_children) && (child == None); i++) - child = scrot_find_window_by_property(display, children[i], property); - if (children != None) - XFree(children); - return (child); -} - -Imlib_Image -scrot_grab_stack_windows(void) -{ - if (XGetSelectionOwner(disp, XInternAtom(disp, "_NET_WM_CM_S0", False)) == None) { - fprintf(stderr, "Composite Manager is not running, required to use this option.\n"); - exit(EXIT_FAILURE); + imlib_context_set_image(im); + for (c = strf; *c != '\0'; c++) { + if (*c == '$') { + c++; + switch (*c) { + case 'a': + gethostname(buf, sizeof(buf)); + strlcat(ret, buf, sizeof(ret)); + break; + case 'f': + if (filenameIM) + strlcat(ret, filenameIM, sizeof(ret)); + break; + case 'm': /* t was already taken, so m as in mini */ + if (filenameThumb) + strlcat(ret, filenameThumb, sizeof(ret)); + break; + case 'n': + if (filenameIM) { + tmp = strrchr(filenameIM, '/'); + if (tmp) + strlcat(ret, tmp + 1, sizeof(ret)); + else + strlcat(ret, filenameIM, sizeof(ret)); + } + break; + case 'w': + snprintf(buf, sizeof(buf), "%d", imlib_image_get_width()); + strlcat(ret, buf, sizeof(ret)); + break; + case 'h': + snprintf(buf, sizeof(buf), "%d", imlib_image_get_height()); + strlcat(ret, buf, sizeof(ret)); + break; + case 's': + if (filenameIM) { + if (!stat(filenameIM, &st)) { + int size; + + size = st.st_size; + snprintf(buf, sizeof(buf), "%d", size); + strlcat(ret, buf, sizeof(ret)); + } else + strlcat(ret, "[err]", sizeof(ret)); + } + break; + case 'p': + snprintf(buf, sizeof(buf), "%d", + imlib_image_get_width() * imlib_image_get_height()); + strlcat(ret, buf, sizeof(ret)); + break; + case 't': + tmp = imlib_image_format(); + if (tmp) + strlcat(ret, tmp, sizeof(ret)); + break; + case '$': + strlcat(ret, "$", sizeof(ret)); + break; + default: + snprintf(buf, sizeof(buf), "%.1s", c); + strlcat(ret, buf, sizeof(ret)); + break; + } + } else if (*c == '\\') { + c++; + switch (*c) { + case 'n': + if (filenameIM) + strlcat(ret, "\n", sizeof(ret)); + break; + default: + snprintf(buf, sizeof(buf), "%.1s", c); + strlcat(ret, buf, sizeof(ret)); + break; + } + } else { + const size_t length = strlen(ret); + ret[length] = *c; + ret[length + 1] = '\0'; + } } + return strdup(ret); +} - unsigned long nitems_return; - unsigned long bytes_after_return; - unsigned char *prop_return; - long long_offset = 0L; - long long_length = ~0L; - Bool delete = False; - int actual_format_return; - Atom actual_type_return; - Scrot_Imlib_List *list_images = NULL; - Imlib_Image im = NULL; - XImage *ximage = NULL; +Window scrotGetClientWindow(Display* display, Window target) +{ + Atom state; + Atom type = None; + int format, status; + unsigned char* data; + unsigned long after, items; + Window client; + + state = XInternAtom(display, "WM_STATE", True); + if (state == None) + return target; + status = XGetWindowProperty(display, target, state, 0L, 0L, False, + AnyPropertyType, &type, &format, &items, &after, + &data); + if ((status == Success) && (type != None)) + return target; + client = scrotFindWindowByProperty(display, target, state); + if (!client) + return target; + return client; +} + +Window scrotFindWindowByProperty(Display* display, const Window window, const Atom property) +{ + Atom type = None; + int format, status; + unsigned char* data; + unsigned int i, numberChildren; + unsigned long after, numberItems; + Window child = None, *children, parent, rootReturn; + + status = XQueryTree(display, window, &rootReturn, &parent, &children, &numberChildren); + if (!status) + return None; + for (i = 0; (i < numberChildren) && (child == None); i++) { + status = XGetWindowProperty(display, children[i], property, 0L, 0L, False, + AnyPropertyType, &type, &format, + &numberItems, &after, &data); + if (data) + XFree(data); + if ((status == Success) && type) + child = children[i]; + } + for (i = 0; (i < numberChildren) && (child == None); i++) + child = scrotFindWindowByProperty(display, children[i], property); + if (children != None) + XFree(children); + return (child); +} + +Imlib_Image scrotGrabStackWindows(void) +{ + if (XGetSelectionOwner(disp, XInternAtom(disp, "_NET_WM_CM_S0", False)) == None) + errx(EXIT_FAILURE, "option --stack: Composite Manager is not running, required to use this option."); + + unsigned long numberItemsReturn; + unsigned long bytesAfterReturn; + unsigned char* propReturn; + long offset = 0L; + long length = ~0L; + Bool delete = False; + int actualFormatReturn; + Atom actualTypeReturn; + Imlib_Image im = NULL; + XImage* ximage = NULL; XWindowAttributes attr; unsigned long i = 0; - #define EWMH_CLIENT_LIST "_NET_CLIENT_LIST" // spec EWMH - Atom atom_prop = XInternAtom(disp, EWMH_CLIENT_LIST, False); - Atom atom_type = AnyPropertyType; + Atom atomProp = XInternAtom(disp, EWMH_CLIENT_LIST, False); + Atom atomType = AnyPropertyType; - int result = XGetWindowProperty(disp, root, atom_prop, long_offset, long_length, - delete, atom_type, &actual_type_return, &actual_format_return, - &nitems_return, &bytes_after_return, &prop_return); - - if (result != Success || nitems_return == 0) { - fprintf(stderr, "Failed XGetWindowProperty: " EWMH_CLIENT_LIST "\n"); - exit(EXIT_FAILURE); - } + int result = XGetWindowProperty(disp, root, atomProp, offset, length, + delete, atomType, &actualTypeReturn, &actualFormatReturn, + &numberItemsReturn, &bytesAfterReturn, &propReturn); - XCompositeRedirectSubwindows(disp, root, CompositeRedirectAutomatic); + if (result != Success || numberItemsReturn == 0) + errx(EXIT_FAILURE, "option --stack: Failed XGetWindowProperty: " EWMH_CLIENT_LIST); + + initializeScrotList(images); - for (i = 0; i < nitems_return; i++) { + XCompositeRedirectSubwindows(disp, root, CompositeRedirectAutomatic); - Window win = *((Window*)prop_return + i); + for (i = 0; i < numberItemsReturn; i++) { + Window win = *((Window*)propReturn + i); - if (0 == XGetWindowAttributes(disp, win, &attr)) { - fprintf(stderr, "Failed XGetWindowAttributes\n"); - exit(EXIT_FAILURE); - } + if (!XGetWindowAttributes(disp, win, &attr)) + errx(EXIT_FAILURE, "option --stack: Failed XGetWindowAttributes"); /* Only visible windows */ - if (attr.map_state != IsViewable) { + if (attr.map_state != IsViewable) continue; - } - if (!scrot_match_window_class_name(win)) { + if (!scrotMatchWindowClassName(win)) continue; - } ximage = XGetImage(disp, win, 0, 0, attr.width, attr.height, AllPlanes, ZPixmap); - if (ximage == NULL) { - fprintf(stderr, "Failed XGetImage: Window id 0x%lx.\n", win); - exit(EXIT_FAILURE); - } + if (!ximage) + errx(EXIT_FAILURE, "option --stack: Failed XGetImage: Window id 0x%lx", win); im = imlib_create_image_from_ximage(ximage, NULL, attr.x, attr.y, attr.width, attr.height, 1); XFree(ximage); - list_images = append_to_scrot_imlib(list_images, im); + appendToScrotList(images, im); } - return stalk_image_concat(list_images); + return stalkImageConcat(&images, opt.stackDirection); } -Imlib_Image -scrot_grab_shot_multi(void) +Imlib_Image scrotGrabShotMulti(void) { - int screens; - int i; - char *dispstr, *subdisp; - char newdisp[255]; - Scrot_Imlib_List *images = NULL; - Imlib_Image ret = NULL; - - screens = ScreenCount(disp); - if (screens < 2) - return scrot_grab_shot(); - - subdisp = strdup(DisplayString(disp)); - - for (i = 0; i < screens; i++) { - dispstr = strchr(subdisp, ':'); - if (dispstr) { - dispstr = strchr(dispstr, '.'); - if (NULL != dispstr) - *dispstr = '\0'; + int screens = ScreenCount(disp); + if (screens < 2) + return scrotGrabShot(); + + int i; + char* dispStr; + char* subDisp; + char newDisp[255]; + Imlib_Image ret = NULL; + + initializeScrotList(images); + + subDisp = strdup(DisplayString(disp)); + + for (i = 0; i < screens; i++) { + dispStr = strchr(subDisp, ':'); + if (dispStr) { + dispStr = strchr(dispStr, '.'); + if (dispStr) + *dispStr = '\0'; + } + snprintf(newDisp, sizeof(newDisp), "%s.%d", subDisp, i); + initXAndImlib(newDisp, i); + ret = imlib_create_image_from_drawable(0, 0, 0, scr->width, + scr->height, 1); + + appendToScrotList(images, ret); + } + free(subDisp); + + return stalkImageConcat(&images, HORIZONTAL); +} + +Imlib_Image stalkImageConcat(ScrotList* images, enum Direction const dir) +{ + if (isEmptyScrotList(images)) + return NULL; + + int total = 0, max = 0; + int x = 0, y = 0, w , h; + Imlib_Image ret, im; + ScrotListNode* image = NULL; + + bool const vertical = (dir == VERTICAL) ? true : false; + + forEachScrotList(images, image) { + im = (Imlib_Image) image->data; + imlib_context_set_image(im); + h = imlib_image_get_height(); + w = imlib_image_get_width(); + if (!vertical) { + if (h > max) + max = h; + total += w; + } else { + if (w > max) + max = w; + total += h; + } } - snprintf(newdisp, sizeof(newdisp), "%s.%d", subdisp, i); - init_x_and_imlib(newdisp, i); - ret = - imlib_create_image_from_drawable(0, 0, 0, scr->width, - scr->height, 1); - images = append_to_scrot_imlib(images, ret); - } - free(subdisp); - - ret = stalk_image_concat(images); - - return ret; -} - -Imlib_Image -stalk_image_concat(Scrot_Imlib_List * images) -{ - int tot_w = 0, max_h = 0, w, h; - int x = 0; - Scrot_Imlib_List *l, *item; - Imlib_Image ret, im; - - if (is_scrot_imlib_list_empty(images)) - return NULL; - - l = images; - while (l) { - im = (Imlib_Image) l->data; - imlib_context_set_image(im); - h = imlib_image_get_height(); - w = imlib_image_get_width(); - if (h > max_h) - max_h = h; - tot_w += w; - l = l->next; - } - ret = imlib_create_image(tot_w, max_h); - imlib_context_set_image(ret); - imlib_context_set_color(255, 0, 0, 0); - imlib_image_fill_rectangle(0, 0, tot_w, max_h); - l = images; - while (l) { - im = (Imlib_Image) l->data; - item = l; - l = l->next; - imlib_context_set_image(im); - h = imlib_image_get_height(); - w = imlib_image_get_width(); + if (!vertical) { + w = total; + h = max; + } else { + w = max; + h = total; + } + ret = imlib_create_image(w, h); + imlib_context_set_image(ret); - imlib_context_set_anti_alias(0); - imlib_context_set_dither(1); - imlib_context_set_blend(0); - imlib_context_set_angle(0); - imlib_blend_image_onto_image(im, 0, 0, 0, w, h, x, 0, w, h); - x += w; - imlib_context_set_image(im); - imlib_free_image_and_decache(); - free(item); - } - return ret; + imlib_context_set_color(0, 0, 0, 255); + imlib_image_fill_rectangle(0, 0, w, h); + + image = firstScrotList(images); + while (image) { + im = (Imlib_Image) image->data; + imlib_context_set_image(im); + h = imlib_image_get_height(); + w = imlib_image_get_width(); + imlib_context_set_image(ret); + imlib_context_set_anti_alias(0); + imlib_context_set_dither(1); + imlib_context_set_blend(0); + imlib_context_set_angle(0); + imlib_blend_image_onto_image(im, 0, 0, 0, w, h, x, y, w, h); + (!vertical) ? (x += w) : (y += h); + imlib_context_set_image(im); + imlib_free_image_and_decache(); + nextAndFreeScrotList(image); + } + return ret; } diff -Nru scrot-1.6/src/Makefile.am scrot-1.7/src/Makefile.am --- scrot-1.6/src/Makefile.am 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/src/Makefile.am 2021-11-10 02:08:36.000000000 +0000 @@ -2,7 +2,7 @@ # gilbertt@linuxbrit.co.uk, # scrot_sucks@linuxbrit.co.uk> # Copyright 2016 Joao Eriberto Mota Filho -# Copyright 2020-2021 Daniel T. Borelli +# Copyright 2020-2021 Daniel T. Borelli # Copyright 2020 Jeroen Roovers # Copyright 2021 Christopher R. Nelson # Copyright 2021 Guilherme Janczak @@ -34,16 +34,11 @@ bin_PROGRAMS = scrot - -scrot_CPPFLAGS = @X11_CFLAGS@ @IMLIB2_CFLAGS@ @XCOMPOSITE_CFLAGS@ \ - @XEXT_CFLAGS@ @XFIXES_CFLAGS@ -scrot_LDADD = @X11_LIBS@ @IMLIB2_LIBS@ @XCOMPOSITE_LIBS@ \ - @XEXT_LIBS@ @XFIXES_LIBS@ - - -scrot_SOURCES = main.c scrot.h \ +scrot_CPPFLAGS = @CPPFLAGS@ +scrot_LDADD = @LIBS@ +scrot_SOURCES = main.c scrot.h \ options.c options.h imlib.c structs.h note.c note.h \ scrot_selection.c scrot_selection.h \ selection_classic.c selection_classic.h \ selection_edge.c selection_edge.h \ -slist.c slist.h +slist.h diff -Nru scrot-1.6/src/note.c scrot-1.7/src/note.c --- scrot-1.6/src/note.c 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/src/note.c 2021-11-10 02:08:36.000000000 +0000 @@ -1,6 +1,9 @@ /* note.c -Copyright 2019-2020 Daniel T. Borelli +Copyright 2019-2021 Daniel T. Borelli +Copyright 2021 Guilherme Janczak +Copyright 2021 IFo Hancroft +Copyright 2021 Peter Wu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -30,235 +33,210 @@ #include "scrot.h" -scrotnote note; +enum { // default color + DEF_COLOR_RED = 0, + DEF_COLOR_GREEN = 0, + DEF_COLOR_BLUE = 0, + DEF_COLOR_ALPHA = 255 +}; -static Imlib_Font imfont = NULL; +ScrotNote note; -static void load_font(void); +static Imlib_Font imFont = NULL; -static char *parse_text(char **tok, char *const end); +static void loadFont(void); -static char *new_text(const char *src, const size_t len); +static char* parseText(char**, char* const); -static inline void pfree(char **ptr) +static inline void pfree(char** ptr) { - free(*ptr); - *ptr = NULL; + free(*ptr); + *ptr = NULL; } -static inline void next_space(char **tok) +static inline void nextSpace(char** token) { - while (*++*tok == ' ' && **tok != '\0'); + while (*++*token == ' ' && **token != '\0') { } } -static inline void next_not_space(char **tok) +static inline void nextNotSpace(char** token) { - while (*++*tok != ' ' && **tok != '\0'); + while (*++*token != ' ' && **token != '\0') { } } -void scrot_note_new(char *format) +void scrotNoteNew(char* format) { - scrot_note_free(); + scrotNoteFree(); - note = (scrotnote){NULL,NULL,0,0,0.0,{COLOR_OPTIONAL,0,0,0,0}}; + note = (ScrotNote) { + NULL, NULL, 0, 0, 0.0, + { DEF_COLOR_RED, DEF_COLOR_GREEN, + DEF_COLOR_BLUE, DEF_COLOR_ALPHA } + }; - char *const end = format + strlen(format); + char* const end = format + strlen(format); - char *tok = strpbrk(format, "-"); + char* token = strpbrk(format, "-"); - if ((NULL == tok) || (strlen(tok) == 1)) { + if (!token || (strlen(token) == 1)) { + malformed: -malformed: - - pfree(&format); - fprintf(stderr, "Error --note option : Malformed syntax.\n"); - exit(EXIT_FAILURE); - } - - while (tok != NULL) { - - const char type = *++tok; - - next_space(&tok); - - switch(type) { - case 'f': { - note.font = parse_text(&tok, end); - - if (NULL == note.font) { - fprintf(stderr, "Error --note option : Malformed syntax for -f\n"); - exit(EXIT_FAILURE); - } - - char *number = strrchr(note.font, '/'); - - if (NULL == number) { - fprintf(stderr, "Error --note option : Malformed syntax for -f, required number.\n"); - exit(EXIT_FAILURE); - } - - int fntsize = options_parse_required_number(++number); - - if (fntsize < 6) - fprintf(stderr, "Warning: --note option: font size < 6\n"); - } - break; - case 'x': { - if ((1 != sscanf(tok, "%d", ¬e.x) || (note.x < 0))) { - fprintf(stderr, "Error --note option : Malformed syntax for -x\n"); - exit(EXIT_FAILURE); - } - next_not_space(&tok); - } - break; - case 'y': { - if ((1 != sscanf(tok, "%d", ¬e.y)) || (note.y < 0)) { - fprintf(stderr, "Error --note option : Malformed syntax for -y\n"); - exit(EXIT_FAILURE); - } - next_not_space(&tok); - } - break; - case 'a': { - if ((1 != sscanf(tok, "%lf", ¬e.angle))) { - fprintf(stderr, "Error --note option : Malformed syntax for -a\n"); - exit(EXIT_FAILURE); - } - next_not_space(&tok); - } - break; - case 't': - note.text = parse_text(&tok, end); - if (NULL == note.text) { - fprintf(stderr, "Error --note option : Malformed syntax for -t\n"); - exit(EXIT_FAILURE); - } - break; - case 'c': { - char *saveptr = NULL; - - char *c = strtok_r(tok, ",", &saveptr); - - int nclrs = 0; - - note.color.status = COLOR_OK; - - while (c) { - - tok = c; - - int color = options_parse_required_number(c); - - if ((color < 0) || color > 255) { - fprintf(stderr, "Error --note option : color '%d' out of range 0..255\n", color); - note.color.status = COLOR_ERROR; - break; - } - - switch(++nclrs) { - case 1 : note.color.r = color; break; - case 2 : note.color.g = color; break; - case 3 : note.color.b = color; break; - case 4 : note.color.a = color; break; - } - - c = strtok_r(NULL, ",", &saveptr); - } + pfree(&format); + errx(EXIT_FAILURE, "Error --note option : Malformed syntax."); + } - if (nclrs != 4) { - fprintf(stderr, "Error --note option : Malformed syntax for -c\n"); - note.color.status = COLOR_ERROR; + while (token) { + const char type = *++token; + char* savePtr = NULL; + char* c; + + nextSpace(&token); + + switch (type) { + case 'f': + note.font = parseText(&token, end); + + if (!note.font) + errx(EXIT_FAILURE, "Error --note option : Malformed syntax for -f"); + + char* number = strrchr(note.font, '/'); + + if (!number) + errx(EXIT_FAILURE, "Error --note option : Malformed syntax for -f, required number."); + + int fontSize = optionsParseRequiredNumber(++number); + + if (fontSize < 6) + warnx("Warning: --note option: font size < 6"); + break; + case 'x': + if ((1 != sscanf(token, "%d", ¬e.x) || (note.x < 0))) + errx(EXIT_FAILURE, "Error --note option : Malformed syntax for -x"); + nextNotSpace(&token); + break; + case 'y': + if ((1 != sscanf(token, "%d", ¬e.y)) || (note.y < 0)) + errx(EXIT_FAILURE, "Error --note option : Malformed syntax for -y"); + nextNotSpace(&token); + break; + case 'a': + if ((1 != sscanf(token, "%lf", ¬e.angle))) + errx(EXIT_FAILURE, "Error --note option : Malformed syntax for -a"); + nextNotSpace(&token); + break; + case 't': + note.text = parseText(&token, end); + if (!note.text) + errx(EXIT_FAILURE, "Error --note option : Malformed syntax for -t"); + break; + case 'c': + c = strtok_r(token, ",", &savePtr); + + int numberColors = 0; + + while (c) { + token = c; + + int const color = optionsParseRequireRange( + optionsParseRequiredNumber(c), 0 ,255); + + switch (++numberColors) { + case 1: + note.color.r = color; + break; + case 2: + note.color.g = color; + break; + case 3: + note.color.b = color; + break; + case 4: + note.color.a = color; + break; + } + + c = strtok_r(NULL, ",", &savePtr); + } + + if (numberColors > 4) + warnx("Warning --note option : Malformed syntax for -c"); + break; + default: + errx(EXIT_FAILURE, "Error --note option : unknown option: '-%c'", type); } - } - break; - default: - fprintf(stderr, "Error --note option : unknown option: '-%c'\n", type); - exit(EXIT_FAILURE); - } - tok = strpbrk(tok, "-"); - } + token = strpbrk(token, "-"); + } - if ((NULL == note.font) || (NULL == note.text)) - goto malformed; + if (!note.font || !note.text) + goto malformed; - load_font(); + loadFont(); } -void scrot_note_free(void) +void scrotNoteFree(void) { - if (note.text) pfree(¬e.text); - if (note.font) pfree(¬e.font); + if (note.text) + pfree(¬e.text); + + if (note.font) + pfree(¬e.font); - if (imfont) { - imlib_context_set_font(imfont); - imlib_free_font(); + if (imFont) { + imlib_context_set_font(imFont); + imlib_free_font(); } } -void scrot_note_draw(Imlib_Image im) +void scrotNoteDraw(Imlib_Image im) { - if (NULL == im) return; + if (!im) + return; - imlib_context_set_image(im); - imlib_context_set_font(imfont); + imlib_context_set_image(im); + imlib_context_set_font(imFont); - imlib_context_set_direction(IMLIB_TEXT_TO_ANGLE); - imlib_context_set_angle(note.angle); + imlib_context_set_direction(IMLIB_TEXT_TO_ANGLE); + imlib_context_set_angle(note.angle); - if (note.color.status == COLOR_OK) - imlib_context_set_color(note.color.r, - note.color.g, - note.color.b, - note.color.a); + imlib_context_set_color(note.color.r, + note.color.g, + note.color.b, + note.color.a); - imlib_text_draw(note.x, note.y, note.text); + imlib_text_draw(note.x, note.y, note.text); } -void load_font(void) +void loadFont(void) { - imfont = imlib_load_font(note.font); + imFont = imlib_load_font(note.font); - if (!imfont) { - fprintf(stderr, "Error --note option : Failed to load fontname: %s\n", note.font); - scrot_note_free(); - exit(EXIT_FAILURE); - } + if (!imFont) { + warnx("Error --note option : Failed to load fontname: %s", note.font); + scrotNoteFree(); + exit(EXIT_FAILURE); + } } -char *parse_text(char **tok, char *const end) +char* parseText(char** token, char* const end) { - assert(NULL != *tok); - assert(NULL != end); - - if (**tok != '\'') return NULL; - - (*tok)++; - - char *begin = *tok; + assert(NULL != *token); + assert(NULL != end); - while ((*tok != end) && **tok != '\'') { - (*tok)++; - } + if (**token != '\'') + return NULL; - ptrdiff_t len = (*tok - begin); - - if (len == 0) return NULL; - - return new_text(begin, len); -} - -char *new_text(const char *src, const size_t len) -{ - assert(NULL != src); + (*token)++; - char *text = malloc(len + 1); + char* begin = *token; - assert(NULL != text); + while ((*token != end) && **token != '\'') + (*token)++; - strncpy(text, src, len); + ptrdiff_t length = (*token - begin); - text[len] = '\0'; + if (length == 0) + return NULL; - return text; + return strndup(begin, length); } diff -Nru scrot-1.6/src/note.h scrot-1.7/src/note.h --- scrot-1.6/src/note.h 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/src/note.h 2021-11-10 02:08:36.000000000 +0000 @@ -1,7 +1,8 @@ /* note.h -Copyright 2019 Daniel T. Borelli -Copyright 2021 Christopher R. Nelson +Copyright 2019-2021 Daniel T. Borelli +Copyright 2021 Christopher R. Nelson +Copyright 2021 Peter Wu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -25,12 +26,11 @@ */ /* This file is part of the scrot project. */ - -#ifndef NOTE_H -#define NOTE_H -#include +#pragma once + #include "options.h" +#include /* * Format: -f 'NAME/SIZE' -x NUM -y NUM -t 'TEXT' -c NUM,NUM,NUM,NUM @@ -43,36 +43,25 @@ * * */ -enum ecolor { - COLOR_ERROR = -1, /* error parser */ - COLOR_OPTIONAL = 0, /* the user did not indicate the color */ - COLOR_OK = 1, /* the user indicate the color */ +struct __ScrotNote { + char* font; /* font name */ + char* text; /* text of the note */ + int x; /* position screen (optional) */ + int y; /* position screen (optional) */ + double angle; /* angle text (optional) */ + + struct Color { /* (optional) */ + int r, /* red */ + g, /* green */ + b, /* blue */ + a; /* alpha */ + } color; }; -struct __scrotnote -{ - char *font; /* font name */ - char *text; /* text of the note */ - int x; /* position screen (optional) */ - int y; /* position screen (optional) */ - double angle; /* angle text (optional) */ - - struct color /* (optional) */ - { - enum ecolor status; - int r, /* red */ - g, /* green */ - b, /* blue */ - a; /* alpha */ - } color; -}; - -extern scrotnote note; - -void scrot_note_new(char *format); +extern ScrotNote note; -void scrot_note_free(void); +void scrotNoteNew(char*); -void scrot_note_draw(Imlib_Image im); +void scrotNoteFree(void); -#endif +void scrotNoteDraw(Imlib_Image); diff -Nru scrot-1.6/src/options.c scrot-1.7/src/options.c --- scrot-1.6/src/options.c 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/src/options.c 2021-11-10 02:08:36.000000000 +0000 @@ -9,10 +9,14 @@ Copyright 2010 Ibragimov Rinat Copyright 2017 Stoney Sauce Copyright 2019 Daniel Lublin -Copyright 2019-2021 Daniel T. Borelli +Copyright 2019-2021 Daniel T. Borelli Copyright 2019 Jade Auer Copyright 2020 Sean Brennan Copyright 2021 Christopher R. Nelson +Copyright 2021 Guilherme Janczak +Copyright 2021 IFo Hancroft +Copyright 2021 Peter Wu +Copyright 2021 Wilson Smith <01wsmith+gh@gmail.com> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -35,465 +39,537 @@ */ -#include "scrot.h" #include "options.h" +#include "scrot.h" #include -#define MAX_LEN_WINDOW_CLASS_NAME 80 +#define STR_LEN_MAX_FILENAME(msg, fileName) do { \ + if (strlen((fileName)) > MAX_FILENAME) { \ + errx(EXIT_FAILURE, #msg " filename too long, must be " \ + "less than %d characters", MAX_FILENAME); \ + } \ +} while(0) + +#define checkMaxOutputFileName(fileName) \ + STR_LEN_MAX_FILENAME(output, (fileName)) + +#define checkMaxInputFileName(fileName) \ + STR_LEN_MAX_FILENAME(input, (fileName)) + +enum { + MAX_LEN_WINDOW_CLASS_NAME = 80, //characters + MAX_FILENAME = 256, // characters + MAX_DISPLAY_NAME = 256, // characters +}; + +ScrotOptions opt = { + .quality = 75, + .lineStyle = LineSolid, + .lineWidth = 1, + .lineOpacity = SELECTION_OPACITY_DEFAULT, + .lineMode = LINE_MODE_S_CLASSIC, + .stackDirection = HORIZONTAL, +}; + +int optionsParseRequiredNumber(char const* str) +{ + assert(NULL != str); // fix yout caller function, + // the user does not impose this behavior + char* end = NULL; + long ret = 0L; + errno = 0; + + ret = strtol(str, &end, 10); + + if (errno) + goto range_error; + + if (str == end) + errx(EXIT_FAILURE, "the option is not a number: %s", end); + + if (ret > INT_MAX || ret < INT_MIN) { + errno = ERANGE; + goto range_error; + } -static void scrot_parse_option_array(int argc, char **argv); -scrotoptions opt; + return ret; -void -init_parse_options(int argc, char **argv) +range_error: + err(EXIT_FAILURE, "error strtol"); +} + +static int nonNegativeNumber(int number) { - /* Set default options */ - memset(&opt, 0, sizeof(scrotoptions)); + return (number < 0) ? 0 : number; +} - opt.quality = 75; - opt.overwrite = 0; - opt.line_style = LineSolid; - opt.line_width = 1; - opt.line_opacity = 100; - opt.line_mode = LINE_MODE_CLASSIC; +int optionsParseRequireRange(int n, int lo, int hi) +{ + return (n < lo ? lo : n > hi ? hi : n); +} + +bool optionsParseIsString(char const* const str) +{ + return (str && (str[0] != '\0')); +} + +static void optionsParseStack(char const* optarg) +{ + // the suboption it's optional + if (!optarg) { + opt.stackDirection = HORIZONTAL; + return; + } + char const* value = strchr(optarg, '='); - /* Parse the cmdline args */ - scrot_parse_option_array(argc, argv); + if (value) + ++value; + else + value = optarg; + + if (*value == 'v') + opt.stackDirection = VERTICAL; + else if (*value == 'h') + opt.stackDirection = HORIZONTAL; + else { + errx(EXIT_FAILURE, "option --stack: Unknown value for suboption '%s'", + value); + } } -int -options_parse_required_number(char *str) +static void optionsParseSelection(char const* optarg) { - char *end = NULL; - int ret = 0; - errno = 0; + // the suboption it's optional + if (!optarg) { + opt.selection.mode = SELECTION_MODE_CAPTURE; + return; + } - if (str != NULL) { - ret = strtol(str, &end, 10); - } + char const* value = strchr(optarg, '='); - if (str == end) { - fprintf(stderr, "the option is not a number: %s\n", end); - exit(EXIT_FAILURE); - } + if (value) + ++value; + else + value = optarg; + + if (!strncmp(value, SELECTION_MODE_S_CAPTURE, SELECTION_MODE_L_CAPTURE)) { + opt.selection.mode = SELECTION_MODE_CAPTURE; + return; /* it has no parameter */ + } + else if (!strncmp(value, SELECTION_MODE_S_HIDE, SELECTION_MODE_L_HIDE)) { + opt.selection.mode = SELECTION_MODE_HIDE; + value += SELECTION_MODE_L_HIDE; + } + else if (!strncmp(value, SELECTION_MODE_S_HOLE, SELECTION_MODE_L_HOLE)) { + opt.selection.mode = SELECTION_MODE_HOLE; + } + else if (!strncmp(value, SELECTION_MODE_S_BLUR, SELECTION_MODE_L_BLUR)) { + opt.selection.mode = SELECTION_MODE_BLUR; + opt.selection.paramNum = SELECTION_MODE_BLUR_DEFAULT; + value += SELECTION_MODE_L_BLUR; + } + else { + errx(EXIT_FAILURE, "option --select: Unknown value for suboption '%s'", + value); + } - if (errno) { - perror("strtol"); - exit(EXIT_FAILURE); - } + if (opt.selection.mode & SELECTION_MODE_NOT_NEED_PARAM) + return; - return ret; -} + if (*value != SELECTION_MODE_SEPARATOR) + return; -static void -options_parse_line(char *optarg) -{ - enum {STYLE = 0, WIDTH, COLOR, OPACITY, MODE}; + if (*(++value) == '\0') + errx(EXIT_FAILURE, "option --select: Invalid parameter."); - char *const token[] = { - [STYLE] = "style", - [WIDTH] = "width", - [COLOR] = "color", - [OPACITY] = "opacity", - [MODE] = "mode", - NULL - }; + if (opt.selection.mode == SELECTION_MODE_BLUR) { + int const num = nonNegativeNumber(optionsParseRequiredNumber(value)); - char *subopts = optarg; - char *value = NULL; + opt.selection.paramNum = optionsParseRequireRange(num, + SELECTION_MODE_BLUR_MIN, SELECTION_MODE_BLUR_MAX); - while (*subopts != '\0') { - switch(getsubopt(&subopts, token, &value)) { + } else { // SELECTION_MODE_HIDE - case STYLE: + checkMaxInputFileName(value); + + opt.selection.paramStr = strdup(value); + } +} - if (value == NULL || *value == '\0') { - fprintf(stderr, "Missing value for " - "suboption '%s'\n", token[STYLE]); - exit(EXIT_FAILURE); +static void optionsParseLine(char* optarg) +{ + enum { + Style = 0, + Width, + Color, + Opacity, + Mode + }; + + char* const token[] = { + [Style] = "style", + [Width] = "width", + [Color] = "color", + [Opacity] = "opacity", + [Mode] = "mode", + NULL + }; + + char* subopts = optarg; + char* value = NULL; + + while (*subopts != '\0') { + switch (getsubopt(&subopts, token, &value)) { + case Style: + if (!optionsParseIsString(value)) { + errx(EXIT_FAILURE, "Missing value for suboption '%s'", + token[Style]); } if (!strncmp(value, "dash", 4)) - opt.line_style = LineOnOffDash; + opt.lineStyle = LineOnOffDash; else if (!strncmp(value, "solid", 5)) - opt.line_style = LineSolid; + opt.lineStyle = LineSolid; else { - fprintf(stderr, "Unknown value for " - "suboption '%s': %s\n", token[STYLE], value); - exit(EXIT_FAILURE); + errx(EXIT_FAILURE, "Unknown value for suboption '%s': %s", + token[Style], value); } break; - - case WIDTH: - - if (value == NULL) { - fprintf(stderr, "Missing value for " - "suboption '%s'\n", token[WIDTH]); - exit(EXIT_FAILURE); + case Width: + if (!optionsParseIsString(value)) { + errx(EXIT_FAILURE, "Missing value for suboption '%s'", + token[Width]); } - opt.line_width = options_parse_required_number(value); + opt.lineWidth = optionsParseRequiredNumber(value); - if (opt.line_width <= 0 || opt.line_width > 8){ - fprintf(stderr, "Value of the range (1..8) for " - "suboption '%s': %d\n", token[WIDTH], opt.line_width); - exit(EXIT_FAILURE); + if (opt.lineWidth <= 0 || opt.lineWidth > 8) { + errx(EXIT_FAILURE, "Value of the range (1..8) for " + "suboption '%s': %d", token[Width], opt.lineWidth); } break; - - case COLOR: - - if (value == NULL || *value == '\0') { - fprintf(stderr, "Missing value for " - "suboption '%s'\n", token[COLOR]); - exit(EXIT_FAILURE); + case Color: + if (!optionsParseIsString(value)) { + errx(EXIT_FAILURE, "Missing value for suboption '%s'", + token[Color]); } - opt.line_color = strdup(value); - + opt.lineColor = strdup(value); break; - - case MODE: - - if (value == NULL || *value == '\0') { - fprintf(stderr, "Missing value for " - "suboption '%s'\n", token[MODE]); - exit(EXIT_FAILURE); + case Mode: + if (!optionsParseIsString(value)) { + errx(EXIT_FAILURE, "Missing value for suboption '%s'", + token[Mode]); } - bool isValidMode = (bool)(0 == strncmp(value, LINE_MODE_CLASSIC, LINE_MODE_CLASSIC_LEN) ); + bool isValidMode = !strncmp(value, LINE_MODE_S_CLASSIC, LINE_MODE_L_CLASSIC); - isValidMode = isValidMode || (bool)(0 == strncmp(value, LINE_MODE_EDGE, LINE_MODE_EDGE_LEN)); + isValidMode = isValidMode || !strncmp(value, LINE_MODE_S_EDGE, LINE_MODE_L_EDGE); - if(isValidMode == false) { - fprintf(stderr, "Unknown value for " - "suboption '%s': %s\n", token[MODE], value); - exit(EXIT_FAILURE); + if (!isValidMode) { + errx(EXIT_FAILURE, "Unknown value for suboption '%s': %s", + token[Mode], value); } - opt.line_mode = strdup(value); - + opt.lineMode = strdup(value); + break; + case Opacity: + if (!optionsParseIsString(value)) { + errx(EXIT_FAILURE, "Missing value for suboption '%s'", + token[Opacity]); + } + opt.lineOpacity = optionsParseRequiredNumber(value); + break; + default: + errx(EXIT_FAILURE, "No match found for token: '%s'", value); break; + } + } /* while */ +} - case OPACITY: +static void optionsParseWindowClassName(const char* windowClassName) +{ + assert(windowClassName != NULL); - if (value == NULL) { - fprintf(stderr, "Missing value for " - "suboption '%s'\n", token[OPACITY]); - exit(EXIT_FAILURE); - } + if (windowClassName[0] != '\0') + opt.windowClassName = strndup(windowClassName, MAX_LEN_WINDOW_CLASS_NAME); +} - opt.line_opacity = options_parse_required_number(value); +static bool accessFileOk(const char* const pathName) +{ + errno = 0; + return (0 == access(pathName, W_OK)); +} - if (opt.line_opacity < 10 || opt.line_opacity > 100){ - fprintf(stderr, "Value of the range (10..100) for " - "suboption '%s': %d\n", token[OPACITY], opt.line_opacity); - exit(EXIT_FAILURE); - } - break; +static char* getPathOfStdout(void) +{ + char path[16] = {"/dev/stdout"}; + size_t const len = sizeof(path); - default: - fprintf(stderr, "No match found for token: '%s'\n", value); - exit(EXIT_FAILURE); - break; - } + if (!accessFileOk(path)) { - } /* while */ -} + snprintf(path, len, "/dev/fd/%d", STDOUT_FILENO); -static void options_parse_window_class_name(const char* window_class_name) -{ - assert(window_class_name != NULL); + if (!accessFileOk(path)) { + + snprintf(path, len, "/proc/self/fd/%d", STDOUT_FILENO); - if (window_class_name[0] != '\0' && - strlen(window_class_name) < MAX_LEN_WINDOW_CLASS_NAME) - { - opt.window_class_name = strdup(window_class_name); + if (!accessFileOk(path)) { + // We quit because imlib2 will fail later anyway. + err(EXIT_FAILURE, "access to stdout failed"); + } + } } + return strndup(path, len); } +void optionsParse(int argc, char** argv) +{ + static char stropts[] = "a:ofipbcd:e:hmq:s::t:uvzn:l:D:k::C:S:F:"; -static void -scrot_parse_option_array(int argc, char **argv) -{ - static char stropts[] = "a:ofpbcd:e:hmq:st:uv+:zn:l:D:kC:S:"; - - static struct option lopts[] = { - /* actions */ - {"help", 0, 0, 'h'}, /* okay */ - {"version", 0, 0, 'v'}, /* okay */ - {"count", 0, 0, 'c'}, - {"select", 0, 0, 's'}, - {"focused", 0, 0, 'u'}, - {"focussed", 0, 0, 'u'}, /* macquarie dictionary has both spellings */ - {"border", 0, 0, 'b'}, - {"multidisp", 0, 0, 'm'}, - {"silent", 0, 0, 'z'}, - {"pointer", 0, 0, 'p'}, - {"freeze", 0, 0, 'f'}, - {"overwrite", 0, 0, 'o'}, - {"stack", 0, 0,'k'}, - /* toggles */ - {"thumb", 1, 0, 't'}, - {"delay", 1, 0, 'd'}, - {"quality", 1, 0, 'q'}, - {"exec", 1, 0, 'e'}, - {"debug-level", 1, 0, '+'}, - {"autoselect", required_argument, 0, 'a'}, - {"display", required_argument, 0, 'D'}, - {"note", required_argument, 0, 'n'}, - {"line", required_argument, 0, 'l'}, - {"class", required_argument, 0, 'C'}, - {"script", required_argument, 0, 'S'}, - {0, 0, 0, 0} - }; - int optch = 0, cmdx = 0; - - /* Now to pass some optionarinos */ - while ((optch = getopt_long(argc, argv, stropts, lopts, &cmdx)) != - EOF) - { - switch (optch) - { + static struct option lopts[] = { + /* actions */ + { "help", no_argument, 0, 'h' }, + { "version", no_argument, 0, 'v' }, + { "count", no_argument, 0, 'c' }, + { "focused", no_argument, 0, 'u' }, + { "focussed", no_argument, 0, 'u' }, /* macquarie dictionary has both spellings */ + { "border", no_argument, 0, 'b' }, + { "multidisp", no_argument, 0, 'm' }, + { "silent", no_argument, 0, 'z' }, + { "pointer", no_argument, 0, 'p' }, + { "ignorekeyboard", no_argument, 0, 'i' }, + { "freeze", no_argument, 0, 'f' }, + { "overwrite", no_argument, 0, 'o' }, + /* toggles */ + { "stack", optional_argument, 0, 'k' }, + { "select", optional_argument, 0, 's' }, + { "thumb", required_argument, 0, 't' }, + { "delay", required_argument, 0, 'd' }, + { "quality", required_argument, 0, 'q' }, + { "exec", required_argument, 0, 'e' }, + { "autoselect", required_argument, 0, 'a' }, + { "display", required_argument, 0, 'D' }, + { "note", required_argument, 0, 'n' }, + { "line", required_argument, 0, 'l' }, + { "class", required_argument, 0, 'C' }, + { "script", required_argument, 0, 'S' }, + { "file", required_argument, 0, 'F' }, + { 0, 0, 0, 0 } + }; + int optch = 0, cmdx = 0; + + /* Now to pass some optionarinos */ + while ((optch = getopt_long(argc, argv, stropts, lopts, &cmdx)) != EOF) { + switch (optch) { case 0: - break; + break; case 'h': - show_usage(); - break; + showUsage(); + break; case 'v': - show_version(); - break; + showVersion(); + break; case 'b': - opt.border = 1; - break; + opt.border = 1; + break; case 'd': - opt.delay = options_parse_required_number(optarg); - break; + opt.delay = nonNegativeNumber(optionsParseRequiredNumber(optarg)); + break; case 'e': - opt.exec = strdup(optarg); - break; + opt.exec = strdup(optarg); + break; case 'm': - opt.multidisp = 1; - break; + opt.multidisp = 1; + break; case 'q': - opt.quality = options_parse_required_number(optarg); - break; + opt.quality = optionsParseRequiredNumber(optarg); + break; case 's': - opt.select = 1; - break; + optionsParseSelection(optarg); + break; case 'u': - opt.focused = 1; - break; - case '+': - opt.debug_level = options_parse_required_number(optarg); - break; + opt.focused = 1; + break; case 'c': - opt.countdown = 1; - break; + opt.countdown = 1; + break; case 't': - options_parse_thumbnail(optarg); - break; + optionsParseThumbnail(optarg); + break; case 'z': - opt.silent = 1; - break; + opt.silent = 1; + break; case 'p': - opt.pointer = 1; - break; + opt.pointer = 1; + break; + case 'i': + opt.ignoreKeyboard = 1; + break; case 'f': - opt.freeze = 1; - break; + opt.freeze = 1; + break; case 'o': - opt.overwrite = 1; - break; + opt.overwrite = 1; + break; case 'a': - options_parse_autoselect(optarg); - break; + optionsParseAutoselect(optarg); + break; case 'D': - options_parse_display(optarg); - break; + optionsParseDisplay(optarg); + break; case 'n': - options_parse_note(optarg); - break; + optionsParseNote(optarg); + break; case 'l': - options_parse_line(optarg); - break; + optionsParseLine(optarg); + break; case 'k': - opt.stack = 1; - break; + opt.stack = 1; + optionsParseStack(optarg); + break; case 'C': - options_parse_window_class_name(optarg); - break; + optionsParseWindowClassName(optarg); + break; case 'S': - opt.script = strdup(optarg); - break; + opt.script = strdup(optarg); + break; + case 'F': + optionsParseFileName(optarg); + break; case '?': - exit(EXIT_FAILURE); + exit(EXIT_FAILURE); default: - break; - } - } - - /* Now the leftovers, which must be files */ - while (optind < argc) - { - /* If recursive is NOT set, but the only argument is a directory - name, we grab all the files in there, but not subdirs */ - if (!opt.output_file) - { - opt.output_file = argv[optind++]; + break; + } + } - if ( strlen(opt.output_file) > 256 ) { - printf("output filename too long.\n"); - exit(EXIT_FAILURE); - } + /* Now the leftovers, which must be files */ + while (optind < argc) { + /* If recursive is NOT set, but the only argument is a directory + name, we grab all the files in there, but not subdirs */ + if (!opt.outputFile) { + optionsParseFileName(argv[optind++]); + + bool const redirectChar = ( opt.outputFile[0] == '-' + && opt.outputFile[1] == '\0'); + if (redirectChar) { + free(opt.outputFile); + opt.outputFile = getPathOfStdout(); + opt.overwrite = 1; + opt.thumb = 0; + } + } else + warnx("unrecognised option %s", argv[optind++]); + } + + /* So that we can safely be called again */ + optind = 1; +} + +char* optionsNameThumbnail(const char* name) +{ + const char* const thumbSuffix = "-thumb"; + const size_t thumbSuffixLength = 7; + const size_t newNameLength = strlen(name) + thumbSuffixLength; + char* newName = calloc(1, newNameLength); + + if (!newName) + err(EXIT_FAILURE, "Unable to allocate thumbnail"); + + const char* const extension = strrchr(name, '.'); + + if (extension) { + /* We add one so length includes '\0'*/ + const ptrdiff_t nameLength = (extension - name) + 1; + strlcpy(newName, name, nameLength); + strlcat(newName, thumbSuffix, newNameLength); + strlcat(newName, extension, newNameLength); + } else + snprintf(newName, newNameLength, "%s%s", name, thumbSuffix); + + return newName; +} + +void optionsParseAutoselect(char* optarg) +{ + char* token; + const char tokenDelimiter[2] = ","; + int dimensions[4]; + int i = 0; + + if (strchr(optarg, ',')) { /* geometry dimensions must be in format x,y,w,h */ + dimensions[i++] = optionsParseRequiredNumber(strtok(optarg, tokenDelimiter)); + while ((token = strtok(NULL, tokenDelimiter))) + dimensions[i++] = optionsParseRequiredNumber(token); + opt.autoselect = 1; + opt.autoselectX = dimensions[0]; + opt.autoselectY = dimensions[1]; + opt.autoselectW = dimensions[2]; + opt.autoselectH = dimensions[3]; + + if (i != 4) + errx(EXIT_FAILURE, "option 'autoselect' require 4 arguments"); + } else + errx(EXIT_FAILURE, "invalid format for option -- 'autoselect'"); +} + +void optionsParseDisplay(char* optarg) +{ + opt.display = strndup(optarg, MAX_DISPLAY_NAME); + if (!opt.display) + err(EXIT_FAILURE, "Unable to allocate display"); +} + +void optionsParseThumbnail(char* optarg) +{ + char* token; + + if (strchr(optarg, 'x')) { /* We want to specify the geometry */ + token = strtok(optarg, "x"); + opt.thumbWidth = optionsParseRequiredNumber(token); + token = strtok(NULL, "x"); + if (token) { + opt.thumbWidth = optionsParseRequiredNumber(optarg); + opt.thumbHeight = optionsParseRequiredNumber(token); + + if (opt.thumbWidth < 0) + opt.thumbWidth = 1; + if (opt.thumbHeight < 0) + opt.thumbHeight = 1; + + if (!opt.thumbWidth && !opt.thumbHeight) + opt.thumb = 0; + else + opt.thumb = 1; + } + } else { + opt.thumb = optionsParseRequiredNumber(optarg); + if (opt.thumb < 1) + opt.thumb = 1; + else if (opt.thumb > 100) + opt.thumb = 100; + } +} - if (opt.thumb) - opt.thumb_file = name_thumbnail(opt.output_file); - } - else - fprintf(stderr, "unrecognised option %s\n", argv[optind++]); - } - - /* So that we can safely be called again */ - optind = 1; -} - -char * -name_thumbnail(char *name) -{ - size_t length = 0; - char *new_title; - char *dot_pos; - size_t diff = 0; - - length = strlen(name) + 7; - new_title = malloc(length); - if (! new_title) { - fprintf(stderr, "Unable to allocate thumbnail: %s", strerror(errno)); - exit(EXIT_FAILURE); - } - - dot_pos = strrchr(name, '.'); - if (dot_pos) - { - diff = (dot_pos - name) / sizeof(char); - - strncpy(new_title, name, diff); - strcat(new_title, "-thumb"); - strcat(new_title, dot_pos); - } - else { - snprintf(new_title, length, "%s-thumb", name); - } - - return new_title; -} - -void -options_parse_autoselect(char *optarg) -{ - char *tok; - const char tokdelim[2] = ","; - int dimensions[4]; - int i=0; - - if (strchr(optarg, ',')) /* geometry dimensions must be in format x,y,w,h */ - { - dimensions[i++] = options_parse_required_number(strtok(optarg, tokdelim)); - while ((tok = strtok(NULL, tokdelim)) ) - dimensions[i++] = options_parse_required_number(tok); - opt.autoselect=1; - opt.autoselect_x=dimensions[0]; - opt.autoselect_y=dimensions[1]; - opt.autoselect_w=dimensions[2]; - opt.autoselect_h=dimensions[3]; - - if (i != 4) - { - fprintf(stderr, "option 'autoselect' require 4 arguments\n"); - exit(EXIT_FAILURE); - } - } - else { - fprintf(stderr, "invalid format for option -- 'autoselect'\n"); - exit(EXIT_FAILURE); - } - - -} - -void -options_parse_display(char *optarg) -{ -#if SCROT_HAVE_STRNDUP - opt.display = strndup(optarg, 256); -#else - size_t length = 0; - char *new_display; - - length = strlen(optarg) + 1; - if (length > 256) { - length = 256; - } - new_display = malloc(length); - if (! new_display) { - fprintf(stderr, "Unable to allocate display: %s", strerror(errno)); - exit(EXIT_FAILURE); - } - strncpy(new_display, optarg, length); - opt.display=new_display; -#endif -} - -void -options_parse_thumbnail(char *optarg) -{ - char *tok; - - if (strchr(optarg, 'x')) /* We want to specify the geometry */ - { - tok = strtok(optarg, "x"); - opt.thumb_width = options_parse_required_number(tok); - tok = strtok(NULL, "x"); - if (tok) - { - opt.thumb_width = options_parse_required_number(optarg); - opt.thumb_height = options_parse_required_number(tok); - - if (opt.thumb_width < 0) - opt.thumb_width = 1; - if (opt.thumb_height < 0) - opt.thumb_height = 1; - - if (!opt.thumb_width && !opt.thumb_height) - opt.thumb = 0; - else - opt.thumb = 1; - } - } - else - { - opt.thumb = options_parse_required_number(optarg); - if (opt.thumb < 1) - opt.thumb = 1; - else if (opt.thumb > 100) - opt.thumb = 100; - } -} - -void options_parse_note(char *optarg) -{ - opt.note = strdup(optarg); - - if (opt.note == NULL) return; - - if (opt.note[0] == '\0') { - fprintf(stderr, "Required arguments for --note."); - exit(EXIT_FAILURE); - } +void optionsParseFileName(const char* optarg) +{ + checkMaxOutputFileName(optarg); + opt.outputFile = strdup(optarg); +} + +void optionsParseNote(char* optarg) +{ + opt.note = strdup(optarg); - scrot_note_new(opt.note); + if (!opt.note) + return; + + if (opt.note[0] == '\0') + errx(EXIT_FAILURE, "Required arguments for --note."); + + scrotNoteNew(opt.note); } /* @@ -501,121 +577,26 @@ 0 : It does not match 1 : If it matches */ -int options_cmp_window_class_name(const char* target_class_name) - { - assert(target_class_name != NULL); - assert(opt.window_class_name != NULL); - return !!(!strncmp(target_class_name, opt.window_class_name, MAX_LEN_WINDOW_CLASS_NAME - 1)); -} - - -void -show_version(void) -{ - printf(SCROT_PACKAGE " version " SCROT_VERSION "\n"); - exit(0); -} - -void -show_mini_usage(void) -{ - printf("Usage : " SCROT_PACKAGE " [OPTIONS]... FILE\nUse " SCROT_PACKAGE - " --help for detailed usage information\n"); - exit(0); -} - - -void -show_usage(void) -{ - fprintf(stdout, - "Usage : " SCROT_PACKAGE " [OPTIONS]... [FILE]\n" - " Where FILE is the target file for the screenshot.\n" - " If FILE is not specified, a date-stamped file will be dropped in the\n" - " current directory.\n" " See man " SCROT_PACKAGE " for more details\n" - " -h, --help display this help and exit\n" - " -v, --version output version information and exit\n" - " -D, --display Set DISPLAY target other than current\n" - " -a, --autoselect non-interactively choose a rectangle of x,y,w,h\n" - " -b, --border When selecting a window, grab wm border too\n" - " Use with --select to raise the focus of the window.\n" - " -c, --count show a countdown before taking the shot\n" - " -d, --delay NUM wait NUM seconds before taking a shot\n" - " -e, --exec APP run APP on the resulting screenshot\n" - " -q, --quality NUM Image quality (1-100) high value means\n" - " high size, low compression. Default: 75.\n" - " For lossless compression formats, like png,\n" - " low quality means high compression.\n" - " -m, --multidisp For multiple heads, grab shot from each\n" - " and join them together.\n" - " -s, --select interactively choose a window or rectangle\n" - " with the mouse (use the arrow keys to resize)\n" - " -u, --focused use the currently focused window\n" - " -t, --thumb NUM generate thumbnail too. NUM is the percentage\n" - " of the original size for the thumbnail to be,\n" - " or the geometry in percent, e.g. 50x60 or 80x20.\n" - " -z, --silent Prevent beeping\n" - " -p, --pointer Capture the mouse pointer.\n" - " -f, --freeze Freeze the screen when the selection is used: --select\n" - " -o, --overwrite By default " SCROT_PACKAGE " does not overwrite the files, use this option to allow it.\n" - " -l, --line Indicates the style of the line when the selection is used: --select\n" - " See SELECTION STYLE\n" - " -n, --note Draw a text note.\n" - " See NOTE FORMAT\n" - " -k, --stack Capture stack/overlapped windows and join them together.\n" - " A running Composite Manager is needed.\n" - " -C, --class NAME Window class name. Associative with options: -k\n" - " -S, --script CMD Imlib2 script commands\n" - "\n" " SPECIAL STRINGS\n" - " Both the --exec and filename parameters can take format specifiers\n" - " that are expanded by " SCROT_PACKAGE " when encountered.\n" - " There are two types of format specifier. Characters preceded by a '%%'\n" - " are interpreted by strftime(2). See man strftime for examples.\n" - " These options may be used to refer to the current date and time.\n" - " The second kind are internal to " SCROT_PACKAGE - " and are prefixed by '$'\n" - " The following specifiers are recognised:\n" - " $a hostname\n" - " $f image path/filename (ignored when used in the filename)\n" - " $m thumbnail path/filename\n" - " $n image name (ignored when used in the filename)\n" - " $s image size (bytes) (ignored when used in the filename)\n" - " $p image pixel size\n" - " $w image width\n" - " $h image height\n" - " $t image format (ignored when used in the filename)\n" - " $$ prints a literal '$'\n" - " \\n prints a newline (ignored when used in the filename)\n" - " Example:\n" " " SCROT_PACKAGE - " '%%Y-%%m-%%d_$wx$h_scrot.png' -e 'mv $f ~/images/shots/'\n" - " Creates a file called something like 2000-10-30_2560x1024_scrot.png\n" - " and moves it to your images directory.\n" "\n" - "\n" " SELECTION STYLE\n" - " When using --select you can indicate the style of the line with --line.\n" - " The following specifiers are recognised:\n" - " style=(solid,dash),width=(range 1 to 8),color=\"value\",\n" - " opacity=(range 10 to 100),mode=(edge,classic)\n" - " The default style is:\n" - " mode=classic,style=solid,width=1,opacity=100\n" - " Mode 'edge' ignore : style, --freeze\n" - " Mode 'classic' ignore : opacity\n\n" - " The 'opacity' specifier is only effective if a Composite Manager is running.\n\n" - " For the color you can use a name or a hexadecimal value.\n" - " color=\"red\" or color=\"#ff0000\"\n" - " Example:\n" " " SCROT_PACKAGE - " --line style=dash,width=3,color=\"red\" --select\n\n" - "\n" " NOTE FORMAT\n" - " The following specifiers are recognised for the option --note\n" - " -f 'FontName/size'\n" - " -t 'text'\n" - " -x position (optional)\n" - " -y position (optional)\n" - " -c color(RGBA) (optional)\n" - " -a angle (optional)\n" - " Example:\n" " " SCROT_PACKAGE - " --note \"-f '/usr/share/fonts/TTF/DroidSans-Bold/40' -x 10 -y 20 -c 255,0,0,255 -t 'Hi'\"\n\n" - "This program is free software see the file COPYING for licensing info.\n" - "Copyright Tom Gilbert 2000\n" - "Email bugs to \n"); - exit(0); +int optionsCompareWindowClassName(const char* targetClassName) +{ + assert(targetClassName != NULL); + assert(opt.windowClassName != NULL); + return !!(!strncmp(targetClassName, opt.windowClassName, MAX_LEN_WINDOW_CLASS_NAME - 1)); +} + +void showVersion(void) +{ + printf(SCROT_PACKAGE " version " SCROT_VERSION "\n"); + exit(0); +} + +void showUsage(void) +{ + fputs(/* Check that everything lines up after any changes. */ + "usage: " SCROT_PACKAGE " [-bcfhikmopsuvz] [-a X,Y,W,H] [-C NAME] [-D DISPLAY]" + "\n" + " [-F FILE] [-d SEC] [-e CMD] [-l STYLE] [-n OPTS] [-q NUM] [-S CMD] \n" + " [-t NUM | GEOM] [FILE]\n", + stdout); + exit(0); } diff -Nru scrot-1.6/src/options.h scrot-1.7/src/options.h --- scrot-1.6/src/options.h 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/src/options.h 2021-11-10 02:08:36.000000000 +0000 @@ -6,8 +6,11 @@ Copyright 2009 James Cameron Copyright 2010 Ibragimov Rinat Copyright 2017 Stoney Sauce -Copyright 2019-2021 Daniel T. Borelli +Copyright 2019-2021 Daniel T. Borelli Copyright 2020 Sean Brennan +Copyright 2021 IFo Hancroft +Copyright 2021 Peter Wu +Copyright 2021 Wilson Smith <01wsmith+gh@gmail.com> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -30,54 +33,63 @@ */ -#ifndef OPTIONS_H -#define OPTIONS_H +#include "structs.h" +#include "scrot_selection.h" -struct __scrotoptions -{ - int debug_level; - int delay; - int countdown; - int select; - int focused; - int quality; - int border; - int silent; - int multidisp; - int thumb; - int thumb_width; - int thumb_height; - int pointer; - int freeze; - int overwrite; - int line_style; - int line_width; - int line_opacity; - int stack; - char *line_color; - char *line_mode; - char *output_file; - char *thumb_file; - char *exec; - char *display; - char *note; - char *window_class_name; - char *script; - int autoselect; - int autoselect_x; - int autoselect_y; - int autoselect_h; - int autoselect_w; +#pragma once + +// General purpose enum +enum Direction { + // see main.c:stalkImageConcat(...) + HORIZONTAL, + VERTICAL, }; -void init_parse_options(int argc, char **argv); -char *name_thumbnail(char *name); -void options_parse_thumbnail(char *optarg); -void options_parse_autoselect(char *optarg); -void options_parse_display(char *optarg); -void options_parse_note(char *optarg); -int options_parse_required_number(char *str); -int options_cmp_window_class_name(const char* target_class_name); -extern scrotoptions opt; +struct __ScrotOptions { + int delay; + int countdown; + int focused; + int quality; + int border; + int silent; + int multidisp; + int thumb; + int thumbWidth; + int thumbHeight; + int pointer; + int ignoreKeyboard; + int freeze; + int overwrite; + int lineStyle; + int lineWidth; + int lineOpacity; + int stack; + enum Direction stackDirection; + char* lineColor; + char* lineMode; + char* outputFile; + char* thumbFile; + char* exec; + char* display; + char* note; + char* windowClassName; + char* script; + int autoselect; + int autoselectX; + int autoselectY; + int autoselectH; + int autoselectW; + SelectionMode selection; +}; -#endif +void optionsParse(int, char**); +char* optionsNameThumbnail(const char*); +void optionsParseFileName(const char*); +void optionsParseThumbnail(char*); +void optionsParseAutoselect(char*); +void optionsParseDisplay(char*); +void optionsParseNote(char*); +int optionsParseRequiredNumber(char const *); +int optionsCompareWindowClassName(const char*); +int optionsParseRequireRange(int, int, int); +extern ScrotOptions opt; diff -Nru scrot-1.6/src/scrot.h scrot-1.7/src/scrot.h --- scrot-1.6/src/scrot.h 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/src/scrot.h 2021-11-10 02:08:36.000000000 +0000 @@ -4,11 +4,12 @@ gilbertt@linuxbrit.co.uk, scrot_sucks@linuxbrit.co.uk> Copyright 2009 James Cameron -Copyright 2019-2020 Daniel T. Borelli +Copyright 2019-2021 Daniel T. Borelli Copyright 2020 Jeroen Roovers Copyright 2020 Hinigatsu Copyright 2021 Christopher R. Nelson Copyright 2021 Guilherme Janczak +Copyright 2021 Peter Wu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -31,92 +32,75 @@ */ -#ifndef SCROT_H -#define SCROT_H +#pragma once -#include -#include #include +#include #include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include #include -#include #include -#include -#include -#include -#include -#include +#include #include -#include -#include -#include +#include +#include -#include "scrot_config.h" -#include "structs.h" +#include "options.h" #include "note.h" +#include "scrot_config.h" #include "scrot_selection.h" #include "slist.h" +#include "structs.h" -#ifndef __GNUC__ -# define __attribute__(x) -#endif - -typedef void (*sighandler_t) (int); - -void show_usage(void); -void show_version(void); -void show_mini_usage(void); -void init_x_and_imlib(char *dispstr, int screen_num); -char *chop_file_from_full_path(char *str); -Imlib_Image scrot_grab_shot(void); -void scrot_exec_app(Imlib_Image image, struct tm *tm, - char *filename_im, char *filename_thumb); -void scrot_do_delay(void); -Imlib_Image scrot_sel_and_grab_image(void); -Imlib_Image scrot_grab_focused(void); -Imlib_Image scrot_grab_autoselect(void); -void scrot_sel_area(int *x, int *y, int *w, int *h); -void scrot_nice_clip(int *rx, int *ry, int *rw, int *rh); -int scrot_get_geometry(Window target, int *rx, int *ry, int *rw, int *rh); -int scrot_match_window_class_name(Window target); -Window scrot_get_window(Display *display,Window window,int x,int y); -Window scrot_get_client_window(Display * display, Window target); -Window scrot_find_window_by_property(Display * display, const Window window, - const Atom property); -char *im_printf(char *str, struct tm *tm, - char *filename_im, char *filename_thumb, - Imlib_Image im); -Imlib_Image scrot_grab_shot_multi(void); -Imlib_Image scrot_grab_stack_windows(void); -Imlib_Image stalk_image_concat(Scrot_Imlib_List *images); +typedef void (*signalHandler)(int); -void scrot_grab_mouse_pointer(const Imlib_Image image, - const int ix_off, const int iy_off); +void showUsage(void); +void showVersion(void); +void initXAndImlib(char*, int); +Imlib_Image scrotGrabShot(void); +void scrotExecApp(Imlib_Image, struct tm*, char*, char*); +void scrotDoDelay(void); +Imlib_Image scrotGrabFocused(void); +Imlib_Image scrotGrabAutoselect(void); +void scrotSelArea(int*, int*, int*, int*); +void scrotNiceClip(int*, int*, int*, int*); +int scrotGetGeometry(Window, int*, int*, int*, int*); +int scrotMatchWindowClassName(Window); +Window scrotGetWindow(Display*, Window, int, int); +Window scrotGetClientWindow(Display*, Window); +Window scrotFindWindowByProperty(Display*, const Window, const Atom); +char* imPrintf(char*, struct tm*, char*, char*, Imlib_Image); +Imlib_Image scrotGrabShotMulti(void); +Imlib_Image scrotGrabStackWindows(void); +Imlib_Image stalkImageConcat(ScrotList*, enum Direction const); -void scrot_check_if_overwrite_file(char **filename); -size_t scrot_have_file_extension(char const *filename, char **ext); +void scrotGrabMousePointer(const Imlib_Image, const int, const int); + +void scrotCheckIfOverwriteFile(char**); +size_t scrotHaveFileExtension(char const*, char**); /* Imlib stuff */ -extern Display *disp; -extern Visual *vis; +extern Display* disp; +extern Visual* vis; extern Colormap cm; extern int depth; /* Thumbnail sizes */ extern Window root; -extern Screen *scr; - -#endif +extern Screen* scr; diff -Nru scrot-1.6/src/scrot_selection.c scrot-1.7/src/scrot_selection.c --- scrot-1.6/src/scrot_selection.c 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/src/scrot_selection.c 2021-11-10 02:08:36.000000000 +0000 @@ -1,7 +1,9 @@ /* scrot_selection.c -Copyright 2020-2021 Daniel T. Borelli +Copyright 2020-2021 Daniel T. Borelli Copyright 2021 Martin C +Copyright 2021 Peter Wu +Copyright 2021 Wilson Smith <01wsmith+gh@gmail.com> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -33,95 +35,104 @@ #include "selection_classic.h" #include "selection_edge.h" -struct selection_t** selection_get(void) +struct Selection** selectionGet(void) { - static struct selection_t* sel = NULL; + static struct Selection* sel = NULL; return &sel; } -static void selection_allocate(void) +static void selectionAllocate(void) { - struct selection_t** sel = selection_get(); - *sel = calloc(1, sizeof(struct selection_t)); + struct Selection** sel = selectionGet(); + *sel = calloc(1, sizeof(**sel)); } -static void selection_deallocate(void) +static void selectionDeallocate(void) { - struct selection_t** sel = selection_get(); + struct Selection** sel = selectionGet(); free(*sel); *sel = NULL; } -static void create_cursors(void) +static void createCursors(void) { - struct selection_t *const sel = *selection_get(); + struct Selection* const sel = *selectionGet(); assert(sel != NULL); - sel->cur_cross = XCreateFontCursor(disp, XC_cross); - sel->cur_angle_ne = XCreateFontCursor(disp, XC_ur_angle); - sel->cur_angle_nw = XCreateFontCursor(disp, XC_ul_angle); - sel->cur_angle_se = XCreateFontCursor(disp, XC_lr_angle); - sel->cur_angle_sw = XCreateFontCursor(disp, XC_ll_angle); + if (opt.selection.mode == SELECTION_MODE_CAPTURE) + sel->curCross = XCreateFontCursor(disp, XC_cross); + else if (opt.selection.mode == SELECTION_MODE_HIDE) + sel->curCross = XCreateFontCursor(disp, XC_spraycan); + else if (opt.selection.mode == SELECTION_MODE_BLUR) + sel->curCross = XCreateFontCursor(disp, XC_box_spiral); + else // SELECTION_MODE_HOLE + sel->curCross = XCreateFontCursor(disp, XC_target); + sel->curAngleNE = XCreateFontCursor(disp, XC_ur_angle); + sel->curAngleNW = XCreateFontCursor(disp, XC_ul_angle); + sel->curAngleSE = XCreateFontCursor(disp, XC_lr_angle); + sel->curAngleSW = XCreateFontCursor(disp, XC_ll_angle); } -static void free_cursors(void) +static void freeCursors(void) { - struct selection_t *const sel = *selection_get(); + struct Selection* const sel = *selectionGet(); assert(sel != NULL); - XFreeCursor(disp, sel->cur_cross); - XFreeCursor(disp, sel->cur_angle_ne); - XFreeCursor(disp, sel->cur_angle_nw); - XFreeCursor(disp, sel->cur_angle_se); - XFreeCursor(disp, sel->cur_angle_sw); + XFreeCursor(disp, sel->curCross); + XFreeCursor(disp, sel->curAngleNE); + XFreeCursor(disp, sel->curAngleNW); + XFreeCursor(disp, sel->curAngleSE); + XFreeCursor(disp, sel->curAngleSW); } -void selection_calculate_rect(int x0, int y0, int x1, int y1) +void selectionCalculateRect(int x0, int y0, int x1, int y1) { - struct selection_rect_t* const rect = scrot_selection_get_rect(); + struct SelectionRect* const rect = scrotSelectionGetRect(); rect->x = x0; rect->y = y0; rect->w = x1 - x0; rect->h = y1 - y0; - if (rect->w == 0) rect->w++; + if (rect->w == 0) + rect->w++; - if (rect->h == 0) rect->h++; + if (rect->h == 0) + rect->h++; if (rect->w < 0) { - rect->x += rect->w; - rect->w = 0 - rect->w; + rect->x += rect->w; + rect->w = 0 - rect->w; } if (rect->h < 0) { - rect->y += rect->h; - rect->h = 0 - rect->h; + rect->y += rect->h; + rect->h = 0 - rect->h; } } -void scrot_selection_create(void) +void scrotSelectionCreate(void) { - selection_allocate(); + selectionAllocate(); - struct selection_t *const sel = *selection_get(); + struct Selection* const sel = *selectionGet(); assert(sel != NULL); - create_cursors(); + createCursors(); - if (0 == strncmp(opt.line_mode, LINE_MODE_CLASSIC, LINE_MODE_CLASSIC_LEN)) { - sel->create = selection_classic_create; - sel->draw = selection_classic_draw; - sel->motion_draw = selection_classic_motion_draw; - sel->destroy = selection_classic_destroy; - } else if (0 == strncmp(opt.line_mode, LINE_MODE_EDGE, LINE_MODE_EDGE_LEN)) { - sel->create = selection_edge_create; - sel->draw = selection_edge_draw; - sel->motion_draw = selection_edge_motion_draw; - sel->destroy = selection_edge_destroy; + if (!strncmp(opt.lineMode, LINE_MODE_S_CLASSIC, LINE_MODE_L_CLASSIC)) { + sel->create = selectionClassicCreate; + sel->draw = selectionClassicDraw; + sel->motionDraw = selectionClassicMotionDraw; + sel->destroy = selectionClassicDestroy; + } else if (!strncmp(opt.lineMode, LINE_MODE_S_EDGE, LINE_MODE_L_EDGE)) { + sel->create = selectionEdgeCreate; + sel->draw = selectionEdgeDraw; + sel->motionDraw = selectionEdgeMotionDraw; + sel->destroy = selectionEdgeDestroy; } else { // It never happened, fix the options.c file assert(0); @@ -131,53 +142,387 @@ unsigned int const EVENT_MASK = ButtonMotionMask | ButtonPressMask | ButtonReleaseMask; - if ((XGrabPointer (disp, root, False, EVENT_MASK, GrabModeAsync, - GrabModeAsync, root, sel->cur_cross, CurrentTime) != GrabSuccess)) { - fprintf(stderr, "couldn't grab pointer\n"); - scrot_selection_destroy(); - exit(EXIT_FAILURE); + if ((XGrabPointer(disp, root, False, EVENT_MASK, GrabModeAsync, + GrabModeAsync, root, sel->curCross, CurrentTime) + != GrabSuccess)) { + scrotSelectionDestroy(); + errx(EXIT_FAILURE, "couldn't grab pointer"); } } - -void scrot_selection_destroy(void) +void scrotSelectionDestroy(void) { - struct selection_t *const sel = *selection_get(); + struct Selection* const sel = *selectionGet(); XUngrabPointer(disp, CurrentTime); - free_cursors(); + freeCursors(); XSync(disp, True); sel->destroy(); - selection_deallocate(); + selectionDeallocate(); } - -void scrot_selection_draw(void) +void scrotSelectionDraw(void) { - struct selection_t const *const sel = *selection_get(); + struct Selection const* const sel = *selectionGet(); sel->draw(); } - -void scrot_selection_motion_draw(int x0, int y0, int x1, int y1) +void scrotSelectionMotionDraw(int x0, int y0, int x1, int y1) { - struct selection_t const *const sel = *selection_get(); + struct Selection const* const sel = *selectionGet(); unsigned int const EVENT_MASK = ButtonMotionMask | ButtonReleaseMask; Cursor cursor = None; - if (x1 > x0 && y1 > y0) { - cursor = sel->cur_angle_se; - } else if (x1 > x0) { - cursor = sel->cur_angle_ne; - } else if (y1 > y0) { - cursor = sel->cur_angle_sw; + if (x1 > x0 && y1 > y0) + cursor = sel->curAngleSE; + else if (x1 > x0) + cursor = sel->curAngleNE; + else if (y1 > y0) + cursor = sel->curAngleSW; + else + cursor = sel->curAngleNW; + XChangeActivePointerGrab(disp, EVENT_MASK, cursor, CurrentTime); + sel->motionDraw(x0, y0, x1, y1); +} + +struct SelectionRect* scrotSelectionGetRect(void) +{ + return &(*selectionGet())->rect; +} + +Status scrotSelectionCreateNamedColor(char const* nameColor, XColor* color) +{ + assert(nameColor != NULL); + assert(color != NULL); + + return XAllocNamedColor(disp, XDefaultColormap(disp, DefaultScreen(disp)), + nameColor, color, &(XColor) {}); +} + +void scrotSelectionGetLineColor(XColor* color) +{ + scrotSelectionSetDefaultColorLine(); + + Status const ret = scrotSelectionCreateNamedColor(opt.lineColor, color); + + if (!ret) { + scrotSelectionDestroy(); + errx(EXIT_FAILURE, "Error allocate color:%s", strerror(BadColor)); + } +} + +void scrotSelectionSetDefaultColorLine(void) +{ + if (!opt.lineColor) + opt.lineColor = "gray"; +} + +bool scrotSelectionGetUserSel(struct SelectionRect* selectionRect) +{ + static int xfd = 0; + static int fdSize = 0; + XEvent ev; + fd_set fdSet; + int count = 0, done = 0; + int rx = 0, ry = 0, rw = 0, rh = 0, isButtonPressed = 0; + Window target = None; + Status ret; + + scrotSelectionCreate(); + + xfd = ConnectionNumber(disp); + fdSize = xfd + 1; + + ret = XGrabKeyboard(disp, root, False, GrabModeAsync, GrabModeAsync, CurrentTime); + if (ret == AlreadyGrabbed) { + int attempts = 20; + struct timespec delay = { 0, 50 * 1000L * 1000L }; + do { + nanosleep(&delay, NULL); + ret = XGrabKeyboard(disp, root, False, GrabModeAsync, GrabModeAsync, CurrentTime); + } while (--attempts > 0 && ret == AlreadyGrabbed); + } + if (ret != GrabSuccess) { + scrotSelectionDestroy(); + errx(EXIT_FAILURE, "failed to grab keyboard"); + } + + while (1) { + /* Handle events here */ + while (!done && XPending(disp)) { + XNextEvent(disp, &ev); + switch (ev.type) { + case MotionNotify: + if (isButtonPressed) + scrotSelectionMotionDraw(rx, ry, ev.xbutton.x, ev.xbutton.y); + break; + case ButtonPress: + isButtonPressed = 1; + rx = ev.xbutton.x; + ry = ev.xbutton.y; + target = scrotGetWindow(disp, ev.xbutton.subwindow, ev.xbutton.x, ev.xbutton.y); + if (target == None) + target = root; + break; + case ButtonRelease: + done = 1; + break; + case KeyPress: + { + KeySym* keysym = NULL; + int keycode; /*dummy*/ + + keysym = XGetKeyboardMapping(disp, ev.xkey.keycode, 1, &keycode); + + if (!keysym) + break; + + if (!isButtonPressed) { + key_abort_shot: + if (!opt.ignoreKeyboard || *keysym == XK_Escape) { + warnx("Key was pressed, aborting shot"); + done = 2; + } + XFree(keysym); + break; + } + + switch (*keysym) { + case XK_Right: + if (++rx > scr->width) + rx = scr->width; + break; + case XK_Left: + if (--rx < 0) + rx = 0; + break; + case XK_Down: + if (++ry > scr->height) + ry = scr->height; + break; + case XK_Up: + if (--ry < 0) + ry = 0; + break; + default: + goto key_abort_shot; + } + XFree(keysym); + scrotSelectionMotionDraw(rx, ry, ev.xbutton.x, ev.xbutton.y); + break; + } + case KeyRelease: + /* ignore */ + break; + default: + break; + } + } + if (done) + break; + + /* now block some */ + FD_ZERO(&fdSet); + FD_SET(xfd, &fdSet); + errno = 0; + count = select(fdSize, &fdSet, NULL, NULL, NULL); + if ((count < 0) + && ((errno == ENOMEM) || (errno == EINVAL) || (errno == EBADF))) { + scrotSelectionDestroy(); + errx(EXIT_FAILURE, "Connection to X display lost"); + } + } + scrotSelectionDraw(); + + XUngrabKeyboard(disp, CurrentTime); + + bool const isAreaSelect = (scrotSelectionGetRect()->w > 5); + + scrotSelectionDestroy(); + + if (done == 2) + return false; + + if (isAreaSelect) { + /* If a rect has been drawn, it's an area selection */ + rw = ev.xbutton.x - rx; + rh = ev.xbutton.y - ry; + + if ((ev.xbutton.x + 1) == WidthOfScreen(scr)) + ++rw; + + if ((ev.xbutton.y + 1) == HeightOfScreen(scr)) + ++rh; + + if (rw < 0) { + rx += rw; + rw = 0 - rw; + } + + if (rh < 0) { + ry += rh; + rh = 0 - rh; + } + + // Not record pointer if there is a selection area because it is busy on that, + // unless the delay option is used. + if (opt.delay == 0) + opt.pointer = 0; } else { - cursor = sel->cur_angle_nw; + /* else it's a window click */ + if (!scrotGetGeometry(target, &rx, &ry, &rw, &rh)) + return false; } - XChangeActivePointerGrab(disp, EVENT_MASK, cursor, CurrentTime); - sel->motion_draw(x0, y0, x1, y1); + scrotNiceClip(&rx, &ry, &rw, &rh); + + if (!opt.silent) + XBell(disp, 0); + + selectionRect->x = rx; + selectionRect->y = ry; + selectionRect->w = rw; + selectionRect->h = rh; + return true; +} + +static void changeImageOpacity(Imlib_Image image, int const opacity) +{ +#define PIXEL_ARGB(a, r, g, b) ((a) << 24) | ((r) << 16) | ((g) << 8) | (b) +#define PIXEL_A(argb) (((argb) >> 24) & 0xff) +#define PIXEL_R(argb) (((argb) >> 16) & 0xff) +#define PIXEL_G(argb) (((argb) >> 8) & 0xff) +#define PIXEL_B(argb) (((argb) ) & 0xff) + + imlib_context_set_image(image); + int const w = imlib_image_get_width(); + int const h = imlib_image_get_height(); + + DATA32* data = imlib_image_get_data(); + DATA32* end = data + (h * w); + + for (DATA32* pixel = data; pixel != end; ++pixel) { + DATA8 const a = PIXEL_A(*pixel) * opacity / 255; + DATA8 const r = PIXEL_R(*pixel); + DATA8 const g = PIXEL_G(*pixel); + DATA8 const b = PIXEL_B(*pixel); + *pixel = (DATA32)PIXEL_ARGB(a, r, g, b); + } + + imlib_image_put_back_data(data); +} + +static Imlib_Image loadImage(char const* const fileName, int const opacity) +{ + Imlib_Image image = imlib_load_image(fileName); + + if (!image) { + errx(EXIT_FAILURE, "option --select: Failed to load image:%s", + fileName); + } + + imlib_context_set_image(image); + + if (imlib_image_has_alpha() == 0) { + warnx("Warning, ignoring the opacity parameter because the image '%s'" + " has no alpha channel, it will be drawn fully opaque.", fileName); + return image; + } + + if (opacity == 255) { + // Do nothing if a totally opaque image is expected. + return image; + } + + changeImageOpacity(image, opacity); + + return image; } -struct selection_rect_t* scrot_selection_get_rect(void) +Imlib_Image scrotSelectionSelectMode(void) { - return &(*selection_get())->rect; + struct SelectionRect rect0, rect1; + + unsigned int const oldMode = opt.selection.mode; + + opt.selection.mode = SELECTION_MODE_CAPTURE; + + if (!scrotSelectionGetUserSel(&rect0)) + return NULL; + + opt.selection.mode = oldMode; + + if (opt.selection.mode & SELECTION_MODE_NOT_CAPTURE) + if (!scrotSelectionGetUserSel(&rect1)) + return NULL; + + scrotDoDelay(); + + Imlib_Image capture = imlib_create_image_from_drawable(0, rect0.x, rect0.y, + rect0.w, rect0.h, 1); + + if (opt.pointer) + scrotGrabMousePointer(capture, rect0.x, rect0.y); + + if (opt.selection.mode == SELECTION_MODE_CAPTURE) + return capture; + + XColor color; + scrotSelectionGetLineColor(&color); + + int const x = rect1.x - rect0.x; + int const y = rect1.y - rect0.y; + int const opacity = optionsParseRequireRange(opt.lineOpacity, + SELECTION_OPACITY_MIN, SELECTION_OPACITY_MAX); + + imlib_context_set_image(capture); + + switch(opt.selection.mode) { + case SELECTION_MODE_HOLE: + if (opacity > 0) { + Imlib_Image hole = imlib_clone_image(); + imlib_context_set_color(color.red, color.green, color.blue, opacity); + imlib_image_fill_rectangle(0, 0, rect0.w, rect0.h); + imlib_blend_image_onto_image(hole, 0, x, y, rect1.w, rect1.h, x, y, rect1.w, rect1.h); + imlib_context_set_image(hole); + imlib_free_image_and_decache(); + } + break; + case SELECTION_MODE_HIDE: + { + char* const fileName = opt.selection.paramStr; + + if (fileName) { + if (opacity > 0) { + Imlib_Image hide = loadImage(fileName, opacity); + imlib_context_set_image(hide); + int const w = imlib_image_get_width(); + int const h = imlib_image_get_height(); + imlib_context_set_image(capture); + imlib_blend_image_onto_image(hide, 0, 0, 0, w, h, x, y, rect1.w, rect1.h); + imlib_context_set_image(hide); + imlib_free_image_and_decache(); + } + free(fileName); + } else { + imlib_context_set_color(color.red, color.green, color.blue, opacity); + imlib_image_fill_rectangle(x, y, rect1.w, rect1.h); + } + break; + } + case SELECTION_MODE_BLUR: + { + int const amountBlur = opt.selection.paramNum; + Imlib_Image blur = imlib_clone_image(); + imlib_context_set_image(blur); + imlib_image_blur(amountBlur); + imlib_context_set_image(capture); + imlib_blend_image_onto_image(blur, 0, x, y, rect1.w, rect1.h, x, y, rect1.w, rect1.h); + imlib_context_set_image(blur); + imlib_free_image_and_decache(); + break; + } + default: + assert(0); + } + + return capture; } diff -Nru scrot-1.6/src/scrot_selection.h scrot-1.7/src/scrot_selection.h --- scrot-1.6/src/scrot_selection.h 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/src/scrot_selection.h 2021-11-10 02:08:36.000000000 +0000 @@ -1,7 +1,8 @@ /* scrot_selection.h -Copyright 2020-2021 Daniel T. Borelli +Copyright 2020-2021 Daniel T. Borelli Copyright 2021 Martin C +Copyright 2021 Peter Wu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -29,40 +30,84 @@ Part of the code comes from the main.c file and maintains its authorship. */ -#ifndef SCROT_SELECTION_H -#define SCROT_SELECTION_H +#pragma once +#include +#include +#include +#include +#include +#include +#include #include -#define LINE_MODE_CLASSIC "classic" -#define LINE_MODE_CLASSIC_LEN 7 -#define LINE_MODE_EDGE "edge" -#define LINE_MODE_EDGE_LEN 4 +/* S: string, L: len */ +#define LINE_MODE_S_CLASSIC "classic" +#define LINE_MODE_L_CLASSIC 7 +#define LINE_MODE_S_EDGE "edge" +#define LINE_MODE_L_EDGE 4 +#define SELECTION_MODE_S_CAPTURE "capture" +#define SELECTION_MODE_L_CAPTURE 7 +#define SELECTION_MODE_S_HIDE "hide" +#define SELECTION_MODE_L_HIDE 4 +#define SELECTION_MODE_S_HOLE "hole" +#define SELECTION_MODE_L_HOLE 4 +#define SELECTION_MODE_S_BLUR "blur" +#define SELECTION_MODE_L_BLUR 4 + +enum { + SELECTION_MODE_SEPARATOR = ',', + SELECTION_MODE_CAPTURE = (1 << 1), + SELECTION_MODE_HIDE = (1 << 2), + SELECTION_MODE_HOLE = (1 << 3), + SELECTION_MODE_BLUR = (1 << 4), + SELECTION_MODE_ANY = (SELECTION_MODE_CAPTURE | SELECTION_MODE_HIDE | SELECTION_MODE_HOLE | SELECTION_MODE_BLUR), + SELECTION_MODE_NOT_CAPTURE = (SELECTION_MODE_ANY & ~SELECTION_MODE_CAPTURE), + SELECTION_MODE_NEED_PARAM = (SELECTION_MODE_HIDE | SELECTION_MODE_BLUR), + SELECTION_MODE_NOT_NEED_PARAM = (~SELECTION_MODE_NEED_PARAM), + SELECTION_MODE_BLUR_MIN= 1, + SELECTION_MODE_BLUR_MAX= 30, + SELECTION_MODE_BLUR_DEFAULT = 18, + SELECTION_OPACITY_MIN = 0, + SELECTION_OPACITY_MAX = 255, + SELECTION_OPACITY_DEFAULT = 100, + SELECTION_EDGE_OPACITY_MIN = 10, + SELECTION_EDGE_OPACITY_MAX = 100, +}; -struct selection_rect_t { +struct SelectionRect { int x, y, w, h; }; -struct selection_classic_t; -struct selection_edge_t; - -struct selection_t { - Cursor cur_cross, cur_angle_nw, cur_angle_ne, cur_angle_sw, cur_angle_se; - - struct selection_rect_t rect; - struct selection_classic_t* classic; - struct selection_edge_t* edge; +typedef struct SelectionMode { + unsigned int mode; + int paramNum; + char* paramStr; +} SelectionMode; + +struct SelectionClassic; +struct SelectionEdge; + +struct Selection { + Cursor curCross, curAngleNW, curAngleNE, curAngleSW, curAngleSE; + + struct SelectionRect rect; + struct SelectionClassic* classic; + struct SelectionEdge* edge; void (*create)(void); void (*destroy)(void); void (*draw)(void); - void (*motion_draw)(int x0, int y0, int x1, int y1); + void (*motionDraw)(int, int, int, int); }; -void scrot_selection_create(void); -void scrot_selection_destroy(void); -void scrot_selection_draw(void); -void scrot_selection_motion_draw(int x0, int y0, int x1, int y1); -struct selection_rect_t* scrot_selection_get_rect(void); - -#endif +void scrotSelectionCreate(void); +void scrotSelectionDestroy(void); +void scrotSelectionDraw(void); +void scrotSelectionMotionDraw(int, int, int, int); +struct SelectionRect* scrotSelectionGetRect(void); +void scrotSelectionGetLineColor(XColor*); +Status scrotSelectionCreateNamedColor(char const*, XColor*); +void scrotSelectionSetDefaultColorLine(void); +bool scrotSelectionGetUserSel(struct SelectionRect*); +Imlib_Image scrotSelectionSelectMode(void); diff -Nru scrot-1.6/src/selection_classic.c scrot-1.7/src/selection_classic.c --- scrot-1.6/src/selection_classic.c 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/src/selection_classic.c 2021-11-10 02:08:36.000000000 +0000 @@ -1,6 +1,7 @@ /* scrot_selection_classic.c -Copyright 2020-2021 Daniel T. Borelli +Copyright 2020-2021 Daniel T. Borelli +Copyright 2021 Peter Wu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -29,95 +30,77 @@ */ #include "selection_classic.h" -extern void selection_calculate_rect(int x0, int y0, int x1, int y1); -extern struct selection_t** selection_get(void); +extern void selectionCalculateRect(int, int, int, int); +extern struct Selection** selectionGet(void); -struct selection_classic_t { - XGCValues gcval; +struct SelectionClassic { + XGCValues gcValues; GC gc; }; -void selection_classic_create(void) +void selectionClassicCreate(void) { - struct selection_t *const sel = *selection_get(); + struct Selection* const sel = *selectionGet(); - sel->classic = calloc(1, sizeof(struct selection_classic_t)); + sel->classic = calloc(1, sizeof(*sel->classic)); - struct selection_classic_t* pc = sel->classic; + struct SelectionClassic* pc = sel->classic; - pc->gcval.function = GXxor; - pc->gcval.foreground = XWhitePixel(disp, 0); - pc->gcval.background = XBlackPixel(disp, 0); - pc->gcval.plane_mask = pc->gcval.background ^ pc->gcval.foreground; - pc->gcval.subwindow_mode = IncludeInferiors; + unsigned long const whiteColor = XWhitePixel(disp, 0); + unsigned long const blackColor = XBlackPixel(disp, 0); - if (opt.line_color != NULL) { - XColor clr_exact, clr_closest; - Status ret; + pc->gcValues.function = GXxor; + pc->gcValues.foreground = whiteColor; + pc->gcValues.background = blackColor; + pc->gcValues.plane_mask = pc->gcValues.background ^ pc->gcValues.foreground; + pc->gcValues.subwindow_mode = IncludeInferiors; - ret = XAllocNamedColor(disp, XDefaultColormap(disp, DefaultScreen(disp)), - opt.line_color, &clr_exact, &clr_closest); + XColor color; + scrotSelectionGetLineColor(&color); - if (ret == 0) { - free(opt.line_color); - fprintf(stderr, "Error allocate color:%s\n", strerror(BadColor)); - scrot_selection_destroy(); - exit(EXIT_FAILURE); - } - - pc->gcval.foreground = clr_exact.pixel; - - free(opt.line_color); - opt.line_color = NULL; - } + if (color.pixel != blackColor) + pc->gcValues.foreground = color.pixel; pc->gc = XCreateGC(disp, root, - GCFunction | GCForeground | GCBackground | GCSubwindowMode, - &pc->gcval); + GCFunction | GCForeground | GCBackground | GCSubwindowMode, + &pc->gcValues); assert(pc->gc != NULL); - XSetLineAttributes(disp, pc->gc, opt.line_width, opt.line_style, CapRound, JoinRound); + XSetLineAttributes(disp, pc->gc, opt.lineWidth, opt.lineStyle, CapRound, JoinRound); - if (opt.freeze == 1) { + if (opt.freeze) XGrabServer(disp); - } } - -void selection_classic_destroy(void) +void selectionClassicDestroy(void) { - struct selection_t const *const sel = *selection_get(); - struct selection_classic_t* pc = sel->classic; - - if (opt.freeze == 1) { + struct Selection const* const sel = *selectionGet(); + struct SelectionClassic* pc = sel->classic; + + if (opt.freeze) XUngrabServer(disp); - } - if (pc->gc) { + if (pc->gc) XFreeGC(disp, pc->gc); - } free(pc); } - -void selection_classic_draw(void) +void selectionClassicDraw(void) { - struct selection_t const *const sel = *selection_get(); - struct selection_classic_t const *const pc = sel->classic; + struct Selection const* const sel = *selectionGet(); + struct SelectionClassic const* const pc = sel->classic; XDrawRectangle(disp, root, pc->gc, sel->rect.x, sel->rect.y, sel->rect.w, sel->rect.h); XFlush(disp); } - -void selection_classic_motion_draw(int x0, int y0, int x1, int y1) +void selectionClassicMotionDraw(int x0, int y0, int x1, int y1) { - struct selection_t const *const sel = *selection_get(); + struct Selection const* const sel = *selectionGet(); - if (sel->rect.w) { - selection_classic_draw(); - } - selection_calculate_rect(x0, y0, x1, y1); - selection_classic_draw(); + if (sel->rect.w) + selectionClassicDraw(); + selectionCalculateRect(x0, y0, x1, y1); + selectionClassicDraw(); } diff -Nru scrot-1.6/src/selection_classic.h scrot-1.7/src/selection_classic.h --- scrot-1.6/src/selection_classic.h 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/src/selection_classic.h 2021-11-10 02:08:36.000000000 +0000 @@ -1,6 +1,7 @@ /* scrot_selection_classic.h -Copyright 2020-2021 Daniel T. Borelli +Copyright 2020-2021 Daniel T. Borelli +Copyright 2021 Peter Wu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -27,13 +28,12 @@ This file is part of the scrot project. Part of the code comes from the main.c file and maintains its authorship. */ -#ifndef SELECTION_CLASSIC_H -#define SELECTION_CLASSIC_H + +#pragma once #include "scrot.h" -void selection_classic_create(void); -void selection_classic_destroy(void); -void selection_classic_draw(void); -void selection_classic_motion_draw(int x0, int y0, int x1, int y1); -#endif +void selectionClassicCreate(void); +void selectionClassicDestroy(void); +void selectionClassicDraw(void); +void selectionClassicMotionDraw(int, int, int, int); diff -Nru scrot-1.6/src/selection_edge.c scrot-1.7/src/selection_edge.c --- scrot-1.6/src/selection_edge.c 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/src/selection_edge.c 2021-11-10 02:08:36.000000000 +0000 @@ -1,6 +1,7 @@ /* scrot_selection_edge.c -Copyright 2020-2021 Daniel T. Borelli +Copyright 2020-2021 Daniel T. Borelli +Copyright 2021 Peter Wu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -29,130 +30,119 @@ */ #include "scrot.h" -extern void selection_calculate_rect(int x0, int y0, int x1, int y1); -extern struct selection_t** selection_get(void); +extern void selectionCalculateRect(int, int, int, int); +extern struct Selection** selectionGet(void); -struct selection_edge_t { +struct SelectionEdge { Window wndDraw; XClassHint* classHint; }; - -static Bool xevent_unmap(Display *dpy, XEvent *ev, XPointer arg) +static Bool xeventUnmap(Display* dpy, XEvent* ev, XPointer arg) { - (void) dpy; //unused - Window *win = (Window*)arg; + (void)dpy; // unused + Window* win = (Window*)arg; return (ev->xunmap.window == *win); } - -static void wait_unmap_window_notify(void) +static void waitUnmapWindowNotify(void) { - struct selection_t const *const sel = *selection_get(); - struct selection_edge_t const *const pe = sel->edge; + struct Selection const* const sel = *selectionGet(); + struct SelectionEdge const* const pe = sel->edge; XEvent ev; XSelectInput(disp, pe->wndDraw, StructureNotifyMask); XUnmapWindow(disp, pe->wndDraw); - for(short i = 0; i < 30; ++i) { - if (XCheckIfEvent(disp, &ev, &xevent_unmap, (XPointer)&(pe->wndDraw)) == True) { + struct timespec delay = {0, 80000000L}; // 80ms + + for (short i = 0; i < 30; ++i) { + if (XCheckIfEvent(disp, &ev, &xeventUnmap, (XPointer) & (pe->wndDraw))) break; - } - usleep(8000); + nanosleep(&delay, NULL); } } +void selectionEdgeCreate(void) +{ + struct Selection* const sel = *selectionGet(); -void selection_edge_create(void) -{ - struct selection_t *const sel = *selection_get(); - - sel->edge = calloc(1, sizeof(struct selection_edge_t)); - - struct selection_edge_t *const pe = sel->edge; + sel->edge = calloc(1, sizeof(*sel->edge)); - // It is ok that in the "classic" mode it is to NULL, but it is not "edge" mode - if (opt.line_color == NULL) { - opt.line_color = "gray"; - } + struct SelectionEdge* const pe = sel->edge; XColor color; - - if (0 == XAllocNamedColor(disp, XDefaultColormap(disp, DefaultScreen(disp)), - opt.line_color, &color, &(XColor){})) - { - fprintf(stderr, "Error allocate color:%s\n", strerror(BadColor)); - scrot_selection_destroy(); - exit(EXIT_FAILURE); - } + scrotSelectionGetLineColor(&color); XSetWindowAttributes attr; attr.background_pixel = color.pixel; attr.override_redirect = True; pe->classHint = XAllocClassHint(); - pe->classHint->res_name = "scrot"; + pe->classHint->res_name = "scrot"; pe->classHint->res_class = "scrot"; pe->wndDraw = XCreateWindow(disp, root, 0, 0, WidthOfScreen(scr), HeightOfScreen(scr), 0, - CopyFromParent, InputOutput, CopyFromParent, CWOverrideRedirect | CWBackPixel, &attr); + CopyFromParent, InputOutput, CopyFromParent, CWOverrideRedirect | CWBackPixel, &attr); + + int const lineOpacity = optionsParseRequireRange(opt.lineOpacity, + SELECTION_EDGE_OPACITY_MIN, SELECTION_OPACITY_MAX); - unsigned long opacity = opt.line_opacity * ((unsigned)-1 / 100); + unsigned long opacity = lineOpacity * ((unsigned)-1 / 100); XChangeProperty(disp, pe->wndDraw, XInternAtom(disp, "_NET_WM_WINDOW_OPACITY", False), - XA_CARDINAL, 32, PropModeReplace, - (unsigned char*)&opacity, 1L); + XA_CARDINAL, 32, PropModeReplace, + (unsigned char*) &opacity, 1L); XChangeProperty(disp, pe->wndDraw, XInternAtom(disp, "_NET_WM_WINDOW_TYPE", False), - XA_ATOM, 32, PropModeReplace, - (unsigned char*)&(Atom){XInternAtom(disp, "_NET_WM_WINDOW_TYPE_DOCK", False)}, - 1L); + XA_ATOM, 32, PropModeReplace, + (unsigned char*) &(Atom) { XInternAtom(disp, "_NET_WM_WINDOW_TYPE_DOCK", False) }, + 1L); XSetClassHint(disp, pe->wndDraw, pe->classHint); } - -void selection_edge_destroy(void) +void selectionEdgeDestroy(void) { - struct selection_t const *const sel = *selection_get(); - struct selection_edge_t *pe = sel->edge; + struct Selection const* const sel = *selectionGet(); + struct SelectionEdge* pe = sel->edge; + + if (pe->wndDraw != 0) { + waitUnmapWindowNotify(); + XFree(pe->classHint); + XDestroyWindow(disp, pe->wndDraw); + } - wait_unmap_window_notify(); - XFree(pe->classHint); - XDestroyWindow(disp, pe->wndDraw); free(pe); } - -void selection_edge_draw(void) +void selectionEdgeDraw(void) { - struct selection_t const *const sel = *selection_get(); - struct selection_edge_t const *const pe = sel->edge; + struct Selection const* const sel = *selectionGet(); + struct SelectionEdge const* const pe = sel->edge; XRectangle rects[4] = { - {sel->rect.x, sel->rect.y, opt.line_width, sel->rect.h}, //left - {sel->rect.x, sel->rect.y, sel->rect.w, opt.line_width}, //top - {sel->rect.x + sel->rect.w, sel->rect.y, opt.line_width, sel->rect.h}, //right - {sel->rect.x, sel->rect.y + sel->rect.h, sel->rect.w + opt.line_width, opt.line_width} //bottom + { sel->rect.x, sel->rect.y, opt.lineWidth, sel->rect.h }, // left + { sel->rect.x, sel->rect.y, sel->rect.w, opt.lineWidth }, // top + { sel->rect.x + sel->rect.w, sel->rect.y, opt.lineWidth, sel->rect.h }, // right + { sel->rect.x, sel->rect.y + sel->rect.h, sel->rect.w + opt.lineWidth, opt.lineWidth } // bottom }; XShapeCombineRectangles(disp, pe->wndDraw, ShapeBounding, 0, 0, rects, 4, ShapeSet, 0); XMapWindow(disp, pe->wndDraw); } - -void selection_edge_motion_draw(int x0, int y0, int x1, int y1) +void selectionEdgeMotionDraw(int x0, int y0, int x1, int y1) { - struct selection_t *const sel = *selection_get(); + struct Selection* const sel = *selectionGet(); - selection_calculate_rect(x0, y0, x1, y1); + selectionCalculateRect(x0, y0, x1, y1); - sel->rect.x -= opt.line_width; - sel->rect.y -= opt.line_width; - sel->rect.w += opt.line_width; - sel->rect.h += opt.line_width; + sel->rect.x -= opt.lineWidth; + sel->rect.y -= opt.lineWidth; + sel->rect.w += opt.lineWidth; + sel->rect.h += opt.lineWidth; - selection_edge_draw(); + selectionEdgeDraw(); } diff -Nru scrot-1.6/src/selection_edge.h scrot-1.7/src/selection_edge.h --- scrot-1.6/src/selection_edge.h 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/src/selection_edge.h 2021-11-10 02:08:36.000000000 +0000 @@ -1,6 +1,7 @@ /* scrot_selection_edge.h -Copyright 2020-2021 Daniel T. Borelli +Copyright 2020-2021 Daniel T. Borelli +Copyright 2021 Peter Wu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -27,14 +28,12 @@ This file is part of the scrot project. Part of the code comes from the main.c file and maintains its authorship. */ -#ifndef SELECTION_EDGE_H -#define SELECTION_EDGE_H -#include "scrot.h" +#pragma once -void selection_edge_create(void); -void selection_edge_destroy(void); -void selection_edge_draw(void); -void selection_edge_motion_draw(int x0, int y0, int x1, int y1); +#include "scrot.h" -#endif +void selectionEdgeCreate(void); +void selectionEdgeDestroy(void); +void selectionEdgeDraw(void); +void selectionEdgeMotionDraw(int, int, int, int); diff -Nru scrot-1.6/src/slist.c scrot-1.7/src/slist.c --- scrot-1.6/src/slist.c 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/src/slist.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -/* slist.c - -Copyright 2021 Christopher Nelson - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies of the Software and its documentation and acknowledgment shall be -given in the documentation and software packages that this Software was -used. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ - -#include -#include -#include "slist.h" - -Scrot_Imlib_List * append_to_scrot_imlib(Scrot_Imlib_List *head, Imlib_Image *data) { - - Scrot_Imlib_List *tail = walk_to_end_of_scrot_imlib_list(head); - Scrot_Imlib_List *appended = (Scrot_Imlib_List *) malloc(sizeof(Scrot_Imlib_List)); - appended->data = data; - appended->next = NULL; - - if (head == NULL) { - return appended; - } else { - tail->next = appended; - } - - return head; -} - -Scrot_Imlib_List * walk_to_end_of_scrot_imlib_list(Scrot_Imlib_List *list) { - if (list == NULL) return NULL; - if (list->next == NULL) return list; - - while(list->next) { - list = list->next; - } - - return list; -} - -int is_scrot_imlib_list_empty(Scrot_Imlib_List *list) { - if (list == NULL) - return 1; - else - return 0; -} diff -Nru scrot-1.6/src/slist.h scrot-1.7/src/slist.h --- scrot-1.6/src/slist.h 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/src/slist.h 2021-11-10 02:08:36.000000000 +0000 @@ -1,6 +1,8 @@ /* slist.h -Copyright 2021 Christopher Nelson +Copyright 2021 Christopher Nelson +Copyright 2021 Peter Wu +Copyright 2021 Daniel T. Borelli Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -23,20 +25,42 @@ */ -#ifndef SCROT_SLIST_H -#define SCROT_SLIST_H +#pragma once -#include -#include +#include -typedef struct Scrot_Imlib_List { - Imlib_Image * data; - - struct Scrot_Imlib_List * next; -} Scrot_Imlib_List; - -Scrot_Imlib_List * append_to_scrot_imlib(Scrot_Imlib_List *head, Imlib_Image *data); -Scrot_Imlib_List * walk_to_end_of_scrot_imlib_list(Scrot_Imlib_List *list); -int is_scrot_imlib_list_empty(Scrot_Imlib_List *list); +typedef struct ScrotListNode { + void* data; + STAILQ_ENTRY(ScrotListNode) nodes; +} ScrotListNode; + +typedef STAILQ_HEAD(ScrotLists, ScrotListNode) ScrotList; + +#define initializeScrotList(name) \ + ScrotList name = STAILQ_HEAD_INITIALIZER(name); \ + STAILQ_INIT(&name); + +#define appendToScrotList(name, newData) do { \ + ScrotListNode* node = calloc(1, sizeof(*node)); \ + node->data = (void*)newData; \ + STAILQ_INSERT_TAIL(&name, node, nodes); \ +} while(0) + +#define isEmptyScrotList(name) \ + STAILQ_EMPTY(name) + +#define forEachScrotList(name, node) \ + STAILQ_FOREACH(node, name, nodes) + +#define firstScrotList(name) \ + STAILQ_FIRST(name) + +#define nextScrotList(name) \ + STAILQ_NEXT(name, nodes); + +#define nextAndFreeScrotList(name) do { \ + ScrotListNode* next = nextScrotList(name); \ + free(name); \ + name = next; \ +} while(0) -#endif diff -Nru scrot-1.6/src/structs.h scrot-1.7/src/structs.h --- scrot-1.6/src/structs.h 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/src/structs.h 2021-11-10 02:08:36.000000000 +0000 @@ -1,6 +1,7 @@ /* structs.h Copyright (C) 1999,2000 Tom Gilbert. +Copyright (C) 2021 Peter Wu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -23,10 +24,7 @@ */ -#ifndef STRUCTS_H -#define STRUCTS_H +#pragma once -typedef struct __scrotoptions scrotoptions; -typedef struct __scrotnote scrotnote; - -#endif +typedef struct __ScrotOptions ScrotOptions; +typedef struct __ScrotNote ScrotNote; diff -Nru scrot-1.6/TODO scrot-1.7/TODO --- scrot-1.6/TODO 2021-07-26 02:42:43.000000000 +0000 +++ scrot-1.7/TODO 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -There has to be some way I can add pr0n to this thing... diff -Nru scrot-1.6/TODO.md scrot-1.7/TODO.md --- scrot-1.6/TODO.md 1970-01-01 00:00:00.000000000 +0000 +++ scrot-1.7/TODO.md 2021-11-10 02:08:36.000000000 +0000 @@ -0,0 +1,54 @@ +# TODO + +#### The lists in this page summarize current efforts in the scrot project. + +## Fix bugs + +Look for any bugs reported downstream or in our github issues and fix them: +- https://github.com/resurrecting-open-source-projects/scrot/issues +- https://bugs.debian.org/cgi-bin/pkgreport.cgi?dist=unstable;package=scrot +- https://bugs.launchpad.net/ubuntu/+source/scrot/+bugs +- https://apps.fedoraproject.org/packages/scrot/bugs +- https://bugs.gentoo.org/buglist.cgi?quicksearch=scrot + +## Integrate [libbsd](https://libbsd.freedesktop.org/wiki/) + +The BSD systems provide nonstandard C functions; many of the functions remove +the need for some boilerplate code, and provide safer or easier to use APIs +compared to the C standard library. +scrot is in the process of auditing its source to make use of BSD extensions +to the C library where they are found to improve code quality. scrot depends on +libbsd to provide the required functions where they're missing to remain +portable. libbsd includes manuals for all the functions it implements-a list of +them can be found at libbsd(7). The manual can alternatively be accessed from +the web at [manpages.debian.org](https://manpages.debian.org/unstable/libbsd-dev/libbsd.7.en.html). +BSD systems provide manuals for these functions in the default install. + +The following libbsd integration efforts are in progress: +- ~~Replace strncpy() and strcpy() calls with strlcpy().~~ +- ~~Replace strcat() and strncat() calls with strlcat().~~ +- ~~Replace error exits with the err() family of functions.~~ +- ~~Replace local implementations of data structures with the sys/queue.h API.~~ +- Find places where other BSD functions can serve scrot well. + +## Comply with WebKit style +We're currently in the process of complying with the new obligatory C style +described in [CONTRIBUTING.md](CONTRIBUTING.md). + +The following files are yet to be converted: +- ~~src/imlib.c~~ +- ~~src/main.c~~ +- ~~src/note.c~~ +- ~~src/options.c~~ +- ~~src/scrot_selection.c~~ +- ~~src/selection_classic.c~~ +- ~~src/selection_edge.c~~ +- ~~src/note.h~~ +- ~~src/options.h~~ +- ~~src/slist.c~~ +- ~~src/scrot.h~~ +- ~~src/scrot_selection.h~~ +- ~~src/selection_classic.h~~ +- ~~src/selection_edge.h~~ +- ~~src/slist.h~~ +- ~~src/structs.h~~