Compare commits

...

10 Commits

Author SHA1 Message Date
6231bc2a3b refactor: xmonad qwerty file 2023-05-21 22:59:52 +02:00
Max Hohlfeld
b3345f64fe feat: add calculator and direct web search 2023-05-17 15:33:02 +02:00
Max Hohlfeld
80c8527ce3 feat: add dmenu screenshot script 2023-05-15 10:20:15 +02:00
Max Hohlfeld
7df593f721 feat: add slock 2023-05-15 09:40:13 +02:00
Max Hohlfeld
65d62e131a feat: add dmenu 2023-05-15 09:31:47 +02:00
Max Hohlfeld
016b5a591a feat: create just command for only syncing configs 2023-05-10 11:31:27 +02:00
Max Hohlfeld
cbb3f34dfb feat: add nnn and bash config 2023-04-24 08:19:24 +02:00
Max Hohlfeld
90122ec55d fix: fix font for xmobar 2023-03-31 08:55:05 +02:00
Max Hohlfeld
f099ac6a85 feat: add background color to md code highlighting 2023-03-28 10:46:56 +02:00
521ffd29c9 feat: add xmonad prompt; use newer nvim lua ls 2023-03-05 10:03:06 +01:00
50 changed files with 5051 additions and 96 deletions

View File

@ -8,9 +8,20 @@ This project contains my dotfiles and scripts for daily usage. In addition to th
- alacritty
- xmobar
- dunst
- nnn
- bash
- dircolours
- dmenu
- border patch
- center patch
- lineheight patch
- zenburn colour sheme
- mapped j-k to down-up and h-l to prior-next
- slock
- neovim
- git
- git delta
- lazygit
- scripts
- `compiledoc` - compile a markdown or latex file into pdf using pandoc and tectonic
- `open_editor_in_new_shell` - used by nnn to open a file in `$EDITOR` in a new `$TERMINAL`

1040
ansible.cfg Normal file

File diff suppressed because it is too large Load Diff

View File

@ -3,15 +3,23 @@ allTags := "nvim,xmonad,git,scripts"
default:
just --list
sync-qwerty tags=allTags:
ANSIBLE_LOCALHOST_WARNING=false ansible-playbook site.yml -K -t "pc,qwerty,{{tags}}"
setup-qwerty tags=allTags:
ansible-playbook site.yml -K -t "pc,qwerty,{{tags}}"
sync-x220 tags=allTags:
ANSIBLE_LOCALHOST_WARNING=false ansible-playbook site.yml -K -t "pc,x220,{{tags}}"
config-qwerty tags=allTags:
ansible-playbook site.yml -t "pc,qwerty,{{tags}}" --skip-tags "setup"
sync-t460p tags=allTags:
ANSIBLE_LOCALHOST_WARNING=false ansible-playbook site.yml -K -t "pc,t460p,{{tags}}"
setup-x220 tags=allTags:
ansible-playbook site.yml -K -t "pc,x220,{{tags}}"
config-x220 tags=allTags:
ansible-playbook site.yml -t "pc,x220,{{tags}}" --skip-tags "setup"
setup-t460p tags=allTags:
ansible-playbook site.yml -K -t "pc,t460p,{{tags}}"
config-t460p tags=allTags:
ansible-playbook site.yml -t "pc,t460p,{{tags}}" --skip-tags "setup"
sync-server tags=allTags:
ANSIBLE_LOCALHOST_WARNING=false ansible-playbook site.yml -K -t "server,{{tags}}"
ansible-playbook site.yml -K -t "server,{{tags}}"

View File

@ -167,7 +167,7 @@ for _, server in ipairs(servers) do
}
end
lsp.sumneko_lua.setup {
lsp.lua_ls.setup {
on_attach = on_attach,
capabilities = capabilities,
settings = {

View File

@ -7,14 +7,14 @@
- git
- xclip
state: present
tags: always
tags: [always, setup]
- name: Create a config directory if it doesn't exist
ansible.builtin.file:
path: ~/.config/nvim
state: directory
mode: '0755'
tags: always
tags: [always, setup]
- name: Server specific nvim tasks
tags: server
@ -41,6 +41,7 @@
mode: '0755'
- name: Install language servers
tags: setup
become: true
ansible.builtin.package:
name:

View File

@ -29,6 +29,8 @@ case "$ext" in
-V geometry:margin=2cm \
-V mainfont="Liberation Sans" \
-V monofont="Liberation Mono" \
--highlight-style tango \
--include-in-header ~/.local/bin/inline_code.tex \
-o "$base".pdf "$file" ;;
tex) compile_tex ;;
esac

View File

@ -0,0 +1,14 @@
#! /usr/bin/env sh
# Changed a bit from Luke Smith https://github.com/LukeSmithxyz/voidrice/blob/master/.local/bin/maimpick
# A dmenu for selecting a screenshot option as listed below. Requires maim, xdotool and dmenu.
DEST="/home/max/bilder/screenshots/screenshot_$(date +%Y-%m-%d_%T).png"
case "$(printf "a selected area\\ncurrent window\\nfull screen\\na selected area (to clipboard)\\ncurrent window (to clipboard)\\nfull screen (to clipboard)" | dmenu -i -p "Screenshot which area?")" in
"a selected area") maim -u -s $DEST ;;
"current window") maim -u -i "$(xdotool getactivewindow)" $DEST ;;
"full screen") maim -u -B -d '0.8' --quiet $DEST ;;
"a selected area (to clipboard)") maim -s -u | xclip -selection clipboard -t image/png ;;
"current window (to clipboard)") maim -u -i "$(xdotool getactivewindow)" | xclip -selection clipboard -t image/png ;;
"full screen (to clipboard)") maim | xclip -selection clipboard -t image/png ;;
esac

View File

@ -0,0 +1,8 @@
\usepackage{fancyvrb,newverbs,xcolor}
\definecolor{Light}{HTML}{F8F8F8}
\let\oldtexttt\texttt
\renewcommand{\texttt}[1]{
\colorbox{Light}{\oldtexttt{#1}}
}

View File

@ -0,0 +1,3 @@
#!/usr/bin/env sh
$TERMINAL -e $EDITOR $1 &

View File

@ -5,6 +5,8 @@
- tectonic
- pandoc
- ttf-liberation
- maim
- xdotool
state: present
become: true
tags: pc
@ -23,4 +25,7 @@
mode: '0755'
with_items:
- { src: compiledoc, dest: ~/.local/bin/compiledoc }
- { src: inline_code.tex, dest: ~/.local/bin/inline_code.tex }
- { src: open_editor_in_new_shell, dest: ~/.local/bin/open_editor_in_new_shell }
- { src: dmenu_screenshot, dest: ~/.local/bin/dmenu_screenshot }
tags: pc

View File

@ -0,0 +1,78 @@
# ~/.bashrc
# colouring terminal
export PS1='\[\033[38;5;174m\]\u\[\033[38;5;187m\]@\h\[\033[00m\]:\[\033[38;5;174m\] \w \[\033[00m\]\$ '
# colouring ls
eval $(dircolors -b $HOME/.config/dircolours)
# set vi mode for bash
set -o vi
# aliases
alias ls='ls --color'
alias la='ls -lah'
alias gf='git fetch'
alias gd='git diff'
alias gl='git log'
alias gpl='git pull'
alias gps='git push'
alias ga='git add'
alias gst='git status'
alias gck='git checkout'
alias gcm='git commit'
alias gcl='git clone'
alias gb='git branch'
alias gr='git reset'
alias grm='git rm'
# starting ssh-agent
if [ -z "$SSH_AUTH_SOCK" ] ; then
eval `ssh-agent -s` 2>&1 >/dev/null
fi
# nnn config
export NNN_OPTS="eE"
export NNN_COLORS='#a744b322'
export NNN_FCOLORS='dfdfdf6c0000df42bbbaba5f'
export NNN_TRASH=1
export NNN_ARCHIVE="\\.(7z|a|ace|alz|arc|arj|bz|bz2|cab|cpio|deb|gz|jar|lha|lz|lzh|lzma|lzo|rar|rpm|rz|t7z|tar|tbz|tbz2|tgz|tlz|txz|tZ|tzo|war|xpi|xz|Z|zip)$"
export NNN_BMS='b:~/bilder;d:~/downloads;D:~/dokumente;v:~/videos;m:~/music;c:~/.config'
export NNN_PLUG='m:nmount'
# nnn cd on quit
n ()
{
# Block nesting of nnn in subshells
if [ -n $NNNLVL ] && [ "${NNNLVL:-0}" -ge 1 ]; then
echo "nnn is already running"
return
fi
NNN_TMPFILE="${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.lastd"
nnn "$@"
if [ -f "$NNN_TMPFILE" ]; then
. "$NNN_TMPFILE"
rm -f "$NNN_TMPFILE" > /dev/null
fi
}
# vimwiki
vw () {
if [[ $# == 0 ]]
then
git -C ~/.local/share/vimwiki pull
nvim ~/.local/share/vimwiki/index.md
git -C ~/.local/share/vimwiki add ~/.local/share/vimwiki/*
git -C ~/.local/share/vimwiki commit -m "autosync-$(date +%FT%T)"
git -C ~/.local/share/vimwiki push
elif [[ $1 == 'g' ]]
then
git -C ~/.local/share/vimwiki ${@:2}
else
echo 'Usage: vw [g] [args ...]'
fi
}

View File

@ -0,0 +1,268 @@
# Zenburn color theme for the color GNU ls utility.
# Ivaylo Kuzev <ivkuzev@gmail.com>, 2014 - 2015
# Term Section
TERM Eterm
TERM ansi
TERM color-xterm
TERM con132x25
TERM con132x30
TERM con132x43
TERM con132x60
TERM con80x25
TERM con80x28
TERM con80x30
TERM con80x43
TERM con80x50
TERM con80x60
TERM cons25
TERM console
TERM cygwin
TERM dtterm
TERM eterm-color
TERM gnome
TERM gnome-256color
TERM jfbterm
TERM konsole
TERM kterm
TERM linux
TERM linux-c
TERM mach-color
TERM mlterm
TERM putty
TERM rxvt
TERM rxvt-256color
TERM rxvt-cygwin
TERM rxvt-cygwin-native
TERM rxvt-unicode
TERM rxvt-unicode256
TERM rxvt-unicode-256color
TERM screen
TERM screen-256color
TERM screen-256color-bce
TERM screen-bce
TERM screen-w
TERM screen.linux
TERM st
TERM st-meta
TERM st-256color
TERM st-meta-256color
TERM vt100
TERM xterm
TERM xterm-16color
TERM xterm-256color
TERM xterm-88color
TERM xterm-color
TERM xterm-debian
TERM xterm-termite
## Documentation
#
# Attribute codes:
# 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed
# Text color codes:
# 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white
# Background color codes:
# 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white
#
# Text 256 color coding:
# 38;5;COLOR_NUMBER
# Background 256 color coding:
# 48;5;COLOR_NUMBER
# block device driver:
BLK 48;5;108;38;5;223;01
# file with capability:
CAPABILITY 01;38;5;95
# character device driver:
CHR 48;5;108;38;5;223;01
# directory:
DIR 48;5;237;01;38;5;223
# door:
DOOR 48;5;237;38;5;180;01
# This is for files with execute permission:
EXEC 01;38;5;108
# pipe:
FIFO 48;5;237;38;5;180;01
# regular file:
#FILE 00
# symbolic link:
LINK 48;5;237;38;5;223
# normal (nonfilename) text:
#NORMAL 00
# orphaned symbolic link:
ORPHAN 48;5;237;38;5;187
# directory that is other-writable (o+w) and not sticky:
OTHER_WRITABLE 48;5;237;38;5;180
# file that is setuid (u+s):
SETUID 48;5;237;38;5;66
# file that is setgid (g+s):
SETGID 48;5;237;38;5;66
# socket:
SOCK 48;5;237;38;5;180;01
# directory with the sticky bit set (+t) and not other-writable:
STICKY 48;5;180;38;5;234
# dir that is sticky and other-writable (+t,o+w):
STICKY_OTHER_WRITABLE 48;5;180;38;5;234
# archives
.7z 01;38;5;174
.arj 01;38;5;174
.bz2 01;38;5;174
.bz 01;38;5;174
.gz 01;38;5;174
.rar 01;38;5;174
.tar 01;38;5;174
.tgz 01;38;5;174
.tbz 01;38;5;174
.tbz2 01;38;5;174
.xz 01;38;5;174
.zip 01;38;5;174
# packaged apps
.apk 01;38;5;95
.deb 01;38;5;174
.jad 01;38;5;95
.jar 01;38;5;95
.rpm 01;38;5;174
# images|graphics
.bmp 00;38;5;109
.gif 00;38;5;109
.ico 00;38;5;109
.jpg 00;38;5;109
.JPG 00;38;5;109
.jpeg 00;38;5;109
.png 00;38;5;109
.svg 00;38;5;109
.xbm 00;38;5;109
.xpm 00;38;5;109
# audio formats
.aac 00;38;5;116
.au 00;38;5;116
.flac 00;38;5;116
.mid 00;38;5;116
.midi 00;38;5;116
.mka 00;38;5;116
.mp3 00;38;5;116
.mpc 00;38;5;116
.ogg 00;38;5;116
.ra 00;38;5;116
.wav 00;38;5;116
# video formats
.mov 00;38;5;66
.mpg 00;38;5;66
.mpeg 00;38;5;66
.m2v 00;38;5;66
.mkv 00;38;5;66
.ogm 00;38;5;66
.mp4 00;38;5;66
.m4v 00;38;5;66
.mp4v 00;38;5;66
.vob 00;38;5;66
.qt 00;38;5;66
.nuv 00;38;5;66
.wmv 00;38;5;66
.asf 00;38;5;66
.rm 00;38;5;66
.rmvb 01;38;5;66
.flc 00;38;5;66
.avi 00;38;5;66
.fli 00;38;5;66
.flv 00;38;5;66
.gl 00;38;5;66
.m2ts 00;38;5;66
.divx 00;38;5;66
.webm 00;38;5;66
# shell
.awk 00;38;5;151
.bash 00;38;5;151
.bat 00;38;5;151
.BAT 00;38;5;151
.sed 00;38;5;151
.sh 00;38;5;151
.zsh 00;38;5;151
# build
*CMakeLists.txt 00;38;5;187
.cabal 00;38;5;187
*Makefile 00;38;5;187
.mk 00;38;5;187
.make 00;38;5;187
# source files
.c 01;38;5;187
.h 01;38;5;187
.s 01;38;5;187
.cs 01;38;5;187
.java 01;38;5;187
.scala 01;38;5;187
.hs 01;38;5;187
.py 01;38;5;187
.rb 01;38;5;187
.php 01;38;5;187
.pl 01;38;5;187
.vim 01;38;5;187
.js 01;38;5;187
.coffee 01;38;5;187
.go 01;38;5;187
.lisp 01;38;5;187
.scm 01;38;5;187
# documents
.txt 04;38;5;188
.tex 04;38;5;188
.html 04;38;5;188
.xhtml 04;38;5;188
.xml 04;38;5;188
.md 04;38;5;188
.mkd 04;38;5;188
.markdown 04;38;5;188
.org 04;38;5;188
.pandoc 04;38;5;188
.pdc 04;38;5;188
.pdf 04;38;5;188
# Files of special interest
*rc 04;38;5;180
.conf 04;38;5;180
*Dockerfile 04;38;5;180
# meta
*README 04;38;5;187
*LICENSE 04;38;5;187
*AUTHORS 04;38;5;187
# version control
.gitignore 00;38;5;248
.gitmodules 00;38;5;248
# logs and backups
.log 00;38;5;234
.bak 00;38;5;234
.aux 00;38;5;234
.toc 00;38;5;234
*~ 00;38;5;234
*# 00;38;5;234
.swp 00;38;5;234
.tmp 00;38;5;234
.temp 00;38;5;234
.o 00;38;5;234
.pyc 00;38;5;234
.class 00;38;5;234
.cache 00;38;5;234
# pacman files
.pacnew 48;5;95;38;5;108
.pacsave 48;5;95;38;5;108
.pacorig 48;5;95;38;5;108
*PKGBUILD 00;38;5;110
# rpm files
.rpmsave 48;5;95;38;5;108
.rpmorig 48;5;95;38;5;108
.rpmnew 48;5;95;38;5;108
.spec 00;38;5;110

View File

@ -0,0 +1,30 @@
MIT/X Consortium License
© 2006-2019 Anselm R Garbe <anselm@garbe.ca>
© 2006-2008 Sander van Dijk <a.h.vandijk@gmail.com>
© 2006-2007 Michał Janeczek <janeczek@gmail.com>
© 2007 Kris Maglione <jg@suckless.org>
© 2009 Gottox <gottox@s01.de>
© 2009 Markus Schnalke <meillo@marmaro.de>
© 2009 Evan Gates <evan.gates@gmail.com>
© 2010-2012 Connor Lane Smith <cls@lubutu.com>
© 2014-2020 Hiltjo Posthuma <hiltjo@codemadness.org>
© 2015-2019 Quentin Rameau <quinq@fifth.space>
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.

View File

@ -0,0 +1,64 @@
# dmenu - dynamic menu
# See LICENSE file for copyright and license details.
include config.mk
SRC = drw.c dmenu.c stest.c util.c
OBJ = $(SRC:.c=.o)
all: options dmenu stest
options:
@echo dmenu build options:
@echo "CFLAGS = $(CFLAGS)"
@echo "LDFLAGS = $(LDFLAGS)"
@echo "CC = $(CC)"
.c.o:
$(CC) -c $(CFLAGS) $<
config.h:
cp config.def.h $@
$(OBJ): arg.h config.h config.mk drw.h
dmenu: dmenu.o drw.o util.o
$(CC) -o $@ dmenu.o drw.o util.o $(LDFLAGS)
stest: stest.o
$(CC) -o $@ stest.o $(LDFLAGS)
clean:
rm -f dmenu stest $(OBJ) dmenu-$(VERSION).tar.gz
dist: clean
mkdir -p dmenu-$(VERSION)
cp LICENSE Makefile README arg.h config.def.h config.mk dmenu.1\
drw.h util.h dmenu_path dmenu_run stest.1 $(SRC)\
dmenu-$(VERSION)
tar -cf dmenu-$(VERSION).tar dmenu-$(VERSION)
gzip dmenu-$(VERSION).tar
rm -rf dmenu-$(VERSION)
install: all
mkdir -p $(DESTDIR)$(PREFIX)/bin
cp -f dmenu dmenu_path dmenu_run stest $(DESTDIR)$(PREFIX)/bin
chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu
chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu_path
chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu_run
chmod 755 $(DESTDIR)$(PREFIX)/bin/stest
mkdir -p $(DESTDIR)$(MANPREFIX)/man1
sed "s/VERSION/$(VERSION)/g" < dmenu.1 > $(DESTDIR)$(MANPREFIX)/man1/dmenu.1
sed "s/VERSION/$(VERSION)/g" < stest.1 > $(DESTDIR)$(MANPREFIX)/man1/stest.1
chmod 644 $(DESTDIR)$(MANPREFIX)/man1/dmenu.1
chmod 644 $(DESTDIR)$(MANPREFIX)/man1/stest.1
uninstall:
rm -f $(DESTDIR)$(PREFIX)/bin/dmenu\
$(DESTDIR)$(PREFIX)/bin/dmenu_path\
$(DESTDIR)$(PREFIX)/bin/dmenu_run\
$(DESTDIR)$(PREFIX)/bin/stest\
$(DESTDIR)$(MANPREFIX)/man1/dmenu.1\
$(DESTDIR)$(MANPREFIX)/man1/stest.1
.PHONY: all options clean dist install uninstall

View File

@ -0,0 +1,24 @@
dmenu - dynamic menu
====================
dmenu is an efficient dynamic menu for X.
Requirements
------------
In order to build dmenu you need the Xlib header files.
Installation
------------
Edit config.mk to match your local setup (dmenu is installed into
the /usr/local namespace by default).
Afterwards enter the following command to build and install dmenu
(if necessary as root):
make clean install
Running dmenu
-------------
See the man page for details.

View File

@ -0,0 +1,49 @@
/*
* 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_)
#define ARGEND }\
}
#define ARGC() argc_
#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])))
#endif

View File

@ -0,0 +1,29 @@
/* See LICENSE file for copyright and license details. */
/* Default settings; can be overriden by command line. */
static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */
static int centered = 0; /* -c option; centers dmenu on screen */
static int min_width = 500; /* minimum width when centered */
static int colorprompt = 1; /* -p option; if 1, prompt uses SchemeSel, otherwise SchemeNorm */
/* -fn option overrides fonts[0]; default X11 font or font set */
static const char *fonts[] = {
"monospace:size=10"
};
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[] = " ";
/* Size of the window border */
static unsigned int border_width = 0;

View File

@ -0,0 +1,29 @@
/* See LICENSE file for copyright and license details. */
/* Default settings; can be overriden by command line. */
static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */
static int centered = 1; /* -c option; centers dmenu on screen */
static int min_width = 500; /* minimum width when centered */
static int colorprompt = 1; /* -p option; if 1, prompt uses SchemeSel, otherwise SchemeNorm */
/* -fn option overrides fonts[0]; default X11 font or font set */
static const char *fonts[] = {
"Iosevka:pixelsize=12:antialias=true:autohint=true"
};
static const char *prompt = NULL; /* -p option; prompt to the left of input field */
static const char *colors[SchemeLast][2] = {
/* fg bg */
[SchemeNorm] = { "#dcdccc", "#434443" },
[SchemeSel] = { "#333333", "#dca3a3" },
[SchemeOut] = { "#dca3a3", "#434443" },
};
/* -l option; if nonzero, dmenu uses vertical list with given number of lines */
static unsigned int lines = 10;
/*
* Characters not considered part of a word while deleting words
* for example: " /?\"&[]"
*/
static const char worddelimiters[] = " ";
/* Size of the window border */
static unsigned int border_width = 2;

View File

@ -0,0 +1,31 @@
# dmenu version
VERSION = 5.0
# paths
PREFIX = /usr/local
MANPREFIX = $(PREFIX)/share/man
X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib
# Xinerama, comment if you don't want it
XINERAMALIBS = -lXinerama
XINERAMAFLAGS = -DXINERAMA
# freetype
FREETYPELIBS = -lfontconfig -lXft
FREETYPEINC = /usr/include/freetype2
# OpenBSD (uncomment)
#FREETYPEINC = $(X11INC)/freetype2
# includes and libs
INCS = -I$(X11INC) -I$(FREETYPEINC)
LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS)
# flags
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 = $(LIBS)
# compiler and linker
CC = cc

View File

@ -0,0 +1,197 @@
.TH DMENU 1 dmenu\-VERSION
.SH NAME
dmenu \- dynamic menu
.SH SYNOPSIS
.B dmenu
.RB [ \-bfiv ]
.RB [ \-l
.IR lines ]
.RB [ \-m
.IR monitor ]
.RB [ \-p
.IR prompt ]
.RB [ \-fn
.IR font ]
.RB [ \-nb
.IR color ]
.RB [ \-nf
.IR color ]
.RB [ \-sb
.IR color ]
.RB [ \-sf
.IR color ]
.RB [ \-w
.IR windowid ]
.P
.BR dmenu_run " ..."
.SH DESCRIPTION
.B dmenu
is a dynamic menu for X, which reads a list of newline\-separated items from
stdin. When the user selects an item and presses Return, their choice is printed
to stdout and dmenu terminates. Entering text will narrow the items to those
matching the tokens in the input.
.P
.B dmenu_run
is a script used by
.IR dwm (1)
which lists programs in the user's $PATH and runs the result in their $SHELL.
.SH OPTIONS
.TP
.B \-b
dmenu appears at the bottom of the screen.
.TP
.B \-c
dmenu appears centered on the screen.
.TP
.B \-f
dmenu grabs the keyboard before reading stdin if not reading from a tty. This
is faster, but will lock up X until stdin reaches end\-of\-file.
.TP
.B \-i
dmenu matches menu items case insensitively.
.TP
.BI \-l " lines"
dmenu lists items vertically, with the given number of lines.
.TP
.BI \-m " monitor"
dmenu is displayed on the monitor number supplied. Monitor numbers are starting
from 0.
.TP
.BI \-p " prompt"
defines the prompt to be displayed to the left of the input field.
.TP
.BI \-fn " font"
defines the font or font set used.
.TP
.BI \-nb " color"
defines the normal background color.
.IR #RGB ,
.IR #RRGGBB ,
and X color names are supported.
.TP
.BI \-nf " color"
defines the normal foreground color.
.TP
.BI \-sb " color"
defines the selected background color.
.TP
.BI \-sf " color"
defines the selected foreground color.
.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.
.TP
.B Tab
Copy the selected item to the input field.
.TP
.B Return
Confirm selection. Prints the selected item to stdout and exits, returning
success.
.TP
.B Ctrl-Return
Confirm selection. Prints the selected item to stdout and continues.
.TP
.B Shift\-Return
Confirm input. Prints the input text to stdout and exits, returning success.
.TP
.B Escape
Exit without selecting an item, returning failure.
.TP
.B Ctrl-Left
Move cursor to the start of the current word
.TP
.B Ctrl-Right
Move cursor to the end of the current word
.TP
.B C\-a
Home
.TP
.B C\-b
Left
.TP
.B C\-c
Escape
.TP
.B C\-d
Delete
.TP
.B C\-e
End
.TP
.B C\-f
Right
.TP
.B C\-g
Escape
.TP
.B C\-h
Backspace
.TP
.B C\-i
Tab
.TP
.B C\-j
Return
.TP
.B C\-J
Shift-Return
.TP
.B C\-k
Delete line right
.TP
.B C\-m
Return
.TP
.B C\-M
Shift-Return
.TP
.B C\-n
Down
.TP
.B C\-p
Up
.TP
.B C\-u
Delete line left
.TP
.B C\-w
Delete word left
.TP
.B C\-y
Paste from primary X selection
.TP
.B C\-Y
Paste from X clipboard
.TP
.B M\-b
Move cursor to the start of the current word
.TP
.B M\-f
Move cursor to the end of the current word
.TP
.B M\-g
Home
.TP
.B M\-G
End
.TP
.B M\-h
Up
.TP
.B M\-j
Page down
.TP
.B M\-k
Page up
.TP
.B M\-l
Down
.SH SEE ALSO
.IR dwm (1),
.IR stest (1)

View File

@ -0,0 +1,801 @@
/* See LICENSE file for copyright and license details. */
#include <ctype.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#ifdef XINERAMA
#include <X11/extensions/Xinerama.h>
#endif
#include <X11/Xft/Xft.h>
#include "drw.h"
#include "util.h"
/* macros */
#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 TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
/* enums */
enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */
struct item {
char *text;
struct item *left, *right;
int out;
};
static char text[BUFSIZ] = "";
static char *embed;
static int bh, mw, mh;
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;
static struct item *prev, *curr, *next, *sel;
static int mon = -1, screen;
static Atom clip, utf8;
static Display *dpy;
static Window root, parentwin, win;
static XIC xic;
static Drw *drw;
static Clr *scheme[SchemeLast];
#include "config.h"
static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
static char *(*fstrstr)(const char *, const char *) = strstr;
static void
appenditem(struct item *item, struct item **list, struct item **last)
{
if (*last)
(*last)->right = item;
else
*list = item;
item->left = *last;
item->right = NULL;
*last = item;
}
static void
calcoffsets(void)
{
int i, n;
if (lines > 0)
n = lines * bh;
else
n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">"));
/* calculate which items will begin the next page and previous page */
for (i = 0, next = curr; next; next = next->right)
if ((i += (lines > 0) ? bh : MIN(TEXTW(next->text), n)) > n)
break;
for (i = 0, prev = curr; prev && prev->left; prev = prev->left)
if ((i += (lines > 0) ? bh : MIN(TEXTW(prev->left->text), n)) > n)
break;
}
static int
max_textw(void)
{
int len = 0;
for (struct item *item = items; item && item->text; item++)
len = MAX(TEXTW(item->text), len);
return len;
}
static void
cleanup(void)
{
size_t i;
XUngrabKey(dpy, AnyKey, AnyModifier, root);
for (i = 0; i < SchemeLast; i++)
free(scheme[i]);
drw_free(drw);
XSync(dpy, False);
XCloseDisplay(dpy);
}
static char *
cistrstr(const char *s, const char *sub)
{
size_t len;
for (len = strlen(sub); *s; s++)
if (!strncasecmp(s, sub, len))
return (char *)s;
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)
{
unsigned int curpos;
struct item *item;
int x = 0, y = 0, w;
drw_setscheme(drw, scheme[SchemeNorm]);
drw_rect(drw, 0, 0, mw, mh, 1, 1);
if (prompt && *prompt) {
if (colorprompt)
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, lrpad / 2, text, 0);
curpos = TEXTW(text) - TEXTW(&text[cursor]);
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 */
for (item = curr; item != next; item = item->right)
drawitem(item, 0, 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, lrpad / 2, "<", 0);
}
x += w;
for (item = curr; item != next; item = item->right)
x = drawitem(item, x, 0, MIN(TEXTW(item->text), mw - x - TEXTW(">")));
if (next) {
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)
return;
nanosleep(&ts, NULL);
}
die("cannot grab keyboard");
}
static void
match(void)
{
static char **tokv = NULL;
static int tokn = 0;
char buf[sizeof text], *s;
int i, tokc = 0;
size_t len, textsize;
struct item *item, *lprefix, *lsubstr, *prefixend, *substrend;
strcpy(buf, text);
/* 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:", tokn * sizeof *tokv);
len = tokc ? strlen(tokv[0]) : 0;
matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL;
textsize = strlen(text) + 1;
for (item = items; item && item->text; item++) {
for (i = 0; i < tokc; i++)
if (!fstrstr(item->text, tokv[i]))
break;
if (i != tokc) /* not all tokens match */
continue;
/* exact matches go first, then prefixes, then substrings */
if (!tokc || !fstrncmp(text, item->text, textsize))
appenditem(item, &matches, &matchend);
else if (!fstrncmp(tokv[0], item->text, len))
appenditem(item, &lprefix, &prefixend);
else
appenditem(item, &lsubstr, &substrend);
}
if (lprefix) {
if (matches) {
matchend->right = lprefix;
lprefix->left = matchend;
} else
matches = lprefix;
matchend = prefixend;
}
if (lsubstr) {
if (matches) {
matchend->right = lsubstr;
lsubstr->left = matchend;
} else
matches = lsubstr;
matchend = substrend;
}
curr = sel = matches;
calcoffsets();
}
static void
insert(const char *str, ssize_t n)
{
if (strlen(text) + n > sizeof text - 1)
return;
/* move existing text out of the way, insert new text, and update cursor */
memmove(&text[cursor + n], &text[cursor], sizeof text - cursor - MAX(n, 0));
if (n > 0)
memcpy(&text[cursor], str, n);
cursor += n;
match();
}
static size_t
nextrune(int inc)
{
ssize_t n;
/* return location of next utf8 rune in the given direction (+1 or -1) */
for (n = cursor + inc; n + inc >= 0 && (text[n] & 0xc0) == 0x80; n += inc)
;
return n;
}
static void
movewordedge(int dir)
{
if (dir < 0) { /* move cursor to the start of the word*/
while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)]))
cursor = nextrune(-1);
while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)]))
cursor = nextrune(-1);
} else { /* move cursor to the end of the word */
while (text[cursor] && strchr(worddelimiters, text[cursor]))
cursor = nextrune(+1);
while (text[cursor] && !strchr(worddelimiters, text[cursor]))
cursor = nextrune(+1);
}
}
static void
keypress(XKeyEvent *ev)
{
char buf[32];
int len;
KeySym ksym;
Status status;
len = XmbLookupString(xic, ev, buf, sizeof buf, &ksym, &status);
switch (status) {
default: /* XLookupNone, XBufferOverflow */
return;
case XLookupChars:
goto insert;
case XLookupKeySym:
case XLookupBoth:
break;
}
if (ev->state & ControlMask) {
switch(ksym) {
case XK_a: ksym = XK_Home; break;
case XK_b: ksym = XK_Left; break;
case XK_c: ksym = XK_Escape; break;
case XK_d: ksym = XK_Delete; break;
case XK_e: ksym = XK_End; break;
case XK_f: ksym = XK_Right; break;
case XK_g: ksym = XK_Escape; break;
case XK_h: ksym = XK_BackSpace; break;
case XK_i: ksym = XK_Tab; break;
case XK_j: /* fallthrough */
case XK_J: /* fallthrough */
case XK_m: /* fallthrough */
case XK_M: ksym = XK_Return; ev->state &= ~ControlMask; break;
case XK_n: ksym = XK_Down; break;
case XK_p: ksym = XK_Up; break;
case XK_k: /* delete right */
text[cursor] = '\0';
match();
break;
case XK_u: /* delete left */
insert(NULL, 0 - cursor);
break;
case XK_w: /* delete word */
while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)]))
insert(NULL, nextrune(-1) - cursor);
while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)]))
insert(NULL, nextrune(-1) - cursor);
break;
case XK_y: /* paste selection */
case XK_Y:
XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY,
utf8, utf8, win, CurrentTime);
return;
case XK_Left:
movewordedge(-1);
goto draw;
case XK_Right:
movewordedge(+1);
goto draw;
case XK_Return:
case XK_KP_Enter:
break;
case XK_bracketleft:
cleanup();
exit(1);
default:
return;
}
} else if (ev->state & Mod1Mask) {
switch(ksym) {
case XK_b:
movewordedge(-1);
goto draw;
case XK_f:
movewordedge(+1);
goto draw;
case XK_g: ksym = XK_Home; break;
case XK_G: ksym = XK_End; break;
case XK_h: ksym = XK_Up; break;
case XK_j: ksym = XK_Next; break;
case XK_k: ksym = XK_Prior; break;
case XK_l: ksym = XK_Down; break;
default:
return;
}
}
switch(ksym) {
default:
insert:
if (!iscntrl(*buf))
insert(buf, len);
break;
case XK_Delete:
if (text[cursor] == '\0')
return;
cursor = nextrune(+1);
/* fallthrough */
case XK_BackSpace:
if (cursor == 0)
return;
insert(NULL, nextrune(-1) - cursor);
break;
case XK_End:
if (text[cursor] != '\0') {
cursor = strlen(text);
break;
}
if (next) {
/* jump to end of list and position items in reverse */
curr = matchend;
calcoffsets();
curr = prev;
calcoffsets();
while (next && (curr = curr->right))
calcoffsets();
}
sel = matchend;
break;
case XK_Escape:
cleanup();
exit(1);
case XK_Home:
if (sel == matches) {
cursor = 0;
break;
}
sel = curr = matches;
calcoffsets();
break;
case XK_Left:
if (cursor > 0 && (!sel || !sel->left || lines > 0)) {
cursor = nextrune(-1);
break;
}
if (lines > 0)
return;
/* fallthrough */
case XK_Prior:
if (sel && sel->left && (sel = sel->left)->right == curr) {
curr = prev;
calcoffsets();
}
break;
case XK_Down:
if (!next)
return;
sel = curr = next;
calcoffsets();
break;
case XK_Up:
if (!prev)
return;
sel = curr = prev;
calcoffsets();
break;
case XK_Return:
case XK_KP_Enter:
puts((sel && !(ev->state & ShiftMask)) ? sel->text : text);
if (!(ev->state & ControlMask)) {
cleanup();
exit(0);
}
if (sel)
sel->out = 1;
break;
case XK_Right:
if (text[cursor] != '\0') {
cursor = nextrune(+1);
break;
}
if (lines > 0)
return;
/* fallthrough */
case XK_Next:
if (sel && sel->right && (sel = sel->right) == next) {
curr = next;
calcoffsets();
}
break;
case XK_Tab:
if (!sel)
return;
strncpy(text, sel->text, sizeof text - 1);
text[sizeof text - 1] = '\0';
cursor = strlen(text);
match();
break;
}
draw:
drawmenu();
}
static void
paste(void)
{
char *p, *q;
int di;
unsigned long dl;
Atom da;
/* we have been given the current selection, now insert it into input */
if (XGetWindowProperty(dpy, win, utf8, 0, (sizeof text / 4) + 1, False,
utf8, &da, &di, &dl, &dl, (unsigned char **)&p)
== Success && p) {
insert(p, (q = strchr(p, '\n')) ? q - p : (ssize_t)strlen(p));
XFree(p);
}
drawmenu();
}
static void
readstdin(void)
{
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++) {
if (i + 1 >= size / sizeof *items)
if (!(items = realloc(items, (size += BUFSIZ))))
die("cannot realloc %u bytes:", size);
if ((p = strchr(buf, '\n')))
*p = '\0';
if (!(items[i].text = strdup(buf)))
die("cannot strdup %u bytes:", strlen(buf) + 1);
items[i].out = 0;
drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL);
if (tmpmax > inputw) {
inputw = tmpmax;
imax = i;
}
}
if (items)
items[i].text = NULL;
inputw = items ? TEXTW(items[imax].text) : 0;
lines = MIN(lines, i);
}
static void
run(void)
{
XEvent ev;
while (!XNextEvent(dpy, &ev)) {
if (XFilterEvent(&ev, win))
continue;
switch(ev.type) {
case DestroyNotify:
if (ev.xdestroywindow.window != win)
break;
cleanup();
exit(1);
case Expose:
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;
case SelectionNotify:
if (ev.xselection.property == utf8)
paste();
break;
case VisibilityNotify:
if (ev.xvisibility.state != VisibilityUnobscured)
XRaiseWindow(dpy, win);
break;
}
}
}
static void
setup(void)
{
int x, y, i, j;
unsigned int du;
XSetWindowAttributes swa;
XIM xim;
Window w, dw, *dws;
XWindowAttributes wa;
XClassHint ch = {"dmenu", "dmenu"};
#ifdef XINERAMA
XineramaScreenInfo *info;
Window pw;
int a, di, n, area = 0;
#endif
/* init appearance */
for (j = 0; j < SchemeLast; j++)
scheme[j] = drw_scm_create(drw, colors[j], 2);
clip = XInternAtom(dpy, "CLIPBOARD", False);
utf8 = XInternAtom(dpy, "UTF8_STRING", False);
/* calculate menu geometry */
bh = drw->fonts->h + 2;
lines = MAX(lines, 0);
mh = (lines + 1) * bh;
promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
#ifdef XINERAMA
i = 0;
if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) {
XGetInputFocus(dpy, &w, &di);
if (mon >= 0 && mon < n)
i = mon;
else if (w != root && w != PointerRoot && w != None) {
/* find top-level window containing current input focus */
do {
if (XQueryTree(dpy, (pw = w), &dw, &w, &dws, &du) && dws)
XFree(dws);
} while (w != root && w != pw);
/* find xinerama screen with which the window intersects most */
if (XGetWindowAttributes(dpy, pw, &wa))
for (j = 0; j < n; j++)
if ((a = INTERSECT(wa.x, wa.y, wa.width, wa.height, info[j])) > area) {
area = a;
i = j;
}
}
/* no focused window is on screen, so use pointer location instead */
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;
if (centered) {
mw = MIN(MAX(max_textw() + promptw, min_width), info[i].width);
x = info[i].x_org + ((info[i].width - mw) / 2);
y = info[i].y_org + ((info[i].height - mh) / 2);
} else {
x = info[i].x_org;
y = info[i].y_org + (topbar ? 0 : info[i].height - mh);
mw = info[i].width;
}
XFree(info);
} else
#endif
{
if (!XGetWindowAttributes(dpy, parentwin, &wa))
die("could not get embedding window attributes: 0x%lx",
parentwin);
if (centered) {
mw = MIN(MAX(max_textw() + promptw, min_width), wa.width);
x = (wa.width - mw) / 2;
y = (wa.height - mh) / 2;
} else {
x = 0;
y = topbar ? 0 : wa.height - mh;
mw = wa.width;
}
}
inputw = MIN(inputw, mw/3);
match();
/* create menu window */
swa.override_redirect = True;
swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
win = XCreateWindow(dpy, parentwin, x, y - (topbar ? 0 : border_width * 2), mw - border_width * 2, mh, border_width,
CopyFromParent, CopyFromParent, CopyFromParent,
CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
if (border_width)
XSetWindowBorder(dpy, win, scheme[SchemeSel][ColBg].pixel);
XSetClassHint(dpy, win, &ch);
/* input methods */
if ((xim = XOpenIM(dpy, NULL, NULL, NULL)) == NULL)
die("XOpenIM failed: could not open input device");
xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
XNClientWindow, win, XNFocusWindow, win, NULL);
XMapRaised(dpy, win);
if (embed) {
XSelectInput(dpy, parentwin, FocusChangeMask | SubstructureNotifyMask);
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();
}
static void
usage(void)
{
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++)
/* these options take no arguments */
if (!strcmp(argv[i], "-v")) { /* prints version information */
puts("dmenu-"VERSION);
exit(0);
} else if (!strcmp(argv[i], "-b")) /* appears at the bottom of the screen */
topbar = 0;
else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */
fast = 1;
else if (!strcmp(argv[i], "-c")) /* centers dmenu on screen */
centered = 1;
else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */
fstrncmp = strncasecmp;
fstrstr = cistrstr;
} else if (i + 1 == argc)
usage();
/* these options take one argument */
else if (!strcmp(argv[i], "-l")) /* number of lines in vertical list */
lines = atoi(argv[++i]);
else if (!strcmp(argv[i], "-m"))
mon = atoi(argv[++i]);
else if (!strcmp(argv[i], "-p")) /* adds prompt to left of input field */
prompt = argv[++i];
else if (!strcmp(argv[i], "-fn")) /* font or font set */
fonts[0] = argv[++i];
else if (!strcmp(argv[i], "-nb")) /* normal background color */
colors[SchemeNorm][ColBg] = argv[++i];
else if (!strcmp(argv[i], "-nf")) /* normal foreground color */
colors[SchemeNorm][ColFg] = argv[++i];
else if (!strcmp(argv[i], "-sb")) /* selected background color */
colors[SchemeSel][ColBg] = argv[++i];
else if (!strcmp(argv[i], "-sf")) /* selected foreground color */
colors[SchemeSel][ColFg] = argv[++i];
else if (!strcmp(argv[i], "-w")) /* embedding window id */
embed = argv[++i];
else if (!strcmp(argv[i], "-bw"))
border_width = atoi(argv[++i]); /* border width */
else
usage();
if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
fputs("warning: no locale support\n", stderr);
if (!(dpy = XOpenDisplay(NULL)))
die("cannot open display");
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
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;
#ifdef __OpenBSD__
if (pledge("stdio rpath", NULL) == -1)
die("pledge");
#endif
if (fast && !isatty(0)) {
grabkeyboard();
readstdin();
} else {
readstdin();
grabkeyboard();
}
setup();
run();
return 1; /* unreachable */
}

