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