Compare commits
32 Commits
3a505cebe8
...
main
Author | SHA1 | Date |
---|---|---|
Jef Roosens | 78280fae2b | |
Jef Roosens | 8dfee8f81b | |
Tom Schwindl | e68533eb4b | |
Hiltjo Posthuma | c0783a60ad | |
Hiltjo Posthuma | 4717a35cfb | |
NRK | 2960a6644f | |
NRK | 61d32c8d35 | |
Hiltjo Posthuma | 16524400dc | |
Hiltjo Posthuma | 78e64ffb9c | |
Hiltjo Posthuma | 801a3e50dd | |
Hiltjo Posthuma | a5a24f475f | |
NRK | af8fbc7a90 | |
NRK | e29eca6fdb | |
Hiltjo Posthuma | d4b980b763 | |
Hiltjo Posthuma | 273d967324 | |
NRK | ad50c7b741 | |
NRK | cced315e68 | |
NRK | 3a060d98f5 | |
NRK | 3450386f77 | |
NRK | 49c6f40235 | |
NRK | 576d46bf00 | |
NRK | 2f8a305376 | |
Jef Roosens | f84f1080d8 | |
Jef Roosens | e1a14e69f6 | |
Jef Roosens | 39850bd500 | |
Jef Roosens | 2055ca2d9b | |
Jef Roosens | 9ce1c3e3da | |
Jef Roosens | 0d852f8a7c | |
Jef Roosens | d8ff6423a6 | |
Jef Roosens | a140c508b0 | |
Jef Roosens | 7630d80f21 | |
Jef Roosens | 93b21c779d |
|
@ -0,0 +1,12 @@
|
|||
*.rej
|
||||
*.orig
|
||||
|
||||
# build artifacts
|
||||
*.o
|
||||
dmenu
|
||||
stest
|
||||
|
||||
# makepkg
|
||||
src/
|
||||
pkg/
|
||||
*.pkg*
|
|
@ -0,0 +1,45 @@
|
|||
matrix:
|
||||
# PLATFORM:
|
||||
# - linux/amd64
|
||||
# - linux/arm64
|
||||
|
||||
ARCH:
|
||||
# tuur
|
||||
- tigerlake
|
||||
# cenny
|
||||
- skylake
|
||||
|
||||
branches: main
|
||||
platform: linux/amd64
|
||||
|
||||
when:
|
||||
event: push
|
||||
|
||||
pipeline:
|
||||
build:
|
||||
image: 'menci/archlinuxarm:base-devel'
|
||||
commands:
|
||||
# Add my bur repo to pacman for the libxft-bgra dependency
|
||||
- echo -e '[bur]\nServer = https://arch.r8r.be/$repo/$arch\nSigLevel = Optional' >> /etc/pacman.conf
|
||||
# Update packages
|
||||
- pacman -Syu --noconfirm
|
||||
# Create non-root user to perform build & switch to their home
|
||||
- groupadd -g 1000 builder
|
||||
- useradd -mg builder builder
|
||||
- chown -R builder:builder "$PWD"
|
||||
- "echo 'builder ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers"
|
||||
- su builder
|
||||
# Build the package
|
||||
- >
|
||||
MAKEFLAGS="-j$(nproc)"
|
||||
makepkg -s --noconfirm --needed
|
||||
CFLAGS="-O3 -flto -march=${ARCH}"
|
||||
CARCH="x86_64_${ARCH}"
|
||||
|
||||
publish:
|
||||
image: 'curlimages/curl'
|
||||
commands:
|
||||
# Publish the package
|
||||
- 'curl -s -XPOST -H "X-API-KEY: $API_KEY" -T "$(ls *.pkg*)" https://arch.r8r.be/jjr/publish'
|
||||
secrets:
|
||||
- api_key
|
4
Makefile
4
Makefile
|
@ -42,7 +42,9 @@ dist: clean
|
|||
|
||||
install: all
|
||||
mkdir -p $(DESTDIR)$(PREFIX)/bin
|
||||
cp -f dmenu dmenu_path dmenu_run stest $(DESTDIR)$(PREFIX)/bin
|
||||
cp -f dmenu stest $(DESTDIR)$(PREFIX)/bin
|
||||
cp -f dmenu_path.sh $(DESTDIR)$(PREFIX)/bin/dmenu_path
|
||||
cp -f dmenu_run.sh $(DESTDIR)$(PREFIX)/bin/dmenu_run
|
||||
chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu
|
||||
chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu_path
|
||||
chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu_run
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
# Maintainer: Jef Roosens
|
||||
|
||||
pkgname=jjr-dmenu
|
||||
pkgver=5.3
|
||||
pkgrel=1
|
||||
pkgdesc="Chewing_Bever's custom build of Suckless's dmenu."
|
||||
url="https://git.rustybever.be/Chewing_Bever/dmenu"
|
||||
|
||||
arch=(
|
||||
"x86_64"
|
||||
"x86_64_tigerlake"
|
||||
"x86_64_skylake"
|
||||
"aarch64"
|
||||
)
|
||||
|
||||
license=("MIT")
|
||||
|
||||
depends=("glibc" "libxinerama" "libxft" "fontconfig" "freetype2")
|
||||
makedepends=("gcc")
|
||||
provides=("dmenu")
|
||||
conflicts=("dmenu-git")
|
||||
|
||||
source=("arg.h" "config.h" "config.mk" "dmenu.1" "dmenu.c" "dmenu_path.sh"
|
||||
"dmenu_run.sh" "drw.c" "drw.h" "LICENSE" "Makefile" "README" "stest.1"
|
||||
"stest.c" "util.c" "util.h")
|
||||
sha256sums=('9ed2b2e3396fdebc8ecab2cdbb09db115cca015f63ec0443b8ccc56340b6b03c'
|
||||
'9ae33f74aed02823abb8381e553d38455541ce3b6a0d642282b693992e71caef'
|
||||
'a2a83c2343343e44d6c0f50a9de1ace023599974e5cb4b12d90e69ed66cdb22f'
|
||||
'9f749419697381a1db77e9b23cb41629808fd7e451d475c9b5ee0e88bee803f6'
|
||||
'dc93fd213531f01c968ec073382d4c91c14a3fb2464e1a62e23e94653a74fb81'
|
||||
'a3f19e648e20eb80532dfe87e9bd9feeaa92df838e6ecc061f274c9da579d617'
|
||||
'564035fd8a8ade6504521d98fa10e8732e135403d546d04ca77316fe4a67b21c'
|
||||
'8c9f81b98f447440cf59dd3eefda99eec4e7733266ad0c072612163ccff4e1df'
|
||||
'7ed1cf72bfcb0f5444f338293aef74c455ce4ed5463f171a48358f64d7835d49'
|
||||
'9f8e922fcfc18ffcc4975dd0b1bee38302bd4e0c538251dfef6d77cd7ed59c89'
|
||||
'c32b5173eddf376296af085725cb878e4ca2603d4fda8bba3faac6a2bb1b4390'
|
||||
'ec98e8759049af796598f0790752a21a69eaea1d438b09c39922d4a9f4a7cfe2'
|
||||
'00d3389ef8858a565cf3fb3445620b90eb67d1a9b31434f4d54b05ed6c5abefb'
|
||||
'ba76404e61abbd734e315999ffe4e883419c4c69ff17a5d4d88a5cd11dd4b055'
|
||||
'1c093b9969daaf3e1a001b924c6c2da3770993916b444dfe65fe39aa0090aa1a'
|
||||
'1196a7b6efbf4cb3f5c435fffd72e7647f977483845d5c78c1c48d9ab8b96819')
|
||||
|
||||
build() {
|
||||
make
|
||||
}
|
||||
|
||||
package() {
|
||||
local installopts='--mode 0644 -D --target-directory'
|
||||
local shrdir="$pkgdir/usr/share"
|
||||
local licdir="$shrdir/licenses/$pkgname"
|
||||
local docdir="$shrdir/doc/$pkgname"
|
||||
|
||||
make PREFIX=/usr DESTDIR="$pkgdir" install
|
||||
|
||||
install $installopts "$licdir" "LICENSE"
|
||||
install $installopts "$docdir" "README"
|
||||
# install $installopts "$docdir" README.terminfo.rst
|
||||
# install $installopts "$shrdir/$pkgname" "$_sourcedir/st.info"
|
||||
}
|
||||
|
||||
# vim: ft=bash
|
|
@ -2,6 +2,7 @@
|
|||
/* Default settings; can be overriden by command line. */
|
||||
|
||||
static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */
|
||||
static int fuzzy = 1; /* -F option; if 0, dmenu doesn't use fuzzy matching */
|
||||
/* -fn option overrides fonts[0]; default X11 font or font set */
|
||||
static const char *fonts[] = {
|
||||
"monospace:size=10"
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
/* Default settings; can be overriden by command line. */
|
||||
|
||||
static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */
|
||||
static int fuzzy = 1; /* -F option; if 0, dmenu doesn't use fuzzy matching */
|
||||
/* -fn option overrides fonts[0]; default X11 font or font set */
|
||||
static const char *fonts[] = {
|
||||
"monospace:size=10"
|
||||
};
|
||||
static const char *prompt = NULL; /* -p option; prompt to the left of input field */
|
||||
static const char *colors[SchemeLast][2] = {
|
||||
/* fg bg */
|
||||
[SchemeNorm] = { "#bbbbbb", "#222222" },
|
||||
[SchemeSel] = { "#eeeeee", "#005577" },
|
||||
[SchemeOut] = { "#000000", "#00ffff" },
|
||||
};
|
||||
/* -l option; if nonzero, dmenu uses vertical list with given number of lines */
|
||||
static unsigned int lines = 0;
|
||||
|
||||
/*
|
||||
* Characters not considered part of a word while deleting words
|
||||
* for example: " /?\"&[]"
|
||||
*/
|
||||
static const char worddelimiters[] = " ";
|
|
@ -1,5 +1,5 @@
|
|||
# dmenu version
|
||||
VERSION = 5.1
|
||||
VERSION = 5.3
|
||||
|
||||
# paths
|
||||
PREFIX = /usr/local
|
||||
|
@ -17,14 +17,15 @@ FREETYPELIBS = -lfontconfig -lXft
|
|||
FREETYPEINC = /usr/include/freetype2
|
||||
# OpenBSD (uncomment)
|
||||
#FREETYPEINC = $(X11INC)/freetype2
|
||||
#MANPREFIX = ${PREFIX}/man
|
||||
|
||||
# includes and libs
|
||||
INCS = -I$(X11INC) -I$(FREETYPEINC)
|
||||
LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS)
|
||||
LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -lm
|
||||
|
||||
# flags
|
||||
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS)
|
||||
CFLAGS = -std=c99 -pedantic -Wall -Os $(INCS) $(CPPFLAGS)
|
||||
CFLAGS = -std=c99 -pedantic -Wall -O3 $(INCS) $(CPPFLAGS)
|
||||
LDFLAGS = $(LIBS)
|
||||
|
||||
# compiler and linker
|
||||
|
|
6
dmenu.1
6
dmenu.1
|
@ -3,7 +3,7 @@
|
|||
dmenu \- dynamic menu
|
||||
.SH SYNOPSIS
|
||||
.B dmenu
|
||||
.RB [ \-bfiv ]
|
||||
.RB [ \-bfsv ]
|
||||
.RB [ \-l
|
||||
.IR lines ]
|
||||
.RB [ \-m
|
||||
|
@ -44,8 +44,8 @@ dmenu appears at the bottom of the screen.
|
|||
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.
|
||||
.B \-s
|
||||
dmenu matches menu items case sensitively.
|
||||
.TP
|
||||
.BI \-l " lines"
|
||||
dmenu lists items vertically, with the given number of lines.
|
||||
|
|
156
dmenu.c
156
dmenu.c
|
@ -1,6 +1,7 @@
|
|||
/* See LICENSE file for copyright and license details. */
|
||||
#include <ctype.h>
|
||||
#include <locale.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -32,6 +33,7 @@ struct item {
|
|||
char *text;
|
||||
struct item *left, *right;
|
||||
int out;
|
||||
double distance;
|
||||
};
|
||||
|
||||
static char text[BUFSIZ] = "";
|
||||
|
@ -55,8 +57,16 @@ static Clr *scheme[SchemeLast];
|
|||
|
||||
#include "config.h"
|
||||
|
||||
static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
|
||||
static char *(*fstrstr)(const char *, const char *) = strstr;
|
||||
static char * cistrstr(const char *s, const char *sub);
|
||||
static int (*fstrncmp)(const char *, const char *, size_t) = strncasecmp;
|
||||
static char *(*fstrstr)(const char *, const char *) = cistrstr;
|
||||
|
||||
static unsigned int
|
||||
textw_clamp(const char *str, unsigned int n)
|
||||
{
|
||||
unsigned int w = drw_fontset_getwidth_clamp(drw, str, n) + lrpad;
|
||||
return MIN(w, n);
|
||||
}
|
||||
|
||||
static void
|
||||
appenditem(struct item *item, struct item **list, struct item **last)
|
||||
|
@ -82,10 +92,10 @@ calcoffsets(void)
|
|||
n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">"));
|
||||
/* calculate which items will begin the next page and previous page */
|
||||
for (i = 0, next = curr; next; next = next->right)
|
||||
if ((i += (lines > 0) ? bh : MIN(TEXTW(next->text), n)) > n)
|
||||
if ((i += (lines > 0) ? bh : textw_clamp(next->text, n)) > n)
|
||||
break;
|
||||
for (i = 0, prev = curr; prev && prev->left; prev = prev->left)
|
||||
if ((i += (lines > 0) ? bh : MIN(TEXTW(prev->left->text), n)) > n)
|
||||
if ((i += (lines > 0) ? bh : textw_clamp(prev->left->text, n)) > n)
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -97,6 +107,9 @@ cleanup(void)
|
|||
XUngrabKey(dpy, AnyKey, AnyModifier, root);
|
||||
for (i = 0; i < SchemeLast; i++)
|
||||
free(scheme[i]);
|
||||
for (i = 0; items && items[i].text; ++i)
|
||||
free(items[i].text);
|
||||
free(items);
|
||||
drw_free(drw);
|
||||
XSync(dpy, False);
|
||||
XCloseDisplay(dpy);
|
||||
|
@ -172,7 +185,7 @@ drawmenu(void)
|
|||
}
|
||||
x += w;
|
||||
for (item = curr; item != next; item = item->right)
|
||||
x = drawitem(item, x, 0, MIN(TEXTW(item->text), mw - x - TEXTW(">")));
|
||||
x = drawitem(item, x, 0, textw_clamp(item->text, mw - x - TEXTW(">")));
|
||||
if (next) {
|
||||
w = TEXTW(">");
|
||||
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||
|
@ -217,9 +230,94 @@ grabkeyboard(void)
|
|||
die("cannot grab keyboard");
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
/* 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]) {
|
||||
appenditem(it, &matches, &matchend);
|
||||
}
|
||||
free(fuzzymatches);
|
||||
}
|
||||
curr = sel = matches;
|
||||
calcoffsets();
|
||||
}
|
||||
|
||||
static void
|
||||
match(void)
|
||||
{
|
||||
if (fuzzy) {
|
||||
fuzzymatch();
|
||||
return;
|
||||
}
|
||||
static char **tokv = NULL;
|
||||
static int tokn = 0;
|
||||
|
||||
|
@ -232,7 +330,7 @@ match(void)
|
|||
/* separate input text into tokens to be matched individually */
|
||||
for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " "))
|
||||
if (++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv)))
|
||||
die("cannot realloc %u bytes:", tokn * sizeof *tokv);
|
||||
die("cannot realloc %zu bytes:", tokn * sizeof *tokv);
|
||||
len = tokc ? strlen(tokv[0]) : 0;
|
||||
|
||||
matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL;
|
||||
|
@ -405,7 +503,7 @@ keypress(XKeyEvent *ev)
|
|||
switch(ksym) {
|
||||
default:
|
||||
insert:
|
||||
if (!iscntrl(*buf))
|
||||
if (!iscntrl((unsigned char)*buf))
|
||||
insert(buf, len);
|
||||
break;
|
||||
case XK_Delete:
|
||||
|
@ -507,9 +605,9 @@ insert:
|
|||
case XK_Tab:
|
||||
if (!sel)
|
||||
return;
|
||||
strncpy(text, sel->text, sizeof text - 1);
|
||||
text[sizeof text - 1] = '\0';
|
||||
cursor = strlen(text);
|
||||
cursor = strnlen(sel->text, sizeof text - 1);
|
||||
memcpy(text, sel->text, cursor);
|
||||
text[cursor] = '\0';
|
||||
match();
|
||||
break;
|
||||
}
|
||||
|
@ -539,29 +637,22 @@ paste(void)
|
|||
static void
|
||||
readstdin(void)
|
||||
{
|
||||
char buf[sizeof text], *p;
|
||||
size_t i, imax = 0, size = 0;
|
||||
unsigned int tmpmax = 0;
|
||||
char *line = NULL;
|
||||
size_t i, junk, size = 0;
|
||||
ssize_t len;
|
||||
|
||||
/* read each line from stdin and add it to the item list */
|
||||
for (i = 0; fgets(buf, sizeof buf, stdin); i++) {
|
||||
for (i = 0; (len = getline(&line, &junk, stdin)) != -1; i++, line = NULL) {
|
||||
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);
|
||||
die("cannot realloc %zu bytes:", size);
|
||||
if (line[len - 1] == '\n')
|
||||
line[len - 1] = '\0';
|
||||
items[i].text = line;
|
||||
items[i].out = 0;
|
||||
drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL);
|
||||
if (tmpmax > inputw) {
|
||||
inputw = tmpmax;
|
||||
imax = i;
|
||||
}
|
||||
}
|
||||
if (items)
|
||||
items[i].text = NULL;
|
||||
inputw = items ? TEXTW(items[imax].text) : 0;
|
||||
lines = MIN(lines, i);
|
||||
}
|
||||
|
||||
|
@ -670,7 +761,7 @@ setup(void)
|
|||
mw = wa.width;
|
||||
}
|
||||
promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
|
||||
inputw = MIN(inputw, mw/3);
|
||||
inputw = mw / 3; /* input width: ~33% of monitor width */
|
||||
match();
|
||||
|
||||
/* create menu window */
|
||||
|
@ -707,9 +798,8 @@ setup(void)
|
|||
static void
|
||||
usage(void)
|
||||
{
|
||||
fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
|
||||
" [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr);
|
||||
exit(1);
|
||||
die("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
|
||||
" [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]");
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -727,9 +817,11 @@ main(int argc, char *argv[])
|
|||
topbar = 0;
|
||||
else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */
|
||||
fast = 1;
|
||||
else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */
|
||||
fstrncmp = strncasecmp;
|
||||
fstrstr = cistrstr;
|
||||
else if (!strcmp(argv[i], "-F")) /* disable fuzzy search */
|
||||
fuzzy = 0;
|
||||
else if (!strcmp(argv[i], "-s")) { /* case-sensitive item matching */
|
||||
fstrncmp = strncmp;
|
||||
fstrstr = strstr;
|
||||
} else if (i + 1 == argc)
|
||||
usage();
|
||||
/* these options take one argument */
|
||||
|
|
102
drw.c
102
drw.c
|
@ -133,19 +133,6 @@ xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
|
|||
die("no font specified.");
|
||||
}
|
||||
|
||||
/* Do not allow using color fonts. This is a workaround for a BadLength
|
||||
* error from Xft with color glyphs. Modelled on the Xterm workaround. See
|
||||
* https://bugzilla.redhat.com/show_bug.cgi?id=1498269
|
||||
* https://lists.suckless.org/dev/1701/30932.html
|
||||
* https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=916349
|
||||
* and lots more all over the internet.
|
||||
*/
|
||||
FcBool iscol;
|
||||
if(FcPatternGetBool(xfont->pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) {
|
||||
XftFontClose(drw->dpy, xfont);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
font = ecalloc(1, sizeof(Fnt));
|
||||
font->xfont = xfont;
|
||||
font->pattern = pattern;
|
||||
|
@ -251,12 +238,10 @@ drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int
|
|||
int
|
||||
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
|
||||
{
|
||||
char buf[1024];
|
||||
int ty;
|
||||
unsigned int ew;
|
||||
int i, ty, ellipsis_x = 0;
|
||||
unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len;
|
||||
XftDraw *d = NULL;
|
||||
Fnt *usedfont, *curfont, *nextfont;
|
||||
size_t i, len;
|
||||
int utf8strlen, utf8charlen, render = x || y || w || h;
|
||||
long utf8codepoint = 0;
|
||||
const char *utf8str;
|
||||
|
@ -264,13 +249,17 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||
FcPattern *fcpattern;
|
||||
FcPattern *match;
|
||||
XftResult result;
|
||||
int charexists = 0;
|
||||
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;
|
||||
static unsigned int ellipsis_width = 0;
|
||||
|
||||
if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
|
||||
if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts)
|
||||
return 0;
|
||||
|
||||
if (!render) {
|
||||
w = ~w;
|
||||
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);
|
||||
|
@ -282,8 +271,10 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||
}
|
||||
|
||||
usedfont = drw->fonts;
|
||||
if (!ellipsis_width && render)
|
||||
ellipsis_width = drw_fontset_getwidth(drw, "...");
|
||||
while (1) {
|
||||
utf8strlen = 0;
|
||||
ew = ellipsis_len = utf8strlen = 0;
|
||||
utf8str = text;
|
||||
nextfont = NULL;
|
||||
while (*text) {
|
||||
|
@ -291,9 +282,27 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||
for (curfont = drw->fonts; curfont; curfont = curfont->next) {
|
||||
charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
|
||||
if (charexists) {
|
||||
if (curfont == usedfont) {
|
||||
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;
|
||||
}
|
||||
|
@ -301,36 +310,25 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||
}
|
||||
}
|
||||
|
||||
if (!charexists || nextfont)
|
||||
if (overflow || !charexists || nextfont)
|
||||
break;
|
||||
else
|
||||
charexists = 0;
|
||||
}
|
||||
|
||||
if (utf8strlen) {
|
||||
drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL);
|
||||
/* shorten text if necessary */
|
||||
for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--)
|
||||
drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
|
||||
|
||||
if (len) {
|
||||
memcpy(buf, utf8str, len);
|
||||
buf[len] = '\0';
|
||||
if (len < utf8strlen)
|
||||
for (i = len; i && i > len - 3; buf[--i] = '.')
|
||||
; /* NOP */
|
||||
|
||||
if (render) {
|
||||
ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
|
||||
XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
|
||||
usedfont->xfont, x, ty, (XftChar8 *)buf, len);
|
||||
}
|
||||
x += ew;
|
||||
w -= ew;
|
||||
if (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)
|
||||
drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert);
|
||||
|
||||
if (!*text) {
|
||||
if (!*text || overflow) {
|
||||
break;
|
||||
} else if (nextfont) {
|
||||
charexists = 0;
|
||||
|
@ -340,6 +338,12 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||
* 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);
|
||||
|
||||
|
@ -351,7 +355,6 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||
fcpattern = FcPatternDuplicate(drw->fonts->pattern);
|
||||
FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
|
||||
FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
|
||||
FcPatternAddBool(fcpattern, FC_COLOR, FcFalse);
|
||||
|
||||
FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
|
||||
FcDefaultSubstitute(fcpattern);
|
||||
|
@ -368,6 +371,8 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||
curfont->next = usedfont;
|
||||
} else {
|
||||
xfont_free(usedfont);
|
||||
nomatches.codepoint[++nomatches.idx % nomatches_len] = utf8codepoint;
|
||||
no_match:
|
||||
usedfont = drw->fonts;
|
||||
}
|
||||
}
|
||||
|
@ -397,6 +402,15 @@ drw_fontset_getwidth(Drw *drw, const char *text)
|
|||
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);
|
||||
}
|
||||
|
||||
void
|
||||
drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h)
|
||||
{
|
||||
|
|
1
drw.h
1
drw.h
|
@ -35,6 +35,7 @@ void drw_free(Drw *drw);
|
|||
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);
|
||||
|
||||
/* Colorscheme abstraction */
|
||||
|
|
23
util.c
23
util.c
|
@ -6,18 +6,9 @@
|
|||
|
||||
#include "util.h"
|
||||
|
||||
void *
|
||||
ecalloc(size_t nmemb, size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if (!(p = calloc(nmemb, size)))
|
||||
die("calloc:");
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
die(const char *fmt, ...) {
|
||||
die(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
@ -33,3 +24,13 @@ die(const char *fmt, ...) {
|
|||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void *
|
||||
ecalloc(size_t nmemb, size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if (!(p = calloc(nmemb, size)))
|
||||
die("calloc:");
|
||||
return p;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue