mirror of
https://github.com/eRgo35/dots.git
synced 2025-12-16 23:46:13 +01:00
moving software to separate submodules part 1
This commit is contained in:
5
desktop/.dmenu/.gitignore
vendored
Normal file
5
desktop/.dmenu/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
*.o
|
||||
config.h
|
||||
patches.h
|
||||
dmenu
|
||||
stest
|
||||
30
desktop/.dmenu/LICENSE
Normal file
30
desktop/.dmenu/LICENSE
Normal 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
67
desktop/.dmenu/Makefile
Normal 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
24
desktop/.dmenu/README
Normal 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
260
desktop/.dmenu/README.md
Normal 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
49
desktop/.dmenu/arg.h
Normal 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
151
desktop/.dmenu/config.def.h
Normal 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
42
desktop/.dmenu/config.mk
Normal 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
194
desktop/.dmenu/dmenu.1
Normal 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
2187
desktop/.dmenu/dmenu.c
Normal file
File diff suppressed because it is too large
Load Diff
13
desktop/.dmenu/dmenu_path
Executable file
13
desktop/.dmenu/dmenu_path
Executable 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
6
desktop/.dmenu/dmenu_run
Executable 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
696
desktop/.dmenu/drw.c
Normal 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
103
desktop/.dmenu/drw.h
Normal 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
|
||||
8
desktop/.dmenu/patch/center.c
Normal file
8
desktop/.dmenu/patch/center.c
Normal 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;
|
||||
}
|
||||
91
desktop/.dmenu/patch/dynamicoptions.c
Normal file
91
desktop/.dmenu/patch/dynamicoptions.c
Normal 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;
|
||||
}
|
||||
}
|
||||
2
desktop/.dmenu/patch/dynamicoptions.h
Normal file
2
desktop/.dmenu/patch/dynamicoptions.h
Normal file
@@ -0,0 +1,2 @@
|
||||
static void refreshoptions();
|
||||
static void readstream(FILE* stream);
|
||||
57
desktop/.dmenu/patch/fuzzyhighlight.c
Normal file
57
desktop/.dmenu/patch/fuzzyhighlight.c
Normal 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++;
|
||||
}
|
||||
}
|
||||
106
desktop/.dmenu/patch/fuzzymatch.c
Normal file
106
desktop/.dmenu/patch/fuzzymatch.c
Normal 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();
|
||||
}
|
||||
39
desktop/.dmenu/patch/fzfexpect.c
Normal file
39
desktop/.dmenu/patch/fzfexpect.c
Normal 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
|
||||
1
desktop/.dmenu/patch/fzfexpect.h
Normal file
1
desktop/.dmenu/patch/fzfexpect.h
Normal file
@@ -0,0 +1 @@
|
||||
static void expect(char *expect, XKeyEvent *ev);
|
||||
51
desktop/.dmenu/patch/highlight.c
Normal file
51
desktop/.dmenu/patch/highlight.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
35
desktop/.dmenu/patch/highpriority.c
Normal file
35
desktop/.dmenu/patch/highpriority.c
Normal 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;
|
||||
}
|
||||
2
desktop/.dmenu/patch/highpriority.h
Normal file
2
desktop/.dmenu/patch/highpriority.h
Normal file
@@ -0,0 +1,2 @@
|
||||
static int arrayhas(char **list, int length, char *item);
|
||||
|
||||
38
desktop/.dmenu/patch/include.c
Normal file
38
desktop/.dmenu/patch/include.c
Normal 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
|
||||
15
desktop/.dmenu/patch/include.h
Normal file
15
desktop/.dmenu/patch/include.h
Normal 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
|
||||
159
desktop/.dmenu/patch/mousesupport.c
Normal file
159
desktop/.dmenu/patch/mousesupport.c
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
53
desktop/.dmenu/patch/multiselect.c
Normal file
53
desktop/.dmenu/patch/multiselect.c
Normal 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;
|
||||
}
|
||||
}
|
||||
126
desktop/.dmenu/patch/navhistory.c
Normal file
126
desktop/.dmenu/patch/navhistory.c
Normal 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);
|
||||
}
|
||||
68
desktop/.dmenu/patch/nonblockingstdin.c
Normal file
68
desktop/.dmenu/patch/nonblockingstdin.c
Normal 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();
|
||||
}
|
||||
}
|
||||
1
desktop/.dmenu/patch/nonblockingstdin.h
Normal file
1
desktop/.dmenu/patch/nonblockingstdin.h
Normal file
@@ -0,0 +1 @@
|
||||
static void readevent();
|
||||
16
desktop/.dmenu/patch/numbers.c
Normal file
16
desktop/.dmenu/patch/numbers.c
Normal 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);
|
||||
}
|
||||
4
desktop/.dmenu/patch/numbers.h
Normal file
4
desktop/.dmenu/patch/numbers.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#define NUMBERSMAXDIGITS 100
|
||||
#define NUMBERSBUFSIZE (NUMBERSMAXDIGITS * 2) + 1
|
||||
|
||||
static void recalculatenumbers();
|
||||
168
desktop/.dmenu/patch/scroll.c
Normal file
168
desktop/.dmenu/patch/scroll.c
Normal 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;
|
||||
}
|
||||
3
desktop/.dmenu/patch/scroll.h
Normal file
3
desktop/.dmenu/patch/scroll.h
Normal 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);
|
||||
90
desktop/.dmenu/patch/xresources.c
Normal file
90
desktop/.dmenu/patch/xresources.c
Normal 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);
|
||||
}
|
||||
}
|
||||
349
desktop/.dmenu/patches.def.h
Normal file
349
desktop/.dmenu/patches.def.h
Normal 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
4
desktop/.dmenu/recompile
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
rm -f ./config.h
|
||||
sudo make clean install
|
||||
90
desktop/.dmenu/stest.1
Normal file
90
desktop/.dmenu/stest.1
Normal 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
109
desktop/.dmenu/stest.c
Normal 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
36
desktop/.dmenu/util.c
Normal 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
12
desktop/.dmenu/util.h
Normal 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);
|
||||
Reference in New Issue
Block a user