diff -Nru alttab-1.3.0/aclocal.m4 alttab-1.5.0/aclocal.m4 --- alttab-1.3.0/aclocal.m4 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/aclocal.m4 2020-07-23 08:24:20.000000000 +0000 @@ -1,6 +1,6 @@ -# generated automatically by aclocal 1.15.1 -*- Autoconf -*- +# generated automatically by aclocal 1.16.2 -*- Autoconf -*- -# Copyright (C) 1996-2017 Free Software Foundation, Inc. +# Copyright (C) 1996-2020 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -20,9 +20,9 @@ If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) -dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- -dnl serial 11 (pkg-config-0.29) -dnl +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# serial 12 (pkg-config-0.29.2) + dnl Copyright © 2004 Scott James Remnant . dnl Copyright © 2012-2015 Dan Nicholson dnl @@ -63,7 +63,7 @@ dnl See the "Since" comment for each macro you use to see what version dnl of the macros you require. m4_defun([PKG_PREREQ], -[m4_define([PKG_MACROS_VERSION], [0.29]) +[m4_define([PKG_MACROS_VERSION], [0.29.2]) m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ @@ -164,7 +164,7 @@ AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no -AC_MSG_CHECKING([for $1]) +AC_MSG_CHECKING([for $2]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) @@ -174,11 +174,11 @@ See the pkg-config man page for more details.]) if test $pkg_failed = yes; then - AC_MSG_RESULT([no]) + AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` - else + else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs @@ -195,7 +195,7 @@ _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then - AC_MSG_RESULT([no]) + AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full @@ -296,7 +296,7 @@ AS_VAR_IF([$1], [""], [$5], [$4])dnl ])dnl PKG_CHECK_VAR -# Copyright (C) 2002-2017 Free Software Foundation, Inc. +# Copyright (C) 2002-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -308,10 +308,10 @@ # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], -[am__api_version='1.15' +[am__api_version='1.16' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.15.1], [], +m4_if([$1], [1.16.2], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -327,14 +327,14 @@ # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.15.1])dnl +[AM_AUTOMAKE_VERSION([1.16.2])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- -# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -386,7 +386,7 @@ # AM_CONDITIONAL -*- Autoconf -*- -# Copyright (C) 1997-2017 Free Software Foundation, Inc. +# Copyright (C) 1997-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -417,7 +417,7 @@ Usually this means the macro was only invoked conditionally.]]) fi])]) -# Copyright (C) 1999-2017 Free Software Foundation, Inc. +# Copyright (C) 1999-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -608,13 +608,12 @@ # Generate code to set up dependency tracking. -*- Autoconf -*- -# Copyright (C) 1999-2017 Free Software Foundation, Inc. +# Copyright (C) 1999-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. - # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], @@ -622,49 +621,43 @@ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. - case $CONFIG_FILES in - *\'*) eval set x "$CONFIG_FILES" ;; - *) set x $CONFIG_FILES ;; - esac + # TODO: see whether this extra hack can be removed once we start + # requiring Autoconf 2.70 or later. + AS_CASE([$CONFIG_FILES], + [*\'*], [eval set x "$CONFIG_FILES"], + [*], [set x $CONFIG_FILES]) shift - for mf + # Used to flag and report bootstrapping failures. + am_rc=0 + for am_mf do # Strip MF so we end up with the name of the file. - mf=`echo "$mf" | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile or not. - # We used to match only the files named 'Makefile.in', but - # some people rename them; so instead we look at the file content. - # Grep'ing the first line is not enough: some people post-process - # each Makefile.in and add a new line on top of each file to say so. - # Grep'ing the whole file is not good either: AIX grep has a line + am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile which includes + # dependency-tracking related rules and includes. + # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. - if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then - dirpart=`AS_DIRNAME("$mf")` - else - continue - fi - # Extract the definition of DEPDIR, am__include, and am__quote - # from the Makefile without running 'make'. - DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` - test -z "$DEPDIR" && continue - am__include=`sed -n 's/^am__include = //p' < "$mf"` - test -z "$am__include" && continue - am__quote=`sed -n 's/^am__quote = //p' < "$mf"` - # Find all dependency output files, they are included files with - # $(DEPDIR) in their names. We invoke sed twice because it is the - # simplest approach to changing $(DEPDIR) to its actual value in the - # expansion. - for file in `sed -n " - s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ - sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do - # Make sure the directory exists. - test -f "$dirpart/$file" && continue - fdir=`AS_DIRNAME(["$file"])` - AS_MKDIR_P([$dirpart/$fdir]) - # echo "creating $dirpart/$file" - echo '# dummy' > "$dirpart/$file" - done + sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ + || continue + am_dirpart=`AS_DIRNAME(["$am_mf"])` + am_filepart=`AS_BASENAME(["$am_mf"])` + AM_RUN_LOG([cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles]) || am_rc=$? done + if test $am_rc -ne 0; then + AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments + for automatic dependency tracking. If GNU make was not used, consider + re-running the configure script with MAKE="gmake" (or whatever is + necessary). You can also try re-running configure with the + '--disable-dependency-tracking' option to at least be able to build + the package (albeit without support for automatic dependency tracking).]) + fi + AS_UNSET([am_dirpart]) + AS_UNSET([am_filepart]) + AS_UNSET([am_mf]) + AS_UNSET([am_rc]) + rm -f conftest-deps.mk } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS @@ -673,18 +666,17 @@ # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # -# This code is only required when automatic dependency tracking -# is enabled. FIXME. This creates each '.P' file that we will -# need in order to bootstrap the dependency handling code. +# This code is only required when automatic dependency tracking is enabled. +# This creates each '.Po' and '.Plo' makefile fragment that we'll need in +# order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], - [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) -]) + [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) # Do all the work for Automake. -*- Autoconf -*- -# Copyright (C) 1996-2017 Free Software Foundation, Inc. +# Copyright (C) 1996-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -771,8 +763,8 @@ AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: -# -# +# +# AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. @@ -839,7 +831,7 @@ Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation -that behaves properly: . +that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM @@ -881,7 +873,7 @@ done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) -# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -902,7 +894,7 @@ fi AC_SUBST([install_sh])]) -# Copyright (C) 2003-2017 Free Software Foundation, Inc. +# Copyright (C) 2003-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -923,7 +915,7 @@ # Check to see how 'make' treats includes. -*- Autoconf -*- -# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -931,49 +923,42 @@ # AM_MAKE_INCLUDE() # ----------------- -# Check to see how make treats includes. +# Check whether make has an 'include' directive that can support all +# the idioms we need for our automatic dependency tracking code. AC_DEFUN([AM_MAKE_INCLUDE], -[am_make=${MAKE-make} -cat > confinc << 'END' +[AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) +cat > confinc.mk << 'END' am__doit: - @echo this is the am__doit target + @echo this is the am__doit target >confinc.out .PHONY: am__doit END -# If we don't find an include directive, just comment out the code. -AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= -_am_result=none -# First try GNU make style include. -echo "include confinc" > confmf -# Ignore all kinds of additional output from 'make'. -case `$am_make -s -f confmf 2> /dev/null` in #( -*the\ am__doit\ target*) - am__include=include - am__quote= - _am_result=GNU - ;; -esac -# Now try BSD make style include. -if test "$am__include" = "#"; then - echo '.include "confinc"' > confmf - case `$am_make -s -f confmf 2> /dev/null` in #( - *the\ am__doit\ target*) - am__include=.include - am__quote="\"" - _am_result=BSD - ;; - esac -fi -AC_SUBST([am__include]) -AC_SUBST([am__quote]) -AC_MSG_RESULT([$_am_result]) -rm -f confinc confmf -]) +# BSD make does it like this. +echo '.include "confinc.mk" # ignored' > confmf.BSD +# Other make implementations (GNU, Solaris 10, AIX) do it like this. +echo 'include confinc.mk # ignored' > confmf.GNU +_am_result=no +for s in GNU BSD; do + AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) + AS_CASE([$?:`cat confinc.out 2>/dev/null`], + ['0:this is the am__doit target'], + [AS_CASE([$s], + [BSD], [am__include='.include' am__quote='"'], + [am__include='include' am__quote=''])]) + if test "$am__include" != "#"; then + _am_result="yes ($s style)" + break + fi +done +rm -f confinc.* confmf.* +AC_MSG_RESULT([${_am_result}]) +AC_SUBST([am__include])]) +AC_SUBST([am__quote])]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- -# Copyright (C) 1997-2017 Free Software Foundation, Inc. +# Copyright (C) 1997-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1012,7 +997,7 @@ # Helper functions for option handling. -*- Autoconf -*- -# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1041,7 +1026,7 @@ AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) -# Copyright (C) 1999-2017 Free Software Foundation, Inc. +# Copyright (C) 1999-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1088,7 +1073,7 @@ # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) -# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1107,7 +1092,7 @@ # Check to make sure that the build environment is sane. -*- Autoconf -*- -# Copyright (C) 1996-2017 Free Software Foundation, Inc. +# Copyright (C) 1996-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1188,7 +1173,7 @@ rm -f conftest.file ]) -# Copyright (C) 2009-2017 Free Software Foundation, Inc. +# Copyright (C) 2009-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1248,7 +1233,7 @@ _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) -# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1276,7 +1261,7 @@ INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) -# Copyright (C) 2006-2017 Free Software Foundation, Inc. +# Copyright (C) 2006-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1295,7 +1280,7 @@ # Check how to create a tarball. -*- Autoconf -*- -# Copyright (C) 2004-2017 Free Software Foundation, Inc. +# Copyright (C) 2004-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, diff -Nru alttab-1.3.0/ChangeLog alttab-1.5.0/ChangeLog --- alttab-1.3.0/ChangeLog 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/ChangeLog 2020-07-23 08:24:20.000000000 +0000 @@ -1,3 +1,39 @@ +2020-07-23 Alexander Kulak + + version 1.5.0 + + Use xpm icons and pixmap directories. + Use XDG_DATA_DIRS. + Add extra keys: next/prev, cancel. + Optimize main event loop. + Fix numerous memleaks and overflows. + Satisfy gcc 10 requirements. + +2019-05-01 Alexander Kulak + + version 1.4.0 + + Use icon from _NET_WM_ICON window property. + +2018-11-28 Yauheni Kaliuta + + Code quality patch: + gui: skip extra winlist initializations, + gui, win: make selected window number local for gui, + ewmh: fold window property calls, + treewide: fix memory leaks, + treewide: delete trailing whitespaces, + treewide: make private stuff really private. + Automatic indent. + + Closes: #71, #72, #79. + +2018-07-04 Alexander Kulak + + Support RANDR output without CRTCinfo. + + Closes: #69. + 2018-04-12 Alexander Kulak version 1.3.0 diff -Nru alttab-1.3.0/compile alttab-1.5.0/compile --- alttab-1.3.0/compile 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/compile 2020-07-23 08:24:20.000000000 +0000 @@ -1,9 +1,9 @@ #! /bin/sh # Wrapper for compilers which do not understand '-c -o'. -scriptversion=2012-10-14.11; # UTC +scriptversion=2018-03-07.03; # UTC -# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Copyright (C) 1999-2018 Free Software Foundation, Inc. # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify @@ -17,7 +17,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -255,7 +255,8 @@ echo "compile $scriptversion" exit $? ;; - cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) + cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ + icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac @@ -339,9 +340,9 @@ # Local Variables: # mode: shell-script # sh-indentation: 2 -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC" +# time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: diff -Nru alttab-1.3.0/configure alttab-1.5.0/configure --- alttab-1.3.0/configure 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/configure 2020-07-23 08:24:20.000000000 +0000 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for alttab 1.3.0. +# Generated by GNU Autoconf 2.69 for alttab 1.5.0. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -577,8 +577,8 @@ # Identity of this package. PACKAGE_NAME='alttab' PACKAGE_TARNAME='alttab' -PACKAGE_VERSION='1.3.0' -PACKAGE_STRING='alttab 1.3.0' +PACKAGE_VERSION='1.5.0' +PACKAGE_STRING='alttab 1.5.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -628,6 +628,8 @@ CPP fts_LIBS fts_CFLAGS +xpm_LIBS +xpm_CFLAGS libpng_LIBS libpng_CFLAGS xrandr_LIBS @@ -648,7 +650,6 @@ AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE -am__quote am__include DEPDIR OBJEXT @@ -723,7 +724,8 @@ PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR -SHELL' +SHELL +am__quote' ac_subst_files='' ac_user_opts=' enable_option_checking @@ -751,6 +753,8 @@ xrandr_LIBS libpng_CFLAGS libpng_LIBS +xpm_CFLAGS +xpm_LIBS CPP' @@ -1302,7 +1306,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures alttab 1.3.0 to adapt to many kinds of systems. +\`configure' configures alttab 1.5.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1369,7 +1373,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of alttab 1.3.0:";; + short | recursive ) echo "Configuration of alttab 1.5.0:";; esac cat <<\_ACEOF @@ -1411,6 +1415,8 @@ libpng_CFLAGS C compiler flags for libpng, overriding pkg-config libpng_LIBS linker flags for libpng, overriding pkg-config + xpm_CFLAGS C compiler flags for xpm, overriding pkg-config + xpm_LIBS linker flags for xpm, overriding pkg-config CPP C preprocessor Use these variables to override the choices made by `configure' or to help @@ -1479,7 +1485,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -alttab configure 1.3.0 +alttab configure 1.5.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1731,7 +1737,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by alttab $as_me 1.3.0, which was +It was created by alttab $as_me 1.5.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2079,7 +2085,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu -am__api_version='1.15' +am__api_version='1.16' ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do @@ -2594,7 +2600,7 @@ # Define the identity of the package. PACKAGE='alttab' - VERSION='1.3.0' + VERSION='1.5.0' cat >>confdefs.h <<_ACEOF @@ -2624,8 +2630,8 @@ # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: -# -# +# +# mkdir_p='$(MKDIR_P)' # We need awk for the "check" target (and possibly the TAP driver). The @@ -2676,7 +2682,7 @@ Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation -that behaves properly: . +that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM @@ -3541,45 +3547,45 @@ ac_config_commands="$ac_config_commands depfiles" - -am_make=${MAKE-make} -cat > confinc << 'END' +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 +$as_echo_n "checking whether ${MAKE-make} supports the include directive... " >&6; } +cat > confinc.mk << 'END' am__doit: - @echo this is the am__doit target + @echo this is the am__doit target >confinc.out .PHONY: am__doit END -# If we don't find an include directive, just comment out the code. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 -$as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= -_am_result=none -# First try GNU make style include. -echo "include confinc" > confmf -# Ignore all kinds of additional output from 'make'. -case `$am_make -s -f confmf 2> /dev/null` in #( -*the\ am__doit\ target*) - am__include=include - am__quote= - _am_result=GNU - ;; -esac -# Now try BSD make style include. -if test "$am__include" = "#"; then - echo '.include "confinc"' > confmf - case `$am_make -s -f confmf 2> /dev/null` in #( - *the\ am__doit\ target*) - am__include=.include - am__quote="\"" - _am_result=BSD +# BSD make does it like this. +echo '.include "confinc.mk" # ignored' > confmf.BSD +# Other make implementations (GNU, Solaris 10, AIX) do it like this. +echo 'include confinc.mk # ignored' > confmf.GNU +_am_result=no +for s in GNU BSD; do + { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 + (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + case $?:`cat confinc.out 2>/dev/null` in #( + '0:this is the am__doit target') : + case $s in #( + BSD) : + am__include='.include' am__quote='"' ;; #( + *) : + am__include='include' am__quote='' ;; +esac ;; #( + *) : ;; - esac -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 -$as_echo "$_am_result" >&6; } -rm -f confinc confmf +esac + if test "$am__include" != "#"; then + _am_result="yes ($s style)" + break + fi +done +rm -f confinc.* confmf.* +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 +$as_echo "${_am_result}" >&6; } # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : @@ -3892,7 +3898,7 @@ if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -3919,7 +3925,7 @@ and x11_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} @@ -3983,7 +3989,7 @@ if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -4010,7 +4016,7 @@ and xft_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} @@ -4074,7 +4080,7 @@ if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -4101,7 +4107,7 @@ and xrender_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} @@ -4165,7 +4171,7 @@ if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -4192,7 +4198,7 @@ and xrandr_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} @@ -4256,7 +4262,7 @@ if test $pkg_failed = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then @@ -4283,7 +4289,7 @@ and libpng_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} @@ -4305,6 +4311,97 @@ fi +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for xpm" >&5 +$as_echo_n "checking for xpm... " >&6; } + +if test -n "$xpm_CFLAGS"; then + pkg_cv_xpm_CFLAGS="$xpm_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xpm\""; } >&5 + ($PKG_CONFIG --exists --print-errors "xpm") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_xpm_CFLAGS=`$PKG_CONFIG --cflags "xpm" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$xpm_LIBS"; then + pkg_cv_xpm_LIBS="$xpm_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xpm\""; } >&5 + ($PKG_CONFIG --exists --print-errors "xpm") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_xpm_LIBS=`$PKG_CONFIG --libs "xpm" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + xpm_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "xpm" 2>&1` + else + xpm_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "xpm" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$xpm_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements (xpm) were not met: + +$xpm_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables xpm_CFLAGS +and xpm_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables xpm_CFLAGS +and xpm_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see . +See \`config.log' for more details" "$LINENO" 5; } +else + xpm_CFLAGS=$pkg_cv_xpm_CFLAGS + xpm_LIBS=$pkg_cv_xpm_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for standalone fts library" >&5 $as_echo_n "checking for standalone fts library... " >&6; } if pkg-config --exists libfts ; then @@ -5275,7 +5372,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by alttab $as_me 1.3.0, which was +This file was extended by alttab $as_me 1.5.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -5341,7 +5438,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -alttab config.status 1.3.0 +alttab config.status 1.5.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -5460,7 +5557,7 @@ # # INIT-COMMANDS # -AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" +AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" _ACEOF @@ -6074,29 +6171,35 @@ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. - case $CONFIG_FILES in - *\'*) eval set x "$CONFIG_FILES" ;; - *) set x $CONFIG_FILES ;; - esac + # TODO: see whether this extra hack can be removed once we start + # requiring Autoconf 2.70 or later. + case $CONFIG_FILES in #( + *\'*) : + eval set x "$CONFIG_FILES" ;; #( + *) : + set x $CONFIG_FILES ;; #( + *) : + ;; +esac shift - for mf + # Used to flag and report bootstrapping failures. + am_rc=0 + for am_mf do # Strip MF so we end up with the name of the file. - mf=`echo "$mf" | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile or not. - # We used to match only the files named 'Makefile.in', but - # some people rename them; so instead we look at the file content. - # Grep'ing the first line is not enough: some people post-process - # each Makefile.in and add a new line on top of each file to say so. - # Grep'ing the whole file is not good either: AIX grep has a line + am_mf=`$as_echo "$am_mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile which includes + # dependency-tracking related rules and includes. + # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. - if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then - dirpart=`$as_dirname -- "$mf" || -$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$mf" : 'X\(//\)[^/]' \| \ - X"$mf" : 'X\(//\)$' \| \ - X"$mf" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$mf" | + sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ + || continue + am_dirpart=`$as_dirname -- "$am_mf" || +$as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$am_mf" : 'X\(//\)[^/]' \| \ + X"$am_mf" : 'X\(//\)$' \| \ + X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$am_mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -6114,53 +6217,50 @@ q } s/.*/./; q'` - else - continue - fi - # Extract the definition of DEPDIR, am__include, and am__quote - # from the Makefile without running 'make'. - DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` - test -z "$DEPDIR" && continue - am__include=`sed -n 's/^am__include = //p' < "$mf"` - test -z "$am__include" && continue - am__quote=`sed -n 's/^am__quote = //p' < "$mf"` - # Find all dependency output files, they are included files with - # $(DEPDIR) in their names. We invoke sed twice because it is the - # simplest approach to changing $(DEPDIR) to its actual value in the - # expansion. - for file in `sed -n " - s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ - sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do - # Make sure the directory exists. - test -f "$dirpart/$file" && continue - fdir=`$as_dirname -- "$file" || -$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$file" : 'X\(//\)[^/]' \| \ - X"$file" : 'X\(//\)$' \| \ - X"$file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ + am_filepart=`$as_basename -- "$am_mf" || +$as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ + X"$am_mf" : 'X\(//\)$' \| \ + X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$am_mf" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } - /^X\(\/\/\)$/{ + /^X\/\(\/\/\)$/{ s//\1/ q } - /^X\(\/\).*/{ + /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` - as_dir=$dirpart/$fdir; as_fn_mkdir_p - # echo "creating $dirpart/$file" - echo '# dummy' > "$dirpart/$file" - done + { echo "$as_me:$LINENO: cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles" >&5 + (cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } || am_rc=$? done + if test $am_rc -ne 0; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "Something went wrong bootstrapping makefile fragments + for automatic dependency tracking. If GNU make was not used, consider + re-running the configure script with MAKE=\"gmake\" (or whatever is + necessary). You can also try re-running configure with the + '--disable-dependency-tracking' option to at least be able to build + the package (albeit without support for automatic dependency tracking). +See \`config.log' for more details" "$LINENO" 5; } + fi + { am_dirpart=; unset am_dirpart;} + { am_filepart=; unset am_filepart;} + { am_mf=; unset am_mf;} + { am_rc=; unset am_rc;} + rm -f conftest-deps.mk } ;; diff -Nru alttab-1.3.0/configure.ac alttab-1.5.0/configure.ac --- alttab-1.3.0/configure.ac 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/configure.ac 2020-07-23 08:24:20.000000000 +0000 @@ -1,4 +1,4 @@ -AC_INIT([alttab], [1.3.0]) +AC_INIT([alttab], [1.5.0]) AM_INIT_AUTOMAKE([foreign subdir-objects]) AC_CONFIG_SRCDIR([configure.ac]) AC_CONFIG_HEADERS([config.h]) @@ -8,6 +8,7 @@ PKG_CHECK_MODULES([xrender], [xrender]) PKG_CHECK_MODULES([xrandr], [xrandr]) PKG_CHECK_MODULES([libpng], [libpng]) +PKG_CHECK_MODULES([xpm], [xpm]) AC_MSG_CHECKING(for standalone fts library) if pkg-config --exists libfts ; then diff -Nru alttab-1.3.0/debian/changelog alttab-1.5.0/debian/changelog --- alttab-1.3.0/debian/changelog 2018-04-12 08:00:00.000000000 +0000 +++ alttab-1.5.0/debian/changelog 2020-07-23 09:19:05.000000000 +0000 @@ -1,3 +1,28 @@ +alttab (1.5.0-1) unstable; urgency=medium + + * New upstream release + + -- Alexander Kulak Thu, 23 Jul 2020 12:19:05 +0300 + +alttab (1.4.0-2) UNRELEASED; urgency=medium + + * Set debhelper-compat version in Build-Depends. + * Set field Upstream-Contact in debian/copyright. + * Set upstream metadata fields: Repository, Repository-Browse. + * Remove obsolete fields Contact, Name from debian/upstream/metadata + (already present in machine-readable debian/copyright). + * Update standards version to 4.5.0, no changes needed. + + -- Debian Janitor Tue, 28 Apr 2020 14:41:34 +0000 + +alttab (1.4.0-1) experimental; urgency=medium + + * New upstream release + * Bump debhelper compat to 12 + * Change maintainer email address + + -- Alexander Kulak Wed, 1 May 2019 20:47:47 +0300 + alttab (1.3.0-1) unstable; urgency=medium * New upstream release @@ -19,4 +44,3 @@ * Initial release (Closes: #861533) -- Alexander Kulak Wed, 25 Oct 2017 11:15:28 +0300 - diff -Nru alttab-1.3.0/debian/compat alttab-1.5.0/debian/compat --- alttab-1.3.0/debian/compat 2018-04-12 08:00:00.000000000 +0000 +++ alttab-1.5.0/debian/compat 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -11 diff -Nru alttab-1.3.0/debian/control alttab-1.5.0/debian/control --- alttab-1.3.0/debian/control 2018-04-12 08:00:00.000000000 +0000 +++ alttab-1.5.0/debian/control 2020-07-23 09:19:05.000000000 +0000 @@ -1,21 +1,23 @@ Source: alttab Section: x11 Priority: optional -Maintainer: Alexander Kulak -Build-Depends: debhelper (>= 11~), +Maintainer: Alexander Kulak +Build-Depends: debhelper-compat (= 13), libx11-dev, libxmu-dev, libxft-dev, libxrender-dev, libxrandr-dev, libpng-dev, + libxpm-dev, uthash-dev, autoconf, automake -Standards-Version: 4.1.4 +Standards-Version: 4.5.0 Vcs-Git: https://github.com/sagb/alttab.git -b debian/unstable Vcs-Browser: https://github.com/sagb/alttab/tree/debian/unstable Homepage: https://sagb.github.io/alttab +Rules-Requires-Root: no Package: alttab Architecture: any diff -Nru alttab-1.3.0/debian/copyright alttab-1.5.0/debian/copyright --- alttab-1.3.0/debian/copyright 2018-04-12 08:00:00.000000000 +0000 +++ alttab-1.5.0/debian/copyright 2020-07-23 09:19:05.000000000 +0000 @@ -1,9 +1,10 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: alttab Source: https://github.com/sagb/alttab +Upstream-Contact: Alexander Kulak Files: * -Copyright: 2017-2018 Alexander Kulak +Copyright: 2017-2020 Alexander Kulak License: GPL-3.0+ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,7 +23,7 @@ Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". Files: doc/alttab.1.ronn -Copyright: 2017-2018 Alexander Kulak +Copyright: 2017-2020 Alexander Kulak License: permissive Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright diff -Nru alttab-1.3.0/debian/rules alttab-1.5.0/debian/rules --- alttab-1.3.0/debian/rules 2018-04-12 08:00:00.000000000 +0000 +++ alttab-1.5.0/debian/rules 2020-07-23 09:19:05.000000000 +0000 @@ -9,4 +9,3 @@ # important in bootstrap.sh, besides of autotools and man page. #override_dh_autoreconf: # dh_autoreconf ./bootstrap.sh -f - diff -Nru alttab-1.3.0/debian/upstream/metadata alttab-1.5.0/debian/upstream/metadata --- alttab-1.3.0/debian/upstream/metadata 2018-04-12 08:00:00.000000000 +0000 +++ alttab-1.5.0/debian/upstream/metadata 2020-07-23 09:19:05.000000000 +0000 @@ -2,8 +2,7 @@ Bug-Database: https://github.com/sagb/alttab/issues Bug-Submit: https://github.com/sagb/alttab/issues Changelog: https://raw.githubusercontent.com/sagb/alttab/master/ChangeLog -Contact: Alexander Kulak -Name: alttab Other-References: https://sagb.github.io/alttab -Repository: https://github.com/sagb/alttab +Repository: https://github.com/sagb/alttab.git +Repository-Browse: https://github.com/sagb/alttab Screenshots: https://github.com/sagb/alttab/blob/master/doc/screenshots/screenshots.md diff -Nru alttab-1.3.0/debian/upstream/signing-key.asc alttab-1.5.0/debian/upstream/signing-key.asc --- alttab-1.3.0/debian/upstream/signing-key.asc 2018-04-12 08:00:00.000000000 +0000 +++ alttab-1.5.0/debian/upstream/signing-key.asc 2020-07-23 09:19:05.000000000 +0000 @@ -11,41 +11,54 @@ m/jP6wwEWocwXuz+MDdO4v+6oBeKWzL/hV4bezoloFfDsTOPvZphkDo+GE6Rr2yT Jkg+BofGs6hsirZe2y9NnVQZeoaSz+RvWO3t/LMaGJVCNRgU5YlknXoDta4rapOX SHuchyxnOxsmddCabaqkX0QeBZu8qSiWjn7hXs8efIW5NGSQxBFId668XwARAQAB -tCNBbGV4YW5kZXIgS3VsYWsgPHNhLWRldkByYWluYm93LmJ5PokCPwQTAQgAKQUC -WQHzJQIbAwUJEswDAAcLCQgHAwIBBhUIAgkKCwQWAgMBAh4BAheAAAoJEDchGd+R -R41t5LQP/jf3tWr+OAQ5f6prO0+CxkxFQhzrWsuBaiTy7dLH27VMXjuEWDRYcz0I -v+n0QQYZTrxK+KNEBFJXu/IeBIuUyB7tumIYvgDD2mOHVC0bnqBYvqWG2MnobqyV -pTv5KEQfK8jDVZxxK3kSdT0Sta0/rfyKQRmWg+abAVRWSz5F6lCv/IPXEShRPMAV -oX5cA+zYyQEcgKLvVNSmV/zdr34UH43kGBjSRcJNeemtK+feZ+AxaxDjc5hws9Dy -8mj1qIF35f40owwIIj/RRc5h3CzPczkvgyP5FDoi0+QcvSLrnN8JfY/pDmBRvAvf -4Cswu/nHONoUSLD/LcoeEDezubn3PF5ZrH04p9LRXJxFPZZ6O3Uhq9VoWor531/k -kd841Jz+n7Oa2zb8YJTvU+Za1AbcLZE0JTBNTF6NX6AGPqodHPQk0d3Zvb+gtCtk -e8OZgADGjWH6azxVW2UIlM0vLDCFQrIAZv6lAvB82x5x0xm+SdhunqCEaO7qyLYq -WqiRfUctOJ7uPYqxOUCt3u5NuIdDWm7jDRbMdrzoAqDQvflujRd089h9f4fllXgU -KZH2Kb0WaKnoyLVlxs704SF8MJUNpr1V2sd3RKTGR/XYVJxVkjuSYSUjzHn8lVL5 -6xgmUQVga3Y8jH1e4AmeQIkbKmE8ezsxv6T112ThstKCYGBlQNIhuQINBFkB8yUB -EADl5vSoHQnmTG5HOuFlbAU2DC6VnI+IMnBbDgXxBMCJrhN+OMstBbl0Omcev6vG -XRLDdcGzProjllglzOLjBHXIwkeJZ95UVJVtwqhOViT9YZdVPvxvjVPGP+HckO6k -XozKS/UkkWp3/wDI0yUBuVlJr+/PoUXsRPESjXT+CSW9dPatLum+yHrtQPe8ubHX -llkXiPL755DSnM17jmXasK3cm+SPoXBo4UTMZOHe5+OBICFykZqQL4Ayc3AUvnrE -vLuricvYd5aotA5Mr2NZHay4IWXPSGJoxDVQIbrGENkBItzttb/nC1pS6WzOXbqa -UeZ8oViVYjANP4vo5Pd1AdfYm4a6D5+CsFMfiHAAiieLE+NVX9gUhH37/SCaXi7u -1x+aosigKTPDEDWKhG1GCWgzr+k66oZxHEbWq5iYPssXZGk/zuWK58u5Moaeaxp8 -j5ZddtODJjFruAp80GpO2Jd/GZDksLVw6Rl/C5LZMes8vWnZwbtwbXYE/HFef6Md -N+Xmcnql1DYYcM0Hda+dh3gX4kZplFBL1cF6g79k0NR7xjaemgYSaTiT66BI5lCG -gq0QAW16JcLLmqfjl2ecvga9tkIlBmpui//wAwBwQPuf0COrSOt5j+TI2kalkq9g -H9rQmQUq+CMjdygifvOo7aDnZ5xG0+Ci75J8/KpW1lRqrwARAQABiQIlBBgBCAAP -BQJZAfMlAhsMBQkSzAMAAAoJEDchGd+RR41tv8kP/2WUOnnNGTIrifFXhtiyz4d8 -+8P+UdyR9sXfAPMzdmaa+pgQqMe9S+RZDgIIKnfzhSqft+6aO7GOQxWjZvckMlMN -6Fx5C03awjYGSfIpfvy71OG3AqkvazbhhevbbPGtLuEiTHkAHyeASnlOfniTSLcH -wgZYlFS6z6yTeiHxHkvzPu253kyRDbKmq5QobBfknf7AFN5VwQf40wewZpLDcBsE -R6czWHrgUZCgYWQvKc9Hr7cVeFvgS9uMcrH+YDMhicKvA80Rvuc86YRo2QWAUNNs -BiSaRZmNXPX43nHHc8MeFItC6z1bMwETMP5EQWuvb4OOFA5rVSWH0rT+DuUp5VNY -2q7xk+DVYrcbuZ6JvlzJarbWdGtHc/g0Ox7dRrxxHJForQPkhyOrIPcqff/9W/aV -uiXjRfs6BH5UuHaDTY43yl90surWAq5pjE03iE95MhNocKneUXD4sO4v0055FNsc -NgiFHurQvdmqRvqOasqpRxmRev1oPm4kQDKZoN5UViugGIxUkzSrrKgNxhHcd8KM -NNrg9uoktzShmBFl0owUI8vvOPrjPW4wUjnu8EmBz33U7wgJNgnviFQjEuI+81be -Dzwgi4Sd0pxvk0aR5MukrAloMVQ5SGledrz+HVl2xRijTawp/3FklaJLnhVGeRgo -NePhdvUA5HTNLK8z+8L0 -=Azmw +tCRBbGV4YW5kZXIgS3VsYWsgPHNhLWRldkBvZGQuc3lzdGVtcz6JAlcEEwEIAEEC +GwMFCRLMAwAFCwkIBwIGFQgJCgsCBBYCAwECHgECF4AWIQQKlK7WfvVm3Pt8C7s3 +IRnfkUeNbQUCXCimgAIZAQAKCRA3IRnfkUeNbdRnD/oDK1eCz54EQme/egwZRrrI +mIL46Cn2BoN5S8vPjY+gpy9hI8U+tvR3xxaF6sgYSy+YIjUnDH+Cy3x6xcdI32+v +kfJSN6MRU53uo9q7NA7BbIvFhG7v3XMpHMsqLV7N++xNeaQ11HeUfXUZksq81AUt +chQwY3KytOiLzkdJK6ofBd0linCcFpY02O4q9VpLQUQRjfH5ScjWfCtKaAErd6oN +PCTq/XNFeerGhNYsIuGbZDyTFI6Z2Z41ch2ta0coLm2jgH0Eo0XhuX+mQJuhWHmm +9F2jPCW9eN7p3t5wA6MKf5D7jMDpNQKvVp9v368NljQrONTAmCnSVMKHO+guPBHX +K7p9GmRxitScB5s41cS1Cyz09o8sxQCaJiunAdNyci+JuhuORko7KZjIxBG2gPhV +udQT40W94UG2hg6HxZAkDRfp7viUF0qDqzu3wzwYKMWksisStkf817s/Un6kGS+X +CmpQnWZ+aXDOSnryjtKZbMPpkX74EpHAnCgYwhMIu1w2JvqrtsmUQrK1eDKNilX/ +S2t/SvNrUShgUWi3bHbCmbvPfmTjYo/yqhtu28zHCZmDc5YB1g2+pppv97uTexx8 +M2uqlZorGH3uDqYJzFqJcnr4+Gf+dG+qgKCxuKm1sv8UQ75eqtVRZTdtEl03aDKp +a2mW3bmTEQbM9wJg1tgmULQjQWxleGFuZGVyIEt1bGFrIDxzYS1kZXZAcmFpbmJv +dy5ieT6JAj8EEwEIACkFAlkB8yUCGwMFCRLMAwAHCwkIBwMCAQYVCAIJCgsEFgID +AQIeAQIXgAAKCRA3IRnfkUeNbeS0D/4397Vq/jgEOX+qaztPgsZMRUIc61rLgWok +8u3Sx9u1TF47hFg0WHM9CL/p9EEGGU68SvijRARSV7vyHgSLlMge7bpiGL4Aw9pj +h1QtG56gWL6lhtjJ6G6slaU7+ShEHyvIw1WccSt5EnU9ErWtP638ikEZloPmmwFU +Vks+RepQr/yD1xEoUTzAFaF+XAPs2MkBHICi71TUplf83a9+FB+N5BgY0kXCTXnp +rSvn3mfgMWsQ43OYcLPQ8vJo9aiBd+X+NKMMCCI/0UXOYdwsz3M5L4Mj+RQ6ItPk +HL0i65zfCX2P6Q5gUbwL3+ArMLv5xzjaFEiw/y3KHhA3s7m59zxeWax9OKfS0Vyc +RT2Wejt1IavVaFqK+d9f5JHfONSc/p+zmts2/GCU71PmWtQG3C2RNCUwTUxejV+g +Bj6qHRz0JNHd2b2/oLQrZHvDmYAAxo1h+ms8VVtlCJTNLywwhUKyAGb+pQLwfNse +cdMZvknYbp6ghGju6si2KlqokX1HLTie7j2KsTlArd7uTbiHQ1pu4w0WzHa86AKg +0L35bo0XdPPYfX+H5ZV4FCmR9im9Fmip6Mi1ZcbO9OEhfDCVDaa9VdrHd0Skxkf1 +2FScVZI7kmElI8x5/JVS+esYJlEFYGt2PIx9XuAJnkCJGyphPHs7Mb+k9ddk4bLS +gmBgZUDSIbkCDQRZAfMlARAA5eb0qB0J5kxuRzrhZWwFNgwulZyPiDJwWw4F8QTA +ia4TfjjLLQW5dDpnHr+rxl0Sw3XBsz66I5ZYJczi4wR1yMJHiWfeVFSVbcKoTlYk +/WGXVT78b41Txj/h3JDupF6Mykv1JJFqd/8AyNMlAblZSa/vz6FF7ETxEo10/gkl +vXT2rS7pvsh67UD3vLmx15ZZF4jy++eQ0pzNe45l2rCt3Jvkj6FwaOFEzGTh3ufj +gSAhcpGakC+AMnNwFL56xLy7q4nL2HeWqLQOTK9jWR2suCFlz0hiaMQ1UCG6xhDZ +ASLc7bW/5wtaUulszl26mlHmfKFYlWIwDT+L6OT3dQHX2JuGug+fgrBTH4hwAIon +ixPjVV/YFIR9+/0gml4u7tcfmqLIoCkzwxA1ioRtRgloM6/pOuqGcRxG1quYmD7L +F2RpP87liufLuTKGnmsafI+WXXbTgyYxa7gKfNBqTtiXfxmQ5LC1cOkZfwuS2THr +PL1p2cG7cG12BPxxXn+jHTfl5nJ6pdQ2GHDNB3WvnYd4F+JGaZRQS9XBeoO/ZNDU +e8Y2npoGEmk4k+ugSOZQhoKtEAFteiXCy5qn45dnnL4GvbZCJQZqbov/8AMAcED7 +n9Ajq0jreY/kyNpGpZKvYB/a0JkFKvgjI3coIn7zqO2g52ecRtPgou+SfPyqVtZU +aq8AEQEAAYkCJQQYAQgADwUCWQHzJQIbDAUJEswDAAAKCRA3IRnfkUeNbb/JD/9l +lDp5zRkyK4nxV4bYss+HfPvD/lHckfbF3wDzM3ZmmvqYEKjHvUvkWQ4CCCp384Uq +n7fumjuxjkMVo2b3JDJTDehceQtN2sI2BknyKX78u9ThtwKpL2s24YXr22zxrS7h +Ikx5AB8ngEp5Tn54k0i3B8IGWJRUus+sk3oh8R5L8z7tud5MkQ2ypquUKGwX5J3+ +wBTeVcEH+NMHsGaSw3AbBEenM1h64FGQoGFkLynPR6+3FXhb4EvbjHKx/mAzIYnC +rwPNEb7nPOmEaNkFgFDTbAYkmkWZjVz1+N5xx3PDHhSLQus9WzMBEzD+REFrr2+D +jhQOa1Ulh9K0/g7lKeVTWNqu8ZPg1WK3G7meib5cyWq21nRrR3P4NDse3Ua8cRyR +aK0D5IcjqyD3Kn3//Vv2lbol40X7OgR+VLh2g02ON8pfdLLq1gKuaYxNN4hPeTIT +aHCp3lFw+LDuL9NOeRTbHDYIhR7q0L3Zqkb6jmrKqUcZkXr9aD5uJEAymaDeVFYr +oBiMVJM0q6yoDcYR3HfCjDTa4PbqJLc0oZgRZdKMFCPL7zj64z1uMFI57vBJgc99 +1O8ICTYJ74hUIxLiPvNW3g88IIuEndKcb5NGkeTLpKwJaDFUOUhpXna8/h1ZdsUY +o02sKf9xZJWiS54VRnkYKDXj4Xb1AOR0zSyvM/vC9A== +=S7LU -----END PGP PUBLIC KEY BLOCK----- diff -Nru alttab-1.3.0/depcomp alttab-1.5.0/depcomp --- alttab-1.3.0/depcomp 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/depcomp 2020-07-23 08:24:20.000000000 +0000 @@ -1,9 +1,9 @@ #! /bin/sh # depcomp - compile a program generating dependencies as side-effects -scriptversion=2013-05-30.07; # UTC +scriptversion=2018-03-07.03; # UTC -# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Copyright (C) 1999-2018 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -16,7 +16,7 @@ # GNU General Public License for more details. # You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -783,9 +783,9 @@ # Local Variables: # mode: shell-script # sh-indentation: 2 -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC" +# time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: diff -Nru alttab-1.3.0/doc/alttab.1 alttab-1.5.0/doc/alttab.1 --- alttab-1.3.0/doc/alttab.1 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/doc/alttab.1 2020-07-23 08:24:20.000000000 +0000 @@ -1,13 +1,13 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "ALTTAB" "1" "April 2018" "" "" +.TH "ALTTAB" "1" "July 2020" "" "" . .SH "NAME" \fBalttab\fR \- the task switcher . .SH "SYNOPSIS" -\fBalttab\fR [\fB\-w\fR \fIN\fR] [\fB\-d\fR \fIN\fR] [\fB\-sc\fR \fIN\fR] [\fB\-mk\fR \fIstr\fR] [\fB\-kk\fR \fIstr\fR] [\fB\-bk\fR \fIstr\fR] [\fB\-mm\fR \fIN\fR] [\fB\-bm\fR \fIN\fR] [\fB\-t\fR \fINxM\fR] [\fB\-i\fR \fINxM\fR] [\fB\-vp\fR \fIstr\fR] [\fB\-p\fR \fIstr\fR] [\fB\-s\fR \fIN\fR] [\fB\-theme\fR \fIname\fR] [\fB\-bg\fR \fIcolor\fR] [\fB\-fg\fR \fIcolor\fR] [\fB\-frame\fR \fIcolor\fR] [\fB\-font\fR \fIname\fR] [\fB\-v\fR|\fB\-vv\fR] +\fBalttab\fR [\fB\-w\fR \fIN\fR] [\fB\-d\fR \fIN\fR] [\fB\-sc\fR \fIN\fR] [\fB\-mk\fR \fIstr\fR] [\fB\-kk\fR \fIstr\fR] [\fB\-bk\fR \fIstr\fR] [\fB\-pk\fR \fIstr\fR] [\fB\-nk\fR \fIstr\fR] [\fB\-ck\fR \fIstr\fR] [\fB\-mm\fR \fIN\fR] [\fB\-bm\fR \fIN\fR] [\fB\-t\fR \fINxM\fR] [\fB\-i\fR \fINxM\fR] [\fB\-vp\fR \fIstr\fR] [\fB\-p\fR \fIstr\fR] [\fB\-s\fR \fIN\fR] [\fB\-theme\fR \fIname\fR] [\fB\-bg\fR \fIcolor\fR] [\fB\-fg\fR \fIcolor\fR] [\fB\-frame\fR \fIcolor\fR] [\fB\-font\fR \fIname\fR] [\fB\-v\fR|\fB\-vv\fR] . .SH "DESCRIPTION" The task switcher designed for minimalistic window managers or standalone X11 session\. @@ -136,6 +136,36 @@ Keysym of backward scroll key\. . .TP +\fB\-pk\fR \fIstr\fR +resource: alttab\.prevkey\.keysym +. +.br +default: no key assigned +. +.IP +Keysym of auxiliary \'previous\' key\. For example, Left, H\. +. +.TP +\fB\-nk\fR \fIstr\fR +resource: alttab\.nextkey\.keysym +. +.br +default: no key assigned +. +.IP +Keysym of auxiliary \'next\' key\. For example, Right, L\. +. +.TP +\fB\-ck\fR \fIstr\fR +resource: alttab\.cancelkey\.keysym +. +.br +default: Escape +. +.IP +Keysym of auxiliary \'cancel\' key\. For example, Escape\. +. +.TP \fB\-mm\fR \fINUM\fR resource: alttab\.modifier\.mask . @@ -177,7 +207,7 @@ default: \fIfocus\fR . .IP -Limit viewport for the switcher\. The switcher always has variable size and position, but tries to never break out of \fB\-vp\fR container, while \fB\-p\fR specifies position relative to this container\. Together these options allow for multi\-monitor support\. Possible values for \fB\-vp\fR: +Limit viewport for the switcher\. The switcher always has variable size and position, but tries to never break out of \fB\-vp\fR container, while \fB\-p\fR specifies position relative to this container\. Together these options allow for WM\-independent multi\-monitor support\. Possible values for \fB\-vp\fR: . .IP \fIfocus\fR: in multihead configuration: the monitor which shows largest part of currently focused window\. If this part is shared with other monitors, then the smallest of these monitors is choosen\. In single head configuration: the geometry of default root window\. @@ -192,13 +222,13 @@ \fItotal\fR: the geometry of default root window\. . .IP -If you specify this in tiling multihead, then the switcher will be drawn relative to the entire combined screen, crossing monitors\' borders\. +If you specify this in tiling multihead configuration, then the switcher will be drawn relative to the entire combined screen, crossing monitors\' borders\. . .IP \fIWxH+X+Y\fR: Specific position relative to default root window\. . .IP -This allows for static manual bounding if XRANDR detection fails\. Suppose X operates in tiling configuration for two 2560х1440 monitors, resulting in combined screen of 5120x1440 size\. Then the switcher may be positioned at the center of the right monitor with \-vp 2560x1440+2560+0 \-p center\. +This allows for static manual bounding if XRANDR detection fails\. Suppose X root window spans over two 2560х1440 monitors, resulting in combined screen of 5120x1440 size\. Then the switcher may be positioned at the center of the right monitor with \-vp 2560x1440+2560+0 \-p center\. . .TP \fB\-p\fR \fIstr\fR @@ -227,7 +257,7 @@ \fI1\fR: Load icon from file if not found in window attributes\. . .IP -Alttab searches for PNG icons under: +Alttab searches for PNG and XPM icons in $XDG_DATA_DIRS and also under: . .IP /usr/share/icons @@ -245,6 +275,15 @@ Directory structure should obey freedesktop standard, but desktop files are ignored, instead file name is expected to be equal to application class\. That is, if alttab doesn\'t recognize an icon for window of class foo, as obtained by \'xprop WM_CLASS\', then just drop a 32x32 icon into /usr/local/share/icons/hicolor/32x32/apps/foo\.png\. . .IP +Also, alttab scans for icons in legacy directories without freedesktop directory structure: +. +.IP +/usr/share/pixmaps +. +.br +~/\.local/share/pixmaps +. +.IP \fI2\fR: Prefer icon from file when it matches requested size better (see \fB\-i\fR option)\. . .IP @@ -333,7 +372,7 @@ Run alttab after WM, or autodetection will fail\. . .SH "AUTHOR" -Copyright 2017\-2018 Alexander Kulak \fB\fR\. +Copyright 2017\-2020 Alexander Kulak \fB\fR\. . .SH "REPORTING BUGS" Please report issues on github \fIhttps://github\.com/sagb/alttab/issues\fR\. diff -Nru alttab-1.3.0/doc/alttab.1.ronn alttab-1.5.0/doc/alttab.1.ronn --- alttab-1.3.0/doc/alttab.1.ronn 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/doc/alttab.1.ronn 2020-07-23 08:24:20.000000000 +0000 @@ -2,7 +2,7 @@ The source of alttab.1. Read doc/development.md. vim:ft=markdown -Copyright 2017-2018 Alexander Kulak. +Copyright 2017-2020 Alexander Kulak. This file is part of alttab program. Copying and distribution of this file, with or without modification, @@ -16,7 +16,7 @@ ## SYNOPSIS -`alttab` [`-w` ] [`-d` ] [`-sc` ] [`-mk` ] [`-kk` ] [`-bk` ] [`-mm` ] [`-bm` ] [`-t` ] [`-i` ] [`-vp` ] [`-p` ] [`-s` ] [`-theme` ] [`-bg` ] [`-fg` ] [`-frame` ] [`-font` ] [`-v`|`-vv`] +`alttab` [`-w` ] [`-d` ] [`-sc` ] [`-mk` ] [`-kk` ] [`-bk` ] [`-pk` ] [`-nk` ] [`-mm` ] [`-bm` ] [`-t` ] [`-i` ] [`-vp` ] [`-p` ] [`-s` ] [`-theme` ] [`-bg` ] [`-fg` ] [`-frame` ] [`-font` ] [`-v`|`-vv`] ## DESCRIPTION @@ -120,6 +120,26 @@ Keysym of backward scroll key. + * `-pk` : + resource: alttab.prevkey.keysym + default: no key assigned + + Keysym of auxiliary 'previous' key. + For example, Left, H. + + * `-nk` : + resource: alttab.nextkey.keysym + default: no key assigned + + Keysym of auxiliary 'next' key. + For example, Right, L. + + * `-ck` : + resource: alttab.cancelkey.keysym + default: Escape + + Keysym of auxiliary 'cancel' key. + * `-mm` : resource: alttab.modifier.mask @@ -150,7 +170,7 @@ The switcher always has variable size and position, but tries to never break out of `-vp` container, while `-p` specifies position relative to this container. - Together these options allow for multi-monitor support. + Together these options allow for WM-independent multi-monitor support. Possible values for `-vp`: : in multihead configuration: the monitor which shows @@ -167,14 +187,14 @@ : the geometry of default root window. - If you specify this in tiling multihead, then the switcher - will be drawn relative to the entire combined screen, crossing - monitors' borders. + If you specify this in tiling multihead configuration, then + the switcher will be drawn relative to the entire combined screen, + crossing monitors' borders. : Specific position relative to default root window. This allows for static manual bounding if XRANDR detection fails. - Suppose X operates in tiling configuration for two 2560х1440 monitors, + Suppose X root window spans over two 2560х1440 monitors, resulting in combined screen of 5120x1440 size. Then the switcher may be positioned at the center of the right monitor with -vp 2560x1440+2560+0 -p center. @@ -196,7 +216,7 @@ <1>: Load icon from file if not found in window attributes. - Alttab searches for PNG icons under: + Alttab searches for PNG and XPM icons in $XDG_DATA_DIRS and also under: /usr/share/icons /usr/local/share/icons @@ -208,6 +228,12 @@ That is, if alttab doesn't recognize an icon for window of class foo, as obtained by 'xprop WM_CLASS', then just drop a 32x32 icon into /usr/local/share/icons/hicolor/32x32/apps/foo.png. + + Also, alttab scans for icons in legacy directories without freedesktop directory + structure: + + /usr/share/pixmaps + ~/.local/share/pixmaps <2>: Prefer icon from file when it matches requested size better (see `-i` option). @@ -266,7 +292,7 @@ ##AUTHOR -Copyright 2017-2018 Alexander Kulak ``. +Copyright 2017-2020 Alexander Kulak ``. ##REPORTING BUGS diff -Nru alttab-1.3.0/doc/alttab.ad alttab-1.5.0/doc/alttab.ad --- alttab-1.3.0/doc/alttab.ad 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/doc/alttab.ad 2020-07-23 08:24:20.000000000 +0000 @@ -25,6 +25,14 @@ ! grave (back apostrophe) instead of Tab !alttab.key.keysym: grave +! auxiliary 'previous' key +!alttab.prevkey.keysym: Left +! auxiliary 'next' key +!alttab.nextkey.keysym: Right + +! auxiliary 'cancel' key +!alttab.cancelkey.keysym: Escape + ! Limit the switcher to this rectangle ! instead of default screen size !alttab.viewport: 1280x1024+1280+0 diff -Nru alttab-1.3.0/doc/development.md alttab-1.5.0/doc/development.md --- alttab-1.3.0/doc/development.md 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/doc/development.md 2020-07-23 08:24:20.000000000 +0000 @@ -1,10 +1,15 @@ -repository, bug reporting +Stability +--------- + +Alttab is considered stable. + +Repository, bug reporting ------------------------- [On github](https://github.com/sagb/alttab). -maintainer script +Maintainer script ----------------- To rebuild autotools stuff use bootstrap.sh. @@ -14,7 +19,7 @@ This is not included in makefiles to not require casual user to install ronn. -coding +Coding ------ Functions return 0 on failure, positive on success. @@ -22,7 +27,7 @@ adheres to the following: * Satisfy `-Wall` compiler option -* Use Linux coding style (indent -linux) +* Use the following indent: `indent -nbad -bap -nbc -bbo -hnl -br -brs -c33 -cd33 -ncdb -ce -ci4 -cli0 -d0 -di1 -nfc1 -i4 -ip0 -l80 -lp -npcs -nprs -npsl -sai -saf -saw -ncs -nsc -sob -nfca -cp33 -ss -ts4 -il1 -nut` * Pass Clang Static Analyzer check (scan-build make) without warnings, except of those about uthash internals and obvious false-positives The only global variables are: g, dpy, scr, root, ee\_complain. diff -Nru alttab-1.3.0/doc/Makefile.in alttab-1.5.0/doc/Makefile.in --- alttab-1.3.0/doc/Makefile.in 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/doc/Makefile.in 2020-07-23 08:24:20.000000000 +0000 @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.15.1 from Makefile.am. +# Makefile.in generated by automake 1.16.2 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2017 Free Software Foundation, Inc. +# Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -250,6 +250,8 @@ x11_LIBS = @x11_LIBS@ xft_CFLAGS = @xft_CFLAGS@ xft_LIBS = @xft_LIBS@ +xpm_CFLAGS = @xpm_CFLAGS@ +xpm_LIBS = @xpm_LIBS@ xrandr_CFLAGS = @xrandr_CFLAGS@ xrandr_LIBS = @xrandr_LIBS@ xrender_CFLAGS = @xrender_CFLAGS@ @@ -276,8 +278,8 @@ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) @@ -359,7 +361,10 @@ cscope cscopelist: -distdir: $(DISTFILES) +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ diff -Nru alttab-1.3.0/doc/README alttab-1.5.0/doc/README --- alttab-1.3.0/doc/README 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/doc/README 2020-07-23 08:24:20.000000000 +0000 @@ -2,8 +2,9 @@ or standalone X11 session. alttab [-w N] [-d N] [-sc N] [`-mk` ] [`-kk` ] [`-bk` ] - [`-mm` ] [`-bm` ] [-t NxM] [-i NxM] [-vp str] [-p str] [-s N] - [-theme name] [-bg color] [-fg color] [-frame color] [-font name] [-v|-vv] + [`-pk` ] [`-nk` ] [`-ck` ] [`-mm` ] [`-bm` ] + [-t NxM] [-i NxM] [-vp str] [-p str] [-s N] [-theme name] [-bg color] + [-fg color] [-frame color] [-font name] [-v|-vv] (see man page for details) @@ -29,10 +30,11 @@ Source ------ -Copyright 2017-2018 Alexander Kulak . +Copyright 2017-2020 Alexander Kulak . License: GPLv3 (see COPYING). Repository: https://github.com/sagb/alttab Chat: #alttab on Freenode - -- Alexander Kulak Fri, 28 Apr 2017 13:19:28 +0300 + + -- Alexander Kulak Fri, 28 Apr 2017 13:19:28 +0300 Binary files /tmp/tmpJ1k9Dq/bbppLSU1M2/alttab-1.3.0/doc/screenshots/alttab-jtaala.png and /tmp/tmpJ1k9Dq/GFwuAW5k0u/alttab-1.5.0/doc/screenshots/alttab-jtaala.png differ diff -Nru alttab-1.3.0/doc/screenshots/screenshots.md alttab-1.5.0/doc/screenshots/screenshots.md --- alttab-1.3.0/doc/screenshots/screenshots.md 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/doc/screenshots/screenshots.md 2020-07-23 08:24:20.000000000 +0000 @@ -1,14 +1,27 @@ Screenshots of alttab ===================== -![Default options, raw X11](alttab-default-rawx.png?raw=true) +## Default options, raw X11 session. -Default options, raw X11 session. +![Default options, raw X11](alttab-default-rawx.png?raw=true)     -![Low DPI](alttab-high.png?raw=true) +## Low DPI + +![Low DPI](alttab-high.png?raw=true) ``` alttab -font "xft:DejaVu Sans Condensed-10" -bg '#c3c6b7' -frame darkblue -t 100x100 -i 16x16 -s 2 ``` +  +  + +## Translucent + +![Translucent](alttab-jtaala.png?raw=true) +``` +alttab -fg "#d58681" -bg "#4a4a4a" -frame "#eb564d" -t 128x150 -i 127x64 +``` +© Jay Ta'ala +([source](https://confluence.jaytaala.com/display/TKB/My+Manjaro+i3+setup#MyManjaroi3setup-Ricingalttab)) diff -Nru alttab-1.3.0/doc/wm-setup.md alttab-1.5.0/doc/wm-setup.md --- alttab-1.3.0/doc/wm-setup.md 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/doc/wm-setup.md 2020-07-23 08:24:20.000000000 +0000 @@ -34,7 +34,7 @@ metacity/MATE| 1 (auto) | see "MATE" section below | jwm | 1 (auto) | comment A-Tab entry in .jwmrc | see "jwm" section below openbox | 1 (auto) | see "openbox" section below | -fluxbox | 1 (auto) | see "fluxbox" section below | `alttab &` in ~/.fluxbox/startup +fluxbox | 1 (auto) | see "fluxbox" section below | see "fluxbox" section below icewm | 1 (auto) | ? | ? matchbox | 1 (auto, partial support) | doesn't grab | ? enlightenment| 1 (auto) | ? | ? @@ -129,9 +129,16 @@ #Mod1 Shift Tab :PrevWindow {groups} (workspace=[current]) ### startup -In ~/.fluxbox/startup: +To start alttab _after_ fluxbox, in `~/.fluxbox/startup` replace `exec fluxbox` with: - ...other apps... - alttab & - exec fluxbox + fluxbox & + fbpid=$! + sleep 3 + { + alttab & + # ...other apps to run after fluxbox startup... + } & + wait $fbpid + +Details [here](http://fluxbox-wiki.org/Editing_the_startup_file.html). diff -Nru alttab-1.3.0/INSTALL.md alttab-1.5.0/INSTALL.md --- alttab-1.3.0/INSTALL.md 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/INSTALL.md 2020-07-23 08:24:20.000000000 +0000 @@ -27,6 +27,13 @@ * In Alpine Linux, alttab is in _aports/testing_ repository. +* In openSUSE, alttab is available in Tumbleweed and from the [X11:Utilities](https://build.opensuse.org/package/show/X11:Utilities/alttab) repository: + + ``` + zypper ar -f obs://X11:Utilities x11utils + zypper ref + zypper in alttab + ``` Building from source -------------------- diff -Nru alttab-1.3.0/install-sh alttab-1.5.0/install-sh --- alttab-1.3.0/install-sh 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/install-sh 2020-07-23 08:24:20.000000000 +0000 @@ -1,7 +1,7 @@ #!/bin/sh # install - install a program, script, or datafile -scriptversion=2011-11-20.07; # UTC +scriptversion=2018-03-11.20; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the @@ -41,19 +41,15 @@ # This script is compatible with the BSD install script, but was written # from scratch. +tab=' ' nl=' ' -IFS=" "" $nl" +IFS=" $tab$nl" -# set DOITPROG to echo to test this script +# Set DOITPROG to "echo" to test this script. -# Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} -if test -z "$doit"; then - doit_exec=exec -else - doit_exec=$doit -fi +doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. @@ -68,17 +64,6 @@ rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} -posix_glob='?' -initialize_posix_glob=' - test "$posix_glob" != "?" || { - if (set -f) 2>/dev/null; then - posix_glob= - else - posix_glob=: - fi - } -' - posix_mkdir= # Desired mode of installed file. @@ -97,7 +82,7 @@ dst_arg= copy_on_change=false -no_target_directory= +is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE @@ -137,46 +122,57 @@ -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" - shift;; + shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 - case $mode in - *' '* | *' '* | *' -'* | *'*'* | *'?'* | *'['*) - echo "$0: invalid mode: $mode" >&2 - exit 1;; - esac - shift;; + case $mode in + *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; -o) chowncmd="$chownprog $2" - shift;; + shift;; -s) stripcmd=$stripprog;; - -t) dst_arg=$2 - # Protect names problematic for 'test' and other utilities. - case $dst_arg in - -* | [=\(\)!]) dst_arg=./$dst_arg;; - esac - shift;; + -t) + is_target_a_directory=always + dst_arg=$2 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; - -T) no_target_directory=true;; + -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; - --) shift - break;; + --) shift + break;; - -*) echo "$0: invalid option: $1" >&2 - exit 1;; + -*) echo "$0: invalid option: $1" >&2 + exit 1;; *) break;; esac shift done +# We allow the use of options -d and -T together, by making -d +# take the precedence; this is for compatibility with GNU install. + +if test -n "$dir_arg"; then + if test -n "$dst_arg"; then + echo "$0: target directory not allowed when installing a directory." >&2 + exit 1 + fi +fi + if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. @@ -208,6 +204,15 @@ fi if test -z "$dir_arg"; then + if test $# -gt 1 || test "$is_target_a_directory" = always; then + if test ! -d "$dst_arg"; then + echo "$0: $dst_arg: Is not a directory." >&2 + exit 1 + fi + fi +fi + +if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 @@ -223,16 +228,16 @@ *[0-7]) if test -z "$stripcmd"; then - u_plus_rw= + u_plus_rw= else - u_plus_rw='% 200' + u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then - u_plus_rw= + u_plus_rw= else - u_plus_rw=,u+rw + u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac @@ -266,129 +271,113 @@ fi dst=$dst_arg - # If destination is a directory, append the input filename; won't work - # if double slashes aren't ignored. + # If destination is a directory, append the input filename. if test -d "$dst"; then - if test -n "$no_target_directory"; then - echo "$0: $dst_arg: Is a directory" >&2 - exit 1 + if test "$is_target_a_directory" = never; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 fi dstdir=$dst - dst=$dstdir/`basename "$src"` + dstbase=`basename "$src"` + case $dst in + */) dst=$dst$dstbase;; + *) dst=$dst/$dstbase;; + esac dstdir_status=0 else - # Prefer dirname, but fall back on a substitute if dirname fails. - dstdir=` - (dirname "$dst") 2>/dev/null || - expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$dst" : 'X\(//\)[^/]' \| \ - X"$dst" : 'X\(//\)$' \| \ - X"$dst" : 'X\(/\)' \| . 2>/dev/null || - echo X"$dst" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q' - ` - + dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi + case $dstdir in + */) dstdirslash=$dstdir;; + *) dstdirslash=$dstdir/;; + esac + obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') - # Create intermediate dirs using mode 755 as modified by the umask. - # This is like FreeBSD 'install' as of 1997-10-28. - umask=`umask` - case $stripcmd.$umask in - # Optimize common cases. - *[2367][2367]) mkdir_umask=$umask;; - .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; - - *[0-7]) - mkdir_umask=`expr $umask + 22 \ - - $umask % 100 % 40 + $umask % 20 \ - - $umask % 10 % 4 + $umask % 2 - `;; - *) mkdir_umask=$umask,go-w;; - esac - - # With -d, create the new directory with the user-specified mode. - # Otherwise, rely on $mkdir_umask. - if test -n "$dir_arg"; then - mkdir_mode=-m$mode - else - mkdir_mode= - fi - - posix_mkdir=false - case $umask in - *[123567][0-7][0-7]) - # POSIX mkdir -p sets u+wx bits regardless of umask, which - # is incompatible with FreeBSD 'install' when (umask & 300) != 0. - ;; - *) - # $RANDOM is not portable (e.g. dash); use it when possible to - # lower collision chance - tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ - trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0 - - # As "mkdir -p" follows symlinks and we work in /tmp possibly; so - # create the $tmpdir first (and fail if unsuccessful) to make sure - # that nobody tries to guess the $tmpdir name. - if (umask $mkdir_umask && - $mkdirprog $mkdir_mode "$tmpdir" && - exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 - then - if test -z "$dir_arg" || { - # Check for POSIX incompatibilities with -m. - # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or - # other-writable bit of parent directory when it shouldn't. - # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. - test_tmpdir="$tmpdir/a" - ls_ld_tmpdir=`ls -ld "$test_tmpdir"` - case $ls_ld_tmpdir in - d????-?r-*) different_mode=700;; - d????-?--*) different_mode=755;; - *) false;; - esac && - $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { - ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` - test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" - } - } - then posix_mkdir=: - fi - rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" - else - # Remove any dirs left behind by ancient mkdir implementations. - rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null - fi - trap '' 0;; - esac;; + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + # Note that $RANDOM variable is not portable (e.g. dash); Use it + # here however when possible just to lower collision chance. + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + + trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0 + + # Because "mkdir -p" follows existing symlinks and we likely work + # directly in world-writeable /tmp, make sure that the '$tmpdir' + # directory is successfully created first before we actually test + # 'mkdir -p' feature. + if (umask $mkdir_umask && + $mkdirprog $mkdir_mode "$tmpdir" && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + test_tmpdir="$tmpdir/a" + ls_ld_tmpdir=`ls -ld "$test_tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null + fi + trap '' 0;; + esac;; esac if $posix_mkdir && ( - umask $mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else @@ -398,53 +387,51 @@ # directory the slow way, step by step, checking for races as we go. case $dstdir in - /*) prefix='/';; - [-=\(\)!]*) prefix='./';; - *) prefix='';; + /*) prefix='/';; + [-=\(\)!]*) prefix='./';; + *) prefix='';; esac - eval "$initialize_posix_glob" - oIFS=$IFS IFS=/ - $posix_glob set -f + set -f set fnord $dstdir shift - $posix_glob set +f + set +f IFS=$oIFS prefixes= for d do - test X"$d" = X && continue + test X"$d" = X && continue - prefix=$prefix$d - if test -d "$prefix"; then - prefixes= - else - if $posix_mkdir; then - (umask=$mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break - # Don't fail if two instances are running concurrently. - test -d "$prefix" || exit 1 - else - case $prefix in - *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; - *) qprefix=$prefix;; - esac - prefixes="$prefixes '$qprefix'" - fi - fi - prefix=$prefix/ + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ done if test -n "$prefixes"; then - # Don't fail if two instances are running concurrently. - (umask $mkdir_umask && - eval "\$doit_exec \$mkdirprog $prefixes") || - test -d "$dstdir" || exit 1 - obsolete_mkdir_used=true + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true fi fi fi @@ -457,8 +444,8 @@ else # Make a couple of temp file names in the proper directory. - dsttmp=$dstdir/_inst.$$_ - rmtmp=$dstdir/_rm.$$_ + dsttmp=${dstdirslash}_inst.$$_ + rmtmp=${dstdirslash}_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 @@ -479,15 +466,12 @@ # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && - old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && - new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && - - eval "$initialize_posix_glob" && - $posix_glob set -f && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && - $posix_glob set +f && - + set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then @@ -500,24 +484,24 @@ # to itself, or perhaps because mv is so ancient that it does not # support -f. { - # Now remove or move aside any old file at destination location. - # We try this two ways since rm can't unlink itself on some - # systems and the destination file might be busy for other - # reasons. In this case, the final cleanup might fail but the new - # file should still install successfully. - { - test ! -f "$dst" || - $doit $rmcmd -f "$dst" 2>/dev/null || - { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && - { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } - } || - { echo "$0: cannot unlink or rename $dst" >&2 - (exit 1); exit 1 - } - } && + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && - # Now rename the file to the real destination. - $doit $mvcmd "$dsttmp" "$dst" + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 @@ -526,9 +510,9 @@ done # Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC" +# time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: diff -Nru alttab-1.3.0/Makefile.in alttab-1.5.0/Makefile.in --- alttab-1.3.0/Makefile.in 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/Makefile.in 2020-07-23 08:24:20.000000000 +0000 @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.15.1 from Makefile.am. +# Makefile.in generated by automake 1.16.2 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2017 Free Software Foundation, Inc. +# Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -132,9 +132,9 @@ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ - cscope distdir dist dist-all distcheck -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ - $(LISP)config.h.in + cscope distdir distdir-am dist dist-all distcheck +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) \ + config.h.in # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. @@ -298,6 +298,8 @@ x11_LIBS = @x11_LIBS@ xft_CFLAGS = @xft_CFLAGS@ xft_LIBS = @xft_LIBS@ +xpm_CFLAGS = @xpm_CFLAGS@ +xpm_LIBS = @xpm_LIBS@ xrandr_CFLAGS = @xrandr_CFLAGS@ xrandr_LIBS = @xrandr_LIBS@ xrender_CFLAGS = @xrender_CFLAGS@ @@ -328,8 +330,8 @@ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) @@ -462,7 +464,10 @@ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files -distdir: $(DISTFILES) +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ @@ -542,6 +547,10 @@ tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) +dist-zstd: distdir + tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst + $(am__post_remove_distdir) + dist-tarZ: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @@ -584,6 +593,8 @@ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ + *.tar.zst*) \ + zstd -dc $(distdir).tar.zst | $(am__untar) ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) @@ -760,7 +771,7 @@ am--refresh check check-am clean clean-cscope clean-generic \ cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ - distcheck distclean distclean-generic distclean-hdr \ + dist-zstd distcheck distclean distclean-generic distclean-hdr \ distclean-tags distcleancheck distdir distuninstallcheck dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ diff -Nru alttab-1.3.0/missing alttab-1.5.0/missing --- alttab-1.3.0/missing 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/missing 2020-07-23 08:24:20.000000000 +0000 @@ -1,9 +1,9 @@ #! /bin/sh # Common wrapper for a few potentially missing GNU programs. -scriptversion=2013-10-28.13; # UTC +scriptversion=2018-03-07.03; # UTC -# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# Copyright (C) 1996-2018 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify @@ -17,7 +17,7 @@ # GNU General Public License for more details. # You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -101,9 +101,9 @@ exit $st fi -perl_URL=http://www.perl.org/ -flex_URL=http://flex.sourceforge.net/ -gnu_software_URL=http://www.gnu.org/software +perl_URL=https://www.perl.org/ +flex_URL=https://github.com/westes/flex +gnu_software_URL=https://www.gnu.org/software program_details () { @@ -207,9 +207,9 @@ exit $st # Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC" +# time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: diff -Nru alttab-1.3.0/README.md alttab-1.5.0/README.md --- alttab-1.3.0/README.md 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/README.md 2020-07-23 08:24:20.000000000 +0000 @@ -4,6 +4,8 @@ ![Low DPI](doc/screenshots/alttab-high.png?raw=true) +![Translucent](doc/screenshots/alttab-jtaala.png?raw=true) + [screenshot options](doc/screenshots/screenshots.md) [![chat on freenode](https://img.shields.io/badge/chat-on%20freenode-brightgreen.svg)](https://webchat.freenode.net/?channels=%23alttab) @@ -11,8 +13,9 @@ **alttab** is X11 window switcher designed for minimalistic window managers or standalone X11 session. ``` - alttab [-w N] [-d N] [-sc N] [-mk str] [-kk str] [-bk str] [-mm N] [-bm N] - [-t NxM] [-i NxM] [-vp str] [-p str] [-s N] [-theme name] [-bg color] + alttab [-w N] [-d N] [-sc N] [`-mk` ] [`-kk` ] [`-bk` ] + [`-pk` ] [`-nk` ] [`-ck` ] [`-mm` ] [`-bm` ] + [-t NxM] [-i NxM] [-vp str] [-p str] [-s N] [-theme name] [-bg color] [-fg color] [-frame color] [-font name] [-v|-vv] ``` (see man page for details) @@ -41,5 +44,5 @@ [no-wm](https://github.com/patrickhaller/no-wm): use X11 without a window manager     -alttab (C) Alexander Kulak <sa-dev AT rainbow POINT by> 2016-2018 +alttab (C) Alexander Kulak <sa-dev AT odd POINT systems> 2016-2020 diff -Nru alttab-1.3.0/src/alttab.c alttab-1.5.0/src/alttab.c --- alttab-1.3.0/src/alttab.c 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/src/alttab.c 2020-07-23 08:24:20.000000000 +0000 @@ -1,7 +1,7 @@ /* Parsing options/resources, top-level keygrab functions and main(). -Copyright 2017-2018 Alexander Kulak. +Copyright 2017-2020 Alexander Kulak. This file is part of alttab program. alttab is free software: you can redistribute it and/or modify @@ -34,18 +34,19 @@ Globals g; // globals common for alttab, util and icon -Display* dpy; +Display *dpy; int scr; Window root; // PRIVATE +static XrmDatabase db; // // help and exit // -void helpexit() +static void helpexit() { - msg(-1, "the task switcher, v%s\n\ + msg(-1, "the task switcher, v%s\n\ Options:\n\ -w N window manager: 0=no, 1=ewmh-compatible, 2=ratpoison, 3=old fashion\n\ -d N desktop: 0=current 1=all, 2=all but special, 3=all but current\n\ @@ -53,6 +54,8 @@ -kk str keysym of main key\n\ -mk str keysym of main modifier\n\ -bk str keysym of backscroll modifier\n\ + -pk str keysym of 'prev' key\n\ + -nk str keysym of 'next' key\n\ -mm N (obsoleted) main modifier mask\n\ -bm N (obsoleted) backward scroll modifier mask\n\ -t NxM tile geometry\n\ @@ -68,7 +71,7 @@ -v|-vv verbose\n\ -h help\n\ See man alttab for details.\n", PACKAGE_VERSION); - exit(0); + exit(0); } // @@ -76,85 +79,85 @@ // return 1 if success, 0 otherwise // on fatal failure, calls die/exit // -int use_args_and_xrm(int *argc, char **argv) +static int use_args_and_xrm(int *argc, char **argv) { // set debug level early - g.debug = 0; - XrmDatabase db; + g.debug = 0; char *errmsg; int ksi; KeyCode BC; - unsigned int wmindex, dsindex, scindex, isrc; - char *gtile, *gicon, *gview, *gpos; - int x, y; - unsigned int w, h; - int xpg; + unsigned int wmindex, dsindex, scindex, isrc; + char *gtile, *gicon, *gview, *gpos; + int x, y; + unsigned int w, h; + int xpg; char *s; - char *rm; - char *empty = ""; + char *rm; + char *empty = ""; int uo; - Atom nwm_prop, atype; - unsigned char *nwm; - int form; - unsigned long remain, len; - XrmOptionDescRec xrmTable[] = { - {"-w", "*windowmanager", XrmoptionSepArg, NULL} , - {"-d", "*desktops", XrmoptionSepArg, NULL} , - {"-sc", "*screens", XrmoptionSepArg, NULL} , - {"-mm", "*modifier.mask", XrmoptionSepArg, NULL} , - {"-bm", "*backscroll.mask", XrmoptionSepArg, NULL} , - {"-mk", "*modifier.keysym", XrmoptionSepArg, NULL} , - {"-kk", "*key.keysym", XrmoptionSepArg, NULL} , - {"-bk", "*backscroll.keysym", XrmoptionSepArg, NULL} , - {"-t", "*tile.geometry", XrmoptionSepArg, NULL} , - {"-i", "*icon.geometry", XrmoptionSepArg, NULL} , - {"-vp", "*viewport", XrmoptionSepArg, NULL} , - {"-p", "*position", XrmoptionSepArg, NULL} , - {"-s", "*icon.source", XrmoptionSepArg, NULL} , - {"-theme", "*theme", XrmoptionSepArg, NULL} , - {"-bg", "*background", XrmoptionSepArg, NULL} , - {"-fg", "*foreground", XrmoptionSepArg, NULL} , - {"-frame", "*framecolor", XrmoptionSepArg, NULL} , - {"-font", "*font", XrmoptionSepArg, NULL} , - }; + Atom nwm_prop, atype; + unsigned char *nwm; + int form; + unsigned long remain, len; + XrmOptionDescRec xrmTable[] = { + {"-w", "*windowmanager", XrmoptionSepArg, NULL}, + {"-d", "*desktops", XrmoptionSepArg, NULL}, + {"-sc", "*screens", XrmoptionSepArg, NULL}, + {"-mm", "*modifier.mask", XrmoptionSepArg, NULL}, + {"-bm", "*backscroll.mask", XrmoptionSepArg, NULL}, + {"-mk", "*modifier.keysym", XrmoptionSepArg, NULL}, + {"-kk", "*key.keysym", XrmoptionSepArg, NULL}, + {"-bk", "*backscroll.keysym", XrmoptionSepArg, NULL}, + {"-pk", "*prevkey.keysym", XrmoptionSepArg, NULL}, + {"-nk", "*nextkey.keysym", XrmoptionSepArg, NULL}, + {"-ck", "*cancelkey.keysym", XrmoptionSepArg, NULL}, + {"-t", "*tile.geometry", XrmoptionSepArg, NULL}, + {"-i", "*icon.geometry", XrmoptionSepArg, NULL}, + {"-vp", "*viewport", XrmoptionSepArg, NULL}, + {"-p", "*position", XrmoptionSepArg, NULL}, + {"-s", "*icon.source", XrmoptionSepArg, NULL}, + {"-theme", "*theme", XrmoptionSepArg, NULL}, + {"-bg", "*background", XrmoptionSepArg, NULL}, + {"-fg", "*foreground", XrmoptionSepArg, NULL}, + {"-frame", "*framecolor", XrmoptionSepArg, NULL}, + {"-font", "*font", XrmoptionSepArg, NULL}, + }; const char *inv = "invalid %s, use -h for help\n"; const char *rmb = "can't figure out modmask from keycode 0x%x\n"; // not using getopt() because of need for "-v" before Xrm - int arg; - for (arg = 0; arg < (*argc); arg++) { - if ((strcmp(argv[arg], "-v") == 0)) { - g.debug = 1; + int arg; + for (arg = 0; arg < (*argc); arg++) { + if ((strcmp(argv[arg], "-v") == 0)) { + g.debug = 1; remove_arg(argc, argv, arg); - } - else if ((strcmp(argv[arg], "-vv") == 0)) { - g.debug = 2; + } else if ((strcmp(argv[arg], "-vv") == 0)) { + g.debug = 2; remove_arg(argc, argv, arg); - } - else if ((strcmp(argv[arg], "-h") == 0)) { - helpexit(); + } else if ((strcmp(argv[arg], "-h") == 0)) { + helpexit(); remove_arg(argc, argv, arg); } - } + } msg(0, "%s\n", PACKAGE_STRING); msg(0, "debug level %d\n", g.debug); - XrmInitialize(); - rm = XResourceManagerString(dpy); + XrmInitialize(); + rm = XResourceManagerString(dpy); msg(1, "resource manager: \"%s\"\n", rm); - if (!rm) { + if (!rm) { msg(0, "can't get resource manager, using empty db\n"); - //return 0; // we can do it - //db = XrmGetDatabase (dpy); - rm = empty; - } - db = XrmGetStringDatabase(rm); - if (!db) { + //return 0; // we can do it + //db = XrmGetDatabase (dpy); + rm = empty; + } + db = XrmGetStringDatabase(rm); + if (!db) { msg(-1, "can't get resource database\n"); - return 0; - } - XrmParseCommand(&db, xrmTable, sizeof(xrmTable) / sizeof(xrmTable[0]), - XRMAPPNAME, argc, argv); + return 0; + } + XrmParseCommand(&db, xrmTable, sizeof(xrmTable) / sizeof(xrmTable[0]), + XRMAPPNAME, argc, argv); if ((*argc) > 1) { g.debug = 1; msg(-1, "unknown options or wrong arguments:"); @@ -165,85 +168,83 @@ exit(1); } - switch (xresource_load_int(&db, XRMAPPNAME, "windowmanager", - &wmindex)) { - case 1: - if (wmindex >= WM_MIN && wmindex <= WM_MAX) { - g.option_wm = wmindex; - goto wmDone; - } else { - die(inv, "windowmanager argument range"); - } - break; - case 0: - msg(0, "no WM index or unknown, guessing\n"); - break; - case -1: - die(inv, "windowmanager argument"); - break; + switch (xresource_load_int(&db, XRMAPPNAME, "windowmanager", &wmindex)) { + case 1: + if (wmindex >= WM_MIN && wmindex <= WM_MAX) { + g.option_wm = wmindex; + goto wmDone; + } else { + die(inv, "windowmanager argument range"); + } + break; + case 0: + msg(0, "no WM index or unknown, guessing\n"); + break; + case -1: + die(inv, "windowmanager argument"); + break; } // EWMH? - if (ewmh_detectFeatures(&(g.ewmh))) { - msg(0, "EWMH-compatible WM detected: %s\n", - g.ewmh.wmname); - g.option_wm = WM_EWMH; - goto wmDone; - } + if (ewmh_detectFeatures(&(g.ewmh))) { + msg(0, "EWMH-compatible WM detected: %s\n", g.ewmh.wmname); + g.option_wm = WM_EWMH; + goto wmDone; + } // ratpoison? - nwm_prop = XInternAtom(dpy, "_NET_WM_NAME", false); - if (XGetWindowProperty(dpy, root, nwm_prop, 0, MAXNAMESZ, false, - AnyPropertyType, &atype, &form, &len, &remain, - &nwm) == Success && nwm) { - msg (0, "_NET_WM_NAME root property present: %s\n", - nwm); - if (strstr((char *)nwm, "ratpoison") != NULL) { - g.option_wm = WM_RATPOISON; - XFree(nwm); - goto wmDone; - } - XFree(nwm); - } + nwm_prop = XInternAtom(dpy, "_NET_WM_NAME", false); + if (XGetWindowProperty(dpy, root, nwm_prop, 0, MAXNAMESZ, false, + AnyPropertyType, &atype, &form, &len, &remain, + &nwm) == Success && nwm) { + msg(0, "_NET_WM_NAME root property present: %s\n", nwm); + if (strstr((char *)nwm, "ratpoison") != NULL) { + g.option_wm = WM_RATPOISON; + XFree(nwm); + goto wmDone; + } + XFree(nwm); + } msg(0, "unknown WM, using WM_TWM\n"); - g.option_wm = WM_TWM; + g.option_wm = WM_TWM; wmDone: msg(0, "WM: %d\n", g.option_wm); - switch (xresource_load_int(&db, XRMAPPNAME, "desktops", - &dsindex)) { - case 1: - if (dsindex >= DESK_MIN && dsindex <= DESK_MAX) - g.option_desktop = dsindex; - else - die(inv, "desktops argument range"); - break; - case 0: - g.option_desktop = DESK_DEFAULT; - break; - case -1: - die(inv, "desktops argument"); - break; + switch (xresource_load_int(&db, XRMAPPNAME, "desktops", &dsindex)) { + case 1: + if (dsindex >= DESK_MIN && dsindex <= DESK_MAX) + g.option_desktop = dsindex; + else + die(inv, "desktops argument range"); + break; + case 0: + g.option_desktop = DESK_DEFAULT; + break; + case -1: + die(inv, "desktops argument"); + break; } msg(0, "desktops: %d\n", g.option_desktop); - switch (xresource_load_int(&db, XRMAPPNAME, "screens", - &scindex)) { - case 1: - if (scindex >= SCR_MIN && scindex <= SCR_MAX) - g.option_screen = scindex; - else - die(inv, "screens argument range"); - break; - case 0: - g.option_screen = SCR_DEFAULT; - break; - case -1: - die(inv, "screens argument"); - break; + switch (xresource_load_int(&db, XRMAPPNAME, "screens", &scindex)) { + case 1: + if (scindex >= SCR_MIN && scindex <= SCR_MAX) + g.option_screen = scindex; + else + die(inv, "screens argument range"); + break; + case 0: + g.option_screen = SCR_DEFAULT; + break; + case -1: + die(inv, "screens argument"); + break; } msg(0, "screens: %d\n", g.option_screen); #define MC g.option_modCode #define KC g.option_keyCode +#define prevC g.option_prevCode +#define nextC g.option_nextCode +#define cancelC g.option_cancelCode #define GMM g.option_modMask #define GBM g.option_backMask @@ -257,43 +258,58 @@ die("%s\n", errmsg); KC = ksi != 0 ? ksi : XKeysymToKeycode(dpy, DEFKEYKS); + ksi = ksym_option_to_keycode(&db, XRMAPPNAME, "prevkey", &errmsg); + if (ksi == -1) + die("%s\n", errmsg); + prevC = ksi != 0 ? ksi : XKeysymToKeycode(dpy, DEFPREVKEYKS); + + ksi = ksym_option_to_keycode(&db, XRMAPPNAME, "nextkey", &errmsg); + if (ksi == -1) + die("%s\n", errmsg); + nextC = ksi != 0 ? ksi : XKeysymToKeycode(dpy, DEFNEXTKEYKS); + + ksi = ksym_option_to_keycode(&db, XRMAPPNAME, "cancelkey", &errmsg); + if (ksi == -1) + die("%s\n", errmsg); + cancelC = ksi != 0 ? ksi : XKeysymToKeycode(dpy, DEFCANCELKS); + switch (xresource_load_int(&db, XRMAPPNAME, "modifier.mask", &(GMM))) { - case 1: - msg(-1, - "Using obsoleted -mm option or modifier.mask resource, see man page for upgrade\n"); - break; - case 0: - GMM = keycode_to_modmask(MC); - if (GMM == 0) - die (rmb, MC); - break; - case -1: - die(inv, "modifier mask"); - break; + case 1: + msg(-1, + "Using obsoleted -mm option or modifier.mask resource, see man page for upgrade\n"); + break; + case 0: + GMM = keycode_to_modmask(MC); + if (GMM == 0) + die(rmb, MC); + break; + case -1: + die(inv, "modifier mask"); + break; } switch (xresource_load_int(&db, XRMAPPNAME, "backscroll.mask", &(GBM))) { - case 1: - msg(-1, - "Using obsoleted -bm option or backscroll.mask resource, see man page for upgrade\n"); - break; - case 0: - BC = ksym_option_to_keycode(&db, XRMAPPNAME, "backscroll", &errmsg); - if (BC != 0) { - GBM = keycode_to_modmask(BC); - if (GBM == 0) - die(rmb, BC); - } else { - GBM = DEFBACKMASK; - } - break; - case -1: - die(inv, "backscroll mask"); - break; + case 1: + msg(-1, + "Using obsoleted -bm option or backscroll.mask resource, see man page for upgrade\n"); + break; + case 0: + BC = ksym_option_to_keycode(&db, XRMAPPNAME, "backscroll", &errmsg); + if (BC != 0) { + GBM = keycode_to_modmask(BC); + if (GBM == 0) + die(rmb, BC); + } else { + GBM = DEFBACKMASK; + } + break; + case -1: + die(inv, "backscroll mask"); + break; } msg(0, "modMask %d, backMask %d, modCode %d, keyCode %d\n", - GMM, GBM, MC, KC); + GMM, GBM, MC, KC); g.option_tileW = DEFTILEW; g.option_tileH = DEFTILEH; @@ -314,22 +330,21 @@ g.option_iconH = DEFICONH; gicon = xresource_load_string(&db, XRMAPPNAME, "icon.geometry"); if (gicon) { - xpg = XParseGeometry(gicon, &x, &y, &w, &h); + xpg = XParseGeometry(gicon, &x, &y, &w, &h); if (xpg & WidthValue) - g.option_iconW = w; + g.option_iconW = w; else die(inv, "icon width"); if (xpg & HeightValue) - g.option_iconH = h; + g.option_iconH = h; else die(inv, "icon height"); } msg(0, "%dx%d tile, %dx%d icon\n", - g.option_tileW, g.option_tileH, g.option_iconW, - g.option_iconH); + g.option_tileW, g.option_tileH, g.option_iconW, g.option_iconH); - bzero (&(g.option_vp), sizeof(g.option_vp)); + bzero(&(g.option_vp), sizeof(g.option_vp)); g.option_vp_mode = VP_DEFAULT; gview = xresource_load_string(&db, XRMAPPNAME, "viewport"); if (gview) { @@ -353,9 +368,8 @@ } } msg(0, "viewport: mode %d, %dx%d+%d+%d\n", - g.option_vp_mode, - g.option_vp.w, g.option_vp.h, - g.option_vp.x, g.option_vp.y); + g.option_vp_mode, + g.option_vp.w, g.option_vp.h, g.option_vp.x, g.option_vp.y); g.option_positioning = POS_DEFAULT; g.option_posX = 0; @@ -368,38 +382,38 @@ g.option_positioning = POS_NONE; } else { g.option_positioning = POS_SPECIFIC; - xpg = XParseGeometry(gpos, &x, &y, &w, &h); + xpg = XParseGeometry(gpos, &x, &y, &w, &h); if (xpg & (XValue | YValue)) { - g.option_posX = x; - g.option_posY = y; + g.option_posX = x; + g.option_posY = y; } else { die(inv, "position"); } } } msg(0, "positioning policy: %d, position: +%d+%d\n", - g.option_positioning, g.option_posX, g.option_posY); + g.option_positioning, g.option_posX, g.option_posY); g.option_iconSrc = ISRC_DEFAULT; switch (xresource_load_int(&db, XRMAPPNAME, "icon.source", &isrc)) { - case 1: - if (isrc >= ISRC_MIN && isrc <= ISRC_MAX) - g.option_iconSrc = isrc; - else - die("icon source argument must be from %d to %d\n", - ISRC_MIN, ISRC_MAX); - break; - case 0: - g.option_iconSrc = ISRC_DEFAULT; - break; - case -1: - die(inv, "icon source"); - break; + case 1: + if (isrc >= ISRC_MIN && isrc <= ISRC_MAX) + g.option_iconSrc = isrc; + else + die("icon source argument must be from %d to %d\n", + ISRC_MIN, ISRC_MAX); + break; + case 0: + g.option_iconSrc = ISRC_DEFAULT; + break; + case -1: + die(inv, "icon source"); + break; } msg(0, "icon source: %d\n", g.option_iconSrc); s = xresource_load_string(&db, XRMAPPNAME, "theme"); - g.option_theme = s ? s : DEFTHEME; + g.option_theme = s ? s : DEFTHEME; msg(0, "icon theme: %s\n", g.option_theme); s = xresource_load_string(&db, XRMAPPNAME, "background"); @@ -412,13 +426,11 @@ s = xresource_load_string(&db, XRMAPPNAME, "font"); if (s) { if ((strncmp(s, "xft:", 4) == 0) - && (*(s + 4) != '\0')) { + && (*(s + 4) != '\0')) { g.option_font = s + 4; } else { // resource may indeed be valid but non-xft - msg(-1, - "invalid font: %s, using default: %s\n", - s, DEFFONT); + msg(-1, "invalid font: %s, using default: %s\n", s, DEFFONT); g.option_font = DEFFONT + 4; } } else { @@ -426,78 +438,94 @@ } // max recursion for searching windows -// -1 is "everything" +// -1 is "everything" // in raw X this returns too much windows, "1" is probably sufficient // no need for an option - g.option_max_reclevel = (g.option_wm == WM_NO) ? 1 : -1; + g.option_max_reclevel = (g.option_wm == WM_NO) ? 1 : -1; - return 1; + return 1; } // // grab Alt-Tab and Alt-Shift-Tab // note: exit() on failure // -int grabAllKeys(bool grabUngrab) +static int grabKeysAtStartup(bool grabUngrab) { - g.ignored_modmask = getOffendingModifiersMask(dpy); // or 0 for g.debug - char *grabhint = - "Error while (un)grabbing key 0x%x with mask 0x%x/0x%x.\nProbably other program already grabbed this combination.\nCheck: xdotool keydown alt+Tab; xdotool key XF86LogGrabInfo; xdotool keyup Tab; sleep 1; xdotool keyup alt\nand then look for active device grabs in /var/log/Xorg.0.log\nOr try Ctrl-Tab instead of Alt-Tab: alttab -mk Control_L\n"; + g.ignored_modmask = getOffendingModifiersMask(dpy); // or 0 for g.debug + char *grabhint = + "Error while (un)grabbing key 0x%x with mask 0x%x/0x%x.\nProbably other program already grabbed this combination.\nCheck: xdotool keydown alt+Tab; xdotool key XF86LogGrabInfo; xdotool keyup Tab; sleep 1; xdotool keyup alt\nand then look for active device grabs in /var/log/Xorg.0.log\nOr try Ctrl-Tab instead of Alt-Tab: alttab -mk Control_L\n"; // attempt XF86Ungrab? probably too invasive - if (!changeKeygrab - (root, grabUngrab, g.option_keyCode, g.option_modMask, - g.ignored_modmask)) { - die(grabhint, g.option_keyCode, - g.option_modMask, g.ignored_modmask); - } - if (!changeKeygrab - (root, grabUngrab, g.option_keyCode, - g.option_modMask | g.option_backMask, g.ignored_modmask)) { - die(grabhint, g.option_keyCode, - g.option_modMask | g.option_backMask, g.ignored_modmask); - } - return 1; + if (!changeKeygrab + (root, grabUngrab, g.option_keyCode, g.option_modMask, + g.ignored_modmask)) { + die(grabhint, g.option_keyCode, g.option_modMask, g.ignored_modmask); + } + if (!changeKeygrab + (root, grabUngrab, g.option_keyCode, + g.option_modMask | g.option_backMask, g.ignored_modmask)) { + die(grabhint, g.option_keyCode, + g.option_modMask | g.option_backMask, g.ignored_modmask); + } + + return 1; +} + +// +// Returns 0 if not an extra prev/next keycode, 1 if extra prev keycode, and 2 if extra next keycode. +// +static int isPrevNextKey(unsigned int keycode) +{ + if (keycode == g.option_prevCode) { + return 1; + } + if (keycode == g.option_nextCode) { + return 2; + } + // if here then is neither + return 0; } + int main(int argc, char **argv) { - XEvent ev; - dpy = XOpenDisplay(NULL); + XEvent ev; + dpy = XOpenDisplay(NULL); if (!dpy) die("can't open display"); scr = DefaultScreen(dpy); - root = DefaultRootWindow(dpy); + root = DefaultRootWindow(dpy); - ee_complain = true; + ee_complain = true; //hnd = (XErrorHandler)0; - XErrorHandler hnd = XSetErrorHandler (zeroErrorHandler); // for entire program - if (hnd) ;; // make -Wunused happy + XErrorHandler hnd = XSetErrorHandler(zeroErrorHandler); // for entire program + if (hnd) ;; // make -Wunused happy - if (!use_args_and_xrm(&argc, argv)) - die("use_args_and_xrm failed"); - if (!startupWintasks()) - die("startupWintasks failed"); - if (!startupGUItasks()) - die("startupGUItasks failed"); - - grabAllKeys(true); - g.uiShowHasRun = false; - - struct timespec nanots; - nanots.tv_sec = 0; - nanots.tv_nsec = 1E7; - char keys_pressed[32]; - int octet = g.option_modCode / 8; - int kmask = 1 << (g.option_modCode - octet * 8); + if (!use_args_and_xrm(&argc, argv)) + die("use_args_and_xrm failed"); + if (!startupWintasks()) + die("startupWintasks failed"); + if (!startupGUItasks()) + die("startupGUItasks failed"); + + grabKeysAtStartup(true); + g.uiShowHasRun = false; + + struct timespec nanots; + nanots.tv_sec = 0; + nanots.tv_nsec = 1E7; + char keys_pressed[32]; + int octet = g.option_modCode / 8; + int kmask = 1 << (g.option_modCode - octet * 8); - while (true) { - memset(&(ev.xkey), 0, sizeof(ev.xkey)); + while (true) { + memset(&(ev.xkey), 0, sizeof(ev.xkey)); if (g.uiShowHasRun) { // poll: lag and consume cpu, but necessary because of bug #1 and #2 XQueryKeymap(dpy, keys_pressed); - if (!(keys_pressed[octet] & kmask)) { // Alt released + if (!(keys_pressed[octet] & kmask)) { // Alt released uiHide(); continue; } @@ -505,58 +533,76 @@ nanosleep(&nanots, NULL); continue; } - } else { - // event: immediate, when we don't care about Alt release - XNextEvent(dpy, &ev); - } - - switch (ev.type) { - case KeyPress: - msg (1, "Press %lx: %d-%d\n", - ev.xkey.window, ev.xkey.state, - ev.xkey.keycode); - if (! - ((ev.xkey.state & g.option_modMask) - && ev.xkey.keycode == g.option_keyCode)) { - break; - } // safety redundance - if (!g.uiShowHasRun) { - uiShow((ev.xkey.state & g.option_backMask)); - } else { - if (ev.xkey.state & g.option_backMask) { - uiPrevWindow(); - } else { - uiNextWindow(); - } - } - break; + } else { + // event: immediate, when we don't care about Alt release + XNextEvent(dpy, &ev); + } + + switch (ev.type) { + case KeyPress: + msg(1, "Press %lx: %d-%d\n", + ev.xkey.window, ev.xkey.state, ev.xkey.keycode); + if (ev.xkey.state & g.option_modMask) { // alt + if (ev.xkey.keycode == g.option_keyCode) { // tab + // additional check, see #97 + XQueryKeymap(dpy, keys_pressed); + if (!(keys_pressed[octet] & kmask)) { + msg(1, "Wrong modifier, skip event\n"); + continue; + } + if (!g.uiShowHasRun) { + uiShow((ev.xkey.state & g.option_backMask)); + } else { + if (ev.xkey.state & g.option_backMask) { + uiPrevWindow(); + } else { + uiNextWindow(); + } + } + } else if (ev.xkey.keycode == g.option_cancelCode) { // escape + // additional check, see #97 + XQueryKeymap(dpy, keys_pressed); + if (!(keys_pressed[octet] & kmask)) { + msg(1, "Wrong modifier, skip event\n"); + continue; + } + uiSelectWindow(0); + } else { // non-tab + switch (isPrevNextKey(ev.xkey.keycode)) { + case 1: + uiPrevWindow(); + break; + case 2: + uiNextWindow(); + break; + } + } + } + break; - case KeyRelease: + case KeyRelease: msg(1, "Release %lx: %d-%d\n", - ev.xkey.window, ev.xkey.state, - ev.xkey.keycode); - // interested only in "final" release - if (! - ((ev.xkey.state & g.option_modMask) - && ev.xkey.keycode == g.option_modCode - && g.uiShowHasRun)) { - break; - } - uiHide(); - break; - - case Expose: - if (g.uiShowHasRun) { - uiExpose(); - } - break; + ev.xkey.window, ev.xkey.state, ev.xkey.keycode); + // interested only in "final" release + if (!((ev.xkey.state & g.option_modMask) + && ev.xkey.keycode == g.option_modCode && g.uiShowHasRun)) { + break; + } + uiHide(); + break; + + case Expose: + if (g.uiShowHasRun) { + uiExpose(); + } + break; - case ButtonPress: - case ButtonRelease: + case ButtonPress: + case ButtonRelease: uiButtonEvent(ev.xbutton); break; - case PropertyNotify: + case PropertyNotify: winPropChangeEvent(ev.xproperty); break; @@ -568,16 +614,19 @@ winFocusChangeEvent(ev.xfocus); break; - default: + default: msg(1, "Event type %d\n", ev.type); - break; - } + break; + } - } + } // this is probably never reached - grabAllKeys(false); + shutdownWin(); + shutdownGUI(); + XrmDestroyDatabase(db); + grabKeysAtStartup(false); // not restoring error handler - XCloseDisplay(dpy); - return 0; -} // main + XCloseDisplay(dpy); + return 0; +} // main diff -Nru alttab-1.3.0/src/alttab.h alttab-1.5.0/src/alttab.h --- alttab-1.3.0/src/alttab.h 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/src/alttab.h 2020-07-23 08:24:20.000000000 +0000 @@ -1,7 +1,7 @@ /* Global includes. -Copyright 2017-2018 Alexander Kulak. +Copyright 2017-2020 Alexander Kulak. This file is part of alttab program. alttab is free software: you can redistribute it and/or modify @@ -49,46 +49,51 @@ #define DEFCOLFG "grey" #define DEFCOLFRAME "#a0abab" -#define XDEPTH 24 // TODO: get rid of this +#define XDEPTH 24 // TODO: get rid of this #define DEFMODMASK Mod1Mask #define DEFBACKMASK ShiftMask #define DEFMODKS XK_Alt_L #define DEFKEYKS XK_Tab +#define DEFPREVKEYKS XK_VoidSymbol +#define DEFNEXTKEYKS XK_VoidSymbol +#define DEFCANCELKS XK_Escape #include "icon.h" #ifndef COMTYPES #define COMTYPES typedef struct { - int w; int h; - int x; int y; + int w; + int h; + int x; + int y; } quad; #define MAXNAMESZ 256 #endif typedef struct { - Window id; - int wm_id; // wm's internal window id, when WM has it (ratpoison) - char name[MAXNAMESZ]; - int reclevel; - Pixmap icon_drawable; // Window or Pixmap + Window id; + int wm_id; // wm's internal window id, when WM has it (ratpoison) + char name[MAXNAMESZ]; + int reclevel; + Pixmap icon_drawable; // Window or Pixmap Pixmap icon_mask; - unsigned int icon_w, icon_h; - bool icon_allocated; // we must free icon, because we created it (placeholder or depth conversion) - Pixmap tile; // ready to display. w/h are all equal and defined in gui.c -// this constant can't be 0, 1, -1, MAXINT, + unsigned int icon_w, icon_h; + bool icon_allocated; // we must free icon, because we created it (placeholder or depth conversion) + Pixmap tile; // ready to display. w/h are all equal and defined in gui.c +// this constant can't be 0, 1, -1, MAXINT, // because WMs set it to these values incoherently #define DESKTOP_UNKNOWN 0xdead unsigned long desktop; } WindowInfo; typedef struct { - //char name[MAXNAMESZ]; - char *name; - XColor xcolor; - XftColor xftcolor; - //XRenderColor xrendercolor; + //char name[MAXNAMESZ]; + char *name; + XColor xcolor; + XftColor xftcolor; + //XRenderColor xrendercolor; } Color; typedef struct { @@ -113,24 +118,23 @@ typedef struct { int debug; - bool uiShowHasRun; // means: 1. window is ready to Expose, 2. need to call uiHide to free X stuff - WindowInfo *winlist; - int maxNdx; // number of items in list above - int selNdx; // current (selected) item + bool uiShowHasRun; // means: 1. window is ready to Expose, 2. need to call uiHide to free X stuff + WindowInfo *winlist; + int maxNdx; // number of items in list above /* auxiliary list for sorting * head = recently focused * display-wide, for all groups/desktops * unlike g.winlist, survives uiHide */ - PermanentWindowInfo *sortlist; - // option_* are initialized from command line arguments or X resources or defaults - int option_max_reclevel; // max reclevel. -1 is "everything" + PermanentWindowInfo *sortlist; + // option_* are initialized from command line arguments or X resources or defaults + int option_max_reclevel; // max reclevel. -1 is "everything" #define WM_MIN 0 #define WM_NO 0 #define WM_EWMH 1 #define WM_RATPOISON 2 #define WM_TWM 3 #define WM_MAX 3 - int option_wm; + int option_wm; #define DESK_MIN 0 #define DESK_CURRENT 0 #define DESK_ALL 1 @@ -145,9 +149,9 @@ #define SCR_MAX 1 #define SCR_DEFAULT SCR_ALL int option_screen; - char *option_font; - int option_tileW, option_tileH; - int option_iconW, option_iconH; + char *option_font; + int option_tileW, option_tileH; + int option_iconW, option_iconH; #define VP_FOCUS 0 #define VP_POINTER 1 #define VP_TOTAL 2 @@ -172,14 +176,16 @@ #define ISRC_DEFAULT ISRC_SIZE int option_iconSrc; char *option_theme; - unsigned int option_modMask, option_backMask; - KeyCode option_modCode, option_keyCode; - Color color[NCOLORS]; - GC gcDirect, gcReverse, gcFrame; // used in both gui.c and win.c - unsigned int ignored_modmask; - icon_t *ic; // cache of all icons - EwmhFeatures ewmh; // guessed by ewmh_detectFeatures - Atom naw; // _NET_ACTIVE_WINDOW + unsigned int option_modMask, option_backMask; + KeyCode option_modCode, option_keyCode; + KeyCode option_prevCode, option_nextCode; + KeyCode option_cancelCode; + Color color[NCOLORS]; + GC gcDirect, gcReverse, gcFrame; // used in both gui.c and win.c + unsigned int ignored_modmask; + icon_t *ic; // cache of all icons + EwmhFeatures ewmh; // guessed by ewmh_detectFeatures + Atom naw; // _NET_ACTIVE_WINDOW // SwitchMoment last; // for detecting false focus events from WM } Globals; @@ -193,13 +199,16 @@ int uiSelectWindow(int ndx); void uiButtonEvent(XButtonEvent e); Window getUiwin(); +void shutdownGUI(void); // windows int startupWintasks(); -int addIconFromHints (WindowInfo* wi); -int addIconFromFiles (WindowInfo* wi); -int addWindowInfo(Window win, int reclevel, int wm_id, unsigned long desktop, char *wm_name); -int initWinlist(bool direction); +int addIconFromProperty(WindowInfo * wi); +int addIconFromHints(WindowInfo * wi); +int addIconFromFiles(WindowInfo * wi); +int addWindowInfo(Window win, int reclevel, int wm_id, unsigned long desktop, + char *wm_name); +int initWinlist(void); void freeWinlist(); int setFocus(int winNdx); int rp_startupWintasks(); @@ -212,12 +221,14 @@ void winPropChangeEvent(XPropertyEvent e); void winDestroyEvent(XDestroyWindowEvent e); void winFocusChangeEvent(XFocusChangeEvent e); -bool common_skipWindow(Window w, unsigned long current_desktop, unsigned long window_desktop); +bool common_skipWindow(Window w, unsigned long current_desktop, + unsigned long window_desktop); void x_setCommonPropertiesForAnyWindow(Window win); void addToSortlist(Window w, bool to_head, bool move); +void shutdownWin(void); /* EWHM */ -bool ewmh_detectFeatures(EwmhFeatures *e); +bool ewmh_detectFeatures(EwmhFeatures * e); Window ewmh_getActiveWindow(); int ewmh_initWinlist(); int ewmh_setFocus(int winNdx, Window fwin); // fwin used if non-zero @@ -227,7 +238,7 @@ /* RANDR */ bool randrAvailable(); -bool randrGetViewport(quad *res, bool *multihead); +bool randrGetViewport(quad * res, bool * multihead); /* autil */ void die(const char *format, ...); diff -Nru alttab-1.3.0/src/autil.c alttab-1.5.0/src/autil.c --- alttab-1.3.0/src/autil.c 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/src/autil.c 2020-07-23 08:24:20.000000000 +0000 @@ -1,7 +1,7 @@ /* Helper functions specific to alttab. -Copyright 2017-2018 Alexander Kulak. +Copyright 2017-2020 Alexander Kulak. This file is part of alttab program. alttab is free software: you can redistribute it and/or modify @@ -48,10 +48,9 @@ void die(const char *format, ...) { va_list ap; - fprintf (stderr, MSGPREFIX); + fprintf(stderr, MSGPREFIX); va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); exit(1); } - diff -Nru alttab-1.3.0/src/ewmh.c alttab-1.5.0/src/ewmh.c --- alttab-1.3.0/src/ewmh.c 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/src/ewmh.c 2020-07-23 08:24:20.000000000 +0000 @@ -2,7 +2,7 @@ Interface with EWMH-compatible window managers. Note: _WIN fallbacks are not part of EWMH or ICCCM, but kept here anyway. -Copyright 2017-2018 Alexander Kulak. +Copyright 2017-2020 Alexander Kulak. This file is part of alttab program. alttab is free software: you can redistribute it and/or modify @@ -31,7 +31,7 @@ #include "alttab.h" #include "util.h" extern Globals g; -extern Display* dpy; +extern Display *dpy; extern int scr; extern Window root; @@ -41,44 +41,44 @@ // returns ptr to EWMH client list and client_list_size // or NULL // -Window *ewmh_get_client_list(unsigned long *client_list_size) +static Window *ewmh_get_client_list(unsigned long *client_list_size) { Window *client_list; - if (g.ewmh.try_stacking_list_first) { + if (g.ewmh.try_stacking_list_first) { if ((client_list = - (Window *) get_x_property(root, XA_WINDOW, "_NET_CLIENT_LIST_STACKING", - client_list_size)) != NULL) { + (Window *) get_x_property(root, XA_WINDOW, + "_NET_CLIENT_LIST_STACKING", + client_list_size)) != NULL) { msg(1, "ewmh found stacking window list\n"); return client_list; } else { g.ewmh.try_stacking_list_first = false; } } - if ((client_list = - (Window *) get_x_property(root, XA_WINDOW, "_NET_CLIENT_LIST", - client_list_size)) != NULL) - return client_list; - if ((client_list = - (Window *) get_x_property(root, XA_CARDINAL, "_WIN_CLIENT_LIST", - client_list_size)) != NULL) - return client_list; - return 0; + + client_list = + (Window *) get_x_property_alt(root, + XA_WINDOW, "_NET_CLIENT_LIST", + XA_CARDINAL, "_WIN_CLIENT_LIST", + client_list_size); + + return client_list; } -int ewmh_send_wm_evt(Window w, char *atom, unsigned long edata[]) +static int ewmh_send_wm_evt(Window w, char *atom, unsigned long edata[]) { XEvent evt; long rn_mask = SubstructureRedirectMask | SubstructureNotifyMask; evt.xclient.window = w; evt.xclient.type = ClientMessage; - evt.xclient.message_type = - XInternAtom(dpy, atom, False); + evt.xclient.message_type = XInternAtom(dpy, atom, False); evt.xclient.serial = 0; evt.xclient.send_event = True; evt.xclient.format = 32; //memset (&(evt.xclient.data.l[1]), 0, 4*sizeof(evt.xclient.data.l[1])); - int ei; for (ei = 0; ei < 5; ei++) + int ei; + for (ei = 0; ei < 5; ei++) evt.xclient.data.l[ei] = edata[ei]; if (!XSendEvent(dpy, root, False, rn_mask, &evt)) { msg(-1, "can't send %s xevent\n", atom); @@ -87,10 +87,10 @@ return 1; } -int ewmh_switch_desktop(unsigned long desktop) +static int ewmh_switch_desktop(unsigned long desktop) { int evr, elapsed; - unsigned long edata[] = {desktop, CurrentTime, 0,0,0}; + unsigned long edata[] = { desktop, CurrentTime, 0, 0, 0 }; if (desktop == -1 && g.ewmh.minus1_desktop_unusable) return 0; msg(1, "ewmh switching desktop to %ld\n", desktop); @@ -98,24 +98,22 @@ if (evr == 0) return 0; // wait for WM (#45) -#define WM_POLL_TIMEOUT 200000 // 200 ms +#define WM_POLL_TIMEOUT 200000 // 200 ms #define WM_POLL_INTERVAL 10000 for (elapsed = 0; - elapsed < WM_POLL_TIMEOUT - && ewmh_getCurrentDesktop() != desktop; - elapsed += WM_POLL_INTERVAL) { + elapsed < WM_POLL_TIMEOUT + && ewmh_getCurrentDesktop() != desktop; elapsed += WM_POLL_INTERVAL) { msg(1, "usleep %d\n", WM_POLL_INTERVAL); usleep(WM_POLL_INTERVAL); } return evr; } -int ewmh_switch_window(unsigned long window) +static int ewmh_switch_window(unsigned long window) { - unsigned long edata[] = {2, CurrentTime, 0,0,0}; + unsigned long edata[] = { 2, CurrentTime, 0, 0, 0 }; msg(1, "ewmh switching window to 0x%lx\n", window); - return - ewmh_send_wm_evt(window, "_NET_ACTIVE_WINDOW", edata); + return ewmh_send_wm_evt(window, "_NET_ACTIVE_WINDOW", edata); } // PUBLIC @@ -124,13 +122,14 @@ // initialize EwmhFeatures // return true if usable at all // -bool ewmh_detectFeatures(EwmhFeatures *e) +bool ewmh_detectFeatures(EwmhFeatures * e) { - Window *chld_win; - char *r; - Atom utf8string; + Window *chld_win; + char *r; + Atom utf8string; char *default_wm_name = "unknown_ewmh_compatible"; unsigned long client_list_size; + Window *client_list; // This function is used in alttab for detection of EWMH compatibility. // But there are WM (dwm) that support EWMH subset required for alttab @@ -138,38 +137,36 @@ // We detect those WM as EWMH-compatible and return their name // as "unknown_ewmh_compatible". - bzero (e, sizeof(EwmhFeatures)); + bzero(e, sizeof(EwmhFeatures)); e->try_stacking_list_first = true; // first, detect necessary feature: client list // also, this resets try_stacking_list_first if necessary - if (ewmh_get_client_list(&client_list_size) == NULL) { + client_list = ewmh_get_client_list(&client_list_size); + if (client_list == NULL) { // WM is not usable in EWMH mode return false; } + free(client_list); // then, guess/devise WM name - chld_win = (Window *) NULL; - if (! (chld_win = (Window *) get_x_property(root, XA_WINDOW, "_NET_SUPPORTING_WM_CHECK", NULL))) { - if (! (chld_win = (Window *) get_x_property(root, XA_CARDINAL, "_WIN_SUPPORTING_WM_CHECK", NULL))) { - e->wmname = default_wm_name; - return true; - } - } - r = (char *)NULL; - utf8string = XInternAtom(dpy, "UTF8_STRING", False); - if (! - (r = - get_x_property(*chld_win, utf8string, "_NET_WM_NAME", - NULL))) { - (r = - get_x_property(*chld_win, XA_STRING, "_NET_WM_NAME", - NULL)); - } - if (chld_win!=NULL) - free(chld_win); + chld_win = (Window *)get_x_property_alt(root, + XA_WINDOW, "_NET_SUPPORTING_WM_CHECK", + XA_CARDINAL, "_WIN_SUPPORTING_WM_CHECK", + NULL); + if (!chld_win) { + e->wmname = default_wm_name; + return true; + } - e->wmname = (r!=NULL) ? r : default_wm_name; + utf8string = XInternAtom(dpy, "UTF8_STRING", False); + + r = get_x_property_alt(*chld_win, + utf8string, "_NET_WM_NAME", + XA_STRING, "_NET_WM_NAME", NULL); + free(chld_win); + + e->wmname = (r != NULL) ? r : default_wm_name; // special workarounds if (strncmp(e->wmname, "CWM", 4) == 0) @@ -184,14 +181,14 @@ Window ewmh_getActiveWindow() { Window w = (Window) 0; - char *awp; - unsigned long sz; - if ((awp = get_x_property(root, XA_WINDOW, "_NET_ACTIVE_WINDOW", &sz))) { - w = *((Window *) awp); - free(awp); - } else { + char *awp; + unsigned long sz; + if ((awp = get_x_property(root, XA_WINDOW, "_NET_ACTIVE_WINDOW", &sz))) { + w = *((Window *) awp); + free(awp); + } else { msg(0, "can't obtain _NET_ACTIVE_WINDOW\n"); - } + } return w; } @@ -201,28 +198,29 @@ // int ewmh_initWinlist() { - Window *client_list; - unsigned long client_list_size; - int i; - Window aw; - char *title; + Window *client_list; + unsigned long client_list_size; + int i; + Window aw; + char *title; unsigned long current_desktop, window_desktop; current_desktop = ewmh_getCurrentDesktop(); aw = ewmh_getActiveWindow(); - if (!aw) { + if (!aw) { msg(0, "can't obtain _NET_ACTIVE_WINDOW\n"); // continue anyway } - if ((client_list = ewmh_get_client_list(&client_list_size)) == NULL) { + client_list = ewmh_get_client_list(&client_list_size); + if (client_list == NULL) { msg(-1, "can't get client list\n"); return 0; } - for (i = 0; i < client_list_size / sizeof(Window); i++) { - Window w = client_list[i]; + for (i = 0; i < client_list_size / sizeof(Window); i++) { + Window w = client_list[i]; if (ewmh_skipWindowInTaskbar(w)) continue; @@ -231,28 +229,29 @@ if (common_skipWindow(w, current_desktop, window_desktop)) continue; - // build title - char *wmn1 = get_x_property(w, XA_STRING, "WM_NAME", NULL); - Atom utf8str = XInternAtom(dpy, "UTF8_STRING", False); - char *wmn2 = - get_x_property(w, utf8str, "_NET_WM_NAME", NULL); - title = wmn2 ? strdup(wmn2) : (wmn1 ? strdup(wmn1) : NULL); - free(wmn1); - free(wmn2); - - addWindowInfo(w, 0, 0, window_desktop, title); - if (w == aw) { - addToSortlist (w, true, true); // pull to head - } - } + // build title + char *wmn1 = get_x_property(w, XA_STRING, "WM_NAME", NULL); + Atom utf8str = XInternAtom(dpy, "UTF8_STRING", False); + char *wmn2 = get_x_property(w, utf8str, "_NET_WM_NAME", NULL); + title = wmn2 ? strdup(wmn2) : (wmn1 ? strdup(wmn1) : NULL); + free(wmn1); + free(wmn2); + + addWindowInfo(w, 0, 0, window_desktop, title); + if (w == aw) { + addToSortlist(w, true, true); // pull to head + } + free(title); + } // TODO: BUG? sometimes i3 returns previous active window, // which breaks sortlist // no more startNdx, can't output this //msg(1, "ewmh active window: %lu name: %s\n", - // aw, (g.winlist ? g.winlist[g.startNdx].name : "null")); + // aw, (g.winlist ? g.winlist[g.startNdx].name : "null")); - return 1; + free(client_list); + return 1; } // @@ -267,14 +266,30 @@ unsigned long wdesk = g.winlist[winNdx].desktop; unsigned long cdesk = ewmh_getCurrentDesktop(); msg(1, "ewmh_setFocus fwin 0x%lx opt %d wdesk %lu cdesk %lu\n", - fwin, g.option_desktop, wdesk, cdesk); + fwin, g.option_desktop, wdesk, cdesk); if (cdesk != wdesk && wdesk != DESKTOP_UNKNOWN) { ewmh_switch_desktop(wdesk); } } - ewmh_switch_window(win); - XMapRaised(dpy, win); - return 1; + ewmh_switch_window(win); + XMapRaised(dpy, win); + return 1; +} + +static unsigned long ewmh_getDesktopFromProp(Window w, char *prop1, char *prop2) +{ + unsigned long *d; + unsigned long propsize; + unsigned long ret = DESKTOP_UNKNOWN; + + d = (unsigned long *)get_x_property_alt(w, + XA_CARDINAL, prop1, + XA_CARDINAL, prop2, &propsize); + if (d && (propsize > 0)) + ret = *d; + + free(d); + return ret; } // @@ -282,14 +297,7 @@ // unsigned long ewmh_getCurrentDesktop() { - unsigned long *cd; - unsigned long propsize; - cd = (unsigned long*)get_x_property (root, XA_CARDINAL, - "_NET_CURRENT_DESKTOP", &propsize); - if (!cd) - cd = (unsigned long*)get_x_property (root, XA_CARDINAL, - "_WIN_WORKSPACE", &propsize); - return (cd && (propsize>0)) ? *cd : DESKTOP_UNKNOWN; + return ewmh_getDesktopFromProp(root, "_NET_CURRENT_DESKTOP", "_WIN_WORKSPACE"); } // @@ -297,14 +305,7 @@ // unsigned long ewmh_getDesktopOfWindow(Window w) { - unsigned long *d; - unsigned long propsize; - d = (unsigned long*)get_x_property (w, XA_CARDINAL, - "_NET_WM_DESKTOP", &propsize); - if (!d) - d = (unsigned long*)get_x_property (w, XA_CARDINAL, - "_WIN_WORKSPACE", &propsize); - return (d && (propsize>0)) ? *d : DESKTOP_UNKNOWN; + return ewmh_getDesktopFromProp(w, "_NET_WM_DESKTOP", "_WIN_WORKSPACE"); } // @@ -316,19 +317,24 @@ long unsigned int state_propsize; Atom a_skip_tb; int i; + bool ret = false; - state = (Atom*)get_x_property(w, XA_ATOM, "_NET_WM_STATE", &state_propsize); + state = + (Atom *) get_x_property(w, XA_ATOM, "_NET_WM_STATE", &state_propsize); if (state == NULL || state_propsize == 0) { msg(1, "%lx: no _NET_WM_STATE property\n", w); - return false; + goto out; } a_skip_tb = XInternAtom(dpy, "_NET_WM_STATE_SKIP_TASKBAR", True); - for (i = 0; i < state_propsize / sizeof(Atom); i++) { + for (i = 0; i < state_propsize / sizeof(Atom); i++) { if (state[i] == a_skip_tb) { msg(1, "%lx: _NET_WM_STATE_SKIP_TASKBAR found\n", w); - return true; + ret = true; + goto out; } } - return false; -} + out: + free(state); + return ret; +} diff -Nru alttab-1.3.0/src/gui.c alttab-1.5.0/src/gui.c --- alttab-1.3.0/src/gui.c 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/src/gui.c 2020-07-23 08:24:20.000000000 +0000 @@ -1,7 +1,7 @@ /* Draw and interface with our switcher window. -Copyright 2017-2018 Alexander Kulak. +Copyright 2017-2020 Alexander Kulak. This file is part of alttab program. alttab is free software: you can redistribute it and/or modify @@ -30,135 +30,245 @@ #include "alttab.h" #include "util.h" extern Globals g; -extern Display* dpy; +extern Display *dpy; extern int scr; extern Window root; // PRIVATE -unsigned int tileW, tileH, iconW, iconH; -unsigned int visualTileW; -int lastPressedTile; -quad scrdim; -Window uiwin; -int uiwinW, uiwinH, uiwinX, uiwinY; -Colormap colormap; -Visual *visual; +static unsigned int tileW, tileH, iconW, iconH; +static unsigned int visualTileW; +static int lastPressedTile; +static quad scrdim; +static Window uiwin; +static int uiwinW, uiwinH, uiwinX, uiwinY; +static Colormap colormap; +static Visual *visual; //Font fontLabel; // Xft instead -XftFont *fontLabel; +static XftFont *fontLabel; +static int selNdx; // current (selected) item // // allocates GC -// type is: +// type is: // 0: normal // 1: for bg fill // 2: for drawing frame // -GC create_gc(int type) +static GC create_gc(int type) { - GC gc; /* handle of newly created GC. */ - unsigned long valuemask = 0; /* which values in 'values' to */ - /* check when creating the GC. */ - XGCValues values; /* initial values for the GC. */ - int line_style = LineSolid; - int cap_style = CapButt; - int join_style = JoinMiter; - - gc = XCreateGC(dpy, root, valuemask, &values); - if (gc < 0) { - msg(-1, "can't create GC\n"); - return 0; - } - /* allocate foreground and background colors for this GC. */ - switch (type) { - case 1: - XSetForeground(dpy, gc, g.color[COLBG].xcolor.pixel); - XSetBackground(dpy, gc, g.color[COLFG].xcolor.pixel); - XSetLineAttributes(dpy, gc, FRAME_W, line_style, cap_style, - join_style); - break; - case 0: - XSetForeground(dpy, gc, g.color[COLFG].xcolor.pixel); - XSetBackground(dpy, gc, g.color[COLBG].xcolor.pixel); - XSetLineAttributes(dpy, gc, 1, line_style, cap_style, - join_style); - break; - case 2: - XSetForeground(dpy, gc, g.color[COLFRAME].xcolor.pixel); - XSetBackground(dpy, gc, g.color[COLBG].xcolor.pixel); - XSetLineAttributes(dpy, gc, FRAME_W, line_style, cap_style, - join_style); - break; - default: - msg(-1, "unknown GC type, not setting colors\n"); - break; - } - /* define the fill style for the GC. to be 'solid filling'. */ - XSetFillStyle(dpy, gc, FillSolid); - return gc; + GC gc; /* handle of newly created GC. */ + unsigned long valuemask = 0; /* which values in 'values' to */ + /* check when creating the GC. */ + XGCValues values; /* initial values for the GC. */ + int line_style = LineSolid; + int cap_style = CapButt; + int join_style = JoinMiter; + + gc = XCreateGC(dpy, root, valuemask, &values); + if (gc < 0) { + msg(-1, "can't create GC\n"); + return 0; + } + /* allocate foreground and background colors for this GC. */ + switch (type) { + case 1: + XSetForeground(dpy, gc, g.color[COLBG].xcolor.pixel); + XSetBackground(dpy, gc, g.color[COLFG].xcolor.pixel); + XSetLineAttributes(dpy, gc, FRAME_W, line_style, cap_style, join_style); + break; + case 0: + XSetForeground(dpy, gc, g.color[COLFG].xcolor.pixel); + XSetBackground(dpy, gc, g.color[COLBG].xcolor.pixel); + XSetLineAttributes(dpy, gc, 1, line_style, cap_style, join_style); + break; + case 2: + XSetForeground(dpy, gc, g.color[COLFRAME].xcolor.pixel); + XSetBackground(dpy, gc, g.color[COLBG].xcolor.pixel); + XSetLineAttributes(dpy, gc, FRAME_W, line_style, cap_style, join_style); + break; + default: + msg(-1, "unknown GC type, not setting colors\n"); + break; + } + /* define the fill style for the GC. to be 'solid filling'. */ + XSetFillStyle(dpy, gc, FillSolid); + return gc; } // // single use helper for function below // -void drawFr(GC gc, int f) +static void drawFr(GC gc, int f) { - int d = XDrawRectangle(dpy, uiwin, gc, - f * (tileW + FRAME_W) + (FRAME_W / 2), - 0 + (FRAME_W / 2), - tileW + FRAME_W, tileH + FRAME_W); - if (!d) { - msg(-1, "can't draw frame\n"); - } + int d = XDrawRectangle(dpy, uiwin, gc, + f * (tileW + FRAME_W) + (FRAME_W / 2), + 0 + (FRAME_W / 2), + tileW + FRAME_W, tileH + FRAME_W); + if (!d) { + msg(-1, "can't draw frame\n"); + } } // // draw selected and unselected frames around tiles // -void framesRedraw() +static void framesRedraw() { - int f; - for (f = 0; f < g.maxNdx; f++) { - if (f == g.selNdx) - continue; // skip - drawFr(g.gcReverse, f); // thick bg - drawFr(g.gcDirect, f); // thin frame - } + int f; + for (f = 0; f < g.maxNdx; f++) { + if (f == selNdx) + continue; // skip + drawFr(g.gcReverse, f); // thick bg + drawFr(g.gcDirect, f); // thin frame + } // _after_ unselected draw selected, because they may overlap - drawFr(g.gcFrame, g.selNdx); + drawFr(g.gcFrame, selNdx); } // // given coordinates relative to our window, // return the tile number or -1 // -int pointedTile(int x, int y) +static int pointedTile(int x, int y) { if (x < (FRAME_W / 2) - || x > (uiwinW - (FRAME_W / 2)) - || y < 0 - || y > uiwinH ) + || x > (uiwinW - (FRAME_W / 2)) + || y < 0 || y > uiwinH) return -1; return (x - (FRAME_W / 2)) / visualTileW; } +// +// combine widgets into wi->tile +// for uiShow() +// +static void prepareTile(WindowInfo * wi) +{ + wi->tile = XCreatePixmap(dpy, root, tileW, tileH, XDEPTH); + if (!wi->tile) + die("can't create tile"); + int fr = XFillRectangle(dpy, wi->tile, g.gcReverse, 0, 0, + tileW, tileH); + if (!fr) { + msg(-1, "can't fill tile\n"); + } + // mini-window content could be drawn here, + // but there is no backing store of windows + // in my simple environments (as reported by xwininfo) + // + // place icons + if (wi->icon_drawable) { + if (wi->icon_w == iconW && wi->icon_h == iconH) { + // direct copy + msg(1, "copying icon onto tile\n"); + // prepare special GC to copy icon, with clip mask if icon_mask present + unsigned long ic_valuemask = 0; + XGCValues ic_values; + GC ic_gc = XCreateGC(dpy, root, ic_valuemask, + &ic_values); + if (ic_gc < 0) { + msg(-1, "can't create GC to draw icon\n"); + goto endIcon; + } + if (wi->icon_mask != None) { + XSetClipMask(dpy, ic_gc, wi->icon_mask); + } + int or = XCopyArea(dpy, + wi->icon_drawable, + wi->tile, + ic_gc, 0, 0, + wi->icon_w, wi->icon_h, // src + 0, 0); // dst + if (!or) { + msg(-1, "can't copy icon to tile\n"); + } + XFreeGC(dpy, ic_gc); + } else { + // scale + msg(1, "scaling icon onto tile\n"); + int sc = pixmapFit(wi->icon_drawable, + wi->icon_mask, + wi->tile, + wi->icon_w, + wi->icon_h, + iconW, iconH); + if (!sc) { + msg(-1, "can't scale icon to tile\n"); + } + } + } else { + // draw placeholder or standalone icons from some WM + GC gcL = create_gc(0); // GC for thin line + if (!gcL) { + msg(-1, "can't create gcL\n"); + } else { + XSetLineAttributes(dpy, gcL, 1, LineSolid, CapButt, JoinMiter); + //XSetForeground (dpy, gcL, pixel); + int pr = XDrawRectangle(dpy, wi->tile, gcL, + 0, 0, iconW, iconH); + if (!pr) { + msg(-1, "can't draw placeholder\n"); + } + XFreeGC(dpy, gcL); + } + } + endIcon: + // draw labels + if (wi->name && fontLabel) { + int dr = drawMultiLine(wi->tile, fontLabel, + &(g.color[COLFG].xftcolor), + wi->name, + 0, (iconH + 5), tileW, + (tileH - iconH - 5)); + if (dr != 1) { + msg(-1, "can't draw label\n"); + } + } +} // prepareTile + +// +// grab auxiliary keys: arrows +// rely on pre-calculated g.ignored_modmask and g.option_modMask +// +static int grabKeysAtUiShow(bool grabUngrab) +{ + char *grabhint = + "Error while (un)grabbing key 0x%x with mask 0x%x/0x%x.\n"; + if (g.option_prevCode != 0) { + if (!changeKeygrab + (root, grabUngrab, g.option_prevCode, g.option_modMask, + g.ignored_modmask)) { + msg(0, grabhint, g.option_prevCode, g.option_modMask, g.ignored_modmask); + return 0; + } + } + if (g.option_nextCode != 0) { + if (!changeKeygrab + (root, grabUngrab, g.option_nextCode, g.option_modMask, + g.ignored_modmask)) { + msg(0, grabhint, g.option_nextCode, g.option_modMask, g.ignored_modmask); + return 0; + } + } + if (g.option_cancelCode != 0) { + if (!changeKeygrab + (root, grabUngrab, g.option_cancelCode, g.option_modMask, + g.ignored_modmask)) { + msg(0, grabhint, g.option_cancelCode, g.option_modMask, g.ignored_modmask); + return 0; + } + } + return 1; +} + // PUBLIC // // early initialization // called once per execution // mostly initializes g.* -// TODO: counterpair for freeing X resources, -// even if called once per execution: -/* -int p; for (p=0; p 0) { - msg(0, "got %d windows\n", g.maxNdx); - int i; - for (i = 0; i < g.maxNdx; i++) { - msg(0, - "%d: %lx (lvl %d, icon %lu (%dx%d)): %s\n", i, - g.winlist[i].id, g.winlist[i].reclevel, - g.winlist[i].icon_drawable, g.winlist[i].icon_w, - g.winlist[i].icon_h, g.winlist[i].name); - } - } + return 0; + } + + selNdx = direction ? (g.maxNdx - 1) : ((0 >= (g.maxNdx - 1)) ? 0 : 1); +//if (selNdx<0 || selNdx>=g.maxNdx) { selNdx=0; } // just for case + msg(1, "Current (selected) item in winlist: %d\n", selNdx); + + if (g.debug > 0) { + msg(0, "got %d windows\n", g.maxNdx); + int i; + for (i = 0; i < g.maxNdx; i++) { + msg(0, + "%d: %lx (lvl %d, icon %lu (%dx%d)): %s\n", i, + g.winlist[i].id, g.winlist[i].reclevel, + g.winlist[i].icon_drawable, g.winlist[i].icon_w, + g.winlist[i].icon_h, g.winlist[i].name); + } + } // have winlist, now back to uiwin stuff // calculate dimensions - tileW = g.option_tileW; + tileW = g.option_tileW; tileH = g.option_tileH; - iconW = g.option_iconW; - iconH = g.option_iconH; - float rt = 1.0; + iconW = g.option_iconW; + iconH = g.option_iconH; + float rt = 1.0; // for subsequent calculation of width(s), use 'avail_w' // instead of g.vp.w, because they don't match for POS_SPECIFIC int avail_w = g.vp.w; if (g.option_positioning == POS_SPECIFIC) avail_w -= g.option_posX; // tiles may be smaller if they don't fit viewport - uiwinW = (tileW + FRAME_W) * g.maxNdx + FRAME_W; - if (uiwinW > avail_w) { + uiwinW = (tileW + FRAME_W) * g.maxNdx + FRAME_W; + if (uiwinW > avail_w) { int frames = FRAME_W * g.maxNdx + FRAME_W; - rt = ((float)(avail_w - frames)) / ((float)(tileW * g.maxNdx)); - tileW = (float)tileW * rt; - tileH = (float)tileH * rt; - uiwinW = tileW * g.maxNdx + frames; - } + rt = ((float)(avail_w - frames)) / ((float)(tileW * g.maxNdx)); + tileW = (float)tileW *rt; + tileH = (float)tileH *rt; + uiwinW = tileW * g.maxNdx + frames; + } // icon may be smaller if it doesn't fit tile - if (iconW > tileW) { - rt = (float)tileW / (float)iconW; - iconW = tileW; - iconH = rt * iconH; - } - if (iconH > tileH) { - rt = (float)tileH / (float)iconH; - iconH = tileH; - iconW = rt * iconW; - } - uiwinH = tileH + 2 * FRAME_W; + if (iconW > tileW) { + rt = (float)tileW / (float)iconW; + iconW = tileW; + iconH = rt * iconH; + } + if (iconH > tileH) { + rt = (float)tileH / (float)iconH; + iconH = tileH; + iconW = rt * iconW; + } + uiwinH = tileH + 2 * FRAME_W; if (g.option_positioning == POS_CENTER) { - uiwinX = (g.vp.w - uiwinW) / 2 + g.vp.x; - uiwinY = (g.vp.h - uiwinH) / 2 + g.vp.y; + uiwinX = (g.vp.w - uiwinW) / 2 + g.vp.x; + uiwinY = (g.vp.h - uiwinH) / 2 + g.vp.y; } else { uiwinX = g.option_posX + g.vp.x; uiwinY = g.option_posY + g.vp.y; } visualTileW = (uiwinW - FRAME_W) / g.maxNdx; - if (g.debug > 0) { - msg(0, "tile w=%d h=%d\n", tileW, tileH); + if (g.debug > 0) { + msg(0, "tile w=%d h=%d\n", tileW, tileH); msg(0, "uiwin %dx%d +%d+%d", uiwinW, uiwinH, uiwinX, uiwinY); if (g.debug > 1) { int nscr, si; @@ -381,122 +485,37 @@ s = ScreenOfDisplay(dpy, si); msg(0, " [%dx%d]", s->width, s->height); } - msg(0, ", viewport %dx%d+%d+%d, avail_w %d", - g.vp.w, g.vp.h, g.vp.x, g.vp.y, avail_w); + msg(0, ", viewport %dx%d+%d+%d, avail_w %d", + g.vp.w, g.vp.h, g.vp.x, g.vp.y, avail_w); } msg(0, "\n"); - } + } // prepare tiles - int m; - for (m = 0; m < g.maxNdx; m++) { - if (!g.winlist) - die("no winlist in uiShow. this shouldn't happen, please report."); - g.winlist[m].tile = - XCreatePixmap(dpy, root, tileW, tileH, XDEPTH); - if (!g.winlist[m].tile) - die("can't create tile"); - int fr = - XFillRectangle(dpy, g.winlist[m].tile, g.gcReverse, 0, 0, - tileW, tileH); - if (!fr) { - msg(-1, "can't fill tile\n"); - } - // place icons - if (g.winlist[m].icon_drawable) { - if (g.winlist[m].icon_w == iconW && - g.winlist[m].icon_h == iconH) { - // direct copy - msg(1, "%d: copying icon\n", m); - // prepare special GC to copy icon, with clip mask if icon_mask present - unsigned long ic_valuemask = 0; - XGCValues ic_values; - GC ic_gc = - XCreateGC(dpy, root, ic_valuemask, - &ic_values); - if (ic_gc < 0) { - msg(-1, "can't create GC to draw icon\n"); - return 0; - } - if (g.winlist[m].icon_mask != 0) { - XSetClipMask(dpy, ic_gc, - g.winlist[m].icon_mask); - } - - int or = XCopyArea(dpy, - g.winlist[m].icon_drawable, - g.winlist[m].tile, - ic_gc, 0, 0, - g.winlist[m].icon_w, g.winlist[m].icon_h, // src - 0, 0); // dst - if (!or) { - msg(-1, "can't copy icon to tile\n"); - } - } else { - // scale - msg(1, "%d: scaling icon\n", m); - int sc = pixmapFit(g.winlist[m].icon_drawable, - g.winlist[m].icon_mask, - g.winlist[m].tile, - g.winlist[m].icon_w, - g.winlist[m].icon_h, - iconW, iconH); - if (!sc) { - msg(-1, "can't scale icon to tile\n"); - } - } - } else { - // draw placeholder or standalone icons from some WM - GC gcL = create_gc(0); // GC for thin line - if (!gcL) { - msg(-1, "can't create gcL\n"); - } else { - XSetLineAttributes(dpy, gcL, 1, LineSolid, - CapButt, JoinMiter); - //XSetForeground (dpy, gcL, pixel); - int pr = - XDrawRectangle(dpy, g.winlist[m].tile, gcL, - 0, 0, iconW, iconH); - if (!pr) { - msg(-1, "can't draw placeholder\n"); - } - XFreeGC(dpy, gcL); - } - } - // draw labels - if (g.winlist[m].name && fontLabel) { - int dr = - drawMultiLine(g.winlist[m].tile, fontLabel, - &(g.color[COLFG].xftcolor), - g.winlist[m].name, - 0, (iconH + 5), tileW, - (tileH - iconH - 5)); - if (dr != 1) { - msg(-1, "can't draw label\n"); - } - } - } + if (!g.winlist) { + die("no winlist in uiShow. this shouldn't happen, please report."); + } + int m; + for (m = 0; m < g.maxNdx; m++) { + prepareTile(&(g.winlist[m])); + } msg(0, "prepared %d tiles\n", m); - if (fontLabel) - XftFontClose(dpy, fontLabel); + if (fontLabel) + XftFontClose(dpy, fontLabel); // prepare our window - unsigned long valuemask = CWBackPixel | CWBorderPixel | CWOverrideRedirect; - XSetWindowAttributes attributes; - attributes.background_pixel = g.color[COLBG].xcolor.pixel; - attributes.border_pixel = g.color[COLFRAME].xcolor.pixel; - attributes.override_redirect = 1; - uiwin = XCreateWindow( - dpy, root, - uiwinX, uiwinY, - uiwinW, uiwinH, - 0, // border_width - CopyFromParent, // depth - InputOutput, // class - CopyFromParent, // visual - valuemask, &attributes); - if (uiwin <= 0) - die("can't create window"); + unsigned long valuemask = CWBackPixel | CWBorderPixel | CWOverrideRedirect; + XSetWindowAttributes attributes; + attributes.background_pixel = g.color[COLBG].xcolor.pixel; + attributes.border_pixel = g.color[COLFRAME].xcolor.pixel; + attributes.override_redirect = 1; + uiwin = XCreateWindow(dpy, root, uiwinX, uiwinY, uiwinW, uiwinH, 0, // border_width + CopyFromParent, // depth + InputOutput, // class + CopyFromParent, // visual + valuemask, &attributes); + if (uiwin <= 0) + die("can't create window"); msg(0, "our window is 0x%lx\n", uiwin); // set properties of our window @@ -504,24 +523,25 @@ XSetClassHint(dpy, uiwin, &class_h); // warning: this overwrites any previous value. // note: x_setCommonPropertiesForAnyWindow does the same thing for any window - XSelectInput(dpy, uiwin, ExposureMask | KeyPressMask | KeyReleaseMask - | ButtonPressMask | ButtonReleaseMask); + XSelectInput(dpy, uiwin, ExposureMask | KeyPressMask | KeyReleaseMask + | ButtonPressMask | ButtonReleaseMask); + grabKeysAtUiShow(true); // set window type so that WM will hopefully not resize it // before mapping: https://specifications.freedesktop.org/wm-spec/1.3/ar01s05.html - Atom at = XInternAtom(dpy, "ATOM", True); - Atom wt = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); - Atom td = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); - if (at && wt && td) - XChangeProperty(dpy, uiwin, wt, at, 32, PropModeReplace, - (unsigned char *)(&td), 1); + Atom at = XInternAtom(dpy, "ATOM", True); + Atom wt = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); + Atom td = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); + if (at && wt && td) + XChangeProperty(dpy, uiwin, wt, at, 32, PropModeReplace, + (unsigned char *)(&td), 1); // disable appearance in taskbar Atom st = XInternAtom(dpy, "_NET_WM_STATE", True); Atom sk = XInternAtom(dpy, "_NET_WM_STATE_SKIP_TASKBAR", True); // there is also PAGER if (at && st && sk) XChangeProperty(dpy, uiwin, st, at, 32, PropModeReplace, - (unsigned char *)(&sk), 1); + (unsigned char *)(&sk), 1); // xmonad ignores _NET_WM_WINDOW_TYPE_DIALOG but obeys WM_TRANSIENT_FOR - XSetTransientForHint(dpy, uiwin, uiwin); + XSetTransientForHint(dpy, uiwin, uiwin); // disable window title and borders. works in xfwm4. #define PROP_MOTIF_WM_HINTS_ELEMENTS 5 #define MWM_HINTS_DECORATIONS (1L << 1) @@ -531,38 +551,44 @@ unsigned long decorations; long inputMode; unsigned long status; - } hints = { MWM_HINTS_DECORATIONS, 0, 0, }; + } hints = { + MWM_HINTS_DECORATIONS, 0, 0,}; Atom ma = XInternAtom(dpy, "_MOTIF_WM_HINTS", False); if (ma) { XChangeProperty(dpy, uiwin, ma, ma, 32, PropModeReplace, - (unsigned char *)&hints, PROP_MOTIF_WM_HINTS_ELEMENTS); + (unsigned char *)&hints, PROP_MOTIF_WM_HINTS_ELEMENTS); } XMapWindow(dpy, uiwin); // positioning and size hints. // centering required in JWM. - // should really perform centering when + // should really perform centering when // viewport == wm screen. how would we know the latter? long sflags; - sflags = USPosition|USSize|PPosition|PSize|PMinSize|PMaxSize|PBaseSize; + sflags = + USPosition | USSize | PPosition | PSize | PMinSize | PMaxSize | + PBaseSize; // gravity: https://tronche.com/gui/x/xlib/window/attributes/gravity.html if (g.option_positioning != POS_NONE) sflags |= PWinGravity; XSizeHints uiwinSizeHints = { sflags, - uiwinX, uiwinY, // obsoleted - uiwinW, uiwinH, // obsoleted + uiwinX, uiwinY, // obsoleted + uiwinW, uiwinH, // obsoleted uiwinW, uiwinH, uiwinW, uiwinH, 0, 0, - {0,0}, {0,0}, + {0, 0} + , {0, 0} + , uiwinW, uiwinH, - (g.option_positioning == POS_CENTER + (g.option_positioning == POS_CENTER //&& g.option_vp_mode != VP_SPECIFIC) ? CenterGravity : ForgetGravity }; - && g.option_vp_mode != VP_SPECIFIC) ? CenterGravity : StaticGravity }; + && g.option_vp_mode != VP_SPECIFIC) ? CenterGravity : StaticGravity + }; XSetWMNormalHints(dpy, uiwin, &uiwinSizeHints); - return 1; + return 1; } // @@ -579,13 +605,11 @@ if (get_absolute_coordinates(uiwin, &uwq)) { // debug for #54 msg(1, "attr abs at expose: %dx%d +%d+%d\n", - uwq.w, uwq.h, uwq.x, uwq.y); + uwq.w, uwq.h, uwq.x, uwq.y); int xdiff = uwq.x - uiwinX; int ydiff = uwq.y - uiwinY; - if (abs(xdiff) > FRAME_W / 2 || - abs(ydiff) > FRAME_W / 2) { - msg(1, - "WM moved uiwin too far, trying to correct\n"); + if (abs(xdiff) > FRAME_W / 2 || abs(ydiff) > FRAME_W / 2) { + msg(1, "WM moved uiwin too far, trying to correct\n"); XMoveWindow(dpy, uiwin, uiwinX, uiwinY); } if (uwq.w != uiwinW || uwq.h != uiwinH) { @@ -593,25 +617,25 @@ // floating_maximum_size in #54. // there is little can be done here, // so just complain. - msg(-1, - "switcher window resized, expect bugs. Please configure WM to not interfere with alttab window size, for example, disable 'floating_maximum_size' in i3\n"); + msg(-1, + "switcher window resized, expect bugs. Please configure WM to not interfere with alttab window size, for example, disable 'floating_maximum_size' in i3\n"); } } // icons - int j; - for (j = 0; j < g.maxNdx; j++) { - if (g.winlist[j].tile) { + int j; + for (j = 0; j < g.maxNdx; j++) { + if (g.winlist[j].tile) { msg(1, "copying tile %d to canvas\n", j); - //XSync (dpy, false); - int r = XCopyArea(dpy, g.winlist[j].tile, uiwin, - g.gcDirect, 0, 0, tileW, tileH, // src - j * (tileW + FRAME_W) + FRAME_W, FRAME_W); // dst - //XSync (dpy, false); + //XSync (dpy, false); + int r = XCopyArea(dpy, g.winlist[j].tile, uiwin, + g.gcDirect, 0, 0, tileW, tileH, // src + j * (tileW + FRAME_W) + FRAME_W, FRAME_W); // dst + //XSync (dpy, false); msg(1, "XCopyArea returned %d\n", r); - } - } + } + } // frame - framesRedraw(); + framesRedraw(); } // @@ -619,39 +643,39 @@ // int uiHide() { + grabKeysAtUiShow(false); // order is important: to set focus in Metacity, // our window must be destroyed first - if (uiwin) { + if (uiwin) { msg(0, "destroying our window\n"); - XUnmapWindow(dpy, uiwin); - XDestroyWindow(dpy, uiwin); - uiwin = 0; - } - if (g.winlist) { - msg(0, "changing focus to 0x%lx\n", - g.winlist[g.selNdx].id); + XUnmapWindow(dpy, uiwin); + XDestroyWindow(dpy, uiwin); + uiwin = 0; + } + if (g.winlist) { + msg(0, "changing focus to 0x%lx\n", g.winlist[selNdx].id); /* - // save the switch moment for detecting - // subsequent false focus event from WM - gettimeofday(&(g.last.tv), NULL); - g.last.prev = g.winlist[g.startNdx].id; - g.last.to = g.winlist[g.selNdx].id; - */ - setFocus(g.selNdx); // before winlist destruction! - } + // save the switch moment for detecting + // subsequent false focus event from WM + gettimeofday(&(g.last.tv), NULL); + g.last.prev = g.winlist[g.startNdx].id; + g.last.to = g.winlist[selNdx].id; + */ + setFocus(selNdx); // before winlist destruction! + } msg(0, "destroying tiles\n"); - int y; - for (y = 0; y < g.maxNdx; y++) { - if (g.winlist && g.winlist[y].tile) { - XFreePixmap(dpy, g.winlist[y].tile); - g.winlist[y].tile = 0; - } - } - if (g.winlist) { - freeWinlist(); - } - g.uiShowHasRun = false; - return 1; + int y; + for (y = 0; y < g.maxNdx; y++) { + if (g.winlist && g.winlist[y].tile) { + XFreePixmap(dpy, g.winlist[y].tile); + g.winlist[y].tile = 0; + } + } + if (g.winlist) { + freeWinlist(); + } + g.uiShowHasRun = false; + return 1; } // @@ -659,14 +683,14 @@ // int uiNextWindow() { - if (!uiwin) - return 0; // kb events may trigger it even when no window drawn yet - g.selNdx++; - if (g.selNdx >= g.maxNdx) - g.selNdx = 0; - msg(0, "item %d\n", g.selNdx); - framesRedraw(); - return 1; + if (!uiwin) + return 0; // kb events may trigger it even when no window drawn yet + selNdx++; + if (selNdx >= g.maxNdx) + selNdx = 0; + msg(0, "item %d\n", selNdx); + framesRedraw(); + return 1; } // @@ -674,14 +698,14 @@ // int uiPrevWindow() { - if (!uiwin) - return 0; // kb events may trigger it even when no window drawn yet - g.selNdx--; - if (g.selNdx < 0) - g.selNdx = g.maxNdx - 1; - msg(0, "item %d\n", g.selNdx); - framesRedraw(); - return 1; + if (!uiwin) + return 0; // kb events may trigger it even when no window drawn yet + selNdx--; + if (selNdx < 0) + selNdx = g.maxNdx - 1; + msg(0, "item %d\n", selNdx); + framesRedraw(); + return 1; } // @@ -689,14 +713,15 @@ // int uiSelectWindow(int ndx) { - if (!uiwin) - return 0; // kb events may trigger it even when no window drawn yet + if (!uiwin) + return 0; // kb events may trigger it even when no window drawn yet if (ndx < 0 || ndx >= g.maxNdx) { - return 0; } - g.selNdx = ndx; - msg(0, "item %d\n", g.selNdx); - framesRedraw(); - return 1; + return 0; + } + selNdx = ndx; + msg(0, "item %d\n", selNdx); + framesRedraw(); + return 1; } // @@ -708,22 +733,21 @@ return; if (e.type == ButtonPress) { switch (e.button) { - case 1: - lastPressedTile = pointedTile (e.x, e.y); - if (lastPressedTile != -1) - uiSelectWindow (lastPressedTile); - break; - case 4: - uiPrevWindow(); - break; - case 5: - uiNextWindow(); - break; + case 1: + lastPressedTile = pointedTile(e.x, e.y); + if (lastPressedTile != -1) + uiSelectWindow(lastPressedTile); + break; + case 4: + uiPrevWindow(); + break; + case 5: + uiNextWindow(); + break; } } if (e.type == ButtonRelease && e.button == 1) { - if (lastPressedTile != -1 - && lastPressedTile == pointedTile (e.x, e.y)) + if (lastPressedTile != -1 && lastPressedTile == pointedTile(e.x, e.y)) uiHide(); } } @@ -736,3 +760,24 @@ return uiwin; } +void shutdownGUI(void) +{ + int p; + + for (p=0; papp[0] = '\0'; - ic->src_path[0] = '\0'; - ic->src_w = ic->src_h = 0; - ic->drawable = ic->mask = 0; - ic->drawable_allocated = false; + ic = (icon_t *) malloc(sizeof(icon_t)); + if (ic == NULL) + return NULL; + + ic->app[0] = '\0'; + ic->src_path[0] = '\0'; + ic->src_w = ic->src_h = 0; + ic->drawable = ic->mask = None; + ic->drawable_allocated = false; + ic->ext = ICON_EXT_UNKNOWN; + ic->dir = ICON_DIR_FREEDESKTOP; - return ic; + return ic; } // @@ -56,10 +58,15 @@ // void deleteIcon(icon_t * ic) { - if (ic->drawable_allocated) { - XFreePixmap(dpy, ic->drawable); - } - free(ic); + if (ic->drawable_allocated) { + XFreePixmap(dpy, ic->drawable); + /* + if (ic->mask != None) { + XFreePixmap(dpy, ic->mask); + } + */ + } + free(ic); } // @@ -68,41 +75,46 @@ // int initIconHash(icon_t ** ihash) { - *ihash = NULL; // required by uthash - updateIconsFromFile(ihash); - return 1; + *ihash = NULL; // required by uthash + updateIconsFromFile(ihash); + return 1; } // -// load all icons -// (no pixmaps, just path and dimension) +// build array of icon directories +// return the number of elements or 0 // -int updateIconsFromFile(icon_t ** ihash) +int allocIconDirs(char ** icon_dirs) { - int hd; - char *id2; - int id2len; - char *icon_dirs[MAXICONDIRS]; - int d_c, f_c; - FTS *ftsp; - FTSENT *p, *chp; - icon_t *iiter, *tmp; - - int fts_options = FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOCHDIR; - // XDG_DATA_DIRS ignored - const char *icondir[] = { - "/usr/share/icons", - "/usr/local/share/icons", - "~/.icons", - "~/.local/share/icons", - NULL - }; - int idndx = 0; - int theme_len = strlen(g.option_theme); - char* home = getenv("HOME"); - - for (hd = 0; icondir[hd] != NULL; hd++) { - id2len = strlen(icondir[hd]) + 1 + theme_len + 1; + int hd; + char *id2; + int id2len; + const char *icondir[] = { + "/usr/share/icons", + "/usr/local/share/icons", + "~/.icons", + "~/.local/share/icons", + "/usr/share/pixmaps", + "~/.local/share/pixmaps", + NULL + }; + int idndx = 0; + int theme_len = strlen(g.option_theme); + char *home = getenv("HOME"); + char *xdgdd = getenv("XDG_DATA_DIRS"); + bool legacy; + char *str1; + char *xdg; + char *saveptr1; + int j; + char *k; + int idsd; + + for (hd = 0; icondir[hd] != NULL; hd++) { + legacy = (strstr (icondir[hd], "pixmap") != NULL); + id2len = strlen(icondir[hd]) + 1; + if (!legacy) + id2len += theme_len + 1; if (icondir[hd][0] == '~') { if (home == NULL) continue; @@ -112,170 +124,344 @@ if (!id2) return 0; if (icondir[hd][0] == '~') - snprintf (id2, id2len, "%s%s/%s", home, icondir[hd]+1, g.option_theme); + snprintf(id2, id2len, "%s%s", home, icondir[hd] + 1); else - snprintf (id2, id2len, "%s/%s", icondir[hd], g.option_theme); + snprintf(id2, id2len, "%s", icondir[hd]); + if (!legacy) { + strcat(id2, "/"); + strncat(id2, g.option_theme, theme_len); + } id2[id2len - 1] = '\0'; icon_dirs[idndx] = id2; idndx++; - } - icon_dirs[idndx] = NULL; - if (g.debug > 1) { - for (idndx = 0; icon_dirs[idndx] != NULL; idndx++) - msg(1, "icon dir: %s\n", icon_dirs[idndx]); - } - - if ((ftsp = fts_open(icon_dirs, fts_options, NULL)) == NULL) { - warn("fts_open"); - return 0; - } - /* Initialize ftsp with as many icon_dirs as possible. */ - chp = fts_children(ftsp, 0); - if (chp == NULL) { - return 0; /* no files to traverse */ - } - d_c = f_c = 0; - while ((p = fts_read(ftsp)) != NULL) { - switch (p->fts_info) { - case FTS_D: - //printf("d %s\n", p->fts_path); - d_c++; - break; - case FTS_F: - //msg(1, "f %s\n", p->fts_path); - inspectIconFile(p); - f_c++; - break; - default: - break; - } - } - fts_close(ftsp); - if (g.debug > 0) { - msg(0, "icon dirs: %d, files: %d, apps: %d\n", d_c, - f_c, HASH_COUNT(*ihash)); - if (g.debug > 1) { - HASH_ITER(hh, *ihash, iiter, tmp) { - msg(1, "app \"%s\" [%s] (%dx%d)\n", - iiter->app, iiter->src_path, - iiter->src_w, iiter->src_h); - } - } - } - return 1; -} // updateIconsFromFile + } + + if (xdgdd != NULL) { + for (j = 1, str1 = xdgdd; ; j++, str1 = NULL) { + xdg = strtok_r(str1, ":", &saveptr1); + if (xdg == NULL) + break; + msg(1, "xdg dir %d: %s\n", j, xdg); + // strip trailing "/"'s + for (k = xdg + strlen(xdg) - 1; *k == '/'; k--) { + *k = '\0'; + } + id2len = strlen(xdg) + strlen("/icons/") + theme_len + 1; + id2 = malloc(id2len); + if (!id2) + return 0; + snprintf(id2, id2len, "%s/icons/%s", xdg, g.option_theme); + id2[id2len - 1] = '\0'; + // search for duplicates + for (idsd = 0; idsd < idndx; idsd++) { + if (strncmp (icon_dirs[idsd], id2, id2len) == 0) { + msg(1, "skip duplicate icon dir: %s\n", id2); + free(id2); id2 = NULL; + break; + } + } + if (id2 != NULL) { + icon_dirs[idndx] = id2; + idndx++; + } + } + } + + icon_dirs[idndx] = NULL; + if (g.debug > 1) { + for (idndx = 0; icon_dirs[idndx] != NULL; idndx++) + msg(1, "icon dir: %s\n", icon_dirs[idndx]); + } + return idndx; +} + +// +// free icon_dirs +// +void destroyIconDirs(char ** icon_dirs) +{ + int idndx; + for (idndx = 0; icon_dirs[idndx] != NULL; idndx++) + free(icon_dirs[idndx]); +} + +// +// load all icons +// (no pixmaps, just path and dimension) +// +int updateIconsFromFile(icon_t ** ihash) +{ + char *icon_dirs[MAXICONDIRS]; + int d_c, f_c; + FTS *ftsp; + FTSENT *p, *chp; + icon_t *iiter, *tmp; + int fts_options = FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOCHDIR; + int ret = 0; + + if (allocIconDirs(icon_dirs) <= 0) { + goto out; + } + if ((ftsp = fts_open(icon_dirs, fts_options, NULL)) == NULL) { + warn("fts_open"); + goto out; + } + /* Initialize ftsp with as many icon_dirs as possible. */ + chp = fts_children(ftsp, 0); + if (chp == NULL) { + goto out; /* no files to traverse */ + } + d_c = f_c = 0; + while ((p = fts_read(ftsp)) != NULL) { + switch (p->fts_info) { + case FTS_D: + //printf("d %s\n", p->fts_path); + d_c++; + break; + case FTS_F: + //msg(1, "f %s\n", p->fts_path); + inspectIconMeta(p); + f_c++; + break; + default: + break; + } + } + fts_close(ftsp); + if (g.debug > 0) { + msg(0, "icon dirs: %d, files: %d, apps: %d\n", d_c, + f_c, HASH_COUNT(*ihash)); + if (g.debug > 1) { + HASH_ITER(hh, *ihash, iiter, tmp) { + msg(1, "app \"%s\" [%s] (%dx%d)\n", + iiter->app, iiter->src_path, iiter->src_w, iiter->src_h); + } + } + } + ret = 1; + +out: + destroyIconDirs(icon_dirs); + return ret; +} // updateIconsFromFile // // check if the file has better icon for given app than in g.ic // return 1 if this icon is used, 0 otherwise // -int inspectIconFile(FTSENT * pe) +int inspectIconMeta(FTSENT * pe) { - char *point; - char *fname; - char app[MAXAPPLEN]; - int applen; - char *xchar; - char *dim; - int dimlen; - char sx[5]; - char sy[5]; - int ix, iy; - icon_t *ic; - char *suff; - int sfxn; - int tl; - char *generic_suffixes[] = { "-color", NULL }; - - // skip non-apps icons - if (strcmp(pe->fts_parent->fts_name, "apps") != 0) - return 0; - - // guess app - fname = pe->fts_name; - point = rindex(fname, '.'); - if (point == NULL) - return 0; // no extension? - if (strcmp(point + 1, "png") != 0) - return 0; // going to load png only TODO: mention in doc - applen = - point - fname > (MAXAPPLEN - 1) ? (MAXAPPLEN - 1) : point - fname; - strncpy(app, fname, applen); - app[applen] = '\0'; - for (tl = 0; app[tl] != '\0'; tl++) - app[tl] = tolower(app[tl]); - - // sort of generalization - sfxn = 0; - while (generic_suffixes[sfxn] != NULL) { - suff = strcasestr(app, generic_suffixes[sfxn]); - if (suff != NULL) { - *suff = '\0'; - } - sfxn++; - } - - // guess dimensions - dim = pe->fts_parent->fts_parent->fts_name; - dimlen = pe->fts_parent->fts_parent->fts_namelen; - xchar = index(dim, 'x'); - if (xchar == NULL) - return 0; // unknown dimensions - strncpy(sx, dim, (xchar - dim)); - sx[xchar - dim] = '\0'; - ix = atoi(sx); - strncpy(sy, xchar + 1, dim + dimlen - xchar); - sy[dim + dimlen - xchar - 1] = '\0'; - iy = atoi(sy); - - // is app already in hash? - HASH_FIND_STR(g.ic, app, ic); - if (ic == NULL) { - ic = initIcon(); - strncpy(ic->app, app, MAXAPPLEN); - strncpy(ic->src_path, pe->fts_path, MAXICONPATHLEN); - ic->src_w = ix; - ic->src_h = iy; - HASH_ADD_STR(g.ic, app, ic); - } else { - // we already have icon with dimensions: ic->src_w, h - // new candidate: ix, iy - // best value: g.option_iconW, H - // should we replace the icon? - if (iconMatchBetter(ix, iy, ic->src_w, ic->src_h)) { - strncpy(ic->src_path, pe->fts_path, MAXICONPATHLEN); - ic->src_w = ix; - ic->src_h = iy; - } - } + char *point; + char *fname; + char app[MAXAPPLEN]; + int applen; + char *xchar; + char *uchar; + char *endptr; + char *dim; + int dimlen; + char sx[5]; + char sy[5]; + int ix, iy; + icon_t *ic; + char *suff; + int sfxn; + int tl; + char *lds; + char *digit; + char *minus; + char *generic_suffixes[] = { "-color", NULL }; + char *legacy_dim_suffixes[] = { "16", "24", "32", "48", "64", NULL }; + int dir = ICON_DIR_FREEDESKTOP; + int ext = ICON_EXT_UNKNOWN; + const char *special_fail_1 = "failed to interpret %s as app_WWxHH at %s\n"; + + fname = pe->fts_name; + point = strrchr(fname, '.'); + if (point == NULL) + return 0; // no extension? + if (strcmp(point + 1, "png") == 0) { + ext = ICON_EXT_PNG; + } else if (strcmp(point + 1, "xpm") == 0) { + ext = ICON_EXT_XPM; + } + if (ext == ICON_EXT_UNKNOWN) + return 0; + + if (strstr(pe->fts_parent->fts_name, "pixmap") != NULL) + dir = ICON_DIR_LEGACY; + + // skip non-apps freedesktop icons + if (dir == ICON_DIR_FREEDESKTOP && strcmp(pe->fts_parent->fts_name, "apps") != 0) + return 0; + + // guess app + applen = point - fname > (MAXAPPLEN - 1) ? (MAXAPPLEN - 1) : point - fname; + strncpy(app, fname, applen); + app[applen] = '\0'; + for (tl = 0; app[tl] != '\0'; tl++) + app[tl] = tolower(app[tl]); + + // guess dimensions by directory + if (dir == ICON_DIR_FREEDESKTOP) { + dim = pe->fts_parent->fts_parent->fts_name; + dimlen = pe->fts_parent->fts_parent->fts_namelen; + xchar = strchr(dim, 'x'); + if (xchar == NULL) + return 0; // unknown dimensions + strncpy(sx, dim, (xchar - dim)); + sx[xchar - dim] = '\0'; + ix = atoi(sx); + strncpy(sy, xchar + 1, dim + dimlen - xchar); + sy[dim + dimlen - xchar - 1] = '\0'; + iy = atoi(sy); + } else { + // icon other than a priory known dimensions has lowest priority + ix = iy = 1; + } + + // drop known suffix + sfxn = 0; + while (generic_suffixes[sfxn] != NULL) { + suff = strcasestr(app, generic_suffixes[sfxn]); + if (suff != NULL) { + *suff = '\0'; + } + sfxn++; + } - return 1; -} // inspectIconFile + // app_48x48 legacy xpm + if (dir == ICON_DIR_LEGACY) { + uchar = strrchr(app, '_'); + xchar = strrchr(app, 'x'); + if (xchar != NULL && uchar != NULL && xchar > uchar) { + strncpy(sx, uchar+1, (xchar - uchar - 1)); + sx[xchar - uchar - 1] = '\0'; + ix = strtol(sx, &endptr, 10); + if (!(*sx != '\0' && *endptr == '\0')) { + msg (0, special_fail_1, app, "WW"); + ix = 0; + goto end_special_1; + } + strncpy(sy, xchar + 1, app + strlen(app) - xchar); + sy[app + strlen(app) - xchar] = '\0'; + iy = strtol(sy, &endptr, 10); + if (!(*sy != '\0' && *endptr == '\0')) { + msg (0, special_fail_1, app, "HH"); + iy = 0; + goto end_special_1; + } + *uchar = '\0'; + } + } +end_special_1: + + // app48 and app-48 legacy xpm + if (dir == ICON_DIR_LEGACY) { + digit = app + strlen(app) - 2; + minus = app + strlen(app) - 3; // trick for gcc-10 pseudo-intelligence + if (digit > app + 1) { + sfxn = 0; + while ((lds = legacy_dim_suffixes[sfxn]) != 0) { + if (strncasecmp(digit, lds, 3) == 0) { + ix = iy = strtol(lds, &endptr, 10); + if (*(minus) == '-') { + *(minus) = '\0'; + } else { + *digit = '\0'; + } + break; + } + sfxn++; + } + } + } + + // is app already in hash? + HASH_FIND_STR(g.ic, app, ic); + if (ic == NULL) { + ic = initIcon(); + strncpy(ic->app, app, MAXAPPLEN); + strncpy(ic->src_path, pe->fts_path, MAXICONPATHLEN-1); + ic->src_w = ix; + ic->src_h = iy; + ic->ext = ext; + ic->dir = dir; + HASH_ADD_STR(g.ic, app, ic); + } else { + // we already have icon with dimensions: ic->src_w, h + // new candidate: ix, iy + // best value: g.option_iconW, H + // should we replace the icon? + if (iconMatchBetter(ix, iy, ic->src_w, ic->src_h)) { + strncpy(ic->src_path, pe->fts_path, MAXICONPATHLEN-1); + ic->src_w = ix; + ic->src_h = iy; + } + } + + return 1; +} // inspectIconMeta + +// +// update Drawable from png file +// +int loadIconContentPNG(icon_t * ic) +{ + + if (!ic->drawable_allocated) { + ic->drawable = XCreatePixmap(dpy, root, ic->src_w, ic->src_h, XDEPTH); + if (ic->drawable == None) { + msg(-1, "can't create pixmap for png icon\n"); + return 0; + } + ic->drawable_allocated = true; + } + + if (pngReadToDrawable + (ic->src_path, ic->drawable, g.color[COLBG].xcolor.red, + g.color[COLBG].xcolor.green, g.color[COLBG].xcolor.blue) == 0) { + msg(-1, "can't read png to drawable: %s\n", ic->src_path); + return 0; + } + + return 1; +} + +// +// update Drawable from xpm file +// +int loadIconContentXPM(icon_t * ic) +{ + int ret; + + ret = (XpmReadFileToPixmap(dpy, root, ic->src_path, &(ic->drawable), + &(ic->mask), NULL) == XpmSuccess) ? 1 : 0; + if (ret == 1) { + ic->drawable_allocated = true; + } else { + msg(-1, "can't read xpm to drawable: %s\n", ic->src_path); + } + + return ret; +} // // update drawable // int loadIconContent(icon_t * ic) { + int ret; - if (!ic->drawable_allocated) { - ic->drawable = - XCreatePixmap(dpy, root, ic->src_w, ic->src_h, XDEPTH); - if (ic->drawable == None) { - msg(-1, "can't create pixmap for png icon\n"); - return 0; - } - ic->drawable_allocated = true; - } - - if (pngReadToDrawable - (ic->src_path, ic->drawable, g.color[COLBG].xcolor.red, - g.color[COLBG].xcolor.green, g.color[COLBG].xcolor.blue) == 0) { - msg(-1, "can't read png to drawable\n"); - return 0; - } - - return 1; + if (ic->ext == ICON_EXT_PNG) { + ret = loadIconContentPNG(ic); + } else if (ic->ext == ICON_EXT_XPM) { + ret = loadIconContentXPM(ic); + } else { + msg(1, "unknown icon extension: %d\n", ic->ext); + ret = 0; + } + return ret; } // @@ -284,16 +470,16 @@ // icon_t *lookupIcon(char *app) { - icon_t *ic; - char appl[MAXAPPLEN]; - int l; - - for (l = 0; (*(app + l)) != '\0' && l < MAXAPPLEN; l++) - appl[l] = tolower(*(app + l)); - appl[l] = '\0'; + icon_t *ic; + char appl[MAXAPPLEN]; + int l; + + for (l = 0; (*(app + l)) != '\0' && l < MAXAPPLEN; l++) + appl[l] = tolower(*(app + l)); + appl[l] = '\0'; - HASH_FIND_STR(g.ic, appl, ic); - return ic; + HASH_FIND_STR(g.ic, appl, ic); + return ic; } // @@ -302,19 +488,24 @@ // bool iconMatchBetter(int new_w, int new_h, int old_w, int old_h) { - int hasdiff, newdiff; + int hasdiff, newdiff; - hasdiff = old_h - g.option_iconH; - newdiff = new_h - g.option_iconH; + hasdiff = old_h - g.option_iconH; + newdiff = new_h - g.option_iconH; return - (hasdiff >= 0) ? ( - (newdiff < 0) ? false : ( - (newdiff < hasdiff) ? true : false - ) - ) : ( - (newdiff >= 0) ? true : ( - (newdiff > hasdiff) ? true : false - ) + (hasdiff >= 0) ? ((newdiff < 0) ? false : ((newdiff < + hasdiff) ? true : false) + ) : ((newdiff >= 0) ? true : ((newdiff > hasdiff) ? true : false) ); } +void deleteIconHash(icon_t **ihash) +{ + icon_t *iiter, *tmp; + + HASH_ITER(hh, *ihash, iiter, tmp) { + HASH_DEL(*ihash, iiter); + if (iiter != NULL) + deleteIcon(iiter); + } +} diff -Nru alttab-1.3.0/src/icon.h alttab-1.5.0/src/icon.h --- alttab-1.3.0/src/icon.h 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/src/icon.h 2020-07-23 08:24:20.000000000 +0000 @@ -1,7 +1,7 @@ /* icon.c definitions. -Copyright 2017-2018 Alexander Kulak. +Copyright 2017-2020 Alexander Kulak. This file is part of alttab program. alttab is free software: you can redistribute it and/or modify @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -39,22 +40,34 @@ #define MAXICONPATHLEN 1024 typedef struct { - char app[MAXAPPLEN]; // application name; uthash key - char src_path[MAXICONPATHLEN]; // \0 -if not initialized or loaded from X window properties - unsigned int src_w, src_h; // width/height of source (not resized) icon - Pixmap drawable; // resized (ready to use) - Pixmap mask; - bool drawable_allocated; // we must free drawable (but not mask), because we created it - UT_hash_handle hh; + char app[MAXAPPLEN]; // application name; uthash key + char src_path[MAXICONPATHLEN]; // \0 -if not initialized or loaded from X window properties + unsigned int src_w, src_h; // width/height of source (not resized) icon. may be 1x1 if unknown, so use it only for better icon selection, not for allocations + Pixmap drawable; // resized (ready to use) + Pixmap mask; + bool drawable_allocated; // we must free drawable (but not mask), because we created it +#define ICON_EXT_UNKNOWN 0 +#define ICON_EXT_PNG 2 +#define ICON_EXT_XPM 3 + unsigned int ext; +#define ICON_DIR_FREEDESKTOP 0 // in WxH/apps/ +#define ICON_DIR_LEGACY 1 + unsigned int dir; + UT_hash_handle hh; } icon_t; icon_t *initIcon(); void deleteIcon(icon_t * ic); int initIconHash(icon_t ** ihash); -int updateIconsFromFile(icon_t ** ihash); // load all icons into hash (no pixmaps, just path and dimension) -int inspectIconFile(FTSENT * pe); // check if file pe has better icon than we have in g.ic -int loadIconContent(icon_t * ic); // update drawable -icon_t *lookupIcon(char *app); // search app icon in hash +int allocIconDirs(char ** icon_dirs); +void destroyIconDirs(char ** icon_dirs); +int updateIconsFromFile(icon_t ** ihash); // load all icons into hash (no pixmaps, just path and dimension) +int inspectIconMeta(FTSENT * pe); // check if file pe has better icon than we have in g.ic +int loadIconContentPNG(icon_t * ic); +int loadIconContentXPM(icon_t * ic); +int loadIconContent(icon_t * ic); // update drawable +icon_t *lookupIcon(char *app); // search app icon in hash bool iconMatchBetter(int new_w, int new_h, int old_w, int old_h); +void deleteIconHash(icon_t **ihash); #endif diff -Nru alttab-1.3.0/src/Makefile.am alttab-1.5.0/src/Makefile.am --- alttab-1.3.0/src/Makefile.am 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/src/Makefile.am 2020-07-23 08:24:20.000000000 +0000 @@ -1,4 +1,4 @@ bin_PROGRAMS = alttab alttab_SOURCES = alttab.c gui.c win.c x.c rp.c util.c ewmh.c icon.c pngd.c randr.c autil.c -AM_CFLAGS = $(x11_CFLAGS) $(xft_CFLAGS) $(xrender_CFLAGS) $(xrandr_CFLAGS) $(libpng_CFLAGS) $(fts_CFLAGS) -Wall -LIBS += $(x11_LIBS) $(xft_LIBS) $(xrender_LIBS) $(xrandr_LIBS) $(libpng_LIBS) $(fts_LIBS) +AM_CFLAGS = $(x11_CFLAGS) $(xft_CFLAGS) $(xrender_CFLAGS) $(xrandr_CFLAGS) $(libpng_CFLAGS) $(fts_CFLAGS) $(xpm_CFLAGS) -Wall +LIBS += $(x11_LIBS) $(xft_LIBS) $(xrender_LIBS) $(xrandr_LIBS) $(libpng_LIBS) $(fts_LIBS) $(xpm_LIBS) diff -Nru alttab-1.3.0/src/Makefile.in alttab-1.5.0/src/Makefile.in --- alttab-1.3.0/src/Makefile.in 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/src/Makefile.in 2020-07-23 08:24:20.000000000 +0000 @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.15.1 from Makefile.am. +# Makefile.in generated by automake 1.16.2 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2017 Free Software Foundation, Inc. +# Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -118,7 +118,11 @@ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp -am__depfiles_maybe = depfiles +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/alttab.Po ./$(DEPDIR)/autil.Po \ + ./$(DEPDIR)/ewmh.Po ./$(DEPDIR)/gui.Po ./$(DEPDIR)/icon.Po \ + ./$(DEPDIR)/pngd.Po ./$(DEPDIR)/randr.Po ./$(DEPDIR)/rp.Po \ + ./$(DEPDIR)/util.Po ./$(DEPDIR)/win.Po ./$(DEPDIR)/x.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) @@ -189,7 +193,7 @@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ $(x11_LIBS) $(xft_LIBS) $(xrender_LIBS) $(xrandr_LIBS) \ - $(libpng_LIBS) $(fts_LIBS) + $(libpng_LIBS) $(fts_LIBS) $(xpm_LIBS) LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ @@ -260,12 +264,14 @@ x11_LIBS = @x11_LIBS@ xft_CFLAGS = @xft_CFLAGS@ xft_LIBS = @xft_LIBS@ +xpm_CFLAGS = @xpm_CFLAGS@ +xpm_LIBS = @xpm_LIBS@ xrandr_CFLAGS = @xrandr_CFLAGS@ xrandr_LIBS = @xrandr_LIBS@ xrender_CFLAGS = @xrender_CFLAGS@ xrender_LIBS = @xrender_LIBS@ alttab_SOURCES = alttab.c gui.c win.c x.c rp.c util.c ewmh.c icon.c pngd.c randr.c autil.c -AM_CFLAGS = $(x11_CFLAGS) $(xft_CFLAGS) $(xrender_CFLAGS) $(xrandr_CFLAGS) $(libpng_CFLAGS) $(fts_CFLAGS) -Wall +AM_CFLAGS = $(x11_CFLAGS) $(xft_CFLAGS) $(xrender_CFLAGS) $(xrandr_CFLAGS) $(libpng_CFLAGS) $(fts_CFLAGS) $(xpm_CFLAGS) -Wall all: all-am .SUFFIXES: @@ -287,8 +293,8 @@ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) @@ -352,17 +358,23 @@ distclean-compile: -rm -f *.tab.c -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alttab.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/autil.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ewmh.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gui.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icon.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pngd.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/randr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rp.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/win.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alttab.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/autil.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ewmh.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gui.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icon.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pngd.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/randr.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/win.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @@ -432,7 +444,10 @@ distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -distdir: $(DISTFILES) +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ @@ -504,7 +519,17 @@ clean-am: clean-binPROGRAMS clean-generic mostlyclean-am distclean: distclean-am - -rm -rf ./$(DEPDIR) + -rm -f ./$(DEPDIR)/alttab.Po + -rm -f ./$(DEPDIR)/autil.Po + -rm -f ./$(DEPDIR)/ewmh.Po + -rm -f ./$(DEPDIR)/gui.Po + -rm -f ./$(DEPDIR)/icon.Po + -rm -f ./$(DEPDIR)/pngd.Po + -rm -f ./$(DEPDIR)/randr.Po + -rm -f ./$(DEPDIR)/rp.Po + -rm -f ./$(DEPDIR)/util.Po + -rm -f ./$(DEPDIR)/win.Po + -rm -f ./$(DEPDIR)/x.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags @@ -550,7 +575,17 @@ installcheck-am: maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) + -rm -f ./$(DEPDIR)/alttab.Po + -rm -f ./$(DEPDIR)/autil.Po + -rm -f ./$(DEPDIR)/ewmh.Po + -rm -f ./$(DEPDIR)/gui.Po + -rm -f ./$(DEPDIR)/icon.Po + -rm -f ./$(DEPDIR)/pngd.Po + -rm -f ./$(DEPDIR)/randr.Po + -rm -f ./$(DEPDIR)/rp.Po + -rm -f ./$(DEPDIR)/util.Po + -rm -f ./$(DEPDIR)/win.Po + -rm -f ./$(DEPDIR)/x.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic @@ -570,7 +605,7 @@ .MAKE: install-am install-strip -.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-binPROGRAMS clean-generic cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ diff -Nru alttab-1.3.0/src/pngd.c alttab-1.5.0/src/pngd.c --- alttab-1.3.0/src/pngd.c 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/src/pngd.c 2020-07-23 08:24:20.000000000 +0000 @@ -1,7 +1,7 @@ /* Reading PNG into Drawable. -Copyright 2017-2018 Alexander Kulak. +Copyright 2017-2020 Alexander Kulak. This file is part of alttab program. alttab is free software: you can redistribute it and/or modify @@ -19,6 +19,7 @@ */ #include +#include #include "pngd.h" extern Display *dpy; @@ -30,39 +31,44 @@ // int pngInit(FILE * infile, TImage * img) { - png_structp png_ptr; - png_infop info_ptr; - png_uint_32 width, height; - uint8_t sig[8]; - - if (fread(sig, 1, 8, infile) == 0) - return 0; - if (!png_check_sig(sig, 8)) - return 0; - png_ptr = - png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_ptr) - return 0; - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_read_struct(&png_ptr, NULL, NULL); - return 0; - } - if (setjmp(png_jmpbuf(png_ptr))) { - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - return 0; - } - png_init_io(png_ptr, infile); - png_set_sig_bytes(png_ptr, 8); - png_read_info(png_ptr, info_ptr); - png_get_IHDR(png_ptr, info_ptr, &width, &height, &(img->bit_depth), - &(img->color_type), NULL, NULL, NULL); - img->width = width; - img->height = height; - img->png_ptr = png_ptr; - img->info_ptr = info_ptr; + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 width, height; + uint8_t sig[8]; - return 1; + if (fread(sig, 1, 8, infile) == 0) + return 0; + if (!png_check_sig(sig, 8)) + return 0; + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + return 0; + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_read_struct(&png_ptr, NULL, NULL); + return 0; + } + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + return 0; + } + png_init_io(png_ptr, infile); + png_set_sig_bytes(png_ptr, 8); + png_read_info(png_ptr, info_ptr); + png_get_IHDR(png_ptr, info_ptr, &width, &height, &(img->bit_depth), + &(img->color_type), NULL, NULL, NULL); + img->width = width; + img->height = height; + img->png_ptr = png_ptr; + img->info_ptr = info_ptr; + + return 1; +} + +static void pngFree(TImage *img) +{ + png_destroy_read_struct(&img->png_ptr, &img->info_ptr, NULL); + free(img->data); } // @@ -70,68 +76,54 @@ // uint8_t *pngLoadData(TImage * img) { - double gamma; - png_uint_32 i, rowbytes; + double gamma; + png_uint_32 i, rowbytes; - png_bytepp row_ptrs = NULL; - uint8_t *data = NULL; // local - static double exponent = 2.2; - - if (setjmp(png_jmpbuf(img->png_ptr))) { - png_destroy_read_struct(&(img->png_ptr), &(img->info_ptr), - NULL); - return NULL; - } - if (img->color_type == PNG_COLOR_TYPE_PALETTE) - png_set_expand(img->png_ptr); - if (img->color_type == PNG_COLOR_TYPE_GRAY && img->bit_depth < 8) - png_set_expand(img->png_ptr); - if (png_get_valid(img->png_ptr, img->info_ptr, PNG_INFO_tRNS)) - png_set_expand(img->png_ptr); - if (img->bit_depth == 16) - png_set_strip_16(img->png_ptr); - if (img->color_type == PNG_COLOR_TYPE_GRAY || - img->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb(img->png_ptr); - if (png_get_gAMA(img->png_ptr, img->info_ptr, &gamma)) - png_set_gamma(img->png_ptr, exponent, gamma); - - png_read_update_info(img->png_ptr, img->info_ptr); - img->rowbytes = rowbytes = - png_get_rowbytes(img->png_ptr, img->info_ptr); - img->channels = (int)png_get_channels(img->png_ptr, img->info_ptr); - if ((data = (uint8_t *) malloc(rowbytes * (img->height))) == NULL) { - png_destroy_read_struct(&img->png_ptr, &img->info_ptr, NULL); - return NULL; - } - if ((row_ptrs = - (png_bytepp) malloc((img->height) * sizeof(png_bytep))) == NULL) { - png_destroy_read_struct(&(img->png_ptr), &(img->info_ptr), - NULL); - free(data); - data = NULL; - return NULL; - } - for (i = 0; i < img->height; ++i) - row_ptrs[i] = data + i * rowbytes; - - png_read_image(img->png_ptr, row_ptrs); - free(row_ptrs); - row_ptrs = NULL; - png_read_end(img->png_ptr, NULL); - - return data; -} + png_bytepp row_ptrs = NULL; + uint8_t *data = NULL; // local + static double exponent = 2.2; + + if (setjmp(png_jmpbuf(img->png_ptr))) { + png_destroy_read_struct(&(img->png_ptr), &(img->info_ptr), NULL); + return NULL; + } + if (img->color_type == PNG_COLOR_TYPE_PALETTE) + png_set_expand(img->png_ptr); + if (img->color_type == PNG_COLOR_TYPE_GRAY && img->bit_depth < 8) + png_set_expand(img->png_ptr); + if (png_get_valid(img->png_ptr, img->info_ptr, PNG_INFO_tRNS)) + png_set_expand(img->png_ptr); + if (img->bit_depth == 16) + png_set_strip_16(img->png_ptr); + if (img->color_type == PNG_COLOR_TYPE_GRAY || + img->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(img->png_ptr); + if (png_get_gAMA(img->png_ptr, img->info_ptr, &gamma)) + png_set_gamma(img->png_ptr, exponent, gamma); + + png_read_update_info(img->png_ptr, img->info_ptr); + img->rowbytes = rowbytes = png_get_rowbytes(img->png_ptr, img->info_ptr); + img->channels = (int)png_get_channels(img->png_ptr, img->info_ptr); + if ((data = (uint8_t *) malloc(rowbytes * (img->height))) == NULL) { + png_destroy_read_struct(&img->png_ptr, &img->info_ptr, NULL); + return NULL; + } + if ((row_ptrs = + (png_bytepp) malloc((img->height) * sizeof(png_bytep))) == NULL) { + png_destroy_read_struct(&(img->png_ptr), &(img->info_ptr), NULL); + free(data); + data = NULL; + return NULL; + } + for (i = 0; i < img->height; ++i) + row_ptrs[i] = data + i * rowbytes; + + png_read_image(img->png_ptr, row_ptrs); + free(row_ptrs); + row_ptrs = NULL; + png_read_end(img->png_ptr, NULL); -int convert_msb(uint32_t in) -{ - int out; - for (out = 31; out >= 0; --out) { - if (in & 0x80000000L) - break; - in <<= 1; - } - return out; + return data; } // @@ -139,148 +131,153 @@ // using: intermediate ximage, visual, background // int pngDraw(TImage * img, Drawable d, XImage * ximage, Visual * visual, - uint8_t bg_red, uint8_t bg_green, uint8_t bg_blue) + uint8_t bg_red, uint8_t bg_green, uint8_t bg_blue) { - uint8_t *src; - char *dest; - uint8_t r, g, b, a; - uint32_t pixel; - int RShift, GShift, BShift; - uint32_t RMask, GMask, BMask; - uint32_t red, green, blue; - - int xrowbytes = ximage->bytes_per_line; - uint32_t i, row, lastrow = 0; - GC gc = DefaultGC(dpy, scr); - - RMask = visual->red_mask; - GMask = visual->green_mask; - BMask = visual->blue_mask; - RShift = convert_msb(RMask) - 7; - GShift = convert_msb(GMask) - 7; - BShift = convert_msb(BMask) - 7; - - for (lastrow = row = 0; row < img->height; ++row) { - src = img->data + row * img->rowbytes; - dest = ximage->data + row * xrowbytes; - if (img->channels == 3) { - for (i = img->width; i > 0; --i) { - red = *src++; - green = *src++; - blue = *src++; - pixel = (red << RShift) | - (green << GShift) | (blue << BShift); - *dest++ = (char)((pixel >> 24) & 0xff); - *dest++ = (char)((pixel >> 16) & 0xff); - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)(pixel & 0xff); - } - } else { /* if (channels == 4) */ - - for (i = img->width; i > 0; --i) { - r = *src++; - g = *src++; - b = *src++; - a = *src++; - if (a == 255) { - red = r; - green = g; - blue = b; - } else if (a == 0) { - red = bg_red; - green = bg_green; - blue = bg_blue; - } else { - alpha_composite(red, r, a, bg_red); - alpha_composite(green, g, a, bg_green); - alpha_composite(blue, b, a, bg_blue); - } - //fprintf (stderr, "r=%d g=%d b=%d a=%d red=%d green=%d blue=%d RShift=%d GShift=%d BShift=%d\n", r, g, b, a, red, green, blue, RShift, GShift, BShift); - pixel = (red << RShift) | - (green << GShift) | (blue << BShift); - *dest++ = (char)((pixel >> 24) & 0xff); - *dest++ = (char)((pixel >> 16) & 0xff); - *dest++ = (char)((pixel >> 8) & 0xff); - *dest++ = (char)(pixel & 0xff); - } - } - if (((row + 1) & 0xf) == 0) { - XPutImage(dpy, d, gc, ximage, 0, (int)lastrow, 0, - (int)lastrow, img->width, 16); - XFlush(dpy); - lastrow = row + 1; - } - } - - if (lastrow < img->height) { - XPutImage(dpy, d, gc, ximage, 0, (int)lastrow, 0, - (int)lastrow, img->width, img->height - lastrow); - } + uint8_t *src; + char *dest; + uint8_t r, g, b, a; + uint32_t pixel; + int RShift, GShift, BShift; + uint32_t RMask, GMask, BMask; + uint32_t red, green, blue; + + int xrowbytes = ximage->bytes_per_line; + uint32_t i, row, lastrow = 0; + GC gc = DefaultGC(dpy, scr); + + // TODO: replace this by initCompositeConst/pixelComposite from util + RMask = visual->red_mask; + GMask = visual->green_mask; + BMask = visual->blue_mask; + RShift = convert_msb(RMask) - 7; + GShift = convert_msb(GMask) - 7; + BShift = convert_msb(BMask) - 7; + + for (lastrow = row = 0; row < img->height; ++row) { + src = img->data + row * img->rowbytes; + dest = ximage->data + row * xrowbytes; + if (img->channels == 3) { + for (i = img->width; i > 0; --i) { + red = *src++; + green = *src++; + blue = *src++; + pixel = (red << RShift) | (green << GShift) | (blue << BShift); + *dest++ = (char)((pixel >> 24) & 0xff); + *dest++ = (char)((pixel >> 16) & 0xff); + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)(pixel & 0xff); + } + } else { /* if (channels == 4) */ + + for (i = img->width; i > 0; --i) { + r = *src++; + g = *src++; + b = *src++; + a = *src++; + if (a == 255) { + red = r; + green = g; + blue = b; + } else if (a == 0) { + red = bg_red; + green = bg_green; + blue = bg_blue; + } else { + alpha_composite(red, r, a, bg_red); + alpha_composite(green, g, a, bg_green); + alpha_composite(blue, b, a, bg_blue); + } + //fprintf (stderr, "r=%d g=%d b=%d a=%d red=%d green=%d blue=%d RShift=%d GShift=%d BShift=%d\n", r, g, b, a, red, green, blue, RShift, GShift, BShift); + pixel = (red << RShift) | (green << GShift) | (blue << BShift); + *dest++ = (char)((pixel >> 24) & 0xff); + *dest++ = (char)((pixel >> 16) & 0xff); + *dest++ = (char)((pixel >> 8) & 0xff); + *dest++ = (char)(pixel & 0xff); + } + } + if (((row + 1) & 0xf) == 0) { + XPutImage(dpy, d, gc, ximage, 0, (int)lastrow, 0, + (int)lastrow, img->width, 16); + XFlush(dpy); + lastrow = row + 1; + } + } + + if (lastrow < img->height) { + XPutImage(dpy, d, gc, ximage, 0, (int)lastrow, 0, + (int)lastrow, img->width, img->height - lastrow); + } - return 1; + return 1; } // // draw file on d // int pngReadToDrawable(char *pngpath, Drawable d, uint8_t bg_red, - uint8_t bg_green, uint8_t bg_blue) + uint8_t bg_green, uint8_t bg_blue) { - int debug = 0; + int debug = 0; - FILE *infile; - Visual *visual; - TImage img; - uint8_t *xdata; - int pad; - XImage *ximage; - int depth; - - img.data = NULL; - img.png_ptr = NULL; - img.info_ptr = NULL; - visual = DefaultVisual(dpy, scr); - depth = DisplayPlanes(dpy, scr); - - if (!(depth == 24 || depth == 32)) { - fprintf(stderr, "X11 depth must be 24 or 32, we have %d\n", - depth); - return 0; - } - if (!(infile = fopen(pngpath, "rb"))) { - fprintf(stderr, "can't open [%s]\n", pngpath); - return 0; - } - if ((pngInit(infile, &img)) != 1) { - fprintf(stderr, "error reading png header\n"); - return 0; - } - img.data = pngLoadData(&img); - fclose(infile); - if (!img.data || img.width == 0 || img.height == 0) { - fprintf(stderr, "error loading png data\n"); - return 0; - } - if (debug > 0) - fprintf(stderr, "read %dx%d png, %d channels\n", img.width, - img.height, img.channels); - xdata = (uint8_t *) malloc(4 * img.width * img.height); - pad = 32; - if (!xdata) { - fprintf(stderr, "xdata malloc error\n"); - return 0; - } - ximage = - XCreateImage(dpy, visual, depth, ZPixmap, 0, (char *)xdata, - img.width, img.height, pad, 0); - if (!ximage) { - fprintf(stderr, "error creating ximage\n"); - free(xdata); - return 0; - } - ximage->byte_order = MSBFirst; + FILE *infile; + Visual *visual; + TImage img; + uint8_t *xdata; + int pad; + XImage *ximage; + int depth; + int ret; + + img.data = NULL; + img.png_ptr = NULL; + img.info_ptr = NULL; + visual = DefaultVisual(dpy, scr); + depth = DisplayPlanes(dpy, scr); - return pngDraw(&img, d, ximage, visual, bg_red, bg_green, bg_blue); + if (!(depth == 24 || depth == 32)) { + fprintf(stderr, "X11 depth must be 24 or 32, we have %d\n", depth); + return 0; + } + if (!(infile = fopen(pngpath, "rb"))) { + fprintf(stderr, "can't open [%s]\n", pngpath); + return 0; + } + if ((pngInit(infile, &img)) != 1) { + fprintf(stderr, "error reading png header\n"); + return 0; + } + img.data = pngLoadData(&img); + fclose(infile); + if (!img.data || img.width == 0 || img.height == 0) { + fprintf(stderr, "error loading png data\n"); + pngFree(&img); + return 0; + } + if (debug > 0) + fprintf(stderr, "read %dx%d png, %d channels\n", img.width, + img.height, img.channels); + xdata = (uint8_t *) malloc(4 * img.width * img.height); + pad = 32; + if (!xdata) { + fprintf(stderr, "xdata malloc error\n"); + pngFree(&img); + return 0; + } + ximage = + XCreateImage(dpy, visual, depth, ZPixmap, 0, (char *)xdata, + img.width, img.height, pad, 0); + if (!ximage) { + fprintf(stderr, "error creating ximage\n"); + free(xdata); + pngFree(&img); + return 0; + } + ximage->byte_order = MSBFirst; + + ret = pngDraw(&img, d, ximage, visual, bg_red, bg_green, bg_blue); + pngFree(&img); + XDestroyImage(ximage); + return ret; } // @@ -288,32 +285,32 @@ // int pngReadToDrawable_test(char *pngfile) { - Window p; - XEvent e; + Window p; + XEvent e; - // define these as globals in caller - dpy = XOpenDisplay(NULL); - scr = DefaultScreen(dpy); - root = RootWindow(dpy, scr); - - p = XCreateSimpleWindow(dpy, root, 0, 0, 600, 600, 0, - WhitePixel(dpy, scr), WhitePixel(dpy, scr)); - if (p == None) { - fprintf(stderr, "error creating main window\n"); - return 0; - } - XSelectInput(dpy, p, ExposureMask | KeyPressMask | KeyReleaseMask); - XMapWindow(dpy, p); - do - XNextEvent(dpy, &e); - while (e.type != Expose || e.xexpose.count); - XFlush(dpy); - - if (pngReadToDrawable(pngfile, p, 255, 255, 255) != 1) { - fprintf(stderr, "can't read png to drawadle\n"); - return 0; - } + // define these as globals in caller + dpy = XOpenDisplay(NULL); + scr = DefaultScreen(dpy); + root = RootWindow(dpy, scr); + + p = XCreateSimpleWindow(dpy, root, 0, 0, 600, 600, 0, + WhitePixel(dpy, scr), WhitePixel(dpy, scr)); + if (p == None) { + fprintf(stderr, "error creating main window\n"); + return 0; + } + XSelectInput(dpy, p, ExposureMask | KeyPressMask | KeyReleaseMask); + XMapWindow(dpy, p); + do + XNextEvent(dpy, &e); + while (e.type != Expose || e.xexpose.count); + XFlush(dpy); + + if (pngReadToDrawable(pngfile, p, 255, 255, 255) != 1) { + fprintf(stderr, "can't read png to drawadle\n"); + return 0; + } - sleep(2); - return 1; + sleep(2); + return 1; } diff -Nru alttab-1.3.0/src/pngd.h alttab-1.5.0/src/pngd.h --- alttab-1.3.0/src/pngd.h 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/src/pngd.h 2020-07-23 08:24:20.000000000 +0000 @@ -1,7 +1,7 @@ /* pngd.c definitions. -Copyright 2017-2018 Alexander Kulak. +Copyright 2017-2020 Alexander Kulak. This file is part of alttab program. alttab is free software: you can redistribute it and/or modify @@ -26,31 +26,26 @@ #include #include #include +#include "util.h" // PUBLIC -#define alpha_composite(composite, fg, alpha, bg) { \ - uint16_t shiftarg = ((uint16_t)(fg) * (uint16_t)(alpha) + \ - (uint16_t)(bg) * (uint16_t)(255 - (uint16_t)(alpha)) + (uint16_t)128); \ - (composite) = (uint8_t)((shiftarg + (shiftarg >> 8)) >> 8); \ -} - typedef struct { - png_structp png_ptr; - png_infop info_ptr; - png_uint_32 width, height; - int bit_depth, color_type, channels; - uint32_t rowbytes; - uint8_t *data; + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 width, height; + int bit_depth, color_type, channels; + uint32_t rowbytes; + uint8_t *data; } TImage; int pngInit(FILE * infile, TImage * img); uint8_t *pngLoadData(TImage * img); int convert_msb(uint32_t in); int pngDraw(TImage * img, Drawable d, XImage * ximage, Visual * visual, - uint8_t bg_red, uint8_t bg_green, uint8_t bg_blue); + uint8_t bg_red, uint8_t bg_green, uint8_t bg_blue); int pngReadToDrawable(char *pngpath, Drawable d, uint8_t bg_red, - uint8_t bg_green, uint8_t bg_blue); + uint8_t bg_green, uint8_t bg_blue); int pngReadToDrawable_test(); #endif diff -Nru alttab-1.3.0/src/randr.c alttab-1.5.0/src/randr.c --- alttab-1.3.0/src/randr.c 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/src/randr.c 2020-07-23 08:24:20.000000000 +0000 @@ -1,7 +1,7 @@ /* Interface to XRANDR -Copyright 2017-2018 Alexander Kulak. +Copyright 2017-2020 Alexander Kulak. This file is part of alttab program. alttab is free software: you can redistribute it and/or modify @@ -27,14 +27,14 @@ #include "alttab.h" #include "util.h" extern Globals g; -extern Display* dpy; +extern Display *dpy; extern int scr; extern Window root; -// Documentation: +// Documentation: // https://cgit.freedesktop.org/xorg/proto/randrproto/tree/randrproto.txt -// version requirements: +// version requirements: // RRGetScreenResourcesCurrent (1.3) #define MAJ_REQ 1 #define MIN_REQ 3 @@ -47,39 +47,46 @@ // // update outs, return nout or 0 // -int randr_update_outputs(Window w, quad **outs) +static int randr_update_outputs(Window w, quad ** outs) { XRRScreenResources *scr_res; XRROutputInfo *out_info; XRRCrtcInfo *crtc_info; int nout; - int out; // as returned by randr; may include inactive + int out; // as returned by randr; may include inactive - scr_res = XRRGetScreenResourcesCurrent (dpy, w); - if (scr_res == NULL) return 0; + scr_res = XRRGetScreenResourcesCurrent(dpy, w); + if (scr_res == NULL) + return 0; nout = 0; (*outs) = NULL; - for (out = 0; out < scr_res->noutput; out++ ) { - out_info = XRRGetOutputInfo (dpy, scr_res, scr_res->outputs[out]); - if (out_info->connection != RR_Connected) + for (out = 0; out < scr_res->noutput; out++) { + out_info = XRRGetOutputInfo(dpy, scr_res, scr_res->outputs[out]); + if (out_info == NULL + || out_info->connection != RR_Connected || out_info->crtc == 0) { + XRRFreeOutputInfo(out_info); // does it neen NULL check? continue; - crtc_info = XRRGetCrtcInfo (dpy, scr_res, out_info->crtc); - (*outs) = realloc ((*outs), (nout + 1) * sizeof(quad)); - if ((*outs) == NULL) return 0; + } + crtc_info = XRRGetCrtcInfo(dpy, scr_res, out_info->crtc); + if (crtc_info == NULL) + continue; + (*outs) = realloc((*outs), (nout + 1) * sizeof(quad)); + if ((*outs) == NULL) + return 0; // would be nice to free Infos (*outs)[nout].x = crtc_info->x; (*outs)[nout].y = crtc_info->y; (*outs)[nout].w = crtc_info->width; (*outs)[nout].h = crtc_info->height; msg(0, - "output %d (%d by randr) crtc: +%d+%d %dx%d noutput %d npossible %d\n", - nout, out, - crtc_info->x, crtc_info->y, crtc_info->width, crtc_info->height, - crtc_info->noutput, crtc_info->npossible); + "output %d (%d by randr) crtc: +%d+%d %dx%d noutput %d npossible %d\n", + nout, out, + crtc_info->x, crtc_info->y, crtc_info->width, crtc_info->height, + crtc_info->noutput, crtc_info->npossible); XRRFreeCrtcInfo(crtc_info); - XRRFreeOutputInfo (out_info); + XRRFreeOutputInfo(out_info); nout++; } - //XRRFreeScreenResources(scr_res); // don't do this for XRRGetScreenResourcesCurrent? + XRRFreeScreenResources(scr_res); return nout; } @@ -88,7 +95,7 @@ // or focus point (depending on vp_mode). // res and fw must be allocated by caller. // -bool x_get_activity_area (quad *res, Window *fw) +static bool x_get_activity_area(quad * res, Window * fw) { #define VPM g.option_vp_mode int rtr; @@ -99,23 +106,22 @@ *fw = 0; if (VPM == VP_FOCUS) { - if (XGetInputFocus (dpy, fw, &rtr) == 0 || (*fw) == 0) { + if (XGetInputFocus(dpy, fw, &rtr) == 0 || (*fw) == 0) { msg(-1, "can't recognize focused window\n"); return false; } - if (! get_absolute_coordinates(*fw, res)) { + if (!get_absolute_coordinates(*fw, res)) { msg(-1, "can't get window 0x%lx absolute coordinates\n", (*fw)); return false; } msg(0, "focus in window 0x%lx (%dx%d +%d+%d)\n", - (*fw), res->w, res->h, - res->x, res->y); + (*fw), res->w, res->h, res->x, res->y); return true; } if (VPM == VP_POINTER) { - if (! XQueryPointer(dpy, root, &root_ret, &child_ret, - &root_x, &root_y, &win_x, &win_y, &mask_ret) ) { + if (!XQueryPointer(dpy, root, &root_ret, &child_ret, + &root_x, &root_y, &win_x, &win_y, &mask_ret)) { // pointer is not on the same screen as root return false; } @@ -126,7 +132,6 @@ msg(0, "pointer: +%d+%d\n", res->x, res->y); return true; } - // unknown vp_mode return false; } @@ -141,12 +146,10 @@ { int maj, min; bool ok; - Status s = XRRQueryVersion (dpy, &maj, &min); + Status s = XRRQueryVersion(dpy, &maj, &min); if (s != 0) { - ok = ( - (maj == MAJ_REQ && min >= MIN_REQ) || - (maj > MAJ_REQ) - ); + ok = ((maj == MAJ_REQ && min >= MIN_REQ) || (maj > MAJ_REQ) + ); } else { ok = false; } @@ -155,7 +158,7 @@ msg(0, "randr not available\n"); else msg(0, "randr v. %d.%d available (%ssufficient)\n", - maj, min, ok ? "" : "not "); + maj, min, ok ? "" : "not "); } return ok; } @@ -165,50 +168,54 @@ // of false if not found. // res must be allocated by caller. // -bool randrGetViewport(quad *res, bool *multihead) +bool randrGetViewport(quad * res, bool * multihead) { Window fw = 0; - quad aq; // 'activity area': focused window geometry or pointer point - quad *oq; // outputs geometries + quad aq; // 'activity area': focused window geometry or pointer point + quad *oq = NULL; // outputs geometries int o, no; int x1, x2, y1, y2, area; - quad lq; // largest cross-section at 1st stage + quad lq; // largest cross-section at 1st stage int largest_cross_area = 0; // its square int best_1_stage_output = -1; int best_2_stage_output = -1; int smallest_2_stage_area; - + //no = randr_update_outputs(fw != 0 ? fw : root, &oq); // no fw here no = randr_update_outputs(root, &oq); if (no < 1) { msg(0, "randr didn't detect any output\n"); *multihead = false; - if (oq != NULL) free (oq); + free(oq); return false; } if (no == 1) { msg(0, "using single randr output as viewport\n"); *res = oq[0]; *multihead = false; - free (oq); return true; + free(oq); + return true; } *multihead = true; - if (! x_get_activity_area (&aq, &fw)) { + if (!x_get_activity_area(&aq, &fw)) { msg(0, "failed to detect activity area, using first randr output\n"); *res = oq[0]; - free (oq); return true; + free(oq); + return true; } for (o = 0; o < no; o++) { - if (rectangles_cross (aq, oq[o])) { + if (rectangles_cross(aq, oq[o])) { // this output has a common cross-section with activity area, // now find this cross-section. x1 = aq.x > oq[o].x ? aq.x : oq[o].x; - x2 = (aq.x + aq.w) < (oq[o].x + oq[o].w) ? (aq.x + aq.w) :(oq[o].x + oq[o].w); + x2 = (aq.x + aq.w) < + (oq[o].x + oq[o].w) ? (aq.x + aq.w) : (oq[o].x + oq[o].w); y1 = aq.y > oq[o].y ? aq.y : oq[o].y; - y2 = (aq.y + aq.h) < (oq[o].y + oq[o].h) ? (aq.y + aq.h) :(oq[o].y + oq[o].h); + y2 = (aq.y + aq.h) < + (oq[o].y + oq[o].h) ? (aq.y + aq.h) : (oq[o].y + oq[o].h); area = (x2 - x1) * (y2 - y1); msg(0, "output %d cross-section: %d\n", o, area); if (area > largest_cross_area) { @@ -220,35 +227,37 @@ largest_cross_area = area; } /* - // disabled feature: - // total area of CRTCs which have cross-section with focused window - if (oq[o].x < res->x) res->x = oq[o].x; - int right_diff = (oq[o].x + oq[o].w) - (res->x + res->w); - if (right_diff > 0) res->w += right_diff; - if (oq[o].y < res->y) res->y = oq[o].y; - int bot_diff = (oq[o].y + oq[o].h) - (res->y + res->h); - if (bot_diff > 0) res->h += bot_diff; - */ + // disabled feature: + // total area of CRTCs which have cross-section with focused window + if (oq[o].x < res->x) res->x = oq[o].x; + int right_diff = (oq[o].x + oq[o].w) - (res->x + res->w); + if (right_diff > 0) res->w += right_diff; + if (oq[o].y < res->y) res->y = oq[o].y; + int bot_diff = (oq[o].y + oq[o].h) - (res->y + res->h); + if (bot_diff > 0) res->h += bot_diff; + */ } else { msg(0, "output %d doesn't cross with activity area\n", o); } - } // outputs + } // outputs if (best_1_stage_output == -1) { - msg(0, - "failed to find largest cross-section, using first randr output\n"); + msg(0, + "failed to find largest cross-section, using first randr output\n"); *res = oq[0]; - free (oq); return true; + free(oq); + return true; } - - // if best cross-area is shared with some other monitor, + // if best cross-area is shared with some other monitor, // then smallest of these monitors is choosen. - smallest_2_stage_area = oq[best_1_stage_output].w * oq[best_1_stage_output].h; + smallest_2_stage_area = + oq[best_1_stage_output].w * oq[best_1_stage_output].h; for (o = 0; o < no; o++) { - if (o == best_1_stage_output) continue; - if (rectangles_cross (lq, oq[o])) { + if (o == best_1_stage_output) + continue; + if (rectangles_cross(lq, oq[o])) { area = oq[o].w * oq[o].h; - if (area < smallest_2_stage_area ) { + if (area < smallest_2_stage_area) { best_2_stage_output = o; smallest_2_stage_area = area; } @@ -258,17 +267,17 @@ if (best_2_stage_output == -1) { best_2_stage_output = best_1_stage_output; } else { - msg(0, - "found better (smallest output) candidate: %d\n", - best_2_stage_output); + msg(0, + "found better (smallest output) candidate: %d\n", + best_2_stage_output); } // the single result here is best_2_stage_output *res = oq[best_2_stage_output]; - msg(0, - "best viewport from randr: %dx%d +%d+%d\n", - res->w, res->h, res->x, res->y); - free (oq); return true; + msg(0, + "best viewport from randr: %dx%d +%d+%d\n", + res->w, res->h, res->x, res->y); + free(oq); + return true; } - diff -Nru alttab-1.3.0/src/rp.c alttab-1.5.0/src/rp.c --- alttab-1.3.0/src/rp.c 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/src/rp.c 2020-07-23 08:24:20.000000000 +0000 @@ -1,7 +1,7 @@ /* Interface with Ratpoison window manager. -Copyright 2017-2018 Alexander Kulak. +Copyright 2017-2020 Alexander Kulak. This file is part of alttab program. alttab is free software: you can redistribute it and/or modify @@ -35,68 +35,68 @@ #define RP_MAXGROUPS 64 -char *ratpoison_cmd; +static char *ratpoison_cmd; // -// process ratpoison window_group, adding its windows +// process ratpoison window_group, adding its windows // to winlist/sortlist. // window_group must be selected in advance. // -int rp_add_windows_in_group(int current_group, int window_group) +static int rp_add_windows_in_group(int current_group, int window_group) { - char *args[] = { "ratpoison", "-c", "windows %n %i %s %t", NULL }; - char buf[MAXRPOUT]; - char *rpse = "bad token while parsing ratpoison output: "; - - bzero(buf, MAXRPOUT); - if (!execAndReadStdout(ratpoison_cmd, args, buf, MAXRPOUT)) { - msg(-1, "can't exec ratpoison\n"); - return 0; - } + char *args[] = { "ratpoison", "-c", "windows %n %i %s %t", NULL }; + char buf[MAXRPOUT]; + char *rpse = "bad token while parsing ratpoison output: "; + + bzero(buf, MAXRPOUT); + if (!execAndReadStdout(ratpoison_cmd, args, buf, MAXRPOUT)) { + msg(-1, "can't exec ratpoison\n"); + return 0; + } msg(1, "windows in current rp group:\n%s", buf); - char *rest = buf; - char *tok; + char *rest = buf; + char *tok; - if (strstr(buf, "No managed windows")) { - // no windows at all. - return 0; - } else { - while ((tok = strsep(&rest, "\r\n")) && (*tok)) { - // parse single line - char *rest2 = tok; - char *tok2; - char *endptr; - if (!((tok2 = strsep(&rest2, " \t")) && (*tok2))) - die(rpse, rest2); - int wm_id = strtol(tok2, &endptr, 10); - if (endptr == tok2) - die(rpse, tok2); - if (!((tok2 = strsep(&rest2, " \t")) && (*tok2))) - die(rpse, rest2); - int win = strtol(tok2, &endptr, 10); - if (endptr == tok2) - die(rpse, tok2); - if (!((tok2 = strsep(&rest2, " \t")) && (*tok2))) - die(rpse, rest2); - switch (*tok2) { - case '*': + if (strstr(buf, "No managed windows")) { + // no windows at all. + return 0; + } else { + while ((tok = strsep(&rest, "\r\n")) && (*tok)) { + // parse single line + char *rest2 = tok; + char *tok2; + char *endptr; + if (!((tok2 = strsep(&rest2, " \t")) && (*tok2))) + die(rpse, rest2); + int wm_id = strtol(tok2, &endptr, 10); + if (endptr == tok2) + die(rpse, tok2); + if (!((tok2 = strsep(&rest2, " \t")) && (*tok2))) + die(rpse, rest2); + int win = strtol(tok2, &endptr, 10); + if (endptr == tok2) + die(rpse, tok2); + if (!((tok2 = strsep(&rest2, " \t")) && (*tok2))) + die(rpse, rest2); + switch (*tok2) { + case '*': // pull to head // g.winlist isn't here yet! - addToSortlist (win, true, true); - break; - case '+': - case '-': - break; // use? - default: - break; - } + addToSortlist(win, true, true); + break; + case '+': + case '-': + break; // use? + default: + break; + } if (common_skipWindow(win, current_group, window_group)) return 0; - // the rest of string is name - addWindowInfo(win, 0, wm_id, window_group, rest2); - } - } - return 1; + // the rest of string is name + addWindowInfo(win, 0, wm_id, window_group, rest2); + } + } + return 1; } // PUBLIC @@ -108,55 +108,51 @@ { // search for ratpoison executable for later execv - ratpoison_cmd = (char *)malloc(MAXPATHSZ); // we don't free it, hopefully run only once - FILE *fp; + ratpoison_cmd = (char *)malloc(MAXPATHSZ); // we don't free it, hopefully run only once + FILE *fp; char *fr; // search in PATH on startup only, // then execv() for speed - if ((fp = popen("which ratpoison", "r"))) { - fr = fgets(ratpoison_cmd, MAXPATHSZ, fp); + if ((fp = popen("which ratpoison", "r"))) { + fr = fgets(ratpoison_cmd, MAXPATHSZ, fp); if (fr == NULL) { - msg(-1, "can't find ratpoison executable\n"); - return 0; + msg(-1, "can't find ratpoison executable\n"); + return 0; } - pclose(fp); - } - if (strlen(ratpoison_cmd) < 2) { - msg(-1, "can't find ratpoison executable\n"); - return 0; - } else { - ratpoison_cmd[strcspn(ratpoison_cmd, "\r\n")] = 0; + pclose(fp); + } + if (strlen(ratpoison_cmd) < 2) { + msg(-1, "can't find ratpoison executable\n"); + return 0; + } else { + ratpoison_cmd[strcspn(ratpoison_cmd, "\r\n")] = 0; msg(0, "ratpoison: %s\n", ratpoison_cmd); - } + } // insert myself in "unmanaged windows" list // this is not required, as soon as ratpoison obeys DIALOG window type, // but without "unmanage" it draws ugly additional frame around our window. - char *ua[] = { "ratpoison", "-c", "unmanage", NULL }; - char *uains[] = { "ratpoison", "-c", "unmanage " XWINNAME, NULL }; - char buf[MAXRPOUT]; - memset(buf, '\0', MAXRPOUT); - if (!execAndReadStdout(ratpoison_cmd, ua, buf, MAXRPOUT)) { - msg(-1, - "can't get unmanaged window list from ratpoison\n"); - return 1; // not fatal - } + char *ua[] = { "ratpoison", "-c", "unmanage", NULL }; + char *uains[] = { "ratpoison", "-c", "unmanage " XWINNAME, NULL }; + char buf[MAXRPOUT]; + memset(buf, '\0', MAXRPOUT); + if (!execAndReadStdout(ratpoison_cmd, ua, buf, MAXRPOUT)) { + msg(-1, "can't get unmanaged window list from ratpoison\n"); + return 1; // not fatal + } msg(1, "ratpoison reports unmanaged:\n%s", buf); - if (!strstr(buf, XWINNAME)) { - msg(0, - "registering in ratpoison unmanaged list\n"); - //memset (buf, '\0', MAXRPOUT); - if (!execAndReadStdout(ratpoison_cmd, uains, buf, MAXRPOUT)) { - msg(-1, - "can't register in ratpoison unmanaged window list\n"); - return 1; // not fatal - } - } else { - msg(0, - "our window is already in ratpoison unmanaged list\n"); - } + if (!strstr(buf, XWINNAME)) { + msg(0, "registering in ratpoison unmanaged list\n"); + //memset (buf, '\0', MAXRPOUT); + if (!execAndReadStdout(ratpoison_cmd, uains, buf, MAXRPOUT)) { + msg(-1, "can't register in ratpoison unmanaged window list\n"); + return 1; // not fatal + } + } else { + msg(0, "our window is already in ratpoison unmanaged list\n"); + } - return 1; + return 1; } // @@ -168,51 +164,49 @@ return rp_add_windows_in_group(DESKTOP_UNKNOWN, DESKTOP_UNKNOWN); } #define arg2len 19 #define intlen 10 - char arg2[arg2len]; // fits 'groups', 'gselect N' + char arg2[arg2len]; // fits 'groups', 'gselect N' char *args[] = { "ratpoison", "-c", arg2, NULL }; char buf[MAXRPOUT]; - int gr[RP_MAXGROUPS]; int ngr, gri; // numbers from 'groups' output - int w_group; // window group - int c_group = DESKTOP_UNKNOWN; // current group + int gr[RP_MAXGROUPS]; + int ngr, gri; // numbers from 'groups' output + int w_group; // window group + int c_group = DESKTOP_UNKNOWN; // current group char *endptr; - char *rest; - char *tok; + char *rest; + char *tok; g.maxNdx = 0; if (g.option_desktop == DESK_CURRENT) return rp_add_windows_in_group(DESKTOP_UNKNOWN, DESKTOP_UNKNOWN); // discover rp groups - strncpy (arg2, "groups", arg2len); + strncpy(arg2, "groups", arg2len); bzero(buf, MAXRPOUT); if (!execAndReadStdout(ratpoison_cmd, args, buf, MAXRPOUT)) - fallback - rest = buf; + fallback rest = buf; for (ngr = 0; - ((tok = strsep(&rest, "\r\n")) && (*tok) && ngr < RP_MAXGROUPS); - ngr++) { + ((tok = strsep(&rest, "\r\n")) && (*tok) && ngr < RP_MAXGROUPS); + ngr++) { // parse single line gr[ngr] = strtol(tok, &endptr, 10); if (endptr == tok) { msg(-1, "no group number detected in rp output\n"); - fallback - } + fallback} if (*endptr == '*') c_group = gr[ngr]; // the rest of line is group name, skip } if (ngr < 1) { msg(0, "no ratpoison (rpws) groups detected\n"); - fallback - } + fallback} msg(0, "number of ratpoison (rpws) groups: %d, current: %d\n", - ngr, c_group); + ngr, c_group); // cycle through rp groups for (gri = 0; gri < ngr; gri++) { w_group = gr[gri]; msg(0, "processing rp group %d\n", w_group); - snprintf (arg2, arg2len, "gselect %d", w_group); + snprintf(arg2, arg2len, "gselect %d", w_group); if (!execAndReadStdout(ratpoison_cmd, args, NULL, 0)) continue; rp_add_windows_in_group(c_group, w_group); @@ -225,20 +219,20 @@ // int rp_setFocus(int winNdx) { - char selarg[64]; - char *args[] = { "ratpoison", "-c", selarg, NULL }; - char buf[MAXRPOUT]; + char selarg[64]; + char *args[] = { "ratpoison", "-c", selarg, NULL }; + char buf[MAXRPOUT]; - // don't skip changing group if it's current, because + // don't skip changing group if it's current, because // rp_initWinlist left current group inconsistent if (g.winlist[winNdx].desktop != DESKTOP_UNKNOWN) { - snprintf(selarg, 63, "gselect %lu", g.winlist[winNdx].desktop); - execAndReadStdout(ratpoison_cmd, args, buf, MAXRPOUT); + snprintf(selarg, 63, "gselect %lu", g.winlist[winNdx].desktop); + execAndReadStdout(ratpoison_cmd, args, buf, MAXRPOUT); // ignore possible failure } - snprintf(selarg, 63, "select %d", g.winlist[winNdx].wm_id); - if (!execAndReadStdout(ratpoison_cmd, args, buf, MAXRPOUT)) - return 0; + snprintf(selarg, 63, "select %d", g.winlist[winNdx].wm_id); + if (!execAndReadStdout(ratpoison_cmd, args, buf, MAXRPOUT)) + return 0; - return 1; + return 1; } diff -Nru alttab-1.3.0/src/util.c alttab-1.5.0/src/util.c --- alttab-1.3.0/src/util.c 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/src/util.c 2020-07-23 08:24:20.000000000 +0000 @@ -1,7 +1,7 @@ /* Helper functions. -Copyright 2017-2018 Alexander Kulak. +Copyright 2017-2020 Alexander Kulak. This file is part of alttab program. alttab is free software: you can redistribute it and/or modify @@ -21,10 +21,13 @@ #include "util.h" #include #include -extern Display* dpy; +extern Display *dpy; extern int scr; extern Window root; +XErrorEvent *ee_ignored; +bool ee_complain; + // PUBLIC: // @@ -32,50 +35,52 @@ // unsigned int getOffendingModifiersMask() { - unsigned int lockmask[3]; // num=0 scroll=1 caps=2 - int i; - XModifierKeymap *map; - KeyCode numlock, scrolllock; - static int masks[8] = { - ShiftMask, LockMask, ControlMask, - Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask - }; - - memset(lockmask, 0, sizeof(unsigned int) * 3); - numlock = XKeysymToKeycode(dpy, XK_Num_Lock); - scrolllock = XKeysymToKeycode(dpy, XK_Scroll_Lock); - map = XGetModifierMapping(dpy); - if (map != NULL && map->max_keypermod > 0) { - for (i = 0; i < 8 * map->max_keypermod; i++) { - if (numlock != 0 && map->modifiermap[i] == numlock) - lockmask[0] = masks[i / map->max_keypermod]; - else if (scrolllock != 0 - && map->modifiermap[i] == scrolllock) - lockmask[1] = masks[i / map->max_keypermod]; - } - } - lockmask[2] = LockMask; - if (map) - XFreeModifiermap(map); - return (lockmask[0] | lockmask[1] | lockmask[2]); + unsigned int lockmask[3]; // num=0 scroll=1 caps=2 + int i; + XModifierKeymap *map; + KeyCode numlock, scrolllock; + static int masks[8] = { + ShiftMask, LockMask, ControlMask, + Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask + }; + + memset(lockmask, 0, sizeof(unsigned int) * 3); + numlock = XKeysymToKeycode(dpy, XK_Num_Lock); + scrolllock = XKeysymToKeycode(dpy, XK_Scroll_Lock); + map = XGetModifierMapping(dpy); + if (map != NULL && map->max_keypermod > 0) { + for (i = 0; i < 8 * map->max_keypermod; i++) { + if (numlock != 0 && map->modifiermap[i] == numlock) + lockmask[0] = masks[i / map->max_keypermod]; + else if (scrolllock != 0 && map->modifiermap[i] == scrolllock) + lockmask[1] = masks[i / map->max_keypermod]; + } + } + lockmask[2] = LockMask; + if (map) + XFreeModifiermap(map); + return (lockmask[0] | lockmask[1] | lockmask[2]); } // // for ignoring X errors // https://tronche.com/gui/x/xlib/event-handling/protocol-errors/default-handlers.html#XErrorEvent -// -int zeroErrorHandler(Display* dpy_our, XErrorEvent * theEvent) +// +int zeroErrorHandler(Display * dpy_our, XErrorEvent * theEvent) { - ee_ignored = theEvent; + ee_ignored = theEvent; #define EM 512 - char etext[EM]; - if (ee_complain) { - memset(etext, '\0', EM); - XGetErrorText(dpy_our, theEvent->error_code, etext, EM); - fprintf(stderr, "Unexpected X Error: %s\n", etext); - fprintf(stderr, "Error details: request_code=%hhu minor_code=%hhu resourceid=%lu\n", theEvent->request_code, theEvent->minor_code, theEvent->resourceid); - } - return 0; + char etext[EM]; + if (ee_complain) { + memset(etext, '\0', EM); + XGetErrorText(dpy_our, theEvent->error_code, etext, EM); + fprintf(stderr, "Unexpected X Error: %s\n", etext); + fprintf(stderr, + "Error details: request_code=%hhu minor_code=%hhu resourceid=%lu\n", + theEvent->request_code, theEvent->minor_code, + theEvent->resourceid); + } + return 0; } // @@ -84,42 +89,42 @@ // Grabs are not restored on failure. // int changeKeygrab(Window win, bool grab, KeyCode keycode, - unsigned int modmask, unsigned int ignored_modmask) + unsigned int modmask, unsigned int ignored_modmask) { - int debug = 1; - unsigned int mask = 0; + int debug = 1; + unsigned int mask = 0; - while (mask <= ignored_modmask) { - if (mask & ~(ignored_modmask)) { - ++mask; - continue; - } - if (grab) { - if (debug > 1) { - fprintf(stderr, "grabbing %d with mask %d\n", - keycode, (modmask | mask)); - } - ee_ignored = NULL; // to detect X error event - ee_complain = false; // our handler will not croak - XGrabKey(dpy, keycode, modmask | mask, win, True, - GrabModeAsync, GrabModeAsync); - XSync(dpy, False); // for error to appear - if (ee_ignored) { - ee_complain = true; - return 0; // signal caller that XGrabKey failed - } - } else { - if (debug > 1) { - fprintf(stderr, "ungrabbing %d with mask %d\n", - keycode, (modmask | mask)); - } - XUngrabKey(dpy, keycode, modmask | mask, win); - } - ++mask; - } + while (mask <= ignored_modmask) { + if (mask & ~(ignored_modmask)) { + ++mask; + continue; + } + if (grab) { + if (debug > 1) { + fprintf(stderr, "grabbing %d with mask %d\n", + keycode, (modmask | mask)); + } + ee_ignored = NULL; // to detect X error event + ee_complain = false; // our handler will not croak + XGrabKey(dpy, keycode, modmask | mask, win, True, + GrabModeAsync, GrabModeAsync); + XSync(dpy, False); // for error to appear + if (ee_ignored) { + ee_complain = true; + return 0; // signal caller that XGrabKey failed + } + } else { + if (debug > 1) { + fprintf(stderr, "ungrabbing %d with mask %d\n", + keycode, (modmask | mask)); + } + XUngrabKey(dpy, keycode, modmask | mask, win); + } + ++mask; + } - ee_complain = true; - return 1; + ee_complain = true; + return 1; } /* @@ -157,36 +162,36 @@ // int execAndReadStdout(char *exe, char *args[], char *buf, int bufsize) { - int link[2]; - pid_t pid; - ssize_t rb; - - if (pipe(link) == -1) { - perror("pipe"); - return 0; - } - if ((pid = fork()) == -1) { - perror("fork"); - return 0; - } - if (pid == 0) { - dup2(link[1], STDOUT_FILENO); - close(link[0]); - close(link[1]); - execv(exe, args); - perror("execv"); - return 0; - } else { - close(link[1]); + int link[2]; + pid_t pid; + ssize_t rb; + + if (pipe(link) == -1) { + perror("pipe"); + return 0; + } + if ((pid = fork()) == -1) { + perror("fork"); + return 0; + } + if (pid == 0) { + dup2(link[1], STDOUT_FILENO); + close(link[0]); + close(link[1]); + execv(exe, args); + perror("execv"); + return 0; + } else { + close(link[1]); if (buf != NULL) { - rb = read(link[0], buf, bufsize); - if (rb == -1) - *buf = '\0'; + rb = read(link[0], buf, bufsize); + if (rb == -1) + *buf = '\0'; } - close(link[0]); - wait(NULL); - } - return 1; + close(link[0]); + wait(NULL); + } + return 1; } // @@ -195,63 +200,60 @@ // Slow but extension-independent version // 1=success 0=fail // -int pixmapFitGeneric( Drawable src, Pixmap src_mask, Drawable dst, - unsigned int srcW, unsigned int srcH, - unsigned int dstWscal, unsigned int dstHscal, - unsigned int dstWoff, unsigned int dstHoff) -{ - unsigned long valuemask = 0; - XGCValues values; - GC gc = XCreateGC(dpy, root, valuemask, &values); - if (!gc) { - fprintf(stderr, "pixmapScale: can't create GC\n"); - return 0; - } - XImage *srci = XGetImage(dpy, src, 0, 0, srcW, srcH, - 0xffffffff, XYPixmap); - if (!srci) { - fprintf(stderr, "XGetImage failed\n"); - XFreeGC(dpy, gc); - return 0; - } - XImage *maski; - if (src_mask != 0) { - maski = XGetImage(dpy, src_mask, 0, 0, srcW, srcH, - 0xffffffff, XYPixmap); - if (!maski) { - fprintf(stderr, "XGetImage failed for the mask\n"); - XFreeGC(dpy, gc); - return 0; - } - } - unsigned long pixel; - int x, y; - int re = 0; - for (x = 0; x < dstWscal; x++) { - for (y = 0; y < dstHscal; y++) { - if (src_mask != 0 - && XGetPixel(maski, x * srcW / dstWscal, - y * srcH / dstHscal) == 0) - continue; - pixel = - XGetPixel(srci, x * srcW / dstWscal, - y * srcH / dstHscal); - if (!XSetForeground(dpy, gc, pixel)) - re++; - if (!XDrawPoint(dpy, dst, gc, x + dstWoff, y + dstHoff)) - re++; - } - } - if (re > 0) { - fprintf(stderr, "something failed during scaling %d times\n", - re); - XDestroyImage(srci); - XFreeGC(dpy, gc); - return 0; - } - XDestroyImage(srci); - XFreeGC(dpy, gc); - return 1; +int pixmapFitGeneric(Drawable src, Pixmap src_mask, Drawable dst, + unsigned int srcW, unsigned int srcH, + unsigned int dstWscal, unsigned int dstHscal, + unsigned int dstWoff, unsigned int dstHoff) +{ + unsigned long valuemask = 0; + XGCValues values; + GC gc = XCreateGC(dpy, root, valuemask, &values); + if (!gc) { + fprintf(stderr, "pixmapScale: can't create GC\n"); + return 0; + } + XImage *srci = XGetImage(dpy, src, 0, 0, srcW, srcH, + 0xffffffff, XYPixmap); + if (!srci) { + fprintf(stderr, "XGetImage failed\n"); + XFreeGC(dpy, gc); + return 0; + } + XImage *maski; + if (src_mask != 0) { + maski = XGetImage(dpy, src_mask, 0, 0, srcW, srcH, + 0xffffffff, XYPixmap); + if (!maski) { + fprintf(stderr, "XGetImage failed for the mask\n"); + XFreeGC(dpy, gc); + return 0; + } + } + unsigned long pixel; + int x, y; + int re = 0; + for (x = 0; x < dstWscal; x++) { + for (y = 0; y < dstHscal; y++) { + if (src_mask != 0 + && XGetPixel(maski, x * srcW / dstWscal, + y * srcH / dstHscal) == 0) + continue; + pixel = XGetPixel(srci, x * srcW / dstWscal, y * srcH / dstHscal); + if (!XSetForeground(dpy, gc, pixel)) + re++; + if (!XDrawPoint(dpy, dst, gc, x + dstWoff, y + dstHoff)) + re++; + } + } + if (re > 0) { + fprintf(stderr, "something failed during scaling %d times\n", re); + XDestroyImage(srci); + XFreeGC(dpy, gc); + return 0; + } + XDestroyImage(srci); + XFreeGC(dpy, gc); + return 1; } // @@ -262,54 +264,53 @@ // /usr/share/doc/libxrender-dev/libXrender.txt.gz // https://cgit.freedesktop.org/xorg/proto/renderproto/plain/renderproto.txt // -int pixmapFitXrender( Drawable src, Pixmap src_mask, Drawable dst, - unsigned int srcW, unsigned int srcH, - unsigned int dstWscal, unsigned int dstHscal, - unsigned int dstWoff, unsigned int dstHoff) -{ - Picture Psrc, Pmask, Pdst; - XRenderPictFormat *format, *format_of_mask; - XTransform transform; - - format = XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)); - if (!format) { - fprintf(stderr, "error, couldn't find valid Xrender format\n"); - return 0; - } - format_of_mask = XRenderFindStandardFormat(dpy, PictStandardA1); - if (!format_of_mask) { - fprintf(stderr, - "error, couldn't find valid Xrender format for mask\n"); - return 0; - } - Psrc = XRenderCreatePicture(dpy, src, format, 0, NULL); - Pmask = - (src_mask != 0) ? XRenderCreatePicture(dpy, src_mask, - format_of_mask, 0, NULL) : 0; - Pdst = XRenderCreatePicture(dpy, dst, format, 0, NULL); - XRenderSetPictureFilter(dpy, Psrc, FilterBilinear, 0, 0); - if (Pmask != 0) - XRenderSetPictureFilter(dpy, Pmask, FilterBilinear, 0, 0); - transform.matrix[0][0] = (srcW << 16) / dstWscal; - transform.matrix[0][1] = 0; - transform.matrix[0][2] = 0; - transform.matrix[1][0] = 0; - transform.matrix[1][1] = (srcH << 16) / dstHscal; - transform.matrix[1][2] = 0; - transform.matrix[2][0] = 0; - transform.matrix[2][1] = 0; - transform.matrix[2][2] = XDoubleToFixed(1.0); - XRenderSetPictureTransform(dpy, Psrc, &transform); - if (Pmask != 0) - XRenderSetPictureTransform(dpy, Pmask, &transform); - XRenderComposite(dpy, PictOpOver, Psrc, Pmask, Pdst, 0, 0, 0, 0, - dstWoff, dstHoff, dstWscal, dstHscal); - XRenderFreePicture(dpy, Psrc); - XRenderFreePicture(dpy, Pdst); - if (Pmask != 0) - XRenderFreePicture(dpy, Pmask); +int pixmapFitXrender(Drawable src, Pixmap src_mask, Drawable dst, + unsigned int srcW, unsigned int srcH, + unsigned int dstWscal, unsigned int dstHscal, + unsigned int dstWoff, unsigned int dstHoff) +{ + Picture Psrc, Pmask, Pdst; + XRenderPictFormat *format, *format_of_mask; + XTransform transform; + + format = XRenderFindVisualFormat(dpy, DefaultVisual(dpy, scr)); + if (!format) { + fprintf(stderr, "error, couldn't find valid Xrender format\n"); + return 0; + } + format_of_mask = XRenderFindStandardFormat(dpy, PictStandardA1); + if (!format_of_mask) { + fprintf(stderr, "error, couldn't find valid Xrender format for mask\n"); + return 0; + } + Psrc = XRenderCreatePicture(dpy, src, format, 0, NULL); + Pmask = + (src_mask != 0) ? XRenderCreatePicture(dpy, src_mask, + format_of_mask, 0, NULL) : 0; + Pdst = XRenderCreatePicture(dpy, dst, format, 0, NULL); + XRenderSetPictureFilter(dpy, Psrc, FilterBilinear, 0, 0); + if (Pmask != 0) + XRenderSetPictureFilter(dpy, Pmask, FilterBilinear, 0, 0); + transform.matrix[0][0] = (srcW << 16) / dstWscal; + transform.matrix[0][1] = 0; + transform.matrix[0][2] = 0; + transform.matrix[1][0] = 0; + transform.matrix[1][1] = (srcH << 16) / dstHscal; + transform.matrix[1][2] = 0; + transform.matrix[2][0] = 0; + transform.matrix[2][1] = 0; + transform.matrix[2][2] = XDoubleToFixed(1.0); + XRenderSetPictureTransform(dpy, Psrc, &transform); + if (Pmask != 0) + XRenderSetPictureTransform(dpy, Pmask, &transform); + XRenderComposite(dpy, PictOpOver, Psrc, Pmask, Pdst, 0, 0, 0, 0, + dstWoff, dstHoff, dstWscal, dstHscal); + XRenderFreePicture(dpy, Psrc); + XRenderFreePicture(dpy, Pdst); + if (Pmask != 0) + XRenderFreePicture(dpy, Pmask); - return 1; + return 1; } // @@ -317,39 +318,39 @@ // centering and preserving aspect ratio // 1=success 0=fail // -int pixmapFit( Drawable src, Pixmap src_mask, Drawable dst, - unsigned int srcW, unsigned int srcH, - unsigned int dstW, unsigned int dstH) -{ - int event_basep, error_basep; - int32_t fWrat, fHrat; // ratio * 65536 - int dstWscal, dstWoff, dstHscal, dstHoff; - - fWrat = (dstW << 16) / srcW; - fHrat = (dstH << 16) / srcH; - if (fWrat > fHrat) { - dstWscal = ((srcW * fHrat) >> 16); - if (abs(dstWscal - dstW) <= 1) // suppress rounding errors - dstWscal = dstW; - dstWoff = (dstW - dstWscal) / 2; - dstHscal = dstH; - dstHoff = 0; - } else { - dstWscal = dstW; - dstWoff = 0; - dstHscal = ((srcH * fWrat) >> 16); - if (abs(dstHscal - dstH) <= 1) - dstHscal = dstH; - dstHoff = (dstH - dstHscal) / 2; - } +int pixmapFit(Drawable src, Pixmap src_mask, Drawable dst, + unsigned int srcW, unsigned int srcH, + unsigned int dstW, unsigned int dstH) +{ + int event_basep, error_basep; + int32_t fWrat, fHrat; // ratio * 65536 + int dstWscal, dstWoff, dstHscal, dstHoff; + + fWrat = (dstW << 16) / srcW; + fHrat = (dstH << 16) / srcH; + if (fWrat > fHrat) { + dstWscal = ((srcW * fHrat) >> 16); + if (abs(dstWscal - dstW) <= 1) // suppress rounding errors + dstWscal = dstW; + dstWoff = (dstW - dstWscal) / 2; + dstHscal = dstH; + dstHoff = 0; + } else { + dstWscal = dstW; + dstWoff = 0; + dstHscal = ((srcH * fWrat) >> 16); + if (abs(dstHscal - dstH) <= 1) + dstHscal = dstH; + dstHoff = (dstH - dstHscal) / 2; + } - return XRenderQueryExtension(dpy, &event_basep, &error_basep) == True ? - pixmapFitXrender(src, src_mask, dst, srcW, srcH, - dstWscal, dstHscal, dstWoff, - dstHoff) : pixmapFitGeneric(src, src_mask, dst, srcW, - srcH, dstWscal, - dstHscal, dstWoff, - dstHoff); + return XRenderQueryExtension(dpy, &event_basep, &error_basep) == True ? + pixmapFitXrender(src, src_mask, dst, srcW, srcH, + dstWscal, dstHscal, dstWoff, + dstHoff) : pixmapFitGeneric(src, src_mask, dst, srcW, + srcH, dstWscal, + dstHscal, dstWoff, + dstHoff); } // @@ -357,11 +358,11 @@ // size_t utf8len(char *s) { - size_t len = 0; - for (; *s; ++s) - if ((*s & 0xC0) != 0x80) - ++len; - return len; + size_t len = 0; + for (; *s; ++s) + if ((*s & 0xC0) != 0x80) + ++len; + return len; } // @@ -370,131 +371,128 @@ // char *utf8index(char *s, size_t pos) { - ++pos; - for (; *s; ++s) { - if ((*s & 0xC0) != 0x80) - --pos; - if (pos == 0) - return s; - } - return NULL; + ++pos; + for (; *s; ++s) { + if ((*s & 0xC0) != 0x80) + --pos; + if (pos == 0) + return s; + } + return NULL; } // -// Draw utf-8 string str on window/pixmap d, +// Draw utf-8 string str on window/pixmap d, // using *font and *xrcolor, // splitting and cropping it to fit (x1,y1 - x1+width,y1+height) rectangle. // Return 1 if ok. // int drawMultiLine(Drawable d, XftFont * font, - XftColor * xftcolor, char *str, unsigned int x1, - unsigned int y1, unsigned int width, unsigned int height) + XftColor * xftcolor, char *str, unsigned int x1, + unsigned int y1, unsigned int width, unsigned int height) { - int debug = 0; - XftDraw *xftdraw; - XGlyphInfo ext; + int debug = 0; + XftDraw *xftdraw; + XGlyphInfo ext; #define M 2014 - char line[M]; - size_t line_clen, line_ulen; // current line (substring) to draw - size_t line_from_sym, line_to_sym; - char *line_from_char, *line_to_char; // and its "window" in str - float approx_px_per_sym; - int line_new_ulen; - unsigned int x, y; // current upper left corner at which XftDrawStringUtf8 will draw - float line_interval = 0.3; - int line_spacing_px; - bool finish_after_draw = false; - - if ((*str) == '\0') - return 1; - - xftdraw = - XftDrawCreate(dpy, d, DefaultVisual(dpy, 0), - DefaultColormap(dpy, scr)); + char line[M]; + size_t line_clen, line_ulen; // current line (substring) to draw + size_t line_from_sym, line_to_sym; + char *line_from_char, *line_to_char; // and its "window" in str + float approx_px_per_sym; + int line_new_ulen; + unsigned int x, y; // current upper left corner at which XftDrawStringUtf8 will draw + float line_interval = 0.3; + int line_spacing_px; + bool finish_after_draw = false; + + if ((*str) == '\0') + return 1; + + xftdraw = + XftDrawCreate(dpy, d, DefaultVisual(dpy, 0), DefaultColormap(dpy, scr)); //XftColorAllocValue (dpy,DefaultVisual(dpy,scr),DefaultColormap(dpy,scr),xrcolor,&xftcolor); // once: calculate approx_px_per_sym and line_spacing_px - XftTextExtentsUtf8(dpy, font, (unsigned char *)str, strlen(str), &ext); - approx_px_per_sym = (float)ext.width / (float)utf8len(str); - line_spacing_px = (float)ext.height * line_interval; + XftTextExtentsUtf8(dpy, font, (unsigned char *)str, strlen(str), &ext); + approx_px_per_sym = (float)ext.width / (float)utf8len(str); + line_spacing_px = (float)ext.height * line_interval; // cycle by lines - line_to_sym = 0; - x = x1; - y = y1; - do { - // have line_to_sym from previous line - // initialize new line with the rest of str; estimate px_per_sym - /* ACTIVE CHANGE: */ line_from_sym = line_to_sym; - line_from_char = utf8index(str, line_from_sym); - strncpy(line, line_from_char, M); - line[M - 1] = '\0'; - line_clen = strlen(line); - line_ulen = utf8len(line); - if (debug > 0) { - fprintf(stderr, "NEW LINE: \"%s\" ulen=%zu clen=%zu\n", - line, line_ulen, line_clen); - } - // first approximation for line size - line_new_ulen = (float)width / approx_px_per_sym; - if (line_new_ulen >= line_ulen) { // just draw the end of str and finish - XftTextExtentsUtf8(dpy, font, (unsigned char *)line, - line_clen, &ext); - finish_after_draw = true; - goto Draw; - } - /* ACTIVE CHANGE: */ - line_ulen = line_new_ulen; - line_to_sym = line_from_sym + line_ulen; // try to cut here - line_to_char = utf8index(str, line_to_sym); - line[line_to_char - line_from_char] = '\0'; - line_clen = strlen(line); - XftTextExtentsUtf8(dpy, font, (unsigned char *)line, line_clen, - &ext); - if (debug > 0) { - fprintf(stderr, - "first cut approximation: \"%s\" ulen=%zu clen=%zu width=%d px, x2-x1=%d px\n", - line, line_ulen, line_clen, ext.width, width); - } - while (ext.width > width) { - // decrease line by 1 utf symbol - /* ACTIVE CHANGE: */ line_ulen--; - line_to_sym--; - line_to_char = utf8index(str, line_to_sym); - line[line_to_char - line_from_char] = '\0'; - line_clen = strlen(line); - XftTextExtentsUtf8(dpy, font, (unsigned char *)line, - line_clen, &ext); - if (debug > 0) { - fprintf(stderr, - "cut correction: \"%s\" ulen=%zu clen=%zu width=%d px, x2-x1=%d px\n", - line, line_ulen, line_clen, ext.width, - width); - } - } + line_to_sym = 0; + x = x1; + y = y1; + do { + // have line_to_sym from previous line + // initialize new line with the rest of str; estimate px_per_sym + /* ACTIVE CHANGE: */ line_from_sym = line_to_sym; + line_from_char = utf8index(str, line_from_sym); + strncpy(line, line_from_char, M); + line[M - 1] = '\0'; + line_clen = strlen(line); + line_ulen = utf8len(line); + if (debug > 0) { + fprintf(stderr, "NEW LINE: \"%s\" ulen=%zu clen=%zu\n", + line, line_ulen, line_clen); + } + // first approximation for line size + line_new_ulen = (float)width / approx_px_per_sym; + if (line_new_ulen >= line_ulen) { // just draw the end of str and finish + XftTextExtentsUtf8(dpy, font, (unsigned char *)line, + line_clen, &ext); + finish_after_draw = true; + goto Draw; + } + /* ACTIVE CHANGE: */ + line_ulen = line_new_ulen; + line_to_sym = line_from_sym + line_ulen; // try to cut here + line_to_char = utf8index(str, line_to_sym); + line[line_to_char - line_from_char] = '\0'; + line_clen = strlen(line); + XftTextExtentsUtf8(dpy, font, (unsigned char *)line, line_clen, &ext); + if (debug > 0) { + fprintf(stderr, + "first cut approximation: \"%s\" ulen=%zu clen=%zu width=%d px, x2-x1=%d px\n", + line, line_ulen, line_clen, ext.width, width); + } + while (ext.width > width) { + // decrease line by 1 utf symbol + /* ACTIVE CHANGE: */ line_ulen--; + line_to_sym--; + line_to_char = utf8index(str, line_to_sym); + line[line_to_char - line_from_char] = '\0'; + line_clen = strlen(line); + XftTextExtentsUtf8(dpy, font, (unsigned char *)line, + line_clen, &ext); + if (debug > 0) { + fprintf(stderr, + "cut correction: \"%s\" ulen=%zu clen=%zu width=%d px, x2-x1=%d px\n", + line, line_ulen, line_clen, ext.width, width); + } + } Draw: - if ((y + ext.height) > (y1 + height)) { - if (debug > 0) { - fprintf(stderr, - "y+ext.height=%d, y2=%d - breaking\n", - y + ext.height, (y1 + height)); - } - break; - } - x += (width - ext.width) / 2; // center - XftDrawStringUtf8(xftdraw, xftcolor, font, x + ext.x, y + ext.y, - (unsigned char *)line, line_clen); - if (debug > 0) { - GC gc = DefaultGC(dpy, scr); - XSetForeground(dpy, gc, WhitePixel(dpy, scr)); - XDrawRectangle(dpy, d, gc, x, y, ext.width, ext.height); - } - x = x1; - y += ext.height + line_spacing_px; - } while (!finish_after_draw); + if ((y + ext.height) > (y1 + height)) { + if (debug > 0) { + fprintf(stderr, + "y+ext.height=%d, y2=%d - breaking\n", + y + ext.height, (y1 + height)); + } + break; + } + x += (width - ext.width) / 2; // center + XftDrawStringUtf8(xftdraw, xftcolor, font, x + ext.x, y + ext.y, + (unsigned char *)line, line_clen); + if (debug > 0) { + GC gc = DefaultGC(dpy, scr); + XSetForeground(dpy, gc, WhitePixel(dpy, scr)); + XDrawRectangle(dpy, d, gc, x, y, ext.width, ext.height); + } + x = x1; + y += ext.height + line_spacing_px; + } while (!finish_after_draw); - XftDrawDestroy(xftdraw); - return 1; + XftDrawDestroy(xftdraw); + return 1; } // @@ -510,39 +508,37 @@ scr = DefaultScreen(dpy); root = RootWindow(dpy, scr); - Window win = - XCreateSimpleWindow(dpy, root, 0, 0, 1000, 600, 0, - 0, 0); - XMapWindow(dpy, win); - - XftColor xftcolor; - XftColorAllocName(dpy, DefaultVisual(dpy, 0), DefaultColormap(dpy, 0), - "blue", &xftcolor); + Window win = XCreateSimpleWindow(dpy, root, 0, 0, 1000, 600, 0, + 0, 0); + XMapWindow(dpy, win); + + XftColor xftcolor; + XftColorAllocName(dpy, DefaultVisual(dpy, 0), DefaultColormap(dpy, 0), + "blue", &xftcolor); - XftFont *font = NULL; - font = XftFontOpenName(dpy, 0, "DejaVu Sans Condensed-50"); + XftFont *font = NULL; + font = XftFontOpenName(dpy, 0, "DejaVu Sans Condensed-50"); //font = XftFontOpenName(dpy,0,"Arial-24"); - if (!font) - return 0; + if (!font) + return 0; - char line[104]; - line[0] = '\0'; - char *add = "example of drawMultiLine "; - int sc; - for (sc = 0; sc < 4; sc++) - strncat(line, add, 25); - - GC gc = DefaultGC(dpy, 0); - XSetForeground(dpy, gc, WhitePixel(dpy, 0)); - XDrawRectangle(dpy, win, gc, 100, 100, 500, 400); - int r = - drawMultiLine(win, font, &xftcolor, line, 100, 100, 500, 400); + char line[104]; + line[0] = '\0'; + char *add = "example of drawMultiLine "; + int sc; + for (sc = 0; sc < 4; sc++) + strncat(line, add, 26); + + GC gc = DefaultGC(dpy, 0); + XSetForeground(dpy, gc, WhitePixel(dpy, 0)); + XDrawRectangle(dpy, win, gc, 100, 100, 500, 400); + int r = drawMultiLine(win, font, &xftcolor, line, 100, 100, 500, 400); - XFlush(dpy); - sleep(2); + XFlush(dpy); + sleep(2); - XftFontClose(dpy, font); - return r; + XftFontClose(dpy, font); + return r; } // @@ -550,68 +546,86 @@ // Bool predproc_true(Display * display, XEvent * event, char *arg) { - return (True); + return (True); } // // obtain X Window property +// prop_size is returned in bytes // char *get_x_property(Window win, Atom prop_type, char *prop_name, - unsigned long *prop_size) + unsigned long *prop_size) { - int prop_ret_fmt; - unsigned long n_prop_ret_items, ret_bytes_after, size; - unsigned char *ret_prop; - char *r; - Atom prop_name_x, prop_ret_type_x; - - int debug = 0; + int prop_ret_fmt; + unsigned long n_prop_ret_items, ret_bytes_after, size; + unsigned char *ret_prop; + char *r; + Atom prop_name_x, prop_ret_type_x; + int max_prop_len; + + int debug = 0; + + prop_name_x = XInternAtom(dpy, prop_name, False); + max_prop_len = strstr(prop_name, "ICON") == NULL ? MAXPROPLEN : MAXPROPBIG; + + ee_complain = false; + Status propstatus = + XGetWindowProperty(dpy, win, prop_name_x, 0, max_prop_len / 4, False, + prop_type, &prop_ret_type_x, &prop_ret_fmt, + &n_prop_ret_items, &ret_bytes_after, &ret_prop); + XSync(dpy, False); // for error to "appear" + ee_complain = true; + + if (propstatus != Success && debug > 0) { + fprintf(stderr, + "get_x_property: XGetWindowProperty failed (win %ld, prop %s)\n", + win, prop_name); + return (char *)NULL; + } - prop_name_x = XInternAtom(dpy, prop_name, False); + if (prop_type != prop_ret_type_x) { + // this diagnostic may cause BadAtom + if (debug > 1) + fprintf(stderr, + "get_x_property: prop type doesn't match (win %ld, prop %s, requested: %s, obtained: %s)\n", + win, prop_name, + (prop_type == 0) ? "0" : XGetAtomName(dpy, + prop_type), + (prop_ret_type_x == 0) ? "0" : XGetAtomName(dpy, + prop_ret_type_x)); + XFree(ret_prop); + return (char *)NULL; + } - ee_complain = false; - Status propstatus = - XGetWindowProperty(dpy, win, prop_name_x, 0, MAXPROPLEN / 4, False, - prop_type, &prop_ret_type_x, &prop_ret_fmt, - &n_prop_ret_items, &ret_bytes_after, &ret_prop); - XSync(dpy, False); // for error to "appear" - ee_complain = true; + size = (prop_ret_fmt / 8) * n_prop_ret_items; + if (prop_ret_fmt == 32) { + size *= sizeof(long) / 4; + } + r = malloc(size + 1); + memcpy(r, ret_prop, size); + r[size] = '\0'; + if (prop_size) { + *prop_size = size; + } - if (propstatus != Success && debug > 0) { - fprintf(stderr, - "get_x_property: XGetWindowProperty failed (win %ld, prop %s)\n", - win, prop_name); - return (char *)NULL; - } + XFree(ret_prop); + return r; +} - if (prop_type != prop_ret_type_x) { - // this diagnostic may cause BadAtom - if (debug > 1) - fprintf(stderr, - "get_x_property: prop type doesn't match (win %ld, prop %s, requested: %s, obtained: %s)\n", - win, prop_name, - (prop_type == 0) ? "0" : XGetAtomName(dpy, - prop_type), - (prop_ret_type_x == 0) ? "0" : XGetAtomName(dpy, - prop_ret_type_x)); - XFree(ret_prop); - return (char *)NULL; - } +char *get_x_property_alt(Window win, + Atom prop_type1, char *prop_name1, + Atom prop_type2, char *prop_name2, + unsigned long *prop_size) +{ + char *p; - size = (prop_ret_fmt / 8) * n_prop_ret_items; - if (prop_ret_fmt == 32) { - size *= sizeof(long) / 4; - } - r = malloc(size + 1); - memcpy(r, ret_prop, size); - r[size] = '\0'; - if (prop_size) { - *prop_size = size; - } + p = get_x_property(win, prop_type1, prop_name1, prop_size); + if (p != NULL) + return p; - XFree(ret_prop); - return r; + p = get_x_property(win, prop_type2, prop_name2, prop_size); + return p; } // @@ -619,24 +633,21 @@ // bool rectangles_cross(quad a, quad b) { - return !( - a.x >= (b.x + b.w) || - (a.x + a.w) <= b.x || - a.y >= (b.y + b.h) || - (a.y + a.h) <= b.y ); + return !(a.x >= (b.x + b.w) || + (a.x + a.w) <= b.x || a.y >= (b.y + b.h) || (a.y + a.h) <= b.y); } // // coordinates relative to root // -bool get_absolute_coordinates(Window w, quad *q) +bool get_absolute_coordinates(Window w, quad * q) { Window child; XWindowAttributes wa; int x, y; - if (XTranslateCoordinates (dpy, w, root, 0, 0, &x, &y, &child) == False) + if (XTranslateCoordinates(dpy, w, root, 0, 0, &x, &y, &child) == False) return false; - if (XGetWindowAttributes (dpy, w, &wa) == 0) + if (XGetWindowAttributes(dpy, w, &wa) == 0) return false; q->x = x; q->y = y; @@ -651,8 +662,8 @@ void remove_arg(int *argc, char **argv, int argn) { int i; - for(i = argn; i < (*argc); ++i) - argv[i] = argv[i+1]; + for (i = argn; i < (*argc); ++i) + argv[i] = argv[i + 1]; --(*argc); } @@ -660,17 +671,15 @@ // return resource/option `appname.name' // or NULL if not specified // -char* xresource_load_string(XrmDatabase *db, const char *appname, char *name) +char *xresource_load_string(XrmDatabase * db, const char *appname, char *name) { char xappname[MAXNAMESZ]; XrmValue v; char *type; - snprintf (xappname, MAXNAMESZ, "%s.%s", appname, name); - XrmGetResource (*db, xappname, xappname, &type, &v); - return - (v.addr != NULL && !strncmp ("String", type, 6)) ? - v.addr : NULL; + snprintf(xappname, MAXNAMESZ, "%s.%s", appname, name); + XrmGetResource(*db, xappname, xappname, &type, &v); + return (v.addr != NULL && !strncmp("String", type, 6)) ? v.addr : NULL; } // @@ -680,7 +689,8 @@ // 0: not specified // -1: conversion error // -int xresource_load_int(XrmDatabase *db, const char *appname, char *name, unsigned int *ret) +int xresource_load_int(XrmDatabase * db, const char *appname, char *name, + unsigned int *ret) { unsigned int r; char *endptr; @@ -705,20 +715,22 @@ // 0: not specified // -1: bad value, errmsg is set (caller must free) // -int ksym_option_to_keycode(XrmDatabase *db, const char *appname, const char *name, char **errmsg) +int ksym_option_to_keycode(XrmDatabase * db, const char *appname, + const char *name, char **errmsg) { - char *endptr, *opt; + char *endptr, *opt; KeySym ksym; char xresr[MAXNAMESZ]; KeyCode retcode = 0; endptr = opt = NULL; - snprintf (xresr, MAXNAMESZ, "%s.keysym", name); xresr[MAXNAMESZ-1]='\0'; + snprintf(xresr, MAXNAMESZ, "%s.keysym", name); + xresr[MAXNAMESZ - 1] = '\0'; opt = xresource_load_string(db, appname, xresr); - if (opt) { + if (opt) { ksym = XStringToKeysym(opt); if (ksym == NoSymbol) { - ksym = strtol(opt, &endptr, 0); + ksym = strtol(opt, &endptr, 0); if (!(*opt != '\0' && *endptr == '\0')) ksym = NoSymbol; } @@ -727,8 +739,8 @@ if (retcode == 0) { *errmsg = malloc(ERRLEN); snprintf(*errmsg, ERRLEN, - "the specified %s keysym is not defined for any keycode", - name); + "the specified %s keysym is not defined for any keycode", + name); return -1; } return retcode; @@ -746,21 +758,80 @@ // return first modifier corresponding to given keycode, // in the form of modmask, // or zero if not found -// +// unsigned int keycode_to_modmask(KeyCode kc) { int mi, ksi; KeyCode tkc; XModifierKeymap *xmk = XGetModifierMapping(dpy); + unsigned int ret = 0; for (mi = 0; mi < 8; mi++) { for (ksi = 0; ksi < xmk->max_keypermod; ksi++) { tkc = (xmk->modifiermap)[xmk->max_keypermod * mi + ksi]; if (tkc == kc) { - return (1 << mi); + ret = (1 << mi); + goto out; } } } - return 0; + +out: + XFreeModifiermap(xmk); + return ret; +} + +// +// initCompositeConst helper +// +int convert_msb(uint32_t in) +{ + int out; + for (out = 31; out >= 0; --out) { + if (in & 0x80000000L) + break; + in <<= 1; + } + return out; +} + +// +// prepare composition transformations +// +CompositeConst initCompositeConst(unsigned long bg) +{ + CompositeConst cc; + Visual *visual = DefaultVisual(dpy, scr); + cc.RMask = visual->red_mask; + cc.GMask = visual->green_mask; + cc.BMask = visual->blue_mask; + cc.RShift = convert_msb(cc.RMask) - 7; + cc.GShift = convert_msb(cc.GMask) - 7; + cc.BShift = convert_msb(cc.BMask) - 7; + cc.bg = bg; + cc.bg_r = (bg >> cc.RShift) & 0xff; + cc.bg_g = (bg >> cc.GShift) & 0xff; + cc.bg_b = (bg >> cc.BShift) & 0xff; + return cc; +} + +// +// compose "fg" pixel with background (from "cc") using alpha "a" +// +uint32_t pixelComposite(uint32_t fg, uint8_t a, CompositeConst *cc) +{ + uint32_t ret; + uint8_t r, g, b; + if (a == 0) { + ret = cc->bg; + } else if (a == 255) { + ret = fg; + } else { + alpha_composite(r, (fg >> 16) & 0xff, a, cc->bg_r); + alpha_composite(g, (fg >> 8) & 0xff, a, cc->bg_g); + alpha_composite(b, fg & 0xff, a, cc->bg_b); + ret = (r << cc->RShift) | (g << cc->GShift) | (b << cc->BShift); + } + return ret; } diff -Nru alttab-1.3.0/src/util.h alttab-1.5.0/src/util.h --- alttab-1.3.0/src/util.h 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/src/util.h 2020-07-23 08:24:20.000000000 +0000 @@ -1,7 +1,7 @@ /* util.c definitions. -Copyright 2017-2018 Alexander Kulak. +Copyright 2017-2020 Alexander Kulak. This file is part of alttab program. alttab is free software: you can redistribute it and/or modify @@ -30,60 +30,91 @@ #include #include #include +#include #define MAXPROPLEN 4096 +#define MAXPROPBIG 128000 * sizeof(long) // for icon array, for example #define ERRLEN 2048 #ifndef COMTYPES #define COMTYPES typedef struct { - int w; int h; - int x; int y; + int w; + int h; + int x; + int y; } quad; #define MAXNAMESZ 256 #endif -XErrorEvent *ee_ignored; -bool ee_complain; +extern XErrorEvent *ee_ignored; +extern bool ee_complain; + +// values for pixel composite transformations +// which are constant per entire image +typedef struct { + int RShift, GShift, BShift; + uint32_t RMask, GMask, BMask; + unsigned long bg; + uint8_t bg_r, bg_g, bg_b; +} CompositeConst; + +#define alpha_composite(composite, fg, alpha, bg) { \ + uint16_t shiftarg = ((uint16_t)(fg) * (uint16_t)(alpha) + \ + (uint16_t)(bg) * (uint16_t)(255 - (uint16_t)(alpha)) + (uint16_t)128); \ + (composite) = (uint8_t)((shiftarg + (shiftarg >> 8)) >> 8); \ +} + unsigned int getOffendingModifiersMask(); int changeKeygrab(Window win, bool grab, KeyCode keycode, - unsigned int modmask, unsigned int ignored_modmask); + unsigned int modmask, unsigned int ignored_modmask); int zeroErrorHandler(Display * dpy_our, XErrorEvent * theEvent); //void setSelectInput(Window win, int reg); int execAndReadStdout(char *exe, char *args[], char *buf, int bufsize); -int pixmapFitGeneric(Drawable src, Pixmap src_mask, Drawable dst, unsigned int srcW, - unsigned int srcH, unsigned int dstWscaled, - unsigned int dstHscaled, unsigned int dstWoffset, - unsigned int dstHoffset); -int pixmapFitXrender(Drawable src, Pixmap src_mask, Drawable dst, unsigned int srcW, - unsigned int srcH, unsigned int dstWscaled, - unsigned int dstHscaled, unsigned int dstWoffset, - unsigned int dstHoffset); +int pixmapFitGeneric(Drawable src, Pixmap src_mask, Drawable dst, + unsigned int srcW, unsigned int srcH, + unsigned int dstWscaled, unsigned int dstHscaled, + unsigned int dstWoffset, unsigned int dstHoffset); +int pixmapFitXrender(Drawable src, Pixmap src_mask, Drawable dst, + unsigned int srcW, unsigned int srcH, + unsigned int dstWscaled, unsigned int dstHscaled, + unsigned int dstWoffset, unsigned int dstHoffset); int pixmapFit(Drawable src, Pixmap src_mask, Drawable dst, unsigned int srcW, - unsigned int srcH, unsigned int dstW, unsigned int dstH); + unsigned int srcH, unsigned int dstW, unsigned int dstH); size_t utf8len(char *s); char *utf8index(char *s, size_t pos); -int drawMultiLine(Drawable d, XftFont * font, XftColor * xftcolor, char *str, unsigned int x1, - unsigned int y1, unsigned int width, unsigned int height); +int drawMultiLine(Drawable d, XftFont * font, XftColor * xftcolor, char *str, + unsigned int x1, unsigned int y1, unsigned int width, + unsigned int height); int drawMultiLine_test(); Bool predproc_true(Display * display, XEvent * event, char *arg); char *get_x_property(Window win, Atom prop_type, char *prop_name, - unsigned long *prop_size); + unsigned long *prop_size); +char *get_x_property_alt(Window win, + Atom prop_type1, char *prop_name1, + Atom prop_type2, char *prop_name2, + unsigned long *prop_size); bool rectangles_cross(quad a, quad b); -bool get_absolute_coordinates(Window w, quad *q); +bool get_absolute_coordinates(Window w, quad * q); void remove_arg(int *argc, char **argv, int argn); -char* xresource_load_string(XrmDatabase *db, const char *appname, char *name); -int xresource_load_int(XrmDatabase *db, const char *appname, char *name, unsigned int *ret); -int ksym_option_to_keycode(XrmDatabase *db, const char *appname, const char *name, char **errmsg); +char *xresource_load_string(XrmDatabase * db, const char *appname, char *name); +int xresource_load_int(XrmDatabase * db, const char *appname, char *name, + unsigned int *ret); +int ksym_option_to_keycode(XrmDatabase * db, const char *appname, + const char *name, char **errmsg); unsigned int keycode_to_modmask(KeyCode kc); +int convert_msb(uint32_t in); +CompositeConst initCompositeConst(unsigned long bg); +uint32_t pixelComposite(uint32_t fg, uint8_t a, CompositeConst *cc); + #endif diff -Nru alttab-1.3.0/src/win.c alttab-1.5.0/src/win.c --- alttab-1.3.0/src/win.c 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/src/win.c 2020-07-23 08:24:20.000000000 +0000 @@ -1,7 +1,7 @@ /* Interface with foreign windows common for all WMs. -Copyright 2017-2018 Alexander Kulak. +Copyright 2017-2020 Alexander Kulak. This file is part of alttab program. alttab is free software: you can redistribute it and/or modify @@ -45,16 +45,16 @@ static int sort_by_order(const void *p1, const void *p2) { PermanentWindowInfo *s; - WindowInfo *w1 = (WindowInfo*) p1; - WindowInfo *w2 = (WindowInfo*) p2; + WindowInfo *w1 = (WindowInfo *) p1; + WindowInfo *w2 = (WindowInfo *) p2; int r = 0; DL_FOREACH(g.sortlist, s) { - if (s->id == w1->id ) { + if (s->id == w1->id) { r = (s->id == w2->id) ? 0 : -1; break; } - if (s->id == w2->id ) { + if (s->id == w2->id) { r = 1; break; } @@ -66,11 +66,11 @@ // // debug output of sortlist // -void print_sortlist() +static void print_sortlist() { PermanentWindowInfo *s; msg(0, "sortlist:\n"); - DL_FOREACH (g.sortlist, s) { + DL_FOREACH(g.sortlist, s) { msg(0, " 0x%lx\n", s->id); } } @@ -78,23 +78,24 @@ // // debug output of winlist // -void print_winlist() +static void print_winlist() { int wi, si; PermanentWindowInfo *s; - if (g.winlist == NULL && g.maxNdx == 0) return; // safety + if (g.winlist == NULL && g.maxNdx == 0) + return; // safety msg(0, "winlist:\n"); for (wi = 0; wi < g.maxNdx; wi++) { si = 0; - DL_FOREACH (g.sortlist, s) { - if (s == NULL) continue; // safety - if (s->id == g.winlist[wi].id ) + DL_FOREACH(g.sortlist, s) { + if (s == NULL) + continue; // safety + if (s->id == g.winlist[wi].id) break; si++; } - msg(0, " %4d: 0x%lx %s\n", si, - g.winlist[wi].id, g.winlist[wi].name); + msg(0, " %4d: 0x%lx %s\n", si, g.winlist[wi].id, g.winlist[wi].name); } } @@ -110,24 +111,25 @@ bool was = false; bool add = false; - DL_SEARCH_SCALAR (g.sortlist, s, id, w); + DL_SEARCH_SCALAR(g.sortlist, s, id, w); if (s == NULL) { - s = malloc (sizeof (PermanentWindowInfo)); - if (s == NULL) return; + s = malloc(sizeof(PermanentWindowInfo)); + if (s == NULL) + return; s->id = w; add = true; } else { was = true; if (move) { - DL_DELETE (g.sortlist, s); + DL_DELETE(g.sortlist, s); add = true; } } if (add) { if (to_head) { - DL_PREPEND (g.sortlist, s); + DL_PREPEND(g.sortlist, s); } else { - DL_APPEND (g.sortlist, s); + DL_APPEND(g.sortlist, s); } } if (add && !was) { @@ -145,13 +147,11 @@ { long rootevmask = 0; - g.sortlist = NULL; // utlist head must be initialized to NULL - g.ic = NULL; // uthash too - if (g.option_iconSrc != ISRC_RAM) { - g.ic = initIcon(); - initIconHash(&(g.ic)); - } - + g.sortlist = NULL; // utlist head must be initialized to NULL + g.ic = NULL; // uthash too + if (g.option_iconSrc != ISRC_RAM) { + initIconHash(&(g.ic)); + } // root: watching for _NET_ACTIVE_WINDOW if (g.option_wm == WM_EWMH) { g.naw = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", true); @@ -164,18 +164,107 @@ XSelectInput(dpy, root, rootevmask); } - switch (g.option_wm) { - case WM_NO: - return 1; - case WM_RATPOISON: - return rp_startupWintasks(); - case WM_EWMH: - return 1; + switch (g.option_wm) { + case WM_NO: + return 1; + case WM_RATPOISON: + return rp_startupWintasks(); + case WM_EWMH: + return 1; case WM_TWM: return 1; - default: - return 0; - } + default: + return 0; + } +} + +// +// search for suitable icon in NET_WM_ICON window property +// https://specifications.freedesktop.org/wm-spec/latest/ar01s05.html#_NET_WM_ICON +// if found, then +// fill in "wi->icon_pixmap" and "wi->icon_mask" +// and return 1, +// 0 otherwise. +// +#define best_w pro[best-2] +#define best_h pro[best-1] +// +int addIconFromProperty(WindowInfo * wi) +{ + long *pro; + long unsigned n, nelem, best; + unsigned int w, h; + const char *NWI = "_NET_WM_ICON"; + uint32_t *image32; + uint32_t fg; + uint8_t alpha; + int x, y; + int bitmap_pad; + int bytes_per_line; + XImage *img; + GC gc; + + if ((pro = (long *) get_x_property(wi->id, XA_CARDINAL, + (char*)NWI, &nelem)) == NULL) { + msg(1, "Can't find %s (%lx, %s)\n", NWI, wi->id, wi->name); + return 0; + } + nelem = nelem / sizeof(long); + msg (1, "Found %lu elements in %s (%lx, %s)\n", nelem, NWI, wi->id, wi->name); + best = 0; + n = 0; + while (n + 2 < nelem) { + w = pro[n++]; + h = pro[n++]; + if (n + w*h > nelem || w == 0 || h == 0) { + msg(1, "Skipping invalid %s icon: element=%lu/%lu w*h=%lux%lu\n", NWI, n, nelem, w, h); + n += w*h; + continue; + } + if (best == 0 || iconMatchBetter(w, h, best_w, best_h)) { + best = n; + } + n += w*h; + } + if (best == 0) { + msg(0, "%s found but no suitable icons in it\n", NWI); + //free(prop); better don't + return 0; + } + msg(1, "using %dx%d %s icon for %lx\n", w, h, NWI, wi->id); + + image32 = malloc(best_w * best_h * 4); + CompositeConst cc = initCompositeConst(g.color[COLBG].xcolor.pixel); + for (y = 0; y < best_h; y++) { + for (x = 0; x < best_w; x++) { + int ndx = y*best_w + x; + // pro is ARGB by definition + fg = pro[best + ndx] & 0x00ffffff; + alpha = pro[best + ndx] >> 24; + image32[ndx] = pixelComposite(fg, alpha, &cc); + } + } + // result: image32 + + bitmap_pad = (XDEPTH == 15 || XDEPTH == 16) ? 16 : 32; + bytes_per_line = 0; + img = XCreateImage(dpy, CopyFromParent, XDEPTH, ZPixmap, 0, (char*)image32, best_w, best_h, bitmap_pad, bytes_per_line); + if (!img) { + msg(0, "Can't XCreateImage, abort %s search\n", NWI); + free(image32); + free(pro); + return 0; + } + wi->icon_drawable = XCreatePixmap(dpy, root, best_w, best_h, XDEPTH); + gc = DefaultGC(dpy, scr); + XPutImage(dpy, wi->icon_drawable, gc, img, 0, 0, 0, 0, best_w, best_h); + wi->icon_mask = 0; + wi->icon_allocated = true; + wi->icon_w = best_w; + wi->icon_h = best_h; + free(image32); + free(pro); + return 1; } // @@ -187,45 +276,44 @@ // int addIconFromHints(WindowInfo * wi) { - XWMHints *hints; - Pixmap hicon, hmask; + XWMHints *hints; + Pixmap hicon, hmask; - hicon = hmask = 0; - if ((hints = XGetWMHints(dpy, wi->id))) { + hicon = hmask = 0; + if ((hints = XGetWMHints(dpy, wi->id))) { msg(1, - "IconPixmapHint: %ld, icon_pixmap: %lu, IconMaskHint: %ld, icon_mask: %lu, IconWindowHint: %ld, icon_window: %lu\n", - hints->flags & IconPixmapHint, - hints->icon_pixmap, hints->flags & IconMaskHint, - hints->icon_mask, hints->flags & IconWindowHint, - hints->icon_window); - if ((hints->flags & IconWindowHint) & - (!(hints->flags & IconPixmapHint))) { - msg(0, "icon_window without icon_pixmap in hints, ignoring\n"); // not usable in xterm? - } - hicon = - (hints->flags & IconPixmapHint) ? hints->icon_pixmap : 0; + "IconPixmapHint: %ld, icon_pixmap: %lu, IconMaskHint: %ld, icon_mask: %lu, IconWindowHint: %ld, icon_window: %lu\n", + hints->flags & IconPixmapHint, + hints->icon_pixmap, hints->flags & IconMaskHint, + hints->icon_mask, hints->flags & IconWindowHint, + hints->icon_window); + if ((hints->flags & IconWindowHint) & + (!(hints->flags & IconPixmapHint))) { + msg(0, "icon_window without icon_pixmap in hints, ignoring\n"); // not usable in xterm? + } + hicon = (hints->flags & IconPixmapHint) ? hints->icon_pixmap : 0; // ((hints->flags & IconPixmapHint) ? hints->icon_pixmap : ( // (hints->flags & IconWindowHint) ? hints->icon_window : 0)); - hmask = (hints->flags & IconMaskHint) ? hints->icon_mask : 0; - XFree(hints); - if (hicon) - msg(0, "no icon in WM hints (%s)\n", wi->name); - } else { + hmask = (hints->flags & IconMaskHint) ? hints->icon_mask : 0; + XFree(hints); + if (hicon) + msg(0, "no icon in WM hints (%s)\n", wi->name); + } else { msg(0, "no WM hints (%s)\n", wi->name); - } - if (hmask != 0) - wi->icon_mask = hmask; - if (hicon != 0) { - wi->icon_drawable = hicon; - return 1; - } - return 0; + } + if (hmask != 0) + wi->icon_mask = hmask; + if (hicon != 0) { + wi->icon_drawable = hicon; + return 1; + } + return 0; } // // search for "wi" application class in PNG hash. // if found, then -// if program options don't request size comparison +// if program options don't request size comparison // OR png size match better, then // fill in "wi->icon_pixmap" and "wi->icon_mask" // and return 1 @@ -234,42 +322,51 @@ // int addIconFromFiles(WindowInfo * wi) { - char *appclass, *tryclass; - long unsigned int class_size; - icon_t *ic; - - appclass = get_x_property(wi->id, XA_STRING, "WM_CLASS", &class_size); - if (appclass) { - for (tryclass = appclass; tryclass - appclass < class_size; - tryclass += (strlen(tryclass) + 1)) { - ic = lookupIcon(tryclass); - if (ic && - (g.option_iconSrc != ISRC_SIZE - || iconMatchBetter(ic->src_w, ic->src_h, - wi->icon_w, wi->icon_h)) - ) { - msg(0, - "using png icon for %s\n", - tryclass); - if (ic->drawable == None) { - msg(1, - "loading content for %s\n", - ic->app); - if (loadIconContent(ic) == 0) { - msg(-1, "can't load png icon content\n"); - continue; - } - } - wi->icon_drawable = ic->drawable; - wi->icon_mask = 0; - return 1; - } - } - } else { - msg(0, "can't find WM_CLASS for \"%s\"\n", - wi->name); - } - return 0; + char *appclass, *tryclass; + long unsigned int class_size; + icon_t *ic; + int ret = 0; + + appclass = get_x_property(wi->id, XA_STRING, "WM_CLASS", &class_size); + if (appclass) { + for (tryclass = appclass; tryclass - appclass < class_size; + tryclass += (strlen(tryclass) + 1)) { + ic = lookupIcon(tryclass); + if (ic && + (g.option_iconSrc != ISRC_SIZE + || iconMatchBetter(ic->src_w, ic->src_h, + wi->icon_w, wi->icon_h)) + ) { + msg(0, "using file icon for %s\n", tryclass); + if (ic->drawable == None) { + msg(1, "loading content for %s\n", ic->app); + if (loadIconContent(ic) == 0) { + msg(-1, "can't load file icon content: %s\n", ic->src_path); + continue; + } + } + // for the case when icon was already found in window props + if (wi->icon_allocated) { + XFreePixmap(dpy, wi->icon_drawable); + /* + if (wi->icon_mask != None) { + XFreePixmap(dpy, wi->icon_mask); + } + */ + wi->icon_allocated = false; + } + wi->icon_drawable = ic->drawable; + wi->icon_mask = ic->mask; + ret = 1; + goto out; + } + } + } else { + msg(0, "can't find WM_CLASS for \"%s\"\n", wi->name); + } +out: + free(appclass); + return ret; } // @@ -277,35 +374,33 @@ // used by x, rp, ... // only dpy and win are mandatory // -int addWindowInfo(Window win, int reclevel, int wm_id, unsigned long desktop, char *wm_name) +int addWindowInfo(Window win, int reclevel, int wm_id, unsigned long desktop, + char *wm_name) { - if (! - (g.winlist = - realloc(g.winlist, (g.maxNdx + 1) * sizeof(WindowInfo)))) - return 0; - g.winlist[g.maxNdx].id = win; - g.winlist[g.maxNdx].wm_id = wm_id; + if (!(g.winlist = realloc(g.winlist, (g.maxNdx + 1) * sizeof(WindowInfo)))) + return 0; + g.winlist[g.maxNdx].id = win; + g.winlist[g.maxNdx].wm_id = wm_id; // 1. get name - if (wm_name) { - strncpy(g.winlist[g.maxNdx].name, wm_name, MAXNAMESZ); - } else { - unsigned char *wn; - Atom prop = XInternAtom(dpy, "WM_NAME", false), type; - int form; - unsigned long remain, len; - if (XGetWindowProperty(dpy, win, prop, 0, MAXNAMESZ, false, - AnyPropertyType, &type, &form, &len, - &remain, &wn) == Success && wn) { - strncpy(g.winlist[g.maxNdx].name, (char *)wn, - MAXNAMESZ); - g.winlist[g.maxNdx].name[MAXNAMESZ - 1] = '\0'; - XFree(wn); - } else { - g.winlist[g.maxNdx].name[0] = '\0'; - } - } // guessing name without WM hints + if (wm_name) { + strncpy(g.winlist[g.maxNdx].name, wm_name, MAXNAMESZ-1); + } else { + unsigned char *wn; + Atom prop = XInternAtom(dpy, "WM_NAME", false), type; + int form; + unsigned long remain, len; + if (XGetWindowProperty(dpy, win, prop, 0, MAXNAMESZ, false, + AnyPropertyType, &type, &form, &len, + &remain, &wn) == Success && wn) { + strncpy(g.winlist[g.maxNdx].name, (char *)wn, MAXNAMESZ-1); + g.winlist[g.maxNdx].name[MAXNAMESZ - 1] = '\0'; + XFree(wn); + } else { + g.winlist[g.maxNdx].name[0] = '\0'; + } + } // guessing name without WM hints // 2. icon @@ -316,112 +411,123 @@ // it's more sophisticated than icon_drawable=win, because hidden window contents aren't available. // * understand hints->icon_window (twm concept, xterm). - g.winlist[g.maxNdx].icon_drawable = - g.winlist[g.maxNdx].icon_mask = - g.winlist[g.maxNdx].icon_w = g.winlist[g.maxNdx].icon_h = 0; - unsigned int icon_depth = 0; - g.winlist[g.maxNdx].icon_allocated = false; - - // search for icon in hints or file hash - int icon_in_hints = 0; - int opt = g.option_iconSrc; - if (opt != ISRC_FILES) - icon_in_hints = addIconFromHints(&(g.winlist[g.maxNdx])); - if ((opt == ISRC_FALLBACK && !icon_in_hints) || - opt == ISRC_SIZE || opt == ISRC_FILES) - addIconFromFiles(&(g.winlist[g.maxNdx])); - - // extract icon width/height/depth - Window root_return; - int x_return, y_return; - unsigned int border_width_return; - if (g.winlist[g.maxNdx].icon_drawable) { - if (XGetGeometry(dpy, g.winlist[g.maxNdx].icon_drawable, - &root_return, &x_return, &y_return, - &(g.winlist[g.maxNdx].icon_w), - &(g.winlist[g.maxNdx].icon_h), - &border_width_return, &icon_depth) == 0) { - msg(0, - "icon dimensions unknown (%s)\n", - g.winlist[g.maxNdx].name); - // probably draw placeholder? - g.winlist[g.maxNdx].icon_drawable = 0; - } else { + g.winlist[g.maxNdx].icon_drawable = + g.winlist[g.maxNdx].icon_mask = + g.winlist[g.maxNdx].icon_w = g.winlist[g.maxNdx].icon_h = 0; + unsigned int icon_depth = 0; + g.winlist[g.maxNdx].icon_allocated = false; + + // search for icon in window properties, hints or file hash + int opt = g.option_iconSrc; + int icon_in_x = 0; + if (opt != ISRC_FILES) { + icon_in_x = addIconFromProperty(&(g.winlist[g.maxNdx])); + if (!icon_in_x) + icon_in_x = addIconFromHints(&(g.winlist[g.maxNdx])); + } + if ((opt == ISRC_FALLBACK && !icon_in_x) || + opt == ISRC_SIZE || opt == ISRC_FILES) + addIconFromFiles(&(g.winlist[g.maxNdx])); + + // extract icon width/height/depth + Window root_return; + int x_return, y_return; + unsigned int border_width_return; + if (g.winlist[g.maxNdx].icon_drawable) { + if (XGetGeometry(dpy, g.winlist[g.maxNdx].icon_drawable, + &root_return, &x_return, &y_return, + &(g.winlist[g.maxNdx].icon_w), + &(g.winlist[g.maxNdx].icon_h), + &border_width_return, &icon_depth) == 0) { + msg(0, "icon dimensions unknown (%s)\n", g.winlist[g.maxNdx].name); + // probably draw placeholder? + g.winlist[g.maxNdx].icon_drawable = 0; + } else { msg(1, "depth=%d\n", icon_depth); - } - } + } + } // convert icon with different depth (currently 1 only) into default depth - if (g.winlist[g.maxNdx].icon_drawable && icon_depth == 1) { + if (g.winlist[g.maxNdx].icon_drawable && icon_depth == 1) { msg(0, - "rebuilding icon from depth 1 to %d (%s)\n", - XDEPTH, g.winlist[g.maxNdx].name); - Pixmap pswap = - XCreatePixmap(dpy, g.winlist[g.maxNdx].icon_drawable, - g.winlist[g.maxNdx].icon_w, - g.winlist[g.maxNdx].icon_h, XDEPTH); - if (!pswap) - die("can't create pixmap"); - // GC should be already prepared in uiShow - if (!XCopyPlane - (dpy, g.winlist[g.maxNdx].icon_drawable, pswap, g.gcDirect, - 0, 0, g.winlist[g.maxNdx].icon_w, - g.winlist[g.maxNdx].icon_h, 0, 0, 1)) - die("can't copy plane"); // plane #1? - g.winlist[g.maxNdx].icon_drawable = pswap; - g.winlist[g.maxNdx].icon_allocated = true; // for subsequent free() - icon_depth = XDEPTH; - } - if (g.winlist[g.maxNdx].icon_drawable && icon_depth != XDEPTH) { - msg(-1, - "can't handle icon depth other than %d or 1 (%d, %s). Please report this condition.\n", - XDEPTH, icon_depth, g.winlist[g.maxNdx].name); - g.winlist[g.maxNdx].icon_drawable = g.winlist[g.maxNdx].icon_w = - g.winlist[g.maxNdx].icon_h = 0; - } + "rebuilding icon from depth %d to %d (%s)\n", + icon_depth, XDEPTH, g.winlist[g.maxNdx].name); + Pixmap pswap = XCreatePixmap(dpy, g.winlist[g.maxNdx].icon_drawable, + g.winlist[g.maxNdx].icon_w, + g.winlist[g.maxNdx].icon_h, XDEPTH); + if (!pswap) + die("can't create pixmap"); + // GC should be already prepared in uiShow + if (!XCopyPlane + (dpy, g.winlist[g.maxNdx].icon_drawable, pswap, g.gcDirect, + 0, 0, g.winlist[g.maxNdx].icon_w, + g.winlist[g.maxNdx].icon_h, 0, 0, 1)) + die("can't copy plane"); // plane #1? + g.winlist[g.maxNdx].icon_drawable = pswap; + g.winlist[g.maxNdx].icon_allocated = true; // for subsequent free() + icon_depth = XDEPTH; + } + if (g.winlist[g.maxNdx].icon_drawable && icon_depth != XDEPTH) { + msg(-1, + "can't handle icon depth other than %d or 1 (%d, %s). Please report this condition.\n", + XDEPTH, icon_depth, g.winlist[g.maxNdx].name); + g.winlist[g.maxNdx].icon_drawable = g.winlist[g.maxNdx].icon_w = + g.winlist[g.maxNdx].icon_h = 0; + } // 3. sort - addToSortlist (win, false, false); + addToSortlist(win, false, false); // 4. other window data - g.winlist[g.maxNdx].reclevel = reclevel; - g.winlist[g.maxNdx].desktop = desktop; + g.winlist[g.maxNdx].reclevel = reclevel; + g.winlist[g.maxNdx].desktop = desktop; - g.maxNdx++; + g.maxNdx++; msg(1, "window %d, id %lx added to list\n", g.maxNdx, win); - return 1; -} // addWindowInfo() + return 1; +} // addWindowInfo() + +static void __initWinlist(void) +{ + free(g.winlist); + g.winlist = NULL; + g.maxNdx = 0; +} + // -// sets g.winlist, g.maxNdx, g.selNdx +// sets g.winlist, g.maxNdx // updates g.sortlist, g.sortNdx // n.b.: in heavy WM, use _NET_CLIENT_LIST // direction is direction of first press: with shift or without // -int initWinlist(bool direction) +int initWinlist(void) { - int r; - if (g.debug > 1) { - msg(1, "before initWinlist\n"); + int r; + if (g.debug > 1) { + msg(1, "before initWinlist\n"); print_sortlist(); - } - switch (g.option_wm) { - case WM_NO: - r = x_initWindowsInfoRecursive(root, 0); // note: direction/current window index aren't used - break; - case WM_RATPOISON: - r = rp_initWinlist(); - break; - case WM_EWMH: - r = ewmh_initWinlist(); - break; + } + switch (g.option_wm) { + case WM_NO: + r = x_initWindowsInfoRecursive(root, 0); // note: direction/current window index aren't used + break; + case WM_RATPOISON: + r = rp_initWinlist(); + break; + case WM_EWMH: + r = ewmh_initWinlist(); + break; case WM_TWM: r = x_initWindowsInfoRecursive(root, 0); break; - default: - r = 0; - break; - } + default: + r = 0; + break; + } + + if (!r) + __initWinlist(); // sort winlist according to .order if (g.debug > 1) { @@ -435,15 +541,9 @@ print_winlist(); } - g.selNdx = direction ? - (g.maxNdx - 1) : - (( 0 >= (g.maxNdx - 1)) ? 0 : 1); -//if (g.selNdx<0 || g.selNdx>=g.maxNdx) { g.selNdx=0; } // just for case - msg(1, - "initWinlist ret: number of items in winlist: %d, current (selected) item in winlist: %d\n", - g.maxNdx, g.selNdx); + msg(1, "initWinlist ret: number of items in winlist: %d\n", g.maxNdx); - return r; + return r; } // @@ -453,16 +553,16 @@ void freeWinlist() { msg(0, "destroying icons and winlist\n"); - if (g.debug > 1) { - msg(1, "before freeWinlist\n"); + if (g.debug > 1) { + msg(1, "before freeWinlist\n"); print_sortlist(); - } - int y; - for (y = 0; y < g.maxNdx; y++) { - if (g.winlist[y].icon_allocated) - XFreePixmap(dpy, g.winlist[y].icon_drawable); - } - free(g.winlist); + } + int y; + for (y = 0; y < g.maxNdx; y++) { + if (g.winlist[y].icon_allocated) + XFreePixmap(dpy, g.winlist[y].icon_drawable); + } + __initWinlist(); } // @@ -470,16 +570,16 @@ // int setFocus(int winNdx) { - int r; - switch (g.option_wm) { - case WM_NO: - r = ewmh_setFocus(winNdx, 0); // for WM which isn't identified as EWMH compatible but accepts setting focus (dwm) - x_setFocus(winNdx); - break; - case WM_RATPOISON: - r = rp_setFocus(winNdx); - break; - case WM_EWMH: + int r; + switch (g.option_wm) { + case WM_NO: + r = ewmh_setFocus(winNdx, 0); // for WM which isn't identified as EWMH compatible but accepts setting focus (dwm) + x_setFocus(winNdx); + break; + case WM_RATPOISON: + r = rp_setFocus(winNdx); + break; + case WM_EWMH: r = ewmh_setFocus(winNdx, 0); // XSetInputFocus stuff. // skippy-xd does it and notes that "order is important". @@ -489,18 +589,19 @@ XWindowAttributes att; XGetWindowAttributes(dpy, g.winlist[winNdx].id, &att); if (att.map_state == IsViewable) - XSetInputFocus(dpy, g.winlist[winNdx].id, RevertToParent, CurrentTime); - break; + XSetInputFocus(dpy, g.winlist[winNdx].id, RevertToParent, + CurrentTime); + break; case WM_TWM: r = ewmh_setFocus(winNdx, 0); x_setFocus(winNdx); break; - default: - return 0; - } + default: + return 0; + } // pull to head - addToSortlist (g.winlist[winNdx].id, true, true); - return r; + addToSortlist(g.winlist[winNdx].id, true, true); + return r; } // @@ -515,21 +616,28 @@ { Window aw; // no _NET_ACTIVE_WINDOW atom, probably not EWMH? - if (g.naw == None) return; + if (g.naw == None) + return; // property change event not for root window? - if (e.window != root) return; + if (e.window != root) + return; // root property other than _NET_ACTIVE_WINDOW changed? - if (e.atom != g.naw) return; + if (e.atom != g.naw) + return; // don't check for wm==EWMH, because _NET_ACTIVE_WINDOW changed for sure aw = ewmh_getActiveWindow(); // can't get active window - if (!aw) return; + if (!aw) + return; // focus changed to our own old/current/zero window? - if (aw == getUiwin()) return; + if (aw == getUiwin()) + return; // focus changed to window which is already top? - if (g.sortlist != NULL && aw == g.sortlist->id) return; + if (g.sortlist != NULL && aw == g.sortlist->id) + return; // is window hidden in WM? - if (ewmh_skipWindowInTaskbar(aw)) return; + if (ewmh_skipWindowInTaskbar(aw)) + return; /* // the i3 sortlist bug is not here, see ewmh.c init_winlist instead // @@ -537,7 +645,7 @@ struct timeval ctv; int usec_delta; gettimeofday(&ctv, NULL); - usec_delta = (ctv.tv_sec - g.last.tv.tv_sec) * 1E6 + usec_delta = (ctv.tv_sec - g.last.tv.tv_sec) * 1E6 + (ctv.tv_usec - g.last.tv.tv_usec); msg(0, "delta %d\n", usec_delta); if (usec_delta < 5E5) { // half a second @@ -554,10 +662,10 @@ // unfortunately, on focus by alttab, this is fired twice: // 1) when alttab window gone, previous window becomes active, // 2) then alttab-focused window becomes active. - msg(0, - "event PropertyChange: 0x%lx active, pull to the head of sortlist\n", - aw); - addToSortlist (aw, true, true); + msg(0, + "event PropertyChange: 0x%lx active, pull to the head of sortlist\n", + aw); + addToSortlist(aw, true, true); } // @@ -569,11 +677,12 @@ { PermanentWindowInfo *s; - DL_SEARCH_SCALAR (g.sortlist, s, id, e.window); + DL_SEARCH_SCALAR(g.sortlist, s, id, e.window); if (s != NULL) { msg(1, - "event DestroyNotify: 0x%lx found in sortlist, removing\n", e.window); - DL_DELETE (g.sortlist, s); + "event DestroyNotify: 0x%lx found in sortlist, removing\n", + e.window); + DL_DELETE(g.sortlist, s); } } @@ -582,44 +691,41 @@ // it checks: desktop, screen // depending on global options and dimensions // -bool common_skipWindow(Window w, - unsigned long current_desktop, unsigned long window_desktop) +bool common_skipWindow(Window w, + unsigned long current_desktop, + unsigned long window_desktop) { - quad wq; // window's absolute coordinates + quad wq; // window's absolute coordinates if (g.option_desktop == DESK_CURRENT - && current_desktop != window_desktop - && current_desktop != DESKTOP_UNKNOWN - && window_desktop != DESKTOP_UNKNOWN) { - msg(1, - "window not on active desktop, skipped (window's %ld, current %ld)\n", - window_desktop, current_desktop); + && current_desktop != window_desktop + && current_desktop != DESKTOP_UNKNOWN + && window_desktop != DESKTOP_UNKNOWN) { + msg(1, + "window not on active desktop, skipped (window's %ld, current %ld)\n", + window_desktop, current_desktop); return true; } - if (g.option_desktop == DESK_NOSPECIAL - && window_desktop == -1) { + if (g.option_desktop == DESK_NOSPECIAL && window_desktop == -1) { msg(1, "window on -1 desktop, skipped\n"); return true; } - if (g.option_desktop == DESK_NOCURRENT && - (window_desktop == current_desktop || - window_desktop == -1)) { + if (g.option_desktop == DESK_NOCURRENT && + (window_desktop == current_desktop || window_desktop == -1)) { msg(1, "window on current or -1 desktop, skipped\n"); return true; } - // man page: -sc 0: Screen is defined according to -vp pointer or -vp focus. // assuming g.vp already calculated in gui.c if (g.option_screen == SCR_CURRENT && - (g.option_vp_mode == VP_POINTER || - g.option_vp_mode == VP_FOCUS)) { - if (! get_absolute_coordinates(w, &wq)) { - msg(-1, - "can't get coordinates of window 0x%lx, included anyway\n", w); + (g.option_vp_mode == VP_POINTER || g.option_vp_mode == VP_FOCUS)) { + if (!get_absolute_coordinates(w, &wq)) { + msg(-1, + "can't get coordinates of window 0x%lx, included anyway\n", w); } else { - if (! rectangles_cross(g.vp, wq)) { - msg(1, - "window's area doesn't cross with current screen, skipped\n"); + if (!rectangles_cross(g.vp, wq)) { + msg(1, + "window's area doesn't cross with current screen, skipped\n"); return true; } } @@ -637,20 +743,29 @@ { Window w; // in non-EWMH only - // probably should also maintain _NET_ACTIVE_WINDOW + // probably should also maintain _NET_ACTIVE_WINDOW // support flag in EwmhFeatures - if (g.option_wm == WM_EWMH) return; + if (g.option_wm == WM_EWMH) + return; // focusIn only - if (e.type != FocusIn) return; + if (e.type != FocusIn) + return; // skip Grab/Ungrab notification modes - if (e.mode != NotifyNormal) return; + if (e.mode != NotifyNormal) + return; // focus changed to our own old/current/zero window? w = e.window; - if (w == getUiwin()) return; + if (w == getUiwin()) + return; // focus changed to window which is already top? - if (g.sortlist != NULL && w == g.sortlist->id) return; + if (g.sortlist != NULL && w == g.sortlist->id) + return; msg(1, "event focusIn 0x%lx, pull to the head of sortlist\n", w); - addToSortlist (w, true, true); + addToSortlist(w, true, true); } +void shutdownWin() +{ + deleteIconHash(&g.ic); +} diff -Nru alttab-1.3.0/src/x.c alttab-1.5.0/src/x.c --- alttab-1.3.0/src/x.c 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/src/x.c 2020-07-23 08:24:20.000000000 +0000 @@ -1,7 +1,7 @@ /* Interface with foreign windows in raw X11. -Copyright 2017-2018 Alexander Kulak. +Copyright 2017-2020 Alexander Kulak. This file is part of alttab program. alttab is free software: you can redistribute it and/or modify @@ -27,7 +27,7 @@ #include "alttab.h" #include "util.h" extern Globals g; -extern Display* dpy; +extern Display *dpy; extern int scr; extern Window root; @@ -39,23 +39,22 @@ // Window x_get_leader(Window win) { - Window *retprop; - XWMHints *h; - Window leader = None; - - retprop = - (Window *) get_x_property(win, XA_WINDOW, "WM_CLIENT_LEADER", - NULL); - if (retprop != NULL) { - leader = retprop[0]; - XFree(retprop); - } else { - if (!(h = XGetWMHints(dpy, win))) - return None; - if (h->flags & WindowGroupHint) - leader = h->window_group; - } - return leader; + Window *retprop; + XWMHints *h; + Window leader = None; + + retprop = + (Window *) get_x_property(win, XA_WINDOW, "WM_CLIENT_LEADER", NULL); + if (retprop != NULL) { + leader = retprop[0]; + XFree(retprop); + } else { + if (!(h = XGetWMHints(dpy, win))) + return None; + if (h->flags & WindowGroupHint) + leader = h->window_group; + } + return leader; } // PUBLIC @@ -67,12 +66,12 @@ int x_initWindowsInfoRecursive(Window win, int reclevel) { - Window root, parent; - Window *children; - unsigned int nchildren, i; + Window root, parent; + Window *children; + unsigned int nchildren, i; // Window leader; - XWindowAttributes wa; - char* winname; + XWindowAttributes wa; + char *winname; // check if window is "leader" or no prop, skip otherwise // caveat: in rp, gvim leader has no file name and icon @@ -90,40 +89,38 @@ // probably add an option for this in WMs too? wa.map_state = 0; if (g.option_wm != WM_TWM) - XGetWindowAttributes(dpy, win, &wa); + XGetWindowAttributes(dpy, win, &wa); // in twm-like, add only windows with a name winname = NULL; if (g.option_wm == WM_TWM) { winname = get_x_property(win, XA_STRING, "WM_NAME", NULL); } - // insert detailed window data in window list - if ( (g.option_wm == WM_TWM || wa.map_state == IsViewable) - && reclevel != 0 - && (g.option_wm != WM_TWM || winname != NULL) + if ((g.option_wm == WM_TWM || wa.map_state == IsViewable) + && reclevel != 0 && (g.option_wm != WM_TWM || winname != NULL) // && (g.option_wm != WM_TWM || leader == win) - && ! common_skipWindow(win, DESKTOP_UNKNOWN, DESKTOP_UNKNOWN) - ) { + && !common_skipWindow(win, DESKTOP_UNKNOWN, DESKTOP_UNKNOWN) + ) { addWindowInfo(win, reclevel, 0, DESKTOP_UNKNOWN, winname); - } + } // skip children if max recursion level reached if (g.option_max_reclevel != -1 && reclevel >= g.option_max_reclevel) return 1; // recursion - if (XQueryTree(dpy, win, &root, &parent, &children, &nchildren) == 0) { + if (XQueryTree(dpy, win, &root, &parent, &children, &nchildren) == 0) { msg(0, "can't get window tree for 0x%lx\n", win); - return 0; - } - for (i = 0; i < nchildren; ++i) { - x_initWindowsInfoRecursive(children[i], reclevel + 1); - } - - if (nchildren > 0 && children) { - XFree(children); - } - return 1; + return 0; + } + for (i = 0; i < nchildren; ++i) { + x_initWindowsInfoRecursive(children[i], reclevel + 1); + } + + if (nchildren > 0 && children) { + XFree(children); + } + return 1; } // @@ -131,25 +128,25 @@ // int x_setFocus(int wndx) { - Window w = g.winlist[wndx].id; + Window w = g.winlist[wndx].id; // 1. XWarpPointer // If such WMs would be discovered that prevent our focus // AND set their own focus via the pointer only. // 2. XRaiseWindow required, but doesn't make window "Viewable" - XRaiseWindow(dpy, w); + XRaiseWindow(dpy, w); // 3. XSetInputFocus -// "The specified focus window must be viewable at the time +// "The specified focus window must be viewable at the time // XSetInputFocus is called, or a BadMatch error results." // This check is redundant: non-viewable windows isn't added to winlist in raw X anyway - XWindowAttributes att; - XGetWindowAttributes(dpy, w, &att); - if (att.map_state == IsViewable) - XSetInputFocus(dpy, w, RevertToParent, CurrentTime); + XWindowAttributes att; + XGetWindowAttributes(dpy, w, &att); + if (att.map_state == IsViewable) + XSetInputFocus(dpy, w, RevertToParent, CurrentTime); - return 1; + return 1; } // @@ -174,4 +171,3 @@ if (evmask != 0) XSelectInput(dpy, win, evmask); } - diff -Nru alttab-1.3.0/test/Makefile alttab-1.5.0/test/Makefile --- alttab-1.3.0/test/Makefile 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/test/Makefile 2020-07-23 08:24:20.000000000 +0000 @@ -1,7 +1,7 @@ # # Stub for possible future test facility. # -# Copyright 2017-2018 Alexander Kulak. +# Copyright 2017-2019 Alexander Kulak. # This file is part of alttab program. # # alttab is free software: you can redistribute it and/or modify diff -Nru alttab-1.3.0/test/pngtest.c alttab-1.5.0/test/pngtest.c --- alttab-1.3.0/test/pngtest.c 2018-04-12 07:28:37.000000000 +0000 +++ alttab-1.5.0/test/pngtest.c 2020-07-23 08:24:20.000000000 +0000 @@ -1,7 +1,7 @@ /* * Stub for possible future test facility. * - * Copyright 2017-2018 Alexander Kulak. + * Copyright 2017-2019 Alexander Kulak. * This file is part of alttab program. * * alttab is free software: you can redistribute it and/or modify