change dmenu to patched build

This commit is contained in:
doman 2025-05-26 18:01:40 +02:00
parent d244cdb4a5
commit fdc643d53e
39 changed files with 99 additions and 4214 deletions

5
menu/.gitignore vendored
View file

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

View file

@ -14,10 +14,7 @@ all: dmenu stest
config.h:
cp config.def.h $@
patches.h:
cp patches.def.h $@
$(OBJ): arg.h config.h config.mk drw.h patches.h
$(OBJ): arg.h config.h config.mk drw.h
dmenu: dmenu.o drw.o util.o
$(CC) -o $@ dmenu.o drw.o util.o $(LDFLAGS)

View file

@ -1,272 +0,0 @@
Similar to [dwm-flexipatch](https://github.com/bakkeby/dwm-flexipatch) this dmenu 5.3 (b1e217b,
2025-03-17) 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:
2024-07-17 - Added the input method patch
2024-07-16 - Added the mouse motion support patch
2023-06-15 - Added the caret width patch
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
- [caret-width](https://github.com/DarkSamus669/dmenu-patches/blob/main/dmenu-caretwidth-5.2.diff)
- makes the caret width configurable and overridable via a command line option
- [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
- input-method
- adds support for input methods (fctix, ibus, etc.)
- [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

View file

@ -1,153 +1,23 @@
/* 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 CARET_WIDTH_PATCH
static int caret_width = 2; /* -cw option; set default caret width */
#endif // CARET_WIDTH_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 = 0; /* -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 = 10; /* 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
static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */
/* -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
{
static const char *fonts[] = {
"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
[SchemeSelHighlight] = { OPAQUE, baralpha, borderalpha },
[SchemeNormHighlight] = { OPAQUE, baralpha, borderalpha },
#endif // HIGHLIGHT_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 */
static const char *colors[SchemeLast][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
[SchemeSelHighlight] = { "#ffc978", "#005577" },
[SchemeNormHighlight] = { "#ffc978", "#222222" },
#endif // HIGHLIGHT_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
[SchemeSel] = { "#eeeeee", "#005577" },
[SchemeOut] = { "#000000", "#00ffff" },
};
/* -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 = 0; /* -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

23
menu/config.h Normal file
View file

@ -0,0 +1,23 @@
/* 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 */
/* -fn option overrides fonts[0]; default X11 font or font set */
static const char *fonts[] = {
"monospace:size=10"
};
static const char *prompt = NULL; /* -p option; prompt to the left of input field */
static const char *colors[SchemeLast][2] = {
/* fg bg */
[SchemeNorm] = { "#bbbbbb", "#222222" },
[SchemeSel] = { "#eeeeee", "#005577" },
[SchemeOut] = { "#000000", "#00ffff" },
};
/* -l option; if nonzero, dmenu uses vertical list with given number of lines */
static unsigned int lines = 0;
/*
* Characters not considered part of a word while deleting words
* for example: " /?\"&[]"
*/
static const char worddelimiters[] = " ";

View file

@ -19,22 +19,12 @@ FREETYPEINC = /usr/include/freetype2
#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}
INCS = -I$(X11INC) -I$(FREETYPEINC)
LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS)
# flags
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS) $(EXTRAFLAGS)
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS)
CFLAGS = -std=c99 -pedantic -Wall -Os $(INCS) $(CPPFLAGS)
LDFLAGS = $(LIBS)

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,2 @@
#!/bin/sh
export _JAVA_AWT_WM_NONREPARENTING=1
dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} &
# 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"} &

View file