View File

@ -0,0 +1,13 @@
#!/bin/sh
cachedir="${XDG_CACHE_HOME:-"$HOME/.cache"}"
cache="$cachedir/dmenu_run"
[ ! -e "$cachedir" ] && mkdir -p "$cachedir"
IFS=:
if stest -dqr -n "$cache" $PATH; then
stest -flx $PATH | sort -u | tee "$cache"
else
cat "$cache"
fi

View File

@ -0,0 +1,2 @@
#!/bin/sh
dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} &

View File

@ -0,0 +1,436 @@
/* See LICENSE file for copyright and license details. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xft/Xft.h>
#include "drw.h"
#include "util.h"
#define UTF_INVALID 0xFFFD
#define UTF_SIZ 4
static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
static long
utf8decodebyte(const char c, size_t *i)
{
for (*i = 0; *i < (UTF_SIZ + 1); ++(*i))
if (((unsigned char)c & utfmask[*i]) == utfbyte[*i])
return (unsigned char)c & ~utfmask[*i];
return 0;
}
static size_t
utf8validate(long *u, size_t i)
{
if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
*u = UTF_INVALID;
for (i = 1; *u > utfmax[i]; ++i)
;
return i;
}
static size_t
utf8decode(const char *c, long *u, size_t clen)
{
size_t i, j, len, type;
long udecoded;
*u = UTF_INVALID;
if (!clen)
return 0;
udecoded = utf8decodebyte(c[0], &len);
if (!BETWEEN(len, 1, UTF_SIZ))
return 1;
for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
if (type)
return j;
}
if (j < len)
return 0;
*u = udecoded;
utf8validate(u, len);
return len;
}
Drw *
drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
{
Drw *drw = ecalloc(1, sizeof(Drw));
drw->dpy = dpy;
drw->screen = screen;
drw->root = root;
drw->w = w;
drw->h = h;
drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
drw->gc = XCreateGC(dpy, root, 0, NULL);
XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
return drw;
}
void
drw_resize(Drw *drw, unsigned int w, unsigned int h)
{
if (!drw)
return;
drw->w = w;
drw->h = h;
if (drw->drawable)
XFreePixmap(drw->dpy, drw->drawable);
drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
}
void
drw_free(Drw *drw)
{
XFreePixmap(drw->dpy, drw->drawable);
XFreeGC(drw->dpy, drw->gc);
drw_fontset_free(drw->fonts);
free(drw);
}
/* This function is an implementation detail. Library users should use
* drw_fontset_create instead.
*/
static Fnt *
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 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. */
if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) {
fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname);
return NULL;
}
if (!(pattern = FcNameParse((FcChar8 *) 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 from pattern.\n");
return NULL;
}
} else {
die("no font specified.");
}
/* Do not allow using color fonts. This is a workaround for a BadLength
* error from Xft with color glyphs. Modelled on the Xterm workaround. See
* https://bugzilla.redhat.com/show_bug.cgi?id=1498269
* https://lists.suckless.org/dev/1701/30932.html
* https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=916349
* and lots more all over the internet.
*/
FcBool iscol;
if(FcPatternGetBool(xfont->pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) {
XftFontClose(drw->dpy, xfont);
return NULL;
}
font = ecalloc(1, sizeof(Fnt));
font->xfont = xfont;
font->pattern = pattern;
font->h = xfont->ascent + xfont->descent;
font->dpy = drw->dpy;
return font;
}
static void
xfont_free(Fnt *font)
{
if (!font)
return;
if (font->pattern)
FcPatternDestroy(font->pattern);
XftFontClose(font->dpy, font->xfont);
free(font);
}
Fnt*
drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
{
Fnt *cur, *ret = NULL;
size_t i;
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_fontset_free(Fnt *font)
{
if (font) {
drw_fontset_free(font->next);
xfont_free(font);
}
}
void
drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
{
if (!drw || !dest || !clrname)
return;
if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
DefaultColormap(drw->dpy, drw->screen),
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;
/* 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_setfontset(Drw *drw, Fnt *set)
{
if (drw)
drw->fonts = set;
}
void
drw_setscheme(Drw *drw, Clr *scm)
{
if (drw)
drw->scheme = scm;
}
void
drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert)
{
if (!drw || !drw->scheme)
return;
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, 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, unsigned int lpad, const char *text, int invert)
{
char buf[1024];
int ty;
unsigned int ew;
XftDraw *d = NULL;
Fnt *usedfont, *curfont, *nextfont;
size_t i, len;
int utf8strlen, utf8charlen, render = x || y || w || h;
long utf8codepoint = 0;
const char *utf8str;
FcCharSet *fccharset;
FcPattern *fcpattern;
FcPattern *match;
XftResult result;
int charexists = 0;
if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
return 0;
if (!render) {
w = ~w;
} else {
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;
}
usedfont = drw->fonts;
while (1) {
utf8strlen = 0;
utf8str = text;
nextfont = NULL;
while (*text) {
utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ);
for (curfont = drw->fonts; curfont; curfont = curfont->next) {
charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
if (charexists) {
if (curfont == usedfont) {
utf8strlen += utf8charlen;
text += utf8charlen;
} else {
nextfont = curfont;
}
break;
}
}
if (!charexists || nextfont)
break;
else
charexists = 0;
}
if (utf8strlen) {
drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL);
/* shorten text if necessary */
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] = '.')
; /* NOP */
if (render) {
ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
usedfont->xfont, x, ty, (XftChar8 *)buf, len);
}
x += ew;
w -= ew;
}
}
if (!*text) {
break;
} else if (nextfont) {
charexists = 0;
usedfont = nextfont;
} else {
/* Regardless of whether or not a fallback font is found, the
* character must be drawn. */
charexists = 1;
fccharset = FcCharSetCreate();
FcCharSetAddChar(fccharset, utf8codepoint);
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->pattern);
FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
FcPatternAddBool(fcpattern, FC_COLOR, FcFalse);
FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
FcDefaultSubstitute(fcpattern);
match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result);
FcCharSetDestroy(fccharset);
FcPatternDestroy(fcpattern);
if (match) {
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 {
xfont_free(usedfont);
usedfont = drw->fonts;
}
}
}
}
if (d)
XftDrawDestroy(d);
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);
}
unsigned int
drw_fontset_getwidth(Drw *drw, const char *text)
{
if (!drw || !drw->fonts || !text)
return 0;
return drw_text(drw, 0, 0, 0, 0, 0, text, 0);
}
void
drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h)
{
XGlyphInfo ext;
if (!font || !text)
return;
XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext);
if (w)
*w = ext.xOff;
if (h)
*h = font->h;
}
Cur *
drw_cur_create(Drw *drw, int shape)
{
Cur *cur;
if (!drw || !(cur = ecalloc(1, sizeof(Cur))))
return NULL;
cur->cursor = XCreateFontCursor(drw->dpy, shape);
return cur;
}
void
drw_cur_free(Drw *drw, Cur *cursor)
{
if (!cursor)
return;
XFreeCursor(drw->dpy, cursor->cursor);
free(cursor);
}

View File

@ -0,0 +1,57 @@
/* See LICENSE file for copyright and license details. */
typedef struct {
Cursor cursor;
} Cur;
typedef struct Fnt {
Display *dpy;
unsigned int h;
XftFont *xfont;
FcPattern *pattern;
struct Fnt *next;
} Fnt;
enum { ColFg, ColBg }; /* Clr scheme index */
typedef XftColor Clr;
typedef struct {
unsigned int w, h;
Display *dpy;
int screen;
Window root;
Drawable drawable;
GC gc;
Clr *scheme;
Fnt *fonts;
} Drw;
/* Drawable abstraction */
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_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 *drw, int shape);
void drw_cur_free(Drw *drw, Cur *cursor);
/* Drawing context manipulation */
void drw_setfontset(Drw *drw, Fnt *set);
void drw_setscheme(Drw *drw, Clr *scm);
/* Drawing functions */
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 *drw, Window win, int x, int y, unsigned int w, unsigned int h);

View File

@ -0,0 +1,50 @@
From d0c3fc8a634c153856cd41438f705175a21ec69a Mon Sep 17 00:00:00 2001
From: braskin <benjaminiraskin@gmail.com>
Date: Thu, 12 Nov 2020 10:13:29 -0500
Subject: [PATCH] fixed border width draw for topbar
---
config.def.h | 3 +++
dmenu.c | 6 +++++-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/config.def.h b/config.def.h
index 1edb647..dd3eb31 100644
--- a/config.def.h
+++ b/config.def.h
@@ -21,3 +21,6 @@ static unsigned int lines = 0;
* for example: " /?\"&[]"
*/
static const char worddelimiters[] = " ";
+
+/* Size of the window border */
+static unsigned int border_width = 0;
diff --git a/dmenu.c b/dmenu.c
index 65f25ce..716e655 100644
--- a/dmenu.c
+++ b/dmenu.c
@@ -659,9 +659,11 @@ setup(void)
swa.override_redirect = True;
swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
- win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0,
+ win = XCreateWindow(dpy, parentwin, x, y - (topbar ? 0 : border_width * 2), mw - border_width * 2, mh, border_width,
CopyFromParent, CopyFromParent, CopyFromParent,
CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
+ if (border_width)
+ XSetWindowBorder(dpy, win, scheme[SchemeSel][ColBg].pixel);
XSetClassHint(dpy, win, &ch);
@@ -733,6 +735,8 @@ main(int argc, char *argv[])
colors[SchemeSel][ColFg] = argv[++i];
else if (!strcmp(argv[i], "-w")) /* embedding window id */
embed = argv[++i];
+ else if (!strcmp(argv[i], "-bw"))
+ border_width = atoi(argv[++i]); /* border width */
else
usage();
--
2.25.1

View File

@ -0,0 +1,120 @@
From 8cd37e1ab9e7cb025224aeb3543f1a5be8bceb93 Mon Sep 17 00:00:00 2001
From: Nihal Jere <nihal@nihaljere.xyz>
Date: Sat, 11 Jan 2020 21:16:08 -0600
Subject: [PATCH] center patch now has adjustable minimum width
---
config.def.h | 2 ++
dmenu.1 | 3 +++
dmenu.c | 39 ++++++++++++++++++++++++++++++++-------
3 files changed, 37 insertions(+), 7 deletions(-)
diff --git a/config.def.h b/config.def.h
index 1edb647..88ef264 100644
--- a/config.def.h
+++ b/config.def.h
@@ -2,6 +2,8 @@
/* Default settings; can be overriden by command line. */
static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */
+static int centered = 0; /* -c option; centers dmenu on screen */
+static int min_width = 500; /* minimum width when centered */
/* -fn option overrides fonts[0]; default X11 font or font set */
static const char *fonts[] = {
"monospace:size=10"
diff --git a/dmenu.1 b/dmenu.1
index 323f93c..c036baa 100644
--- a/dmenu.1
+++ b/dmenu.1
@@ -40,6 +40,9 @@ which lists programs in the user's $PATH and runs the result in their $SHELL.
.B \-b
dmenu appears at the bottom of the screen.
.TP
+.B \-c
+dmenu appears centered on the screen.
+.TP
.B \-f
dmenu grabs the keyboard before reading stdin if not reading from a tty. This
is faster, but will lock up X until stdin reaches end\-of\-file.
diff --git a/dmenu.c b/dmenu.c
index 65f25ce..041c7f8 100644
--- a/dmenu.c
+++ b/dmenu.c
@@ -89,6 +89,15 @@ calcoffsets(void)
break;
}
+static int
+max_textw(void)
+{
+ int len = 0;
+ for (struct item *item = items; item && item->text; item++)
+ len = MAX(TEXTW(item->text), len);
+ return len;
+}
+
static void
cleanup(void)
{
@@ -611,6 +620,7 @@ setup(void)
bh = drw->fonts->h + 2;
lines = MAX(lines, 0);
mh = (lines + 1) * bh;
+ promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
#ifdef XINERAMA
i = 0;
if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) {
@@ -637,9 +647,16 @@ setup(void)
if (INTERSECT(x, y, 1, 1, info[i]))
break;
- x = info[i].x_org;
- y = info[i].y_org + (topbar ? 0 : info[i].height - mh);
- mw = info[i].width;
+ if (centered) {
+ mw = MIN(MAX(max_textw() + promptw, min_width), info[i].width);
+ x = info[i].x_org + ((info[i].width - mw) / 2);
+ y = info[i].y_org + ((info[i].height - mh) / 2);
+ } else {
+ x = info[i].x_org;
+ y = info[i].y_org + (topbar ? 0 : info[i].height - mh);
+ mw = info[i].width;
+ }
+
XFree(info);
} else
#endif
@@ -647,11 +664,17 @@ setup(void)
if (!XGetWindowAttributes(dpy, parentwin, &wa))
die("could not get embedding window attributes: 0x%lx",
parentwin);
- x = 0;
- y = topbar ? 0 : wa.height - mh;
- mw = wa.width;
+
+ if (centered) {
+ mw = MIN(MAX(max_textw() + promptw, min_width), wa.width);
+ x = (wa.width - mw) / 2;
+ y = (wa.height - mh) / 2;
+ } else {
+ x = 0;
+ y = topbar ? 0 : wa.height - mh;
+ mw = wa.width;
+ }
}
- promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
inputw = MIN(inputw, mw/3);
match();
@@ -709,6 +732,8 @@ main(int argc, char *argv[])
topbar = 0;
else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */
fast = 1;
+ else if (!strcmp(argv[i], "-c")) /* centers dmenu on screen */
+ centered = 1;
else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */
fstrncmp = strncasecmp;
fstrstr = cistrstr;
--
2.24.1

