diff -Nru suckless-tools-42/debian/changelog suckless-tools-43/debian/changelog --- suckless-tools-42/debian/changelog 2016-06-19 10:34:55.000000000 +0000 +++ suckless-tools-43/debian/changelog 2017-08-04 17:05:33.000000000 +0000 @@ -1,3 +1,35 @@ +suckless-tools (43-1) unstable; urgency=low + + [ Ilias Tsitsimpis ] + * New upstream release + - Update dmenu to version 4.7 + - Update slock to version 1.4 + * Remove lsx. + The lsx tool has been removed from the upstream repo and is not + supported anymore. + * Update my email address + * Bump Standards-Version to 4.0.0, no changes needed + * Bump dependency on debhelper to >= 10 + * Bump debhelper compat level to 10 + * Update d/copyright file. + Add slock/explicit_bzero.c and bump copyright years. + * Update d/patches + - Use the following patches for slock, from upstream's git repo: + (7a604ec1f) Fix resize with multiple monitors and portrait mode + (35633d456) Properly clear the last entered character + (0ff0d9f7a) there can only be one window in the event + - Remove `drop privileges` code from slock, since it runs without setuid + - Update rest of the patches to apply cleanly + * Fix FTCBFS. + Remove explicit invocation of `strip` and `pkg-config`. + Thanks to Helmut Grohne for providing the patch (Closes: #861341) + * Fix typo in ssid(1) manpage + + [ Barak A. Pearlmutter ] + * Fix typo in package description, missing s in similar (Closes: #857254) + + -- Ilias Tsitsimpis Fri, 04 Aug 2017 20:05:33 +0300 + suckless-tools (42-2) unstable; urgency=medium * Bump Standards-Version to 3.9.8, no changes needed diff -Nru suckless-tools-42/debian/compat suckless-tools-43/debian/compat --- suckless-tools-42/debian/compat 2016-06-19 09:57:11.000000000 +0000 +++ suckless-tools-43/debian/compat 2017-08-04 13:11:47.000000000 +0000 @@ -1 +1 @@ -9 +10 diff -Nru suckless-tools-42/debian/control suckless-tools-43/debian/control --- suckless-tools-42/debian/control 2016-06-19 10:04:12.000000000 +0000 +++ suckless-tools-43/debian/control 2017-08-04 13:11:47.000000000 +0000 @@ -1,9 +1,9 @@ Source: suckless-tools Section: x11 Priority: optional -Maintainer: Ilias Tsitsimpis +Maintainer: Ilias Tsitsimpis Build-Depends: - debhelper (>= 9), + debhelper (>= 10), libx11-dev, libxinerama-dev, dpkg-dev (>= 1.17), @@ -13,7 +13,7 @@ libpam0g-dev, libxrandr-dev, libfreetype6-dev -Standards-Version: 3.9.8 +Standards-Version: 4.0.0 Homepage: http://www.suckless.org Vcs-Git: https://anonscm.debian.org/git/collab-maint/suckless-tools.git Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/suckless-tools.git @@ -22,7 +22,7 @@ Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, libcap2-bin Suggests: dwm, stterm, surf -Provides: dmenu, lsw, lsx, slock, sprop, sselp, ssid, swarp, tabbed, wmname, xssstate +Provides: dmenu, lsw, slock, sprop, sselp, ssid, swarp, tabbed, wmname, xssstate Description: simple commands for minimalistic window managers This package provides simple commands designed to be used with a minimalistic window manager like dwm but they can be useful in scripts regardless of the @@ -30,7 +30,6 @@ . * dmenu: Dynamic menu is a generic menu for X. * lsw: Lists the titles of all running X windows to stdout, similar to ls(1). - * lsx: Lists executables in a directory. * slock: Simple X display locker that locks the X session. * sprop: Sets or gets X window properties. * sselp: Simple X selection printer that prints the X selection to stdout. @@ -38,5 +37,5 @@ * swarp: Simple X warping tool to warp the mouse pointer to a given position. * tabbed: Simple generic tabbed fronted to xembed aware applications. * wmname: Prints/sets the window manager name property of the root - window imilar to how hostname(1) behaves. + window similar to how hostname(1) behaves. * xssstate: Retrieves the state of X screensaver. diff -Nru suckless-tools-42/debian/copyright suckless-tools-43/debian/copyright --- suckless-tools-42/debian/copyright 2016-06-19 09:57:11.000000000 +0000 +++ suckless-tools-43/debian/copyright 2017-08-04 13:44:50.000000000 +0000 @@ -43,12 +43,6 @@ (C) 2006 Sander van Dijk License: Expat -Files: lsx/* -Copyright: - (C) 2006 Anselm R. Garbe - (C) 2006 Sander van Dijk -License: Expat - Files: ssid/* Copyright: (C) 2005-2006 Anselm R. Garbe @@ -67,6 +61,12 @@ (C) 2014-2016 Laslo Hunhold License: Expat +Files: slock/explicit_bzero.c +Copyright: Public Domain +License: public-domain + This file is in the public domain. + Written by Matthew Dempsky. + Files: xssstate/* Copyright: (C) 2008 Kai Hendry @@ -79,7 +79,7 @@ (C) 2010 Kai Hendry (C) 2012 Michael Stummvoll (C) 2012-2013 Vasudev Kamath - (C) 2015-2016 Ilias Tsitsimpis + (C) 2015-2017 Ilias Tsitsimpis License: Expat License: Expat diff -Nru suckless-tools-42/debian/manpages/lsx.1 suckless-tools-43/debian/manpages/lsx.1 --- suckless-tools-42/debian/manpages/lsx.1 2016-06-19 09:57:11.000000000 +0000 +++ suckless-tools-43/debian/manpages/lsx.1 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -.TH LSX 1 "2012-01-22" "0.1" "suckless-tools" - -.SH NAME -lsx \- list executables - -.SH SYNOPSIS -.B lsx - -.SH DESCRIPTION -.B lsx -prints all executables in given paths to stdout. - -.SH OPTIONS -.B lsx -prints its version when fed with \fB\-v\fR. - -.SH SEE ALSO -.B Homepage -<\fIhttp://www.suckless.org/\fR> - -.SH AUTHOR -lsx was written by Anselm R. Garbe <\fIgarbeam@gmail.com\fR> and Sander van Dijk <\fIa.h.vandijk@gmail.com\fR>. -.PP -This manual page was written by Michael Stummvoll <\fImichael@stummi.org\fR>, for the Debian project (but may be used by others). diff -Nru suckless-tools-42/debian/manpages/ssid.1 suckless-tools-43/debian/manpages/ssid.1 --- suckless-tools-42/debian/manpages/ssid.1 2016-06-19 09:57:11.000000000 +0000 +++ suckless-tools-43/debian/manpages/ssid.1 2017-08-04 16:47:12.000000000 +0000 @@ -10,7 +10,7 @@ .SH DESCRIPTION .B ssid -is an extremly simple setsid replacement. +is an extremely simple setsid replacement. It executes any given command after first assuming the present session identity, and possibly after forking to get a correct diff -Nru suckless-tools-42/debian/patches/Change-Mod-key-to-the-Windows-key.patch suckless-tools-43/debian/patches/Change-Mod-key-to-the-Windows-key.patch --- suckless-tools-42/debian/patches/Change-Mod-key-to-the-Windows-key.patch 2016-06-19 10:30:35.000000000 +0000 +++ suckless-tools-43/debian/patches/Change-Mod-key-to-the-Windows-key.patch 2017-08-04 16:24:19.000000000 +0000 @@ -1,6 +1,6 @@ From: Ilias Tsitsimpis Date: Sat, 10 Oct 2015 19:57:37 +0300 -Subject: Change Mod key to the Windows key +Subject: tabbed: Change Mod key to the Windows key Provide 'tabbed.meta' alternative which uses the Windows key as Mod key. diff -Nru suckless-tools-42/debian/patches/Define-PATH_MAX-in-case-it-is-missing.patch suckless-tools-43/debian/patches/Define-PATH_MAX-in-case-it-is-missing.patch --- suckless-tools-42/debian/patches/Define-PATH_MAX-in-case-it-is-missing.patch 2016-06-19 10:30:35.000000000 +0000 +++ suckless-tools-43/debian/patches/Define-PATH_MAX-in-case-it-is-missing.patch 2017-08-04 16:24:19.000000000 +0000 @@ -1,6 +1,6 @@ From: Ilias Tsitsimpis Date: Sun, 19 Jun 2016 13:16:49 +0300 -Subject: Define PATH_MAX in case it is missing +Subject: dmenu: Define PATH_MAX in case it is missing dmenu FTBFS on hurd because the PATH_MAX macro is not defined. According to POSIX, this macro may not be defined, so fix the code to diff -Nru suckless-tools-42/debian/patches/Don-t-exit-if-failed-to-adjust-OOM-score.patch suckless-tools-43/debian/patches/Don-t-exit-if-failed-to-adjust-OOM-score.patch --- suckless-tools-42/debian/patches/Don-t-exit-if-failed-to-adjust-OOM-score.patch 2016-06-19 10:30:35.000000000 +0000 +++ suckless-tools-43/debian/patches/Don-t-exit-if-failed-to-adjust-OOM-score.patch 2017-08-04 16:24:19.000000000 +0000 @@ -1,6 +1,6 @@ From: Ilias Tsitsimpis Date: Tue, 13 Oct 2015 15:27:46 +0300 -Subject: Don't exit if failed to adjust OOM score +Subject: slock: Don't exit if failed to adjust OOM score Adjusting the OOM score needs CAP_SYS_RESOURCE capabilities or the setuid bit. But we don't want to setuid our binary and not all @@ -9,20 +9,33 @@ Forwarded: no (Debian specific) --- - slock/slock.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) + slock/slock.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/slock/slock.c b/slock/slock.c -index cf49555..de0cd72 100644 +index e9d5fba..5175472 100644 --- a/slock/slock.c +++ b/slock/slock.c -@@ -81,7 +81,8 @@ dontkillme(void) - die("buffer too small\n"); - - if (fd < 0 || write(fd, value, length) != length || close(fd) != 0) -- die("cannot disable the out-of-memory killer for this process (make sure to suid or sgid slock)\n"); +@@ -70,15 +70,18 @@ dontkillme(void) + if (!(f = fopen(oomfile, "w"))) { + if (errno == ENOENT) + return; +- die("slock: fopen %s: %s\n", oomfile, strerror(errno)); + fprintf(stderr, "cannot disable the out-of-memory" + " killer for this process\n"); ++ return; + } + fprintf(f, "%d", OOM_SCORE_ADJ_MIN); + if (fclose(f)) { + if (errno == EACCES) +- die("slock: unable to disable OOM killer. " +- "Make sure to suid or sgid slock.\n"); ++ fprintf(stderr, "cannot disable the out-of-memory" ++ " killer for this process\n"); + else +- die("slock: fclose %s: %s\n", oomfile, strerror(errno)); ++ fprintf(stderr, "cannot disable the out-of-memory" ++ " killer for this process\n"); + } } #endif - diff -Nru suckless-tools-42/debian/patches/Escape-symbol-in-manpage.patch suckless-tools-43/debian/patches/Escape-symbol-in-manpage.patch --- suckless-tools-42/debian/patches/Escape-symbol-in-manpage.patch 2016-06-19 10:30:35.000000000 +0000 +++ suckless-tools-43/debian/patches/Escape-symbol-in-manpage.patch 2017-08-04 16:24:19.000000000 +0000 @@ -1,6 +1,6 @@ From: Ilias Tsitsimpis Date: Sat, 10 Oct 2015 19:54:16 +0300 -Subject: Escape '-' symbol in manpage +Subject: tabbed: Escape '-' symbol in manpage Manpage for tabbed was using '-' symbol without escape which will be considered by groff as hyphen. This patch escapes the '-' in manpages. diff -Nru suckless-tools-42/debian/patches/Patch-Makefiles-to-honor-CFLAGS-and-LDFLAGS.patch suckless-tools-43/debian/patches/Patch-Makefiles-to-honor-CFLAGS-and-LDFLAGS.patch --- suckless-tools-42/debian/patches/Patch-Makefiles-to-honor-CFLAGS-and-LDFLAGS.patch 2016-06-19 10:30:35.000000000 +0000 +++ suckless-tools-43/debian/patches/Patch-Makefiles-to-honor-CFLAGS-and-LDFLAGS.patch 2017-08-04 16:24:19.000000000 +0000 @@ -4,37 +4,42 @@ This patch allows the hardening flags injection into all Makefiles during build time. It also removes -Os and -O0 from upstream config.mk -to allow DEB_BUILD_OPTIONS=noopt. This patch also removes -s option to -allow proper working of nostrip value for DEB_BUILD_OPTIONS. +to allow DEB_BUILD_OPTIONS=noopt. + +Also, remove the -s linker option, as well as any explicit strip +invocation to allow proper working of nostrip value for +DEB_BUILD_OPTIONS. Author: Vasudev Kamath Forwarded: no --- dmenu/config.mk | 6 +++--- lsw/config.mk | 6 +++--- - lsx/config.mk | 4 ++-- slock/config.mk | 6 +++--- sprop/config.mk | 6 +++--- sselp/config.mk | 6 +++--- + ssid/Makefile | 1 - ssid/config.mk | 4 ++-- + swarp/Makefile | 1 - swarp/config.mk | 4 ++-- tabbed/config.mk | 6 +++--- + wmname/Makefile | 1 - wmname/config.mk | 6 +++--- xssstate/config.mk | 6 +++--- - 11 files changed, 30 insertions(+), 30 deletions(-) + 13 files changed, 28 insertions(+), 31 deletions(-) diff --git a/dmenu/config.mk b/dmenu/config.mk -index 365d3d6..c11ddf7 100644 +index de3f1d9..f816817 100644 --- a/dmenu/config.mk +++ b/dmenu/config.mk @@ -23,9 +23,9 @@ INCS = -I${X11INC} -I${FREETYPEINC} LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} # flags --CPPFLAGS = -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +-CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} -CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} -LDFLAGS = -s ${LIBS} -+CPPFLAGS += -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} ++CPPFLAGS += -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +CFLAGS += -std=c99 -pedantic -Wall ${INCS} ${CPPFLAGS} +LDFLAGS += ${LIBS} @@ -57,37 +62,22 @@ # compiler and linker CC = cc -diff --git a/lsx/config.mk b/lsx/config.mk -index f526b22..de5cdae 100644 ---- a/lsx/config.mk -+++ b/lsx/config.mk -@@ -12,8 +12,8 @@ INCS = -I/usr/lib - LIBS = -L/usr/lib -lc - - # flags --CFLAGS = -Os ${INCS} -DVERSION=\"${VERSION}\" --LDFLAGS = ${LIBS} -+CFLAGS += ${INCS} -DVERSION=\"${VERSION}\" ${CPPFLAGS} -+LDFLAGS += ${LIBS} - #CFLAGS = -g -Wall -O2 ${INCS} -DVERSION=\"${VERSION}\" - #LDFLAGS = -g ${LIBS} - diff --git a/slock/config.mk b/slock/config.mk -index f93879e..776bd98 100644 +index 74429ae..1c1374a 100644 --- a/slock/config.mk +++ b/slock/config.mk @@ -15,9 +15,9 @@ INCS = -I. -I/usr/include -I${X11INC} LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr # flags --CPPFLAGS = -DVERSION=\"${VERSION}\" -DHAVE_SHADOW_H +-CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_SHADOW_H -CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} -LDFLAGS = -s ${LIBS} -+CPPFLAGS += -DVERSION=\"${VERSION}\" -DHAVE_SHADOW_H ++CPPFLAGS += -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_SHADOW_H +CFLAGS += -std=c99 -pedantic -Wall ${INCS} ${CPPFLAGS} +LDFLAGS += ${LIBS} + COMPATSRC = explicit_bzero.c - # On *BSD remove -DHAVE_SHADOW_H from CPPFLAGS and add -DHAVE_BSD_AUTH # On OpenBSD and Darwin remove -lcrypt from LIBS diff --git a/sprop/config.mk b/sprop/config.mk index 826cdcb..7da5f46 100644 @@ -123,6 +113,18 @@ # compiler and linker CC = cc +diff --git a/ssid/Makefile b/ssid/Makefile +index 3cfd520..8039ab1 100644 +--- a/ssid/Makefile ++++ b/ssid/Makefile +@@ -24,7 +24,6 @@ ${OBJ}: config.mk + ssid: ${OBJ} + @echo LD $@ + @${LD} -o $@ ${OBJ} ${LDFLAGS} +- @strip $@ + + clean: + @echo cleaning diff --git a/ssid/config.mk b/ssid/config.mk index 0b020f2..b675a4b 100644 --- a/ssid/config.mk @@ -138,6 +140,18 @@ #CFLAGS = -g -Wall -O2 ${INCS} -DVERSION=\"${VERSION}\" #LDFLAGS = -g ${LIBS} +diff --git a/swarp/Makefile b/swarp/Makefile +index 8e1c848..514855b 100644 +--- a/swarp/Makefile ++++ b/swarp/Makefile +@@ -24,7 +24,6 @@ ${OBJ}: config.mk + swarp: ${OBJ} + @echo LD $@ + @${LD} -o $@ ${OBJ} ${LDFLAGS} +- @strip $@ + + clean: + @echo cleaning diff --git a/swarp/config.mk b/swarp/config.mk index f6d6fd5..b3bae48 100644 --- a/swarp/config.mk @@ -170,6 +184,18 @@ # Solaris #CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\" +diff --git a/wmname/Makefile b/wmname/Makefile +index fc14296..d902583 100644 +--- a/wmname/Makefile ++++ b/wmname/Makefile +@@ -23,7 +23,6 @@ ${OBJ}: config.mk + wmname: ${OBJ} + @echo LD $@ + @${LD} -o $@ ${OBJ} ${LDFLAGS} +- @strip $@ + + clean: + @echo cleaning diff --git a/wmname/config.mk b/wmname/config.mk index ca6d6c4..034ead9 100644 --- a/wmname/config.mk diff -Nru suckless-tools-42/debian/patches/Remove-custom-library-search-paths-from-Makefiles.patch suckless-tools-43/debian/patches/Remove-custom-library-search-paths-from-Makefiles.patch --- suckless-tools-42/debian/patches/Remove-custom-library-search-paths-from-Makefiles.patch 2016-06-19 10:30:35.000000000 +0000 +++ suckless-tools-43/debian/patches/Remove-custom-library-search-paths-from-Makefiles.patch 2017-08-04 16:24:19.000000000 +0000 @@ -16,7 +16,6 @@ --- dmenu/config.mk | 4 ++-- lsw/config.mk | 4 ++-- - lsx/config.mk | 4 ++-- slock/config.mk | 4 ++-- sprop/config.mk | 4 ++-- sselp/config.mk | 4 ++-- @@ -25,23 +24,23 @@ tabbed/config.mk | 4 ++-- wmname/config.mk | 4 ++-- xssstate/config.mk | 4 ++-- - 11 files changed, 22 insertions(+), 22 deletions(-) + 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/dmenu/config.mk b/dmenu/config.mk -index c11ddf7..7a90ee8 100644 +index f816817..394f672 100644 --- a/dmenu/config.mk +++ b/dmenu/config.mk @@ -19,8 +19,8 @@ FREETYPEINC = /usr/include/freetype2 - FREETYPEINC = ${X11INC}/freetype2 + #FREETYPEINC = ${X11INC}/freetype2 # includes and libs -INCS = -I${X11INC} -I${FREETYPEINC} -LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -+INCS = $(shell pkg-config --cflags fontconfig xft) ++INCS = $(shell $(PKG_CONFIG) --cflags fontconfig xft) +LIBS = -lX11 ${XINERAMALIBS} ${FREETYPELIBS} # flags - CPPFLAGS += -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} + CPPFLAGS += -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} diff --git a/lsw/config.mk b/lsw/config.mk index 400b2ca..186b93b 100644 --- a/lsw/config.mk @@ -57,23 +56,8 @@ # flags CPPFLAGS += -DVERSION=\"${VERSION}\" -diff --git a/lsx/config.mk b/lsx/config.mk -index de5cdae..04b58ea 100644 ---- a/lsx/config.mk -+++ b/lsx/config.mk -@@ -8,8 +8,8 @@ PREFIX = /usr/local - MANPREFIX = ${PREFIX}/share/man - - # includes and libs --INCS = -I/usr/lib --LIBS = -L/usr/lib -lc -+INCS = -+LIBS = -lc - - # flags - CFLAGS += ${INCS} -DVERSION=\"${VERSION}\" ${CPPFLAGS} diff --git a/slock/config.mk b/slock/config.mk -index 776bd98..4fda095 100644 +index 1c1374a..061810b 100644 --- a/slock/config.mk +++ b/slock/config.mk @@ -11,8 +11,8 @@ X11INC = /usr/X11R6/include @@ -86,7 +70,7 @@ +LIBS = -lc -lcrypt -lX11 -lXext -lXrandr # flags - CPPFLAGS += -DVERSION=\"${VERSION}\" -DHAVE_SHADOW_H + CPPFLAGS += -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_SHADOW_H diff --git a/sprop/config.mk b/sprop/config.mk index 7da5f46..e9fbd30 100644 --- a/sprop/config.mk diff -Nru suckless-tools-42/debian/patches/Remove-useless-dependency-against-Xext-library.patch suckless-tools-43/debian/patches/Remove-useless-dependency-against-Xext-library.patch --- suckless-tools-42/debian/patches/Remove-useless-dependency-against-Xext-library.patch 2016-06-19 10:30:35.000000000 +0000 +++ suckless-tools-43/debian/patches/Remove-useless-dependency-against-Xext-library.patch 2017-08-04 16:24:19.000000000 +0000 @@ -1,6 +1,6 @@ From: Ilias Tsitsimpis Date: Tue, 16 Feb 2016 16:10:31 +0200 -Subject: Remove useless dependency against Xext library +Subject: slock: Remove useless dependency against Xext library Slock is linked against libXext.so.6 but uses none of the library's symbols. @@ -11,7 +11,7 @@ 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slock/config.mk b/slock/config.mk -index 26a437d..43c7005 100644 +index d148027..7073961 100644 --- a/slock/config.mk +++ b/slock/config.mk @@ -12,7 +12,7 @@ X11LIB = /usr/X11R6/lib @@ -22,4 +22,4 @@ +LIBS = -lc -lpam -lX11 -lXrandr # flags - CPPFLAGS += -DVERSION=\"${VERSION}\" -DHAVE_PAM + CPPFLAGS += -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_PAM diff -Nru suckless-tools-42/debian/patches/segfault-avoidance.patch suckless-tools-43/debian/patches/segfault-avoidance.patch --- suckless-tools-42/debian/patches/segfault-avoidance.patch 2016-06-19 10:30:35.000000000 +0000 +++ suckless-tools-43/debian/patches/segfault-avoidance.patch 2017-08-04 16:24:19.000000000 +0000 @@ -1,6 +1,6 @@ From: Anselm R Garbe Date: Mon, 22 Dec 2014 10:36:47 +0000 -Subject: segfault avoidance +Subject: lsw: segfault avoidance Origin: upstream, http://git.suckless.org/lsw/commit/?id=4d6e1b39e14666 --- diff -Nru suckless-tools-42/debian/patches/series suckless-tools-43/debian/patches/series --- suckless-tools-42/debian/patches/series 2016-06-19 10:30:35.000000000 +0000 +++ suckless-tools-43/debian/patches/series 2017-08-04 16:51:35.000000000 +0000 @@ -3,7 +3,11 @@ Patch-Makefiles-to-honor-CFLAGS-and-LDFLAGS.patch Remove-custom-library-search-paths-from-Makefiles.patch Change-Mod-key-to-the-Windows-key.patch +Define-PATH_MAX-in-case-it-is-missing.patch +slock-Fix-resize-with-multiple-monitors-and-portrait-mode.patch +slock-there-can-only-be-one-window-in-the-event.patch +slock-Properly-clear-the-last-entered-character.patch Don-t-exit-if-failed-to-adjust-OOM-score.patch +slock-Do-not-drop-privileges.patch Use-PAM-for-authentication.patch Remove-useless-dependency-against-Xext-library.patch -Define-PATH_MAX-in-case-it-is-missing.patch diff -Nru suckless-tools-42/debian/patches/slock-Do-not-drop-privileges.patch suckless-tools-43/debian/patches/slock-Do-not-drop-privileges.patch --- suckless-tools-42/debian/patches/slock-Do-not-drop-privileges.patch 1970-01-01 00:00:00.000000000 +0000 +++ suckless-tools-43/debian/patches/slock-Do-not-drop-privileges.patch 2017-08-04 16:24:19.000000000 +0000 @@ -0,0 +1,58 @@ +From: Ilias Tsitsimpis +Date: Fri, 4 Aug 2017 17:03:14 +0300 +Subject: slock: Do not drop privileges + +In Debian, slock does not have the setuid bit. + +Forwarded: no (Debian specific) +--- + slock/slock.c | 22 ---------------------- + 1 file changed, 22 deletions(-) + +diff --git a/slock/slock.c b/slock/slock.c +index 5175472..83365f2 100644 +--- a/slock/slock.c ++++ b/slock/slock.c +@@ -308,10 +308,6 @@ int + main(int argc, char **argv) { + struct xrandr rr; + struct lock **locks; +- struct passwd *pwd; +- struct group *grp; +- uid_t duid; +- gid_t dgid; + const char *hash; + Display *dpy; + int s, nlocks, nscreens; +@@ -324,17 +320,6 @@ main(int argc, char **argv) { + usage(); + } ARGEND + +- /* validate drop-user and -group */ +- errno = 0; +- if (!(pwd = getpwnam(user))) +- die("slock: getpwnam %s: %s\n", user, +- errno ? strerror(errno) : "user entry not found"); +- duid = pwd->pw_uid; +- errno = 0; +- if (!(grp = getgrnam(group))) +- die("slock: getgrnam %s: %s\n", group, +- errno ? strerror(errno) : "group entry not found"); +- dgid = grp->gr_gid; + + #ifdef __linux__ + dontkillme(); +@@ -348,13 +333,6 @@ main(int argc, char **argv) { + if (!(dpy = XOpenDisplay(NULL))) + die("slock: cannot open display\n"); + +- /* drop privileges */ +- if (setgroups(0, NULL) < 0) +- die("slock: setgroups: %s\n", strerror(errno)); +- if (setgid(dgid) < 0) +- die("slock: setgid: %s\n", strerror(errno)); +- if (setuid(duid) < 0) +- die("slock: setuid: %s\n", strerror(errno)); + + /* check for Xrandr support */ + rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase); diff -Nru suckless-tools-42/debian/patches/slock-Fix-resize-with-multiple-monitors-and-portrait-mode.patch suckless-tools-43/debian/patches/slock-Fix-resize-with-multiple-monitors-and-portrait-mode.patch --- suckless-tools-42/debian/patches/slock-Fix-resize-with-multiple-monitors-and-portrait-mode.patch 1970-01-01 00:00:00.000000000 +0000 +++ suckless-tools-43/debian/patches/slock-Fix-resize-with-multiple-monitors-and-portrait-mode.patch 2017-08-04 16:24:19.000000000 +0000 @@ -0,0 +1,33 @@ +From: Bob Uhl +Date: Mon, 7 Nov 2016 10:15:20 -0700 +Subject: slock: Fix resize with multiple monitors and portrait mode + +When connecting/disconnecting a portrait monitor, the +XRRScreenChangeNotifyEvent height & width are reversed due to the XRandR +rotation; detect this and DTRT. + +Origin: upstream, http://git.suckless.org/slock/commit/?id=7a604ec1fae +--- + slock/slock.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/slock/slock.c b/slock/slock.c +index d2f0886..61fe9ee 100644 +--- a/slock/slock.c ++++ b/slock/slock.c +@@ -201,8 +201,13 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens, + rre = (XRRScreenChangeNotifyEvent*)&ev; + for (screen = 0; screen < nscreens; screen++) { + if (locks[screen]->win == rre->window) { +- XResizeWindow(dpy, locks[screen]->win, +- rre->width, rre->height); ++ if (rre->rotation == RR_Rotate_90 || ++ rre->rotation == RR_Rotate_270) ++ XResizeWindow(dpy, locks[screen]->win, ++ rre->height, rre->width); ++ else ++ XResizeWindow(dpy, locks[screen]->win, ++ rre->width, rre->height); + XClearWindow(dpy, locks[screen]->win); + } + } diff -Nru suckless-tools-42/debian/patches/slock-Properly-clear-the-last-entered-character.patch suckless-tools-43/debian/patches/slock-Properly-clear-the-last-entered-character.patch --- suckless-tools-42/debian/patches/slock-Properly-clear-the-last-entered-character.patch 1970-01-01 00:00:00.000000000 +0000 +++ suckless-tools-43/debian/patches/slock-Properly-clear-the-last-entered-character.patch 2017-08-04 16:24:19.000000000 +0000 @@ -0,0 +1,33 @@ +From: Tobias Stoeckmann +Date: Sat, 25 Mar 2017 21:16:01 +0100 +Subject: slock: Properly clear the last entered character + +When enter is pressed, passwd[len] will be set to '\0'. Pressing +backspace is supposed to remove the last entered character. + +But currently, the clearing has an off-by-one, as in setting +passwd[len] to '\0' just like enter would do. + +You can also verify it by imagining len=1 and that it's impossible to +clear passwd[0] by pressing backspace with the current code. + +Signed-off-by: Tobias Stoeckmann + +Origin: upstream, http://git.suckless.org/slock/commit/?id=35633d45672 +--- + slock/slock.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/slock/slock.c b/slock/slock.c +index 700acfb..e9d5fba 100644 +--- a/slock/slock.c ++++ b/slock/slock.c +@@ -177,7 +177,7 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens, + break; + case XK_BackSpace: + if (len) +- passwd[len--] = '\0'; ++ passwd[--len] = '\0'; + break; + default: + if (num && !iscntrl((int)buf[0]) && diff -Nru suckless-tools-42/debian/patches/slock-there-can-only-be-one-window-in-the-event.patch suckless-tools-43/debian/patches/slock-there-can-only-be-one-window-in-the-event.patch --- suckless-tools-42/debian/patches/slock-there-can-only-be-one-window-in-the-event.patch 1970-01-01 00:00:00.000000000 +0000 +++ suckless-tools-43/debian/patches/slock-there-can-only-be-one-window-in-the-event.patch 2017-08-04 16:24:19.000000000 +0000 @@ -0,0 +1,21 @@ +From: Markus Teich +Date: Wed, 23 Nov 2016 00:28:25 +0100 +Subject: slock: there can only be one window in the event + +Origin: upstream, http://git.suckless.org/slock/commit/?id=0ff0d9f7a71 +--- + slock/slock.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/slock/slock.c b/slock/slock.c +index 61fe9ee..700acfb 100644 +--- a/slock/slock.c ++++ b/slock/slock.c +@@ -209,6 +209,7 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens, + XResizeWindow(dpy, locks[screen]->win, + rre->width, rre->height); + XClearWindow(dpy, locks[screen]->win); ++ break; + } + } + } else for (screen = 0; screen < nscreens; screen++) diff -Nru suckless-tools-42/debian/patches/Use-PAM-for-authentication.patch suckless-tools-43/debian/patches/Use-PAM-for-authentication.patch --- suckless-tools-42/debian/patches/Use-PAM-for-authentication.patch 2016-06-19 10:30:35.000000000 +0000 +++ suckless-tools-43/debian/patches/Use-PAM-for-authentication.patch 2017-08-04 16:24:19.000000000 +0000 @@ -1,6 +1,6 @@ From: Ilias Tsitsimpis Date: Tue, 13 Oct 2015 20:24:46 +0300 -Subject: Use PAM for authentication +Subject: slock: Use PAM for authentication Patch slock to use PAM for authentication instead of querying the shadow file. This means that slock can authenticate the user using some other @@ -16,11 +16,11 @@ Forwarded: http://lists.suckless.org/dev/1011/6405.html --- slock/config.mk | 4 +-- - slock/slock.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- - 2 files changed, 90 insertions(+), 6 deletions(-) + slock/slock.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 92 insertions(+), 2 deletions(-) diff --git a/slock/config.mk b/slock/config.mk -index 4fda095..26a437d 100644 +index 061810b..d148027 100644 --- a/slock/config.mk +++ b/slock/config.mk @@ -12,10 +12,10 @@ X11LIB = /usr/X11R6/lib @@ -31,18 +31,18 @@ +LIBS = -lc -lpam -lX11 -lXext -lXrandr # flags --CPPFLAGS += -DVERSION=\"${VERSION}\" -DHAVE_SHADOW_H -+CPPFLAGS += -DVERSION=\"${VERSION}\" -DHAVE_PAM +-CPPFLAGS += -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_SHADOW_H ++CPPFLAGS += -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_PAM CFLAGS += -std=c99 -pedantic -Wall ${INCS} ${CPPFLAGS} LDFLAGS += ${LIBS} - + COMPATSRC = explicit_bzero.c diff --git a/slock/slock.c b/slock/slock.c -index de0cd72..3e15ecd 100644 +index 83365f2..473c896 100644 --- a/slock/slock.c +++ b/slock/slock.c -@@ -23,6 +23,18 @@ - #include - #endif +@@ -24,6 +24,18 @@ + + char *argv0; +#ifdef HAVE_PAM +#include @@ -59,64 +59,44 @@ enum { INIT, INPUT, -@@ -86,7 +98,7 @@ dontkillme(void) - } - #endif - --#ifndef HAVE_BSD_AUTH -+#if !defined(HAVE_BSD_AUTH) && !defined(HAVE_PAM) - /* only run as root */ - static const char * - getpw(void) -@@ -121,7 +133,7 @@ getpw(void) - #endif - - static void --#ifdef HAVE_BSD_AUTH -+#if defined(HAVE_BSD_AUTH) || defined(HAVE_PAM) - readpw(Display *dpy) - #else - readpw(Display *dpy, const char *pws) -@@ -162,6 +174,8 @@ readpw(Display *dpy, const char *pws) - passwd[len] = 0; - #ifdef HAVE_BSD_AUTH - running = !auth_userokay(getlogin(), NULL, "auth-xlock", passwd); -+#elif defined(HAVE_PAM) +@@ -163,10 +175,14 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens, + case XK_Return: + passwd[len] = '\0'; + errno = 0; ++#ifdef HAVE_PAM + running = !!pam_auth(passwd); - #else - running = !!strcmp(crypt(passwd, pws), pws); - #endif -@@ -290,7 +304,7 @@ usage(void) - - int - main(int argc, char **argv) { --#ifndef HAVE_BSD_AUTH -+#if !defined(HAVE_BSD_AUTH) && !defined(HAVE_PAM) - const char *pws; - #endif - Display *dpy; -@@ -309,7 +323,7 @@ main(int argc, char **argv) { - if (!getpwuid(getuid())) - die("slock: no passwd entry for you\n"); - --#ifndef HAVE_BSD_AUTH -+#if !defined(HAVE_BSD_AUTH) && !defined(HAVE_PAM) - pws = getpw(); ++#else + if (!(inputhash = crypt(passwd, hash))) + fprintf(stderr, "slock: crypt: %s\n", strerror(errno)); + else + running = !!strcmp(inputhash, hash); ++#endif + if (running) { + XBell(dpy, 100); + failure = 1; +@@ -325,10 +341,14 @@ main(int argc, char **argv) { + dontkillme(); #endif -@@ -344,6 +358,10 @@ main(int argc, char **argv) { - /* Everything is now blank. Now wait for the correct password. */ - #ifdef HAVE_BSD_AUTH - readpw(dpy); -+#elif defined(HAVE_PAM) ++#ifdef HAVE_PAM + pam_init(); -+ readpw(dpy); -+ pam_destroy(); - #else - readpw(dpy, pws); - #endif -@@ -357,3 +375,69 @@ main(int argc, char **argv) { ++#else + hash = gethash(); + errno = 0; + if (!crypt("", hash)) + die("slock: crypt: %s\n", strerror(errno)); ++#endif + if (!(dpy = XOpenDisplay(NULL))) + die("slock: cannot open display\n"); +@@ -370,5 +390,75 @@ main(int argc, char **argv) { + /* everything is now blank. Wait for the correct password */ + readpw(dpy, &rr, locks, nscreens, hash); + ++#ifdef HAVE_PAM ++ pam_destroy(); ++#endif ++ return 0; } + diff -Nru suckless-tools-42/debian/rules suckless-tools-43/debian/rules --- suckless-tools-42/debian/rules 2016-06-19 09:57:11.000000000 +0000 +++ suckless-tools-43/debian/rules 2017-08-04 16:27:47.000000000 +0000 @@ -9,6 +9,10 @@ # Path of 'debian' directory DEB_DIR := $(abspath $(dir $(MAKEFILE_LIST))) +# Provide the correct pkg-config for cross-building +include /usr/share/dpkg/architecture.mk +export PKG_CONFIG := $(DEB_HOST_GNU_TYPE)-pkg-config + # Enable all hardening flags export DEB_BUILD_MAINT_OPTIONS = hardening=+all diff -Nru suckless-tools-42/debian/suckless-tools.manpages suckless-tools-43/debian/suckless-tools.manpages --- suckless-tools-42/debian/suckless-tools.manpages 2016-06-19 09:57:11.000000000 +0000 +++ suckless-tools-43/debian/suckless-tools.manpages 2017-08-04 13:11:47.000000000 +0000 @@ -1,6 +1,5 @@ debian/manpages/wmname.1 debian/manpages/sselp.1 -debian/manpages/lsx.1 debian/manpages/swarp.1 debian/manpages/dmenu_run.1 debian/manpages/dmenu_path.1 diff -Nru suckless-tools-42/debian/watch suckless-tools-43/debian/watch --- suckless-tools-42/debian/watch 2016-06-19 09:57:11.000000000 +0000 +++ suckless-tools-43/debian/watch 2017-08-04 13:11:47.000000000 +0000 @@ -3,11 +3,11 @@ # Download dmenu opts=dversionmangle=s/\+(debian|dfsg|ds|deb)(\.\d+)?$//,\ uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha)\d*)$/$1~$2/,\ -oversionmangle=s/.*/42/,\ +oversionmangle=s/.*/43/,\ component=dmenu \ http://dl.suckless.org/tools/ \ dmenu@ANY_VERSION@@ARCHIVE_EXT@ \ -4.6 +4.7 # Download lsw opts=dversionmangle=s/\+(debian|dfsg|ds|deb)(\.\d+)?$//,\ @@ -17,21 +17,13 @@ lsw@ANY_VERSION@@ARCHIVE_EXT@ \ 0.3 -# Download lsx -opts=dversionmangle=s/\+(debian|dfsg|ds|deb)(\.\d+)?$//,\ -uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha)\d*)$/$1~$2/,\ -component=lsx \ -http://dl.suckless.org/tools/ \ -lsx@ANY_VERSION@@ARCHIVE_EXT@ \ -0.1 - # Download slock opts=dversionmangle=s/\+(debian|dfsg|ds|deb)(\.\d+)?$//,\ uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha)\d*)$/$1~$2/,\ component=slock \ http://dl.suckless.org/tools/ \ slock@ANY_VERSION@@ARCHIVE_EXT@ \ -1.3 +1.4 # Download sprop opts=dversionmangle=s/\+(debian|dfsg|ds|deb)(\.\d+)?$//,\ diff -Nru suckless-tools-42/dmenu/arg.h suckless-tools-43/dmenu/arg.h --- suckless-tools-42/dmenu/arg.h 2015-11-08 22:42:21.000000000 +0000 +++ suckless-tools-43/dmenu/arg.h 2017-05-02 16:36:47.000000000 +0000 @@ -10,8 +10,8 @@ /* use main(int argc, char *argv[]) */ #define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ - argv[0] && argv[0][1]\ - && argv[0][0] == '-';\ + argv[0] && argv[0][0] == '-'\ + && argv[0][1];\ argc--, argv++) {\ char argc_;\ char **argv_;\ diff -Nru suckless-tools-42/dmenu/config.def.h suckless-tools-43/dmenu/config.def.h --- suckless-tools-42/dmenu/config.def.h 2015-11-08 22:42:21.000000000 +0000 +++ suckless-tools-43/dmenu/config.def.h 2017-05-02 16:36:47.000000000 +0000 @@ -6,12 +6,18 @@ static const char *fonts[] = { "monospace:size=10" }; -static const char *prompt = NULL; /* -p option; prompt to the elft of input field */ -static const char *normbgcolor = "#222222"; /* -nb option; normal background */ -static const char *normfgcolor = "#bbbbbb"; /* -nf option; normal foreground */ -static const char *selbgcolor = "#005577"; /* -sb option; selected background */ -static const char *selfgcolor = "#eeeeee"; /* -sf option; selected foreground */ -static const char *outbgcolor = "#00ffff"; -static const char *outfgcolor = "#000000"; +static const char *prompt = NULL; /* -p option; prompt to the left of input field */ +static const char *colors[SchemeLast][2] = { + /* fg bg */ + [SchemeNorm] = { "#bbbbbb", "#222222" }, + [SchemeSel] = { "#eeeeee", "#005577" }, + [SchemeOut] = { "#000000", "#00ffff" }, +}; /* -l option; if nonzero, dmenu uses vertical list with given number of lines */ static unsigned int lines = 0; + +/* + * Characters not considered part of a word while deleting words + * for example: " /?\"&[]" + */ +static const char worddelimiters[] = " "; diff -Nru suckless-tools-42/dmenu/config.mk suckless-tools-43/dmenu/config.mk --- suckless-tools-42/dmenu/config.mk 2015-11-08 22:42:21.000000000 +0000 +++ suckless-tools-43/dmenu/config.mk 2017-05-02 16:36:47.000000000 +0000 @@ -1,5 +1,5 @@ # dmenu version -VERSION = 4.6 +VERSION = 4.7 # paths PREFIX = /usr/local @@ -16,14 +16,14 @@ FREETYPELIBS = -lfontconfig -lXft FREETYPEINC = /usr/include/freetype2 # OpenBSD (uncomment) -FREETYPEINC = ${X11INC}/freetype2 +#FREETYPEINC = ${X11INC}/freetype2 # includes and libs INCS = -I${X11INC} -I${FREETYPEINC} LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} # flags -CPPFLAGS = -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} LDFLAGS = -s ${LIBS} diff -Nru suckless-tools-42/dmenu/dmenu.1 suckless-tools-43/dmenu/dmenu.1 --- suckless-tools-42/dmenu/dmenu.1 2015-11-08 22:42:21.000000000 +0000 +++ suckless-tools-43/dmenu/dmenu.1 2017-05-02 16:36:47.000000000 +0000 @@ -3,13 +3,11 @@ dmenu \- dynamic menu .SH SYNOPSIS .B dmenu -.RB [ \-b ] -.RB [ \-f ] -.RB [ \-i ] +.RB [ \-bfiv ] .RB [ \-l +.IR lines ] .RB [ \-m .IR monitor ] -.IR lines ] .RB [ \-p .IR prompt ] .RB [ \-fn @@ -22,7 +20,8 @@ .IR color ] .RB [ \-sf .IR color ] -.RB [ \-v ] +.RB [ \-w +.IR windowid ] .P .BR dmenu_run " ..." .SH DESCRIPTION @@ -78,6 +77,9 @@ .TP .B \-v prints version information to stdout, then exits. +.TP +.BI \-w " windowid" +embed into windowid. .SH USAGE dmenu is completely controlled by the keyboard. Items are selected using the arrow keys, page up, page down, home, and end. diff -Nru suckless-tools-42/dmenu/dmenu.c suckless-tools-43/dmenu/dmenu.c --- suckless-tools-42/dmenu/dmenu.c 2015-11-08 22:42:21.000000000 +0000 +++ suckless-tools-43/dmenu/dmenu.c 2017-05-02 16:36:47.000000000 +0000 @@ -22,8 +22,7 @@ #define INTERSECT(x,y,w,h,r) (MAX(0, MIN((x)+(w),(r).x_org+(r).width) - MAX((x),(r).x_org)) \ * MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org))) #define LENGTH(X) (sizeof X / sizeof X[0]) -#define TEXTNW(X,N) (drw_font_getexts_width(drw->fonts[0], (X), (N))) -#define TEXTW(X) (drw_text(drw, 0, 0, 0, 0, (X), 0) + drw->fonts[0]->h) +#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) /* enums */ enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */ @@ -35,9 +34,10 @@ }; static char text[BUFSIZ] = ""; +static char *embed; static int bh, mw, mh; -static int sw, sh; /* X display screen geometry width, height */ -static int inputw, promptw; +static int inputw = 0, promptw; +static int lrpad; /* sum of left and right padding */ static size_t cursor; static struct item *items = NULL; static struct item *matches, *matchend; @@ -46,11 +46,11 @@ static Atom clip, utf8; static Display *dpy; -static Window root, win; +static Window root, parentwin, win; static XIC xic; -static ClrScheme scheme[SchemeLast]; static Drw *drw; +static Clr *scheme[SchemeLast]; #include "config.h" @@ -94,10 +94,8 @@ size_t i; XUngrabKey(dpy, AnyKey, AnyModifier, root); - for (i = 0; i < SchemeLast; i++) { - drw_clr_free(scheme[i].bg); - drw_clr_free(scheme[i].fg); - } + for (i = 0; i < SchemeLast; i++) + free(scheme[i]); drw_free(drw); XSync(dpy, False); XCloseDisplay(dpy); @@ -114,89 +112,101 @@ return NULL; } +static int +drawitem(struct item *item, int x, int y, int w) +{ + if (item == sel) + drw_setscheme(drw, scheme[SchemeSel]); + else if (item->out) + drw_setscheme(drw, scheme[SchemeOut]); + else + drw_setscheme(drw, scheme[SchemeNorm]); + + return drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0); +} + static void drawmenu(void) { - int curpos; + unsigned int curpos; struct item *item; - int x = 0, y = 0, h = bh, w; + int x = 0, y = 0, w; - drw_setscheme(drw, &scheme[SchemeNorm]); - drw_rect(drw, 0, 0, mw, mh, 1, 1, 1); + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, 0, 0, mw, mh, 1, 1); if (prompt && *prompt) { - drw_setscheme(drw, &scheme[SchemeSel]); - drw_text(drw, x, 0, promptw, bh, prompt, 0); - x += promptw; + drw_setscheme(drw, scheme[SchemeSel]); + x = drw_text(drw, x, 0, promptw, bh, lrpad / 2, prompt, 0); } /* draw input field */ w = (lines > 0 || !matches) ? mw - x : inputw; - drw_setscheme(drw, &scheme[SchemeNorm]); - drw_text(drw, x, 0, w, bh, text, 0); + drw_setscheme(drw, scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0); - if ((curpos = TEXTNW(text, cursor) + bh / 2 - 2) < w) { - drw_setscheme(drw, &scheme[SchemeNorm]); - drw_rect(drw, x + curpos + 2, 2, 1, bh - 4, 1, 1, 0); + drw_font_getexts(drw->fonts, text, cursor, &curpos, NULL); + if ((curpos += lrpad / 2 - 1) < w) { + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0); } if (lines > 0) { /* draw vertical list */ - w = mw - x; - for (item = curr; item != next; item = item->right) { - y += h; - if (item == sel) - drw_setscheme(drw, &scheme[SchemeSel]); - else if (item->out) - drw_setscheme(drw, &scheme[SchemeOut]); - else - drw_setscheme(drw, &scheme[SchemeNorm]); - - drw_text(drw, x, y, w, bh, item->text, 0); - } + for (item = curr; item != next; item = item->right) + drawitem(item, x, y += bh, mw - x); } else if (matches) { /* draw horizontal list */ x += inputw; w = TEXTW("<"); if (curr->left) { - drw_setscheme(drw, &scheme[SchemeNorm]); - drw_text(drw, x, 0, w, bh, "<", 0); - } - for (item = curr; item != next; item = item->right) { - x += w; - w = MIN(TEXTW(item->text), mw - x - TEXTW(">")); - - if (item == sel) - drw_setscheme(drw, &scheme[SchemeSel]); - else if (item->out) - drw_setscheme(drw, &scheme[SchemeOut]); - else - drw_setscheme(drw, &scheme[SchemeNorm]); - drw_text(drw, x, 0, w, bh, item->text, 0); + drw_setscheme(drw, scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, "<", 0); } - w = TEXTW(">"); - x = mw - w; + x += w; + for (item = curr; item != next; item = item->right) + x = drawitem(item, x, 0, MIN(TEXTW(item->text), mw - x - TEXTW(">"))); if (next) { - drw_setscheme(drw, &scheme[SchemeNorm]); - drw_text(drw, x, 0, w, bh, ">", 0); + w = TEXTW(">"); + drw_setscheme(drw, scheme[SchemeNorm]); + drw_text(drw, mw - w, 0, w, bh, lrpad / 2, ">", 0); } } drw_map(drw, win, 0, 0, mw, mh); } static void +grabfocus(void) +{ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; + Window focuswin; + int i, revertwin; + + for (i = 0; i < 100; ++i) { + XGetInputFocus(dpy, &focuswin, &revertwin); + if (focuswin == win) + return; + XSetInputFocus(dpy, win, RevertToParent, CurrentTime); + nanosleep(&ts, NULL); + } + die("cannot grab focus"); +} + +static void grabkeyboard(void) { struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 }; int i; + if (embed) + return; /* try to grab keyboard, we may have to wait for another process to ungrab */ for (i = 0; i < 1000; i++) { - if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, - GrabModeAsync, GrabModeAsync, CurrentTime) == GrabSuccess) + if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync, + GrabModeAsync, CurrentTime) == GrabSuccess) return; nanosleep(&ts, NULL); } - die("cannot grab keyboard\n"); + die("cannot grab keyboard"); } static void @@ -214,11 +224,11 @@ /* separate input text into tokens to be matched individually */ for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " ")) if (++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv))) - die("cannot realloc %u bytes\n", tokn * sizeof *tokv); + die("cannot realloc %u bytes:", tokn * sizeof *tokv); len = tokc ? strlen(tokv[0]) : 0; matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL; - textsize = strlen(text); + textsize = strlen(text) + 1; for (item = items; item && item->text; item++) { for (i = 0; i < tokc; i++) if (!fstrstr(item->text, tokv[i])) @@ -314,9 +324,9 @@ insert(NULL, 0 - cursor); break; case XK_w: /* delete word */ - while (cursor > 0 && text[nextrune(-1)] == ' ') + while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)])) insert(NULL, nextrune(-1) - cursor); - while (cursor > 0 && text[nextrune(-1)] != ' ') + while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)])) insert(NULL, nextrune(-1) - cursor); break; case XK_y: /* paste selection */ @@ -467,8 +477,9 @@ static void readstdin(void) { - char buf[sizeof text], *p, *maxstr = NULL; - size_t i, max = 0, size = 0; + char buf[sizeof text], *p; + size_t i, imax = 0, size = 0; + unsigned int tmpmax = 0; /* read each line from stdin and add it to the item list */ for (i = 0; fgets(buf, sizeof buf, stdin); i++) { @@ -480,12 +491,15 @@ if (!(items[i].text = strdup(buf))) die("cannot strdup %u bytes:", strlen(buf) + 1); items[i].out = 0; - if (strlen(items[i].text) > max) - max = strlen(maxstr = items[i].text); + drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL); + if (tmpmax > inputw) { + inputw = tmpmax; + imax = i; + } } if (items) items[i].text = NULL; - inputw = maxstr ? TEXTW(maxstr) : 0; + inputw = items ? TEXTW(items[imax].text) : 0; lines = MIN(lines, i); } @@ -502,6 +516,11 @@ if (ev.xexpose.count == 0) drw_map(drw, win, 0, 0, mw, mh); break; + case FocusIn: + /* regrab focus from parent window */ + if (ev.xfocus.window != win) + grabfocus(); + break; case KeyPress: keypress(&ev.xkey); break; @@ -520,36 +539,34 @@ static void setup(void) { - int x, y; + int x, y, i = 0; + unsigned int du; XSetWindowAttributes swa; XIM xim; + Window w, dw, *dws; + XWindowAttributes wa; #ifdef XINERAMA XineramaScreenInfo *info; - Window w, pw, dw, *dws; - XWindowAttributes wa; - int a, j, di, n, i = 0, area = 0; - unsigned int du; + Window pw; + int a, j, di, n, area = 0; #endif /* init appearance */ - scheme[SchemeNorm].bg = drw_clr_create(drw, normbgcolor); - scheme[SchemeNorm].fg = drw_clr_create(drw, normfgcolor); - scheme[SchemeSel].bg = drw_clr_create(drw, selbgcolor); - scheme[SchemeSel].fg = drw_clr_create(drw, selfgcolor); - scheme[SchemeOut].bg = drw_clr_create(drw, outbgcolor); - scheme[SchemeOut].fg = drw_clr_create(drw, outfgcolor); + scheme[SchemeNorm] = drw_scm_create(drw, colors[SchemeNorm], 2); + scheme[SchemeSel] = drw_scm_create(drw, colors[SchemeSel], 2); + scheme[SchemeOut] = drw_scm_create(drw, colors[SchemeOut], 2); clip = XInternAtom(dpy, "CLIPBOARD", False); utf8 = XInternAtom(dpy, "UTF8_STRING", False); /* calculate menu geometry */ - bh = drw->fonts[0]->h + 2; + bh = drw->fonts->h + 2; lines = MAX(lines, 0); mh = (lines + 1) * bh; #ifdef XINERAMA - if ((info = XineramaQueryScreens(dpy, &n))) { + if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) { XGetInputFocus(dpy, &w, &di); - if (mon != -1 && mon < n) + if (mon >= 0 && mon < n) i = mon; else if (w != root && w != PointerRoot && w != None) { /* find top-level window containing current input focus */ @@ -566,7 +583,7 @@ } } /* no focused window is on screen, so use pointer location instead */ - if (mon == -1 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du)) + if (mon < 0 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du)) for (i = 0; i < n; i++) if (INTERSECT(x, y, 1, 1, info[i])) break; @@ -578,21 +595,23 @@ } else #endif { + if (!XGetWindowAttributes(dpy, parentwin, &wa)) + die("could not get embedding window attributes: 0x%lx", + parentwin); x = 0; - y = topbar ? 0 : sh - mh; - mw = sw; + y = topbar ? 0 : wa.height - mh; + mw = wa.width; } - promptw = (prompt && *prompt) ? TEXTW(prompt) : 0; + promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; inputw = MIN(inputw, mw/3); match(); /* create menu window */ swa.override_redirect = True; - swa.background_pixel = scheme[SchemeNorm].bg->pix; + swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; - win = XCreateWindow(dpy, root, x, y, mw, mh, 0, - DefaultDepth(dpy, screen), CopyFromParent, - DefaultVisual(dpy, screen), + win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0, + CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); /* open input methods */ @@ -601,6 +620,15 @@ XNClientWindow, win, XNFocusWindow, win, NULL); XMapRaised(dpy, win); + if (embed) { + XSelectInput(dpy, parentwin, FocusChangeMask); + if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) { + for (i = 0; i < du && dws[i] != win; ++i) + XSelectInput(dpy, dws[i], FocusChangeMask); + XFree(dws); + } + grabfocus(); + } drw_resize(drw, mw, mh); drawmenu(); } @@ -608,14 +636,15 @@ static void usage(void) { - fputs("usage: dmenu [-b] [-f] [-i] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" - " [-nb color] [-nf color] [-sb color] [-sf color] [-v]\n", stderr); + fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" + " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); exit(1); } int main(int argc, char *argv[]) { + XWindowAttributes wa; int i, fast = 0; for (i = 1; i < argc; i++) @@ -642,29 +671,33 @@ else if (!strcmp(argv[i], "-fn")) /* font or font set */ fonts[0] = argv[++i]; else if (!strcmp(argv[i], "-nb")) /* normal background color */ - normbgcolor = argv[++i]; + colors[SchemeNorm][ColBg] = argv[++i]; else if (!strcmp(argv[i], "-nf")) /* normal foreground color */ - normfgcolor = argv[++i]; + colors[SchemeNorm][ColFg] = argv[++i]; else if (!strcmp(argv[i], "-sb")) /* selected background color */ - selbgcolor = argv[++i]; + colors[SchemeSel][ColBg] = argv[++i]; else if (!strcmp(argv[i], "-sf")) /* selected foreground color */ - selfgcolor = argv[++i]; + colors[SchemeSel][ColFg] = argv[++i]; + else if (!strcmp(argv[i], "-w")) /* embedding window id */ + embed = argv[++i]; else usage(); if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) fputs("warning: no locale support\n", stderr); if (!(dpy = XOpenDisplay(NULL))) - die("cannot open display\n"); + die("cannot open display"); screen = DefaultScreen(dpy); root = RootWindow(dpy, screen); - sw = DisplayWidth(dpy, screen); - sh = DisplayHeight(dpy, screen); - drw = drw_create(dpy, screen, root, sw, sh); - drw_load_fonts(drw, fonts, LENGTH(fonts)); - if (!drw->fontcount) - die("no fonts could be loaded.\n"); - drw_setscheme(drw, &scheme[SchemeNorm]); + if (!embed || !(parentwin = strtol(embed, NULL, 0))) + parentwin = root; + if (!XGetWindowAttributes(dpy, parentwin, &wa)) + die("could not get embedding window attributes: 0x%lx", + parentwin); + drw = drw_create(dpy, screen, root, wa.width, wa.height); + if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) + die("no fonts could be loaded."); + lrpad = drw->fonts->h; if (fast) { grabkeyboard(); diff -Nru suckless-tools-42/dmenu/drw.c suckless-tools-43/dmenu/drw.c --- suckless-tools-42/dmenu/drw.c 2015-11-08 22:42:21.000000000 +0000 +++ suckless-tools-43/dmenu/drw.c 2017-05-02 16:36:47.000000000 +0000 @@ -63,9 +63,8 @@ Drw * drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h) { - Drw *drw; + Drw *drw = ecalloc(1, sizeof(Drw)); - drw = ecalloc(1, sizeof(Drw)); drw->dpy = dpy; drw->screen = screen; drw->root = root; @@ -73,7 +72,6 @@ drw->h = h; drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); drw->gc = XCreateGC(dpy, root, 0, NULL); - drw->fontcount = 0; XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); return drw; @@ -82,6 +80,9 @@ void drw_resize(Drw *drw, unsigned int w, unsigned int h) { + if (!drw) + return; + drw->w = w; drw->h = h; if (drw->drawable) @@ -92,142 +93,157 @@ void drw_free(Drw *drw) { - size_t i; - - for (i = 0; i < drw->fontcount; i++) - drw_font_free(drw->fonts[i]); XFreePixmap(drw->dpy, drw->drawable); XFreeGC(drw->dpy, drw->gc); free(drw); } /* This function is an implementation detail. Library users should use - * drw_font_create instead. + * drw_fontset_create instead. */ static Fnt * -drw_font_xcreate(Drw *drw, const char *fontname, FcPattern *fontpattern) +xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern) { Fnt *font; XftFont *xfont = NULL; FcPattern *pattern = NULL; if (fontname) { - /* Using the pattern found at font->xfont->pattern does not yield same - * the same substitution results as using the pattern returned by + /* Using the pattern found at font->xfont->pattern does not yield the + * same substitution results as using the pattern returned by * FcNameParse; using the latter results in the desired fallback - * behaviour whereas the former just results in - * missing-character-rectangles being drawn, at least with some fonts. - */ + * behaviour whereas the former just results in missing-character + * rectangles being drawn, at least with some fonts. */ if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) { - fprintf(stderr, "error, cannot load font: '%s'\n", fontname); + fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname); return NULL; } if (!(pattern = FcNameParse((FcChar8 *) fontname))) { - fprintf(stderr, "error, cannot load font: '%s'\n", fontname); + fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname); XftFontClose(drw->dpy, xfont); return NULL; } } else if (fontpattern) { if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) { - fprintf(stderr, "error, cannot load font pattern.\n"); + fprintf(stderr, "error, cannot load font from pattern.\n"); return NULL; } } else { - die("no font specified.\n"); + die("no font specified."); } font = ecalloc(1, sizeof(Fnt)); font->xfont = xfont; font->pattern = pattern; - font->ascent = xfont->ascent; - font->descent = xfont->descent; - font->h = font->ascent + font->descent; + font->h = xfont->ascent + xfont->descent; font->dpy = drw->dpy; return font; } -Fnt* -drw_font_create(Drw *drw, const char *fontname) +static void +xfont_free(Fnt *font) { - return drw_font_xcreate(drw, fontname, NULL); + if (!font) + return; + if (font->pattern) + FcPatternDestroy(font->pattern); + XftFontClose(font->dpy, font->xfont); + free(font); } -void -drw_load_fonts(Drw* drw, const char *fonts[], size_t fontcount) +Fnt* +drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount) { + Fnt *cur, *ret = NULL; size_t i; - Fnt *font; - for (i = 0; i < fontcount; i++) { - if (drw->fontcount >= DRW_FONT_CACHE_SIZE) { - die("Font cache exhausted.\n"); - } else if ((font = drw_font_xcreate(drw, fonts[i], NULL))) { - drw->fonts[drw->fontcount++] = font; + if (!drw || !fonts) + return NULL; + + for (i = 1; i <= fontcount; i++) { + if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) { + cur->next = ret; + ret = cur; } } + return (drw->fonts = ret); } void -drw_font_free(Fnt *font) +drw_fontset_free(Fnt *font) { - if (!font) - return; - if (font->pattern) - FcPatternDestroy(font->pattern); - XftFontClose(font->dpy, font->xfont); - free(font); + if (font) { + drw_fontset_free(font->next); + xfont_free(font); + } } -Clr * -drw_clr_create(Drw *drw, const char *clrname) +void +drw_clr_create(Drw *drw, Clr *dest, const char *clrname) { - Clr *clr; + if (!drw || !dest || !clrname) + return; - clr = ecalloc(1, sizeof(Clr)); if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen), DefaultColormap(drw->dpy, drw->screen), - clrname, &clr->rgb)) - die("error, cannot allocate color '%s'\n", clrname); - clr->pix = clr->rgb.pixel; + clrname, dest)) + die("error, cannot allocate color '%s'", clrname); +} + +/* Wrapper to create color schemes. The caller has to call free(3) on the + * returned color scheme when done using it. */ +Clr * +drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) +{ + size_t i; + Clr *ret; - return clr; + /* need at least two colors for a scheme */ + if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor)))) + return NULL; + + for (i = 0; i < clrcount; i++) + drw_clr_create(drw, &ret[i], clrnames[i]); + return ret; } void -drw_clr_free(Clr *clr) +drw_setfontset(Drw *drw, Fnt *set) { - free(clr); + if (drw) + drw->fonts = set; } void -drw_setscheme(Drw *drw, ClrScheme *scheme) +drw_setscheme(Drw *drw, Clr *scm) { - drw->scheme = scheme; + if (drw) + drw->scheme = scm; } void -drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty, int invert) +drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert) { - if (!drw->scheme) + if (!drw || !drw->scheme) return; - XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->bg->pix : drw->scheme->fg->pix); + XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel); if (filled) - XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w + 1, h + 1); - else if (empty) - XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); + else + XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1); } int -drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int invert) +drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert) { char buf[1024]; - int tx, ty, th; - Extnts tex; + int ty; + unsigned int ew; XftDraw *d = NULL; - Fnt *curfont, *nextfont; + Fnt *usedfont, *curfont, *nextfont; size_t i, len; - int utf8strlen, utf8charlen, render; + int utf8strlen, utf8charlen, render = x || y || w || h; long utf8codepoint = 0; const char *utf8str; FcCharSet *fccharset; @@ -236,66 +252,67 @@ XftResult result; int charexists = 0; - if (!drw->scheme || !drw->fontcount) + if (!drw || (render && !drw->scheme) || !text || !drw->fonts) return 0; - if (!(render = x || y || w || h)) { + if (!render) { w = ~w; } else { - XSetForeground(drw->dpy, drw->gc, invert ? - drw->scheme->fg->pix : drw->scheme->bg->pix); + XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel); XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); d = XftDrawCreate(drw->dpy, drw->drawable, DefaultVisual(drw->dpy, drw->screen), DefaultColormap(drw->dpy, drw->screen)); + x += lpad; + w -= lpad; } - curfont = drw->fonts[0]; + usedfont = drw->fonts; while (1) { utf8strlen = 0; utf8str = text; nextfont = NULL; while (*text) { utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); - for (i = 0; i < drw->fontcount; i++) { - charexists = charexists || XftCharExists(drw->dpy, drw->fonts[i]->xfont, utf8codepoint); + for (curfont = drw->fonts; curfont; curfont = curfont->next) { + charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); if (charexists) { - if (drw->fonts[i] == curfont) { + if (curfont == usedfont) { utf8strlen += utf8charlen; text += utf8charlen; } else { - nextfont = drw->fonts[i]; + nextfont = curfont; } break; } } - if (!charexists || (nextfont && nextfont != curfont)) + if (!charexists || nextfont) break; else charexists = 0; } if (utf8strlen) { - drw_font_getexts(curfont, utf8str, utf8strlen, &tex); + drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL); /* shorten text if necessary */ - for (len = MIN(utf8strlen, (sizeof buf) - 1); len && (tex.w > w - drw->fonts[0]->h || w < drw->fonts[0]->h); len--) - drw_font_getexts(curfont, utf8str, len, &tex); + for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--) + drw_font_getexts(usedfont, utf8str, len, &ew, NULL); if (len) { memcpy(buf, utf8str, len); buf[len] = '\0'; if (len < utf8strlen) - for (i = len; i && i > len - 3; buf[--i] = '.'); + for (i = len; i && i > len - 3; buf[--i] = '.') + ; /* NOP */ if (render) { - th = curfont->ascent + curfont->descent; - ty = y + (h / 2) - (th / 2) + curfont->ascent; - tx = x + (h / 2); - XftDrawStringUtf8(d, invert ? &drw->scheme->bg->rgb : &drw->scheme->fg->rgb, curfont->xfont, tx, ty, (XftChar8 *)buf, len); + ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; + XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], + usedfont->xfont, x, ty, (XftChar8 *)buf, len); } - x += tex.w; - w -= tex.w; + x += ew; + w -= ew; } } @@ -303,26 +320,21 @@ break; } else if (nextfont) { charexists = 0; - curfont = nextfont; + usedfont = nextfont; } else { /* Regardless of whether or not a fallback font is found, the - * character must be drawn. - */ + * character must be drawn. */ charexists = 1; - if (drw->fontcount >= DRW_FONT_CACHE_SIZE) - continue; - fccharset = FcCharSetCreate(); FcCharSetAddChar(fccharset, utf8codepoint); - if (!drw->fonts[0]->pattern) { - /* Refer to the comment in drw_font_xcreate for more - * information. */ - die("the first font in the cache must be loaded from a font string.\n"); + if (!drw->fonts->pattern) { + /* Refer to the comment in xfont_create for more information. */ + die("the first font in the cache must be loaded from a font string."); } - fcpattern = FcPatternDuplicate(drw->fonts[0]->pattern); + fcpattern = FcPatternDuplicate(drw->fonts->pattern); FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); @@ -334,12 +346,14 @@ FcPatternDestroy(fcpattern); if (match) { - curfont = drw_font_xcreate(drw, NULL, match); - if (curfont && XftCharExists(drw->dpy, curfont->xfont, utf8codepoint)) { - drw->fonts[drw->fontcount++] = curfont; + usedfont = xfont_create(drw, NULL, match); + if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) { + for (curfont = drw->fonts; curfont->next; curfont = curfont->next) + ; /* NOP */ + curfont->next = usedfont; } else { - drw_font_free(curfont); - curfont = drw->fonts[0]; + xfont_free(usedfont); + usedfont = drw->fonts; } } } @@ -347,34 +361,40 @@ if (d) XftDrawDestroy(d); - return x; + return x + (render ? w : 0); } void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) { + if (!drw) + return; + XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y); XSync(drw->dpy, False); } -void -drw_font_getexts(Fnt *font, const char *text, unsigned int len, Extnts *tex) +unsigned int +drw_fontset_getwidth(Drw *drw, const char *text) { - XGlyphInfo ext; - - XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext); - tex->h = font->h; - tex->w = ext.xOff; + if (!drw || !drw->fonts || !text) + return 0; + return drw_text(drw, 0, 0, 0, 0, 0, text, 0); } -unsigned int -drw_font_getexts_width(Fnt *font, const char *text, unsigned int len) +void +drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h) { - Extnts tex; + XGlyphInfo ext; - drw_font_getexts(font, text, len, &tex); + if (!font || !text) + return; - return tex.w; + XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext); + if (w) + *w = ext.xOff; + if (h) + *h = font->h; } Cur * @@ -382,7 +402,9 @@ { Cur *cur; - cur = ecalloc(1, sizeof(Cur)); + if (!drw || !(cur = ecalloc(1, sizeof(Cur)))) + return NULL; + cur->cursor = XCreateFontCursor(drw->dpy, shape); return cur; @@ -393,6 +415,7 @@ { if (!cursor) return; + XFreeCursor(drw->dpy, cursor->cursor); free(cursor); } diff -Nru suckless-tools-42/dmenu/drw.h suckless-tools-43/dmenu/drw.h --- suckless-tools-42/dmenu/drw.h 2015-11-08 22:42:21.000000000 +0000 +++ suckless-tools-43/dmenu/drw.h 2017-05-02 16:36:47.000000000 +0000 @@ -1,29 +1,19 @@ /* See LICENSE file for copyright and license details. */ -#define DRW_FONT_CACHE_SIZE 32 - -typedef struct { - unsigned long pix; - XftColor rgb; -} Clr; typedef struct { Cursor cursor; } Cur; -typedef struct { +typedef struct Fnt { Display *dpy; - int ascent; - int descent; unsigned int h; XftFont *xfont; FcPattern *pattern; + struct Fnt *next; } Fnt; -typedef struct { - Clr *fg; - Clr *bg; - Clr *border; -} ClrScheme; +enum { ColFg, ColBg }; /* Clr scheme index */ +typedef XftColor Clr; typedef struct { unsigned int w, h; @@ -32,43 +22,36 @@ Window root; Drawable drawable; GC gc; - ClrScheme *scheme; - size_t fontcount; - Fnt *fonts[DRW_FONT_CACHE_SIZE]; + Clr *scheme; + Fnt *fonts; } Drw; -typedef struct { - unsigned int w; - unsigned int h; -} Extnts; - /* Drawable abstraction */ -Drw *drw_create(Display *, int, Window, unsigned int, unsigned int); -void drw_resize(Drw *, unsigned int, unsigned int); -void drw_free(Drw *); +Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h); +void drw_resize(Drw *drw, unsigned int w, unsigned int h); +void drw_free(Drw *drw); /* Fnt abstraction */ -Fnt *drw_font_create(Drw *, const char *); -void drw_load_fonts(Drw *, const char *[], size_t); -void drw_font_free(Fnt *); -void drw_font_getexts(Fnt *, const char *, unsigned int, Extnts *); -unsigned int drw_font_getexts_width(Fnt *, const char *, unsigned int); - -/* Colour abstraction */ -Clr *drw_clr_create(Drw *, const char *); -void drw_clr_free(Clr *); +Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount); +void drw_fontset_free(Fnt* set); +unsigned int drw_fontset_getwidth(Drw *drw, const char *text); +void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h); + +/* Colorscheme abstraction */ +void drw_clr_create(Drw *drw, Clr *dest, const char *clrname); +Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount); /* Cursor abstraction */ -Cur *drw_cur_create(Drw *, int); -void drw_cur_free(Drw *, Cur *); +Cur *drw_cur_create(Drw *drw, int shape); +void drw_cur_free(Drw *drw, Cur *cursor); /* Drawing context manipulation */ -void drw_setfont(Drw *, Fnt *); -void drw_setscheme(Drw *, ClrScheme *); +void drw_setfontset(Drw *drw, Fnt *set); +void drw_setscheme(Drw *drw, Clr *scm); /* Drawing functions */ -void drw_rect(Drw *, int, int, unsigned int, unsigned int, int, int, int); -int drw_text(Drw *, int, int, unsigned int, unsigned int, const char *, int); +void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert); +int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert); /* Map functions */ -void drw_map(Drw *, Window, int, int, unsigned int, unsigned int); +void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); diff -Nru suckless-tools-42/dmenu/util.c suckless-tools-43/dmenu/util.c --- suckless-tools-42/dmenu/util.c 2015-11-08 22:42:21.000000000 +0000 +++ suckless-tools-43/dmenu/util.c 2017-05-02 16:36:47.000000000 +0000 @@ -12,7 +12,7 @@ void *p; if (!(p = calloc(nmemb, size))) - perror(NULL); + die("calloc:"); return p; } @@ -27,6 +27,8 @@ if (fmt[0] && fmt[strlen(fmt)-1] == ':') { fputc(' ', stderr); perror(NULL); + } else { + fputc('\n', stderr); } exit(1); diff -Nru suckless-tools-42/dmenu/util.h suckless-tools-43/dmenu/util.h --- suckless-tools-42/dmenu/util.h 2015-11-08 22:42:21.000000000 +0000 +++ suckless-tools-43/dmenu/util.h 2017-05-02 16:36:47.000000000 +0000 @@ -4,5 +4,5 @@ #define MIN(A, B) ((A) < (B) ? (A) : (B)) #define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B)) -void die(const char *errstr, ...); -void *ecalloc(size_t, size_t); +void die(const char *fmt, ...); +void *ecalloc(size_t nmemb, size_t size); diff -Nru suckless-tools-42/lsx/config.mk suckless-tools-43/lsx/config.mk --- suckless-tools-42/lsx/config.mk 2006-10-13 09:19:25.000000000 +0000 +++ suckless-tools-43/lsx/config.mk 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -# lsx version -VERSION = 0.1 - -# Customize below to fit your system - -# paths -PREFIX = /usr/local -MANPREFIX = ${PREFIX}/share/man - -# includes and libs -INCS = -I/usr/lib -LIBS = -L/usr/lib -lc - -# flags -CFLAGS = -Os ${INCS} -DVERSION=\"${VERSION}\" -LDFLAGS = ${LIBS} -#CFLAGS = -g -Wall -O2 ${INCS} -DVERSION=\"${VERSION}\" -#LDFLAGS = -g ${LIBS} - -# compiler -CC = cc diff -Nru suckless-tools-42/lsx/LICENSE suckless-tools-43/lsx/LICENSE --- suckless-tools-42/lsx/LICENSE 2006-10-13 09:19:25.000000000 +0000 +++ suckless-tools-43/lsx/LICENSE 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -MIT/X Consortium License - -(C)opyright MMVI Anselm R. Garbe -(C)opyright MMVI Sander van Dijk - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff -Nru suckless-tools-42/lsx/lsx.c suckless-tools-43/lsx/lsx.c --- suckless-tools-42/lsx/lsx.c 2006-10-13 09:19:25.000000000 +0000 +++ suckless-tools-43/lsx/lsx.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -/* (C)opyright MMVI Anselm R. Garbe - * See LICENSE file for license details. - */ -#include -#include -#include -#include -#include -#include - -int -main(int argc, char *argv[]) { - int i; - struct dirent *dp; - struct stat s; - DIR *dir; - - if((argc > 1) && !strncmp(argv[1], "-v", 3)) { - fputs("lsx-"VERSION", (C)opyright MMVI Anselm R. Garbe\n", stdout); - exit(EXIT_SUCCESS); - } - for(i = 0; i < argc; i++) - if((dir = opendir(argv[i]))) { - fchdir(dirfd(dir)); - do - if((dp = readdir(dir)) - && (stat(dp->d_name, &s) != -1) - && S_ISREG (s.st_mode) - && !access(dp->d_name, X_OK)) - puts(dp->d_name); - while(dp); - closedir(dir); - } - return 0; -} diff -Nru suckless-tools-42/lsx/Makefile suckless-tools-43/lsx/Makefile --- suckless-tools-42/lsx/Makefile 2006-10-13 09:19:25.000000000 +0000 +++ suckless-tools-43/lsx/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -# lsx - list executables -# (C)opyright MMVI Anselm R. Garbe - -include config.mk - -SRC = lsx.c -OBJ = ${SRC:.c=.o} - -all: options lsx - @echo finished - -options: - @echo lsx build options: - @echo "CFLAGS = ${CFLAGS}" - @echo "LDFLAGS = ${LDFLAGS}" - @echo "CC = ${CC}" - -.c.o: - @echo CC $< - @${CC} -c ${CFLAGS} $< - -lsx: ${OBJ} - @echo LD $@ - @${CC} -o $@ ${OBJ} ${LDFLAGS} - @strip $@ - -clean: - @echo cleaning - @rm -f lsx ${OBJ} lsx-${VERSION}.tar.gz - -dist: clean - @echo creating dist tarball - @mkdir -p lsx-${VERSION} - @cp -R LICENSE Makefile README config.mk ${SRC} lsx-${VERSION} - @tar -cf lsx-${VERSION}.tar lsx-${VERSION} - @gzip lsx-${VERSION}.tar - @rm -rf lsx-${VERSION} - -install: all - @echo installing executable file to ${DESTDIR}${PREFIX}/bin - @mkdir -p ${DESTDIR}${PREFIX}/bin - @cp -f lsx ${DESTDIR}${PREFIX}/bin - @chmod 755 ${DESTDIR}${PREFIX}/bin/lsx - -uninstall: - @echo removing executable file from ${DESTDIR}${PREFIX}/bin - @rm -f ${DESTDIR}${PREFIX}/bin/lsx - -.PHONY: all options clean dist install uninstall diff -Nru suckless-tools-42/lsx/README suckless-tools-43/lsx/README --- suckless-tools-42/lsx/README 2006-10-13 09:19:25.000000000 +0000 +++ suckless-tools-43/lsx/README 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -lsx - list executables -====================== -Prints all executable file names of given absolute paths to standard output. - - -Installation ------------- -Edit config.mk to match your local setup (lsx is installed into -the /usr/local namespace by default). - -Afterwards enter the following command to build and install lsx (if -necessary as root): - - make clean install - - -Running lsx ------------ -Simply invoke the 'lsx' with arbitrary paths as arguments. diff -Nru suckless-tools-42/slock/arg.h suckless-tools-43/slock/arg.h --- suckless-tools-42/slock/arg.h 1970-01-01 00:00:00.000000000 +0000 +++ suckless-tools-43/slock/arg.h 2016-11-20 00:31:23.000000000 +0000 @@ -0,0 +1,65 @@ +/* + * Copy me if you can. + * by 20h + */ + +#ifndef ARG_H__ +#define ARG_H__ + +extern char *argv0; + +/* use main(int argc, char *argv[]) */ +#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ + argv[0] && argv[0][0] == '-'\ + && argv[0][1];\ + argc--, argv++) {\ + char argc_;\ + char **argv_;\ + int brk_;\ + if (argv[0][1] == '-' && argv[0][2] == '\0') {\ + argv++;\ + argc--;\ + break;\ + }\ + for (brk_ = 0, argv[0]++, argv_ = argv;\ + argv[0][0] && !brk_;\ + argv[0]++) {\ + if (argv_ != argv)\ + break;\ + argc_ = argv[0][0];\ + switch (argc_) + +/* Handles obsolete -NUM syntax */ +#define ARGNUM case '0':\ + case '1':\ + case '2':\ + case '3':\ + case '4':\ + case '5':\ + case '6':\ + case '7':\ + case '8':\ + case '9' + +#define ARGEND }\ + } + +#define ARGC() argc_ + +#define ARGNUMF() (brk_ = 1, estrtonum(argv[0], 0, INT_MAX)) + +#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\ + ((x), abort(), (char *)0) :\ + (brk_ = 1, (argv[0][1] != '\0')?\ + (&argv[0][1]) :\ + (argc--, argv++, argv[0]))) + +#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\ + (char *)0 :\ + (brk_ = 1, (argv[0][1] != '\0')?\ + (&argv[0][1]) :\ + (argc--, argv++, argv[0]))) + +#define LNGARG() &argv[0][0] + +#endif diff -Nru suckless-tools-42/slock/config.def.h suckless-tools-43/slock/config.def.h --- suckless-tools-42/slock/config.def.h 2016-02-12 19:29:02.000000000 +0000 +++ suckless-tools-43/slock/config.def.h 2016-11-20 00:31:23.000000000 +0000 @@ -1,6 +1,12 @@ +/* user and group to drop privileges to */ +static const char *user = "nobody"; +static const char *group = "nogroup"; + static const char *colorname[NUMCOLS] = { - "black", /* after initialization */ - "#005577", /* during input */ - "#CC3333", /* failed/cleared the input */ + [INIT] = "black", /* after initialization */ + [INPUT] = "#005577", /* during input */ + [FAILED] = "#CC3333", /* wrong password */ }; -static const Bool failonclear = True; + +/* treat a cleared input like a wrong password (color) */ +static const int failonclear = 1; diff -Nru suckless-tools-42/slock/config.mk suckless-tools-43/slock/config.mk --- suckless-tools-42/slock/config.mk 2016-02-12 19:29:02.000000000 +0000 +++ suckless-tools-43/slock/config.mk 2016-11-20 00:31:23.000000000 +0000 @@ -1,5 +1,5 @@ # slock version -VERSION = 1.3 +VERSION = 1.4 # Customize below to fit your system @@ -15,17 +15,18 @@ LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr # flags -CPPFLAGS = -DVERSION=\"${VERSION}\" -DHAVE_SHADOW_H +CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_SHADOW_H CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} LDFLAGS = -s ${LIBS} +COMPATSRC = explicit_bzero.c -# On *BSD remove -DHAVE_SHADOW_H from CPPFLAGS and add -DHAVE_BSD_AUTH # On OpenBSD and Darwin remove -lcrypt from LIBS +#LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lXext -lXrandr +# On *BSD remove -DHAVE_SHADOW_H from CPPFLAGS +# On NetBSD add -D_NETBSD_SOURCE to CPPFLAGS +#CPPFLAGS = -DVERSION=\"${VERSION}\" -D_BSD_SOURCE -D_NETBSD_SOURCE +# On OpenBSD set COMPATSRC to empty +#COMPATSRC = # compiler and linker CC = cc - -# Install mode. On BSD systems MODE=2755 and GROUP=auth -# On others MODE=4755 and GROUP=root -#MODE=2755 -#GROUP=auth diff -Nru suckless-tools-42/slock/explicit_bzero.c suckless-tools-43/slock/explicit_bzero.c --- suckless-tools-42/slock/explicit_bzero.c 1970-01-01 00:00:00.000000000 +0000 +++ suckless-tools-43/slock/explicit_bzero.c 2016-11-20 00:31:23.000000000 +0000 @@ -0,0 +1,19 @@ +/* $OpenBSD: explicit_bzero.c,v 1.3 2014/06/21 02:34:26 matthew Exp $ */ +/* + * Public domain. + * Written by Matthew Dempsky. + */ + +#include + +__attribute__((weak)) void +__explicit_bzero_hook(void *buf, size_t len) +{ +} + +void +explicit_bzero(void *buf, size_t len) +{ + memset(buf, 0, len); + __explicit_bzero_hook(buf, len); +} diff -Nru suckless-tools-42/slock/Makefile suckless-tools-43/slock/Makefile --- suckless-tools-42/slock/Makefile 2016-02-12 19:29:02.000000000 +0000 +++ suckless-tools-43/slock/Makefile 2016-11-20 00:31:23.000000000 +0000 @@ -3,7 +3,7 @@ include config.mk -SRC = slock.c +SRC = slock.c ${COMPATSRC} OBJ = ${SRC:.c=.o} all: options slock @@ -18,7 +18,7 @@ @echo CC $< @${CC} -c ${CFLAGS} $< -${OBJ}: config.h config.mk +${OBJ}: config.h config.mk arg.h util.h config.h: @echo creating $@ from config.def.h @@ -35,8 +35,8 @@ dist: clean @echo creating dist tarball @mkdir -p slock-${VERSION} - @cp -R LICENSE Makefile README config.def.h config.mk ${SRC} slock.1 \ - slock-${VERSION} + @cp -R LICENSE Makefile README slock.1 config.mk \ + ${SRC} explicit_bzero.c config.def.h arg.h util.h slock-${VERSION} @tar -cf slock-${VERSION}.tar slock-${VERSION} @gzip slock-${VERSION}.tar @rm -rf slock-${VERSION} diff -Nru suckless-tools-42/slock/slock.1 suckless-tools-43/slock/slock.1 --- suckless-tools-42/slock/slock.1 2016-02-12 19:29:02.000000000 +0000 +++ suckless-tools-43/slock/slock.1 2016-11-20 00:31:23.000000000 +0000 @@ -1,29 +1,39 @@ -.TH SLOCK 1 slock\-VERSION -.SH NAME -slock \- simple X display locker -.SH SYNOPSIS -.B slock -.RB [ \-v -| -.IR post_lock_command ] -.SH DESCRIPTION -.B slock -is a screen locker for X. If provided, the -.IR post_lock_command -will be executed when the screen is locked. -.SH OPTIONS -.TP -.B \-v -prints version information to stdout, then exits. -.SH EXAMPLES -$ slock /usr/sbin/s2ram -.SH CUSTOMIZATION -.B slock -can be customized by creating a custom config.h and (re)compiling the source -code. This keeps it fast, secure and simple. -.SH AUTHORS -See the LICENSE file for the authors. -.SH LICENSE -See the LICENSE file for the terms of redistribution. -.SH BUGS -Please report them. +.Dd 2016-08-23 +.Dt SLOCK 1 +.Sh NAME +.Nm slock +.Nd simple X screen locker +.Sh SYNOPSIS +.Nm +.Op Fl v +.Op Ar cmd Op Ar arg ... +.Sh DESCRIPTION +.Nm +is a simple X screen locker. If provided, +.Ar cmd Op Ar arg ... +is executed after the screen has been locked. +.Sh OPTIONS +.Bl -tag -width Ds +.It Fl v +Print version information to stdout and exit. +.El +.Sh SECURITY CONSIDERATIONS +To make sure a locked screen can not be bypassed by switching VTs +or killing the X server with Ctrl+Alt+Backspace, it is recommended +to disable both in +.Xr xorg.conf 5 +for maximum security: +.Bd -literal -offset left +Section "ServerFlags" + Option "DontVTSwitch" "True" + Option "DontZap" "True" +EndSection +.Ed +.Sh EXAMPLES +$ +.Nm +/usr/sbin/s2ram +.Sh CUSTOMIZATION +.Nm +can be customized by creating a custom config.h from config.def.h and +(re)compiling the source code. This keeps it fast, secure and simple. diff -Nru suckless-tools-42/slock/slock.c suckless-tools-43/slock/slock.c --- suckless-tools-42/slock/slock.c 2016-02-12 19:29:02.000000000 +0000 +++ suckless-tools-43/slock/slock.c 2016-11-20 00:31:23.000000000 +0000 @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -18,10 +19,10 @@ #include #include -#if HAVE_BSD_AUTH -#include -#include -#endif +#include "arg.h" +#include "util.h" + +char *argv0; enum { INIT, @@ -30,22 +31,20 @@ NUMCOLS }; -#include "config.h" - -typedef struct { +struct lock { int screen; Window root, win; Pixmap pmap; unsigned long colors[NUMCOLS]; -} Lock; +}; + +struct xrandr { + int active; + int evbase; + int errbase; +}; -static Lock **locks; -static int nscreens; -static Bool running = True; -static Bool failure = False; -static Bool rr; -static int rrevbase; -static int rrerrbase; +#include "config.h" static void die(const char *errstr, ...) @@ -65,34 +64,32 @@ static void dontkillme(void) { - int fd; - int length; - char value[64]; - - fd = open("/proc/self/oom_score_adj", O_WRONLY); - if (fd < 0 && errno == ENOENT) - return; - - /* convert OOM_SCORE_ADJ_MIN to string for writing */ - length = snprintf(value, sizeof(value), "%d\n", OOM_SCORE_ADJ_MIN); - - /* bail on truncation */ - if (length >= sizeof(value)) - die("buffer too small\n"); + FILE *f; + const char oomfile[] = "/proc/self/oom_score_adj"; - if (fd < 0 || write(fd, value, length) != length || close(fd) != 0) - die("cannot disable the out-of-memory killer for this process (make sure to suid or sgid slock)\n"); + if (!(f = fopen(oomfile, "w"))) { + if (errno == ENOENT) + return; + die("slock: fopen %s: %s\n", oomfile, strerror(errno)); + } + fprintf(f, "%d", OOM_SCORE_ADJ_MIN); + if (fclose(f)) { + if (errno == EACCES) + die("slock: unable to disable OOM killer. " + "Make sure to suid or sgid slock.\n"); + else + die("slock: fclose %s: %s\n", oomfile, strerror(errno)); + } } #endif -#ifndef HAVE_BSD_AUTH -/* only run as root */ static const char * -getpw(void) +gethash(void) { - const char *rval; + const char *hash; struct passwd *pw; + /* Check if the current user has a password entry */ errno = 0; if (!(pw = getpwuid(getuid()))) { if (errno) @@ -100,49 +97,52 @@ else die("slock: cannot retrieve password entry\n"); } - rval = pw->pw_passwd; + hash = pw->pw_passwd; #if HAVE_SHADOW_H - if (rval[0] == 'x' && rval[1] == '\0') { + if (!strcmp(hash, "x")) { struct spwd *sp; - if (!(sp = getspnam(getenv("USER")))) - die("slock: cannot retrieve shadow entry (make sure to suid or sgid slock)\n"); - rval = sp->sp_pwdp; + if (!(sp = getspnam(pw->pw_name))) + die("slock: getspnam: cannot retrieve shadow entry. " + "Make sure to suid or sgid slock.\n"); + hash = sp->sp_pwdp; } -#endif +#else + if (!strcmp(hash, "*")) { +#ifdef __OpenBSD__ + if (!(pw = getpwuid_shadow(getuid()))) + die("slock: getpwnam_shadow: cannot retrieve shadow entry. " + "Make sure to suid or sgid slock.\n"); + hash = pw->pw_passwd; +#else + die("slock: getpwuid: cannot retrieve shadow entry. " + "Make sure to suid or sgid slock.\n"); +#endif /* __OpenBSD__ */ + } +#endif /* HAVE_SHADOW_H */ - /* drop privileges */ - if (geteuid() == 0 && - ((getegid() != pw->pw_gid && setgid(pw->pw_gid) < 0) || setuid(pw->pw_uid) < 0)) - die("slock: cannot drop privileges\n"); - return rval; + return hash; } -#endif static void -#ifdef HAVE_BSD_AUTH -readpw(Display *dpy) -#else -readpw(Display *dpy, const char *pws) -#endif +readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens, + const char *hash) { - char buf[32], passwd[256]; - int num, screen; + XRRScreenChangeNotifyEvent *rre; + char buf[32], passwd[256], *inputhash; + int num, screen, running, failure, oldc; unsigned int len, color; KeySym ksym; XEvent ev; - static int oldc = INIT; len = 0; - running = True; + running = 1; + failure = 0; + oldc = INIT; - /* As "slock" stands for "Simple X display locker", the DPMS settings - * had been removed and you can set it with "xset" or some other - * utility. This way the user can easily set a customized DPMS - * timeout. */ while (running && !XNextEvent(dpy, &ev)) { if (ev.type == KeyPress) { - buf[0] = 0; + explicit_bzero(&buf, sizeof(buf)); num = XLookupString(&ev.xkey, buf, sizeof(buf), &ksym, 0); if (IsKeypadKey(ksym)) { if (ksym == XK_KP_Enter) @@ -158,45 +158,51 @@ continue; switch (ksym) { case XK_Return: - passwd[len] = 0; -#ifdef HAVE_BSD_AUTH - running = !auth_userokay(getlogin(), NULL, "auth-xlock", passwd); -#else - running = !!strcmp(crypt(passwd, pws), pws); -#endif + passwd[len] = '\0'; + errno = 0; + if (!(inputhash = crypt(passwd, hash))) + fprintf(stderr, "slock: crypt: %s\n", strerror(errno)); + else + running = !!strcmp(inputhash, hash); if (running) { XBell(dpy, 100); - failure = True; + failure = 1; } + explicit_bzero(&passwd, sizeof(passwd)); len = 0; break; case XK_Escape: + explicit_bzero(&passwd, sizeof(passwd)); len = 0; break; case XK_BackSpace: if (len) - --len; + passwd[len--] = '\0'; break; default: - if (num && !iscntrl((int)buf[0]) && (len + num < sizeof(passwd))) { + if (num && !iscntrl((int)buf[0]) && + (len + num < sizeof(passwd))) { memcpy(passwd + len, buf, num); len += num; } break; } - color = len ? INPUT : (failure || failonclear ? FAILED : INIT); + color = len ? INPUT : ((failure || failonclear) ? FAILED : INIT); if (running && oldc != color) { for (screen = 0; screen < nscreens; screen++) { - XSetWindowBackground(dpy, locks[screen]->win, locks[screen]->colors[color]); + XSetWindowBackground(dpy, + locks[screen]->win, + locks[screen]->colors[color]); XClearWindow(dpy, locks[screen]->win); } oldc = color; } - } else if (rr && ev.type == rrevbase + RRScreenChangeNotify) { - XRRScreenChangeNotifyEvent *rre = (XRRScreenChangeNotifyEvent*)&ev; + } else if (rr->active && ev.type == rr->evbase + RRScreenChangeNotify) { + rre = (XRRScreenChangeNotifyEvent*)&ev; for (screen = 0; screen < nscreens; screen++) { if (locks[screen]->win == rre->window) { - XResizeWindow(dpy, locks[screen]->win, rre->width, rre->height); + XResizeWindow(dpy, locks[screen]->win, + rre->width, rre->height); XClearWindow(dpy, locks[screen]->win); } } @@ -205,154 +211,177 @@ } } -static void -unlockscreen(Display *dpy, Lock *lock) -{ - if(dpy == NULL || lock == NULL) - return; - - XUngrabPointer(dpy, CurrentTime); - XFreeColors(dpy, DefaultColormap(dpy, lock->screen), lock->colors, NUMCOLS, 0); - XFreePixmap(dpy, lock->pmap); - XDestroyWindow(dpy, lock->win); - - free(lock); -} - -static Lock * -lockscreen(Display *dpy, int screen) +static struct lock * +lockscreen(Display *dpy, struct xrandr *rr, int screen) { char curs[] = {0, 0, 0, 0, 0, 0, 0, 0}; - unsigned int len; - int i; - Lock *lock; + int i, ptgrab, kbgrab; + struct lock *lock; XColor color, dummy; XSetWindowAttributes wa; Cursor invisible; - if (!running || dpy == NULL || screen < 0 || !(lock = malloc(sizeof(Lock)))) + if (dpy == NULL || screen < 0 || !(lock = malloc(sizeof(struct lock)))) return NULL; lock->screen = screen; lock->root = RootWindow(dpy, lock->screen); for (i = 0; i < NUMCOLS; i++) { - XAllocNamedColor(dpy, DefaultColormap(dpy, lock->screen), colorname[i], &color, &dummy); + XAllocNamedColor(dpy, DefaultColormap(dpy, lock->screen), + colorname[i], &color, &dummy); lock->colors[i] = color.pixel; } /* init */ wa.override_redirect = 1; wa.background_pixel = lock->colors[INIT]; - lock->win = XCreateWindow(dpy, lock->root, 0, 0, DisplayWidth(dpy, lock->screen), DisplayHeight(dpy, lock->screen), - 0, DefaultDepth(dpy, lock->screen), CopyFromParent, - DefaultVisual(dpy, lock->screen), CWOverrideRedirect | CWBackPixel, &wa); + lock->win = XCreateWindow(dpy, lock->root, 0, 0, + DisplayWidth(dpy, lock->screen), + DisplayHeight(dpy, lock->screen), + 0, DefaultDepth(dpy, lock->screen), + CopyFromParent, + DefaultVisual(dpy, lock->screen), + CWOverrideRedirect | CWBackPixel, &wa); lock->pmap = XCreateBitmapFromData(dpy, lock->win, curs, 8, 8); - invisible = XCreatePixmapCursor(dpy, lock->pmap, lock->pmap, &color, &color, 0, 0); + invisible = XCreatePixmapCursor(dpy, lock->pmap, lock->pmap, + &color, &color, 0, 0); XDefineCursor(dpy, lock->win, invisible); - XMapRaised(dpy, lock->win); - if (rr) - XRRSelectInput(dpy, lock->win, RRScreenChangeNotifyMask); - - /* Try to grab mouse pointer *and* keyboard, else fail the lock */ - for (len = 1000; len; len--) { - if (XGrabPointer(dpy, lock->root, False, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, - GrabModeAsync, GrabModeAsync, None, invisible, CurrentTime) == GrabSuccess) - break; - usleep(1000); - } - if (!len) { - fprintf(stderr, "slock: unable to grab mouse pointer for screen %d\n", screen); - } else { - for (len = 1000; len; len--) { - if (XGrabKeyboard(dpy, lock->root, True, GrabModeAsync, GrabModeAsync, CurrentTime) == GrabSuccess) { - /* everything fine, we grabbed both inputs */ - XSelectInput(dpy, lock->root, SubstructureNotifyMask); - return lock; - } - usleep(1000); + + /* Try to grab mouse pointer *and* keyboard for 600ms, else fail the lock */ + for (i = 0, ptgrab = kbgrab = -1; i < 6; i++) { + if (ptgrab != GrabSuccess) { + ptgrab = XGrabPointer(dpy, lock->root, False, + ButtonPressMask | ButtonReleaseMask | + PointerMotionMask, GrabModeAsync, + GrabModeAsync, None, invisible, CurrentTime); } - fprintf(stderr, "slock: unable to grab keyboard for screen %d\n", screen); + if (kbgrab != GrabSuccess) { + kbgrab = XGrabKeyboard(dpy, lock->root, True, + GrabModeAsync, GrabModeAsync, CurrentTime); + } + + /* input is grabbed: we can lock the screen */ + if (ptgrab == GrabSuccess && kbgrab == GrabSuccess) { + XMapRaised(dpy, lock->win); + if (rr->active) + XRRSelectInput(dpy, lock->win, RRScreenChangeNotifyMask); + + XSelectInput(dpy, lock->root, SubstructureNotifyMask); + return lock; + } + + /* retry on AlreadyGrabbed but fail on other errors */ + if ((ptgrab != AlreadyGrabbed && ptgrab != GrabSuccess) || + (kbgrab != AlreadyGrabbed && kbgrab != GrabSuccess)) + break; + + usleep(100000); } - /* grabbing one of the inputs failed */ - running = 0; - unlockscreen(dpy, lock); + + /* we couldn't grab all input: fail out */ + if (ptgrab != GrabSuccess) + fprintf(stderr, "slock: unable to grab mouse pointer for screen %d\n", + screen); + if (kbgrab != GrabSuccess) + fprintf(stderr, "slock: unable to grab keyboard for screen %d\n", + screen); return NULL; } static void usage(void) { - fprintf(stderr, "usage: slock [-v|POST_LOCK_CMD]\n"); - exit(1); + die("usage: slock [-v] [cmd [arg ...]]\n"); } int main(int argc, char **argv) { -#ifndef HAVE_BSD_AUTH - const char *pws; -#endif + struct xrandr rr; + struct lock **locks; + struct passwd *pwd; + struct group *grp; + uid_t duid; + gid_t dgid; + const char *hash; Display *dpy; - int screen; - - if ((argc == 2) && !strcmp("-v", argv[1])) - die("slock-%s, © 2006-2016 slock engineers\n", VERSION); + int s, nlocks, nscreens; - if ((argc == 2) && !strcmp("-h", argv[1])) + ARGBEGIN { + case 'v': + fprintf(stderr, "slock-"VERSION"\n"); + return 0; + default: usage(); + } ARGEND + + /* validate drop-user and -group */ + errno = 0; + if (!(pwd = getpwnam(user))) + die("slock: getpwnam %s: %s\n", user, + errno ? strerror(errno) : "user entry not found"); + duid = pwd->pw_uid; + errno = 0; + if (!(grp = getgrnam(group))) + die("slock: getgrnam %s: %s\n", group, + errno ? strerror(errno) : "group entry not found"); + dgid = grp->gr_gid; #ifdef __linux__ dontkillme(); #endif - if (!getpwuid(getuid())) - die("slock: no passwd entry for you\n"); - -#ifndef HAVE_BSD_AUTH - pws = getpw(); -#endif + hash = gethash(); + errno = 0; + if (!crypt("", hash)) + die("slock: crypt: %s\n", strerror(errno)); - if (!(dpy = XOpenDisplay(0))) + if (!(dpy = XOpenDisplay(NULL))) die("slock: cannot open display\n"); - rr = XRRQueryExtension(dpy, &rrevbase, &rrerrbase); - /* Get the number of screens in display "dpy" and blank them all. */ + + /* drop privileges */ + if (setgroups(0, NULL) < 0) + die("slock: setgroups: %s\n", strerror(errno)); + if (setgid(dgid) < 0) + die("slock: setgid: %s\n", strerror(errno)); + if (setuid(duid) < 0) + die("slock: setuid: %s\n", strerror(errno)); + + /* check for Xrandr support */ + rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase); + + /* get number of screens in display "dpy" and blank them */ nscreens = ScreenCount(dpy); - if (!(locks = malloc(sizeof(Lock*) * nscreens))) - die("slock: malloc: %s\n", strerror(errno)); - int nlocks = 0; - for (screen = 0; screen < nscreens; screen++) { - if ((locks[screen] = lockscreen(dpy, screen)) != NULL) + if (!(locks = calloc(nscreens, sizeof(struct lock *)))) + die("slock: out of memory\n"); + for (nlocks = 0, s = 0; s < nscreens; s++) { + if ((locks[s] = lockscreen(dpy, &rr, s)) != NULL) nlocks++; + else + break; } - XSync(dpy, False); + XSync(dpy, 0); - /* Did we actually manage to lock something? */ - if (nlocks == 0) { /* nothing to protect */ - free(locks); - XCloseDisplay(dpy); + /* did we manage to lock everything? */ + if (nlocks != nscreens) return 1; - } - if (argc >= 2 && fork() == 0) { - if (dpy) - close(ConnectionNumber(dpy)); - execvp(argv[1], argv+1); - die("slock: execvp %s failed: %s\n", argv[1], strerror(errno)); + /* run post-lock command */ + if (argc > 0) { + switch (fork()) { + case -1: + die("slock: fork failed: %s\n", strerror(errno)); + case 0: + if (close(ConnectionNumber(dpy)) < 0) + die("slock: close: %s\n", strerror(errno)); + execvp(argv[0], argv); + fprintf(stderr, "slock: execvp %s: %s\n", argv[0], strerror(errno)); + _exit(1); + } } - /* Everything is now blank. Now wait for the correct password. */ -#ifdef HAVE_BSD_AUTH - readpw(dpy); -#else - readpw(dpy, pws); -#endif - - /* Password ok, unlock everything and quit. */ - for (screen = 0; screen < nscreens; screen++) - unlockscreen(dpy, locks[screen]); - - free(locks); - XCloseDisplay(dpy); + /* everything is now blank. Wait for the correct password */ + readpw(dpy, &rr, locks, nscreens, hash); return 0; } diff -Nru suckless-tools-42/slock/util.h suckless-tools-43/slock/util.h --- suckless-tools-42/slock/util.h 1970-01-01 00:00:00.000000000 +0000 +++ suckless-tools-43/slock/util.h 2016-11-20 00:31:23.000000000 +0000 @@ -0,0 +1,2 @@ +#undef explicit_bzero +void explicit_bzero(void *, size_t);