@ -5,11 +5,9 @@
#include <X11/Xlib.h>
#include <X11/Xft/Xft.h>
#include "patches.h"
#include "drw.h"
#include "util.h"
#if !PANGO_PATCH || HIGHLIGHT_PATCH
#define UTF_INVALID 0xFFFD
static int
@ -48,23 +46,8 @@ utf8decode(const char *s_in, long *u, int *err)
return len;
}
#if HIGHLIGHT_PATCH
int
utf8len(const char *c)
{
long utf8codepoint = 0;
int utf8err = 0;
return utf8decode(c, &utf8codepoint, &utf8err);
}
#endif // HIGHLIGHT_PATCH
#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));
@ -73,16 +56,8 @@ drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h
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;
@ -98,11 +73,7 @@ drw_resize(Drw *drw, unsigned int w, unsigned int h)
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
@ -110,49 +81,10 @@ 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.
*/
@ -187,21 +119,6 @@ xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
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;
@ -210,38 +127,18 @@ xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
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)
{
@ -259,16 +156,7 @@ drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
}
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)
{
@ -277,40 +165,23 @@ drw_fontset_free(Fnt *font)
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;
@ -320,22 +191,16 @@ drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
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)
@ -356,77 +221,6 @@ drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int
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 i, ty, th;
unsigned int ew, eh;
XftDraw *d = NULL;
size_t 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, &eh, markup);
th = eh;
/* shorten text if necessary */
for (len = MIN(len, sizeof(buf) - 1); len && ew > w; len--) {
drw_font_getexts(drw->font, text, len, &ew, &eh, markup);
if (eh > th)
th = eh;
}
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 - th) / 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)
{
@ -445,7 +239,6 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
/* keep track of a couple codepoints for which we have no match. */
static unsigned int nomatches[128], ellipsis_width, invalid_width;
static const char invalid[] = "<EFBFBD>";
const char *ellipsis = "...";
if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts)
return 0;
@ -455,24 +248,22 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
} 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
if (w < lpad)
return x + w;
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);
ellipsis_width = drw_fontset_getwidth(drw, "...");
if (!invalid_width && render)
invalid_width = drw_fontset_getwidth(drw, invalid);
while (1) {
ew = ellipsis_len = utf8err = utf8strlen = 0;
ew = ellipsis_len = utf8err = utf8charlen = utf8strlen = 0;
utf8str = text;
nextfont = NULL;
while (*text) {
@ -498,12 +289,12 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
else
utf8strlen = ellipsis_len;
} else if (curfont == usedfont) {
text += utf8charlen;
text += utf8charlen;
utf8strlen += utf8err ? 0 : utf8charlen;
ew += utf8err ? 0 : tmpw;
} else {
nextfont = curfont;
}
} else {
nextfont = curfont;
}
break;
}
}
@ -519,7 +310,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
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;
}
@ -529,8 +320,8 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
x += invalid_width;
w -= invalid_width;
}
if (render && overflow && ellipsis_w)
drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, ellipsis, invert);
if (render && overflow)
drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert);
if (!*text || overflow) {
break;
@ -562,9 +353,6 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
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);
@ -593,7 +381,6 @@ no_match:
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)
@ -605,24 +392,6 @@ drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
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)
{
@ -639,29 +408,7 @@ drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int 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 = r.height / PANGO_SCALE;
}
#else
void
drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h)
{
@ -676,7 +423,6 @@ drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w,
if (h)
*h = font->h;
}
#endif // PANGO_PATCH
Cur *
drw_cur_create(Drw *drw, int shape)
@ -700,7 +446,3 @@ drw_cur_free(Drw *drw, Cur *cursor)
XFreeCursor(drw->dpy, cursor->cursor);
free(cursor);
}
#if SCROLL_PATCH
#include "patch/scroll.c"
#endif

View file