View File

@ -0,0 +1,48 @@
From 7a045242afac6db70a4aee6e3ac0146cdb264277 Mon Sep 17 00:00:00 2001
From: Alex Cole <ajzcole@airmail.cc>
Date: Sun, 4 Oct 2020 19:58:32 +1300
Subject: [PATCH] listfullwidth patch changes
---
config.def.h | 1 +
dmenu.c | 5 +++--
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/config.def.h b/config.def.h
index 1edb647..221db00 100644
--- a/config.def.h
+++ b/config.def.h
@@ -2,6 +2,7 @@
/* Default settings; can be overriden by command line. */
static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */
+static int colorprompt = 1; /* -p option; if 1, prompt uses SchemeSel, otherwise SchemeNorm */
/* -fn option overrides fonts[0]; default X11 font or font set */
static const char *fonts[] = {
"monospace:size=10"
diff --git a/dmenu.c b/dmenu.c
index 65f25ce..f73f299 100644
--- a/dmenu.c
+++ b/dmenu.c
@@ -137,7 +137,8 @@ drawmenu(void)
drw_rect(drw, 0, 0, mw, mh, 1, 1);
if (prompt && *prompt) {
- drw_setscheme(drw, scheme[SchemeSel]);
+ if (colorprompt)
+ drw_setscheme(drw, scheme[SchemeSel]);
x = drw_text(drw, x, 0, promptw, bh, lrpad / 2, prompt, 0);
}
/* draw input field */
@@ -154,7 +155,7 @@ drawmenu(void)
if (lines > 0) {
/* draw vertical list */
for (item = curr; item != next; item = item->right)
- drawitem(item, x, y += bh, mw - x);
+ drawitem(item, 0, y += bh, mw - x);
} else if (matches) {
/* draw horizontal list */
x += inputw;
--
2.28.0

View File

@ -0,0 +1,90 @@
.TH STEST 1 dmenu\-VERSION
.SH NAME
stest \- filter a list of files by properties
.SH SYNOPSIS
.B stest
.RB [ -abcdefghlpqrsuwx ]
.RB [ -n
.IR file ]
.RB [ -o
.IR file ]
.RI [ file ...]
.SH DESCRIPTION
.B stest
takes a list of files and filters by the files' properties, analogous to
.IR test (1).
Files which pass all tests are printed to stdout. If no files are given, stest
reads files from stdin.
.SH OPTIONS
.TP
.B \-a
Test hidden files.
.TP
.B \-b
Test that files are block specials.
.TP
.B \-c
Test that files are character specials.
.TP
.B \-d
Test that files are directories.
.TP
.B \-e
Test that files exist.
.TP
.B \-f
Test that files are regular files.
.TP
.B \-g
Test that files have their set-group-ID flag set.
.TP
.B \-h
Test that files are symbolic links.
.TP
.B \-l
Test the contents of a directory given as an argument.
.TP
.BI \-n " file"
Test that files are newer than
.IR file .
.TP
.BI \-o " file"
Test that files are older than
.IR file .
.TP
.B \-p
Test that files are named pipes.
.TP
.B \-q
No files are printed, only the exit status is returned.
.TP
.B \-r
Test that files are readable.
.TP
.B \-s
Test that files are not empty.
.TP
.B \-u
Test that files have their set-user-ID flag set.
.TP
.B \-v
Invert the sense of tests, only failing files pass.
.TP
.B \-w
Test that files are writable.
.TP
.B \-x
Test that files are executable.
.SH EXIT STATUS
.TP
.B 0
At least one file passed all tests.
.TP
.B 1
No files passed all tests.
.TP
.B 2
An error occurred.
.SH SEE ALSO
.IR dmenu (1),
.IR test (1)

View File

@ -0,0 +1,109 @@
/* See LICENSE file for copyright and license details. */
#include <sys/stat.h>
#include <dirent.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "arg.h"
char *argv0;
#define FLAG(x) (flag[(x)-'a'])
static void test(const char *, const char *);
static void usage(void);
static int match = 0;
static int flag[26];
static struct stat old, new;
static void
test(const char *path, const char *name)
{
struct stat st, ln;
if ((!stat(path, &st) && (FLAG('a') || name[0] != '.') /* hidden files */
&& (!FLAG('b') || S_ISBLK(st.st_mode)) /* block special */
&& (!FLAG('c') || S_ISCHR(st.st_mode)) /* character special */
&& (!FLAG('d') || S_ISDIR(st.st_mode)) /* directory */
&& (!FLAG('e') || access(path, F_OK) == 0) /* exists */
&& (!FLAG('f') || S_ISREG(st.st_mode)) /* regular file */
&& (!FLAG('g') || st.st_mode & S_ISGID) /* set-group-id flag */
&& (!FLAG('h') || (!lstat(path, &ln) && S_ISLNK(ln.st_mode))) /* symbolic link */
&& (!FLAG('n') || st.st_mtime > new.st_mtime) /* newer than file */
&& (!FLAG('o') || st.st_mtime < old.st_mtime) /* older than file */
&& (!FLAG('p') || S_ISFIFO(st.st_mode)) /* named pipe */
&& (!FLAG('r') || access(path, R_OK) == 0) /* readable */
&& (!FLAG('s') || st.st_size > 0) /* not empty */
&& (!FLAG('u') || st.st_mode & S_ISUID) /* set-user-id flag */
&& (!FLAG('w') || access(path, W_OK) == 0) /* writable */
&& (!FLAG('x') || access(path, X_OK) == 0)) != FLAG('v')) { /* executable */
if (FLAG('q'))
exit(0);
match = 1;
puts(name);
}
}
static void
usage(void)
{
fprintf(stderr, "usage: %s [-abcdefghlpqrsuvwx] "
"[-n file] [-o file] [file...]\n", argv0);
exit(2); /* like test(1) return > 1 on error */
}
int
main(int argc, char *argv[])
{
struct dirent *d;
char path[PATH_MAX], *line = NULL, *file;
size_t linesiz = 0;
ssize_t n;
DIR *dir;
int r;
ARGBEGIN {
case 'n': /* newer than file */
case 'o': /* older than file */
file = EARGF(usage());
if (!(FLAG(ARGC()) = !stat(file, (ARGC() == 'n' ? &new : &old))))
perror(file);
break;
default:
/* miscellaneous operators */
if (strchr("abcdefghlpqrsuvwx", ARGC()))
FLAG(ARGC()) = 1;
else
usage(); /* unknown flag */
} ARGEND;
if (!argc) {
/* read list from stdin */
while ((n = getline(&line, &linesiz, stdin)) > 0) {
if (n && line[n - 1] == '\n')
line[n - 1] = '\0';
test(line, line);
}
free(line);
} else {
for (; argc; argc--, argv++) {
if (FLAG('l') && (dir = opendir(*argv))) {
/* test directory contents */
while ((d = readdir(dir))) {
r = snprintf(path, sizeof path, "%s/%s",
*argv, d->d_name);
if (r >= 0 && (size_t)r < sizeof path)
test(path, d->d_name);
}
closedir(dir);
} else {
test(*argv, *argv);
}
}
}
return match ? 0 : 1;
}

View File

@ -0,0 +1,35 @@
/* See LICENSE file for copyright and license details. */
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
void *
ecalloc(size_t nmemb, size_t size)
{
void *p;
if (!(p = calloc(nmemb, size)))
die("calloc:");
return p;
}
void
die(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
fputc(' ', stderr);
perror(NULL);
} else {
fputc('\n', stderr);
}
exit(1);
}

View File

@ -0,0 +1,8 @@
/* See LICENSE file for copyright and license details. */
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B))
void die(const char *fmt, ...);
void *ecalloc(size_t nmemb, size_t size);

View File

@ -0,0 +1,60 @@
# first read by bash on login
# colour scheme for terminal
export TERM=xterm-256color
# colour scheme for gtk applications
export GTK_THEME=Adwaita:dark
# default programs
export EDITOR="nvim"
export TERMINAL="alacritty"
export VISUAL="open_editor_in_new_shell"
export READER="zathura"
export BROWSER="firefox"
# environment variables
export XDG_CONFIG_HOME="$HOME/.config"
export XDG_CACHE_HOME="$HOME/.cache"
export XDG_DATA_HOME="$HOME/.local/share"
export XDG_RUNTIME_DIR="/run/user/1000"
export GNUPGHOME="$XDG_DATA_HOME/gnupg"
export WINEPREFIX="$XDG_DATA_HOME/wine"
export LESSHISTFILE=-
#export XAUTHORITY="$XDG_RUNTIME_DIR/Xauthority"
export XINITRC="$XDG_CONFIG_HOME/X11/xinitrc"
export XSERVERRC="$XDG_CONFIG_HOME/X11/xserverrc"
export HISTFILE="$XDG_DATA_HOME/bash/history"
export WGETRC="$XDG_CONFIG_HOME/wget/wgetrc"
export KDEHOME="$XDG_CONFIG_HOME/kde4"
export ANDROID_SDK_ROOT="$XDG_CONFIG_HOME/android"
export ADB_VENDOR_KEY="$XDG_CONFIG_HOME/android"
export SQLITE_HISTORY="$XDG_DATA_HOME/sqlite_history"
export ASPELL_CONF="per-conf $XDG_CONFIG_HOME/aspell/aspell.conf; personal $XDG_CONFIG_HOME/aspell/de.pws; repl $XDG_CONFIG_HOME/aspell/de.prepl"
export NPM_CONFIG_USERCONFIG="$XDG_CONFIG_HOME/npm/npmrc"
export TS3_CONFIG_DIR="$XDG_CONFIG_HOME/ts3client"
export XMONAD_CONFIG_HOME="$XDG_CONFIG_HOME/xmonad"
export XMONAD_DATA_HOME="$XDG_DATA_HOME/xmonad"
export XMONAD_CACHE_HOME="$XDG_CACHE_HOME/xmonad"
export RUSTUP_HOME="$XDG_DATA_HOME/rustup"
export CARGO_HOME="$XDG_DATA_HOME/cargo"
export PASSWORD_STORE_DIR="$XDG_DATA_HOME/pass"
export DVDCSS_CACHE="$XDG_DATA_HOME/dvdcss"
export DOTNET_CLI_TELEMETRY_OPTOUT=1
export ANSIBLE_HOME="$XDG_CONFIG_HOME/ansible"
export ANSIBLE_CONFIG="$XDG_CONFIG_HOME/ansible.cfg"
export ANSIBLE_GALAXY_CACHE_DIR="$XDG_CACHE_HOME/ansible/galaxy_cache"
export AZURE_CONFIG_DIR="$XDG_DATA_HOME/azure"
export NUGET_PACKAGES="$XDG_CACHE_HOME/NuGetPackages"
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi
# add private bin and its subdirectories to the $PATH
export PATH="$PATH:$XDG_DATA_HOME/cargo/bin:~/.dotnet/tools:$(du "$HOME/.local/bin" | cut -f2 | grep -v git | paste -s -d ':')"

View File

@ -0,0 +1,24 @@
MIT/X Consortium License
© 2015-2016 Markus Teich <markus.teich@stusta.mhn.de>
© 2014 Dimitris Papastamos <sin@2f30.org>
© 2006-2014 Anselm R Garbe <anselm@garbe.us>
© 2014-2016 Laslo Hunhold <dev@frign.de>
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.

View File

@ -0,0 +1,61 @@
# slock - simple screen locker
# See LICENSE file for copyright and license details.
include config.mk
SRC = slock.c ${COMPATSRC}
OBJ = ${SRC:.c=.o}
all: options slock
options:
@echo slock build options:
@echo "CFLAGS = ${CFLAGS}"
@echo "LDFLAGS = ${LDFLAGS}"
@echo "CC = ${CC}"
.c.o:
@echo CC $<
@${CC} -c ${CFLAGS} $<
${OBJ}: config.h config.mk arg.h util.h
config.h:
@echo creating $@ from config.def.h
@cp config.def.h $@
slock: ${OBJ}
@echo CC -o $@
@${CC} -o $@ ${OBJ} ${LDFLAGS}
clean:
@echo cleaning
@rm -f slock ${OBJ} slock-${VERSION}.tar.gz
dist: clean
@echo creating dist tarball
@mkdir -p 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}
install: all
@echo installing executable file to ${DESTDIR}${PREFIX}/bin
@mkdir -p ${DESTDIR}${PREFIX}/bin
@cp -f slock ${DESTDIR}${PREFIX}/bin
@chmod 755 ${DESTDIR}${PREFIX}/bin/slock
@chmod u+s ${DESTDIR}${PREFIX}/bin/slock
@echo installing manual page to ${DESTDIR}${MANPREFIX}/man1
@mkdir -p ${DESTDIR}${MANPREFIX}/man1
@sed "s/VERSION/${VERSION}/g" <slock.1 >${DESTDIR}${MANPREFIX}/man1/slock.1
@chmod 644 ${DESTDIR}${MANPREFIX}/man1/slock.1
uninstall:
@echo removing executable file from ${DESTDIR}${PREFIX}/bin
@rm -f ${DESTDIR}${PREFIX}/bin/slock
@echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
@rm -f ${DESTDIR}${MANPREFIX}/man1/slock.1
.PHONY: all options clean dist install uninstall

View File

@ -0,0 +1,24 @@
slock - simple screen locker
============================
simple screen locker utility for X.
Requirements
------------
In order to build slock you need the Xlib header files.
Installation
------------
Edit config.mk to match your local setup (slock is installed into
the /usr/local namespace by default).
Afterwards enter the following command to build and install slock
(if necessary as root):
make clean install
Running slock
-------------
Simply invoke the 'slock' command. To get out of it, enter your password.

View File

@ -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

View File

