moving software to separate submodules part 1

This commit is contained in:
2023-09-18 22:18:15 +02:00
parent 9bbc679b81
commit 0a3a7b1d15
413 changed files with 178 additions and 26325 deletions

5
desktop/.dmenu/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
*.o
config.h
patches.h
dmenu
stest

30
desktop/.dmenu/LICENSE Normal file
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-2022 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.

67
desktop/.dmenu/Makefile Normal file
View File

@@ -0,0 +1,67 @@
# 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 $@
patches.h:
cp patches.def.h $@
$(OBJ): arg.h config.h config.mk drw.h patches.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

24
desktop/.dmenu/README Normal file
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.

260
desktop/.dmenu/README.md Normal file
View File

@@ -0,0 +1,260 @@
Similar to [dwm-flexipatch](https://github.com/bakkeby/dwm-flexipatch) this dmenu 5.2 (e42c036,
2022-10-26) project has a different take on patching. It uses preprocessor directives to decide
whether or not to include a patch during build time. Essentially this means that this build, for
better or worse, contains both the patched _and_ the original code. The aim being that you can
select which patches to include and the build will contain that code and nothing more.
For example to include the `alpha` patch then you would only need to flip this setting from 0
to 1 in [patches.h](https://github.com/bakkeby/dmenu-flexipatch/blob/master/patches.def.h):
```c
#define ALPHA_PATCH 1
```
Once you have found out what works for you and what doesn't then you should be in a better position
to choose patches should you want to start patching from scratch.
Alternatively if you have found the patches you want, but don't want the rest of the flexipatch
entanglement on your plate then you may want to have a look at
[flexipatch-finalizer](https://github.com/bakkeby/flexipatch-finalizer); a custom pre-processor
tool that removes all the unused flexipatch code leaving you with a build that contains the patches
you selected.
Refer to [https://tools.suckless.org/dmenu/](https://tools.suckless.org/dmenu/) for details on
dmenu, how to install it and how it works.
Browsing patches? There is a [map of patches](https://coggle.it/diagram/YjT2DD6jBM9dayf3) diagram which tries to organise patches into categories.
---
### Changelog:
2022-09-05 - Removed the json patch due to maintenance and compatibility reasons, added the
separator patch
2022-09-04 - Added the fzfexpect patch
2022-06-21 - Adding barpadding patch and relative input width patch
2022-03-02 - Bump to 5.1
2021-05-23 - Adding support for `ctrl+v` to paste and adding emoji-highlight patch
2021-05-17 - Added the restrict return, no sort, gridnav and plain-prompt (listfullwidth) patches
2021-05-15 - Added the tsv and printindex patches
2020-08-08 - Added the json, symbols, managed, morecolor, multi-selection and preselect patches
2020-08-05 - Added the grid, highlight, highpriority, dynamic options and numbers patches
2020-06-13 - Added the pango patch
2020-06-10 - Added the case-insensitive patch
2020-05-29 - Added the alpha patch (derived from Baitinq's [build](https://github.com/Baitinq/dmenu))
and the color emoji patch
2020-04-05 - Added fuzzyhighlight patch
2020-02-09 - Added revised border patch (adding command line parameter for setting border width)
2019-12-29 - Added xresources patch
2019-10-16 - Introduced [flexipatch-finalizer](https://github.com/bakkeby/flexipatch-finalizer)
2019-09-18 - Added border, center, fuzzymatch, incremental, initialtext, instant, line-height,
mouse-support, navhistory, non-blocking-stdin, password, pipeout, printinputtext,
rejectnomatch, scroll, vertfull, wmtype and xyw patches
### Patches included:
- [alpha](https://github.com/bakkeby/patches/blob/master/dmenu/dmenu-alpha-5.0_20210725_523aa08.diff)
- adds transparency for the dmenu window
- [barpadding](https://github.com/bakkeby/patches/wiki/barpadding)
- adds padding for dmenu in similar fashion to the [barpadding](https://dwm.suckless.org/patches/barpadding/)
patch for dwm
- [border](http://tools.suckless.org/dmenu/patches/border/)
- adds a border around the dmenu window
- [case-insensitive](http://tools.suckless.org/dmenu/patches/case-insensitive/)
- makes dmenu case-insensitive by default, replacing the case-insensitive `-i` option with a
case sensitive `-s` option
- [center](https://tools.suckless.org/dmenu/patches/center/)
- this patch centers dmenu in the middle of the screen
- color_emoji
- enables color emoji in dmenu by removing a workaround for a BadLength error in the Xft
library when color glyphs are used
- enabling this will crash dmenu on encountering such glyphs unless you also have an updated
Xft library that can handle them
- [dynamic_options](https://tools.suckless.org/dmenu/patches/dynamicoptions/)
- adds a flag (`-dy`) which makes dmenu run the command given to it whenever input is changed
with the current input as the last argument and update the option list according to the
output of that command
- [emoji-highlight](https://tools.suckless.org/dmenu/patches/emoji-highlight/)
- this patch will allow for emojis on the left side with a colored background when selected
- [fuzzyhighlight](https://tools.suckless.org/dmenu/patches/fuzzyhighlight/)
- intended to be combined with the fuzzymatch patch, this makes it so that fuzzy matches are
highlighted
- [fuzzymatch](https://tools.suckless.org/dmenu/patches/fuzzymatch/)
- adds support for fuzzy-matching to dmenu, allowing users to type non-consecutive portions
of the string to be matched
- [fzfexpect](https://github.com/DAFF0D11/dafmenu/blob/master/patches/dmenu-fzfexpect-5.1.diff)
- adds fzf expect functionality in dmenu
- [grid](https://tools.suckless.org/dmenu/patches/grid/)
- allows dmenu's entries to be rendered in a grid by adding a new `-g` flag to specify the
number of grid columns
- the `-g` and `-l` options can be used together to create a G columns * L lines grid
- [gridnav](https://tools.suckless.org/dmenu/patches/gridnav/)
- adds the ability to move left and right through a grid (when using the grid patch)
- [highlight](https://tools.suckless.org/dmenu/patches/highlight/)
- this patch highlights the individual characters of matched text for each dmenu list entry
- [highpriority](https://tools.suckless.org/dmenu/patches/highpriority/)
- this patch will automatically sort the search result so that high priority items are shown
first
- [incremental](https://tools.suckless.org/dmenu/patches/incremental/)
- this patch causes dmenu to print out the current text each time a key is pressed
- [initialtext](https://tools.suckless.org/dmenu/patches/initialtext/)
- adds an option to provide preselected text
- [instant](https://tools.suckless.org/dmenu/patches/instant/)
- adds a flag that will cause dmenu to select an item immediately if there is only one
matching option left
- [~json~](https://tools.suckless.org/dmenu/patches/json/)
- ~adds basic support for json files~
- [line-height](http://tools.suckless.org/dmenu/patches/line-height/)
- adds a `-h` option which sets the minimum height of a dmenu line
- this helps integrate dmenu with other UI elements that require a particular vertical size
- [managed](https://tools.suckless.org/dmenu/patches/managed/)
- adds a `-wm` flag which sets override_redirect to false; thus letting your window manager
manage the dmenu window
- this may be helpful in contexts where you don't want to exclusively bind dmenu or want to
treat dmenu more as a "window" rather than as an overlay
- [morecolor](https://tools.suckless.org/dmenu/patches/morecolor/)
- adds an additional color scheme for highlighting entries adjacent to the current selection
- [mouse-support](https://tools.suckless.org/dmenu/patches/mouse-support/)
- adds basic mouse support for dmenu
- [multi-selection](https://tools.suckless.org/dmenu/patches/multi-selection/)
- without this patch when you press `Ctrl+Enter` dmenu just outputs current item and it is
not possible to undo that
- with this patch dmenu will output all selected items only on exit
- it is also possible to deselect any selected item
- [navhistory](https://tools.suckless.org/dmenu/patches/navhistory/)
- provides dmenu the ability for history navigation similar to that of bash
- [no-sort](https://tools.suckless.org/dmenu/patches/no-sort/)
- adds the `-S` option to disable sorting menu items after matching
- useful, for example, when menu items are sorted by their frequency of use (using an
external cache) and the most frequently selected items should always appear first regardless
of how they were exact, prefix, or substring matches
- [non-blocking-stdin](https://tools.suckless.org/dmenu/patches/non_blocking_stdin/)
- this is a patch to have dmenu read stdin in a non blocking way, making it wait for input
both from stdin and from X
- this means that you can continue feeding dmenu while you type
- the patch is meant to be used along with the incremental patch in order to use stdout to
feed stdin
- [numbers](https://tools.suckless.org/dmenu/patches/numbers/)
- adds text which displays the number of matched and total items in the top right corner of
dmenu
- [pango](https://github.com/StillANixRookie/dmenu-pango/)
- adds simple markup for dmenu using pango markup
- [password](https://tools.suckless.org/dmenu/patches/password/)
- with this patch dmenu will not directly display the keyboard input, but instead replace it
with dots
- all data from stdin will be ignored
- [pipeout](https://tools.suckless.org/dmenu/patches/pipeout/)
- this patch allows the selected text to be piped back out with dmenu
- this can be useful if you want to display the output of a command on the screen
- [plain-prompt](https://tools.suckless.org/dmenu/patches/listfullwidth/)
- simple change that avoids colors for the prompt by making it use the same style as the
rest of the input field
- [prefix-completion](https://tools.suckless.org/dmenu/patches/prefix-completion/)
- changes the behaviour of matched items and the Tab key to allow tab completion
- [preselect](https://tools.suckless.org/dmenu/patches/preselect/)
- adds an option `-ps` to preselect an item by providing the index that should be pre-selected
- [printindex](https://tools.suckless.org/dmenu/patches/printindex/)
- allows dmenu to print out the 0-based index of matched text instead of the matched text
itself
- this can be useful in cases where you would like to select entries from one array of text
but index into another, or when you are selecting from an ordered list of non-unique items
- [printinputtext](https://tools.suckless.org/dmenu/patches/printinputtext/)
- this patch adds a flag `-t` which makes Return key ignore selection and print the input
text to stdout
- the flag basically swaps the functions of Return and Shift+Return hotkeys
- [rejectnomatch](https://tools.suckless.org/dmenu/patches/reject-no-match/)
- adds a new flag to dmenu with which text input will be rejected if it would result in no
matching item
- relative_input_width
- prior to commit [e1e1de7](https://git.suckless.org/dmenu/commit/e1e1de7b3b8399cba90ddca9613f837b2dbef7b9.html)
the input width was calculated based on the input options
- this feature was removed in favour of hardcoding the input width to always take up 1/3rd of
the available space
- this patch adds that feature back in with some bespoke performance optimisations at the cost
of accuracy and correctness
- [restrict-return](https://tools.suckless.org/dmenu/patches/restrict-return/)
- adds a `-1` option which disables Shift-Return and Ctrl-Return
- this guarantees that dmenu will only output one item, and that item was read from stdin
- [scroll](https://tools.suckless.org/dmenu/patches/scroll/)
- this patch adds support for text scrolling
- it doesn't append `...` for long input anymore as it can handle long text
- [separator](https://tools.suckless.org/dmenu/patches/separator/)
- adds `-d` and `-D` flags which separates the input into two halves; one half to be
displayed in dmenu and the other to be printed to stdout
- [symbols](https://tools.suckless.org/dmenu/patches/symbols/)
- allows the symbols, which are printed in dmenu to indicate that either the input is too
long or there are too many options to be shown in dmenu in one line, to be defined
- [tsv](https://tools.suckless.org/dmenu/patches/tsv/)
- makes dmenu split input lines at first tab character and only display first part, but it
will perform matching on and output full lines as usual
- can be useful if you want to separate data and representation
- [vertfull](https://tools.suckless.org/dmenu/patches/vertfull/)
- prevents dmenu from indenting items at the same level as the prompt length
- [wmtype](https://github.com/Baitinq/dmenu/blob/master/patches/dmenu-wm_type.diff)
- adds extended window manager hints such as \_NET_WM_WINDOW_TYPE and \_NET_WM_WINDOW_TYPE_DOCK
- [xresources](https://tools.suckless.org/dmenu/patches/xresources/)
- allows dmenu to read font and colors from Xresources
- note that with this patch the Xresources settings takes precedence over command line arguments
- [xyw](https://tools.suckless.org/dmenu/patches/xyw/)
- adds options for specifying dmenu window position and width

49
desktop/.dmenu/arg.h Normal file
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

151
desktop/.dmenu/config.def.h Normal file
View File

@@ -0,0 +1,151 @@
/* 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 */
#if ALPHA_PATCH
static int opacity = 1; /* -o option; if 0, then alpha is disabled */
#endif // ALPHA_PATCH
#if FUZZYMATCH_PATCH
static int fuzzy = 1; /* -F option; if 0, dmenu doesn't use fuzzy matching */
#endif // FUZZYMATCH_PATCH
#if INCREMENTAL_PATCH
static int incremental = 0; /* -r option; if 1, outputs text each time a key is pressed */
#endif // INCREMENTAL_PATCH
#if INSTANT_PATCH
static int instant = 0; /* -n option; if 1, selects matching item without the need to press enter */
#endif // INSTANT_PATCH
#if CENTER_PATCH
static int center = 1; /* -c option; if 0, dmenu won't be centered on the screen */
static int min_width = 500; /* minimum width when centered */
#endif // CENTER_PATCH
#if BARPADDING_PATCH
static const int vertpad = 10; /* vertical padding of bar */
static const int sidepad = 30; /* horizontal padding of bar */
#endif // BARPADDING_PATCH
#if RESTRICT_RETURN_PATCH
static int restrict_return = 0; /* -1 option; if 1, disables shift-return and ctrl-return */
#endif // RESTRICT_RETURN_PATCH
/* -fn option overrides fonts[0]; default X11 font or font set */
#if PANGO_PATCH
static char font[] = "monospace 10";
#else
#if XRESOURCES_PATCH
static char *fonts[] =
#else
static const char *fonts[] =
#endif // XRESOURCES_PATCH
{
"SauceCodePro Nerd Font Mono:size=11:antialias=true"
"monospace:size=10"
};
#endif // PANGO_PATCH
#if MANAGED_PATCH
static char *prompt = NULL; /* -p option; prompt to the left of input field */
#else
static const char *prompt = NULL; /* -p option; prompt to the left of input field */
#endif // MANAGED_PATCH
#if DYNAMIC_OPTIONS_PATCH
static const char *dynamic = NULL; /* -dy option; dynamic command to run on input change */
#endif // DYNAMIC_OPTIONS_PATCH
#if SYMBOLS_PATCH
static const char *symbol_1 = "<";
static const char *symbol_2 = ">";
#endif // SYMBOLS_PATCH
#if ALPHA_PATCH
static const unsigned int baralpha = 0xd0;
static const unsigned int borderalpha = OPAQUE;
static const unsigned int alphas[][3] = {
/* fg bg border */
[SchemeNorm] = { OPAQUE, baralpha, borderalpha },
[SchemeSel] = { OPAQUE, baralpha, borderalpha },
#if BORDER_PATCH
[SchemeBorder] = { OPAQUE, OPAQUE, OPAQUE },
#endif // BORDER_PATCH
#if MORECOLOR_PATCH
[SchemeMid] = { OPAQUE, baralpha, borderalpha },
#endif // MORECOLOR_PATCH
#if HIGHLIGHT_PATCH || FUZZYHIGHLIGHT_PATCH
[SchemeSelHighlight] = { OPAQUE, baralpha, borderalpha },
[SchemeNormHighlight] = { OPAQUE, baralpha, borderalpha },
#endif // HIGHLIGHT_PATCH | FUZZYHIGHLIGHT_PATCH
#if HIGHPRIORITY_PATCH
[SchemeHp] = { OPAQUE, baralpha, borderalpha },
#endif // HIGHPRIORITY_PATCH
#if EMOJI_HIGHLIGHT_PATCH
[SchemeHover] = { OPAQUE, baralpha, borderalpha },
[SchemeGreen] = { OPAQUE, baralpha, borderalpha },
[SchemeRed] = { OPAQUE, baralpha, borderalpha },
[SchemeYellow] = { OPAQUE, baralpha, borderalpha },
[SchemeBlue] = { OPAQUE, baralpha, borderalpha },
[SchemePurple] = { OPAQUE, baralpha, borderalpha },
#endif // EMOJI_HIGHLIGHT_PATCH
};
#endif // ALPHA_PATCH
static
#if !XRESOURCES_PATCH
const
#endif // XRESOURCES_PATCH
char *colors[][2] = {
/* fg bg */
[SchemeNorm] = { "#bbbbbb", "#222222" },
[SchemeSel] = { "#eeeeee", "#005577" },
[SchemeOut] = { "#000000", "#00ffff" },
#if BORDER_PATCH
[SchemeBorder] = { "#000000", "#005577" },
#endif // BORDER_PATCH
#if MORECOLOR_PATCH
[SchemeMid] = { "#eeeeee", "#770000" },
#endif // MORECOLOR_PATCH
#if HIGHLIGHT_PATCH || FUZZYHIGHLIGHT_PATCH
[SchemeSelHighlight] = { "#ffc978", "#005577" },
[SchemeNormHighlight] = { "#ffc978", "#222222" },
#endif // HIGHLIGHT_PATCH | FUZZYHIGHLIGHT_PATCH
#if HIGHPRIORITY_PATCH
[SchemeHp] = { "#bbbbbb", "#333333" },
#endif // HIGHPRIORITY_PATCH
#if EMOJI_HIGHLIGHT_PATCH
[SchemeHover] = { "#ffffff", "#353D4B" },
[SchemeGreen] = { "#ffffff", "#52E067" },
[SchemeRed] = { "#ffffff", "#e05252" },
[SchemeYellow] = { "#ffffff", "#e0c452" },
[SchemeBlue] = { "#ffffff", "#5280e0" },
[SchemePurple] = { "#ffffff", "#9952e0" },
#endif // EMOJI_HIGHLIGHT_PATCH
};
/* -l option; if nonzero, dmenu uses vertical list with given number of lines */
static unsigned int lines = 0;
#if GRID_PATCH
/* -g option; if nonzero, dmenu uses a grid comprised of columns and lines */
static unsigned int columns = 0;
#endif // GRID_PATCH
#if LINE_HEIGHT_PATCH
static unsigned int lineheight = 32; /* -h option; minimum height of a menu line */
static unsigned int min_lineheight = 8;
#endif // LINE_HEIGHT_PATCH
#if NAVHISTORY_PATCH
static unsigned int maxhist = 15;
static int histnodup = 1; /* if 0, record repeated histories */
#endif // NAVHISTORY_PATCH
/*
* Characters not considered part of a word while deleting words
* for example: " /?\"&[]"
*/
#if PIPEOUT_PATCH
static const char startpipe[] = "#";
#endif // PIPEOUT_PATCH
static const char worddelimiters[] = " ";
#if BORDER_PATCH
/* Size of the window border */
static unsigned int border_width = 0;
#endif // BORDER_PATCH
#if PREFIXCOMPLETION_PATCH
/*
* Use prefix matching by default; can be inverted with the -x flag.
*/
static int use_prefix = 1;
#endif // PREFIXCOMPLETION_PATCH

42
desktop/.dmenu/config.mk Normal file
View File

@@ -0,0 +1,42 @@
# dmenu version
VERSION = 5.2
# 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
#MANPREFIX = ${PREFIX}/man
# uncomment on RHEL for strcasecmp
#EXTRAFLAGS=-D_GNU_SOURCE
# Uncomment this for the alpha patch / ALPHA_PATCH
XRENDER = -lXrender
# Uncomment for the pango patch / PANGO_PATCH
#PANGOINC = `pkg-config --cflags xft pango pangoxft`
#PANGOLIB = `pkg-config --libs xft pango pangoxft`
# includes and libs
INCS = -I$(X11INC) -I$(FREETYPEINC) ${PANGOINC}
LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -lm $(XRENDER) ${PANGOLIB}
# flags
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS) $(EXTRAFLAGS)
CFLAGS = -std=c99 -pedantic -Wall -Os $(INCS) $(CPPFLAGS)
LDFLAGS = $(LIBS)
# compiler and linker
CC = cc

194
desktop/.dmenu/dmenu.1 Normal file
View File

@@ -0,0 +1,194 @@
.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 \-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)

2187
desktop/.dmenu/dmenu.c Normal file

File diff suppressed because it is too large Load Diff

13
desktop/.dmenu/dmenu_path Executable file
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

6
desktop/.dmenu/dmenu_run Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/sh
export _JAVA_AWT_WM_NONREPARENTING=1
exec $(dmenu_path | dmenu "$@")
# Uncomment for the NAVHISTORY patch (and remove the exec above)
#dmenu_path | dmenu -H "${XDG_CACHE_HOME:-$HOME/.cache/}/dmenu_run.hist" "$@" | ${SHELL:-"/bin/sh"} &

696
desktop/.dmenu/drw.c Normal file
View File

@@ -0,0 +1,696 @@
/* 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 "patches.h"
#include "drw.h"
#include "util.h"
#if !PANGO_PATCH
#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;
}
#endif // PANGO_PATCH
Drw *
#if ALPHA_PATCH
drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap)
#else
drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
#endif // ALPHA_PATCH
{
Drw *drw = ecalloc(1, sizeof(Drw));
drw->dpy = dpy;
drw->screen = screen;
drw->root = root;
drw->w = w;
drw->h = h;
#if ALPHA_PATCH
drw->visual = visual;
drw->depth = depth;
drw->cmap = cmap;
drw->drawable = XCreatePixmap(dpy, root, w, h, depth);
drw->gc = XCreateGC(dpy, drw->drawable, 0, NULL);
#else
drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
drw->gc = XCreateGC(dpy, root, 0, NULL);
#endif // ALPHA_PATCH
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);
#if ALPHA_PATCH
drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, drw->depth);
#else
drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
#endif // ALPHA_PATCH
}
void
drw_free(Drw *drw)
{
XFreePixmap(drw->dpy, drw->drawable);
XFreeGC(drw->dpy, drw->gc);
#if PANGO_PATCH
drw_font_free(drw->font);
#else
drw_fontset_free(drw->fonts);
#endif // PANGO_PATCH
free(drw);
}
#if PANGO_PATCH
/* This function is an implementation detail. Library users should use
* drw_font_create instead.
*/
static Fnt *
xfont_create(Drw *drw, const char *fontname)
{
Fnt *font;
PangoFontMap *fontmap;
PangoContext *context;
PangoFontDescription *desc;
PangoFontMetrics *metrics;
if (!fontname) {
die("no font specified.");
}
font = ecalloc(1, sizeof(Fnt));
font->dpy = drw->dpy;
fontmap = pango_xft_get_font_map(drw->dpy, drw->screen);
context = pango_font_map_create_context(fontmap);
desc = pango_font_description_from_string(fontname);
font->layout = pango_layout_new(context);
pango_layout_set_font_description(font->layout, desc);
metrics = pango_context_get_metrics(context, desc, pango_language_from_string ("en-us"));
font->h = pango_font_metrics_get_height(metrics) / PANGO_SCALE;
pango_font_metrics_unref(metrics);
g_object_unref(context);
return font;
}
#else
/* 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.");
}
#if NO_COLOR_EMOJI_PATCH
/* 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;
}
#endif // NO_COLOR_EMOJI_PATCH
font = ecalloc(1, sizeof(Fnt));
font->xfont = xfont;
font->pattern = pattern;
font->h = xfont->ascent + xfont->descent;
font->dpy = drw->dpy;
return font;
}
#endif // PANGO_PATCH
static void
xfont_free(Fnt *font)
{
if (!font)
return;
#if PANGO_PATCH
if (font->layout)
g_object_unref(font->layout);
#else
if (font->pattern)
FcPatternDestroy(font->pattern);
XftFontClose(font->dpy, font->xfont);
#endif // PANGO_PATCH
free(font);
}
#if PANGO_PATCH
Fnt*
drw_font_create(Drw* drw, const char font[])
{
Fnt *fnt = NULL;
if (!drw || !font)
return NULL;
fnt = xfont_create(drw, font);
return (drw->font = fnt);
}
#else
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);
}
#endif // PANGO_PATCH
#if PANGO_PATCH
void
drw_font_free(Fnt *font)
{
if (font)
xfont_free(font);
}
#else
void
drw_fontset_free(Fnt *font)
{
if (font) {
drw_fontset_free(font->next);
xfont_free(font);
}
}
#endif // PANGO_PATCH
void
#if ALPHA_PATCH
drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha)
#else
drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
#endif // ALPHA_PATCH
{
if (!drw || !dest || !clrname)
return;
#if ALPHA_PATCH
if (!XftColorAllocName(drw->dpy, drw->visual, drw->cmap,
clrname, dest))
die("error, cannot allocate color '%s'", clrname);
dest->pixel = (dest->pixel & 0x00ffffffU) | (alpha << 24);
#else
if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
DefaultColormap(drw->dpy, drw->screen),
clrname, dest))
die("error, cannot allocate color '%s'", clrname);
#endif // ALPHA_PATCH
}
/* Wrapper to create color schemes. The caller has to call free(3) on the
* returned color scheme when done using it. */
Clr *
#if ALPHA_PATCH
drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount)
#else
drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
#endif // ALPHA_PATCH
{
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++)
#if ALPHA_PATCH
drw_clr_create(drw, &ret[i], clrnames[i], alphas[i]);
#else
drw_clr_create(drw, &ret[i], clrnames[i]);
#endif // ALPHA_PATCH
return ret;
}
#if !PANGO_PATCH
void
drw_setfontset(Drw *drw, Fnt *set)
{
if (drw)
drw->fonts = set;
}
#endif // PANGO_PATCH
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);
}
#if PANGO_PATCH
int
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert, Bool markup)
{
char buf[1024];
int ty;
unsigned int ew;
XftDraw *d = NULL;
size_t i, len;
int render = x || y || w || h;
if (!drw || (render && !drw->scheme) || !text || !drw->font)
return 0;
if (!render) {
w = invert ? invert : ~invert;
} else {
XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
#if ALPHA_PATCH
d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap);
#else
d = XftDrawCreate(drw->dpy, drw->drawable,
DefaultVisual(drw->dpy, drw->screen),
DefaultColormap(drw->dpy, drw->screen));
#endif // ALPHA_PATCH
x += lpad;
w -= lpad;
}
len = strlen(text);
if (len) {
drw_font_getexts(drw->font, text, len, &ew, NULL, markup);
/* shorten text if necessary */
for (len = MIN(len, sizeof(buf) - 1); len && ew > w; len--)
drw_font_getexts(drw->font, text, len, &ew, NULL, markup);
if (len) {
memcpy(buf, text, len);
buf[len] = '\0';
if (len < strlen(text))
for (i = len; i && i > len - 3; buf[--i] = '.')
; /* NOP */
if (render) {
ty = y + (h - drw->font->h) / 2;
if (markup)
pango_layout_set_markup(drw->font->layout, buf, len);
else
pango_layout_set_text(drw->font->layout, buf, len);
pango_xft_render_layout(d, &drw->scheme[invert ? ColBg : ColFg],
drw->font->layout, x * PANGO_SCALE, ty * PANGO_SCALE);
if (markup) /* clear markup attributes */
pango_layout_set_attributes(drw->font->layout, NULL);
}
x += ew;
w -= ew;
}
}
if (d)
XftDrawDestroy(d);
return x + (render ? w : 0);
}
#else
int
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
{
int i, ty, ellipsis_x = 0;
unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len;
XftDraw *d = NULL;
Fnt *usedfont, *curfont, *nextfont;
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, overflow = 0;
/* keep track of a couple codepoints for which we have no match. */
enum { nomatches_len = 64 };
static struct { long codepoint[nomatches_len]; unsigned int idx; } nomatches;
const char *ellipsis = "...";
static unsigned int ellipsis_width = 0;
if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts)
return 0;
if (!render) {
w = invert ? invert : ~invert;
} else {
XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
#if ALPHA_PATCH
d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap);
#else
d = XftDrawCreate(drw->dpy, drw->drawable,
DefaultVisual(drw->dpy, drw->screen),
DefaultColormap(drw->dpy, drw->screen));
#endif // ALPHA_PATCH
x += lpad;
w -= lpad;
}
usedfont = drw->fonts;
if (!ellipsis_width && render)
ellipsis_width = drw_fontset_getwidth(drw, ellipsis);
while (1) {
ew = ellipsis_len = 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) {
drw_font_getexts(curfont, text, utf8charlen, &tmpw, NULL);
if (ew + ellipsis_width <= w) {
/* keep track where the ellipsis still fits */
ellipsis_x = x + ew;
ellipsis_w = w - ew;
ellipsis_len = utf8strlen;
}
if (ew + tmpw > w) {
overflow = 1;
/* called from drw_fontset_getwidth_clamp():
* it wants the width AFTER the overflow
*/
if (!render)
x += tmpw;
else
utf8strlen = ellipsis_len;
} else if (curfont == usedfont) {
utf8strlen += utf8charlen;
text += utf8charlen;
ew += tmpw;
} else {
nextfont = curfont;
}
break;
}
}
if (overflow || !charexists || nextfont)
break;
else
charexists = 0;
}
if (utf8strlen) {
if (render) {
ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
usedfont->xfont, x, ty, (XftChar8 *)utf8str, utf8strlen);
}
x += ew;
w -= ew;
}
if (render && overflow && ellipsis_w)
drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, ellipsis, invert);
if (!*text || overflow) {
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;
for (i = 0; i < nomatches_len; ++i) {
/* avoid calling XftFontMatch if we know we won't find a match */
if (utf8codepoint == nomatches.codepoint[i])
goto no_match;
}
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);
#if NO_COLOR_EMOJI_PATCH
FcPatternAddBool(fcpattern, FC_COLOR, FcFalse);
#endif // NO_COLOR_EMOJI_PATCH
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);
nomatches.codepoint[++nomatches.idx % nomatches_len] = utf8codepoint;
no_match:
usedfont = drw->fonts;
}
}
}
}
if (d)
XftDrawDestroy(d);
return x + (render ? w : 0);
}
#endif // PANGO_PATCH
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);
}
#if PANGO_PATCH
unsigned int
drw_font_getwidth(Drw *drw, const char *text, Bool markup)
{
if (!drw || !drw->font || !text)
return 0;
return drw_text(drw, 0, 0, 0, 0, 0, text, 0, markup);
}
unsigned int
drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n)
{
unsigned int tmp = 0;
if (drw && drw->font && text && n)
tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n, True);
return MIN(n, tmp);
}
#else
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);
}
unsigned int
drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n)
{
unsigned int tmp = 0;
if (drw && drw->fonts && text && n)
tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n);
return MIN(n, tmp);
}
#endif // PANGO_PATCH
#if PANGO_PATCH
void
drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h, Bool markup)
{
if (!font || !text)
return;
PangoRectangle r;
if (markup)
pango_layout_set_markup(font->layout, text, len);
else
pango_layout_set_text(font->layout, text, len);
pango_layout_get_extents(font->layout, 0, &r);
if (markup) /* clear markup attributes */
pango_layout_set_attributes(font->layout, NULL);
if (w)
*w = r.width / PANGO_SCALE;
if (h)
*h = font->h;
}
#else
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;
}
#endif // PANGO_PATCH
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);
}
#if SCROLL_PATCH
#include "patch/scroll.c"
#endif

103
desktop/.dmenu/drw.h Normal file
View File

@@ -0,0 +1,103 @@
/* See LICENSE file for copyright and license details. */
#if PANGO_PATCH
#include <pango/pango.h>
#include <pango/pangoxft.h>
#endif // PANGO_PATCH
typedef struct {
Cursor cursor;
} Cur;
typedef struct Fnt {
Display *dpy;
unsigned int h;
#if PANGO_PATCH
PangoLayout *layout;
#else
XftFont *xfont;
FcPattern *pattern;
struct Fnt *next;
#endif // PANGO_PATCH
} Fnt;
enum { ColFg, ColBg }; /* Clr scheme index */
typedef XftColor Clr;
typedef struct {
unsigned int w, h;
Display *dpy;
int screen;
Window root;
#if ALPHA_PATCH
Visual *visual;
unsigned int depth;
Colormap cmap;
#endif // ALPHA_PATCH
Drawable drawable;
GC gc;
Clr *scheme;
#if PANGO_PATCH
Fnt *font;
#else
Fnt *fonts;
#endif // PANGO_PATCH
} Drw;
/* Drawable abstraction */
#if ALPHA_PATCH
Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap);
#else
Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h);
#endif // ALPHA_PATCH
void drw_resize(Drw *drw, unsigned int w, unsigned int h);
void drw_free(Drw *drw);
/* Fnt abstraction */
#if PANGO_PATCH
Fnt *drw_font_create(Drw* drw, const char font[]);
void drw_font_free(Fnt* set);
unsigned int drw_font_getwidth(Drw *drw, const char *text, Bool markup);
unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n);
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h, Bool markup);
#else
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);
unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n);
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);
#endif // PANGO_PATCH
/* Colorscheme abstraction */
#if ALPHA_PATCH
void drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha);
Clr *drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount);
#else
void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
#endif // ALPHA_PATCH
/* Cursor abstraction */
Cur *drw_cur_create(Drw *drw, int shape);
void drw_cur_free(Drw *drw, Cur *cursor);
/* Drawing context manipulation */
#if !PANGO_PATCH
void drw_setfontset(Drw *drw, Fnt *set);
#endif // PANGO_PATCH
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);
#if PANGO_PATCH
int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert, Bool markup);
#else
int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert);
#endif // PANGO_PATCH
/* Map functions */
void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);
#if SCROLL_PATCH
#include "patch/scroll.h"
#endif

View File

@@ -0,0 +1,8 @@
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;
}

View File

@@ -0,0 +1,91 @@
static void
refreshoptions()
{
int dynlen = strlen(dynamic);
char* cmd= malloc(dynlen + strlen(text) + 2);
if (cmd == NULL)
die("malloc:");
sprintf(cmd, "%s %s", dynamic, text);
FILE *stream = popen(cmd, "r");
if (!stream)
die("popen(%s):", cmd);
readstream(stream);
int pc = pclose(stream);
if (pc == -1)
die("pclose:");
free(cmd);
curr = sel = items;
}
static void
readstream(FILE* stream)
{
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, stream); 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);
#if SEPARATOR_PATCH
if (separator && (p = separator_greedy ?
strrchr(items[i].text, separator) : strchr(items[i].text, separator))) {
*p = '\0';
items[i].text_output = ++p;
} else {
items[i].text_output = items[i].text;
}
if (separator_reverse) {
p = items[i].text;
items[i].text = items[i].text_output;
items[i].text_output = p;
}
#elif TSV_PATCH
if ((p = strchr(buf, '\t')))
*p = '\0';
if (!(items[i].stext = strdup(buf)))
die("cannot strdup %u bytes:", strlen(buf) + 1);
#endif // TSV_PATCH
#if MULTI_SELECTION_PATCH
items[i].id = i;
#else
items[i].out = 0;
#endif // MULTI_SELECTION_PATCH
#if HIGHPRIORITY_PATCH
items[i].hp = arrayhas(hpitems, hplength, items[i].text);
#endif // HIGHPRIORITY_PATCH
#if PANGO_PATCH
drw_font_getexts(drw->font, buf, strlen(buf), &tmpmax, NULL, True);
#else
drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL);
#endif // PANGO_PATCH
if (tmpmax > inputw) {
inputw = tmpmax;
imax = i;
}
}
/* If the command did not give any output at all, then do not clear the existing items */
if (!i)
return;
if (items)
items[i].text = NULL;
#if PANGO_PATCH
inputw = items ? TEXTWM(items[imax].text) : 0;
#else
inputw = items ? TEXTW(items[imax].text) : 0;
#endif // PANGO_PATCH
if (!dynamic || !*dynamic)
lines = MIN(lines, i);
else {
text[0] = '\0';
cursor = 0;
}
}

View File

@@ -0,0 +1,2 @@
static void refreshoptions();
static void readstream(FILE* stream);

View File

@@ -0,0 +1,57 @@
static void
#if EMOJI_HIGHLIGHT_PATCH
drawhighlights(struct item *item, char *output, int x, int y, int maxw)
#else
drawhighlights(struct item *item, int x, int y, int maxw)
#endif // EMOJI_HIGHLIGHT_PATCH
{
int i, indent;
char *highlight;
char c;
#if EMOJI_HIGHLIGHT_PATCH
char *itemtext = output;
#elif TSV_PATCH && !SEPARATOR_PATCH
char *itemtext = item->stext;
#else
char *itemtext = item->text;
#endif // TSV_PATCH
if (!(strlen(itemtext) && strlen(text)))
return;
drw_setscheme(drw, scheme[item == sel
? SchemeSelHighlight
: SchemeNormHighlight]);
for (i = 0, highlight = itemtext; *highlight && text[i];) {
#if FUZZYMATCH_PATCH
if (!fstrncmp(&(*highlight), &text[i], 1))
#else
if (*highlight == text[i])
#endif // FUZZYMATCH_PATCH
{
/* get indentation */
c = *highlight;
*highlight = '\0';
indent = TEXTW(itemtext) - lrpad;
*highlight = c;
/* highlight character */
c = highlight[1];
highlight[1] = '\0';
drw_text(
drw,
x + indent + (lrpad / 2),
y,
MIN(maxw - indent - lrpad, TEXTW(highlight) - lrpad),
bh, 0, highlight, 0
#if PANGO_PATCH
, True
#endif // PANGO_PATCH
);
highlight[1] = c;
i++;
}
highlight++;
}
}

View File

@@ -0,0 +1,106 @@
#include <math.h>
int
compare_distance(const void *a, const void *b)
{
struct item *da = *(struct item **) a;
struct item *db = *(struct item **) b;
if (!db)
return 1;
if (!da)
return -1;
return da->distance == db->distance ? 0 : da->distance < db->distance ? -1 : 1;
}
void
fuzzymatch(void)
{
/* bang - we have so much memory */
struct item *it;
struct item **fuzzymatches = NULL;
char c;
int number_of_matches = 0, i, pidx, sidx, eidx;
int text_len = strlen(text), itext_len;
#if HIGHPRIORITY_PATCH
struct item *lhpprefix, *hpprefixend;
lhpprefix = hpprefixend = NULL;
#endif // HIGHPRIORITY_PATCH
matches = matchend = NULL;
/* walk through all items */
for (it = items; it && it->text; it++) {
if (text_len) {
itext_len = strlen(it->text);
pidx = 0; /* pointer */
sidx = eidx = -1; /* start of match, end of match */
/* walk through item text */
for (i = 0; i < itext_len && (c = it->text[i]); i++) {
/* fuzzy match pattern */
if (!fstrncmp(&text[pidx], &c, 1)) {
if (sidx == -1)
sidx = i;
pidx++;
if (pidx == text_len) {
eidx = i;
break;
}
}
}
/* build list of matches */
if (eidx != -1) {
/* compute distance */
/* add penalty if match starts late (log(sidx+2))
* add penalty for long a match without many matching characters */
it->distance = log(sidx + 2) + (double)(eidx - sidx - text_len);
/* fprintf(stderr, "distance %s %f\n", it->text, it->distance); */
appenditem(it, &matches, &matchend);
number_of_matches++;
}
} else {
appenditem(it, &matches, &matchend);
}
}
if (number_of_matches) {
/* initialize array with matches */
if (!(fuzzymatches = realloc(fuzzymatches, number_of_matches * sizeof(struct item*))))
die("cannot realloc %u bytes:", number_of_matches * sizeof(struct item*));
for (i = 0, it = matches; it && i < number_of_matches; i++, it = it->right) {
fuzzymatches[i] = it;
}
#if NO_SORT_PATCH
if (sortmatches)
#endif // NO_SORT_PATCH
/* sort matches according to distance */
qsort(fuzzymatches, number_of_matches, sizeof(struct item*), compare_distance);
/* rebuild list of matches */
matches = matchend = NULL;
for (i = 0, it = fuzzymatches[i]; i < number_of_matches && it && \
it->text; i++, it = fuzzymatches[i]) {
#if HIGHPRIORITY_PATCH
#if NO_SORT_PATCH
if (sortmatches && it->hp)
#else
if (it->hp)
#endif // NO_SORT_PATCH
appenditem(it, &lhpprefix, &hpprefixend);
else
appenditem(it, &matches, &matchend);
#else
appenditem(it, &matches, &matchend);
#endif // HIGHPRIORITY_PATCH
}
free(fuzzymatches);
}
#if HIGHPRIORITY_PATCH
if (lhpprefix) {
hpprefixend->right = matches;
matches = lhpprefix;
}
#endif // HIGHPRIORITY_PATCH
curr = sel = matches;
calcoffsets();
}

View File

@@ -0,0 +1,39 @@
static char *expected;
#if MULTI_SELECTION_PATCH
void
expect(char *expect, XKeyEvent *ev)
{
if (sel && expected && strstr(expected, expect)) {
if (expected && sel && !(ev->state & ShiftMask))
puts(expect);
for (int i = 0; i < selidsize; i++)
if (selid[i] != -1 && (!sel || sel->id != selid[i]))
puts(items[selid[i]].text);
if (sel && !(ev->state & ShiftMask)) {
puts(sel->text);
} else
puts(text);
cleanup();
exit(1);
} else if (!sel && expected && strstr(expected, expect)) {
puts(expect);
cleanup();
exit(1);
}
}
#else
void
expect(char *expect, XKeyEvent *ignored)
{
if (sel && expected && strstr(expected, expect)) {
puts(expect);
puts(sel->text);
cleanup();
exit(1);
} else if (!sel && expected && strstr(expected, expect)){
puts(expect);
cleanup();
exit(1);
}
}
#endif // MULTI_SELECTION_PATCH

View File

@@ -0,0 +1 @@
static void expect(char *expect, XKeyEvent *ev);

View File

@@ -0,0 +1,51 @@
static void
#if EMOJI_HIGHLIGHT_PATCH
drawhighlights(struct item *item, char *output, int x, int y, int maxw)
#else
drawhighlights(struct item *item, int x, int y, int maxw)
#endif // EMOJI_HIGHLIGHT_PATCH
{
char restorechar, tokens[sizeof text], *highlight, *token;
int indentx, highlightlen;
#if EMOJI_HIGHLIGHT_PATCH
char *itemtext = output;
#elif TSV_PATCH && !SEPARATOR_PATCH
char *itemtext = item->stext;
#else
char *itemtext = item->text;
#endif // EMOJI_HIGHLIGHT_PATCH | TSV_PATCH
drw_setscheme(drw, scheme[item == sel ? SchemeSelHighlight : SchemeNormHighlight]);
strcpy(tokens, text);
for (token = strtok(tokens, " "); token; token = strtok(NULL, " ")) {
highlight = fstrstr(itemtext, token);
while (highlight) {
// Move item str end, calc width for highlight indent, & restore
highlightlen = highlight - itemtext;
restorechar = *highlight;
itemtext[highlightlen] = '\0';
indentx = TEXTW(itemtext);
itemtext[highlightlen] = restorechar;
// Move highlight str end, draw highlight, & restore
restorechar = highlight[strlen(token)];
highlight[strlen(token)] = '\0';
if (indentx - (lrpad / 2) - 1 < maxw)
drw_text(
drw,
x + indentx - (lrpad / 2) - 1,
y,
MIN(maxw - indentx, TEXTW(highlight) - lrpad),
bh, 0, highlight, 0
#if PANGO_PATCH
, True
#endif // PANGO_PATCH
);
highlight[strlen(token)] = restorechar;
if (strlen(highlight) - strlen(token) < strlen(token))
break;
highlight = fstrstr(highlight + strlen(token), token);
}
}
}

View File

@@ -0,0 +1,35 @@
static char **hpitems = NULL;
static int hplength = 0;
static char **
tokenize(char *source, const char *delim, int *llen)
{
int listlength = 0, list_size = 0;
char **list = NULL, *token;
token = strtok(source, delim);
while (token) {
if (listlength + 1 >= list_size) {
if (!(list = realloc(list, (list_size += 8) * sizeof(*list))))
die("Unable to realloc %zu bytes\n", list_size * sizeof(*list));
}
if (!(list[listlength] = strdup(token)))
die("Unable to strdup %zu bytes\n", strlen(token) + 1);
token = strtok(NULL, delim);
listlength++;
}
*llen = listlength;
return list;
}
static int
arrayhas(char **list, int length, char *item) {
for (int i = 0; i < length; i++) {
int len1 = strlen(list[i]);
int len2 = strlen(item);
if (fstrncmp(list[i], item, len1 > len2 ? len2 : len1) == 0)
return 1;
}
return 0;
}

View File

@@ -0,0 +1,2 @@
static int arrayhas(char **list, int length, char *item);

View File

@@ -0,0 +1,38 @@
#if CENTER_PATCH
#include "center.c"
#endif
#if FUZZYHIGHLIGHT_PATCH
#include "fuzzyhighlight.c"
#elif HIGHLIGHT_PATCH
#include "highlight.c"
#endif
#if FUZZYMATCH_PATCH
#include "fuzzymatch.c"
#endif
#if FZFEXPECT_PATCH
#include "fzfexpect.c"
#endif
#if HIGHPRIORITY_PATCH
#include "highpriority.c"
#endif
#if DYNAMIC_OPTIONS_PATCH
#include "dynamicoptions.c"
#endif
#if MULTI_SELECTION_PATCH
#include "multiselect.c"
#endif
#if MOUSE_SUPPORT_PATCH
#include "mousesupport.c"
#endif
#if NAVHISTORY_PATCH
#include "navhistory.c"
#endif
#if NON_BLOCKING_STDIN_PATCH
#include "nonblockingstdin.c"
#endif
#if NUMBERS_PATCH
#include "numbers.c"
#endif
#if XRESOURCES_PATCH
#include "xresources.c"
#endif

View File

@@ -0,0 +1,15 @@
#if DYNAMIC_OPTIONS_PATCH
#include "dynamicoptions.h"
#endif
#if FZFEXPECT_PATCH
#include "fzfexpect.h"
#endif
#if HIGHPRIORITY_PATCH
#include "highpriority.h"
#endif
#if NON_BLOCKING_STDIN_PATCH
#include "nonblockingstdin.h"
#endif
#if NUMBERS_PATCH
#include "numbers.h"
#endif

View File

@@ -0,0 +1,159 @@
static void
buttonpress(XEvent *e)
{
struct item *item;
XButtonPressedEvent *ev = &e->xbutton;
int x = 0, y = 0, h = bh, w;
if (ev->window != win)
return;
/* right-click: exit */
if (ev->button == Button3)
exit(1);
if (prompt && *prompt)
x += promptw;
/* input field */
w = (lines > 0 || !matches) ? mw - x : inputw;
/* left-click on input: clear input,
* NOTE: if there is no left-arrow the space for < is reserved so
* add that to the input width */
#if SYMBOLS_PATCH
if (ev->button == Button1 &&
((lines <= 0 && ev->x >= 0 && ev->x <= x + w +
((!prev || !curr->left) ? TEXTW(symbol_1) : 0)) ||
(lines > 0 && ev->y >= y && ev->y <= y + h))) {
insert(NULL, -cursor);
drawmenu();
return;
}
#else
if (ev->button == Button1 &&
((lines <= 0 && ev->x >= 0 && ev->x <= x + w +
((!prev || !curr->left) ? TEXTW("<") : 0)) ||
(lines > 0 && ev->y >= y && ev->y <= y + h))) {
insert(NULL, -cursor);
drawmenu();
return;
}
#endif // SYMBOLS_PATCH
/* middle-mouse click: paste selection */
if (ev->button == Button2) {
XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY,
utf8, utf8, win, CurrentTime);
drawmenu();
return;
}
/* scroll up */
if (ev->button == Button4 && prev) {
sel = curr = prev;
calcoffsets();
drawmenu();
return;
}
/* scroll down */
if (ev->button == Button5 && next) {
sel = curr = next;
calcoffsets();
drawmenu();
return;
}
if (ev->button != Button1)
return;
if (ev->state & ~ControlMask)
return;
if (lines > 0) {
/* vertical list: (ctrl)left-click on item */
w = mw - x;
for (item = curr; item != next; item = item->right) {
y += h;
if (ev->y >= y && ev->y <= (y + h)) {
#if !MULTI_SELECTION_PATCH
puts(item->text);
#endif // MULTI_SELECTION_PATCH
if (!(ev->state & ControlMask)) {
#if MULTI_SELECTION_PATCH
sel = item;
selsel();
printsel(ev->state);
#endif // MULTI_SELECTION_PATCH
exit(0);
}
sel = item;
if (sel) {
#if MULTI_SELECTION_PATCH
selsel();
#else
sel->out = 1;
#endif // MULTI_SELECTION_PATCH
drawmenu();
}
return;
}
}
} else if (matches) {
/* left-click on left arrow */
x += inputw;
#if SYMBOLS_PATCH
w = TEXTW(symbol_1);
#else
w = TEXTW("<");
#endif // SYMBOLS_PATCH
if (prev && curr->left) {
if (ev->x >= x && ev->x <= x + w) {
sel = curr = prev;
calcoffsets();
drawmenu();
return;
}
}
/* horizontal list: (ctrl)left-click on item */
for (item = curr; item != next; item = item->right) {
x += w;
#if SYMBOLS_PATCH
w = MIN(TEXTW(item->text), mw - x - TEXTW(symbol_2));
#else
w = MIN(TEXTW(item->text), mw - x - TEXTW(">"));
#endif // SYMBOLS_PATCH
if (ev->x >= x && ev->x <= x + w) {
#if !MULTI_SELECTION_PATCH
puts(item->text);
#endif // MULTI_SELECTION_PATCH
if (!(ev->state & ControlMask)) {
#if MULTI_SELECTION_PATCH
sel = item;
selsel();
printsel(ev->state);
#endif // MULTI_SELECTION_PATCH
exit(0);
}
sel = item;
if (sel) {
#if MULTI_SELECTION_PATCH
selsel();
#else
sel->out = 1;
#endif // MULTI_SELECTION_PATCH
drawmenu();
}
return;
}
}
/* left-click on right arrow */
#if SYMBOLS_PATCH
w = TEXTW(symbol_2);
#else
w = TEXTW(">");
#endif // SYMBOLS_PATCH
x = mw - w;
if (next && ev->x >= x && ev->x <= x + w) {
sel = curr = next;
calcoffsets();
drawmenu();
return;
}
}
}

View File

@@ -0,0 +1,53 @@
static int
issel(size_t id)
{
for (int i = 0;i < selidsize;i++)
if (selid[i] == id)
return 1;
return 0;
}
static void
printsel(unsigned int state)
{
for (int i = 0;i < selidsize;i++)
if (selid[i] != -1 && (!sel || sel->id != selid[i])) {
#if PRINTINDEX_PATCH
if (print_index)
printf("%d\n", selid[i]);
else
#endif // PRINTINDEX_PATCH
puts(items[selid[i]].text);
}
if (sel && !(state & ShiftMask)) {
#if PRINTINDEX_PATCH
if (print_index)
printf("%d\n", sel->index);
else
#endif // PRINTINDEX_PATCH
puts(sel->text);
} else
puts(text);
}
static void
selsel()
{
if (!sel)
return;
if (issel(sel->id)) {
for (int i = 0; i < selidsize; i++)
if (selid[i] == sel->id)
selid[i] = -1;
} else {
for (int i = 0; i < selidsize; i++)
if (selid[i] == -1) {
selid[i] = sel->id;
return;
}
selidsize++;
selid = realloc(selid, (selidsize + 1) * sizeof(int));
selid[selidsize - 1] = sel->id;
}
}

View File

@@ -0,0 +1,126 @@
static char *histfile;
static char **history;
static size_t histsz, histpos;
static void
loadhistory(void)
{
FILE *fp = NULL;
static size_t cap = 0;
size_t llen;
char *line;
if (!histfile) {
return;
}
fp = fopen(histfile, "r");
if (!fp) {
return;
}
for (;;) {
line = NULL;
llen = 0;
if (-1 == getline(&line, &llen, fp)) {
if (ferror(fp)) {
die("failed to read history");
}
free(line);
break;
}
if (cap == histsz) {
cap += 64 * sizeof(char*);
history = realloc(history, cap);
if (!history) {
die("failed to realloc memory");
}
}
strtok(line, "\n");
history[histsz] = line;
histsz++;
}
histpos = histsz;
if (fclose(fp)) {
die("failed to close file %s", histfile);
}
}
static void
navhistory(int dir)
{
static char def[BUFSIZ];
char *p = NULL;
size_t len = 0;
if (!history || histpos + 1 == 0)
return;
if (histsz == histpos) {
strncpy(def, text, sizeof(def));
}
switch(dir) {
case 1:
if (histpos < histsz - 1) {
p = history[++histpos];
} else if (histpos == histsz - 1) {
p = def;
histpos++;
}
break;
case -1:
if (histpos > 0) {
p = history[--histpos];
}
break;
}
if (p == NULL) {
return;
}
len = MIN(strlen(p), BUFSIZ - 1);
strncpy(text, p, len);
text[len] = '\0';
cursor = len;
match();
}
static void
savehistory(char *input)
{
unsigned int i;
FILE *fp;
if (!histfile ||
0 == maxhist ||
0 == strlen(input)) {
goto out;
}
fp = fopen(histfile, "w");
if (!fp) {
die("failed to open %s", histfile);
}
for (i = histsz < maxhist ? 0 : histsz - maxhist; i < histsz; i++) {
if (0 >= fprintf(fp, "%s\n", history[i])) {
die("failed to write to %s", histfile);
}
}
if (histsz == 0 || !histnodup || (histsz > 0 && strcmp(input, history[histsz-1]) != 0)) { /* TODO */
if (0 >= fputs(input, fp)) {
die("failed to write to %s", histfile);
}
}
if (fclose(fp)) {
die("failed to close file %s", histfile);
}
out:
for (i = 0; i < histsz; i++) {
free(history[i]);
}
free(history);
}

View File

@@ -0,0 +1,68 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/select.h>
static void
readstdin(void)
{
static size_t max = 0;
static struct item **end = &items;
char buf[sizeof text], *p, *maxstr;
struct item *item;
#if PASSWORD_PATCH
if (passwd) {
inputw = lines = 0;
return;
}
#endif // PASSWORD_PATCH
/* read each line from stdin and add it to the item list */
while (fgets(buf, sizeof buf, stdin)) {
if (!(item = malloc(sizeof *item)))
die("cannot malloc %u bytes:", sizeof *item);
if ((p = strchr(buf, '\n')))
*p = '\0';
if (!(item->text = strdup(buf)))
die("cannot strdup %u bytes:", strlen(buf)+1);
if (strlen(item->text) > max) {
max = strlen(maxstr = item->text);
#if PANGO_PATCH
inputw = maxstr ? TEXTWM(maxstr) : 0;
#else
inputw = maxstr ? TEXTW(maxstr) : 0;
#endif // PANGO_PATCH
}
*end = item;
end = &item->next;
item->next = NULL;
item->out = 0;
}
match();
drawmenu();
}
static void
run(void)
{
fd_set fds;
int flags, xfd = XConnectionNumber(dpy);
if ((flags = fcntl(0, F_GETFL)) == -1)
die("cannot get stdin control flags:");
if (fcntl(0, F_SETFL, flags | O_NONBLOCK) == -1)
die("cannot set stdin control flags:");
for (;;) {
FD_ZERO(&fds);
FD_SET(xfd, &fds);
if (!feof(stdin))
FD_SET(0, &fds);
if (select(xfd + 1, &fds, NULL, NULL, NULL) == -1)
die("cannot multiplex input:");
if (FD_ISSET(xfd, &fds))
readevent();
if (FD_ISSET(0, &fds))
readstdin();
}
}

View File

@@ -0,0 +1 @@
static void readevent();

View File

@@ -0,0 +1,16 @@
static char numbers[NUMBERSBUFSIZE] = "";
static void
recalculatenumbers()
{
unsigned int numer = 0, denom = 0;
struct item *item;
if (matchend) {
numer++;
for (item = matchend; item && item->left; item = item->left)
numer++;
}
for (item = items; item && item->text; item++)
denom++;
snprintf(numbers, NUMBERSBUFSIZE, "%d/%d", numer, denom);
}

View File

@@ -0,0 +1,4 @@
#define NUMBERSMAXDIGITS 100
#define NUMBERSBUFSIZE (NUMBERSMAXDIGITS * 2) + 1
static void recalculatenumbers();

View File

@@ -0,0 +1,168 @@
int
utf8nextchar(const char *str, int len, int i, int inc)
{
int n;
for (n = i + inc; n + inc >= 0 && n + inc <= len
&& (str[n] & 0xc0) == 0x80; n += inc)
;
return n;
}
int
drw_text_align(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int textlen, int align)
{
int ty;
unsigned int ew;
XftDraw *d = NULL;
Fnt *usedfont, *curfont, *nextfont;
size_t 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;
int i, n;
if (!drw || (render && !drw->scheme) || !text || !drw->fonts || textlen <= 0
|| (align != AlignL && align != AlignR))
return 0;
if (!render) {
w = ~w;
} else {
XSetForeground(drw->dpy, drw->gc, drw->scheme[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));
}
usedfont = drw->fonts;
i = align == AlignL ? 0 : textlen;
x = align == AlignL ? x : x + w;
while (1) {
utf8strlen = 0;
nextfont = NULL;
/* if (align == AlignL) */
utf8str = text + i;
while ((align == AlignL && i < textlen) || (align == AlignR && i > 0)) {
if (align == AlignL) {
utf8charlen = utf8decode(text + i, &utf8codepoint, MIN(textlen - i, UTF_SIZ));
if (!utf8charlen) {
textlen = i;
break;
}
} else {
n = utf8nextchar(text, textlen, i, -1);
utf8charlen = utf8decode(text + n, &utf8codepoint, MIN(textlen - n, UTF_SIZ));
if (!utf8charlen) {
textlen -= i;
text += i;
i = 0;
break;
}
}
for (curfont = drw->fonts; curfont; curfont = curfont->next) {
charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
if (charexists) {
if (curfont == usedfont) {
utf8strlen += utf8charlen;
i += align == AlignL ? utf8charlen : -utf8charlen;
} else {
nextfont = curfont;
}
break;
}
}
if (!charexists || nextfont)
break;
else
charexists = 0;
}
if (align == AlignR)
utf8str = text + i;
if (utf8strlen) {
drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL);
/* shorten text if necessary */
if (align == AlignL) {
for (len = utf8strlen; len && ew > w; ) {
len = utf8nextchar(utf8str, len, len, -1);
drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
}
} else {
for (len = utf8strlen; len && ew > w; ) {
n = utf8nextchar(utf8str, len, 0, +1);
utf8str += n;
len -= n;
drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
}
}
if (len) {
if (render) {
ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
XftDrawStringUtf8(d, &drw->scheme[ColFg],
usedfont->xfont, align == AlignL ? x : x - ew, ty, (XftChar8 *)utf8str, len);
}
x += align == AlignL ? ew : -ew;
w -= ew;
}
if (len < utf8strlen)
break;
}
if ((align == AlignR && i <= 0) || (align == AlignL && i >= textlen)) {
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);
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;
}

View File

@@ -0,0 +1,3 @@
enum { AlignL, AlignR };
int drw_text_align(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int textlen, int align);

View File

@@ -0,0 +1,90 @@
#include <X11/Xresource.h>
void
readxresources(void)
{
XrmInitialize();
char* xrm;
if ((xrm = XResourceManagerString(drw->dpy))) {
char *type;
XrmDatabase xdb = XrmGetStringDatabase(xrm);
XrmValue xval;
if (XrmGetResource(xdb, "dmenu.font", "*", &type, &xval))
#if PANGO_PATCH
strcpy(font, xval.addr);
#else
fonts[0] = strdup(xval.addr);
#endif // PANGO_PATCH
#if !PANGO_PATCH
else
fonts[0] = strdup(fonts[0]);
#endif // PANGO_PATCH
if (XrmGetResource(xdb, "dmenu.background", "*", &type, &xval))
colors[SchemeNorm][ColBg] = strdup(xval.addr);
if (XrmGetResource(xdb, "dmenu.foreground", "*", &type, &xval))
colors[SchemeNorm][ColFg] = strdup(xval.addr);
if (XrmGetResource(xdb, "dmenu.selbackground", "*", &type, &xval))
colors[SchemeSel][ColBg] = strdup(xval.addr);
if (XrmGetResource(xdb, "dmenu.selforeground", "*", &type, &xval))
colors[SchemeSel][ColFg] = strdup(xval.addr);
if (XrmGetResource(xdb, "dmenu.outbackground", "*", &type, &xval))
colors[SchemeOut][ColBg] = strdup(xval.addr);
if (XrmGetResource(xdb, "dmenu.outforeground", "*", &type, &xval))
colors[SchemeOut][ColFg] = strdup(xval.addr);
#if MORECOLOR_PATCH
if (XrmGetResource(xdb, "dmenu.midbackground", "*", &type, &xval))
colors[SchemeMid][ColBg] = strdup(xval.addr);
if (XrmGetResource(xdb, "dmenu.midforeground", "*", &type, &xval))
colors[SchemeMid][ColFg] = strdup(xval.addr);
#endif // MORECOLOR_PATCH
#if BORDER_PATCH
if (XrmGetResource(xdb, "dmenu.bordercolor", "*", &type, &xval))
colors[SchemeBorder][ColBg] = strdup(xval.addr);
#endif // BORDER_PATCH
#if HIGHLIGHT_PATCH || FUZZYHIGHLIGHT_PATCH
if (XrmGetResource(xdb, "dmenu.selhlbackground", "*", &type, &xval))
colors[SchemeSelHighlight][ColBg] = strdup(xval.addr);
if (XrmGetResource(xdb, "dmenu.selhlforeground", "*", &type, &xval))
colors[SchemeSelHighlight][ColFg] = strdup(xval.addr);
if (XrmGetResource(xdb, "dmenu.hlbackground", "*", &type, &xval))
colors[SchemeNormHighlight][ColBg] = strdup(xval.addr);
if (XrmGetResource(xdb, "dmenu.hlforeground", "*", &type, &xval))
colors[SchemeNormHighlight][ColFg] = strdup(xval.addr);
#endif // HIGHLIGHT_PATCH | FUZZYHIGHLIGHT_PATCH
#if HIGHPRIORITY_PATCH
if (XrmGetResource(xdb, "dmenu.hpbackground", "*", &type, &xval))
colors[SchemeHp][ColBg] = strdup(xval.addr);
if (XrmGetResource(xdb, "dmenu.hpforeground", "*", &type, &xval))
colors[SchemeHp][ColFg] = strdup(xval.addr);
#endif // HIGHPRIORITY_PATCH
#if EMOJI_HIGHLIGHT_PATCH
if (XrmGetResource(xdb, "dmenu.hoverbackground", "*", &type, &xval))
colors[SchemeHover][ColBg] = strdup(xval.addr);
if (XrmGetResource(xdb, "dmenu.hoverforeground", "*", &type, &xval))
colors[SchemeHover][ColFg] = strdup(xval.addr);
if (XrmGetResource(xdb, "dmenu.greenbackground", "*", &type, &xval))
colors[SchemeGreen][ColBg] = strdup(xval.addr);
if (XrmGetResource(xdb, "dmenu.greenforeground", "*", &type, &xval))
colors[SchemeGreen][ColFg] = strdup(xval.addr);
if (XrmGetResource(xdb, "dmenu.yellowbackground", "*", &type, &xval))
colors[SchemeYellow][ColBg] = strdup(xval.addr);
if (XrmGetResource(xdb, "dmenu.yellowforeground", "*", &type, &xval))
colors[SchemeYellow][ColFg] = strdup(xval.addr);
if (XrmGetResource(xdb, "dmenu.bluebackground", "*", &type, &xval))
colors[SchemeBlue][ColBg] = strdup(xval.addr);
if (XrmGetResource(xdb, "dmenu.blueforeground", "*", &type, &xval))
colors[SchemeBlue][ColFg] = strdup(xval.addr);
if (XrmGetResource(xdb, "dmenu.purplebackground", "*", &type, &xval))
colors[SchemePurple][ColBg] = strdup(xval.addr);
if (XrmGetResource(xdb, "dmenu.purpleforeground", "*", &type, &xval))
colors[SchemePurple][ColFg] = strdup(xval.addr);
if (XrmGetResource(xdb, "dmenu.redbackground", "*", &type, &xval))
colors[SchemeRed][ColBg] = strdup(xval.addr);
if (XrmGetResource(xdb, "dmenu.redforeground", "*", &type, &xval))
colors[SchemeRed][ColFg] = strdup(xval.addr);
#endif // EMOJI_HIGHLIGHT_PATCH
XrmDestroyDatabase(xdb);
}
}

View File

@@ -0,0 +1,349 @@
/* Patches */
/* The alpha patch adds transparency for the dmenu window.
* You need to uncomment the corresponding line in config.mk to use the -lXrender library
* when including this patch.
* https://github.com/bakkeby/patches/blob/master/dmenu/dmenu-alpha-5.0_20210725_523aa08.diff
*/
#define ALPHA_PATCH 0
/* This adds padding for dmenu in similar fashion to the similarly named patch for dwm. The idea
* is to have dmenu appear on top of the bar when using said patch in dwm.
* https://github.com/bakkeby/patches/wiki/barpadding
*/
#define BARPADDING_PATCH 1
/* This patch adds a border around the dmenu window. It is intended to be used with the center
* or xyw patches, to make the menu stand out from similarly coloured windows.
* http://tools.suckless.org/dmenu/patches/border/
*/
#define BORDER_PATCH 0
/* This patch makes dmenu case-insensitive by default, replacing the
* case-insensitive -i option with a case sensitive -s option.
* http://tools.suckless.org/dmenu/patches/case-insensitive/
*/
#define CASEINSENSITIVE_PATCH 1
/* This patch centers dmenu in the middle of the screen.
* https://tools.suckless.org/dmenu/patches/center/
*/
#define CENTER_PATCH 0
/* Minor patch to enable the use of Ctrl+v (XA_PRIMARY) and Ctrl+Shift+v (CLIPBOARD) to paste.
* By default dmenu only supports Ctrl+y and Ctrl+Shift+y to paste.
*/
#define CTRL_V_TO_PASTE_PATCH 1
/* This patch adds a flag (-dy) which makes dmenu run the command given to it whenever input
* is changed with the current input as the last argument and update the option list according
* to the output of that command.
* https://tools.suckless.org/dmenu/patches/dynamicoptions/
*/
#define DYNAMIC_OPTIONS_PATCH 0
/* This patch will allow for emojis on the left side with a colored background when selected.
* To test this try running:
* $ echo -e ":b here\n:p there\n:r and here" | ./dmenu -p "Search..." -W 400 -l 20 -i -h -1
* NB: the original patch came embedded with the the xyw patch, the morecolors patch and the
* line height patch and as such is intended to be combined with these.
* https://tools.suckless.org/dmenu/patches/emoji-highlight/
*/
#define EMOJI_HIGHLIGHT_PATCH 0
/* This patch make it so that fuzzy matches gets highlighted and is therefore meant
* to be used together with the fuzzymatch patch.
* https://tools.suckless.org/dmenu/patches/fuzzyhighlight/
*/
#define FUZZYHIGHLIGHT_PATCH 1
/* This patch adds support for fuzzy-matching to dmenu, allowing users to type non-consecutive
* portions of the string to be matched.
* https://tools.suckless.org/dmenu/patches/fuzzymatch/
*/
#define FUZZYMATCH_PATCH 1
/* Adds fzf-like functionality for dmenu.
* Refer to https://github.com/DAFF0D11/dafmenu/ for documentation and example use cases.
* https://github.com/DAFF0D11/dafmenu/blob/master/patches/dmenu-fzfexpect-5.1.diff
*/
#define FZFEXPECT_PATCH 0
/* Allows dmenu's entries to be rendered in a grid by adding a new -g flag to specify
* the number of grid columns. The -g and -l options can be used together to create a
* G columns * L lines grid.
* https://tools.suckless.org/dmenu/patches/grid/
*/
#define GRID_PATCH 0
/* This patch adds the ability to move left and right through a grid.
* This patch depends on the grid patch.
* https://tools.suckless.org/dmenu/patches/gridnav/
*/
#define GRIDNAV_PATCH 0
/* This patch highlights the individual characters of matched text for each dmenu list entry.
* The fuzzy highlight patch takes precedence over this patch.
* https://tools.suckless.org/dmenu/patches/highlight/
*/
#define HIGHLIGHT_PATCH 0
/* This will automatically sort the search result so that high priority items are shown first.
* https://tools.suckless.org/dmenu/patches/highpriority/
*/
#define HIGHPRIORITY_PATCH 0
/* This patch causes dmenu to print out the current text each time a key is pressed.
* https://tools.suckless.org/dmenu/patches/incremental/
*/
#define INCREMENTAL_PATCH 0
/* This patch adds an option to provide preselected text.
* https://tools.suckless.org/dmenu/patches/initialtext/
*/
#define INITIALTEXT_PATCH 0
/* This patch adds a flag which will cause dmenu to select an item immediately if there
* is only one matching option left.
* https://tools.suckless.org/dmenu/patches/instant/
*/
#define INSTANT_PATCH 0
/* This patch adds a '-h' option which sets the minimum height of a dmenu line. This helps
* integrate dmenu with other UI elements that require a particular vertical size.
* http://tools.suckless.org/dmenu/patches/line-height/
*/
#define LINE_HEIGHT_PATCH 1
/* This patch adds a -wm flag which sets override_redirect to false; thus letting your window
* manager manage the dmenu window.
*
* This may be helpful in contexts where you don't want to exclusively bind dmenu or want to
* treat dmenu more as a "window" rather than as an overlay.
* https://tools.suckless.org/dmenu/patches/managed/
*/
#define MANAGED_PATCH 0
/* This patch adds an additional color scheme for highlighting entries adjacent to the current
* selection.
* https://tools.suckless.org/dmenu/patches/morecolor/
*/
#define MORECOLOR_PATCH 0
/* This patch adds basic mouse support for dmenu.
* https://tools.suckless.org/dmenu/patches/mouse-support/
*/
#define MOUSE_SUPPORT_PATCH 1
/* Without this patch when you press Ctrl+Enter dmenu just outputs current item and it is not
* possible to undo that.
* With this patch dmenu will output all selected items only on exit. It is also possible to
* deselect any selected item.
* Also refer to the dmenu_run replacement on the below URL that supports multiple selections.
*
* This patch is not compatible with, and takes precedence over, the json, printinputtext,
* pipeout and non-blocking stdin patches.
*
* https://tools.suckless.org/dmenu/patches/multi-selection/
*/
#define MULTI_SELECTION_PATCH 0
/* This patch provides dmenu the ability for history navigation similar to that of bash.
*
* If you take this patch then it is recommended that you also uncomment the line in the
* dmenu_run script which replaces the exec command.
*
* https://tools.suckless.org/dmenu/patches/navhistory/
*/
#define NAVHISTORY_PATCH 0
/* This patch adds back in the workaround for a BadLength error in the Xft library when color
* glyphs are used. This is for systems that do not have an updated version of the Xft library
* (or generally prefer monochrome fonts).
*/
#define NO_COLOR_EMOJI_PATCH 0
/* Adds the -S option to disable sorting menu items after matching. Useful, for example, when menu
* items are sorted by their frequency of use (using an external cache) and the most frequently
* selected items should always appear first regardless of how they were exact, prefix, or
* substring matches.
* https://tools.suckless.org/dmenu/patches/no-sort/
*/
#define NO_SORT_PATCH 0
/* This is a patch to have dmenu read stdin in a non blocking way, making it wait for input both
* from stdin and from X. This means that you can continue feeding dmenu while you type.
* This patch is meant to be used along with the incremental patch, so that you can use stdout
* to feed stdin.
*
* This patch is not compatible with the json and multi-selection patches, both of which takes
* precedence over this patch.
*
* https://tools.suckless.org/dmenu/patches/non_blocking_stdin/
*/
#define NON_BLOCKING_STDIN_PATCH 0
/* Adds text which displays the number of matched and total items in the top right corner of dmenu.
* https://tools.suckless.org/dmenu/patches/numbers/
*/
#define NUMBERS_PATCH 0
/* This patch adds simple markup for dmenu using pango markup.
* This depends on the pango library v1.44 or greater.
* You need to uncomment the corresponding lines in config.mk to use the pango libraries
* when including this patch.
*
* Note that the pango patch is incompatible with the scroll patch and will result in
* compilation errors if both are enabled.
*
* Note that the pango patch does not protect against the BadLength error from Xft
* when color glyphs are used, which means that dmenu will crash if color emoji is used.
*
* If you need color emoji then you may want to install this patched library from the AUR:
* https://aur.archlinux.org/packages/libxft-bgra/
*
* A long term fix for the libXft library is pending approval of this pull request:
* https://gitlab.freedesktop.org/xorg/lib/libxft/-/merge_requests/1
*
* Also see:
* https://developer.gnome.org/pygtk/stable/pango-markup-language.html
* https://github.com/StillANixRookie/dmenu-pango
*/
#define PANGO_PATCH 0
/* With this patch dmenu will not directly display the keyboard input, but instead replace
* it with dots. All data from stdin will be ignored.
* https://tools.suckless.org/dmenu/patches/password/
*/
#define PASSWORD_PATCH 0
/* This patch allows the selected text to be piped back out with dmenu. This can be useful if you
* want to display the output of a command on the screen.
* Only text starting with the character '#' is piped out by default.
*
* This patch is not compatible with the json and multi-select patches, both of which takes
* precedence over this one.
*
* https://tools.suckless.org/dmenu/patches/pipeout/
*/
#define PIPEOUT_PATCH 0
/* Lifted from the listfullwidth patch this simple change just avoids colors for the prompt (with
* the -p option or in config.h) by making it use the same style as the rest of the input field.
* The rest of the listfullwidth patch is covered by the vertfull patch.
* https://tools.suckless.org/dmenu/patches/listfullwidth/
*/
#define PLAIN_PROMPT_PATCH 0
/* This patch changes the behaviour of matched items and the Tab key to allow tab completion.
* https://tools.suckless.org/dmenu/patches/prefix-completion/
*/
#define PREFIXCOMPLETION_PATCH 0
/* This patch adds an option -ps to specify an item by providing the index that should be
* pre-selected.
* https://tools.suckless.org/dmenu/patches/preselect/
*/
#define PRESELECT_PATCH 0
/* This patch allows dmenu to print out the 0-based index of matched text instead of the matched
* text itself. This can be useful in cases where you would like to select entries from one array
* of text but index into another, or when you are selecting from an ordered list of non-unique
* items.
* https://tools.suckless.org/dmenu/patches/printindex/
*/
#define PRINTINDEX_PATCH 0
/* This patch adds a flag (-t) which makes Return key to ignore selection and print the input
* text to stdout. The flag basically swaps the functions of Return and Shift+Return hotkeys.
*
* This patch is not compatible with the multi-select and json patches, both of which takes
* precedence over this one.
*
* https://tools.suckless.org/dmenu/patches/printinputtext/
*/
#define PRINTINPUTTEXT_PATCH 0
/* This patch adds a new flag to dmenu with which text input will be rejected if it would
* result in no matching item.
* https://tools.suckless.org/dmenu/patches/reject-no-match/
*/
#define REJECTNOMATCH_PATCH 0
/* The input width used to be relative to the input options prior to commit e1e1de7:
* https://git.suckless.org/dmenu/commit/e1e1de7b3b8399cba90ddca9613f837b2dbef7b9.html
*
* This had a performance hit when using large data sets and was removed in favour of having the
* input width take up 1/3rd of the available space.
*
* This option adds that feature back in with some performance optimisations at the cost of
* accuracy and correctness.
*/
#define RELATIVE_INPUT_WIDTH_PATCH 0
/* This patch adds a '-1' option which disables Shift-Return and Ctrl-Return.
* This guarantees that dmenu will only output one item, and that item was read from stdin.
* The original patch used '-r'. This was changed to '-1' to avoid conflict with the incremental
* patch.
* https://tools.suckless.org/dmenu/patches/restrict-return/
*/
#define RESTRICT_RETURN_PATCH 0
/* This patch adds support for text scrolling and no longer appends '...' for long input as
* it can handle long text.
* https://tools.suckless.org/dmenu/patches/scroll/
*/
#define SCROLL_PATCH 0
/* This patch adds -d and -D flags which separates the input into two halves; one half to be
* displayed in dmenu and the other to be printed to stdout. This patch takes precedence over
* the TSV patch.
* https://tools.suckless.org/dmenu/patches/separator/
*/
#define SEPARATOR_PATCH 0
/* This patch allows the symbols, which are printed in dmenu to indicate that either the input
* is too long or there are too many options to be shown in dmenu in one line, to be defined.
* https://tools.suckless.org/dmenu/patches/symbols/
*/
#define SYMBOLS_PATCH 0
/* With this patch dmenu will split input lines at first tab character and only display first
* part, but it will perform matching on and output full lines as usual.
*
* This can be useful if you want to separate data and representation, for example, a music
* player wrapper can display only a track title to user, but still supply full filename to
* the underlying script.
* https://tools.suckless.org/dmenu/patches/tsv/
*/
#define TSV_PATCH 0
/* This patch prevents dmenu from indenting items at the same level as the prompt length.
* https://tools.suckless.org/dmenu/patches/vertfull/
*/
#define VERTFULL_PATCH 0
/* Adds extended window manager hints such as _NET_WM_WINDOW_TYPE and _NET_WM_WINDOW_TYPE_DOCK.
* https://github.com/Baitinq/dmenu/blob/master/patches/dmenu-wm_type.diff
*/
#define WMTYPE_PATCH 0
/* This patch adds the ability to configure dmenu via Xresources. At startup, dmenu will read and
* apply the resources named below:
* dmenu.font : font or font set
* dmenu.background : normal background color
* dmenu.foreground : normal foreground color
* dmenu.selbackground : selected background color
* dmenu.selforeground : selected foreground color
*
* See patch/xresources.c for more color settings.
*
* https://tools.suckless.org/dmenu/patches/xresources/
*/
#define XRESOURCES_PATCH 0
/* This patch adds options for specifying dmenu window position and width.
* The center patch takes precedence over the XYW patch if enabled.
* https://tools.suckless.org/dmenu/patches/xyw/
*/
#define XYW_PATCH 0

4
desktop/.dmenu/recompile Executable file
View File

@@ -0,0 +1,4 @@
#!/bin/bash
rm -f ./config.h
sudo make clean install

90
desktop/.dmenu/stest.1 Normal file
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)

109
desktop/.dmenu/stest.c Normal file
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 (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;
}

36
desktop/.dmenu/util.c Normal file
View File

@@ -0,0 +1,36 @@
/* See LICENSE file for copyright and license details. */
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
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);
}
void *
ecalloc(size_t nmemb, size_t size)
{
void *p;
if (!(p = calloc(nmemb, size)))
die("calloc:");
return p;
}

12
desktop/.dmenu/util.h Normal file
View File

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