From ec64f273fb7660d3746eb765dc02e40726a54294 Mon Sep 17 00:00:00 2001 From: Anselm R Garbe Date: Wed, 17 Apr 2013 20:59:12 +0200 Subject: [PATCH 01/16] applied Alex Sedov's Tab buffer termination patch, thanks --- dmenu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dmenu.c b/dmenu.c index efc1e54..c25dc82 100644 --- a/dmenu.c +++ b/dmenu.c @@ -392,7 +392,8 @@ keypress(XKeyEvent *ev) { case XK_Tab: if(!sel) return; - strncpy(text, sel->text, sizeof text); + strncpy(text, sel->text, sizeof text - 1); + text[sizeof text - 1] = '\0'; cursor = strlen(text); match(); break; -- 2.20.1 From 14f72a276334de4a46543cf648a4922bc54f1e9f Mon Sep 17 00:00:00 2001 From: Anselm R Garbe Date: Wed, 17 Apr 2013 21:04:05 +0200 Subject: [PATCH 02/16] adopted Alex Sedov's config.h revival patch to tip --- Makefile | 6 +++++- dmenu.c | 12 ++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index f011ad7..0f7dfbd 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,11 @@ options: @echo CC -c $< @${CC} -c $< ${CFLAGS} -${OBJ}: config.mk draw.h +config.h: + @echo creating $@ from config.def.h + @cp config.def.h $@ + +${OBJ}: config.h config.mk draw.h dmenu: dmenu.o draw.o @echo CC -o $@ diff --git a/dmenu.c b/dmenu.c index c25dc82..a06ae15 100644 --- a/dmenu.c +++ b/dmenu.c @@ -44,20 +44,10 @@ static char text[BUFSIZ] = ""; static int bh, mw, mh; static int inputw, promptw; static size_t cursor = 0; -static const char *font = NULL; -static const char *prompt = NULL; -static const char *normbgcolor = "#222222"; -static const char *normfgcolor = "#bbbbbb"; -static const char *selbgcolor = "#005577"; -static const char *selfgcolor = "#eeeeee"; -static const char *outbgcolor = "#00ffff"; -static const char *outfgcolor = "#000000"; -static unsigned int lines = 0; static unsigned long normcol[ColLast]; static unsigned long selcol[ColLast]; static unsigned long outcol[ColLast]; static Atom clip, utf8; -static Bool topbar = True; static DC *dc; static Item *items = NULL; static Item *matches, *matchend; @@ -65,6 +55,8 @@ static Item *prev, *curr, *next, *sel; static Window win; static XIC xic; +#include "config.h" + static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; static char *(*fstrstr)(const char *, const char *) = strstr; -- 2.20.1 From 55c9be06ca5a527e14e3f0b5b08845f0fcbf4999 Mon Sep 17 00:00:00 2001 From: Anselm R Garbe Date: Wed, 17 Apr 2013 21:16:51 +0200 Subject: [PATCH 03/16] forgot to add config.def.h, thanks William --- config.def.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 config.def.h diff --git a/config.def.h b/config.def.h new file mode 100644 index 0000000..c2a23fa --- /dev/null +++ b/config.def.h @@ -0,0 +1,17 @@ +/* See LICENSE file for copyright and license details. */ +/* vim: expandtab + */ +/* Default settings; can be overrided by command line. */ + +static Bool topbar = True; /* -b option; if False, dmenu appears at bottom */ +static const char *font = NULL; /* -fn option; default X11 font or font set */ +static const char *prompt = NULL; /* -p option; prompt to the elft of input field */ +static const char *normbgcolor = "#222222"; /* -nb option; normal background */ +static const char *normfgcolor = "#bbbbbb"; /* -nf option; normal foreground */ +static const char *selbgcolor = "#005577"; /* -sb option; selected background */ +static const char *selfgcolor = "#eeeeee"; /* -sf option; selected foreground */ +static const char *outbgcolor = "#00ffff"; +static const char *outfgcolor = "#000000"; +/* -l option; if nonzero, dmenu uses vertical list with given number of lines */ +static unsigned int lines = 0; + -- 2.20.1 From 597d4b43379433a5bf86d490f747c0eeda38bba8 Mon Sep 17 00:00:00 2001 From: Anselm R Garbe Date: Fri, 28 Jun 2013 22:06:02 +0200 Subject: [PATCH 04/16] accepted vi'is exit approach ^[ (suggested by Arkaduisz) --- dmenu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dmenu.c b/dmenu.c index a06ae15..5e0a19c 100644 --- a/dmenu.c +++ b/dmenu.c @@ -279,6 +279,8 @@ keypress(XKeyEvent *ev) { case XK_Return: case XK_KP_Enter: break; + case XK_bracketleft: + exit(EXIT_FAILURE); default: return; } -- 2.20.1 From 13f787306f46a5f838987e3b546d85d1bb1c3c01 Mon Sep 17 00:00:00 2001 From: Anselm R Garbe Date: Fri, 2 Aug 2013 22:30:20 +0200 Subject: [PATCH 05/16] =?utf8?q?applied=20Martti=20K=C3=BChne's=20dmenu=20?= =?utf8?q?monitor=20patch=20https://gist.github.com/mar77i/3349298/raw/f65?= =?utf8?q?81ca96627f4c71c0bd1faf531daaf2a613b95/monarg.patch=20becomes=20u?= =?utf8?q?pstream=20now?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- LICENSE | 2 +- dmenu.1 | 5 +++++ dmenu.c | 11 ++++++++--- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/LICENSE b/LICENSE index e2bfc83..0df62c6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ MIT/X Consortium License +© 2006-2013 Anselm R Garbe © 2010-2012 Connor Lane Smith -© 2006-2012 Anselm R Garbe © 2009 Gottox © 2009 Markus Schnalke © 2009 Evan Gates diff --git a/dmenu.1 b/dmenu.1 index 88f77de..bbee17d 100644 --- a/dmenu.1 +++ b/dmenu.1 @@ -7,6 +7,8 @@ dmenu \- dynamic menu .RB [ \-f ] .RB [ \-i ] .RB [ \-l +.RB [ \-m +.IR monitor ] .IR lines ] .RB [ \-p .IR prompt ] @@ -49,6 +51,9 @@ dmenu matches menu items case insensitively. .BI \-l " lines" dmenu lists items vertically, with the given number of lines. .TP +.BI \-m " monitor" +dmenu is displayed on the monitor supplied. +.TP .BI \-p " prompt" defines the prompt to be displayed to the left of the input field. .TP diff --git a/dmenu.c b/dmenu.c index 5e0a19c..8d9bbb6 100644 --- a/dmenu.c +++ b/dmenu.c @@ -54,6 +54,7 @@ static Item *matches, *matchend; static Item *prev, *curr, *next, *sel; static Window win; static XIC xic; +static int mon = -1; #include "config.h" @@ -84,6 +85,8 @@ main(int argc, char *argv[]) { /* these options take one argument */ else if(!strcmp(argv[i], "-l")) /* number of lines in vertical list */ lines = atoi(argv[++i]); + else if(!strcmp(argv[i], "-m")) + mon = atoi(argv[++i]); else if(!strcmp(argv[i], "-p")) /* adds prompt to left of input field */ prompt = argv[++i]; else if(!strcmp(argv[i], "-fn")) /* font or font set */ @@ -557,7 +560,9 @@ setup(void) { XWindowAttributes wa; XGetInputFocus(dc->dpy, &w, &di); - if(w != root && w != PointerRoot && w != None) { + if(mon != -1 && mon < n) + i = mon; + if(!i && w != root && w != PointerRoot && w != None) { /* find top-level window containing current input focus */ do { if(XQueryTree(dc->dpy, (pw = w), &dw, &w, &dws, &du) && dws) @@ -572,7 +577,7 @@ setup(void) { } } /* no focused window is on screen, so use pointer location instead */ - if(!area && XQueryPointer(dc->dpy, root, &dw, &dw, &x, &y, &di, &di, &du)) + if(mon == -1 && !area && XQueryPointer(dc->dpy, root, &dw, &dw, &x, &y, &di, &di, &du)) for(i = 0; i < n; i++) if(INTERSECT(x, y, 1, 1, info[i])) break; @@ -614,7 +619,7 @@ setup(void) { void usage(void) { - fputs("usage: dmenu [-b] [-f] [-i] [-l lines] [-p prompt] [-fn font]\n" + fputs("usage: dmenu [-b] [-f] [-i] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" " [-nb color] [-nf color] [-sb color] [-sf color] [-v]\n", stderr); exit(EXIT_FAILURE); } -- 2.20.1 From 5ed5e90bfb7760f24661281cf7156087afbe49d3 Mon Sep 17 00:00:00 2001 From: Anselm R Garbe Date: Tue, 13 Aug 2013 19:15:04 +0200 Subject: [PATCH 06/16] =?utf8?q?applied=20Martin=20K=C3=BChl's=20inverse?= =?utf8?q?=20matching=20flag=20to=20stest?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- stest.1 | 3 +++ stest.c | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/stest.1 b/stest.1 index bb48f45..2667d8a 100644 --- a/stest.1 +++ b/stest.1 @@ -67,6 +67,9 @@ Test that files are not empty. .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 diff --git a/stest.c b/stest.c index e1dcf36..8fac42a 100644 --- a/stest.c +++ b/stest.c @@ -22,7 +22,7 @@ main(int argc, char *argv[]) { DIR *dir; int opt; - while((opt = getopt(argc, argv, "abcdefghln:o:pqrsuwx")) != -1) + while((opt = getopt(argc, argv, "abcdefghln:o:pqrsuvwx")) != -1) switch(opt) { case 'n': /* newer than file */ case 'o': /* older than file */ @@ -33,7 +33,7 @@ main(int argc, char *argv[]) { FLAG(opt) = true; break; case '?': /* error: unknown flag */ - fprintf(stderr, "usage: %s [-abcdefghlpqrsuwx] [-n file] [-o file] [file...]\n", argv[0]); + fprintf(stderr, "usage: %s [-abcdefghlpqrsuvwx] [-n file] [-o file] [file...]\n", argv[0]); exit(2); } if(optind == argc) @@ -60,7 +60,7 @@ void test(const char *path, const char *name) { struct stat st, ln; - if(!stat(path, &st) && (FLAG('a') || name[0] != '.') /* hidden files */ + 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 */ @@ -75,7 +75,7 @@ test(const char *path, const char *name) { && (!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)) { /* executable */ + && (!FLAG('x') || access(path, X_OK) == 0)) != FLAG('v')) { /* executable */ if(FLAG('q')) exit(0); match = true; -- 2.20.1 From 4c50e43df46e486a0fac632d34eaed37359ceba7 Mon Sep 17 00:00:00 2001 From: Anselm R Garbe Date: Thu, 29 May 2014 18:03:53 +0200 Subject: [PATCH 07/16] updated copyright notices in LICENSE and dmenu.c file --- LICENSE | 2 +- dmenu.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index 0df62c6..39c4b6e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT/X Consortium License -© 2006-2013 Anselm R Garbe +© 2006-2014 Anselm R Garbe © 2010-2012 Connor Lane Smith © 2009 Gottox © 2009 Markus Schnalke diff --git a/dmenu.c b/dmenu.c index 8d9bbb6..dd2c128 100644 --- a/dmenu.c +++ b/dmenu.c @@ -69,7 +69,7 @@ main(int argc, char *argv[]) { for(i = 1; i < argc; i++) /* these options take no arguments */ if(!strcmp(argv[i], "-v")) { /* prints version information */ - puts("dmenu-"VERSION", © 2006-2012 dmenu engineers, see LICENSE for details"); + puts("dmenu-"VERSION", © 2006-2014 dmenu engineers, see LICENSE for details"); exit(EXIT_SUCCESS); } else if(!strcmp(argv[i], "-b")) /* appears at the bottom of the screen */ -- 2.20.1 From aa69426670bf0ae480db127ff8d4fc62d6da2593 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Thu, 24 Jul 2014 19:10:23 +0000 Subject: [PATCH 08/16] fix crash with ctrl-enter as input reproduce: ./dmenu; send EOF; press ctrl+enter. --- dmenu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dmenu.c b/dmenu.c index dd2c128..b56f3a8 100644 --- a/dmenu.c +++ b/dmenu.c @@ -370,7 +370,8 @@ keypress(XKeyEvent *ev) { puts((sel && !(ev->state & ShiftMask)) ? sel->text : text); if(!(ev->state & ControlMask)) exit(EXIT_SUCCESS); - sel->out = True; + if(sel) + sel->out = True; break; case XK_Right: if(text[cursor] != '\0') { -- 2.20.1 From 13a529ce63364544bdc851dfd5d3aa2ef8740914 Mon Sep 17 00:00:00 2001 From: Anselm R Garbe Date: Wed, 17 Sep 2014 13:40:11 +0200 Subject: [PATCH 09/16] applied Hiltjo's patch as suggested on the ml to fix ControlMask for C-j and C-m --- dmenu.1 | 3 +++ dmenu.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/dmenu.1 b/dmenu.1 index bbee17d..2897ab1 100644 --- a/dmenu.1 +++ b/dmenu.1 @@ -136,6 +136,9 @@ Delete line right C\-m Return .TP +C\-M +Shift-Return +.TP C\-n Down .TP diff --git a/dmenu.c b/dmenu.c index b56f3a8..94c70de 100644 --- a/dmenu.c +++ b/dmenu.c @@ -256,9 +256,9 @@ keypress(XKeyEvent *ev) { case XK_h: ksym = XK_BackSpace; break; case XK_i: ksym = XK_Tab; break; case XK_j: /* fallthrough */ - case XK_J: ksym = XK_Return; break; + case XK_J: /* fallthrough */ case XK_m: /* fallthrough */ - case XK_M: ksym = XK_Return; break; + case XK_M: ksym = XK_Return; ev->state &= ~ControlMask; break; case XK_n: ksym = XK_Down; break; case XK_p: ksym = XK_Up; break; -- 2.20.1 From 4b1fecd44e8376594c418663351fcb30c4e841de Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Mon, 4 May 2015 21:54:46 +0200 Subject: [PATCH 10/16] Use libdraw: add Xft and fallback-fonts support to graphics lib - libdraw, util: add drw.{c,h}, util.{c,h} and update code. - libdraw: fix drw_rect(): use w and h parameter. - libdraw: print errstr if last character in string was ":" (sbase). - libdraw: drw_clr_free() allow valid free(NULL). - config.def.h: set default font to monospace. - cleanup() on exit. - LICENSE: update license string for dmenu -v to 2015. - LICENSE: add myself to LICENSE --- LICENSE | 1 + Makefile | 15 +- config.def.h | 10 +- config.mk | 4 +- dmenu.c | 241 ++++++++++++++++++------------ draw.c | 177 ---------------------- draw.h | 35 ----- drw.c | 413 +++++++++++++++++++++++++++++++++++++++++++++++++++ drw.h | 74 +++++++++ util.c | 23 +++ util.h | 7 + 11 files changed, 684 insertions(+), 316 deletions(-) delete mode 100644 draw.c delete mode 100644 draw.h create mode 100644 drw.c create mode 100644 drw.h create mode 100644 util.c create mode 100644 util.h diff --git a/LICENSE b/LICENSE index 39c4b6e..221603d 100644 --- a/LICENSE +++ b/LICENSE @@ -7,6 +7,7 @@ MIT/X Consortium License © 2009 Evan Gates © 2006-2008 Sander van Dijk © 2006-2007 Michał Janeczek +© 2014-2015 Hiltjo Posthuma Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/Makefile b/Makefile index 0f7dfbd..4a412ee 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ include config.mk -SRC = dmenu.c draw.c stest.c +SRC = drw.c dmenu.c stest.c util.c OBJ = ${SRC:.c=.o} all: options dmenu stest @@ -15,18 +15,18 @@ options: @echo "CC = ${CC}" .c.o: - @echo CC -c $< - @${CC} -c $< ${CFLAGS} + @echo CC $< + @${CC} -c ${CFLAGS} $< config.h: @echo creating $@ from config.def.h @cp config.def.h $@ -${OBJ}: config.h config.mk draw.h +${OBJ}: config.h config.mk drw.h -dmenu: dmenu.o draw.o +dmenu: dmenu.o drw.o util.o @echo CC -o $@ - @${CC} -o $@ dmenu.o draw.o ${LDFLAGS} + @${CC} -o $@ dmenu.o drw.o util.o ${LDFLAGS} stest: stest.o @echo CC -o $@ @@ -39,7 +39,8 @@ clean: dist: clean @echo creating dist tarball @mkdir -p dmenu-${VERSION} - @cp LICENSE Makefile README config.mk dmenu.1 draw.h dmenu_path dmenu_run stest.1 ${SRC} dmenu-${VERSION} + @cp LICENSE Makefile README 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} diff --git a/config.def.h b/config.def.h index c2a23fa..4e5e3e7 100644 --- a/config.def.h +++ b/config.def.h @@ -4,8 +4,11 @@ /* Default settings; can be overrided by command line. */ static Bool topbar = True; /* -b option; if False, dmenu appears at bottom */ -static const char *font = NULL; /* -fn option; default X11 font or font set */ -static const char *prompt = NULL; /* -p option; prompt to the elft of input field */ +/* -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 elft of input field */ static const char *normbgcolor = "#222222"; /* -nb option; normal background */ static const char *normfgcolor = "#bbbbbb"; /* -nf option; normal foreground */ static const char *selbgcolor = "#005577"; /* -sb option; selected background */ @@ -13,5 +16,4 @@ static const char *selfgcolor = "#eeeeee"; /* -sf option; selected foreground static const char *outbgcolor = "#00ffff"; static const char *outfgcolor = "#000000"; /* -l option; if nonzero, dmenu uses vertical list with given number of lines */ -static unsigned int lines = 0; - +static unsigned int lines = 0; diff --git a/config.mk b/config.mk index c0d466b..4e62a09 100644 --- a/config.mk +++ b/config.mk @@ -13,8 +13,8 @@ XINERAMALIBS = -lXinerama XINERAMAFLAGS = -DXINERAMA # includes and libs -INCS = -I${X11INC} -LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} +INCS = -I${X11INC} -I/usr/include/freetype2 +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} -lfontconfig -lXft # flags CPPFLAGS = -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} diff --git a/dmenu.c b/dmenu.c index 94c70de..94be574 100644 --- a/dmenu.c +++ b/dmenu.c @@ -1,5 +1,6 @@ /* See LICENSE file for copyright and license details. */ #include +#include #include #include #include @@ -11,12 +12,20 @@ #ifdef XINERAMA #include #endif -#include "draw.h" +#include +#include "drw.h" +#include "util.h" + +/* macros */ #define INTERSECT(x,y,w,h,r) (MAX(0, MIN((x)+(w),(r).x_org+(r).width) - MAX((x),(r).x_org)) \ * MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org))) -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define LENGTH(X) (sizeof X / sizeof X[0]) +#define TEXTNW(X,N) (drw_font_getexts_width(drw->fonts[0], (X), (N))) +#define TEXTW(X) (drw_text(drw, 0, 0, 0, 0, (X), 0) + drw->fonts[0]->h) + +/* enums */ +enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */ typedef struct Item Item; struct Item { @@ -28,6 +37,7 @@ struct Item { static void appenditem(Item *item, Item **list, Item **last); static void calcoffsets(void); static char *cistrstr(const char *s, const char *sub); +static void cleanup(void); static void drawmenu(void); static void grabkeyboard(void); static void insert(const char *str, ssize_t n); @@ -44,11 +54,7 @@ static char text[BUFSIZ] = ""; static int bh, mw, mh; static int inputw, promptw; static size_t cursor = 0; -static unsigned long normcol[ColLast]; -static unsigned long selcol[ColLast]; -static unsigned long outcol[ColLast]; static Atom clip, utf8; -static DC *dc; static Item *items = NULL; static Item *matches, *matchend; static Item *prev, *curr, *next, *sel; @@ -56,6 +62,13 @@ static Window win; static XIC xic; static int mon = -1; +static ClrScheme scheme[SchemeLast]; +static Display *dpy; +static int screen; +static Window root; +static Drw *drw; +static int sw, sh; /* X display screen geometry width, height */ + #include "config.h" static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; @@ -69,8 +82,8 @@ main(int argc, char *argv[]) { for(i = 1; i < argc; i++) /* these options take no arguments */ if(!strcmp(argv[i], "-v")) { /* prints version information */ - puts("dmenu-"VERSION", © 2006-2014 dmenu engineers, see LICENSE for details"); - exit(EXIT_SUCCESS); + puts("dmenu-"VERSION", © 2006-2015 dmenu engineers, see LICENSE for details"); + exit(0); } else if(!strcmp(argv[i], "-b")) /* appears at the bottom of the screen */ topbar = False; @@ -90,7 +103,7 @@ main(int argc, char *argv[]) { else if(!strcmp(argv[i], "-p")) /* adds prompt to left of input field */ prompt = argv[++i]; else if(!strcmp(argv[i], "-fn")) /* font or font set */ - font = argv[++i]; + fonts[0] = argv[++i]; else if(!strcmp(argv[i], "-nb")) /* normal background color */ normbgcolor = argv[++i]; else if(!strcmp(argv[i], "-nf")) /* normal foreground color */ @@ -102,8 +115,19 @@ main(int argc, char *argv[]) { else usage(); - dc = initdc(); - initfont(dc, font); + if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) + fputs("warning: no locale support\n", stderr); + if(!(dpy = XOpenDisplay(NULL))) + die("dwm: cannot open display\n"); + screen = DefaultScreen(dpy); + root = RootWindow(dpy, screen); + sw = DisplayWidth(dpy, screen); + sh = DisplayHeight(dpy, screen); + drw = drw_create(dpy, screen, root, sw, sh); + drw_load_fonts(drw, fonts, LENGTH(fonts)); + if(!drw->fontcount) + die("No fonts could be loaded.\n"); + drw_setscheme(drw, &scheme[SchemeNorm]); if(fast) { grabkeyboard(); @@ -138,16 +162,30 @@ calcoffsets(void) { if(lines > 0) n = lines * bh; else - n = mw - (promptw + inputw + textw(dc, "<") + textw(dc, ">")); + 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(dc, next->text), n)) > n) + if((i += (lines > 0) ? bh : MIN(TEXTW(next->text), n)) > n) break; for(i = 0, prev = curr; prev && prev->left; prev = prev->left) - if((i += (lines > 0) ? bh : MIN(textw(dc, prev->left->text), n)) > n) + if((i += (lines > 0) ? bh : MIN(TEXTW(prev->left->text), n)) > n) break; } +void +cleanup(void) { + XUngrabKey(dpy, AnyKey, AnyModifier, root); + drw_clr_free(scheme[SchemeNorm].bg); + drw_clr_free(scheme[SchemeNorm].fg); + drw_clr_free(scheme[SchemeSel].fg); + drw_clr_free(scheme[SchemeSel].bg); + drw_clr_free(scheme[SchemeOut].fg); + drw_clr_free(scheme[SchemeOut].bg); + drw_free(drw); + XSync(dpy, False); + XCloseDisplay(dpy); +} + char * cistrstr(const char *s, const char *sub) { size_t len; @@ -162,50 +200,69 @@ void drawmenu(void) { int curpos; Item *item; + int x = 0, y = 0, h = bh, w; - dc->x = 0; - dc->y = 0; - dc->h = bh; - drawrect(dc, 0, 0, mw, mh, True, BG(dc, normcol)); + drw_setscheme(drw, &scheme[SchemeNorm]); + drw_rect(drw, 0, 0, mw, mh, True, 1, 1); if(prompt && *prompt) { - dc->w = promptw; - drawtext(dc, prompt, selcol); - dc->x = dc->w; + drw_setscheme(drw, &scheme[SchemeSel]); + drw_text(drw, x, 0, promptw, bh, prompt, 1); + x += promptw; } /* draw input field */ - dc->w = (lines > 0 || !matches) ? mw - dc->x : inputw; - drawtext(dc, text, normcol); - if((curpos = textnw(dc, text, cursor) + dc->h/2 - 2) < dc->w) - drawrect(dc, curpos, 2, 1, dc->h - 4, True, FG(dc, normcol)); + w = (lines > 0 || !matches) ? mw - x : inputw; + drw_setscheme(drw, &scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, text, 0); + + if((curpos = TEXTNW(text, cursor) + bh/2 - 2) < w) { + drw_setscheme(drw, &scheme[SchemeNorm]); + drw_rect(drw, x + curpos + 2, 2, 1, bh - 4, 1, 1, 0); + } if(lines > 0) { /* draw vertical list */ - dc->w = mw - dc->x; + w = mw - x; for(item = curr; item != next; item = item->right) { - dc->y += dc->h; - drawtext(dc, item->text, (item == sel) ? selcol : - (item->out) ? outcol : normcol); + y += h; + if(item == sel) + drw_setscheme(drw, &scheme[SchemeSel]); + else if(item->out) + drw_setscheme(drw, &scheme[SchemeOut]); + else + drw_setscheme(drw, &scheme[SchemeNorm]); + + drw_text(drw, x, y, w, bh, item->text, 0); } } else if(matches) { /* draw horizontal list */ - dc->x += inputw; - dc->w = textw(dc, "<"); - if(curr->left) - drawtext(dc, "<", normcol); + x += inputw; + w = TEXTW("<"); + if(curr->left) { + drw_setscheme(drw, &scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, "<", 0); + } for(item = curr; item != next; item = item->right) { - dc->x += dc->w; - dc->w = MIN(textw(dc, item->text), mw - dc->x - textw(dc, ">")); - drawtext(dc, item->text, (item == sel) ? selcol : - (item->out) ? outcol : normcol); + x += w; + w = MIN(TEXTW(item->text), mw - x - TEXTW(">")); + + if(item == sel) + drw_setscheme(drw, &scheme[SchemeSel]); + else if(item->out) + drw_setscheme(drw, &scheme[SchemeOut]); + else + drw_setscheme(drw, &scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, item->text, 0); + } + w = TEXTW(">"); + x = mw - w; + if(next) { + drw_setscheme(drw, &scheme[SchemeNorm]); + drw_text(drw, x, 0, w, bh, ">", 0); } - dc->w = textw(dc, ">"); - dc->x = mw - dc->w; - if(next) - drawtext(dc, ">", normcol); } - mapdc(dc, win, mw, mh); + drw_map(drw, win, 0, 0, mw, mh); } void @@ -214,12 +271,12 @@ grabkeyboard(void) { /* try to grab keyboard, we may have to wait for another process to ungrab */ for(i = 0; i < 1000; i++) { - if(XGrabKeyboard(dc->dpy, DefaultRootWindow(dc->dpy), True, + if(XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync, GrabModeAsync, CurrentTime) == GrabSuccess) return; usleep(1000); } - eprintf("cannot grab keyboard\n"); + die("cannot grab keyboard\n"); } void @@ -276,14 +333,15 @@ keypress(XKeyEvent *ev) { insert(NULL, nextrune(-1) - cursor); break; case XK_y: /* paste selection */ - XConvertSelection(dc->dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY, + XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY, utf8, utf8, win, CurrentTime); return; case XK_Return: case XK_KP_Enter: break; case XK_bracketleft: - exit(EXIT_FAILURE); + cleanup(); + exit(1); default: return; } @@ -330,7 +388,8 @@ keypress(XKeyEvent *ev) { sel = matchend; break; case XK_Escape: - exit(EXIT_FAILURE); + cleanup(); + exit(1); case XK_Home: if(sel == matches) { cursor = 0; @@ -368,8 +427,10 @@ keypress(XKeyEvent *ev) { case XK_Return: case XK_KP_Enter: puts((sel && !(ev->state & ShiftMask)) ? sel->text : text); - if(!(ev->state & ControlMask)) - exit(EXIT_SUCCESS); + if(!(ev->state & ControlMask)) { + cleanup(); + exit(0); + } if(sel) sel->out = True; break; @@ -413,7 +474,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))) - eprintf("cannot realloc %u bytes\n", tokn * sizeof *tokv); + die("cannot realloc %u bytes\n", tokn * sizeof *tokv); len = tokc ? strlen(tokv[0]) : 0; matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL; @@ -470,7 +531,7 @@ paste(void) { Atom da; /* we have been given the current selection, now insert it into input */ - XGetWindowProperty(dc->dpy, win, utf8, 0, (sizeof text / 4) + 1, False, + XGetWindowProperty(dpy, win, utf8, 0, (sizeof text / 4) + 1, False, utf8, &da, &di, &dl, &dl, (unsigned char **)&p); insert(p, (q = strchr(p, '\n')) ? q-p : (ssize_t)strlen(p)); XFree(p); @@ -486,18 +547,18 @@ readstdin(void) { for(i = 0; fgets(buf, sizeof buf, stdin); i++) { if(i+1 >= size / sizeof *items) if(!(items = realloc(items, (size += BUFSIZ)))) - eprintf("cannot realloc %u bytes:", size); + die("cannot realloc %u bytes:", size); if((p = strchr(buf, '\n'))) *p = '\0'; if(!(items[i].text = strdup(buf))) - eprintf("cannot strdup %u bytes:", strlen(buf)+1); + die("cannot strdup %u bytes:", strlen(buf)+1); items[i].out = False; if(strlen(items[i].text) > max) max = strlen(maxstr = items[i].text); } if(items) items[i].text = NULL; - inputw = maxstr ? textw(dc, maxstr) : 0; + inputw = maxstr ? TEXTW(maxstr) : 0; lines = MIN(lines, i); } @@ -505,13 +566,13 @@ void run(void) { XEvent ev; - while(!XNextEvent(dc->dpy, &ev)) { + while(!XNextEvent(dpy, &ev)) { if(XFilterEvent(&ev, win)) continue; switch(ev.type) { case Expose: if(ev.xexpose.count == 0) - mapdc(dc, win, mw, mh); + drw_map(drw, win, 0, 0, mw, mh); break; case KeyPress: keypress(&ev.xkey); @@ -522,7 +583,7 @@ run(void) { break; case VisibilityNotify: if(ev.xvisibility.state != VisibilityUnobscured) - XRaiseWindow(dc->dpy, win); + XRaiseWindow(dpy, win); break; } } @@ -530,47 +591,45 @@ run(void) { void setup(void) { - int x, y, screen = DefaultScreen(dc->dpy); - Window root = RootWindow(dc->dpy, screen); + int x, y; XSetWindowAttributes swa; XIM xim; #ifdef XINERAMA - int n; XineramaScreenInfo *info; + Window w, pw, dw, *dws; + XWindowAttributes wa; + int a, j, di, n, i = 0, area = 0; + unsigned int du; #endif - normcol[ColBG] = getcolor(dc, normbgcolor); - normcol[ColFG] = getcolor(dc, normfgcolor); - selcol[ColBG] = getcolor(dc, selbgcolor); - selcol[ColFG] = getcolor(dc, selfgcolor); - outcol[ColBG] = getcolor(dc, outbgcolor); - outcol[ColFG] = getcolor(dc, outfgcolor); + /* init appearance */ + scheme[SchemeNorm].bg = drw_clr_create(drw, normbgcolor); + scheme[SchemeNorm].fg = drw_clr_create(drw, normfgcolor); + scheme[SchemeSel].bg = drw_clr_create(drw, selbgcolor); + scheme[SchemeSel].fg = drw_clr_create(drw, selfgcolor); + scheme[SchemeOut].bg = drw_clr_create(drw, outbgcolor); + scheme[SchemeOut].fg = drw_clr_create(drw, outfgcolor); - clip = XInternAtom(dc->dpy, "CLIPBOARD", False); - utf8 = XInternAtom(dc->dpy, "UTF8_STRING", False); + clip = XInternAtom(dpy, "CLIPBOARD", False); + utf8 = XInternAtom(dpy, "UTF8_STRING", False); /* calculate menu geometry */ - bh = dc->font.height + 2; + bh = drw->fonts[0]->h + 2; lines = MAX(lines, 0); mh = (lines + 1) * bh; #ifdef XINERAMA - if((info = XineramaQueryScreens(dc->dpy, &n))) { - int a, j, di, i = 0, area = 0; - unsigned int du; - Window w, pw, dw, *dws; - XWindowAttributes wa; - - XGetInputFocus(dc->dpy, &w, &di); + if((info = XineramaQueryScreens(dpy, &n))) { + XGetInputFocus(dpy, &w, &di); if(mon != -1 && mon < n) i = mon; if(!i && w != root && w != PointerRoot && w != None) { /* find top-level window containing current input focus */ do { - if(XQueryTree(dc->dpy, (pw = w), &dw, &w, &dws, &du) && dws) + if(XQueryTree(dpy, (pw = w), &dw, &w, &dws, &du) && dws) XFree(dws); } while(w != root && w != pw); /* find xinerama screen with which the window intersects most */ - if(XGetWindowAttributes(dc->dpy, pw, &wa)) + if(XGetWindowAttributes(dpy, pw, &wa)) for(j = 0; j < n; j++) if((a = INTERSECT(wa.x, wa.y, wa.width, wa.height, info[j])) > area) { area = a; @@ -578,7 +637,7 @@ setup(void) { } } /* no focused window is on screen, so use pointer location instead */ - if(mon == -1 && !area && XQueryPointer(dc->dpy, root, &dw, &dw, &x, &y, &di, &di, &du)) + if(mon == -1 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du)) for(i = 0; i < n; i++) if(INTERSECT(x, y, 1, 1, info[i])) break; @@ -592,29 +651,29 @@ setup(void) { #endif { x = 0; - y = topbar ? 0 : DisplayHeight(dc->dpy, screen) - mh; - mw = DisplayWidth(dc->dpy, screen); + y = topbar ? 0 : sh - mh; + mw = sw; } - promptw = (prompt && *prompt) ? textw(dc, prompt) : 0; + promptw = (prompt && *prompt) ? TEXTW(prompt) : 0; inputw = MIN(inputw, mw/3); match(); /* create menu window */ swa.override_redirect = True; - swa.background_pixel = normcol[ColBG]; + swa.background_pixel = scheme[SchemeNorm].bg->pix; swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; - win = XCreateWindow(dc->dpy, root, x, y, mw, mh, 0, - DefaultDepth(dc->dpy, screen), CopyFromParent, - DefaultVisual(dc->dpy, screen), + win = XCreateWindow(dpy, root, x, y, mw, mh, 0, + DefaultDepth(dpy, screen), CopyFromParent, + DefaultVisual(dpy, screen), CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); /* open input methods */ - xim = XOpenIM(dc->dpy, NULL, NULL, NULL); + xim = XOpenIM(dpy, NULL, NULL, NULL); xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, win, XNFocusWindow, win, NULL); - XMapRaised(dc->dpy, win); - resizedc(dc, mw, mh); + XMapRaised(dpy, win); + drw_resize(drw, mw, mh); drawmenu(); } @@ -622,5 +681,5 @@ void usage(void) { fputs("usage: dmenu [-b] [-f] [-i] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" " [-nb color] [-nf color] [-sb color] [-sf color] [-v]\n", stderr); - exit(EXIT_FAILURE); + exit(1); } diff --git a/draw.c b/draw.c deleted file mode 100644 index 76f0c54..0000000 --- a/draw.c +++ /dev/null @@ -1,177 +0,0 @@ -/* See LICENSE file for copyright and license details. */ -#include -#include -#include -#include -#include -#include -#include "draw.h" - -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define DEFAULTFN "fixed" - -static Bool loadfont(DC *dc, const char *fontstr); - -void -drawrect(DC *dc, int x, int y, unsigned int w, unsigned int h, Bool fill, unsigned long color) { - XSetForeground(dc->dpy, dc->gc, color); - if(fill) - XFillRectangle(dc->dpy, dc->canvas, dc->gc, dc->x + x, dc->y + y, w, h); - else - XDrawRectangle(dc->dpy, dc->canvas, dc->gc, dc->x + x, dc->y + y, w-1, h-1); -} - -void -drawtext(DC *dc, const char *text, unsigned long col[ColLast]) { - char buf[BUFSIZ]; - size_t mn, n = strlen(text); - - /* shorten text if necessary */ - for(mn = MIN(n, sizeof buf); textnw(dc, text, mn) + dc->font.height/2 > dc->w; mn--) - if(mn == 0) - return; - memcpy(buf, text, mn); - if(mn < n) - for(n = MAX(mn-3, 0); n < mn; buf[n++] = '.'); - - drawrect(dc, 0, 0, dc->w, dc->h, True, BG(dc, col)); - drawtextn(dc, buf, mn, col); -} - -void -drawtextn(DC *dc, const char *text, size_t n, unsigned long col[ColLast]) { - int x = dc->x + dc->font.height/2; - int y = dc->y + dc->font.ascent+1; - - XSetForeground(dc->dpy, dc->gc, FG(dc, col)); - if(dc->font.set) - XmbDrawString(dc->dpy, dc->canvas, dc->font.set, dc->gc, x, y, text, n); - else { - XSetFont(dc->dpy, dc->gc, dc->font.xfont->fid); - XDrawString(dc->dpy, dc->canvas, dc->gc, x, y, text, n); - } -} - -void -eprintf(const char *fmt, ...) { - va_list ap; - - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - - if(fmt[0] != '\0' && fmt[strlen(fmt)-1] == ':') { - fputc(' ', stderr); - perror(NULL); - } - exit(EXIT_FAILURE); -} - -void -freedc(DC *dc) { - if(dc->font.set) - XFreeFontSet(dc->dpy, dc->font.set); - if(dc->font.xfont) - XFreeFont(dc->dpy, dc->font.xfont); - if(dc->canvas) - XFreePixmap(dc->dpy, dc->canvas); - XFreeGC(dc->dpy, dc->gc); - XCloseDisplay(dc->dpy); - free(dc); -} - -unsigned long -getcolor(DC *dc, const char *colstr) { - Colormap cmap = DefaultColormap(dc->dpy, DefaultScreen(dc->dpy)); - XColor color; - - if(!XAllocNamedColor(dc->dpy, cmap, colstr, &color, &color)) - eprintf("cannot allocate color '%s'\n", colstr); - return color.pixel; -} - -DC * -initdc(void) { - DC *dc; - - if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) - fputs("no locale support\n", stderr); - if(!(dc = calloc(1, sizeof *dc))) - eprintf("cannot malloc %u bytes:", sizeof *dc); - if(!(dc->dpy = XOpenDisplay(NULL))) - eprintf("cannot open display\n"); - - dc->gc = XCreateGC(dc->dpy, DefaultRootWindow(dc->dpy), 0, NULL); - XSetLineAttributes(dc->dpy, dc->gc, 1, LineSolid, CapButt, JoinMiter); - return dc; -} - -void -initfont(DC *dc, const char *fontstr) { - if(!loadfont(dc, fontstr ? fontstr : DEFAULTFN)) { - if(fontstr != NULL) - fprintf(stderr, "cannot load font '%s'\n", fontstr); - if(fontstr == NULL || !loadfont(dc, DEFAULTFN)) - eprintf("cannot load font '%s'\n", DEFAULTFN); - } - dc->font.height = dc->font.ascent + dc->font.descent; -} - -Bool -loadfont(DC *dc, const char *fontstr) { - char *def, **missing, **names; - int i, n; - XFontStruct **xfonts; - - if(!*fontstr) - return False; - if((dc->font.set = XCreateFontSet(dc->dpy, fontstr, &missing, &n, &def))) { - n = XFontsOfFontSet(dc->font.set, &xfonts, &names); - for(i = 0; i < n; i++) { - dc->font.ascent = MAX(dc->font.ascent, xfonts[i]->ascent); - dc->font.descent = MAX(dc->font.descent, xfonts[i]->descent); - dc->font.width = MAX(dc->font.width, xfonts[i]->max_bounds.width); - } - } - else if((dc->font.xfont = XLoadQueryFont(dc->dpy, fontstr))) { - dc->font.ascent = dc->font.xfont->ascent; - dc->font.descent = dc->font.xfont->descent; - dc->font.width = dc->font.xfont->max_bounds.width; - } - if(missing) - XFreeStringList(missing); - return dc->font.set || dc->font.xfont; -} - -void -mapdc(DC *dc, Window win, unsigned int w, unsigned int h) { - XCopyArea(dc->dpy, dc->canvas, win, dc->gc, 0, 0, w, h, 0, 0); -} - -void -resizedc(DC *dc, unsigned int w, unsigned int h) { - if(dc->canvas) - XFreePixmap(dc->dpy, dc->canvas); - - dc->w = w; - dc->h = h; - dc->canvas = XCreatePixmap(dc->dpy, DefaultRootWindow(dc->dpy), w, h, - DefaultDepth(dc->dpy, DefaultScreen(dc->dpy))); -} - -int -textnw(DC *dc, const char *text, size_t len) { - if(dc->font.set) { - XRectangle r; - - XmbTextExtents(dc->font.set, text, len, NULL, &r); - return r.width; - } - return XTextWidth(dc->font.xfont, text, len); -} - -int -textw(DC *dc, const char *text) { - return textnw(dc, text, strlen(text)) + dc->font.height; -} diff --git a/draw.h b/draw.h deleted file mode 100644 index 43a57bf..0000000 --- a/draw.h +++ /dev/null @@ -1,35 +0,0 @@ -/* See LICENSE file for copyright and license details. */ - -#define FG(dc, col) ((col)[(dc)->invert ? ColBG : ColFG]) -#define BG(dc, col) ((col)[(dc)->invert ? ColFG : ColBG]) - -enum { ColBG, ColFG, ColBorder, ColLast }; - -typedef struct { - int x, y, w, h; - Bool invert; - Display *dpy; - GC gc; - Pixmap canvas; - struct { - int ascent; - int descent; - int height; - int width; - XFontSet set; - XFontStruct *xfont; - } font; -} DC; /* draw context */ - -void drawrect(DC *dc, int x, int y, unsigned int w, unsigned int h, Bool fill, unsigned long color); -void drawtext(DC *dc, const char *text, unsigned long col[ColLast]); -void drawtextn(DC *dc, const char *text, size_t n, unsigned long col[ColLast]); -void eprintf(const char *fmt, ...); -void freedc(DC *dc); -unsigned long getcolor(DC *dc, const char *colstr); -DC *initdc(void); -void initfont(DC *dc, const char *fontstr); -void mapdc(DC *dc, Window win, unsigned int w, unsigned int h); -void resizedc(DC *dc, unsigned int w, unsigned int h); -int textnw(DC *dc, const char *text, size_t len); -int textw(DC *dc, const char *text); diff --git a/drw.c b/drw.c new file mode 100644 index 0000000..0423873 --- /dev/null +++ b/drw.c @@ -0,0 +1,413 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include + +#include "drw.h" +#include "util.h" + +#define UTF_INVALID 0xFFFD +#define UTF_SIZ 4 + +static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; +static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; +static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; +static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; + +static long +utf8decodebyte(const char c, size_t *i) { + for(*i = 0; *i < (UTF_SIZ + 1); ++(*i)) + if(((unsigned char)c & utfmask[*i]) == utfbyte[*i]) + return (unsigned char)c & ~utfmask[*i]; + return 0; +} + +static size_t +utf8validate(long *u, size_t i) { + if(!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) + *u = UTF_INVALID; + for(i = 1; *u > utfmax[i]; ++i) + ; + return i; +} + +static size_t +utf8decode(const char *c, long *u, size_t clen) { + size_t i, j, len, type; + long udecoded; + + *u = UTF_INVALID; + if(!clen) + return 0; + udecoded = utf8decodebyte(c[0], &len); + if(!BETWEEN(len, 1, UTF_SIZ)) + return 1; + for(i = 1, j = 1; i < clen && j < len; ++i, ++j) { + udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); + if(type != 0) + return j; + } + if(j < len) + return 0; + *u = udecoded; + utf8validate(u, len); + return len; +} + +Drw * +drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h) { + Drw *drw = (Drw *)calloc(1, sizeof(Drw)); + if(!drw) + return NULL; + drw->dpy = dpy; + drw->screen = screen; + drw->root = root; + drw->w = w; + drw->h = h; + drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); + drw->gc = XCreateGC(dpy, root, 0, NULL); + drw->fontcount = 0; + 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 != 0) + XFreePixmap(drw->dpy, drw->drawable); + drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen)); +} + +void +drw_free(Drw *drw) { + size_t i; + + for (i = 0; i < drw->fontcount; i++) { + drw_font_free(drw->fonts[i]); + } + XFreePixmap(drw->dpy, drw->drawable); + XFreeGC(drw->dpy, drw->gc); + free(drw); +} + +/* This function is an implementation detail. Library users should use + * drw_font_create instead. + */ +static Fnt * +drw_font_xcreate(Drw *drw, const char *fontname, FcPattern *fontpattern) { + Fnt *font; + + if (!(fontname || fontpattern)) + die("No font specified.\n"); + + if (!(font = (Fnt *)calloc(1, sizeof(Fnt)))) + return NULL; + + if (fontname) { + /* Using the pattern found at font->xfont->pattern does not yield same + * 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 (!(font->xfont = XftFontOpenName(drw->dpy, drw->screen, fontname)) || + !(font->pattern = FcNameParse((FcChar8 *) fontname))) { + if (font->xfont) { + XftFontClose(drw->dpy, font->xfont); + font->xfont = NULL; + } + fprintf(stderr, "error, cannot load font: '%s'\n", fontname); + } + } else if (fontpattern) { + if (!(font->xfont = XftFontOpenPattern(drw->dpy, fontpattern))) { + fprintf(stderr, "error, cannot load font pattern.\n"); + } else { + font->pattern = NULL; + } + } + + if (!font->xfont) { + free(font); + return NULL; + } + + font->ascent = font->xfont->ascent; + font->descent = font->xfont->descent; + font->h = font->ascent + font->descent; + font->dpy = drw->dpy; + return font; +} + +Fnt* +drw_font_create(Drw *drw, const char *fontname) { + return drw_font_xcreate(drw, fontname, NULL); +} + +void +drw_load_fonts(Drw* drw, const char *fonts[], size_t fontcount) { + size_t i; + Fnt *font; + + for (i = 0; i < fontcount; i++) { + if (drw->fontcount >= DRW_FONT_CACHE_SIZE) { + die("Font cache exhausted.\n"); + } else if ((font = drw_font_xcreate(drw, fonts[i], NULL))) { + drw->fonts[drw->fontcount++] = font; + } + } +} + +void +drw_font_free(Fnt *font) { + if(!font) + return; + if(font->pattern) + FcPatternDestroy(font->pattern); + XftFontClose(font->dpy, font->xfont); + free(font); +} + +Clr * +drw_clr_create(Drw *drw, const char *clrname) { + Clr *clr; + Colormap cmap; + Visual *vis; + + if(!drw) + return NULL; + clr = (Clr *)calloc(1, sizeof(Clr)); + if(!clr) + return NULL; + cmap = DefaultColormap(drw->dpy, drw->screen); + vis = DefaultVisual(drw->dpy, drw->screen); + if(!XftColorAllocName(drw->dpy, vis, cmap, clrname, &clr->rgb)) + die("error, cannot allocate color '%s'\n", clrname); + clr->pix = clr->rgb.pixel; + return clr; +} + +void +drw_clr_free(Clr *clr) { + free(clr); +} + +void +drw_setscheme(Drw *drw, ClrScheme *scheme) { + if(!drw) + return; + drw->scheme = scheme; +} + +void +drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty, int invert) { + if(!drw || !drw->scheme) + return; + XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->bg->pix : drw->scheme->fg->pix); + if(filled) + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w + 1, h + 1); + else if(empty) + XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); +} + +int +drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int invert) { + char buf[1024]; + int tx, ty, th; + Extnts tex; + Colormap cmap; + Visual *vis; + XftDraw *d; + Fnt *curfont, *nextfont; + size_t i, len; + int utf8strlen, utf8charlen, render; + long utf8codepoint = 0; + const char *utf8str; + FcCharSet *fccharset; + FcPattern *fcpattern; + FcPattern *match; + XftResult result; + int charexists = 0; + + if (!(render = x || y || w || h)) { + w = ~w; + } + + if (!drw || !drw->scheme) { + return 0; + } else if (render) { + XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->fg->pix : drw->scheme->bg->pix); + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); + } + + if (!text || !drw->fontcount) { + return 0; + } else if (render) { + cmap = DefaultColormap(drw->dpy, drw->screen); + vis = DefaultVisual(drw->dpy, drw->screen); + d = XftDrawCreate(drw->dpy, drw->drawable, vis, cmap); + } + + curfont = drw->fonts[0]; + while (1) { + utf8strlen = 0; + utf8str = text; + nextfont = NULL; + while (*text) { + utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); + for (i = 0; i < drw->fontcount; i++) { + charexists = charexists || XftCharExists(drw->dpy, drw->fonts[i]->xfont, utf8codepoint); + if (charexists) { + if (drw->fonts[i] == curfont) { + utf8strlen += utf8charlen; + text += utf8charlen; + } else { + nextfont = drw->fonts[i]; + } + break; + } + } + + if (!charexists || (nextfont && nextfont != curfont)) { + break; + } else { + charexists = 0; + } + } + + if (utf8strlen) { + drw_font_getexts(curfont, utf8str, utf8strlen, &tex); + /* shorten text if necessary */ + for(len = MIN(utf8strlen, (sizeof buf) - 1); len && (tex.w > w - drw->fonts[0]->h || w < drw->fonts[0]->h); len--) + drw_font_getexts(curfont, utf8str, len, &tex); + + if (len) { + memcpy(buf, utf8str, len); + buf[len] = '\0'; + if(len < utf8strlen) + for(i = len; i && i > len - 3; buf[--i] = '.'); + + if (render) { + th = curfont->ascent + curfont->descent; + ty = y + (h / 2) - (th / 2) + curfont->ascent; + tx = x + (h / 2); + XftDrawStringUtf8(d, invert ? &drw->scheme->bg->rgb : &drw->scheme->fg->rgb, curfont->xfont, tx, ty, (XftChar8 *)buf, len); + } + + x += tex.w; + w -= tex.w; + } + } + + if (!*text) { + break; + } else if (nextfont) { + charexists = 0; + curfont = nextfont; + } else { + /* Regardless of whether or not a fallback font is found, the + * character must be drawn. + */ + charexists = 1; + + if (drw->fontcount >= DRW_FONT_CACHE_SIZE) { + continue; + } + + fccharset = FcCharSetCreate(); + FcCharSetAddChar(fccharset, utf8codepoint); + + if (!drw->fonts[0]->pattern) { + /* Refer to the comment in drw_font_xcreate for more + * information. + */ + die("The first font in the cache must be loaded from a font string.\n"); + } + + fcpattern = FcPatternDuplicate(drw->fonts[0]->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) { + curfont = drw_font_xcreate(drw, NULL, match); + if (curfont && XftCharExists(drw->dpy, curfont->xfont, utf8codepoint)) { + drw->fonts[drw->fontcount++] = curfont; + } else { + if (curfont) { + drw_font_free(curfont); + } + curfont = drw->fonts[0]; + } + } + } + } + + if (render) { + XftDrawDestroy(d); + } + + return x; +} + +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); +} + + +void +drw_font_getexts(Fnt *font, const char *text, unsigned int len, Extnts *tex) { + XGlyphInfo ext; + + if(!font || !text) + return; + XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext); + tex->h = font->h; + tex->w = ext.xOff; +} + +unsigned int +drw_font_getexts_width(Fnt *font, const char *text, unsigned int len) { + Extnts tex; + + if(!font) + return -1; + drw_font_getexts(font, text, len, &tex); + return tex.w; +} + +Cur * +drw_cur_create(Drw *drw, int shape) { + Cur *cur; + + if(!drw) + return NULL; + cur = (Cur *)calloc(1, sizeof(Cur)); + if (!cur) + return NULL; + cur->cursor = XCreateFontCursor(drw->dpy, shape); + return cur; +} + +void +drw_cur_free(Drw *drw, Cur *cursor) { + if(!drw || !cursor) + return; + XFreeCursor(drw->dpy, cursor->cursor); + free(cursor); +} diff --git a/drw.h b/drw.h new file mode 100644 index 0000000..536171b --- /dev/null +++ b/drw.h @@ -0,0 +1,74 @@ +/* See LICENSE file for copyright and license details. */ +#define DRW_FONT_CACHE_SIZE 32 + +typedef struct { + unsigned long pix; + XftColor rgb; +} Clr; + +typedef struct { + Cursor cursor; +} Cur; + +typedef struct { + Display *dpy; + int ascent; + int descent; + unsigned int h; + XftFont *xfont; + FcPattern *pattern; +} Fnt; + +typedef struct { + Clr *fg; + Clr *bg; + Clr *border; +} ClrScheme; + +typedef struct { + unsigned int w, h; + Display *dpy; + int screen; + Window root; + Drawable drawable; + GC gc; + ClrScheme *scheme; + size_t fontcount; + Fnt *fonts[DRW_FONT_CACHE_SIZE]; +} Drw; + +typedef struct { + unsigned int w; + unsigned int h; +} Extnts; + +/* Drawable abstraction */ +Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h); +void drw_resize(Drw *drw, unsigned int w, unsigned int h); +void drw_free(Drw *drw); + +/* Fnt abstraction */ +Fnt *drw_font_create(Drw *drw, const char *fontname); +void drw_load_fonts(Drw* drw, const char *fonts[], size_t fontcount); +void drw_font_free(Fnt *font); +void drw_font_getexts(Fnt *font, const char *text, unsigned int len, Extnts *extnts); +unsigned int drw_font_getexts_width(Fnt *font, const char *text, unsigned int len); + +/* Colour abstraction */ +Clr *drw_clr_create(Drw *drw, const char *clrname); +void drw_clr_free(Clr *clr); + +/* Cursor abstraction */ +Cur *drw_cur_create(Drw *drw, int shape); +void drw_cur_free(Drw *drw, Cur *cursor); + +/* Drawing context manipulation */ +void drw_setfont(Drw *drw, Fnt *font); +void drw_setscheme(Drw *drw, ClrScheme *scheme); + +/* Drawing functions */ +void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty, int invert); +int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int invert); + +/* Map functions */ +void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); diff --git a/util.c b/util.c new file mode 100644 index 0000000..9b27512 --- /dev/null +++ b/util.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include + +#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); + } + + exit(1); +} diff --git a/util.h b/util.h new file mode 100644 index 0000000..f7ce721 --- /dev/null +++ b/util.h @@ -0,0 +1,7 @@ +/* See LICENSE file for copyright and license details. */ + +#define MAX(A, B) ((A) > (B) ? (A) : (B)) +#define MIN(A, B) ((A) < (B) ? (A) : (B)) +#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B)) + +void die(const char *errstr, ...); -- 2.20.1 From 1c242df1244af10cf5d2c2640ac0d2a7ad1ad878 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Sun, 19 Jul 2015 20:29:26 +0200 Subject: [PATCH 11/16] fix prompt color style how it used to be This is the style how it was before the big Xft change. The colors were inverted, this was not the case before the change. Reported by "zvz" on #suckless IRC, thanks! --- dmenu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dmenu.c b/dmenu.c index 94be574..11b6e8d 100644 --- a/dmenu.c +++ b/dmenu.c @@ -207,7 +207,7 @@ drawmenu(void) { if(prompt && *prompt) { drw_setscheme(drw, &scheme[SchemeSel]); - drw_text(drw, x, 0, promptw, bh, prompt, 1); + drw_text(drw, x, 0, promptw, bh, prompt, 0); x += promptw; } /* draw input field */ -- 2.20.1 From 5feb0c689dd815a31d48e2007b364057f6fec773 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Sun, 19 Jul 2015 20:32:08 +0200 Subject: [PATCH 12/16] config.mk: add FREETYPELIBS and FREETYPEINC These variables make it simpler to change the paths to this for ports. `pkg-config` is avoided because it sucks, in particular for cross-compilation. A commented path for *BSD is added, the Xft includes are located at: /usr/X11R6/include there. Also already bump the version number to 4.6, a release will come approximately in August. --- config.mk | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/config.mk b/config.mk index 4e62a09..95690f9 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,5 @@ # dmenu version -VERSION = 4.5-tip +VERSION = 4.6 # paths PREFIX = /usr/local @@ -12,9 +12,15 @@ X11LIB = /usr/X11R6/lib XINERAMALIBS = -lXinerama XINERAMAFLAGS = -DXINERAMA +# freetype +FREETYPELIBS = -lfontconfig -lXft +FREETYPEINC = /usr/include/freetype2 +# OpenBSD (uncomment) +#FREETYPEINC = ${X11INC}/freetype2 + # includes and libs -INCS = -I${X11INC} -I/usr/include/freetype2 -LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} -lfontconfig -lXft +INCS = -I${X11INC} -I${FREETYPEINC} +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} # flags CPPFLAGS = -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} -- 2.20.1 From d6742ef8a6ce03f28ee9431ef51901ef712ffd76 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Sun, 19 Jul 2015 21:34:51 +0200 Subject: [PATCH 13/16] stest: get rid of getopt, use suckless arg.h ... also some style improvements. --- Makefile | 6 +-- arg.h | 63 ++++++++++++++++++++++++++++ stest.c | 125 +++++++++++++++++++++++++++++++++---------------------- 3 files changed, 141 insertions(+), 53 deletions(-) create mode 100644 arg.h diff --git a/Makefile b/Makefile index 4a412ee..8f14a8c 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ config.h: @echo creating $@ from config.def.h @cp config.def.h $@ -${OBJ}: config.h config.mk drw.h +${OBJ}: arg.h config.h config.mk drw.h dmenu: dmenu.o drw.o util.o @echo CC -o $@ @@ -39,8 +39,8 @@ clean: dist: clean @echo creating dist tarball @mkdir -p dmenu-${VERSION} - @cp LICENSE Makefile README config.mk dmenu.1 drw.h util.h dmenu_path \ - dmenu_run stest.1 ${SRC} dmenu-${VERSION} + @cp LICENSE Makefile README arg.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} diff --git a/arg.h b/arg.h new file mode 100644 index 0000000..4df77a7 --- /dev/null +++ b/arg.h @@ -0,0 +1,63 @@ +/* + * 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][1]\ + && argv[0][0] == '-';\ + argc--, argv++) {\ + char argc_;\ + char **argv_;\ + int brk_;\ + if (argv[0][1] == '-' && argv[0][2] == '\0') {\ + argv++;\ + argc--;\ + break;\ + }\ + for (brk_ = 0, argv[0]++, argv_ = argv;\ + argv[0][0] && !brk_;\ + argv[0]++) {\ + if (argv_ != argv)\ + break;\ + argc_ = argv[0][0];\ + switch (argc_) + +/* Handles obsolete -NUM syntax */ +#define ARGNUM case '0':\ + case '1':\ + case '2':\ + case '3':\ + case '4':\ + case '5':\ + case '6':\ + case '7':\ + case '8':\ + case '9' + +#define ARGEND }\ + } + +#define ARGC() argc_ + +#define ARGNUMF(base) (brk_ = 1, estrtol(argv[0], (base))) + +#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 diff --git a/stest.c b/stest.c index 8fac42a..7a7b0bc 100644 --- a/stest.c +++ b/stest.c @@ -1,66 +1,31 @@ /* See LICENSE file for copyright and license details. */ +#include + #include -#include +#include #include #include #include #include -#include + +#include "arg.h" +char *argv0; #define FLAG(x) (flag[(x)-'a']) static void test(const char *, const char *); +static void usage(void); -static bool match = false; -static bool flag[26]; +static int match = 0; +static int flag[26]; static struct stat old, new; -int -main(int argc, char *argv[]) { - struct dirent *d; - char buf[BUFSIZ], *p; - DIR *dir; - int opt; - - while((opt = getopt(argc, argv, "abcdefghln:o:pqrsuvwx")) != -1) - switch(opt) { - case 'n': /* newer than file */ - case 'o': /* older than file */ - if(!(FLAG(opt) = !stat(optarg, (opt == 'n' ? &new : &old)))) - perror(optarg); - break; - default: /* miscellaneous operators */ - FLAG(opt) = true; - break; - case '?': /* error: unknown flag */ - fprintf(stderr, "usage: %s [-abcdefghlpqrsuvwx] [-n file] [-o file] [file...]\n", argv[0]); - exit(2); - } - if(optind == argc) - while(fgets(buf, sizeof buf, stdin)) { - if((p = strchr(buf, '\n'))) - *p = '\0'; - test(buf, buf); - } - for(; optind < argc; optind++) - if(FLAG('l') && (dir = opendir(argv[optind]))) { - /* test directory contents */ - while((d = readdir(dir))) - if(snprintf(buf, sizeof buf, "%s/%s", argv[optind], d->d_name) < sizeof buf) - test(buf, d->d_name); - closedir(dir); - } - else - test(argv[optind], argv[optind]); - - return match ? 0 : 1; -} - -void -test(const char *path, const char *name) { +static void +test(const char *path, const char *name) +{ struct stat st, ln; - if((!stat(path, &st) && (FLAG('a') || name[0] != '.') /* hidden files */ + 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 */ @@ -76,9 +41,69 @@ test(const char *path, const char *name) { && (!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')) + if (FLAG('q')) exit(0); - match = true; + match = 1; puts(name); } } + +static void +usage(void) +{ + fprintf(stderr, "usage: %s [-abcdefghlpqrsuvwx] " + "[-n file] [-o file] [file...]\n", argv0); + exit(2); /* like test(1) return > 1 on error */ +} + +int +main(int argc, char *argv[]) +{ + struct dirent *d; + char path[PATH_MAX], *line = NULL, *file; + size_t linesiz = 0; + ssize_t n; + DIR *dir; + int r; + + ARGBEGIN { + case 'n': /* newer than file */ + case 'o': /* older than file */ + file = EARGF(usage()); + if (!(FLAG(ARGC()) = !stat(file, (ARGC() == 'n' ? &new : &old)))) + perror(file); + break; + default: + /* miscellaneous operators */ + if (strchr("abcdefghlpqrsuvwx", ARGC())) + FLAG(ARGC()) = 1; + else + usage(); /* unknown flag */ + } ARGEND; + + if (!argc) { + /* read list from stdin */ + while ((n = getline(&line, &linesiz, stdin)) > 0) { + if (n && line[n - 1] == '\n') + line[n - 1] = '\0'; + test(line, line); + } + free(line); + } else { + for (; argc; argc--, argv++) { + if (FLAG('l') && (dir = opendir(*argv))) { + /* test directory contents */ + while ((d = readdir(dir))) { + r = snprintf(path, sizeof path, "%s/%s", + *argv, d->d_name); + if (r >= 0 && (size_t)r < sizeof path) + test(path, d->d_name); + } + closedir(dir); + } else { + test(*argv, *argv); + } + } + } + return match ? 0 : 1; +} -- 2.20.1 From bbf7b95dc93a47dbb5a4143b903797dc97197515 Mon Sep 17 00:00:00 2001 From: Eric Pruitt Date: Wed, 5 Aug 2015 19:19:14 -0700 Subject: [PATCH 14/16] Fixed typo introduced by shared code --- dmenu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dmenu.c b/dmenu.c index 11b6e8d..f0bc176 100644 --- a/dmenu.c +++ b/dmenu.c @@ -118,7 +118,7 @@ main(int argc, char *argv[]) { if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) fputs("warning: no locale support\n", stderr); if(!(dpy = XOpenDisplay(NULL))) - die("dwm: cannot open display\n"); + die("dmenu: cannot open display\n"); screen = DefaultScreen(dpy); root = RootWindow(dpy, screen); sw = DisplayWidth(dpy, screen); -- 2.20.1 From 2d2175ff6f67e2bc85138d3f359d2f7580bcb754 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Sun, 27 Sep 2015 22:38:14 +0200 Subject: [PATCH 15/16] config.mk: improve feature test check this fixes a crash on NetBSD because it requires -D_XOPEN_SOURCE (strdup, usleep). thanks k0ga and stateless for reporting and fixing this issue! --- config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.mk b/config.mk index 95690f9..7b08bf1 100644 --- a/config.mk +++ b/config.mk @@ -23,7 +23,7 @@ INCS = -I${X11INC} -I${FREETYPEINC} LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} # flags -CPPFLAGS = -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +CPPFLAGS = -D_BSD_SOURCE -D_XOPEN_SOURCE=500 -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} CFLAGS = -ansi -pedantic -Wall -Os ${INCS} ${CPPFLAGS} LDFLAGS = -s ${LIBS} -- 2.20.1 From 96e60c66bc85985fe34cfdcd989abc08fc46a5e2 Mon Sep 17 00:00:00 2001 From: Hiltjo Posthuma Date: Sun, 27 Sep 2015 22:55:21 +0200 Subject: [PATCH 16/16] config.mk: fix _XOPEN_SOURCE=700 for getline() --- config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.mk b/config.mk index 7b08bf1..ea23da4 100644 --- a/config.mk +++ b/config.mk @@ -23,7 +23,7 @@ INCS = -I${X11INC} -I${FREETYPEINC} LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} # flags -CPPFLAGS = -D_BSD_SOURCE -D_XOPEN_SOURCE=500 -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +CPPFLAGS = -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} CFLAGS = -ansi -pedantic -Wall -Os ${INCS} ${CPPFLAGS} LDFLAGS = -s ${LIBS} -- 2.20.1