fixed bugs, no more config.h, updated manpage, new libdraw
a7aee433
7 file(s) · +162 −220
| 3 | 3 | ||
| 4 | 4 | include config.mk |
|
| 5 | 5 | ||
| 6 | - | SRC = dmenu.c |
|
| 7 | - | OBJ = ${SRC:.c=.o} |
|
| 8 | - | ||
| 9 | 6 | all: options dmenu |
|
| 10 | 7 | ||
| 11 | 8 | options: |
|
| 14 | 11 | @echo "LDFLAGS = ${LDFLAGS}" |
|
| 15 | 12 | @echo "CC = ${CC}" |
|
| 16 | 13 | ||
| 17 | - | .c.o: |
|
| 14 | + | dmenu.o: dmenu.c config.mk |
|
| 18 | 15 | @echo CC $< |
|
| 19 | 16 | @${CC} -c ${CFLAGS} $< |
|
| 20 | 17 | ||
| 21 | - | ${OBJ}: config.h config.mk |
|
| 22 | - | ||
| 23 | - | config.h: |
|
| 24 | - | @echo creating $@ from config.def.h |
|
| 25 | - | @cp config.def.h $@ |
|
| 26 | - | ||
| 27 | - | dmenu: ${OBJ} |
|
| 18 | + | dmenu: dmenu.o |
|
| 28 | 19 | @echo CC -o $@ |
|
| 29 | 20 | @${CC} -o $@ $+ ${LDFLAGS} |
|
| 30 | 21 | ||
| 31 | 22 | clean: |
|
| 32 | 23 | @echo cleaning |
|
| 33 | - | @rm -f dmenu ${OBJ} dmenu-${VERSION}.tar.gz |
|
| 24 | + | @rm -f dmenu dmenu.o dmenu-${VERSION}.tar.gz |
|
| 34 | 25 | ||
| 35 | 26 | dist: clean |
|
| 36 | 27 | @echo creating dist tarball |
|
| 37 | 28 | @mkdir -p dmenu-${VERSION} |
|
| 38 | - | @cp -R LICENSE Makefile README config.mk dmenu.1 config.def.h dmenu_path dmenu_run ${SRC} dmenu-${VERSION} |
|
| 29 | + | @cp -R LICENSE Makefile README config.mk dmenu.1 dmenu.c dmenu_path dmenu_run dmenu-${VERSION} |
|
| 39 | 30 | @tar -cf dmenu-${VERSION}.tar dmenu-${VERSION} |
|
| 40 | 31 | @gzip dmenu-${VERSION}.tar |
|
| 41 | 32 | @rm -rf dmenu-${VERSION} |
|
| 42 | 33 | ||
| 43 | 34 | install: all |
|
| 44 | - | @echo installing executable file to ${DESTDIR}${PREFIX}/bin |
|
| 35 | + | @echo installing executables to ${DESTDIR}${PREFIX}/bin |
|
| 45 | 36 | @mkdir -p ${DESTDIR}${PREFIX}/bin |
|
| 46 | 37 | @cp -f dmenu dmenu_path dmenu_run ${DESTDIR}${PREFIX}/bin |
|
| 47 | 38 | @chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu |
|
| 53 | 44 | @chmod 644 ${DESTDIR}${MANPREFIX}/man1/dmenu.1 |
|
| 54 | 45 | ||
| 55 | 46 | uninstall: |
|
| 56 | - | @echo removing executable file from ${DESTDIR}${PREFIX}/bin |
|
| 57 | - | @rm -f ${DESTDIR}${PREFIX}/bin/dmenu ${DESTDIR}${PREFIX}/bin/dmenu_path |
|
| 47 | + | @echo removing executables from ${DESTDIR}${PREFIX}/bin |
|
| 48 | + | @rm -f ${DESTDIR}${PREFIX}/bin/dmenu |
|
| 49 | + | @rm -f ${DESTDIR}${PREFIX}/bin/dmenu_path |
|
| 58 | 50 | @rm -f ${DESTDIR}${PREFIX}/bin/dmenu_run |
|
| 59 | 51 | @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1 |
|
| 60 | 52 | @rm -f ${DESTDIR}${MANPREFIX}/man1/dmenu.1 |
|
| 1 | 1 | dmenu - dynamic menu |
|
| 2 | 2 | ==================== |
|
| 3 | - | dmenu is a generic and efficient menu for X. |
|
| 3 | + | dmenu is an efficient dynamic menu for X. |
|
| 4 | 4 | ||
| 5 | 5 | ||
| 6 | 6 | Requirements |
|
| 7 | 7 | ------------ |
|
| 8 | 8 | In order to build dmenu you need the Xlib header files. |
|
| 9 | + | ||
| 9 | 10 | You also need libdraw, available from http://hg.suckless.org/libdraw |
|
| 10 | 11 | ||
| 11 | 12 | ||
| 12 | 13 | Installation |
|
| 13 | 14 | ------------ |
|
| 14 | - | Edit config.mk to match your local setup (dmenu is installed into the |
|
| 15 | - | /usr/local namespace by default). |
|
| 15 | + | Edit config.mk to match your local setup (dmenu is installed into |
|
| 16 | + | the /usr/local namespace by default). |
|
| 16 | 17 | ||
| 17 | - | Afterwards enter the following command to build and install dmenu (if |
|
| 18 | - | necessary as root): |
|
| 18 | + | Afterwards enter the following command to build and install dmenu |
|
| 19 | + | (if necessary as root): |
|
| 19 | 20 | ||
| 20 | 21 | make clean install |
|
| 21 | 22 |
| 1 | - | /* See LICENSE file for copyright and license details. */ |
|
| 2 | - | ||
| 3 | - | /* appearance */ |
|
| 4 | - | static const char *font = "-*-terminus-medium-r-normal-*-14-*-*-*-*-*-*-*"; |
|
| 5 | - | static const char *normbgcolor = "#cccccc"; |
|
| 6 | - | static const char *normfgcolor = "#000000"; |
|
| 7 | - | static const char *selbgcolor = "#0066ff"; |
|
| 8 | - | static const char *selfgcolor = "#ffffff"; |
| 1 | 1 | # dmenu version |
|
| 2 | - | VERSION = 4.1.1 |
|
| 2 | + | VERSION = 4.2 |
|
| 3 | 3 | ||
| 4 | 4 | # Customize below to fit your system |
|
| 5 | 5 | ||
| 7 | 7 | PREFIX = /usr/local |
|
| 8 | 8 | MANPREFIX = ${PREFIX}/share/man |
|
| 9 | 9 | ||
| 10 | + | # Xlib |
|
| 10 | 11 | X11INC = /usr/X11R6/include |
|
| 11 | 12 | X11LIB = /usr/X11R6/lib |
|
| 12 | 13 | ||
| 13 | 14 | # Xinerama, comment if you don't want it |
|
| 14 | - | XINERAMALIBS = -L${X11LIB} -lXinerama |
|
| 15 | + | XINERAMALIBS = -lXinerama |
|
| 15 | 16 | XINERAMAFLAGS = -DXINERAMA |
|
| 16 | 17 | ||
| 17 | 18 | # includes and libs |
|
| 18 | - | INCS = -I. -I/usr/include -I${X11INC} |
|
| 19 | - | LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -ldraw ${XINERAMALIBS} |
|
| 19 | + | INCS = -I${X11INC} |
|
| 20 | + | LIBS = -L${X11LIB} -ldraw -lX11 ${XINERAMALIBS} |
|
| 20 | 21 | ||
| 21 | 22 | # flags |
|
| 22 | 23 | CPPFLAGS = -D_BSD_SOURCE -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} |
|
| 23 | - | CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} |
|
| 24 | - | LDFLAGS = -s ${LIBS} |
|
| 25 | - | ||
| 26 | - | # Solaris |
|
| 27 | - | #CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\" |
|
| 28 | - | #LDFLAGS = ${LIBS} |
|
| 24 | + | CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} |
|
| 25 | + | LDFLAGS = -s ${LIBS} |
|
| 29 | 26 | ||
| 30 | 27 | # compiler and linker |
|
| 31 | 28 | CC = cc |
|
| 5 | 5 | .B dmenu |
|
| 6 | 6 | .RB [ \-b ] |
|
| 7 | 7 | .RB [ \-i ] |
|
| 8 | - | .RB [ \-l " <lines>]" |
|
| 9 | - | .RB [ \-p " <prompt>]" |
|
| 10 | - | .RB [ \-fn " <font>]" |
|
| 11 | - | .RB [ \-nb " <color>]" |
|
| 12 | - | .RB [ \-nf " <color>]" |
|
| 13 | - | .RB [ \-sb " <color>]" |
|
| 14 | - | .RB [ \-sf " <color>]" |
|
| 8 | + | .RB [ \-l |
|
| 9 | + | .IR lines ] |
|
| 10 | + | .RB [ \-p |
|
| 11 | + | .IR prompt ] |
|
| 12 | + | .RB [ \-fn |
|
| 13 | + | .IR font ] |
|
| 14 | + | .RB [ \-nb |
|
| 15 | + | .IR color ] |
|
| 16 | + | .RB [ \-nf |
|
| 17 | + | .IR color ] |
|
| 18 | + | .RB [ \-sb |
|
| 19 | + | .IR color ] |
|
| 20 | + | .RB [ \-sf |
|
| 21 | + | .IR color ] |
|
| 15 | 22 | .RB [ \-v ] |
|
| 16 | - | ||
| 17 | - | .B dmenu_run |
|
| 18 | - | .RB [ \-b ] |
|
| 19 | - | .RB [ \-i ] |
|
| 20 | - | .RB [ \-l " <lines>]" |
|
| 21 | - | .RB [ \-p " <prompt>]" |
|
| 22 | - | .RB [ \-fn " <font>]" |
|
| 23 | - | .RB [ \-nb " <color>]" |
|
| 24 | - | .RB [ \-nf " <color>]" |
|
| 25 | - | .RB [ \-sb " <color>]" |
|
| 26 | - | .RB [ \-sf " <color>]" |
|
| 27 | - | .RB [ \-v ] |
|
| 28 | - | ||
| 23 | + | .P |
|
| 24 | + | .BR dmenu_run " ..." |
|
| 25 | + | .P |
|
| 29 | 26 | .B dmenu_path |
|
| 30 | 27 | .SH DESCRIPTION |
|
| 31 | - | .SS Overview |
|
| 32 | 28 | .B dmenu |
|
| 33 | - | is a generic menu for X, originally designed for |
|
| 29 | + | is a dynamic menu for X, originally designed for |
|
| 34 | 30 | .BR dwm (1). |
|
| 35 | - | It manages huge amounts (10000 and more) of user defined menu items efficiently. |
|
| 31 | + | It manages huge numbers of user-defined menu items efficiently. |
|
| 32 | + | .P |
|
| 33 | + | dmenu reads a list of newline-separated items from standard input and creates a |
|
| 34 | + | menu. When the user selects an item or enters any text and presses Return, |
|
| 35 | + | their choice is printed to standard output and dmenu terminates. |
|
| 36 | 36 | .P |
|
| 37 | 37 | .B dmenu_run |
|
| 38 | - | is a dmenu script which lists programs in the user's PATH and executes |
|
| 39 | - | the selected item. |
|
| 38 | + | is a dmenu script used by dwm which lists programs in the user's PATH and |
|
| 39 | + | executes the selected item. |
|
| 40 | 40 | .P |
|
| 41 | 41 | .B dmenu_path |
|
| 42 | - | is a script used by |
|
| 43 | - | .I dmenu_run |
|
| 44 | - | to find and cache a list of programs. |
|
| 45 | - | .SS Options |
|
| 42 | + | is a script used by dmenu_run to find and cache a list of programs. |
|
| 43 | + | .SH OPTIONS |
|
| 46 | 44 | .TP |
|
| 47 | 45 | .B \-b |
|
| 48 | 46 | dmenu appears at the bottom of the screen. |
|
| 49 | 47 | .TP |
|
| 50 | 48 | .B \-i |
|
| 51 | - | dmenu matches menu entries case insensitively. |
|
| 49 | + | dmenu matches menu items case insensitively. |
|
| 52 | 50 | .TP |
|
| 53 | - | .B \-l <lines> |
|
| 51 | + | .BI \-l " lines" |
|
| 54 | 52 | dmenu lists items vertically, with the given number of lines. |
|
| 55 | 53 | .TP |
|
| 56 | - | .B \-p <prompt> |
|
| 57 | - | sets the prompt to be displayed to the left of the input area. |
|
| 54 | + | .BI \-p " prompt" |
|
| 55 | + | defines the prompt to be displayed to the left of the input area. |
|
| 58 | 56 | .TP |
|
| 59 | - | .B \-fn <font> |
|
| 60 | - | sets the font. |
|
| 57 | + | .BI \-fn " font" |
|
| 58 | + | defines the font set used. |
|
| 61 | 59 | .TP |
|
| 62 | - | .B \-nb <color> |
|
| 63 | - | sets the background color (#RGB, #RRGGBB, and color names are supported). |
|
| 60 | + | .BI \-nb " color" |
|
| 61 | + | defines the normal background color. |
|
| 62 | + | .IR #RGB , |
|
| 63 | + | .IR #RRGGBB , |
|
| 64 | + | and color names are supported. |
|
| 64 | 65 | .TP |
|
| 65 | - | .B \-nf <color> |
|
| 66 | - | sets the foreground color (#RGB, #RRGGBB, and color names are supported). |
|
| 66 | + | .BI \-nf " color" |
|
| 67 | + | defines the normal foreground color. |
|
| 67 | 68 | .TP |
|
| 68 | - | .B \-sb <color> |
|
| 69 | - | sets the background color of selected items (#RGB, #RRGGBB, and color names are |
|
| 70 | - | supported). |
|
| 69 | + | .BI \-sb " color" |
|
| 70 | + | defines the selected background color. |
|
| 71 | 71 | .TP |
|
| 72 | - | .B \-sf <color> |
|
| 73 | - | sets the foreground color of selected items (#RGB, #RRGGBB, and color names are |
|
| 74 | - | supported). |
|
| 72 | + | .BI \-sf " color" |
|
| 73 | + | defines the selected foreground color. |
|
| 75 | 74 | .TP |
|
| 76 | 75 | .B \-v |
|
| 77 | 76 | prints version information to standard output, then exits. |
|
| 78 | 77 | .SH USAGE |
|
| 79 | - | dmenu reads a list of newline-separated items from standard input and creates a |
|
| 80 | - | menu. When the user selects an item or enters any text and presses Return, |
|
| 81 | - | their choice is printed to standard output and dmenu terminates. |
|
| 82 | - | .P |
|
| 83 | 78 | dmenu is completely controlled by the keyboard. Besides standard Unix line |
|
| 84 | 79 | editing and item selection (Up/Down/Left/Right, PageUp/PageDown, Home/End), the |
|
| 85 | 80 | following keys are recognized: |
|
| 96 | 91 | success. |
|
| 97 | 92 | .TP |
|
| 98 | 93 | .B Escape (Control\-c) |
|
| 99 | - | Quit without selecting an item, returning failure. |
|
| 94 | + | Exit without selecting an item, returning failure. |
|
| 100 | 95 | .TP |
|
| 101 | 96 | .B Control\-y |
|
| 102 | 97 | Paste the current X selection into the input field. |
|
| 103 | 98 | .SH SEE ALSO |
|
| 104 | - | .BR dwm (1), |
|
| 105 | - | .BR wmii (1). |
|
| 99 | + | .BR dwm (1) |
|
| 1 | 1 | /* See LICENSE file for copyright and license details. */ |
|
| 2 | 2 | #include <ctype.h> |
|
| 3 | - | #include <locale.h> |
|
| 4 | 3 | #include <stdio.h> |
|
| 5 | 4 | #include <stdlib.h> |
|
| 6 | 5 | #include <string.h> |
|
| 7 | 6 | #include <unistd.h> |
|
| 8 | - | #include <X11/keysym.h> |
|
| 9 | 7 | #include <X11/Xatom.h> |
|
| 10 | 8 | #include <X11/Xlib.h> |
|
| 11 | 9 | #include <X11/Xutil.h> |
|
| 13 | 11 | #include <X11/extensions/Xinerama.h> |
|
| 14 | 12 | #endif |
|
| 15 | 13 | #include <draw.h> |
|
| 16 | - | #include "config.h" |
|
| 17 | 14 | ||
| 18 | 15 | #define INRECT(x,y,rx,ry,rw,rh) ((x) >= (rx) && (x) < (rx)+(rw) && (y) >= (ry) && (y) < (ry)+(rh)) |
|
| 19 | 16 | #define MIN(a,b) ((a) < (b) ? (a) : (b)) |
|
| 38 | 35 | static void insert(const char *s, ssize_t n); |
|
| 39 | 36 | static void keypress(XKeyEvent *e); |
|
| 40 | 37 | static void match(void); |
|
| 41 | - | static void paste(Atom atom); |
|
| 38 | + | static void paste(void); |
|
| 42 | 39 | static void readstdin(void); |
|
| 43 | 40 | static void run(void); |
|
| 44 | 41 | static void setup(void); |
|
| 45 | 42 | static void usage(void); |
|
| 46 | 43 | ||
| 47 | - | static char *prompt; |
|
| 48 | 44 | static char text[4096]; |
|
| 49 | - | static int screen; |
|
| 50 | 45 | static size_t cursor = 0; |
|
| 46 | + | static const char *prompt = NULL; |
|
| 47 | + | static const char *normbgcolor = "#cccccc"; |
|
| 48 | + | static const char *normfgcolor = "#000000"; |
|
| 49 | + | static const char *selbgcolor = "#0066ff"; |
|
| 50 | + | static const char *selfgcolor = "#ffffff"; |
|
| 51 | 51 | static unsigned int inputw = 0; |
|
| 52 | 52 | static unsigned int lines = 0; |
|
| 53 | 53 | static unsigned int mw, mh; |
|
| 54 | - | static unsigned int promptw = 0; |
|
| 55 | 54 | static unsigned long normcol[ColLast]; |
|
| 56 | 55 | static unsigned long selcol[ColLast]; |
|
| 57 | 56 | static Atom utf8; |
|
| 58 | 57 | static Bool topbar = True; |
|
| 59 | - | static DC dc; |
|
| 58 | + | static DC *dc; |
|
| 60 | 59 | static Item *allitems, *matches; |
|
| 61 | 60 | static Item *curr, *prev, *next, *sel; |
|
| 62 | 61 | static Window root, win; |
|
| 67 | 66 | ||
| 68 | 67 | void |
|
| 69 | 68 | appenditem(Item *item, Item **list, Item **last) { |
|
| 70 | - | if(!(*last)) |
|
| 69 | + | if(!*last) |
|
| 71 | 70 | *list = item; |
|
| 72 | 71 | else |
|
| 73 | 72 | (*last)->right = item; |
|
| 80 | 79 | calcoffsetsh(void) { |
|
| 81 | 80 | unsigned int w, x; |
|
| 82 | 81 | ||
| 83 | - | w = promptw + inputw + textw(&dc, "<") + textw(&dc, ">"); |
|
| 82 | + | w = (prompt ? textw(dc, prompt) : 0) + inputw + textw(dc, "<") + textw(dc, ">"); |
|
| 84 | 83 | for(x = w, next = curr; next; next = next->right) |
|
| 85 | - | if((x += MIN(textw(&dc, next->text), mw / 3)) > mw) |
|
| 84 | + | if((x += MIN(textw(dc, next->text), mw / 3)) > mw) |
|
| 86 | 85 | break; |
|
| 87 | 86 | for(x = w, prev = curr; prev && prev->left; prev = prev->left) |
|
| 88 | - | if((x += MIN(textw(&dc, prev->left->text), mw / 3)) > mw) |
|
| 87 | + | if((x += MIN(textw(dc, prev->left->text), mw / 3)) > mw) |
|
| 89 | 88 | break; |
|
| 90 | 89 | } |
|
| 91 | 90 | ||
| 96 | 95 | next = prev = curr; |
|
| 97 | 96 | for(i = 0; i < lines && next; i++) |
|
| 98 | 97 | next = next->right; |
|
| 99 | - | mh = (dc.font.height + 2) * (i + 1); |
|
| 100 | 98 | for(i = 0; i < lines && prev && prev->left; i++) |
|
| 101 | 99 | prev = prev->left; |
|
| 102 | 100 | } |
|
| 103 | 101 | ||
| 104 | 102 | char * |
|
| 105 | 103 | cistrstr(const char *s, const char *sub) { |
|
| 106 | - | int c, csub; |
|
| 107 | - | unsigned int len; |
|
| 104 | + | size_t len; |
|
| 108 | 105 | ||
| 109 | - | if(!sub) |
|
| 110 | - | return (char *)s; |
|
| 111 | - | if((c = tolower(*sub++)) != '\0') { |
|
| 112 | - | len = strlen(sub); |
|
| 113 | - | do { |
|
| 114 | - | do { |
|
| 115 | - | if((csub = *s++) == '\0') |
|
| 116 | - | return NULL; |
|
| 117 | - | } |
|
| 118 | - | while(tolower(csub) != c); |
|
| 119 | - | } |
|
| 120 | - | while(strncasecmp(s, sub, len) != 0); |
|
| 121 | - | s--; |
|
| 122 | - | } |
|
| 123 | - | return (char *)s; |
|
| 106 | + | for(len = strlen(sub); *s; s++) |
|
| 107 | + | if(!strncasecmp(s, sub, len)) |
|
| 108 | + | return (char *)s; |
|
| 109 | + | return NULL; |
|
| 124 | 110 | } |
|
| 125 | 111 | ||
| 126 | 112 | void |
|
| 127 | 113 | drawmenu(void) { |
|
| 128 | - | dc.x = 0; |
|
| 129 | - | dc.y = 0; |
|
| 130 | - | dc.w = mw; |
|
| 131 | - | dc.h = mh; |
|
| 132 | - | drawbox(&dc, normcol); |
|
| 133 | - | dc.h = dc.font.height + 2; |
|
| 134 | - | dc.y = topbar ? 0 : mh - dc.h; |
|
| 114 | + | dc->x = 0; |
|
| 115 | + | dc->y = 0; |
|
| 116 | + | drawrect(dc, 0, 0, mw, mh, BG(dc, normcol)); |
|
| 117 | + | dc->h = dc->font.height + 2; |
|
| 118 | + | dc->y = topbar ? 0 : mh - dc->h; |
|
| 135 | 119 | /* print prompt? */ |
|
| 136 | 120 | if(prompt) { |
|
| 137 | - | dc.w = promptw; |
|
| 138 | - | drawbox(&dc, selcol); |
|
| 139 | - | drawtext(&dc, prompt, selcol); |
|
| 140 | - | dc.x += dc.w; |
|
| 121 | + | dc->w = textw(dc, prompt); |
|
| 122 | + | drawtext(dc, prompt, selcol); |
|
| 123 | + | dc->x = dc->w; |
|
| 141 | 124 | } |
|
| 142 | - | dc.w = mw - dc.x; |
|
| 125 | + | dc->w = mw - dc->x; |
|
| 143 | 126 | /* print input area */ |
|
| 144 | - | if(matches && lines == 0 && textw(&dc, text) <= inputw) |
|
| 145 | - | dc.w = inputw; |
|
| 146 | - | drawtext(&dc, text, normcol); |
|
| 147 | - | drawline(&dc, textnw(&dc, text, cursor) + dc.h/2 - 2, 2, 1, dc.h-4, normcol); |
|
| 127 | + | if(matches && lines == 0 && textw(dc, text) <= inputw) |
|
| 128 | + | dc->w = inputw; |
|
| 129 | + | drawtext(dc, text, normcol); |
|
| 130 | + | drawrect(dc, textnw(dc, text, cursor) + dc->h/2 - 2, 2, 1, dc->h - 4, FG(dc, normcol)); |
|
| 148 | 131 | if(lines > 0) |
|
| 149 | 132 | drawmenuv(); |
|
| 150 | - | else if(curr && (dc.w == inputw || curr->next)) |
|
| 133 | + | else if(curr && (dc->w == inputw || curr->next)) |
|
| 151 | 134 | drawmenuh(); |
|
| 152 | - | commitdraw(&dc, win); |
|
| 135 | + | commitdraw(dc, win); |
|
| 153 | 136 | } |
|
| 154 | 137 | ||
| 155 | 138 | void |
|
| 156 | 139 | drawmenuh(void) { |
|
| 157 | 140 | Item *item; |
|
| 158 | 141 | ||
| 159 | - | dc.x += inputw; |
|
| 160 | - | dc.w = textw(&dc, "<"); |
|
| 142 | + | dc->x += inputw; |
|
| 143 | + | dc->w = textw(dc, "<"); |
|
| 161 | 144 | if(curr->left) |
|
| 162 | - | drawtext(&dc, "<", normcol); |
|
| 163 | - | dc.x += dc.w; |
|
| 145 | + | drawtext(dc, "<", normcol); |
|
| 164 | 146 | for(item = curr; item != next; item = item->right) { |
|
| 165 | - | dc.w = MIN(textw(&dc, item->text), mw / 3); |
|
| 166 | - | if(item == sel) |
|
| 167 | - | drawbox(&dc, selcol); |
|
| 168 | - | drawtext(&dc, item->text, (item == sel) ? selcol : normcol); |
|
| 169 | - | dc.x += dc.w; |
|
| 147 | + | dc->x += dc->w; |
|
| 148 | + | dc->w = MIN(textw(dc, item->text), mw / 3); |
|
| 149 | + | drawtext(dc, item->text, (item == sel) ? selcol : normcol); |
|
| 170 | 150 | } |
|
| 171 | - | dc.w = textw(&dc, ">"); |
|
| 172 | - | dc.x = mw - dc.w; |
|
| 151 | + | dc->w = textw(dc, ">"); |
|
| 152 | + | dc->x = mw - dc->w; |
|
| 173 | 153 | if(next) |
|
| 174 | - | drawtext(&dc, ">", normcol); |
|
| 154 | + | drawtext(dc, ">", normcol); |
|
| 175 | 155 | } |
|
| 176 | 156 | ||
| 177 | 157 | void |
|
| 178 | 158 | drawmenuv(void) { |
|
| 179 | 159 | Item *item; |
|
| 180 | - | XWindowAttributes wa; |
|
| 181 | 160 | ||
| 182 | - | dc.y = topbar ? dc.h : 0; |
|
| 183 | - | dc.w = mw - dc.x; |
|
| 161 | + | dc->y = topbar ? dc->h : 0; |
|
| 162 | + | dc->w = mw - dc->x; |
|
| 184 | 163 | for(item = curr; item != next; item = item->right) { |
|
| 185 | - | if(item == sel) |
|
| 186 | - | drawbox(&dc, selcol); |
|
| 187 | - | drawtext(&dc, item->text, (item == sel) ? selcol : normcol); |
|
| 188 | - | dc.y += dc.h; |
|
| 164 | + | drawtext(dc, item->text, (item == sel) ? selcol : normcol); |
|
| 165 | + | dc->y += dc->h; |
|
| 189 | 166 | } |
|
| 190 | - | if(!XGetWindowAttributes(dc.dpy, win, &wa)) |
|
| 191 | - | eprintf("cannot get window attributes\n"); |
|
| 192 | - | if(wa.height != mh) |
|
| 193 | - | XMoveResizeWindow(dc.dpy, win, wa.x, wa.y + (topbar ? 0 : wa.height - mh), mw, mh); |
|
| 194 | 167 | } |
|
| 195 | 168 | ||
| 196 | 169 | void |
|
| 198 | 171 | int i; |
|
| 199 | 172 | ||
| 200 | 173 | for(i = 0; i < 1000; i++) { |
|
| 201 | - | if(!XGrabKeyboard(dc.dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime)) |
|
| 174 | + | if(!XGrabKeyboard(dc->dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime)) |
|
| 202 | 175 | return; |
|
| 203 | 176 | usleep(1000); |
|
| 204 | 177 | } |
|
| 254 | 227 | break; |
|
| 255 | 228 | case XK_k: /* delete right */ |
|
| 256 | 229 | text[cursor] = '\0'; |
|
| 230 | + | match(); |
|
| 257 | 231 | break; |
|
| 258 | 232 | case XK_n: |
|
| 259 | 233 | ksym = XK_Down; |
|
| 270 | 244 | n = 0; |
|
| 271 | 245 | while(cursor - n++ > 0 && text[cursor - n] == ' '); |
|
| 272 | 246 | while(cursor - n++ > 0 && text[cursor - n] != ' '); |
|
| 273 | - | insert(NULL, -(--n)); |
|
| 247 | + | insert(NULL, 1-n); |
|
| 274 | 248 | break; |
|
| 275 | 249 | case XK_y: /* paste selection */ |
|
| 276 | - | XConvertSelection(dc.dpy, XA_PRIMARY, utf8, None, win, CurrentTime); |
|
| 250 | + | XConvertSelection(dc->dpy, XA_PRIMARY, utf8, None, win, CurrentTime); |
|
| 277 | 251 | /* causes SelectionNotify event */ |
|
| 278 | 252 | return; |
|
| 279 | 253 | } |
|
| 348 | 322 | break; |
|
| 349 | 323 | case XK_Return: |
|
| 350 | 324 | case XK_KP_Enter: |
|
| 351 | - | fputs(((e->state & ShiftMask) || sel) ? sel->text : text, stdout); |
|
| 325 | + | fputs((sel && !(e->state & ShiftMask)) ? sel->text : text, stdout); |
|
| 352 | 326 | fflush(stdout); |
|
| 353 | 327 | exit(EXIT_SUCCESS); |
|
| 354 | 328 | case XK_Right: |
|
| 418 | 392 | } |
|
| 419 | 393 | ||
| 420 | 394 | void |
|
| 421 | - | paste(Atom atom) |
|
| 422 | - | { |
|
| 395 | + | paste(void) { |
|
| 423 | 396 | char *p, *q; |
|
| 424 | 397 | int di; |
|
| 425 | 398 | unsigned long dl; |
|
| 426 | 399 | Atom da; |
|
| 427 | 400 | ||
| 428 | - | XGetWindowProperty(dc.dpy, win, atom, 0, sizeof text - cursor, True, |
|
| 429 | - | utf8, &da, &di, &dl, &dl, (unsigned char **)&p); |
|
| 401 | + | XGetWindowProperty(dc->dpy, win, utf8, 0, sizeof text - cursor, True, |
|
| 402 | + | utf8, &da, &di, &dl, &dl, (unsigned char **)&p); |
|
| 430 | 403 | insert(p, (q = strchr(p, '\n')) ? q-p : strlen(p)); |
|
| 431 | 404 | XFree(p); |
|
| 432 | 405 | drawmenu(); |
|
| 434 | 407 | ||
| 435 | 408 | void |
|
| 436 | 409 | readstdin(void) { |
|
| 437 | - | char buf[sizeof text]; |
|
| 438 | - | size_t len; |
|
| 410 | + | char buf[sizeof text], *p; |
|
| 439 | 411 | Item *item, *new; |
|
| 440 | 412 | ||
| 441 | 413 | allitems = NULL; |
|
| 442 | 414 | for(item = NULL; fgets(buf, sizeof buf, stdin); item = new) { |
|
| 443 | - | len = strlen(buf); |
|
| 444 | - | if(buf[len-1] == '\n') |
|
| 445 | - | buf[--len] = '\0'; |
|
| 415 | + | if((p = strchr(buf, '\n'))) |
|
| 416 | + | *p = '\0'; |
|
| 446 | 417 | if(!(new = malloc(sizeof *new))) |
|
| 447 | 418 | eprintf("cannot malloc %u bytes\n", sizeof *new); |
|
| 448 | 419 | if(!(new->text = strdup(buf))) |
|
| 449 | - | eprintf("cannot strdup %u bytes\n", len); |
|
| 450 | - | inputw = MAX(inputw, textw(&dc, new->text)); |
|
| 420 | + | eprintf("cannot strdup %u bytes\n", strlen(buf)); |
|
| 421 | + | inputw = MAX(inputw, textw(dc, new->text)); |
|
| 451 | 422 | new->next = new->left = new->right = NULL; |
|
| 452 | 423 | if(item) |
|
| 453 | 424 | item->next = new; |
|
| 454 | - | else |
|
| 425 | + | else |
|
| 455 | 426 | allitems = new; |
|
| 456 | 427 | } |
|
| 457 | 428 | } |
|
| 460 | 431 | run(void) { |
|
| 461 | 432 | XEvent ev; |
|
| 462 | 433 | ||
| 463 | - | while(!XNextEvent(dc.dpy, &ev)) |
|
| 434 | + | while(!XNextEvent(dc->dpy, &ev)) |
|
| 464 | 435 | switch(ev.type) { |
|
| 465 | 436 | case Expose: |
|
| 466 | 437 | if(ev.xexpose.count == 0) |
|
| 470 | 441 | keypress(&ev.xkey); |
|
| 471 | 442 | break; |
|
| 472 | 443 | case SelectionNotify: |
|
| 473 | - | if(ev.xselection.property != None) |
|
| 474 | - | paste(ev.xselection.property); |
|
| 444 | + | if(ev.xselection.property == utf8) |
|
| 445 | + | paste(); |
|
| 475 | 446 | break; |
|
| 476 | 447 | case VisibilityNotify: |
|
| 477 | 448 | if(ev.xvisibility.state != VisibilityUnobscured) |
|
| 478 | - | XRaiseWindow(dc.dpy, win); |
|
| 449 | + | XRaiseWindow(dc->dpy, win); |
|
| 479 | 450 | break; |
|
| 480 | 451 | } |
|
| 481 | 452 | } |
|
| 482 | 453 | ||
| 483 | 454 | void |
|
| 484 | 455 | setup(void) { |
|
| 485 | - | int x, y; |
|
| 456 | + | int x, y, screen; |
|
| 457 | + | XSetWindowAttributes wa; |
|
| 486 | 458 | #ifdef XINERAMA |
|
| 487 | - | int i, n; |
|
| 459 | + | int n; |
|
| 488 | 460 | XineramaScreenInfo *info; |
|
| 489 | 461 | #endif |
|
| 490 | - | XSetWindowAttributes wa; |
|
| 491 | 462 | ||
| 492 | - | normcol[ColBG] = getcolor(&dc, normbgcolor); |
|
| 493 | - | normcol[ColFG] = getcolor(&dc, normfgcolor); |
|
| 494 | - | selcol[ColBG] = getcolor(&dc, selbgcolor); |
|
| 495 | - | selcol[ColFG] = getcolor(&dc, selfgcolor); |
|
| 463 | + | screen = DefaultScreen(dc->dpy); |
|
| 464 | + | root = RootWindow(dc->dpy, screen); |
|
| 465 | + | utf8 = XInternAtom(dc->dpy, "UTF8_STRING", False); |
|
| 466 | + | ||
| 467 | + | normcol[ColBG] = getcolor(dc, normbgcolor); |
|
| 468 | + | normcol[ColFG] = getcolor(dc, normfgcolor); |
|
| 469 | + | selcol[ColBG] = getcolor(dc, selbgcolor); |
|
| 470 | + | selcol[ColFG] = getcolor(dc, selfgcolor); |
|
| 496 | 471 | ||
| 497 | 472 | /* input window geometry */ |
|
| 498 | - | mh = (dc.font.height + 2) * (lines + 1); |
|
| 473 | + | mh = (dc->font.height + 2) * (lines + 1); |
|
| 499 | 474 | #ifdef XINERAMA |
|
| 500 | - | if((info = XineramaQueryScreens(dc.dpy, &n))) { |
|
| 501 | - | int di; |
|
| 475 | + | if((info = XineramaQueryScreens(dc->dpy, &n))) { |
|
| 476 | + | int i, di; |
|
| 502 | 477 | unsigned int du; |
|
| 503 | 478 | Window dw; |
|
| 504 | 479 | ||
| 505 | - | XQueryPointer(dc.dpy, root, &dw, &dw, &x, &y, &di, &di, &du); |
|
| 480 | + | XQueryPointer(dc->dpy, root, &dw, &dw, &x, &y, &di, &di, &du); |
|
| 506 | 481 | for(i = 0; i < n; i++) |
|
| 507 | 482 | if(INRECT(x, y, info[i].x_org, info[i].y_org, info[i].width, info[i].height)) |
|
| 508 | 483 | break; |
|
| 515 | 490 | #endif |
|
| 516 | 491 | { |
|
| 517 | 492 | x = 0; |
|
| 518 | - | y = topbar ? 0 : DisplayHeight(dc.dpy, screen) - mh; |
|
| 519 | - | mw = DisplayWidth(dc.dpy, screen); |
|
| 493 | + | y = topbar ? 0 : DisplayHeight(dc->dpy, screen) - mh; |
|
| 494 | + | mw = DisplayWidth(dc->dpy, screen); |
|
| 520 | 495 | } |
|
| 521 | 496 | ||
| 522 | 497 | /* input window */ |
|
| 523 | 498 | wa.override_redirect = True; |
|
| 524 | 499 | wa.background_pixmap = ParentRelative; |
|
| 525 | 500 | wa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; |
|
| 526 | - | win = XCreateWindow(dc.dpy, root, x, y, mw, mh, 0, |
|
| 527 | - | DefaultDepth(dc.dpy, screen), CopyFromParent, |
|
| 528 | - | DefaultVisual(dc.dpy, screen), |
|
| 501 | + | win = XCreateWindow(dc->dpy, root, x, y, mw, mh, 0, |
|
| 502 | + | DefaultDepth(dc->dpy, screen), CopyFromParent, |
|
| 503 | + | DefaultVisual(dc->dpy, screen), |
|
| 529 | 504 | CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); |
|
| 530 | 505 | ||
| 506 | + | grabkeyboard(); |
|
| 507 | + | setcanvas(dc, win, mw, mh); |
|
| 508 | + | inputw = MIN(inputw, mw/3); |
|
| 509 | + | XMapRaised(dc->dpy, win); |
|
| 531 | 510 | match(); |
|
| 532 | - | grabkeyboard(); |
|
| 533 | - | setupdraw(&dc, win); |
|
| 534 | - | inputw = MIN(inputw, mw / 3); |
|
| 535 | - | utf8 = XInternAtom(dc.dpy, "UTF8_STRING", False); |
|
| 536 | - | XMapRaised(dc.dpy, win); |
|
| 537 | 511 | } |
|
| 538 | 512 | ||
| 539 | 513 | void |
|
| 540 | 514 | usage(void) { |
|
| 541 | - | fputs("usage: dmenu [-b] [-i] [-l <lines>] [-p <prompt>] [-fn <font>] [-nb <color>]\n" |
|
| 542 | - | " [-nf <color>] [-sb <color>] [-sf <color>] [-v]\n", stderr); |
|
| 515 | + | fputs("usage: dmenu [-b] [-i] [-l lines] [-p prompt] [-fn font] [-nb color]\n" |
|
| 516 | + | " [-nf color] [-sb color] [-sf color] [-v]\n", stderr); |
|
| 543 | 517 | exit(EXIT_FAILURE); |
|
| 544 | 518 | } |
|
| 545 | 519 | ||
| 548 | 522 | int i; |
|
| 549 | 523 | ||
| 550 | 524 | progname = "dmenu"; |
|
| 525 | + | dc = initdraw(); |
|
| 526 | + | ||
| 551 | 527 | for(i = 1; i < argc; i++) |
|
| 552 | - | /* 1-arg flags */ |
|
| 528 | + | /* single flags */ |
|
| 553 | 529 | if(!strcmp(argv[i], "-v")) { |
|
| 554 | 530 | fputs("dmenu-"VERSION", © 2006-2010 dmenu engineers, see LICENSE for details\n", stdout); |
|
| 555 | 531 | exit(EXIT_SUCCESS); |
|
| 562 | 538 | } |
|
| 563 | 539 | else if(i == argc-1) |
|
| 564 | 540 | usage(); |
|
| 565 | - | /* 2-arg flags */ |
|
| 541 | + | /* double flags */ |
|
| 566 | 542 | else if(!strcmp(argv[i], "-l")) { |
|
| 567 | 543 | if((lines = atoi(argv[++i])) > 0) |
|
| 568 | 544 | calcoffsets = calcoffsetsv; |
|
| 569 | 545 | } |
|
| 570 | - | else if(!strcmp(argv[i], "-p")) { |
|
| 546 | + | else if(!strcmp(argv[i], "-p")) |
|
| 571 | 547 | prompt = argv[++i]; |
|
| 572 | - | promptw = MIN(textw(&dc, prompt), mw/5); |
|
| 573 | - | } |
|
| 574 | 548 | else if(!strcmp(argv[i], "-fn")) |
|
| 575 | - | font = argv[++i]; |
|
| 549 | + | initfont(dc, argv[i++]); |
|
| 576 | 550 | else if(!strcmp(argv[i], "-nb")) |
|
| 577 | 551 | normbgcolor = argv[++i]; |
|
| 578 | 552 | else if(!strcmp(argv[i], "-nf")) |
|
| 583 | 557 | selfgcolor = argv[++i]; |
|
| 584 | 558 | else |
|
| 585 | 559 | usage(); |
|
| 586 | - | ||
| 587 | - | if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) |
|
| 588 | - | fputs("dmenu: warning: no locale support\n", stderr); |
|
| 589 | - | if(!(dc.dpy = XOpenDisplay(NULL))) |
|
| 590 | - | eprintf("cannot open display\n"); |
|
| 591 | - | screen = DefaultScreen(dc.dpy); |
|
| 592 | - | root = RootWindow(dc.dpy, screen); |
|
| 593 | - | initfont(&dc, font); |
|
| 594 | 560 | ||
| 595 | 561 | readstdin(); |
|
| 596 | 562 | setup(); |
|
| 19 | 19 | do |
|
| 20 | 20 | test -x "$file" && echo "$file" |
|
| 21 | 21 | done |
|
| 22 | - | done | sort | uniq > "$CACHE".$$ && |
|
| 22 | + | done | sort -u > "$CACHE".$$ && |
|
| 23 | 23 | mv "$CACHE".$$ "$CACHE" |
|
| 24 | 24 | fi |
|
| 25 | 25 |