@ -35,16 +35,16 @@ struct Item {
bool out ;
bool out ;
} ;
} ;
static void appenditem ( Item * item , Item * * list , Item * * last ) ;
static void appenditem ( Item * , Item * * , Item * * ) ;
static void calcoffsets ( void ) ;
static void calcoffsets ( void ) ;
static char * cistrstr ( const char * s , const char * sub ) ;
static char * cistrstr ( const char * , const char * ) ;
static void cleanup ( void ) ;
static void cleanup ( void ) ;
static void drawmenu ( void ) ;
static void drawmenu ( void ) ;
static void grabkeyboard ( void ) ;
static void grabkeyboard ( void ) ;
static void insert ( const char * str , ssize_t n ) ;
static void insert ( const char * , ssize_t ) ;
static void keypress ( XKeyEvent * ev ) ;
static void keypress ( XKeyEvent * ) ;
static void match ( void ) ;
static void match ( void ) ;
static size_t nextrune ( int inc ) ;
static size_t nextrune ( int ) ;
static void paste ( void ) ;
static void paste ( void ) ;
static void readstdin ( void ) ;
static void readstdin ( void ) ;
static void run ( void ) ;
static void run ( void ) ;
@ -53,100 +53,31 @@ static void usage(void);
static char text [ BUFSIZ ] = " " ;
static char text [ BUFSIZ ] = " " ;
static int bh , mw , mh ;
static int bh , mw , mh ;
static int sw , sh ; /* X display screen geometry width, height */
static int inputw , promptw ;
static int inputw , promptw ;
static size_t cursor = 0 ;
static size_t cursor ;
static Atom clip , utf8 ;
static Item * items = NULL ;
static Item * items = NULL ;
static Item * matches , * matchend ;
static Item * matches , * matchend ;
static Item * prev , * curr , * next , * sel ;
static Item * prev , * curr , * next , * sel ;
static Window win ;
static int mon = - 1 , screen ;
static Atom clip , utf8 ;
static Display * dpy ;
static Window root , win ;
static XIC xic ;
static XIC xic ;
static int mon = - 1 ;
static ClrScheme scheme [ SchemeLast ] ;
static ClrScheme scheme [ SchemeLast ] ;
static Display * dpy ;
static int screen ;
static Window root ;
static Drw * drw ;
static Drw * drw ;
static int sw , sh ; /* X display screen geometry width, height */
# include "config.h"
# include "config.h"
static int ( * fstrncmp ) ( const char * , const char * , size_t ) = strncmp ;
static int ( * fstrncmp ) ( const char * , const char * , size_t ) = strncmp ;
static char * ( * fstrstr ) ( const char * , const char * ) = strstr ;
static char * ( * fstrstr ) ( const char * , const char * ) = strstr ;
int
static void
main ( int argc , char * argv [ ] ) {
appenditem ( Item * item , Item * * list , Item * * last )
bool fast = false ;
{
int i ;
if ( * last )
for ( i = 1 ; i < argc ; i + + )
/* these options take no arguments */
if ( ! strcmp ( argv [ i ] , " -v " ) ) { /* prints version information */
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 ;
else if ( ! strcmp ( argv [ i ] , " -f " ) ) /* grabs keyboard before reading stdin */
fast = true ;
else if ( ! strcmp ( argv [ i ] , " -i " ) ) { /* case-insensitive item matching */
fstrncmp = strncasecmp ;
fstrstr = cistrstr ;
}
else if ( i + 1 = = argc )
usage ( ) ;
/* 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 */
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 */
normfgcolor = argv [ + + i ] ;
else if ( ! strcmp ( argv [ i ] , " -sb " ) ) /* selected background color */
selbgcolor = argv [ + + i ] ;
else if ( ! strcmp ( argv [ i ] , " -sf " ) ) /* selected foreground color */
selfgcolor = argv [ + + i ] ;
else
usage ( ) ;
if ( ! setlocale ( LC_CTYPE , " " ) | | ! XSupportsLocale ( ) )
fputs ( " warning: no locale support \n " , stderr ) ;
if ( ! ( dpy = XOpenDisplay ( NULL ) ) )
die ( " dmenu: 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 ( ) ;
readstdin ( ) ;
}
else {
readstdin ( ) ;
grabkeyboard ( ) ;
}
setup ( ) ;
run ( ) ;
return 1 ; /* unreachable */
}
void
appenditem ( Item * item , Item * * list , Item * * last ) {
if ( * last )
( * last ) - > right = item ;
( * last ) - > right = item ;
else
else
* list = item ;
* list = item ;
@ -156,25 +87,27 @@ appenditem(Item *item, Item **list, Item **last) {
* last = item ;
* last = item ;
}
}
void
static void
calcoffsets ( void ) {
calcoffsets ( void )
{
int i , n ;
int i , n ;
if ( lines > 0 )
if ( lines > 0 )
n = lines * bh ;
n = lines * bh ;
else
else
n = mw - ( promptw + inputw + TEXTW ( " < " ) + TEXTW ( " > " ) ) ;
n = mw - ( promptw + inputw + TEXTW ( " < " ) + TEXTW ( " > " ) ) ;
/* calculate which items will begin the next page and previous page */
/* calculate which items will begin the next page and previous page */
for ( i = 0 , next = curr ; next ; next = next - > right )
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 : MIN ( TEXTW ( next - > text ) , n ) ) > n )
break ;
break ;
for ( i = 0 , prev = curr ; prev & & prev - > left ; prev = prev - > left )
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 : MIN ( TEXTW ( prev - > left - > text ) , n ) ) > n )
break ;
break ;
}
}
void
static void
cleanup ( void ) {
cleanup ( void )
{
XUngrabKey ( dpy , AnyKey , AnyModifier , root ) ;
XUngrabKey ( dpy , AnyKey , AnyModifier , root ) ;
drw_clr_free ( scheme [ SchemeNorm ] . bg ) ;
drw_clr_free ( scheme [ SchemeNorm ] . bg ) ;
drw_clr_free ( scheme [ SchemeNorm ] . fg ) ;
drw_clr_free ( scheme [ SchemeNorm ] . fg ) ;
@ -187,18 +120,20 @@ cleanup(void) {
XCloseDisplay ( dpy ) ;
XCloseDisplay ( dpy ) ;
}
}
char *
static char *
cistrstr ( const char * s , const char * sub ) {
cistrstr ( const char * s , const char * sub )
{
size_t len ;
size_t len ;
for ( len = strlen ( sub ) ; * s ; s + + )
for ( len = strlen ( sub ) ; * s ; s + + )
if ( ! strncasecmp ( s , sub , len ) )
if ( ! strncasecmp ( s , sub , len ) )
return ( char * ) s ;
return ( char * ) s ;
return NULL ;
return NULL ;
}
}
void
static void
drawmenu ( void ) {
drawmenu ( void )
{
int curpos ;
int curpos ;
Item * item ;
Item * item ;
int x = 0 , y = 0 , h = bh , w ;
int x = 0 , y = 0 , h = bh , w ;
@ -206,7 +141,7 @@ drawmenu(void) {
drw_setscheme ( drw , & scheme [ SchemeNorm ] ) ;
drw_setscheme ( drw , & scheme [ SchemeNorm ] ) ;
drw_rect ( drw , 0 , 0 , mw , mh , 1 , 1 , 1 ) ;
drw_rect ( drw , 0 , 0 , mw , mh , 1 , 1 , 1 ) ;
if ( prompt & & * prompt ) {
if ( prompt & & * prompt ) {
drw_setscheme ( drw , & scheme [ SchemeSel ] ) ;
drw_setscheme ( drw , & scheme [ SchemeSel ] ) ;
drw_text ( drw , x , 0 , promptw , bh , prompt , 0 ) ;
drw_text ( drw , x , 0 , promptw , bh , prompt , 0 ) ;
x + = promptw ;
x + = promptw ;
@ -216,41 +151,40 @@ drawmenu(void) {
drw_setscheme ( drw , & scheme [ SchemeNorm ] ) ;
drw_setscheme ( drw , & scheme [ SchemeNorm ] ) ;
drw_text ( drw , x , 0 , w , bh , text , 0 ) ;
drw_text ( drw , x , 0 , w , bh , text , 0 ) ;
if ( ( curpos = TEXTNW ( text , cursor ) + bh / 2 - 2 ) < w ) {
if ( ( curpos = TEXTNW ( text , cursor ) + bh / 2 - 2 ) < w ) {
drw_setscheme ( drw , & scheme [ SchemeNorm ] ) ;
drw_setscheme ( drw , & scheme [ SchemeNorm ] ) ;
drw_rect ( drw , x + curpos + 2 , 2 , 1 , bh - 4 , 1 , 1 , 0 ) ;
drw_rect ( drw , x + curpos + 2 , 2 , 1 , bh - 4 , 1 , 1 , 0 ) ;
}
}
if ( lines > 0 ) {
if ( lines > 0 ) {
/* draw vertical list */
/* draw vertical list */
w = mw - x ;
w = mw - x ;
for ( item = curr ; item ! = next ; item = item - > right ) {
for ( item = curr ; item ! = next ; item = item - > right ) {
y + = h ;
y + = h ;
if ( item = = sel )
if ( item = = sel )
drw_setscheme ( drw , & scheme [ SchemeSel ] ) ;
drw_setscheme ( drw , & scheme [ SchemeSel ] ) ;
else if ( item - > out )
else if ( item - > out )
drw_setscheme ( drw , & scheme [ SchemeOut ] ) ;
drw_setscheme ( drw , & scheme [ SchemeOut ] ) ;
else
else
drw_setscheme ( drw , & scheme [ SchemeNorm ] ) ;
drw_setscheme ( drw , & scheme [ SchemeNorm ] ) ;
drw_text ( drw , x , y , w , bh , item - > text , 0 ) ;
drw_text ( drw , x , y , w , bh , item - > text , 0 ) ;
}
}
}
} else if ( matches ) {
else if ( matches ) {
/* draw horizontal list */
/* draw horizontal list */
x + = inputw ;
x + = inputw ;
w = TEXTW ( " < " ) ;
w = TEXTW ( " < " ) ;
if ( curr - > left ) {
if ( curr - > left ) {
drw_setscheme ( drw , & scheme [ SchemeNorm ] ) ;
drw_setscheme ( drw , & scheme [ SchemeNorm ] ) ;
drw_text ( drw , x , 0 , w , bh , " < " , 0 ) ;
drw_text ( drw , x , 0 , w , bh , " < " , 0 ) ;
}
}
for ( item = curr ; item ! = next ; item = item - > right ) {
for ( item = curr ; item ! = next ; item = item - > right ) {
x + = w ;
x + = w ;
w = MIN ( TEXTW ( item - > text ) , mw - x - TEXTW ( " > " ) ) ;
w = MIN ( TEXTW ( item - > text ) , mw - x - TEXTW ( " > " ) ) ;
if ( item = = sel )
if ( item = = sel )
drw_setscheme ( drw , & scheme [ SchemeSel ] ) ;
drw_setscheme ( drw , & scheme [ SchemeSel ] ) ;
else if ( item - > out )
else if ( item - > out )
drw_setscheme ( drw , & scheme [ SchemeOut ] ) ;
drw_setscheme ( drw , & scheme [ SchemeOut ] ) ;
else
else
drw_setscheme ( drw , & scheme [ SchemeNorm ] ) ;
drw_setscheme ( drw , & scheme [ SchemeNorm ] ) ;
@ -258,7 +192,7 @@ drawmenu(void) {
}
}
w = TEXTW ( " > " ) ;
w = TEXTW ( " > " ) ;
x = mw - w ;
x = mw - w ;
if ( next ) {
if ( next ) {
drw_setscheme ( drw , & scheme [ SchemeNorm ] ) ;
drw_setscheme ( drw , & scheme [ SchemeNorm ] ) ;
drw_text ( drw , x , 0 , w , bh , " > " , 0 ) ;
drw_text ( drw , x , 0 , w , bh , " > " , 0 ) ;
}
}
@ -266,13 +200,14 @@ drawmenu(void) {
drw_map ( drw , win , 0 , 0 , mw , mh ) ;
drw_map ( drw , win , 0 , 0 , mw , mh ) ;
}
}
void
static void
grabkeyboard ( void ) {
grabkeyboard ( void )
{
int i ;
int i ;
/* try to grab keyboard, we may have to wait for another process to ungrab */
/* try to grab keyboard, we may have to wait for another process to ungrab */
for ( i = 0 ; i < 1000 ; i + + ) {
for ( i = 0 ; i < 1000 ; i + + ) {
if ( XGrabKeyboard ( dpy , DefaultRootWindow ( dpy ) , True ,
if ( XGrabKeyboard ( dpy , DefaultRootWindow ( dpy ) , True ,
GrabModeAsync , GrabModeAsync , CurrentTime ) = = GrabSuccess )
GrabModeAsync , GrabModeAsync , CurrentTime ) = = GrabSuccess )
return ;
return ;
usleep ( 1000 ) ;
usleep ( 1000 ) ;
@ -280,29 +215,31 @@ grabkeyboard(void) {
die ( " cannot grab keyboard \n " ) ;
die ( " cannot grab keyboard \n " ) ;
}
}
void
static void
insert ( const char * str , ssize_t n ) {
insert ( const char * str , ssize_t n )
if ( strlen ( text ) + n > sizeof text - 1 )
{
if ( strlen ( text ) + n > sizeof text - 1 )
return ;
return ;
/* move existing text out of the way, insert new text, and update cursor */
/* move existing text out of the way, insert new text, and update cursor */
memmove ( & text [ cursor + n ] , & text [ cursor ] , sizeof text - cursor - MAX ( n , 0 ) ) ;
memmove ( & text [ cursor + n ] , & text [ cursor ] , sizeof text - cursor - MAX ( n , 0 ) ) ;
if ( n > 0 )
if ( n > 0 )
memcpy ( & text [ cursor ] , str , n ) ;
memcpy ( & text [ cursor ] , str , n ) ;
cursor + = n ;
cursor + = n ;
match ( ) ;
match ( ) ;
}
}
void
static void
keypress ( XKeyEvent * ev ) {
keypress ( XKeyEvent * ev )
{
char buf [ 32 ] ;
char buf [ 32 ] ;
int len ;
int len ;
KeySym ksym = NoSymbol ;
KeySym ksym = NoSymbol ;
Status status ;
Status status ;
len = XmbLookupString ( xic , ev , buf , sizeof buf , & ksym , & status ) ;
len = XmbLookupString ( xic , ev , buf , sizeof buf , & ksym , & status ) ;
if ( status = = XBufferOverflow )
if ( status = = XBufferOverflow )
return ;
return ;
if ( ev - > state & ControlMask )
if ( ev - > state & ControlMask )
switch ( ksym ) {
switch ( ksym ) {
case XK_a : ksym = XK_Home ; break ;
case XK_a : ksym = XK_Home ; break ;
case XK_b : ksym = XK_Left ; break ;
case XK_b : ksym = XK_Left ; break ;
@ -328,9 +265,9 @@ keypress(XKeyEvent *ev) {
insert ( NULL , 0 - cursor ) ;
insert ( NULL , 0 - cursor ) ;
break ;
break ;
case XK_w : /* delete word */
case XK_w : /* delete word */
while ( cursor > 0 & & text [ nextrune ( - 1 ) ] = = ' ' )
while ( cursor > 0 & & text [ nextrune ( - 1 ) ] = = ' ' )
insert ( NULL , nextrune ( - 1 ) - cursor ) ;
insert ( NULL , nextrune ( - 1 ) - cursor ) ;
while ( cursor > 0 & & text [ nextrune ( - 1 ) ] ! = ' ' )
while ( cursor > 0 & & text [ nextrune ( - 1 ) ] ! = ' ' )
insert ( NULL , nextrune ( - 1 ) - cursor ) ;
insert ( NULL , nextrune ( - 1 ) - cursor ) ;
break ;
break ;
case XK_y : /* paste selection */
case XK_y : /* paste selection */
@ -346,7 +283,7 @@ keypress(XKeyEvent *ev) {
default :
default :
return ;
return ;
}
}
else if ( ev - > state & Mod1Mask )
else if ( ev - > state & Mod1Mask )
switch ( ksym ) {
switch ( ksym ) {
case XK_g : ksym = XK_Home ; break ;
case XK_g : ksym = XK_Home ; break ;
case XK_G : ksym = XK_End ; break ;
case XK_G : ksym = XK_End ; break ;
@ -359,31 +296,31 @@ keypress(XKeyEvent *ev) {
}
}
switch ( ksym ) {
switch ( ksym ) {
default :
default :
if ( ! iscntrl ( * buf ) )
if ( ! iscntrl ( * buf ) )
insert ( buf , len ) ;
insert ( buf , len ) ;
break ;
break ;
case XK_Delete :
case XK_Delete :
if ( text [ cursor ] = = ' \0 ' )
if ( text [ cursor ] = = ' \0 ' )
return ;
return ;
cursor = nextrune ( + 1 ) ;
cursor = nextrune ( + 1 ) ;
/* fallthrough */
/* fallthrough */
case XK_BackSpace :
case XK_BackSpace :
if ( cursor = = 0 )
if ( cursor = = 0 )
return ;
return ;
insert ( NULL , nextrune ( - 1 ) - cursor ) ;
insert ( NULL , nextrune ( - 1 ) - cursor ) ;
break ;
break ;
case XK_End :
case XK_End :
if ( text [ cursor ] ! = ' \0 ' ) {
if ( text [ cursor ] ! = ' \0 ' ) {
cursor = strlen ( text ) ;
cursor = strlen ( text ) ;
break ;
break ;
}
}
if ( next ) {
if ( next ) {
/* jump to end of list and position items in reverse */
/* jump to end of list and position items in reverse */
curr = matchend ;
curr = matchend ;
calcoffsets ( ) ;
calcoffsets ( ) ;
curr = prev ;
curr = prev ;
calcoffsets ( ) ;
calcoffsets ( ) ;
while ( next & & ( curr = curr - > right ) )
while ( next & & ( curr = curr - > right ) )
calcoffsets ( ) ;
calcoffsets ( ) ;
}
}
sel = matchend ;
sel = matchend ;
@ -392,7 +329,7 @@ keypress(XKeyEvent *ev) {
cleanup ( ) ;
cleanup ( ) ;
exit ( 1 ) ;
exit ( 1 ) ;
case XK_Home :
case XK_Home :
if ( sel = = matches ) {
if ( sel = = matches ) {
cursor = 0 ;
cursor = 0 ;
break ;
break ;
}
}
@ -400,27 +337,27 @@ keypress(XKeyEvent *ev) {
calcoffsets ( ) ;
calcoffsets ( ) ;
break ;
break ;
case XK_Left :
case XK_Left :
if ( cursor > 0 & & ( ! sel | | ! sel - > left | | lines > 0 ) ) {
if ( cursor > 0 & & ( ! sel | | ! sel - > left | | lines > 0 ) ) {
cursor = nextrune ( - 1 ) ;
cursor = nextrune ( - 1 ) ;
break ;
break ;
}
}
if ( lines > 0 )
if ( lines > 0 )
return ;
return ;
/* fallthrough */
/* fallthrough */
case XK_Up :
case XK_Up :
if ( sel & & sel - > left & & ( sel = sel - > left ) - > right = = curr ) {
if ( sel & & sel - > left & & ( sel = sel - > left ) - > right = = curr ) {
curr = prev ;
curr = prev ;
calcoffsets ( ) ;
calcoffsets ( ) ;
}
}
break ;
break ;
case XK_Next :
case XK_Next :
if ( ! next )
if ( ! next )
return ;
return ;
sel = curr = next ;
sel = curr = next ;
calcoffsets ( ) ;
calcoffsets ( ) ;
break ;
break ;
case XK_Prior :
case XK_Prior :
if ( ! prev )
if ( ! prev )
return ;
return ;
sel = curr = prev ;
sel = curr = prev ;
calcoffsets ( ) ;
calcoffsets ( ) ;
@ -428,29 +365,29 @@ keypress(XKeyEvent *ev) {
case XK_Return :
case XK_Return :
case XK_KP_Enter :
case XK_KP_Enter :
puts ( ( sel & & ! ( ev - > state & ShiftMask ) ) ? sel - > text : text ) ;
puts ( ( sel & & ! ( ev - > state & ShiftMask ) ) ? sel - > text : text ) ;
if ( ! ( ev - > state & ControlMask ) ) {
if ( ! ( ev - > state & ControlMask ) ) {
cleanup ( ) ;
cleanup ( ) ;
exit ( 0 ) ;
exit ( 0 ) ;
}
}
if ( sel )
if ( sel )
sel - > out = true ;
sel - > out = true ;
break ;
break ;
case XK_Right :
case XK_Right :
if ( text [ cursor ] ! = ' \0 ' ) {
if ( text [ cursor ] ! = ' \0 ' ) {
cursor = nextrune ( + 1 ) ;
cursor = nextrune ( + 1 ) ;
break ;
break ;
}
}
if ( lines > 0 )
if ( lines > 0 )
return ;
return ;
/* fallthrough */
/* fallthrough */
case XK_Down :
case XK_Down :
if ( sel & & sel - > right & & ( sel = sel - > right ) = = next ) {
if ( sel & & sel - > right & & ( sel = sel - > right ) = = next ) {
curr = next ;
curr = next ;
calcoffsets ( ) ;
calcoffsets ( ) ;
}
}
break ;
break ;
case XK_Tab :
case XK_Tab :
if ( ! sel )
if ( ! sel )
return ;
return ;
strncpy ( text , sel - > text , sizeof text - 1 ) ;
strncpy ( text , sel - > text , sizeof text - 1 ) ;
text [ sizeof text - 1 ] = ' \0 ' ;
text [ sizeof text - 1 ] = ' \0 ' ;
@ -461,8 +398,9 @@ keypress(XKeyEvent *ev) {
drawmenu ( ) ;
drawmenu ( ) ;
}
}
void
static void
match ( void ) {
match ( void )
{
static char * * tokv = NULL ;
static char * * tokv = NULL ;
static int tokn = 0 ;
static int tokn = 0 ;
@ -473,41 +411,39 @@ match(void) {
strcpy ( buf , text ) ;
strcpy ( buf , text ) ;
/* separate input text into tokens to be matched individually */
/* separate input text into tokens to be matched individually */
for ( s = strtok ( buf , " " ) ; s ; tokv [ tokc - 1 ] = s , s = strtok ( NULL , " " ) )
for ( s = strtok ( buf , " " ) ; s ; tokv [ tokc - 1 ] = s , s = strtok ( NULL , " " ) )
if ( + + tokc > tokn & & ! ( tokv = realloc ( tokv , + + tokn * sizeof * tokv ) ) )
if ( + + tokc > tokn & & ! ( tokv = realloc ( tokv , + + tokn * sizeof * tokv ) ) )
die ( " cannot realloc %u bytes \n " , tokn * sizeof * tokv ) ;
die ( " cannot realloc %u bytes \n " , tokn * sizeof * tokv ) ;
len = tokc ? strlen ( tokv [ 0 ] ) : 0 ;
len = tokc ? strlen ( tokv [ 0 ] ) : 0 ;
matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL ;
matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL ;
for ( item = items ; item & & item - > text ; item + + ) {
for ( item = items ; item & & item - > text ; item + + ) {
for ( i = 0 ; i < tokc ; i + + )
for ( i = 0 ; i < tokc ; i + + )
if ( ! fstrstr ( item - > text , tokv [ i ] ) )
if ( ! fstrstr ( item - > text , tokv [ i ] ) )
break ;
break ;
if ( i ! = tokc ) /* not all tokens match */
if ( i ! = tokc ) /* not all tokens match */
continue ;
continue ;
/* exact matches go first, then prefixes, then substrings */
/* exact matches go first, then prefixes, then substrings */
if ( ! tokc | | ! fstrncmp ( tokv [ 0 ] , item - > text , len + 1 ) )
if ( ! tokc | | ! fstrncmp ( tokv [ 0 ] , item - > text , len + 1 ) )
appenditem ( item , & matches , & matchend ) ;
appenditem ( item , & matches , & matchend ) ;
else if ( ! fstrncmp ( tokv [ 0 ] , item - > text , len ) )
else if ( ! fstrncmp ( tokv [ 0 ] , item - > text , len ) )
appenditem ( item , & lprefix , & prefixend ) ;
appenditem ( item , & lprefix , & prefixend ) ;
else
else
appenditem ( item , & lsubstr , & substrend ) ;
appenditem ( item , & lsubstr , & substrend ) ;
}
}
if ( lprefix ) {
if ( lprefix ) {
if ( matches ) {
if ( matches ) {
matchend - > right = lprefix ;
matchend - > right = lprefix ;
lprefix - > left = matchend ;
lprefix - > left = matchend ;
}
} else
else
matches = lprefix ;
matches = lprefix ;
matchend = prefixend ;
matchend = prefixend ;
}
}
if ( lsubstr ) {
if ( lsubstr ) {
if ( matches ) {
if ( matches ) {
matchend - > right = lsubstr ;
matchend - > right = lsubstr ;
lsubstr - > left = matchend ;
lsubstr - > left = matchend ;
}
} else
else
matches = lsubstr ;
matches = lsubstr ;
matchend = substrend ;
matchend = substrend ;
}
}
@ -515,17 +451,20 @@ match(void) {
calcoffsets ( ) ;
calcoffsets ( ) ;
}
}
size_t
static size_t
nextrune ( int inc ) {
nextrune ( int inc )
{
ssize_t n ;
ssize_t n ;
/* return location of next utf8 rune in the given direction (+1 or -1) */
/* return location of next utf8 rune in the given direction (+1 or -1) */
for ( n = cursor + inc ; n + inc > = 0 & & ( text [ n ] & 0xc0 ) = = 0x80 ; n + = inc ) ;
for ( n = cursor + inc ; n + inc > = 0 & & ( text [ n ] & 0xc0 ) = = 0x80 ; n + = inc )
;
return n ;
return n ;
}
}
void
static void
paste ( void ) {
paste ( void )
{
char * p , * q ;
char * p , * q ;
int di ;
int di ;
unsigned long dl ;
unsigned long dl ;
@ -534,64 +473,67 @@ paste(void) {
/* we have been given the current selection, now insert it into input */
/* we have been given the current selection, now insert it into input */
XGetWindowProperty ( 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 ) ;
utf8 , & da , & di , & dl , & dl , ( unsigned char * * ) & p ) ;
insert ( p , ( q = strchr ( p , ' \n ' ) ) ? q - p : ( ssize_t ) strlen ( p ) ) ;
insert ( p , ( q = strchr ( p , ' \n ' ) ) ? q - p : ( ssize_t ) strlen ( p ) ) ;
XFree ( p ) ;
XFree ( p ) ;
drawmenu ( ) ;
drawmenu ( ) ;
}
}
void
static void
readstdin ( void ) {
readstdin ( void )
{
char buf [ sizeof text ] , * p , * maxstr = NULL ;
char buf [ sizeof text ] , * p , * maxstr = NULL ;
size_t i , max = 0 , size = 0 ;
size_t i , max = 0 , size = 0 ;
/* read each line from stdin and add it to the item list */
/* read each line from stdin and add it to the item list */
for ( i = 0 ; fgets ( buf , sizeof buf , stdin ) ; i + + ) {
for ( i = 0 ; fgets ( buf , sizeof buf , stdin ) ; i + + ) {
if ( i + 1 > = size / sizeof * items )
if ( i + 1 > = size / sizeof * items )
if ( ! ( items = realloc ( items , ( size + = BUFSIZ ) ) ) )
if ( ! ( items = realloc ( items , ( size + = BUFSIZ ) ) ) )
die ( " cannot realloc %u bytes: " , size ) ;
die ( " cannot realloc %u bytes: " , size ) ;
if ( ( p = strchr ( buf , ' \n ' ) ) )
if ( ( p = strchr ( buf , ' \n ' ) ) )
* p = ' \0 ' ;
* p = ' \0 ' ;
if ( ! ( items [ i ] . text = strdup ( buf ) ) )
if ( ! ( items [ i ] . text = strdup ( buf ) ) )
die ( " cannot strdup %u bytes: " , strlen ( buf ) + 1 ) ;
die ( " cannot strdup %u bytes: " , strlen ( buf ) + 1 ) ;
items [ i ] . out = false ;
items [ i ] . out = false ;
if ( strlen ( items [ i ] . text ) > max )
if ( strlen ( items [ i ] . text ) > max )
max = strlen ( maxstr = items [ i ] . text ) ;
max = strlen ( maxstr = items [ i ] . text ) ;
}
}
if ( items )
if ( items )
items [ i ] . text = NULL ;
items [ i ] . text = NULL ;
inputw = maxstr ? TEXTW ( maxstr ) : 0 ;
inputw = maxstr ? TEXTW ( maxstr ) : 0 ;
lines = MIN ( lines , i ) ;
lines = MIN ( lines , i ) ;
}
}
void
static void
run ( void ) {
run ( void )
{
XEvent ev ;
XEvent ev ;
while ( ! XNextEvent ( dpy , & ev ) ) {
while ( ! XNextEvent ( dpy , & ev ) ) {
if ( XFilterEvent ( & ev , win ) )
if ( XFilterEvent ( & ev , win ) )
continue ;
continue ;
switch ( ev . type ) {
switch ( ev . type ) {
case Expose :
case Expose :
if ( ev . xexpose . count = = 0 )
if ( ev . xexpose . count = = 0 )
drw_map ( drw , win , 0 , 0 , mw , mh ) ;
drw_map ( drw , win , 0 , 0 , mw , mh ) ;
break ;
break ;
case KeyPress :
case KeyPress :
keypress ( & ev . xkey ) ;
keypress ( & ev . xkey ) ;
break ;
break ;
case SelectionNotify :
case SelectionNotify :
if ( ev . xselection . property = = utf8 )
if ( ev . xselection . property = = utf8 )
paste ( ) ;
paste ( ) ;
break ;
break ;
case VisibilityNotify :
case VisibilityNotify :
if ( ev . xvisibility . state ! = VisibilityUnobscured )
if ( ev . xvisibility . state ! = VisibilityUnobscured )
XRaiseWindow ( dpy , win ) ;
XRaiseWindow ( dpy , win ) ;
break ;
break ;
}
}
}
}
}
}
void
static void
setup ( void ) {
setup ( void )
{
int x , y ;
int x , y ;
XSetWindowAttributes swa ;
XSetWindowAttributes swa ;
XIM xim ;
XIM xim ;
@ -619,36 +561,35 @@ setup(void) {
lines = MAX ( lines , 0 ) ;
lines = MAX ( lines , 0 ) ;
mh = ( lines + 1 ) * bh ;
mh = ( lines + 1 ) * bh ;
# ifdef XINERAMA
# ifdef XINERAMA
if ( ( info = XineramaQueryScreens ( dpy , & n ) ) ) {
if ( ( info = XineramaQueryScreens ( dpy , & n ) ) ) {
XGetInputFocus ( dpy , & w , & di ) ;
XGetInputFocus ( dpy , & w , & di ) ;
if ( mon ! = - 1 & & mon < n )
if ( mon ! = - 1 & & mon < n )
i = mon ;
i = mon ;
if ( ! i & & w ! = root & & w ! = PointerRoot & & w ! = None ) {
if ( ! i & & w ! = root & & w ! = PointerRoot & & w ! = None ) {
/* find top-level window containing current input focus */
/* find top-level window containing current input focus */
do {
do {
if ( XQueryTree ( dpy , ( pw = w ) , & dw , & w , & dws , & du ) & & dws )
if ( XQueryTree ( dpy , ( pw = w ) , & dw , & w , & dws , & du ) & & dws )
XFree ( dws ) ;
XFree ( dws ) ;
} while ( w ! = root & & w ! = pw ) ;
} while ( w ! = root & & w ! = pw ) ;
/* find xinerama screen with which the window intersects most */
/* find xinerama screen with which the window intersects most */
if ( XGetWindowAttributes ( dpy , pw , & wa ) )
if ( XGetWindowAttributes ( dpy , pw , & wa ) )
for ( j = 0 ; j < n ; j + + )
for ( j = 0 ; j < n ; j + + )
if ( ( a = INTERSECT ( wa . x , wa . y , wa . width , wa . height , info [ j ] ) ) > area ) {
if ( ( a = INTERSECT ( wa . x , wa . y , wa . width , wa . height , info [ j ] ) ) > area ) {
area = a ;
area = a ;
i = j ;
i = j ;
}
}
}
}
/* no focused window is on screen, so use pointer location instead */
/* no focused window is on screen, so use pointer location instead */
if ( mon = = - 1 & & ! area & & XQueryPointer ( 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 + + )
for ( i = 0 ; i < n ; i + + )
if ( INTERSECT ( x , y , 1 , 1 , info [ i ] ) )
if ( INTERSECT ( x , y , 1 , 1 , info [ i ] ) )
break ;
break ;
x = info [ i ] . x_org ;
x = info [ i ] . x_org ;
y = info [ i ] . y_org + ( topbar ? 0 : info [ i ] . height - mh ) ;
y = info [ i ] . y_org + ( topbar ? 0 : info [ i ] . height - mh ) ;
mw = info [ i ] . width ;
mw = info [ i ] . width ;
XFree ( info ) ;
XFree ( info ) ;
}
} else
else
# endif
# endif
{
{
x = 0 ;
x = 0 ;
@ -678,9 +619,77 @@ setup(void) {
drawmenu ( ) ;
drawmenu ( ) ;
}
}
void
static void
usage ( void ) {
usage ( void )
{
fputs ( " usage: dmenu [-b] [-f] [-i] [-l lines] [-p prompt] [-fn font] [-m monitor] \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 ) ;
" [-nb color] [-nf color] [-sb color] [-sf color] [-v] \n " , stderr ) ;
exit ( 1 ) ;
exit ( 1 ) ;
}
}
int
main ( int argc , char * argv [ ] )
{
bool fast = false ;
int i ;
for ( i = 1 ; i < argc ; i + + )
/* these options take no arguments */
if ( ! strcmp ( argv [ i ] , " -v " ) ) { /* prints version information */
puts ( " dmenu- " VERSION ) ;
exit ( 0 ) ;
} else if ( ! strcmp ( argv [ i ] , " -b " ) ) /* appears at the bottom of the screen */
topbar = false ;
else if ( ! strcmp ( argv [ i ] , " -f " ) ) /* grabs keyboard before reading stdin */
fast = true ;
else if ( ! strcmp ( argv [ i ] , " -i " ) ) { /* case-insensitive item matching */
fstrncmp = strncasecmp ;
fstrstr = cistrstr ;
} else if ( i + 1 = = argc )
usage ( ) ;
/* 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 */
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 */
normfgcolor = argv [ + + i ] ;
else if ( ! strcmp ( argv [ i ] , " -sb " ) ) /* selected background color */
selbgcolor = argv [ + + i ] ;
else if ( ! strcmp ( argv [ i ] , " -sf " ) ) /* selected foreground color */
selfgcolor = argv [ + + i ] ;
else
usage ( ) ;
if ( ! setlocale ( LC_CTYPE , " " ) | | ! XSupportsLocale ( ) )
fputs ( " warning: no locale support \n " , stderr ) ;
if ( ! ( dpy = XOpenDisplay ( NULL ) ) )
die ( " 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 ( ) ;
readstdin ( ) ;
} else {
readstdin ( ) ;
grabkeyboard ( ) ;
}
setup ( ) ;
run ( ) ;
return 1 ; /* unreachable */
}