@ -0,0 +1,21 @@
/* user and group to drop privileges to */
static const char *user = "nobody";
static const char *group = "nogroup";
static const char *colorname[NUMCOLS] = {
[INIT] = "black", /* after initialization */
[INPUT] = "#005577", /* during input */
[FAILED] = "#CC3333", /* wrong password */
};
/* treat a cleared input like a wrong password (color) */
static const int failonclear = 1;
/*Enable blur*/
#define BLUR
/*Set blur radius*/
static const int blurRadius=5;
/*Enable Pixelation*/
//#define PIXELATION
/*Set pixelation radius*/
static const int pixelSize=0;

View File

@ -0,0 +1,21 @@
/* user and group to drop privileges to */
static const char *user = "max";
static const char *group = "max";
static const char *colorname[NUMCOLS] = {
[INIT] = "black", /* after initialization */
[INPUT] = "#005577", /* during input */
[FAILED] = "#CC3333", /* wrong password */
};
/* treat a cleared input like a wrong password (color) */
static const int failonclear = 1;
/*Enable blur*/
#define BLUR
/*Set blur radius*/
static const int blurRadius=7;
/*Enable Pixelation*/
/* #define PIXELATION */
/*Set pixelation radius*/
static const int pixelSize=0;

View File

@ -0,0 +1,32 @@
# slock version
VERSION = 1.4
# Customize below to fit your system
# paths
PREFIX = /usr/local
MANPREFIX = ${PREFIX}/share/man
X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib
# includes and libs
INCS = -I. -I/usr/include -I${X11INC}
LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr -lImlib2
# flags
CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_SHADOW_H
CFLAGS = -std=c99 -pedantic -Wall -Ofast ${INCS} ${CPPFLAGS}
LDFLAGS = -s ${LIBS}
COMPATSRC = explicit_bzero.c
# 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

View File

@ -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 <string.h>
__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);
}

View File

@ -0,0 +1,356 @@
From 36a4863f9a399740aaf8b1e01926485c0a055e1c Mon Sep 17 00:00:00 2001
From: Lars Niesen <iah71niesen@gso-koeln.de>
Date: Wed, 29 Apr 2020 13:52:42 +0200
Subject: [PATCH 1/8] Added Bg patch and screenshot capabilities
---
config.mk | 2 +-
slock.c | 35 +++++++++++++++++++++++++++++++----
2 files changed, 32 insertions(+), 5 deletions(-)
diff --git a/config.mk b/config.mk
index 74429ae..987819e 100644
--- a/config.mk
+++ b/config.mk
@@ -12,7 +12,7 @@ X11LIB = /usr/X11R6/lib
# includes and libs
INCS = -I. -I/usr/include -I${X11INC}
-LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr
+LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr -lImlib2
# flags
CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_SHADOW_H
diff --git a/slock.c b/slock.c
index 5ae738c..7c63f34 100644
--- a/slock.c
+++ b/slock.c
@@ -18,6 +18,7 @@
#include <X11/keysym.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
+#include <Imlib2.h>
#include "arg.h"
#include "util.h"
@@ -35,6 +36,7 @@ struct lock {
int screen;
Window root, win;
Pixmap pmap;
+ Pixmap bgmap;
unsigned long colors[NUMCOLS];
};
@@ -46,6 +48,8 @@ struct xrandr {
#include "config.h"
+Imlib_Image image;
+
static void
die(const char *errstr, ...)
{
@@ -190,9 +194,10 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens,
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]);
+ if(locks[screen]->bgmap)
+ XSetWindowBackgroundPixmap(dpy, locks[screen]->win, locks[screen]->bgmap);
+ else
+ XSetWindowBackground(dpy, locks[screen]->win, locks[screen]->colors[0]);
XClearWindow(dpy, locks[screen]->win);
}
oldc = color;
@@ -235,6 +240,17 @@ lockscreen(Display *dpy, struct xrandr *rr, int screen)
lock->screen = screen;
lock->root = RootWindow(dpy, lock->screen);
+ if(image)
+ {
+ lock->bgmap = XCreatePixmap(dpy, lock->root, DisplayWidth(dpy, lock->screen), DisplayHeight(dpy, lock->screen), DefaultDepth(dpy, lock->screen));
+ imlib_context_set_image(image);
+ imlib_context_set_display(dpy);
+ imlib_context_set_visual(DefaultVisual(dpy, lock->screen));
+ imlib_context_set_colormap(DefaultColormap(dpy, lock->screen));
+ imlib_context_set_drawable(lock->bgmap);
+ imlib_render_image_on_drawable(0, 0);
+ imlib_free_image();
+ }
for (i = 0; i < NUMCOLS; i++) {
XAllocNamedColor(dpy, DefaultColormap(dpy, lock->screen),
colorname[i], &color, &dummy);
@@ -251,6 +267,8 @@ lockscreen(Display *dpy, struct xrandr *rr, int screen)
CopyFromParent,
DefaultVisual(dpy, lock->screen),
CWOverrideRedirect | CWBackPixel, &wa);
+ if(lock->bgmap)
+ XSetWindowBackgroundPixmap(dpy, lock->win, lock->bgmap);
lock->pmap = XCreateBitmapFromData(dpy, lock->win, curs, 8, 8);
invisible = XCreatePixmapCursor(dpy, lock->pmap, lock->pmap,
&color, &color, 0, 0);
@@ -354,7 +372,16 @@ main(int argc, char **argv) {
die("slock: setgid: %s\n", strerror(errno));
if (setuid(duid) < 0)
die("slock: setuid: %s\n", strerror(errno));
-
+
+ /*Create screenshot Image*/
+ Screen *scr = ScreenOfDisplay(dpy, DefaultScreen(dpy));
+ image = imlib_create_image(scr->width,scr->height);
+ imlib_context_set_image(image);
+ imlib_context_set_display(dpy);
+ imlib_context_set_visual(DefaultVisual(dpy,0));
+ imlib_context_set_drawable(RootWindow(dpy,XScreenNumberOfScreen(scr)));
+ imlib_copy_drawable_to_image(0,0,0,scr->width,scr->height,0,0,1);
+
/* check for Xrandr support */
rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase);
--
2.27.0
From 9d89604ac52b0949d047dae2f9b78cb5085ee1a2 Mon Sep 17 00:00:00 2001
From: Lars Niesen <iah71niesen@gso-koeln.de>
Date: Wed, 29 Apr 2020 14:15:59 +0200
Subject: [PATCH 2/8] Added blur function
---
config.def.h | 3 +++
slock.c | 3 ++-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/config.def.h b/config.def.h
index c8e52d6..fcc1b39 100644
--- a/config.def.h
+++ b/config.def.h
@@ -10,3 +10,6 @@ static const char *colorname[NUMCOLS] = {
/* treat a cleared input like a wrong password (color) */
static const int failonclear = 1;
+
+/*Set Blur radius*/
+static const int blurRadius=5;
\ No newline at end of file
diff --git a/slock.c b/slock.c
index 7c63f34..0f24cd7 100644
--- a/slock.c
+++ b/slock.c
@@ -372,7 +372,7 @@ main(int argc, char **argv) {
die("slock: setgid: %s\n", strerror(errno));
if (setuid(duid) < 0)
die("slock: setuid: %s\n", strerror(errno));
-
+
/*Create screenshot Image*/
Screen *scr = ScreenOfDisplay(dpy, DefaultScreen(dpy));
image = imlib_create_image(scr->width,scr->height);
@@ -381,6 +381,7 @@ main(int argc, char **argv) {
imlib_context_set_visual(DefaultVisual(dpy,0));
imlib_context_set_drawable(RootWindow(dpy,XScreenNumberOfScreen(scr)));
imlib_copy_drawable_to_image(0,0,0,scr->width,scr->height,0,0,1);
+ imlib_image_blur(blurRadius);
/* check for Xrandr support */
rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase);
--
2.27.0
From 069aabd7e30244befd4efe74c85d3468ed076c21 Mon Sep 17 00:00:00 2001
From: Lars Niesen <iah71niesen@gso-koeln.de>
Date: Wed, 29 Apr 2020 17:33:09 +0200
Subject: [PATCH 4/8] added Pixelation
---
config.def.h | 3 ++-
slock.c | 42 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 44 insertions(+), 1 deletion(-)
diff --git a/config.def.h b/config.def.h
index fcc1b39..1c1aef3 100644
--- a/config.def.h
+++ b/config.def.h
@@ -12,4 +12,5 @@ static const char *colorname[NUMCOLS] = {
static const int failonclear = 1;
/*Set Blur radius*/
-static const int blurRadius=5;
\ No newline at end of file
+static const int blurRadius=0;
+static const int pixelSize=5;
diff --git a/slock.c b/slock.c
index 0f24cd7..33ca569 100644
--- a/slock.c
+++ b/slock.c
@@ -381,7 +381,49 @@ main(int argc, char **argv) {
imlib_context_set_visual(DefaultVisual(dpy,0));
imlib_context_set_drawable(RootWindow(dpy,XScreenNumberOfScreen(scr)));
imlib_copy_drawable_to_image(0,0,0,scr->width,scr->height,0,0,1);
+
+ /*Blur function*/
imlib_image_blur(blurRadius);
+
+
+ /*Pixelation*/
+ int width = scr->width;
+ int height = scr->height;
+
+ for(int y = 0; y < height; y += pixelSize)
+ {
+ for(int x = 0; x < width; x += pixelSize)
+ {
+ int red = 0;
+ int green = 0;
+ int blue = 0;
+
+ Imlib_Color pixel;
+ Imlib_Color* pp;
+ pp = &pixel;
+ for(int j = 0; j < pixelSize && j < height; j++)
+ {
+ for(int i = 0; i < pixelSize && i < width; i++)
+ {
+ imlib_image_query_pixel(x+i,y+j,pp);
+ red += pixel.red;
+ green += pixel.green;
+ blue += pixel.blue;
+ }
+ }
+ red /= (pixelSize*pixelSize);
+ green /= (pixelSize*pixelSize);
+ blue /= (pixelSize*pixelSize);
+ printf("R/G/B: %i/%i/%i\n",red,green,blue);
+ imlib_context_set_color(red,green,blue,pixel.alpha);
+ imlib_image_fill_rectangle(x,y,pixelSize,pixelSize);
+ red = 0;
+ green = 0;
+ blue = 0;
+ }
+ }
+
+
/* check for Xrandr support */
rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase);
--
2.27.0
From 109bac015c1c7fbf8440fb42588fe7e0e9cb5e62 Mon Sep 17 00:00:00 2001
From: Lars Niesen <iah71niesen@gso-koeln.de>
Date: Wed, 29 Apr 2020 17:42:39 +0200
Subject: [PATCH 6/8] removed debug printf
---
slock.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/slock.c b/slock.c
index 33ca569..f54c459 100644
--- a/slock.c
+++ b/slock.c
@@ -414,7 +414,6 @@ main(int argc, char **argv) {
red /= (pixelSize*pixelSize);
green /= (pixelSize*pixelSize);
blue /= (pixelSize*pixelSize);
- printf("R/G/B: %i/%i/%i\n",red,green,blue);
imlib_context_set_color(red,green,blue,pixel.alpha);
imlib_image_fill_rectangle(x,y,pixelSize,pixelSize);
red = 0;
--
2.27.0
From a13a0f4ac86f82e4dff145b7ebd93e52d07492c9 Mon Sep 17 00:00:00 2001
From: Lars Niesen <iah71niesen@gso-koeln.de>
Date: Sun, 3 May 2020 18:03:38 +0200
Subject: [PATCH 7/8] Changed compilerflag to fast
---
config.mk | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/config.mk b/config.mk
index 987819e..d0c2f01 100644
--- a/config.mk
+++ b/config.mk
@@ -16,7 +16,7 @@ LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr -lImlib2
# flags
CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_SHADOW_H
-CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
+CFLAGS = -std=c99 -pedantic -Wall -Ofast ${INCS} ${CPPFLAGS}
LDFLAGS = -s ${LIBS}
COMPATSRC = explicit_bzero.c
--
2.27.0
From 31a7001c4954606c066cc3df4318fafd6d216bcd Mon Sep 17 00:00:00 2001
From: Lars Niesen <iah71niesen@gso-koeln.de>
Date: Mon, 4 May 2020 10:00:40 +0200
Subject: [PATCH 8/8] Added defines for BLUR/PIXELATION to remove from code by
compilation
---
config.def.h | 11 ++++++++---
slock.c | 9 ++++++---
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/config.def.h b/config.def.h
index 1c1aef3..5407953 100644
--- a/config.def.h
+++ b/config.def.h
@@ -11,6 +11,11 @@ static const char *colorname[NUMCOLS] = {
/* treat a cleared input like a wrong password (color) */
static const int failonclear = 1;
-/*Set Blur radius*/
-static const int blurRadius=0;
-static const int pixelSize=5;
+/*Enable blur*/
+#define BLUR
+/*Set blur radius*/
+static const int blurRadius=5;
+/*Enable Pixelation*/
+//#define PIXELATION
+/*Set pixelation radius*/
+static const int pixelSize=0;
diff --git a/slock.c b/slock.c
index f54c459..1a4d6e3 100644
--- a/slock.c
+++ b/slock.c
@@ -381,11 +381,14 @@ main(int argc, char **argv) {
imlib_context_set_visual(DefaultVisual(dpy,0));
imlib_context_set_drawable(RootWindow(dpy,XScreenNumberOfScreen(scr)));
imlib_copy_drawable_to_image(0,0,0,scr->width,scr->height,0,0,1);
-
+
+#ifdef BLUR
+
/*Blur function*/
imlib_image_blur(blurRadius);
+#endif // BLUR
-
+#ifdef PIXELATION
/*Pixelation*/
int width = scr->width;
int height = scr->height;
@@ -423,7 +426,7 @@ main(int argc, char **argv) {
}
-
+#endif
/* check for Xrandr support */
rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase);
--
2.27.0

View File

@ -0,0 +1,39 @@
.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.

View File

@ -0,0 +1,459 @@
/* See LICENSE file for license details. */
#define _XOPEN_SOURCE 500
#if HAVE_SHADOW_H
#include <shadow.h>
#endif
#include <ctype.h>
#include <errno.h>
#include <grp.h>
#include <pwd.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <X11/extensions/Xrandr.h>
#include <X11/keysym.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <Imlib2.h>
#include "arg.h"
#include "util.h"
char *argv0;
enum {
INIT,
INPUT,
FAILED,
NUMCOLS
};
struct lock {
int screen;
Window root, win;
Pixmap pmap;
Pixmap bgmap;
unsigned long colors[NUMCOLS];
};
struct xrandr {
int active;
int evbase;
int errbase;
};
#include "config.h"
Imlib_Image image;
static void
die(const char *errstr, ...)
{
va_list ap;
va_start(ap, errstr);
vfprintf(stderr, errstr, ap);
va_end(ap);
exit(1);
}
#ifdef __linux__
#include <fcntl.h>
#include <linux/oom.h>
static void
dontkillme(void)
{
FILE *f;
const char oomfile[] = "/proc/self/oom_score_adj";
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
static const char *
gethash(void)
{
const char *hash;
struct passwd *pw;
/* Check if the current user has a password entry */
errno = 0;
if (!(pw = getpwuid(getuid()))) {
if (errno)
die("slock: getpwuid: %s\n", strerror(errno));
else
die("slock: cannot retrieve password entry\n");
}
hash = pw->pw_passwd;
#if HAVE_SHADOW_H
if (!strcmp(hash, "x")) {
struct spwd *sp;
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;
}
#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 */
return hash;
}
static void
readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens,
const char *hash)
{
XRRScreenChangeNotifyEvent *rre;
char buf[32], passwd[256], *inputhash;
int num, screen, running, failure, oldc;
unsigned int len, color;
KeySym ksym;
XEvent ev;
len = 0;
running = 1;
failure = 0;
oldc = INIT;
while (running && !XNextEvent(dpy, &ev)) {
if (ev.type == KeyPress) {
explicit_bzero(&buf, sizeof(buf));
num = XLookupString(&ev.xkey, buf, sizeof(buf), &ksym, 0);
if (IsKeypadKey(ksym)) {
if (ksym == XK_KP_Enter)
ksym = XK_Return;
else if (ksym >= XK_KP_0 && ksym <= XK_KP_9)
ksym = (ksym - XK_KP_0) + XK_0;
}
if (IsFunctionKey(ksym) ||
IsKeypadKey(ksym) ||
IsMiscFunctionKey(ksym) ||
IsPFKey(ksym) ||
IsPrivateKeypadKey(ksym))
continue;
switch (ksym) {
case XK_Return:
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 = 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)
passwd[len--] = '\0';
break;
default:
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);
if (running && oldc != color) {
for (screen = 0; screen < nscreens; screen++) {
if(locks[screen]->bgmap)
XSetWindowBackgroundPixmap(dpy, locks[screen]->win, locks[screen]->bgmap);
else
XSetWindowBackground(dpy, locks[screen]->win, locks[screen]->colors[0]);
XClearWindow(dpy, locks[screen]->win);
}
oldc = color;
}
} 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);
XClearWindow(dpy, locks[screen]->win);
}
}
} else for (screen = 0; screen < nscreens; screen++)
XRaiseWindow(dpy, locks[screen]->win);
}
}
static struct lock *
lockscreen(Display *dpy, struct xrandr *rr, int screen)
{
char curs[] = {0, 0, 0, 0, 0, 0, 0, 0};
int i, ptgrab, kbgrab;
struct lock *lock;
XColor color, dummy;
XSetWindowAttributes wa;
Cursor invisible;
if (dpy == NULL || screen < 0 || !(lock = malloc(sizeof(struct lock))))
return NULL;
lock->screen = screen;
lock->root = RootWindow(dpy, lock->screen);
if(image)
{
lock->bgmap = XCreatePixmap(dpy, lock->root, DisplayWidth(dpy, lock->screen), DisplayHeight(dpy, lock->screen), DefaultDepth(dpy, lock->screen));
imlib_context_set_image(image);
imlib_context_set_display(dpy);
imlib_context_set_visual(DefaultVisual(dpy, lock->screen));
imlib_context_set_colormap(DefaultColormap(dpy, lock->screen));
imlib_context_set_drawable(lock->bgmap);
imlib_render_image_on_drawable(0, 0);
imlib_free_image();
}
for (i = 0; i < NUMCOLS; i++) {
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);
if(lock->bgmap)
XSetWindowBackgroundPixmap(dpy, lock->win, lock->bgmap);
lock->pmap = XCreateBitmapFromData(dpy, lock->win, curs, 8, 8);
invisible = XCreatePixmapCursor(dpy, lock->pmap, lock->pmap,
&color, &color, 0, 0);
XDefineCursor(dpy, lock->win, invisible);
/* 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);
}
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);
}
/* 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)
{
die("usage: slock [-v] [cmd [arg ...]]\n");
}
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;
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
hash = gethash();
errno = 0;
if (!crypt("", hash))
die("slock: crypt: %s\n", strerror(errno));
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));
/*Create screenshot Image*/
Screen *scr = ScreenOfDisplay(dpy, DefaultScreen(dpy));
image = imlib_create_image(scr->width,scr->height);
imlib_context_set_image(image);
imlib_context_set_display(dpy);
imlib_context_set_visual(DefaultVisual(dpy,0));
imlib_context_set_drawable(RootWindow(dpy,XScreenNumberOfScreen(scr)));
imlib_copy_drawable_to_image(0,0,0,scr->width,scr->height,0,0,1);
#ifdef BLUR
/*Blur function*/
imlib_image_blur(blurRadius);
#endif // BLUR
#ifdef PIXELATION
/*Pixelation*/
int width = scr->width;
int height = scr->height;
for(int y = 0; y < height; y += pixelSize)
{
for(int x = 0; x < width; x += pixelSize)
{
int red = 0;
int green = 0;
int blue = 0;
Imlib_Color pixel;
Imlib_Color* pp;
pp = &pixel;
for(int j = 0; j < pixelSize && j < height; j++)
{
for(int i = 0; i < pixelSize && i < width; i++)
{
imlib_image_query_pixel(x+i,y+j,pp);
red += pixel.red;
green += pixel.green;
blue += pixel.blue;
}
}
red /= (pixelSize*pixelSize);
green /= (pixelSize*pixelSize);
blue /= (pixelSize*pixelSize);
imlib_context_set_color(red,green,blue,pixel.alpha);
imlib_image_fill_rectangle(x,y,pixelSize,pixelSize);
red = 0;
green = 0;
blue = 0;
}
}
#endif
/* 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 = 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, 0);
/* did we manage to lock everything? */
if (nlocks != nscreens)
return 1;
/* 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. Wait for the correct password */
readpw(dpy, &rr, locks, nscreens, hash);
return 0;
}