@ -1,10 +1,5 @@
/* 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;
@ -12,13 +7,9 @@ typedef struct {
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 */
@ -29,79 +20,39 @@ typedef struct {
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
#if HIGHLIGHT_PATCH
int utf8len(const char *c);
#endif // HIGHLIGHT_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

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

@ -1,91 +0,0 @@
static void
refreshoptions(void)
{
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

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

View file

@ -1,115 +0,0 @@
#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;
#if INSTANT_PATCH
if (instant && matches && matches==matchend) {
puts(matches->text);
cleanup();
exit(0);
}
#endif // INSTANT_PATCH
calcoffsets();
}

View file

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

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

View file

@ -1,107 +0,0 @@
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 indent, highlightlen;
#if FUZZYMATCH_PATCH
int i;
#endif // FUZZYMATCH_PATCH
#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
if (!(strlen(itemtext) && strlen(text)))
return;
/* Do not highlight items scheduled for output */
#if MULTI_SELECTION_PATCH
if (issel(item->id))
return;
#else
if (item->out)
return;
#endif // MULTI_SELECTION_PATCH
drw_setscheme(drw, scheme[item == sel ? SchemeSelHighlight : SchemeNormHighlight]);
#if FUZZYMATCH_PATCH
if (fuzzy) {
for (i = 0, highlight = itemtext; *highlight && text[i];) {
highlightlen = utf8len(highlight);
#if FUZZYMATCH_PATCH
if (!fstrncmp(&(*highlight), &text[i], highlightlen))
#else
if (*highlight == text[i])
#endif // FUZZYMATCH_PATCH
{
/* get indentation */
restorechar = *highlight;
*highlight = '\0';
indent = TEXTW(itemtext) - lrpad;
*highlight = restorechar;
/* highlight character */
restorechar = highlight[highlightlen];
highlight[highlightlen] = '\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[highlightlen] = restorechar;
i += highlightlen;
}
highlight++;
}
return;
}
#endif // FUZZYMATCH_PATCH
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';
indent = TEXTW(itemtext);
itemtext[highlightlen] = restorechar;
// Move highlight str end, draw highlight, & restore
restorechar = highlight[strlen(token)];
highlight[strlen(token)] = '\0';
if (indent - (lrpad / 2) - 1 < maxw)
drw_text(
drw,
x + indent - (lrpad / 2) - 1,
y,
MIN(maxw - indent, 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

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

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

View file

@ -1,39 +0,0 @@
#if CENTER_PATCH
#include "center.c"
#endif
#if 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 INPUTMETHOD_PATCH
#include "inputmethod.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

@ -1,27 +0,0 @@
#if DYNAMIC_OPTIONS_PATCH
#include "dynamicoptions.h"
#endif
#if FZFEXPECT_PATCH
#include "fzfexpect.h"
#endif
#if INPUTMETHOD_PATCH
#include "inputmethod.h"
#endif
#if MOUSE_SUPPORT_PATCH
#include "mousesupport.h"
#endif
#if MULTI_SELECTION_PATCH
#include "multiselect.h"
#endif
#if NAVHISTORY_PATCH
#include "navhistory.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

@ -1,196 +0,0 @@
static size_t nextrunetext(const char *text, size_t position, int inc)
{
ssize_t n;
/* return location of next utf8 rune in the given direction (+1 or -1) */
for (n = position + inc; n + inc >= 0 && (text[n] & 0xc0) == 0x80; n += inc)
;
return n;
}
/* return bytes from beginning of text to nth utf8 rune to the right */
static size_t runebytes(const char *text, size_t n)
{
size_t ret;
ret = 0;
while (n-- > 0)
ret += nextrunetext(text + ret, 0, 1);
return ret;
}
/* return number of characters from beginning of text to nth byte to the right
*/
static size_t runechars(const char *text, size_t n)
{
size_t ret, i;
ret = i = 0;
while (i < n) {
i += nextrunetext(text + i, 0, 1);
ret++;
}
return ret;
}
/* move caret on pre-edit text */
static void preeditcaret(XIC xic, XPointer clientdata, XPointer calldata)
{
XIMPreeditCaretCallbackStruct *pcaret;
(void)xic;
pcaret = (XIMPreeditCaretCallbackStruct *)calldata;
if (!pcaret)
return;
switch (pcaret->direction) {
case XIMForwardChar:
cursor = nextrune(+1);
break;
case XIMBackwardChar:
cursor = nextrune(-1);
break;
case XIMForwardWord:
movewordedge(+1);
break;
case XIMBackwardWord:
movewordedge(-1);
break;
case XIMLineStart:
cursor = 0;
break;
case XIMLineEnd:
if (preview[cursor] != '\0')
cursor = strlen(preview);
break;
case XIMAbsolutePosition:
cursor = runebytes(text, pcaret->position);
break;
case XIMDontChange:
/* do nothing */
break;
case XIMCaretUp:
case XIMCaretDown:
case XIMNextLine:
case XIMPreviousLine:
/* not implemented */
break;
}
pcaret->position = runechars(preview, cursor);
}
/* start input method pre-editing */
static int preeditstart(XIC xic, XPointer clientdata, XPointer calldata)
{
(void)xic;
(void)calldata;
(void)clientdata;
composing = 1;
printf("PREEDIT\n");
return BUFSIZ;
}
/* end input method pre-editing */
static void preeditdone(XIC xic, XPointer clientdata, XPointer calldata)
{
(void)xic;
(void)clientdata;
(void)calldata;
printf("DONE\n");
composing = 0;
}
/* draw input method pre-edit text */
static void preeditdraw(XIC xic, XPointer clientdata, XPointer calldata)
{
XIMPreeditDrawCallbackStruct *pdraw;
size_t beg, dellen, inslen, endlen;
printf("DRAW\n");
(void)xic;
pdraw = (XIMPreeditDrawCallbackStruct *)calldata;
if (!pdraw)
return;
/* we do not support wide characters */
if (pdraw->text && pdraw->text->encoding_is_wchar == True) {
fputs("warning: wchar is not supportecd; use utf8", stderr);
return;
}
beg = runebytes(text, pdraw->chg_first);
dellen = runebytes(preview + beg, pdraw->chg_length);
inslen = pdraw->text ? runebytes(pdraw->text->string.multi_byte, pdraw->text->length) : 0;
endlen = 0;
if (beg + dellen < strlen(preview))
endlen = strlen(preview + beg + dellen);
/* we cannot change text past the end of our pre-edit string */
if (beg + dellen >= BUFSIZ || beg + inslen >= BUFSIZ)
return;
/* get space for text to be copied, and copy it */
memmove(preview + beg + inslen, preview + beg + dellen, endlen + 1);
if (pdraw->text && pdraw->text->length)
memcpy(preview + beg, pdraw->text->string.multi_byte, inslen);
(preview + beg + inslen + endlen)[0] = '\0';
/* get caret position */
cursor = runebytes(text, pdraw->caret);
}
static void init_input_method(XIM xim)
{
XVaNestedList preedit = NULL;
XICCallback start, done, draw, caret;
XIMStyle preeditstyle;
XIMStyle statusstyle;
XIMStyles *imstyles;
int i;
/* get styles supported by input method */
if (XGetIMValues(xim, XNQueryInputStyle, &imstyles, NULL) != NULL)
fputs("XGetIMValues: could not obtain input method values", stderr);
/* check whether input method support on-the-spot pre-editing */
preeditstyle = XIMPreeditNothing;
statusstyle = XIMStatusNothing;
for (i = 0; i < imstyles->count_styles; i++) {
if (imstyles->supported_styles[i] & XIMPreeditCallbacks) {
preeditstyle = XIMPreeditCallbacks;
break;
}
}
/* create callbacks for the input context */
start.client_data = NULL;
done.client_data = NULL;
draw.client_data = (XPointer)text;
caret.client_data = (XPointer)text;
start.callback = (XICProc)preeditstart;
done.callback = (XICProc)preeditdone;
draw.callback = (XICProc)preeditdraw;
caret.callback = (XICProc)preeditcaret;
/* create list of values for input context */
preedit = XVaCreateNestedList(0, XNPreeditStartCallback, &start, XNPreeditDoneCallback,
&done, XNPreeditDrawCallback, &draw, XNPreeditCaretCallback,
&caret, NULL);
if (preedit == NULL)
fputs("XVaCreateNestedList: could not create nested list", stderr);
xic = XCreateIC(xim, XNInputStyle, preeditstyle | statusstyle, XNPreeditAttributes, preedit,
XNClientWindow, win, XNFocusWindow, win, NULL);
XFree(preedit);
long eventmask;
/* get events the input method is interested in */
if (XGetICValues(xic, XNFilterEvents, &eventmask, NULL))
fputs("XGetICValues: could not obtain input context values", stderr);
XSelectInput(dpy, win,
ExposureMask | KeyPressMask | VisibilityChangeMask | ButtonPressMask |
PointerMotionMask | eventmask);
}

View file

@ -1,11 +0,0 @@
static int composing;
static char preview[512] = "";
static size_t nextrunetext(const char *text, size_t position, int inc);
static size_t runebytes(const char *text, size_t n);
static size_t runechars(const char *text, size_t n);
static void preeditcaret(XIC xic, XPointer clientdata, XPointer calldata);
static int preeditstart(XIC xic, XPointer clientdata, XPointer calldata);
static void preeditdone(XIC xic, XPointer clientdata, XPointer calldata);
static void preeditdraw(XIC xic, XPointer clientdata, XPointer calldata);
static void init_input_method(XIM xim);

View file

@ -1,294 +0,0 @@
void
buttonpress(XEvent *e)
{
struct item *item;
XButtonPressedEvent *ev = &e->xbutton;
int x = 0, y = 0, h = bh, w;
#if GRID_PATCH
int i, cols;
#endif // GRID_PATCH
if (ev->window != win) {
/* automatically close dmenu if the user clicks outside of dmenu, but
* ignore the scroll wheel and buttons above that */
if (ev->button <= Button3) {
exit(1);
}
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) {
#if GRID_PATCH
cols = columns ? columns : 1;
for (i = 0, item = curr; item != next; item = item->right, i++) {
if (
(ev->y >= y + ((i % lines) + 1) * bh) && // line y start
(ev->y <= y + ((i % lines) + 2) * bh) && // line y end
(ev->x >= x + ((i / lines) * (w / cols))) && // column x start
(ev->x <= x + ((i / lines + 1) * (w / cols))) // column x end
) {
clickitem(item, ev);
return;
}
}
#else
/* vertical list: (ctrl)left-click on item */
for (item = curr; item != next; item = item->right) {
y += h;
if (ev->y >= y && ev->y <= (y + h)) {
clickitem(item, ev);
return;
}
}
#endif // GRID_PATCH
} 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) {
clickitem(item, ev);
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;
}
}
}
static void
clickitem(struct item *item, XButtonEvent *ev)
{
#if RESTRICT_RETURN_PATCH
if (restrict_return && (ev->state & (ShiftMask | ControlMask)))
return;
#endif // RESTRICT_RETURN_PATCH
#if !MULTI_SELECTION_PATCH
#if PIPEOUT_PATCH
if (item && !(ev->state & ShiftMask))
{
if (item->text[0] == startpipe[0]) {
strncpy(item->text + strlen(item->text),pipeout,8);
puts(item->text+1);
}
#if PRINTINDEX_PATCH
if (print_index) {
printf("%d\n", item->index);
} else {
#if SEPARATOR_PATCH
puts(item->text_output);
#else
puts(item->text);
#endif // SEPARATOR_PATCH
}
#else
puts(item->text);
#endif // PRINTINDEX_PATCH
} else {
if (text[0] == startpipe[0]) {
strncpy(text + strlen(text),pipeout,8);
puts(text+1);
}
puts(text);
}
#elif PRINTINDEX_PATCH
if (print_index) {
printf("%d\n", item->index);
} else {
#if SEPARATOR_PATCH
puts(item->text_output);
#else
puts(item->text);
#endif // SEPARATOR_PATCH
}
#elif SEPARATOR_PATCH
puts(item->text_output);
#else
puts(item->text);
#endif // PIPEOUT_PATCH | PRINTINDEX_PATCH
#endif // MULTI_SELECTION_PATCH
sel = item;
if (!(ev->state & ControlMask)) {
#if NAVHISTORY_PATCH
savehistory(item->text);
#endif // NAVHISTORY_PATCH
#if MULTI_SELECTION_PATCH
selsel();
printsel(ev->state);
#endif // MULTI_SELECTION_PATCH
cleanup();
exit(0);
}
#if MULTI_SELECTION_PATCH
selsel();
#else
sel->out = 1;
#endif // MULTI_SELECTION_PATCH
drawmenu();
}
#if MOTION_SUPPORT_PATCH
void
motionevent(XButtonEvent *ev)
{
struct item *item;
int x = 0, y = 0, w;
#if GRID_PATCH
int i, cols;
#endif // GRID_PATCH
if (ev->window != win || matches == 0)
return;
if (prompt && *prompt)
x += promptw;
if (lines > 0) {
/* input field */
w = mw - x;
#if GRID_PATCH
cols = columns ? columns : 1;
/* grid view or vertical list */
for (i = 0, item = curr; item != next; item = item->right, i++) {
if (
(ev->y >= y + ((i % lines) + 1) * bh) && // line y start
(ev->y <= y + ((i % lines) + 2) * bh) && // line y end
(ev->x >= x + ((i / lines) * (w / cols))) && // column x start
(ev->x <= x + ((i / lines + 1) * (w / cols))) // column x end
) {
sel = item;
calcoffsets();
drawmenu();
break;
}
}
#else
/* vertical list */
w = mw - x;
for (item = curr; item != next; item = item->right) {
y += bh;
if (ev->y >= y && ev->y <= (y + bh)) {
sel = item;
calcoffsets();
drawmenu();
break;
}
}
#endif // GRID_PATCH
return;
}
/* left-click on left arrow */
x += inputw;
#if SYMBOLS_PATCH
w = TEXTW(symbol_1);
#else
w = TEXTW("<");
#endif // SYMBOLS_PATCH
/* horizontal list */
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) {
sel = item;
calcoffsets();
drawmenu();
break;
}
}
}
#endif

View file

@ -1,5 +0,0 @@
static void buttonpress(XEvent *e);
static void clickitem(struct item *item, XButtonEvent *ev);
#if MOTION_SUPPORT_PATCH
static void motionevent(XButtonEvent *ev);
#endif // MOTION_SUPPORT_PATCH

View file

@ -1,69 +0,0 @@
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
#if SEPARATOR_PATCH
puts(items[selid[i]].text_output);
#else
puts(items[selid[i]].text);
#endif // SEPARATOR_PATCH
#elif SEPARATOR_PATCH
puts(items[selid[i]].text_output);
#else
puts(items[selid[i]].text);
#endif // PRINTINDEX_PATCH | SEPARATOR_PATCH
}
if (sel && !(state & ShiftMask)) {
#if PRINTINDEX_PATCH
if (print_index)
printf("%d\n", sel->index);
else
#if SEPARATOR_PATCH
puts(sel->text_output);
#else
puts(sel->text);
#endif // SEPARATOR_PATCH
#elif SEPARATOR_PATCH
puts(sel->text_output);
#else
puts(sel->text);
#endif // PRINTINDEX_PATCH | SEPARATOR_PATCH
} else
puts(text);
}
static void
selsel(void)
{
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

@ -1 +0,0 @@
static int issel(size_t id);

View file

@ -1,126 +0,0 @@
static char *histfile;
static char **history;
static size_t histsz, histpos;
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);
}
}
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();
}
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

@ -1,3 +0,0 @@
static void loadhistory(void);
static void navhistory(int dir);
static void savehistory(char *input);

View file

@ -1,68 +0,0 @@
#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

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

View file

@ -1,16 +0,0 @@
static char numbers[NUMBERSBUFSIZE] = "";
static void
recalculatenumbers(void)
{
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

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

View file

@ -1,173 +0,0 @@
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 utf8err = 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);
#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
}
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, &utf8err);
if (!utf8charlen) {
textlen = i;
break;
}
} else {
n = utf8nextchar(text, textlen, i, -1);
utf8charlen = utf8decode(text + n, &utf8codepoint, &utf8err);
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

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

@ -1,90 +0,0 @@
#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
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
#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

@ -1,370 +0,0 @@
/* 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 0
/* 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
/* By default the caret in dmenu has a width of 2 pixels. This patch makes that configurable
* as well as overridable via a command line option.
* https://github.com/DarkSamus669/dmenu-patches/blob/main/dmenu-caretwidth-5.2.diff
*/
#define CARET_WIDTH_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 0
/* 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 0
/* 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 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 0
/* 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.
* If combined with the fuzzymatch patch then fuzzy highlight will be used for highlighting
* depending on whether fuzzy matching is enabled.
*
* Known issue: highlighting does not work properly when pango markup is used
*
* https://tools.suckless.org/dmenu/patches/highlight/
* https://tools.suckless.org/dmenu/patches/fuzzyhighlight/
*/
#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
/* Adds support for input methods (fctix, ibus, etc.) allowing the user to change the
* keyboard layout while dmenu is open.
* https://github.com/bakkeby/dmenu-flexipatch/pull/22
*/
#define INPUTMETHOD_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 0
/* 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 0
/* Expands the above to support mouse hovering.
* https://tools.suckless.org/dmenu/patches/mouse-support/
*/
#define MOTION_SUPPORT_PATCH 0
/* 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
*
* Known issue: not compatible with the scroll patch
*
* 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.
*
* Known issue: not compatible with the pango patch
*
* 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

View file

@ -1,4 +1,5 @@
/* See LICENSE file for copyright and license details. */
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@ -10,17 +11,17 @@ void
die(const char *fmt, ...)
{
va_list ap;
int saved_errno;
saved_errno = errno;
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);
}
if (fmt[0] && fmt[strlen(fmt)-1] == ':')
fprintf(stderr, " %s", strerror(saved_errno));
fputc('\n', stderr);
exit(1);
}

View file

@ -1,11 +1,7 @@
/* 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))
#define LENGTH(X) (sizeof (X) / sizeof (X)[0])