diff options
author | Connor Lane Smith <cls@lubutu.com> | 2010-07-31 14:56:27 +0100 |
---|---|---|
committer | Connor Lane Smith <cls@lubutu.com> | 2010-07-31 14:56:27 +0100 |
commit | a3606ecb0eeaffa752fdf26565ebaaba29b83239 (patch) | |
tree | a00a059252baff25ef5837605749555efd653c5b | |
parent | 7d5fe17391fefd978eab281a6cbebe2aa601e9ce (diff) |
updated manpage, added paste, cleaned up, new libdraw
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | README | 6 | ||||
-rw-r--r-- | dmenu.1 | 94 | ||||
-rw-r--r-- | dmenu.c | 488 |
4 files changed, 271 insertions, 319 deletions
@@ -6,7 +6,7 @@ include config.mk | |||
6 | SRC = dmenu.c | 6 | SRC = dmenu.c |
7 | OBJ = ${SRC:.c=.o} | 7 | OBJ = ${SRC:.c=.o} |
8 | 8 | ||
9 | all: options dinput dmenu | 9 | all: options dmenu |
10 | 10 | ||
11 | options: | 11 | options: |
12 | @echo dmenu build options: | 12 | @echo dmenu build options: |
@@ -8,13 +8,11 @@ Requirements | |||
8 | In order to build dmenu you need the Xlib header files. | 8 | In order to build dmenu you need the Xlib header files. |
9 | You also need libdraw, available from http://hg.suckless.org/libdraw | 9 | You also need libdraw, available from http://hg.suckless.org/libdraw |
10 | 10 | ||
11 | Pasting the X selection to dmenu requires the sselp utility at runtime. | ||
12 | |||
13 | 11 | ||
14 | Installation | 12 | Installation |
15 | ------------ | 13 | ------------ |
16 | Edit config.mk to match your local setup (dmenu is installed into | 14 | Edit config.mk to match your local setup (dmenu is installed into the |
17 | the /usr/local namespace by default). | 15 | /usr/local namespace by default). |
18 | 16 | ||
19 | Afterwards enter the following command to build and install dmenu (if | 17 | Afterwards enter the following command to build and install dmenu (if |
20 | necessary as root): | 18 | necessary as root): |
@@ -3,99 +3,103 @@ | |||
3 | dmenu \- dynamic menu | 3 | dmenu \- dynamic menu |
4 | .SH SYNOPSIS | 4 | .SH SYNOPSIS |
5 | .B dmenu | 5 | .B dmenu |
6 | .RB [ \-i ] | ||
7 | .RB [ \-b ] | 6 | .RB [ \-b ] |
8 | .RB [ \-e " <xid>]" | 7 | .RB [ \-i ] |
9 | .RB [ \-l " <lines>]" | 8 | .RB [ \-l " <lines>]" |
9 | .RB [ \-p " <prompt>]" | ||
10 | .RB [ \-fn " <font>]" | 10 | .RB [ \-fn " <font>]" |
11 | .RB [ \-nb " <color>]" | 11 | .RB [ \-nb " <color>]" |
12 | .RB [ \-nf " <color>]" | 12 | .RB [ \-nf " <color>]" |
13 | .RB [ \-p " <prompt>]" | ||
14 | .RB [ \-sb " <color>]" | 13 | .RB [ \-sb " <color>]" |
15 | .RB [ \-sf " <color>]" | 14 | .RB [ \-sf " <color>]" |
16 | .RB [ \-v ] | 15 | .RB [ \-v ] |
17 | 16 | ||
18 | .B dmenu_run | 17 | .B dmenu_run |
19 | [<options...>] | 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 ] | ||
20 | 28 | ||
21 | .B dmenu_path | 29 | .B dmenu_path |
22 | .SH DESCRIPTION | 30 | .SH DESCRIPTION |
23 | .SS Overview | 31 | .SS Overview |
24 | dmenu is a generic menu for X, originally designed for | 32 | .B dmenu |
33 | is a generic menu for X, originally designed for | ||
25 | .BR dwm (1). | 34 | .BR dwm (1). |
26 | It manages huge amounts (up to 10.000 and more) of user defined menu items | 35 | It manages huge amounts (10000 and more) of user defined menu items efficiently. |
27 | efficiently. | 36 | .P |
28 | 37 | .B dmenu_run | |
29 | dmenu_run is a dmenu script used by dwm which lists executables in the user's PATH | 38 | is a dmenu script which lists programs in the user's PATH and executes |
30 | and executes the selected item. | 39 | the selected item. |
31 | 40 | .P | |
32 | dmenu_path is a script used by dmenu_run to find and cache a list of executables. | 41 | .B dmenu_path |
42 | is a script used by | ||
43 | .I dmenu_run | ||
44 | to find and cache a list of programs. | ||
33 | .SS Options | 45 | .SS Options |
34 | .TP | 46 | .TP |
35 | .B \-i | ||
36 | makes dmenu match menu entries case insensitively. | ||
37 | .TP | ||
38 | .B \-b | 47 | .B \-b |
39 | defines that dmenu appears at the bottom. | 48 | dmenu appears at the bottom of the screen. |
40 | .TP | 49 | .TP |
41 | .B \-e <xid> | 50 | .B \-i |
42 | reparents dmenu to the window specified by xid. | 51 | dmenu matches menu entries case insensitively. |
43 | .TP | 52 | .TP |
44 | .B \-l <lines> | 53 | .B \-l <lines> |
45 | activates vertical list mode. | 54 | dmenu lists items vertically, with the given number of lines. |
46 | The given number of lines will be displayed. Window height will be adjusted. | 55 | .TP |
56 | .B \-p <prompt> | ||
57 | sets the prompt to be displayed to the left of the input area. | ||
47 | .TP | 58 | .TP |
48 | .B \-fn <font> | 59 | .B \-fn <font> |
49 | defines the font. | 60 | sets the font. |
50 | .TP | 61 | .TP |
51 | .B \-nb <color> | 62 | .B \-nb <color> |
52 | defines the normal background color (#RGB, #RRGGBB, and color names are supported). | 63 | sets the background color (#RGB, #RRGGBB, and color names are supported). |
53 | .TP | 64 | .TP |
54 | .B \-nf <color> | 65 | .B \-nf <color> |
55 | defines the normal foreground color (#RGB, #RRGGBB, and color names are supported). | 66 | sets the foreground color (#RGB, #RRGGBB, and color names are supported). |
56 | .TP | ||
57 | .B \-p <prompt> | ||
58 | defines a prompt to be displayed before the input area. | ||
59 | .TP | 67 | .TP |
60 | .B \-sb <color> | 68 | .B \-sb <color> |
61 | defines the selected background color (#RGB, #RRGGBB, and color names are supported). | 69 | sets the background color of selected items (#RGB, #RRGGBB, and color names are |
70 | supported). | ||
62 | .TP | 71 | .TP |
63 | .B \-sf <color> | 72 | .B \-sf <color> |
64 | defines the selected foreground color (#RGB, #RRGGBB, and color names are supported). | 73 | sets the foreground color of selected items (#RGB, #RRGGBB, and color names are |
74 | supported). | ||
65 | .TP | 75 | .TP |
66 | .B \-v | 76 | .B \-v |
67 | prints version information to standard output, then exits. | 77 | prints version information to standard output, then exits. |
68 | .SH USAGE | 78 | .SH USAGE |
69 | dmenu reads a list of newline-separated items from standard input and creates a | 79 | dmenu reads a list of newline-separated items from standard input and creates a |
70 | menu. When the user selects an item or enters any text and presses Return, his/her | 80 | menu. When the user selects an item or enters any text and presses Return, |
71 | choice is printed to standard output and dmenu terminates. | 81 | their choice is printed to standard output and dmenu terminates. |
72 | .P | 82 | .P |
73 | dmenu is completely controlled by the keyboard. Besides standard Unix line editing, | 83 | dmenu is completely controlled by the keyboard. Besides standard Unix line |
74 | and item selection (Up/Down or Left/Right, PageUp/PageDown, Home/End), the following | 84 | editing and item selection (Up/Down/Left/Right, PageUp/PageDown, Home/End), the |
75 | keys are recognized: | 85 | following keys are recognized: |
76 | .TP | 86 | .TP |
77 | .B Tab (Control\-i) | 87 | .B Tab (Control\-i) |
78 | Copy the selected item to the input field. | 88 | Copy the selected item to the input field. |
79 | .TP | 89 | .TP |
80 | .B Return (Control\-j) | 90 | .B Return (Control\-j) |
81 | Confirm selection and quit (print the selected item to standard output). Returns | 91 | Confirm selection. Prints the selected item to standard output and exits, |
82 | .B 0 | 92 | returning success. |
83 | on termination. | ||
84 | .TP | 93 | .TP |
85 | .B Shift\-Return (Control\-Shift\-j) | 94 | .B Shift\-Return (Control\-Shift\-j) |
86 | Confirm input and quit (print the text in the input field to standard output). | 95 | Confirm input. Prints the input text to standard output and exits, returning |
87 | Returns | 96 | success. |
88 | .B 0 | ||
89 | on termination. | ||
90 | .TP | 97 | .TP |
91 | .B Escape (Control\-c) | 98 | .B Escape (Control\-c) |
92 | Quit without selecting an item. Returns | 99 | Quit without selecting an item, returning failure. |
93 | .B 1 | ||
94 | on termination. | ||
95 | .TP | 100 | .TP |
96 | .B Control\-y | 101 | .B Control\-y |
97 | Pastes the X selection into the input field. This requires | 102 | Paste the current X selection into the input field. |
98 | .BR sselp (1). | ||
99 | .SH SEE ALSO | 103 | .SH SEE ALSO |
100 | .BR dwm (1), | 104 | .BR dwm (1), |
101 | .BR wmii (1). | 105 | .BR wmii (1). |
@@ -6,6 +6,7 @@ | |||
6 | #include <string.h> | 6 | #include <string.h> |
7 | #include <unistd.h> | 7 | #include <unistd.h> |
8 | #include <X11/keysym.h> | 8 | #include <X11/keysym.h> |
9 | #include <X11/Xatom.h> | ||
9 | #include <X11/Xlib.h> | 10 | #include <X11/Xlib.h> |
10 | #include <X11/Xutil.h> | 11 | #include <X11/Xutil.h> |
11 | #ifdef XINERAMA | 12 | #ifdef XINERAMA |
@@ -14,78 +15,72 @@ | |||
14 | #include <draw.h> | 15 | #include <draw.h> |
15 | #include "config.h" | 16 | #include "config.h" |
16 | 17 | ||
17 | #define INRECT(x,y,rx,ry,rw,rh) ((rx) < (x) && (x) < (rx)+(rw) && (ry) < (y) && (y) < (ry)+(rh)) | 18 | #define INRECT(x,y,rx,ry,rw,rh) ((x) >= (rx) && (x) < (rx)+(rw) && (y) >= (ry) && (y) < (ry)+(rh)) |
18 | #define MIN(a,b) ((a) < (b) ? (a) : (b)) | 19 | #define MIN(a,b) ((a) < (b) ? (a) : (b)) |
19 | #define MAX(a,b) ((a) > (b) ? (a) : (b)) | 20 | #define MAX(a,b) ((a) > (b) ? (a) : (b)) |
20 | #define IS_UTF8_1ST_CHAR(c) (((c) & 0xc0) == 0xc0 || ((c) & 0x80) == 0x00) | 21 | #define UTF8_CODEPOINT(c) (((c) & 0xc0) != 0x80) |
21 | 22 | ||
22 | typedef struct Item Item; | 23 | typedef struct Item Item; |
23 | struct Item { | 24 | struct Item { |
24 | char *text; | 25 | char *text; |
25 | Item *next; /* traverses all items */ | 26 | Item *next; /* traverses all items */ |
26 | Item *left, *right; /* traverses items matching current search pattern */ | 27 | Item *left, *right; /* traverses matching items */ |
27 | }; | 28 | }; |
28 | 29 | ||
29 | static void appenditem(Item *i, Item **list, Item **last); | 30 | static void appenditem(Item *item, Item **list, Item **last); |
30 | static void calcoffsetsh(void); | 31 | static void calcoffsetsh(void); |
31 | static void calcoffsetsv(void); | 32 | static void calcoffsetsv(void); |
32 | static char *cistrstr(const char *s, const char *sub); | 33 | static char *cistrstr(const char *s, const char *sub); |
33 | static void cleanup(void); | ||
34 | static void drawitem(const char *s, unsigned long col[ColLast]); | ||
35 | static void drawmenu(void); | 34 | static void drawmenu(void); |
36 | static void drawmenuh(void); | 35 | static void drawmenuh(void); |
37 | static void drawmenuv(void); | 36 | static void drawmenuv(void); |
38 | static void grabkeyboard(void); | 37 | static void grabkeyboard(void); |
38 | static void insert(const char *s, ssize_t n); | ||
39 | static void keypress(XKeyEvent *e); | 39 | static void keypress(XKeyEvent *e); |
40 | static void match(void); | 40 | static void match(void); |
41 | static void paste(Atom atom); | ||
41 | static void readstdin(void); | 42 | static void readstdin(void); |
42 | static void run(void); | 43 | static void run(void); |
43 | static void setup(void); | 44 | static void setup(void); |
45 | static void usage(void); | ||
44 | 46 | ||
45 | static char **argp = NULL; | ||
46 | static char *maxname = NULL; | ||
47 | static char *prompt; | 47 | static char *prompt; |
48 | static char text[4096]; | 48 | static char text[4096]; |
49 | static int promptw; | ||
50 | static int screen; | 49 | static int screen; |
51 | static size_t cur = 0; | 50 | static size_t cursor = 0; |
52 | static unsigned int cmdw = 0; | 51 | static unsigned int inputw = 0; |
53 | static unsigned int lines = 0; | 52 | static unsigned int lines = 0; |
54 | static unsigned int numlockmask; | ||
55 | static unsigned int mw, mh; | 53 | static unsigned int mw, mh; |
54 | static unsigned int promptw = 0; | ||
56 | static unsigned long normcol[ColLast]; | 55 | static unsigned long normcol[ColLast]; |
57 | static unsigned long selcol[ColLast]; | 56 | static unsigned long selcol[ColLast]; |
57 | static Atom utf8; | ||
58 | static Bool topbar = True; | 58 | static Bool topbar = True; |
59 | static DC dc; | 59 | static DC dc; |
60 | static Display *dpy; | 60 | static Item *allitems, *matches; |
61 | static Item *allitems = NULL; /* first of all items */ | 61 | static Item *curr, *prev, *next, *sel; |
62 | static Item *item = NULL; /* first of pattern matching items */ | 62 | static Window root, win; |
63 | static Item *sel = NULL; | ||
64 | static Item *next = NULL; | ||
65 | static Item *prev = NULL; | ||
66 | static Item *curr = NULL; | ||
67 | static Window win, root; | ||
68 | 63 | ||
69 | static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; | 64 | static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; |
70 | static char *(*fstrstr)(const char *, const char *) = strstr; | 65 | static char *(*fstrstr)(const char *, const char *) = strstr; |
71 | static void (*calcoffsets)(void) = calcoffsetsh; | 66 | static void (*calcoffsets)(void) = calcoffsetsh; |
72 | 67 | ||
73 | void | 68 | void |
74 | appenditem(Item *i, Item **list, Item **last) { | 69 | appenditem(Item *item, Item **list, Item **last) { |
75 | if(!(*last)) | 70 | if(!(*last)) |
76 | *list = i; | 71 | *list = item; |
77 | else | 72 | else |
78 | (*last)->right = i; | 73 | (*last)->right = item; |
79 | i->left = *last; | 74 | item->left = *last; |
80 | i->right = NULL; | 75 | item->right = NULL; |
81 | *last = i; | 76 | *last = item; |
82 | } | 77 | } |
83 | 78 | ||
84 | void | 79 | void |
85 | calcoffsetsh(void) { | 80 | calcoffsetsh(void) { |
86 | unsigned int w, x; | 81 | unsigned int w, x; |
87 | 82 | ||
88 | w = promptw + cmdw + textw(&dc, "<") + textw(&dc, ">"); | 83 | w = promptw + inputw + textw(&dc, "<") + textw(&dc, ">"); |
89 | for(x = w, next = curr; next; next = next->right) | 84 | for(x = w, next = curr; next; next = next->right) |
90 | if((x += MIN(textw(&dc, next->text), mw / 3)) > mw) | 85 | if((x += MIN(textw(&dc, next->text), mw / 3)) > mw) |
91 | break; | 86 | break; |
@@ -129,33 +124,6 @@ cistrstr(const char *s, const char *sub) { | |||
129 | } | 124 | } |
130 | 125 | ||
131 | void | 126 | void |
132 | cleanup(void) { | ||
133 | Item *itm; | ||
134 | |||
135 | while(allitems) { | ||
136 | itm = allitems->next; | ||
137 | free(allitems->text); | ||
138 | free(allitems); | ||
139 | allitems = itm; | ||
140 | } | ||
141 | cleanupdraw(&dc); | ||
142 | XDestroyWindow(dpy, win); | ||
143 | XUngrabKeyboard(dpy, CurrentTime); | ||
144 | XCloseDisplay(dpy); | ||
145 | } | ||
146 | |||
147 | void | ||
148 | drawitem(const char *s, unsigned long col[ColLast]) { | ||
149 | const char *p; | ||
150 | unsigned int w = textnw(&dc, text, strlen(text)); | ||
151 | |||
152 | drawbox(&dc, col); | ||
153 | drawtext(&dc, s, col); | ||
154 | for(p = fstrstr(s, text); *text && (p = fstrstr(p, text)); p++) | ||
155 | drawline(&dc, textnw(&dc, s, p-s) + dc.h/2 - 1, dc.h-2, w, 1, col); | ||
156 | } | ||
157 | |||
158 | void | ||
159 | drawmenu(void) { | 127 | drawmenu(void) { |
160 | dc.x = 0; | 128 | dc.x = 0; |
161 | dc.y = 0; | 129 | dc.y = 0; |
@@ -172,82 +140,89 @@ drawmenu(void) { | |||
172 | dc.x += dc.w; | 140 | dc.x += dc.w; |
173 | } | 141 | } |
174 | dc.w = mw - dc.x; | 142 | dc.w = mw - dc.x; |
175 | /* print command */ | 143 | /* print input area */ |
176 | if(cmdw && item && lines == 0) | 144 | if(matches && lines == 0 && textw(&dc, text) <= inputw) |
177 | dc.w = cmdw; | 145 | dc.w = inputw; |
178 | drawtext(&dc, text, normcol); | 146 | drawtext(&dc, text, normcol); |
179 | drawline(&dc, textnw(&dc, text, cur) + dc.h/2 - 2, 2, 1, dc.h-4, normcol); | 147 | drawline(&dc, textnw(&dc, text, cursor) + dc.h/2 - 2, 2, 1, dc.h-4, normcol); |
180 | if(lines > 0) | 148 | if(lines > 0) |
181 | drawmenuv(); | 149 | drawmenuv(); |
182 | else if(curr) | 150 | else if(curr && (dc.w == inputw || curr->next)) |
183 | drawmenuh(); | 151 | drawmenuh(); |
184 | commitdraw(&dc, win); | 152 | commitdraw(&dc, win); |
185 | } | 153 | } |
186 | 154 | ||
187 | void | 155 | void |
188 | drawmenuh(void) { | 156 | drawmenuh(void) { |
189 | Item *i; | 157 | Item *item; |
190 | 158 | ||
191 | dc.x += cmdw; | 159 | dc.x += inputw; |
192 | dc.w = textw(&dc, "<"); | 160 | dc.w = textw(&dc, "<"); |
193 | drawtext(&dc, curr->left ? "<" : NULL, normcol); | 161 | if(curr->left) |
162 | drawtext(&dc, "<", normcol); | ||
194 | dc.x += dc.w; | 163 | dc.x += dc.w; |
195 | for(i = curr; i != next; i = i->right) { | 164 | for(item = curr; item != next; item = item->right) { |
196 | dc.w = MIN(textw(&dc, i->text), mw / 3); | 165 | dc.w = MIN(textw(&dc, item->text), mw / 3); |
197 | drawitem(i->text, (sel == i) ? selcol : normcol); | 166 | if(item == sel) |
167 | drawbox(&dc, selcol); | ||
168 | drawtext(&dc, item->text, (item == sel) ? selcol : normcol); | ||
198 | dc.x += dc.w; | 169 | dc.x += dc.w; |
199 | } | 170 | } |
200 | dc.w = textw(&dc, ">"); | 171 | dc.w = textw(&dc, ">"); |
201 | dc.x = mw - dc.w; | 172 | dc.x = mw - dc.w; |
202 | drawtext(&dc, next ? ">" : NULL, normcol); | 173 | if(next) |
174 | drawtext(&dc, ">", normcol); | ||
203 | } | 175 | } |
204 | 176 | ||
205 | void | 177 | void |
206 | drawmenuv(void) { | 178 | drawmenuv(void) { |
207 | Item *i; | 179 | Item *item; |
208 | XWindowAttributes wa; | 180 | XWindowAttributes wa; |
209 | 181 | ||
210 | dc.y = topbar ? dc.h : 0; | 182 | dc.y = topbar ? dc.h : 0; |
211 | dc.w = mw - dc.x; | 183 | dc.w = mw - dc.x; |
212 | for(i = curr; i != next; i = i->right) { | 184 | for(item = curr; item != next; item = item->right) { |
213 | drawitem(i->text, (sel == i) ? selcol : normcol); | 185 | if(item == sel) |
186 | drawbox(&dc, selcol); | ||
187 | drawtext(&dc, item->text, (item == sel) ? selcol : normcol); | ||
214 | dc.y += dc.h; | 188 | dc.y += dc.h; |
215 | } | 189 | } |
216 | if(!XGetWindowAttributes(dpy, win, &wa)) | 190 | if(!XGetWindowAttributes(dc.dpy, win, &wa)) |
217 | eprint("cannot get window attributes"); | 191 | eprintf("cannot get window attributes\n"); |
218 | XMoveResizeWindow(dpy, win, wa.x, wa.y + (topbar ? 0 : wa.height - mh), mw, mh); | 192 | if(wa.height != mh) |
193 | XMoveResizeWindow(dc.dpy, win, wa.x, wa.y + (topbar ? 0 : wa.height - mh), mw, mh); | ||
219 | } | 194 | } |
220 | 195 | ||
221 | void | 196 | void |
222 | grabkeyboard(void) { | 197 | grabkeyboard(void) { |
223 | unsigned int n; | 198 | int i; |
224 | 199 | ||
225 | for(n = 0; n < 1000; n++) { | 200 | for(i = 0; i < 1000; i++) { |
226 | if(!XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime)) | 201 | if(!XGrabKeyboard(dc.dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime)) |
227 | return; | 202 | return; |
228 | usleep(1000); | 203 | usleep(1000); |
229 | } | 204 | } |
230 | exit(EXIT_FAILURE); | 205 | eprintf("cannot grab keyboard\n"); |
206 | } | ||
207 | |||
208 | void | ||
209 | insert(const char *s, ssize_t n) { | ||
210 | memmove(text + cursor + n, text + cursor, sizeof text - cursor - n); | ||
211 | if(n > 0) | ||
212 | memcpy(text + cursor, s, n); | ||
213 | cursor += n; | ||
214 | match(); | ||
231 | } | 215 | } |
232 | 216 | ||
233 | void | 217 | void |
234 | keypress(XKeyEvent *e) { | 218 | keypress(XKeyEvent *e) { |
235 | char buf[sizeof text]; | 219 | char buf[sizeof text]; |
236 | int num; | 220 | int n; |
237 | unsigned int i, len; | 221 | size_t len; |
238 | KeySym ksym; | 222 | KeySym ksym; |
239 | 223 | ||
240 | len = strlen(text); | 224 | len = strlen(text); |
241 | num = XLookupString(e, buf, sizeof buf, &ksym, NULL); | 225 | XLookupString(e, buf, sizeof buf, &ksym, NULL); |
242 | if(ksym == XK_KP_Enter) | ||
243 | ksym = XK_Return; | ||
244 | else if(ksym >= XK_KP_0 && ksym <= XK_KP_9) | ||
245 | ksym = (ksym - XK_KP_0) + XK_0; | ||
246 | else if(IsFunctionKey(ksym) || IsKeypadKey(ksym) | ||
247 | || IsMiscFunctionKey(ksym) || IsPFKey(ksym) | ||
248 | || IsPrivateKeypadKey(ksym)) | ||
249 | return; | ||
250 | /* first check if a control mask is omitted */ | ||
251 | if(e->state & ControlMask) { | 226 | if(e->state & ControlMask) { |
252 | switch(tolower(ksym)) { | 227 | switch(tolower(ksym)) { |
253 | default: | 228 | default: |
@@ -277,8 +252,8 @@ keypress(XKeyEvent *e) { | |||
277 | case XK_m: | 252 | case XK_m: |
278 | ksym = XK_Return; | 253 | ksym = XK_Return; |
279 | break; | 254 | break; |
280 | case XK_k: | 255 | case XK_k: /* delete right */ |
281 | text[cur] = '\0'; | 256 | text[cursor] = '\0'; |
282 | break; | 257 | break; |
283 | case XK_n: | 258 | case XK_n: |
284 | ksym = XK_Down; | 259 | ksym = XK_Down; |
@@ -286,66 +261,44 @@ keypress(XKeyEvent *e) { | |||
286 | case XK_p: | 261 | case XK_p: |
287 | ksym = XK_Up; | 262 | ksym = XK_Up; |
288 | break; | 263 | break; |
289 | case XK_u: | 264 | case XK_u: /* delete left */ |
290 | memmove(text, text + cur, sizeof text - cur + 1); | 265 | insert(NULL, -cursor); |
291 | cur = 0; | ||
292 | match(); | ||
293 | break; | 266 | break; |
294 | case XK_w: | 267 | case XK_w: /* delete word */ |
295 | if(cur == 0) | 268 | if(cursor == 0) |
296 | return; | 269 | return; |
297 | i = cur; | 270 | n = 0; |
298 | while(i-- > 0 && text[i] == ' '); | 271 | while(cursor - n++ > 0 && text[cursor - n] == ' '); |
299 | while(i-- > 0 && text[i] != ' '); | 272 | while(cursor - n++ > 0 && text[cursor - n] != ' '); |
300 | memmove(text + i + 1, text + cur, sizeof text - cur + 1); | 273 | insert(NULL, -(--n)); |
301 | cur = i + 1; | ||
302 | match(); | ||
303 | break; | ||
304 | case XK_y: | ||
305 | { | ||
306 | FILE *fp; | ||
307 | char *s; | ||
308 | if(!(fp = fopen("sselp", "r"))) | ||
309 | eprint("cannot popen sselp\n"); | ||
310 | s = fgets(buf, sizeof buf, fp); | ||
311 | fclose(fp); | ||
312 | if(!s) | ||
313 | return; | ||
314 | } | ||
315 | num = strlen(buf); | ||
316 | if(num && buf[num-1] == '\n') | ||
317 | buf[--num] = '\0'; | ||
318 | break; | 274 | break; |
275 | case XK_y: /* paste selection */ | ||
276 | XConvertSelection(dc.dpy, XA_PRIMARY, utf8, None, win, CurrentTime); | ||
277 | /* causes SelectionNotify event */ | ||
278 | return; | ||
319 | } | 279 | } |
320 | } | 280 | } |
321 | switch(ksym) { | 281 | switch(ksym) { |
322 | default: | 282 | default: |
323 | num = MIN(num, sizeof text); | 283 | if(!iscntrl((int)*buf)) |
324 | if(num && !iscntrl((int) buf[0])) { | 284 | insert(buf, MIN(strlen(buf), sizeof text - cursor)); |
325 | memmove(text + cur + num, text + cur, sizeof text - cur - num); | ||
326 | memcpy(text + cur, buf, num); | ||
327 | cur += num; | ||
328 | match(); | ||
329 | } | ||
330 | break; | 285 | break; |
331 | case XK_BackSpace: | 286 | case XK_BackSpace: |
332 | if(cur == 0) | 287 | if(cursor == 0) |
333 | return; | 288 | return; |
334 | for(i = 1; len - i > 0 && !IS_UTF8_1ST_CHAR(text[cur - i]); i++); | 289 | for(n = 1; cursor - n > 0 && !UTF8_CODEPOINT(text[cursor - n]); n++); |
335 | memmove(text + cur - i, text + cur, sizeof text - cur + i); | 290 | insert(NULL, -n); |
336 | cur -= i; | ||
337 | match(); | ||
338 | break; | 291 | break; |
339 | case XK_Delete: | 292 | case XK_Delete: |
340 | if(cur == len) | 293 | if(cursor == len) |
341 | return; | 294 | return; |
342 | for(i = 1; cur + i < len && !IS_UTF8_1ST_CHAR(text[cur + i]); i++); | 295 | for(n = 1; cursor + n < len && !UTF8_CODEPOINT(text[cursor + n]); n++); |
343 | memmove(text + cur, text + cur + i, sizeof text - cur); | 296 | cursor += n; |
344 | match(); | 297 | insert(NULL, -n); |
345 | break; | 298 | break; |
346 | case XK_End: | 299 | case XK_End: |
347 | if(cur < len) { | 300 | if(cursor < len) { |
348 | cur = len; | 301 | cursor = len; |
349 | break; | 302 | break; |
350 | } | 303 | } |
351 | while(next) { | 304 | while(next) { |
@@ -358,19 +311,19 @@ keypress(XKeyEvent *e) { | |||
358 | case XK_Escape: | 311 | case XK_Escape: |
359 | exit(EXIT_FAILURE); | 312 | exit(EXIT_FAILURE); |
360 | case XK_Home: | 313 | case XK_Home: |
361 | if(sel == item) { | 314 | if(sel == matches) { |
362 | cur = 0; | 315 | cursor = 0; |
363 | break; | 316 | break; |
364 | } | 317 | } |
365 | sel = curr = item; | 318 | sel = curr = matches; |
366 | calcoffsets(); | 319 | calcoffsets(); |
367 | break; | 320 | break; |
368 | case XK_Left: | 321 | case XK_Left: |
369 | if(cur > 0 && (!sel || !sel->left || lines > 0)) { | 322 | if(cursor > 0 && (!sel || !sel->left || lines > 0)) { |
370 | while(cur-- > 0 && !IS_UTF8_1ST_CHAR(text[cur])); | 323 | while(cursor-- > 0 && !UTF8_CODEPOINT(text[cursor])); |
371 | break; | 324 | break; |
372 | } | 325 | } |
373 | if(lines > 0) | 326 | else if(lines > 0) |
374 | return; | 327 | return; |
375 | case XK_Up: | 328 | case XK_Up: |
376 | if(!sel || !sel->left) | 329 | if(!sel || !sel->left) |
@@ -394,15 +347,16 @@ keypress(XKeyEvent *e) { | |||
394 | calcoffsets(); | 347 | calcoffsets(); |
395 | break; | 348 | break; |
396 | case XK_Return: | 349 | case XK_Return: |
397 | fprintf(stdout, "%s", ((e->state & ShiftMask) || sel) ? sel->text : text); | 350 | case XK_KP_Enter: |
351 | fputs(((e->state & ShiftMask) || sel) ? sel->text : text, stdout); | ||
398 | fflush(stdout); | 352 | fflush(stdout); |
399 | exit(EXIT_SUCCESS); | 353 | exit(EXIT_SUCCESS); |
400 | case XK_Right: | 354 | case XK_Right: |
401 | if(cur < len) { | 355 | if(cursor < len) { |
402 | while(cur++ < len && !IS_UTF8_1ST_CHAR(text[cur])); | 356 | while(cursor++ < len && !UTF8_CODEPOINT(text[cursor])); |
403 | break; | 357 | break; |
404 | } | 358 | } |
405 | if(lines > 0) | 359 | else if(lines > 0) |
406 | return; | 360 | return; |
407 | case XK_Down: | 361 | case XK_Down: |
408 | if(!sel || !sel->right) | 362 | if(!sel || !sel->right) |
@@ -417,7 +371,7 @@ keypress(XKeyEvent *e) { | |||
417 | if(!sel) | 371 | if(!sel) |
418 | return; | 372 | return; |
419 | strncpy(text, sel->text, sizeof text); | 373 | strncpy(text, sel->text, sizeof text); |
420 | cur = strlen(text); | 374 | cursor = strlen(text); |
421 | match(); | 375 | match(); |
422 | break; | 376 | break; |
423 | } | 377 | } |
@@ -427,19 +381,19 @@ keypress(XKeyEvent *e) { | |||
427 | void | 381 | void |
428 | match(void) { | 382 | match(void) { |
429 | unsigned int len; | 383 | unsigned int len; |
430 | Item *i, *itemend, *lexact, *lprefix, *lsubstr, *exactend, *prefixend, *substrend; | 384 | Item *item, *itemend, *lexact, *lprefix, *lsubstr, *exactend, *prefixend, *substrend; |
431 | 385 | ||
432 | len = strlen(text); | 386 | len = strlen(text); |
433 | item = lexact = lprefix = lsubstr = itemend = exactend = prefixend = substrend = NULL; | 387 | matches = lexact = lprefix = lsubstr = itemend = exactend = prefixend = substrend = NULL; |
434 | for(i = allitems; i; i = i->next) | 388 | for(item = allitems; item; item = item->next) |
435 | if(!fstrncmp(text, i->text, len + 1)) | 389 | if(!fstrncmp(text, item->text, len + 1)) |
436 | appenditem(i, &lexact, &exactend); | 390 | appenditem(item, &lexact, &exactend); |
437 | else if(!fstrncmp(text, i->text, len)) | 391 | else if(!fstrncmp(text, item->text, len)) |
438 | appenditem(i, &lprefix, &prefixend); | 392 | appenditem(item, &lprefix, &prefixend); |
439 | else if(fstrstr(i->text, text)) | 393 | else if(fstrstr(item->text, text)) |
440 | appenditem(i, &lsubstr, &substrend); | 394 | appenditem(item, &lsubstr, &substrend); |
441 | if(lexact) { | 395 | if(lexact) { |
442 | item = lexact; | 396 | matches = lexact; |
443 | itemend = exactend; | 397 | itemend = exactend; |
444 | } | 398 | } |
445 | if(lprefix) { | 399 | if(lprefix) { |
@@ -448,7 +402,7 @@ match(void) { | |||
448 | lprefix->left = itemend; | 402 | lprefix->left = itemend; |
449 | } | 403 | } |
450 | else | 404 | else |
451 | item = lprefix; | 405 | matches = lprefix; |
452 | itemend = prefixend; | 406 | itemend = prefixend; |
453 | } | 407 | } |
454 | if(lsubstr) { | 408 | if(lsubstr) { |
@@ -457,36 +411,48 @@ match(void) { | |||
457 | lsubstr->left = itemend; | 411 | lsubstr->left = itemend; |
458 | } | 412 | } |
459 | else | 413 | else |
460 | item = lsubstr; | 414 | matches = lsubstr; |
461 | } | 415 | } |
462 | curr = prev = next = sel = item; | 416 | curr = prev = next = sel = matches; |
463 | calcoffsets(); | 417 | calcoffsets(); |
464 | } | 418 | } |
465 | 419 | ||
466 | void | 420 | void |
421 | paste(Atom atom) | ||
422 | { | ||
423 | char *p, *q; | ||
424 | int di; | ||
425 | unsigned long dl; | ||
426 | Atom da; | ||
427 | |||
428 | XGetWindowProperty(dc.dpy, win, atom, 0, sizeof text - cursor, True, | ||
429 | utf8, &da, &di, &dl, &dl, (unsigned char **)&p); | ||
430 | insert(p, (q = strchr(p, '\n')) ? q-p : strlen(p)); | ||
431 | XFree(p); | ||
432 | drawmenu(); | ||
433 | } | ||
434 | |||
435 | void | ||
467 | readstdin(void) { | 436 | readstdin(void) { |
468 | char *p, buf[sizeof text]; | 437 | char buf[sizeof text]; |
469 | unsigned int len = 0, max = 0; | 438 | size_t len; |
470 | Item *i, *new; | 439 | Item *item, *new; |
471 | 440 | ||
472 | i = NULL; | 441 | allitems = NULL; |
473 | while(fgets(buf, sizeof buf, stdin)) { | 442 | for(item = NULL; fgets(buf, sizeof buf, stdin); item = new) { |
474 | len = strlen(buf); | 443 | len = strlen(buf); |
475 | if(buf[len-1] == '\n') | 444 | if(buf[len-1] == '\n') |
476 | buf[--len] = '\0'; | 445 | buf[--len] = '\0'; |
477 | if(!(p = strdup(buf))) | ||
478 | eprint("cannot strdup %u bytes\n", len); | ||
479 | if((max = MAX(max, len)) == len) | ||
480 | maxname = p; | ||
481 | if(!(new = malloc(sizeof *new))) | 446 | if(!(new = malloc(sizeof *new))) |
482 | eprint("cannot malloc %u bytes\n", sizeof *new); | 447 | eprintf("cannot malloc %u bytes\n", sizeof *new); |
448 | if(!(new->text = strdup(buf))) | ||
449 | eprintf("cannot strdup %u bytes\n", len); | ||
450 | inputw = MAX(inputw, textw(&dc, new->text)); | ||
483 | new->next = new->left = new->right = NULL; | 451 | new->next = new->left = new->right = NULL; |
484 | new->text = p; | 452 | if(item) |
485 | if(!i) | 453 | item->next = new; |
486 | allitems = new; | ||
487 | else | 454 | else |
488 | i->next = new; | 455 | allitems = new; |
489 | i = new; | ||
490 | } | 456 | } |
491 | } | 457 | } |
492 | 458 | ||
@@ -494,8 +460,7 @@ void | |||
494 | run(void) { | 460 | run(void) { |
495 | XEvent ev; | 461 | XEvent ev; |
496 | 462 | ||
497 | XSync(dpy, False); | 463 | while(!XNextEvent(dc.dpy, &ev)) |
498 | while(!XNextEvent(dpy, &ev)) | ||
499 | switch(ev.type) { | 464 | switch(ev.type) { |
500 | case Expose: | 465 | case Expose: |
501 | if(ev.xexpose.count == 0) | 466 | if(ev.xexpose.count == 0) |
@@ -504,62 +469,45 @@ run(void) { | |||
504 | case KeyPress: | 469 | case KeyPress: |
505 | keypress(&ev.xkey); | 470 | keypress(&ev.xkey); |
506 | break; | 471 | break; |
472 | case SelectionNotify: | ||
473 | if(ev.xselection.property != None) | ||
474 | paste(ev.xselection.property); | ||
475 | break; | ||
507 | case VisibilityNotify: | 476 | case VisibilityNotify: |
508 | if(ev.xvisibility.state != VisibilityUnobscured) | 477 | if(ev.xvisibility.state != VisibilityUnobscured) |
509 | XRaiseWindow(dpy, win); | 478 | XRaiseWindow(dc.dpy, win); |
510 | break; | 479 | break; |
511 | } | 480 | } |
512 | exit(EXIT_FAILURE); | ||
513 | } | 481 | } |
514 | 482 | ||
515 | void | 483 | void |
516 | setup(void) { | 484 | setup(void) { |
517 | int i, j, x, y; | 485 | int x, y; |
518 | #if XINERAMA | 486 | #ifdef XINERAMA |
519 | int n; | 487 | int i, n; |
520 | XineramaScreenInfo *info = NULL; | 488 | XineramaScreenInfo *info; |
521 | #endif | 489 | #endif |
522 | XModifierKeymap *modmap; | ||
523 | XSetWindowAttributes wa; | 490 | XSetWindowAttributes wa; |
524 | 491 | ||
525 | /* init modifier map */ | ||
526 | modmap = XGetModifierMapping(dpy); | ||
527 | for(i = 0; i < 8; i++) | ||
528 | for(j = 0; j < modmap->max_keypermod; j++) { | ||
529 | if(modmap->modifiermap[i * modmap->max_keypermod + j] | ||
530 | == XKeysymToKeycode(dpy, XK_Num_Lock)) | ||
531 | numlockmask = (1 << i); | ||
532 | } | ||
533 | XFreeModifiermap(modmap); | ||
534 | |||
535 | dc.dpy = dpy; | ||
536 | normcol[ColBG] = getcolor(&dc, normbgcolor); | 492 | normcol[ColBG] = getcolor(&dc, normbgcolor); |
537 | normcol[ColFG] = getcolor(&dc, normfgcolor); | 493 | normcol[ColFG] = getcolor(&dc, normfgcolor); |
538 | selcol[ColBG] = getcolor(&dc, selbgcolor); | 494 | selcol[ColBG] = getcolor(&dc, selbgcolor); |
539 | selcol[ColFG] = getcolor(&dc, selfgcolor); | 495 | selcol[ColFG] = getcolor(&dc, selfgcolor); |
540 | initfont(&dc, font); | ||
541 | |||
542 | /* input window */ | ||
543 | wa.override_redirect = True; | ||
544 | wa.background_pixmap = ParentRelative; | ||
545 | wa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; | ||
546 | 496 | ||
547 | /* input window geometry */ | 497 | /* input window geometry */ |
548 | mh = (dc.font.height + 2) * (lines + 1); | 498 | mh = (dc.font.height + 2) * (lines + 1); |
549 | #if XINERAMA | 499 | #ifdef XINERAMA |
550 | if(XineramaIsActive(dpy) && (info = XineramaQueryScreens(dpy, &n))) { | 500 | if((info = XineramaQueryScreens(dc.dpy, &n))) { |
551 | i = 0; | 501 | int di; |
552 | if(n > 1) { | 502 | unsigned int du; |
553 | int di; | 503 | Window dw; |
554 | unsigned int dui; | 504 | |
555 | Window dummy; | 505 | XQueryPointer(dc.dpy, root, &dw, &dw, &x, &y, &di, &di, &du); |
556 | if(XQueryPointer(dpy, root, &dummy, &dummy, &x, &y, &di, &di, &dui)) | 506 | for(i = 0; i < n; i++) |
557 | for(i = 0; i < n; i++) | 507 | if(INRECT(x, y, info[i].x_org, info[i].y_org, info[i].width, info[i].height)) |
558 | if(INRECT(x, y, info[i].x_org, info[i].y_org, info[i].width, info[i].height)) | 508 | break; |
559 | break; | ||
560 | } | ||
561 | x = info[i].x_org; | 509 | x = info[i].x_org; |
562 | y = topbar ? info[i].y_org : info[i].y_org + info[i].height - mh; | 510 | y = info[i].y_org + (topbar ? 0 : info[i].height - mh); |
563 | mw = info[i].width; | 511 | mw = info[i].width; |
564 | XFree(info); | 512 | XFree(info); |
565 | } | 513 | } |
@@ -567,84 +515,86 @@ setup(void) { | |||
567 | #endif | 515 | #endif |
568 | { | 516 | { |
569 | x = 0; | 517 | x = 0; |
570 | y = topbar ? 0 : DisplayHeight(dpy, screen) - mh; | 518 | y = topbar ? 0 : DisplayHeight(dc.dpy, screen) - mh; |
571 | mw = DisplayWidth(dpy, screen); | 519 | mw = DisplayWidth(dc.dpy, screen); |
572 | } | 520 | } |
573 | 521 | ||
574 | win = XCreateWindow(dpy, root, x, y, mw, mh, 0, | 522 | /* input window */ |
575 | DefaultDepth(dpy, screen), CopyFromParent, | 523 | wa.override_redirect = True; |
576 | DefaultVisual(dpy, screen), | 524 | wa.background_pixmap = ParentRelative; |
525 | 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), | ||
577 | CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); | 529 | CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); |
578 | 530 | ||
531 | match(); | ||
532 | grabkeyboard(); | ||
579 | setupdraw(&dc, win); | 533 | setupdraw(&dc, win); |
580 | if(prompt) | 534 | inputw = MIN(inputw, mw / 3); |
581 | promptw = MIN(textw(&dc, prompt), mw / 5); | 535 | utf8 = XInternAtom(dc.dpy, "UTF8_STRING", False); |
582 | XMapRaised(dpy, win); | 536 | XMapRaised(dc.dpy, win); |
537 | } | ||
538 | |||
539 | void | ||
540 | 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); | ||
543 | exit(EXIT_FAILURE); | ||
583 | } | 544 | } |
584 | 545 | ||
585 | int | 546 | int |
586 | main(int argc, char *argv[]) { | 547 | main(int argc, char *argv[]) { |
587 | unsigned int i; | 548 | int i; |
588 | 549 | ||
589 | /* command line args */ | ||
590 | progname = "dmenu"; | 550 | progname = "dmenu"; |
591 | for(i = 1; i < argc; i++) | 551 | for(i = 1; i < argc; i++) |
592 | if(!strcmp(argv[i], "-i")) { | 552 | /* 1-arg flags */ |
593 | fstrncmp = strncasecmp; | 553 | if(!strcmp(argv[i], "-v")) { |
594 | fstrstr = cistrstr; | 554 | fputs("dmenu-"VERSION", © 2006-2010 dmenu engineers, see LICENSE for details\n", stdout); |
555 | exit(EXIT_SUCCESS); | ||
595 | } | 556 | } |
596 | else if(!strcmp(argv[i], "-b")) | 557 | else if(!strcmp(argv[i], "-b")) |
597 | topbar = False; | 558 | topbar = False; |
559 | else if(!strcmp(argv[i], "-i")) { | ||
560 | fstrncmp = strncasecmp; | ||
561 | fstrstr = cistrstr; | ||
562 | } | ||
563 | else if(i == argc-1) | ||
564 | usage(); | ||
565 | /* 2-arg flags */ | ||
598 | else if(!strcmp(argv[i], "-l")) { | 566 | else if(!strcmp(argv[i], "-l")) { |
599 | if(++i < argc) lines = atoi(argv[i]); | 567 | if((lines = atoi(argv[++i])) > 0) |
600 | if(lines > 0) | ||
601 | calcoffsets = calcoffsetsv; | 568 | calcoffsets = calcoffsetsv; |
602 | } | 569 | } |
603 | else if(!strcmp(argv[i], "-fn")) { | ||
604 | if(++i < argc) font = argv[i]; | ||
605 | } | ||
606 | else if(!strcmp(argv[i], "-nb")) { | ||
607 | if(++i < argc) normbgcolor = argv[i]; | ||
608 | } | ||
609 | else if(!strcmp(argv[i], "-nf")) { | ||
610 | if(++i < argc) normfgcolor = argv[i]; | ||
611 | } | ||
612 | else if(!strcmp(argv[i], "-p")) { | 570 | else if(!strcmp(argv[i], "-p")) { |
613 | if(++i < argc) prompt = argv[i]; | 571 | prompt = argv[++i]; |
614 | } | 572 | promptw = MIN(textw(&dc, prompt), mw/5); |
615 | else if(!strcmp(argv[i], "-sb")) { | ||
616 | if(++i < argc) selbgcolor = argv[i]; | ||
617 | } | ||
618 | else if(!strcmp(argv[i], "-sf")) { | ||
619 | if(++i < argc) selfgcolor = argv[i]; | ||
620 | } | ||
621 | else if(!strcmp(argv[i], "-v")) { | ||
622 | printf("dmenu-"VERSION", © 2006-2010 dmenu engineers, see LICENSE for details\n"); | ||
623 | exit(EXIT_SUCCESS); | ||
624 | } | ||
625 | else { | ||
626 | fputs("usage: dmenu [-i] [-b] [-l <lines>] [-fn <font>] [-nb <color>]\n" | ||
627 | " [-nf <color>] [-p <prompt>] [-sb <color>] [-sf <color>] [-v]\n", stderr); | ||
628 | exit(EXIT_FAILURE); | ||
629 | } | 573 | } |
574 | else if(!strcmp(argv[i], "-fn")) | ||
575 | font = argv[++i]; | ||
576 | else if(!strcmp(argv[i], "-nb")) | ||
577 | normbgcolor = argv[++i]; | ||
578 | else if(!strcmp(argv[i], "-nf")) | ||
579 | normfgcolor = argv[++i]; | ||
580 | else if(!strcmp(argv[i], "-sb")) | ||
581 | selbgcolor = argv[++i]; | ||
582 | else if(!strcmp(argv[i], "-sf")) | ||
583 | selfgcolor = argv[++i]; | ||
584 | else | ||
585 | usage(); | ||
586 | |||
630 | if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) | 587 | if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) |
631 | fprintf(stderr, "dmenu: warning: no locale support\n"); | 588 | fputs("dmenu: warning: no locale support\n", stderr); |
632 | if(!(dpy = XOpenDisplay(NULL))) | 589 | if(!(dc.dpy = XOpenDisplay(NULL))) |
633 | eprint("cannot open display\n"); | 590 | eprintf("cannot open display\n"); |
634 | if(atexit(&cleanup) != 0) | 591 | screen = DefaultScreen(dc.dpy); |
635 | eprint("cannot register cleanup\n"); | 592 | root = RootWindow(dc.dpy, screen); |
636 | screen = DefaultScreen(dpy); | 593 | initfont(&dc, font); |
637 | root = RootWindow(dpy, screen); | ||
638 | if(!(argp = malloc(sizeof *argp * (argc+2)))) | ||
639 | eprint("cannot malloc %u bytes\n", sizeof *argp * (argc+2)); | ||
640 | memcpy(argp + 2, argv + 1, sizeof *argp * argc); | ||
641 | 594 | ||
642 | readstdin(); | 595 | readstdin(); |
643 | grabkeyboard(); | ||
644 | setup(); | 596 | setup(); |
645 | if(maxname) | ||
646 | cmdw = MIN(textw(&dc, maxname), mw / 3); | ||
647 | match(); | ||
648 | run(); | 597 | run(); |
649 | return 0; | 598 | |
599 | return EXIT_FAILURE; /* should not reach */ | ||
650 | } | 600 | } |