View File

@ -0,0 +1,2 @@
#undef explicit_bzero
void explicit_bzero(void *, size_t);

View File

@ -1,7 +1,7 @@
Config { font = "xft:Iosevka-Regular:size=11:antialias=true"
Config { font = "Iosevka Normal 11"
, bgColor = "#3f3f3f"
, fgColor = "#dcdccc"
, position = Top
, position = TopH 22
, border = FullB
, borderColor = "#dcdccc"
, lowerOnStart = True

View File

@ -1,42 +1,49 @@
{-# LANGUAGE BlockArguments #-}
-- Imports
-- imports
import XMonad
import Data.Monoid
import System.Exit
import XMonad.Util.Run
import XMonad.Util.SpawnOnce
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.ManageDocks
import XMonad.Layout.Spacing
import XMonad.Layout.ThreeColumns
import XMonad.Layout.LayoutModifier
import XMonad.Layout.Renamed
import XMonad.Hooks.SetWMName
import XMonad.Util.Cursor
import XMonad.Layout.NoBorders
import XMonad.Layout.PerWorkspace
import XMonad.Layout.LimitWindows
import XMonad.Hooks.EwmhDesktops
import XMonad.Util.EZConfig
import XMonad.Util.NamedScratchpad
import XMonad.Actions.TopicSpace
import XMonad.Prompt
import XMonad.Prompt.FuzzyMatch
import XMonad.Prompt.Workspace
import XMonad.Hooks.WorkspaceHistory (workspaceHistoryHook)
import XMonad.Hooks.DynamicProperty
import qualified XMonad.StackSet as W
import qualified Data.Map as M
import Text.Regex.Posix
import XMonad.Actions.TopicSpace (TopicConfig (..), TopicItem (..), noAction, tiDirs, tiActions, currentTopicDir, switchNthLastFocusedByScreen, switchTopic, topicNames)
import XMonad.Actions.Search (SearchEngine, openstreetmap, hackage, wikipedia, youtube, searchEngine, promptSearch, selectSearch)
import XMonad.Hooks.DynamicLog (PP(..), dynamicLogWithPP, filterOutWsPP, xmobarPP, xmobarColor, wrap, shorten)
import XMonad.Hooks.ManageDocks (ToggleStruts(..), avoidStruts, docks)
import XMonad.Hooks.DynamicProperty (dynamicPropertyChange)
import XMonad.Hooks.SetWMName (setWMName)
import XMonad.Hooks.WorkspaceHistory (workspaceHistoryHook)
import XMonad.Layout.Spacing (Spacing, spacingRaw, Border (..))
import XMonad.Layout.LayoutModifier (ModifiedLayout)
import XMonad.Layout.Renamed (renamed, Rename (..))
import XMonad.Layout.NoBorders (noBorders, smartBorders)
import XMonad.Util.WorkspaceCompare ( getSortByIndex, filterOutWs )
import XMonad.Util.NamedScratchpad (NamedScratchpad (NS), customFloating, defaultFloating, namedScratchpadAction, namedScratchpadManageHook)
import XMonad.Util.Run (proc, inProgram, termInDir, (>-$), (>->), execute, spawnPipe, spawnExternalProcess, hPutStrLn)
import XMonad.Util.Cursor (setDefaultCursor)
import XMonad.Util.SpawnOnce (spawnOnce)
import XMonad.Util.EZConfig (additionalKeysP)
import XMonad.Prompt (XPConfig (..), mkXPrompt, mkComplFunFromList', XPPosition (..))
import XMonad.Prompt.Workspace (Wor(..))
import XMonad.Prompt.FuzzyMatch (fuzzyMatch, fuzzySort)
import XMonad.Prompt.Shell (shellPrompt, unsafePrompt)
import Text.Regex.Posix ((=~))
-- variables
myTerminal = "alacritty"
myBrowser = "librewolf"
myBorderWidth = 1
myNormalBorderColor = "#dcdccc"
myFocusedBorderColor = "#dca3a3"
myModMask = mod4Mask
white = "#dcdccc"
yellow = "#efef8f"
orange = "#ffcfaf"
red = "#dca3a3"
blue = "#8cd0d3"
darkBlue = "#8c8cbc"
green = "#7f9f7f"
grey = "#3f3f3f"
darkGrey = "#262626"
-- scratchpads
myScratchpads :: [NamedScratchpad]
@ -47,9 +54,11 @@ myScratchpads =
, NS "vimwiki" "st -t vimwiki -e vwwrapper" (title =? "vimwiki") (customFloating $ W.RationalRect (1/6) (1/6) (2/3) (2/3))
, NS "keepassxc" "keepassxc ~/dokumente/Database.kdbx" (title =? "Database.kdbx - KeePassXC" <||> title =? "Database.kdbx [Gesperrt] - KeePassXC") defaultFloating
, NS "discord" "firejail discord" (title *!? "Discord") (customFloating $ W.RationalRect (1/10) (1/10) (8/10) (8/10))
, NS "qalculate" "qalculate-gtk" (title =? "Qalculate!") (customFloating $ W.RationalRect (3/6) (1/6) (1/6) (1/6))
, NS "pavucontrol" "pavucontrol" (title =? "Lautstärkeregler") (customFloating $ W.RationalRect (1/6) (1/6) (2/3) (2/3))
]
-- Topic Space
-- topic space
topicItems :: [TopicItem]
topicItems =
[ noAction "1" "~/"
@ -57,7 +66,7 @@ topicItems =
, noAction "3" "~/"
, noAction "4" "~/"
, noAction "5" "~/"
, TI "recipes" "~/projekte/recipes" (switchToLayout "Programming" *> spawnShellAndExecute "hugo server" *> proc (inProgram "librewolf") *> spawnEditor)
, TI "recipes" "~/projekte/recipes" (switchToLayout "Programming" *> spawnShellAndExecute "hugo server" *> proc (inProgram myBrowser) *> spawnEditor)
, TI "alkaa" "~/projekte/alkaa" (switchToLayout "Programming" *> spawnShell *> spawnEditor)
, TI "steam" "~" (switchToLayout "Steam" *> spawn "steam")
, TI "game" "~" (switchToLayout "Full")
@ -69,8 +78,8 @@ myTopicConfig :: TopicConfig
myTopicConfig = def
{ topicDirs = tiDirs topicItems
, topicActions = tiActions topicItems
, defaultTopicAction = const (pure ()) -- by default, do nothing
, defaultTopic = "1" -- fallback
, defaultTopicAction = const (pure ())
, defaultTopic = "1"
}
spawnShell :: X ()
@ -97,24 +106,41 @@ myWorkSpacePrompt c job = do ws <- gets (W.workspaces . windowset)
topicPrompt :: XPConfig
topicPrompt = def
{ historySize = 20 -- No history in the prompt.
, fgColor = "#dcdccc"
, fgHLight = "#3f3f3f"
, bgHLight = "#dca3a3"
, alwaysHighlight = True -- Current best match
{ historySize = 0
, fgColor = white
, fgHLight = grey
, bgHLight = red
, alwaysHighlight = True
, font = "xft:Iosevka-11"
, height = 25
, position = Top
, promptBorderWidth = myBorderWidth -- Fit in with rest of config
, borderColor = "#dca3a3"
, maxComplRows = Just 5 -- Max rows to show in completion window
, position = CenteredAt 0.45 0.3
, promptBorderWidth = myBorderWidth
, borderColor = red
, maxComplRows = Just 10
, maxComplColumns = Just 1
, searchPredicate = fuzzyMatch
, sorter = fuzzySort
}
-- search
searx :: SearchEngine
searx = searchEngine "searx" "https://search.tfld.de/search?q="
wiktionary :: SearchEngine
wiktionary = searchEngine "wiktionary" "https://wiktionary.org/w/index.php?search="
searchList :: [(String, SearchEngine)]
searchList = [ ("o", openstreetmap)
, ("h", hackage)
, ("w", wikipedia)
, ("y", youtube)
, ("s", searx)
, ("t", wiktionary)
]
-- keybindings
myAdditionalKeys :: [(String, X ())]
myAdditionalKeys =
myAdditionalKeys =
-- xmonad specific
[ ("M-q", spawn "xmonad --recompile; xmonad --restart")
, ("M-S-c", kill)
@ -129,8 +155,8 @@ myAdditionalKeys =
, ("M-.", sendMessage ToggleStruts)
-- dmenu prompts
, ("M-<Return>", spawn "dm-recent-aliases")
, ("M-p s", spawn "dm-screenshot")
, ("M-<Return>", spawn "dmenu_run")
, ("M-p s", spawn "dmenu_scrreenshot")
, ("M-p k", spawn "dm-kill")
-- scratchpads
@ -141,14 +167,16 @@ myAdditionalKeys =
, ("M-S-a", namedScratchpadAction myScratchpads "keepassxc")
, ("M-n", namedScratchpadAction myScratchpads "nnn")
, ("M-s a", namedScratchpadAction myScratchpads "pavucontrol")
, ("M-s q", namedScratchpadAction myScratchpads "qalculate")
-- some shortcuts for prorgrams
, ("M-S-<Return>", spawnShell)
, ("M-b", spawn "librewolf")
, ("M-b", spawn myBrowser)
-- layout
, ("M-t t", switchToLayout "Tall")
, ("M-t h", switchToLayout "Programming")
, ("M-t p", switchToLayout "Programming")
, ("M-t f", switchToLayout "Full")
, ("M-S-f", withFocused $ windows . W.sink)
@ -175,17 +203,20 @@ myAdditionalKeys =
| (i, k) <- zip (topicNames topicItems) (map show [1 .. 5 :: Int])
, (f, m) <- [(switchTopic myTopicConfig, ""), (windows . W.shift, "S-")]
]
-- Search commands
++ [("M-d " ++ k, promptSearch topicPrompt f) | (k,f) <- searchList ]
++ [("M-S-d " ++ k, selectSearch f) | (k,f) <- searchList ]
-- Layouts
mySpacing :: Integer -> l a -> XMonad.Layout.LayoutModifier.ModifiedLayout Spacing l a
mySpacing :: Integer -> l a -> ModifiedLayout Spacing l a
mySpacing i = spacingRaw True (Border i i i i) True (Border i i i i) True
myLayout = avoidStruts $ tiling ||| hacking ||| full ||| steam
where
tiling = renamed [Replace "Tall"] $ smartBorders $ mySpacing 6 $ Tall 1 (3/100) (1/2)
tiling = renamed [Replace "Tall"] $ smartBorders $ mySpacing 6 $ Tall 1 (3/100) (1/2)
hacking = renamed [Replace "Programming"] $ smartBorders $ mySpacing 6 $ Tall 1 (3/100) (5/8)
full = noBorders Full
steam = renamed [Replace "Steam"] $ noBorders $ mySpacing 3 $ limitWindows 2 $ ThreeCol 1 (3/100) (5/8)
steam = renamed [Replace "Steam"] $ noBorders $ mySpacing 3 $ Tall 1 (3/100) (6/8)
-- Regex lifted up to use in manageHook
(*!?) :: Functor f => f String -> String -> f Bool
@ -199,7 +230,7 @@ myManageHook = composeAll . concat $
-- Steam and games
, [ className =? "Steam" --> doShift "steam" ]
, [ ( className =? "Steam" <&&> title *!? "Friends List" <||> title *!? "News" ) --> doF W.swapDown ]
, [ (title *!? "Friends List" <||> title *!? "News" ) --> doF W.swapDown ]
, [ title =? t <&&> title *!? t --> doShift "game" | t <- myGames ]
-- float specific classes
@ -213,15 +244,6 @@ myManageHook = composeAll . concat $
myFloatingClasses = ["Gimp", "Origin"]
myGames = ["Grim Dawn", "Der Herr der Ringe Online™", "Dota 2", "Project Zomboid", "Valheim", "Factorio", "Path of Exile", "Paradox Launcher", "Europa Universalis IV", "Bannerlord"]
------------------------------------------------------------------------
-- Event handling
-- * EwmhDesktops users should change this to ewmhDesktopsEventHook
--
-- Defines a custom handler function for X Events. The function should
-- return (All True) if the default handler is to be run afterwards. To
-- combine event hooks use mappend or mconcat from Data.Monoid.
--
myEventHook = dynamicPropertyChange "WM_NAME" (title =? "Database.kdbx - KeePassXC" <||> title =? "Database.kdbx [Gesperrt] - KeePassXC" --> floating)
where floating = customFloating $ W.RationalRect (1/8) (1/8) (3/4) (3/4)
@ -229,30 +251,28 @@ myEventHook = dynamicPropertyChange "WM_NAME" (title =? "Database.kdbx - KeePass
myStartupHook = do
setWMName "LG3D"
setDefaultCursor xC_left_ptr
spawnOnce("redshift -c /home/max/.config/redshift/redshiftrc")
spawnOnce("feh --bg-fill ~/bilder/bg.jpg")
spawnOnce("/usr/bin/syncthing -no-browser -logfile=default")
spawnOnce "redshift -c /home/max/.config/redshift/redshiftrc"
spawnOnce "feh --bg-fill ~/bilder/bg.jpg"
spawnOnce "/usr/bin/syncthing -no-browser -logfile=default"
-- Main
main = do
xmproc <- spawnPipe "xmobar /home/max/.config/xmobar/xmobarrc"
xmonad $ spawnExternalProcess def $ docks $ def {
-- simple stuff
terminal = myTerminal,
borderWidth = myBorderWidth,
modMask = myModMask,
workspaces = topicNames topicItems,
normalBorderColor = myNormalBorderColor,
focusedBorderColor = myFocusedBorderColor,
-- hooks, layouts
normalBorderColor = white,
focusedBorderColor = red,
layoutHook = myLayout,
manageHook = myManageHook,
handleEventHook = myEventHook,
logHook = workspaceHistoryHook >> (dynamicLogWithPP $ filterOutWsPP ["NSP"] $ xmobarPP {
ppCurrent = xmobarColor "#dca3a3" "" . wrap "[ " " ]",
ppHidden = xmobarColor "#8cd0d3" "",
ppLayout = xmobarColor "#8c8cbc" "",
ppTitle = xmobarColor "#ffcfaf" "" . shorten 100,
logHook = workspaceHistoryHook >> dynamicLogWithPP (filterOutWsPP ["NSP"] $ xmobarPP {
ppCurrent = xmobarColor red "" . wrap "[ " " ]",
ppHidden = xmobarColor blue "",
ppLayout = xmobarColor darkBlue "",
ppTitle = xmobarColor orange "" . shorten 90,
ppSep = " | ",
ppOutput = hPutStrLn xmproc
}),

View File

@ -42,6 +42,8 @@ import Text.Regex.Posix
import XMonad.Util.WorkspaceCompare ( getSortByIndex, filterOutWs )
import Data.Maybe (fromMaybe)
import qualified XMonad.Actions.Search as S
import qualified XMonad.Prompt as P
-- colours
white :: String = "#dcdccc"
@ -67,6 +69,7 @@ myScratchpads =
, NS "vimwiki" "alacritty -t vimwiki -e vwwrapper" (title =? "vimwiki") (customFloating $ W.RationalRect (1/6) (1/6) (2/3) (2/3))
, NS "pavucontrol" "pavucontrol" (title =? "Lautstärkeregler") (customFloating $ W.RationalRect (1/6) (1/6) (2/3) (2/3))
, NS "cmus" "alacritty -t 'cmus' -e cmus" (title =? "cmus") (customFloating $ W.RationalRect (1/6) (1/6) (2/3) (2/3))
, NS "qalculate" "qalculate-gtk" (title =? "Qalculate!") (customFloating $ W.RationalRect (3/6) (1/6) (1/6) (1/6))
]
-- Topic Space
@ -137,6 +140,20 @@ topicPrompt = def
, sorter = fuzzySort
}
searx :: S.SearchEngine
searx = S.searchEngine "searx" "https://search.tfld.de/search?q="
wiktionary :: S.SearchEngine
wiktionary = S.searchEngine "wiktionary" "https://wiktionary.org/w/index.php?search="
searchList :: [(String, S.SearchEngine)]
searchList = [ ("o", S.openstreetmap)
, ("h", S.hackage)
, ("w", S.wikipedia)
, ("y", S.youtube)
, ("s", searx)
, ("t", wiktionary)
]
-- custom keybinds
myAdditionalKeys :: [(String, X ())]
@ -155,10 +172,9 @@ myAdditionalKeys =
, ("M-.", sendMessage ToggleStruts)
-- dmenu prompts
, ("M-<Return>", spawn "dm-recent-aliases")
, ("M-p s", spawn "dm-screenshot")
, ("M-<Return>", spawn "dmenu_run")
, ("M-p s", spawn "dmenu_screenshot")
, ("M-p k", spawn "dm-kill")
, ("M-p p", shellPrompt topicPrompt)
-- scratchpads
, ("M-n", namedScratchpadAction myScratchpads "nnn")
@ -166,6 +182,7 @@ myAdditionalKeys =
, ("M-s v", namedScratchpadAction myScratchpads "vimwiki")
, ("M-s a", namedScratchpadAction myScratchpads "pavucontrol")
, ("M-s c", namedScratchpadAction myScratchpads "cmus")
, ("M-s q", namedScratchpadAction myScratchpads "qalculate")
-- open terminal
, ("M-S-<Return>", spawnShell)
@ -199,6 +216,10 @@ myAdditionalKeys =
| (i, k) <- zip (topicNames topicItems) (map show [1 .. 5 :: Int])
, (f, m) <- [(switchTopic myTopicConfig, ""), (windows . W.shift, "S-")]
]
-- Search commands
++ [("M-d " ++ k, S.promptSearch topicPrompt f) | (k,f) <- searchList ]
++ [("M-S-d " ++ k, S.selectSearch f) | (k,f) <- searchList ]
-- Layouts
mySpacing :: Integer -> l a -> XMonad.Layout.LayoutModifier.ModifiedLayout Spacing l a
@ -269,7 +290,7 @@ myStartupHook = do
main = do
xmproc0 <- spawnPipe "xmobar -x 0 /home/max/.config/xmobar/xmobarrc"
xmproc1 <- spawnPipe "xmobar -x 1 /home/max/.config/xmobar/xmobarrc"
xmonad $ spawnExternalProcess def $ docks def {
xmonad $ ewmh . spawnExternalProcess def $ docks def {
-- simple stuff
terminal = myTerminal,
borderWidth = myBorderWidth,

View File

@ -9,9 +9,16 @@
- dunst
- redshift
- cmus
- lightdm
- lightdm-gtk-greeter
- nnn
- tar
- zip
- unzip
- unrar
state: present
become: true
tags: pc
tags: [pc, setup]
- name: Install t460p specifig packages
ansible.builtin.package:
@ -20,10 +27,35 @@
- pamixer
- brightnessctl
state: present
tags: t460p
tags: [t460p, setup]
# - name: Build and install custom st, dmenu and slock
# tags: pc
- name: Build and install dmenu
community.general.make:
chdir: "{{ role_path }}/files/dmenu"
target: install
become: true
tags: [pc, setup]
- name: Cleanup built dmenu artifacts
community.general.make:
chdir: "{{ role_path }}/files/dmenu"
target: clean
become: true
tags: [pc, setup]
- name: Build and install slock
community.general.make:
chdir: "{{ role_path }}/files/slock"
target: install
become: true
tags: [pc, setup]
- name: Cleanup built slock artifacts
community.general.make:
chdir: "{{ role_path }}/files/slock"
target: clean
become: true
tags: [pc, setup]
- name: Create config directories
ansible.builtin.file:
@ -35,7 +67,7 @@
- ~/.config/xmobar
- ~/.config/dunst
- ~/.config/cmus
tags: pc
tags: [pc, setup]
- name: Copy over alacritty config
ansible.builtin.copy:
@ -51,6 +83,13 @@
mode: '0644'
tags: pc
- name: Copy over dircolours
ansible.builtin.copy:
src: dircolours
dest: ~/.config/dircolours
mode: '0644'
tags: pc
- name: Copy over cmus config
ansible.builtin.copy:
src: "{{ item }}"
@ -59,6 +98,28 @@
with_fileglob: "cmus/*"
tags: pc
- name: Create nnn config directory
ansible.builtin.file:
path: "~/.config/nnn"
state: directory
mode: '0755'
tags: [pc, setup]
- name: Clone nnn repository into temp
ansible.builtin.git:
repo: https://github.com/jarun/nnn.git
force: true
dest: /tmp/nnn
tags: [pc, setup]
- name: Move nnn plugins into right place
ansible.builtin.copy:
remote_src: true
src: /tmp/nnn/plugins
dest: ~/.config/nnn/plugins
mode: '0755'
tags: [pc, setup]
- name: Copy over T460p config files
ansible.builtin.copy:
src: "{{ item.src }}"
@ -67,6 +128,8 @@
with_items:
- { src: xmonad_t460p.hs, dest: ~/.config/xmonad/xmonad.hs }
- { src: xmobarrc_t460p, dest: ~/.config/xmobar/xmobarrc }
- { src: bashrc_t460p, dest: ~/.bashrc }
- { src: profile_t460p, dest: ~/.profile }
tags: t460p
- name: Copy over qwerty config files
@ -78,3 +141,10 @@
- { src: xmonad_qwerty.hs, dest: ~/.config/xmonad/xmonad.hs }
- { src: xmobarrc_qwerty, dest: ~/.config/xmobar/xmobarrc }
tags: qwerty
- name: Enable Lightdm
ansible.builtin.service:
name: lightdm
state: started
enabled: true
tags: [pc, setup]

View File

@ -2,6 +2,7 @@
- name: Dotfile Playbook
connection: local
hosts: localhost
gather_facts: false
tasks:
- name: Nvim role
ansible.builtin.include_role: