4bbc7bc891a27cd7b91cb9e983b969f797190a50
[dmenu.git] / dinput.c
1 /* See LICENSE file for copyright and license details. */
2 #include <ctype.h>
3 #include <locale.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <X11/keysym.h>
8 #include <X11/Xlib.h>
9 #include <X11/Xutil.h>
10 #include "dmenu.h"
11
12 /* forward declarations */
13 static void cleanup(void);
14
15 /* variables */
16 static size_t cursor = 0;
17
18 void
19 cleanup(void) {
20         cleanupdraw(&dc);
21         XDestroyWindow(dpy, win);
22         XUngrabKeyboard(dpy, CurrentTime);
23         XCloseDisplay(dpy);
24 }
25
26 void
27 drawbar(void)
28 {
29         dc.x = 0;
30         dc.y = 0;
31         dc.w = mw;
32         dc.h = mh;
33         drawbox(&dc, normcol);
34         /* print prompt? */
35         if(prompt) {
36                 dc.w = promptw;
37                 drawbox(&dc, selcol);
38                 drawtext(&dc, prompt, selcol);
39                 dc.x += dc.w;
40         }
41         dc.w = mw - dc.x;
42         drawtext(&dc, text, normcol);
43         drawline(&dc, textnw(&dc, text, cursor) + dc.font.height/2, 2, 1,
44                         dc.font.height-2, normcol);
45         commitdraw(&dc, win);
46 }
47
48 void
49 kpress(XKeyEvent *e) {
50         char buf[sizeof text];
51         int num;
52         unsigned int i, len;
53         KeySym ksym;
54
55         len = strlen(text);
56         num = XLookupString(e, buf, sizeof buf, &ksym, NULL);
57         if(ksym == XK_KP_Enter)
58                 ksym = XK_Return;
59         else if(ksym >= XK_KP_0 && ksym <= XK_KP_9)
60                 ksym = (ksym - XK_KP_0) + XK_0;
61         else if(IsFunctionKey(ksym) || IsKeypadKey(ksym)
62         || IsMiscFunctionKey(ksym) || IsPFKey(ksym)
63         || IsPrivateKeypadKey(ksym))
64                 return;
65         /* first check if a control mask is omitted */
66         if(e->state & ControlMask) {
67                 switch(tolower(ksym)) {
68                 default:
69                         return;
70                 case XK_a:
71                         ksym = XK_Home;
72                         break;
73                 case XK_b:
74                         ksym = XK_Left;
75                         break;
76                 case XK_c:
77                         ksym = XK_Escape;
78                         break;
79                 case XK_e:
80                         ksym = XK_End;
81                         break;
82                 case XK_f:
83                         ksym = XK_Right;
84                         break;
85                 case XK_h:
86                         ksym = XK_BackSpace;
87                         break;
88                 case XK_j:
89                 case XK_m:
90                         ksym = XK_Return;
91                         break;
92                 case XK_k:
93                         text[cursor] = '\0';
94                         break;
95                 case XK_u:
96                         memmove(text, text + cursor, sizeof text - cursor + 1);
97                         cursor = 0;
98                         break;
99                 case XK_w:
100                         if(cursor > 0) {
101                                 i = cursor;
102                                 while(i-- > 0 && text[i] == ' ');
103                                 while(i-- > 0 && text[i] != ' ');
104                                 memmove(text + i + 1, text + cursor, sizeof text - cursor + 1);
105                                 cursor = i + 1;
106                         }
107                         break;
108                 case XK_y:
109                         {
110                                 FILE *fp;
111                                 char *s;
112                                 if(!(fp = popen("sselp", "r")))
113                                         eprint("cannot popen sselp\n");
114                                 s = fgets(buf, sizeof buf, fp);
115                                 pclose(fp);
116                                 if(s == NULL)
117                                         return;
118                         }
119                         num = strlen(buf);
120                         if(num && buf[num-1] == '\n')
121                                 buf[--num] = '\0';
122                         break;
123                 }
124         }
125         switch(ksym) {
126         default:
127                 num = MIN(num, sizeof text - cursor);
128                 if(num && !iscntrl((int) buf[0])) {
129                         memmove(text + cursor + num, text + cursor, sizeof text - cursor - num);
130                         memcpy(text + cursor, buf, num);
131                         cursor += num;
132                 }
133                 break;
134         case XK_BackSpace:
135                 if(cursor == 0)
136                         return;
137                 for(i = 1; cursor - i > 0 && !IS_UTF8_1ST_CHAR(text[cursor - i]); i++);
138                 memmove(text + cursor - i, text + cursor, sizeof text - cursor + i);
139                 cursor -= i;
140                 break;
141         case XK_Delete:
142                 if(cursor == len)
143                         return;
144                 for(i = 1; cursor + i < len && !IS_UTF8_1ST_CHAR(text[cursor + i]); i++);
145                 memmove(text + cursor, text + cursor + i, sizeof text - cursor);
146                 break;
147         case XK_End:
148                 cursor = len;
149                 break;
150         case XK_Escape:
151                 exit(EXIT_FAILURE);
152         case XK_Home:
153                 cursor = 0;
154                 break;
155         case XK_Left:
156                 if(cursor == 0)
157                         return;
158                 while(cursor-- > 0 && !IS_UTF8_1ST_CHAR(text[cursor]));
159                 break;
160         case XK_Return:
161                 fprintf(stdout, "%s", text);
162                 fflush(stdout);
163                 exit(EXIT_SUCCESS);
164         case XK_Right:
165                 if(cursor == len)
166                         return;
167                 while(cursor++ < len && !IS_UTF8_1ST_CHAR(text[cursor]));
168                 break;
169         }
170         drawbar();
171 }
172
173 int
174 main(int argc, char *argv[]) {
175         unsigned int i;
176
177         /* command line args */
178         progname = "dinput";
179         for(i = 1; i < argc; i++)
180                 if(!strcmp(argv[i], "-i"))
181                         ;  /* ignore flag */
182                 else if(!strcmp(argv[i], "-b"))
183                         topbar = False;
184                 else if(!strcmp(argv[i], "-l"))
185                         i++;  /* ignore flag */
186                 else if(!strcmp(argv[i], "-fn")) {
187                         if(++i < argc) font = argv[i];
188                 }
189                 else if(!strcmp(argv[i], "-nb")) {
190                         if(++i < argc) normbgcolor = argv[i];
191                 }
192                 else if(!strcmp(argv[i], "-nf")) {
193                         if(++i < argc) normfgcolor = argv[i];
194                 }
195                 else if(!strcmp(argv[i], "-p")) {
196                         if(++i < argc) prompt = argv[i];
197                 }
198                 else if(!strcmp(argv[i], "-sb")) {
199                         if(++i < argc) selbgcolor = argv[i];
200                 }
201                 else if(!strcmp(argv[i], "-sf")) {
202                         if(++i < argc) selfgcolor = argv[i];
203                 }
204                 else if(!strcmp(argv[i], "-v")) {
205                         printf("dinput-"VERSION", © 2006-2010 dmenu engineers, see LICENSE for details\n");
206                         exit(EXIT_SUCCESS);
207                 }
208                 else if(!*text) {
209                         strncpy(text, argv[i], sizeof text);
210                         cursor = strlen(text);
211                 }
212                 else {
213                         fputs("usage: dinput [-b] [-fn <font>] [-nb <color>] [-nf <color>]\n"
214                               "              [-p <prompt>] [-sb <color>] [-sf <color>] [-v] [<text>]\n", stderr);
215                         exit(EXIT_FAILURE);
216                 }
217         if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
218                 fprintf(stderr, "dinput: warning: no locale support\n");
219         if(!(dpy = XOpenDisplay(NULL)))
220                 eprint("cannot open display\n");
221         if(atexit(&cleanup) != 0)
222                 eprint("cannot register cleanup\n");
223         screen = DefaultScreen(dpy);
224         root = RootWindow(dpy, screen);
225
226         grabkeyboard();
227         setup(0);
228         run();
229         return 0;
230 }