initial dmenu / dinput separation
This commit is contained in:
		
							
								
								
									
										17
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								Makefile
									
									
									
									
									
								
							@@ -3,10 +3,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
include config.mk
 | 
					include config.mk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SRC = dmenu.c
 | 
					SRC = dinput.c dmenu.c draw.c
 | 
				
			||||||
OBJ = ${SRC:.c=.o}
 | 
					OBJ = ${SRC:.c=.o}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
all: options dmenu
 | 
					all: options dinput dmenu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
options:
 | 
					options:
 | 
				
			||||||
	@echo dmenu build options:
 | 
						@echo dmenu build options:
 | 
				
			||||||
@@ -18,19 +18,19 @@ options:
 | 
				
			|||||||
	@echo CC $<
 | 
						@echo CC $<
 | 
				
			||||||
	@${CC} -c ${CFLAGS} $<
 | 
						@${CC} -c ${CFLAGS} $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
${OBJ}: config.h config.mk
 | 
					${OBJ}: config.h config.mk draw.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config.h:
 | 
					config.h:
 | 
				
			||||||
	@echo creating $@ from config.def.h
 | 
						@echo creating $@ from config.def.h
 | 
				
			||||||
	@cp config.def.h $@
 | 
						@cp config.def.h $@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dmenu: ${OBJ}
 | 
					.o:
 | 
				
			||||||
	@echo CC -o $@
 | 
						@echo CC -o $@
 | 
				
			||||||
	@${CC} -o $@ ${OBJ} ${LDFLAGS}
 | 
						@${CC} -o $@ $< ${LDFLAGS}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
clean:
 | 
					clean:
 | 
				
			||||||
	@echo cleaning
 | 
						@echo cleaning
 | 
				
			||||||
	@rm -f dmenu ${OBJ} dmenu-${VERSION}.tar.gz
 | 
						@rm -f dinput dmenu ${OBJ} dmenu-${VERSION}.tar.gz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dist: clean
 | 
					dist: clean
 | 
				
			||||||
	@echo creating dist tarball
 | 
						@echo creating dist tarball
 | 
				
			||||||
@@ -43,7 +43,8 @@ dist: clean
 | 
				
			|||||||
install: all
 | 
					install: all
 | 
				
			||||||
	@echo installing executable file to ${DESTDIR}${PREFIX}/bin
 | 
						@echo installing executable file to ${DESTDIR}${PREFIX}/bin
 | 
				
			||||||
	@mkdir -p ${DESTDIR}${PREFIX}/bin
 | 
						@mkdir -p ${DESTDIR}${PREFIX}/bin
 | 
				
			||||||
	@cp -f dmenu dmenu_path dmenu_run ${DESTDIR}${PREFIX}/bin
 | 
						@cp -f dinput dmenu dmenu_path dmenu_run ${DESTDIR}${PREFIX}/bin
 | 
				
			||||||
 | 
						@chmod 755 ${DESTDIR}${PREFIX}/bin/dinput
 | 
				
			||||||
	@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu
 | 
						@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu
 | 
				
			||||||
	@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu_path
 | 
						@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu_path
 | 
				
			||||||
	@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu_run
 | 
						@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu_run
 | 
				
			||||||
@@ -55,7 +56,7 @@ install: all
 | 
				
			|||||||
uninstall:
 | 
					uninstall:
 | 
				
			||||||
	@echo removing executable file from ${DESTDIR}${PREFIX}/bin
 | 
						@echo removing executable file from ${DESTDIR}${PREFIX}/bin
 | 
				
			||||||
	@rm -f ${DESTDIR}${PREFIX}/bin/dmenu ${DESTDIR}${PREFIX}/bin/dmenu_path
 | 
						@rm -f ${DESTDIR}${PREFIX}/bin/dmenu ${DESTDIR}${PREFIX}/bin/dmenu_path
 | 
				
			||||||
	@rm -f ${DESTDIR}${PREFIX}/bin/dmenu ${DESTDIR}${PREFIX}/bin/dmenu_run
 | 
						@rm -f ${DESTDIR}${PREFIX}/bin/dinput ${DESTDIR}${PREFIX}/bin/dmenu_run
 | 
				
			||||||
	@echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
 | 
						@echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
 | 
				
			||||||
	@rm -f ${DESTDIR}${MANPREFIX}/man1/dmenu.1
 | 
						@rm -f ${DESTDIR}${MANPREFIX}/man1/dmenu.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										387
									
								
								dinput.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										387
									
								
								dinput.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,387 @@
 | 
				
			|||||||
 | 
					/* See LICENSE file for copyright and license details. */
 | 
				
			||||||
 | 
					#include <ctype.h>
 | 
				
			||||||
 | 
					#include <locale.h>
 | 
				
			||||||
 | 
					#include <stdarg.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <strings.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <X11/keysym.h>
 | 
				
			||||||
 | 
					#include <X11/Xlib.h>
 | 
				
			||||||
 | 
					#include <X11/Xutil.h>
 | 
				
			||||||
 | 
					#ifdef XINERAMA
 | 
				
			||||||
 | 
					#include <X11/extensions/Xinerama.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* macros */
 | 
				
			||||||
 | 
					#define CLEANMASK(mask)         (mask & ~(numlockmask | LockMask))
 | 
				
			||||||
 | 
					#define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH))
 | 
				
			||||||
 | 
					#define MIN(a, b)               ((a) < (b) ? (a) : (b))
 | 
				
			||||||
 | 
					#define MAX(a, b)               ((a) > (b) ? (a) : (b))
 | 
				
			||||||
 | 
					#define IS_UTF8_1ST_CHAR(c)     ((((c) & 0xc0) == 0xc0) || !((c) & 0x80))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* forward declarations */
 | 
				
			||||||
 | 
					static void cleanup(void);
 | 
				
			||||||
 | 
					static void drawcursor(void);
 | 
				
			||||||
 | 
					static void drawinput(void);
 | 
				
			||||||
 | 
					static void eprint(const char *errstr, ...);
 | 
				
			||||||
 | 
					static Bool grabkeyboard(void);
 | 
				
			||||||
 | 
					static void kpress(XKeyEvent * e);
 | 
				
			||||||
 | 
					static void run(void);
 | 
				
			||||||
 | 
					static void setup(Bool topbar);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* variables */
 | 
				
			||||||
 | 
					static char *prompt = NULL;
 | 
				
			||||||
 | 
					static char text[4096];
 | 
				
			||||||
 | 
					static int promptw = 0;
 | 
				
			||||||
 | 
					static int ret = 0;
 | 
				
			||||||
 | 
					static int screen;
 | 
				
			||||||
 | 
					static unsigned int mw, mh;
 | 
				
			||||||
 | 
					static unsigned int cursor = 0;
 | 
				
			||||||
 | 
					static unsigned int numlockmask = 0;
 | 
				
			||||||
 | 
					static Bool running = True;
 | 
				
			||||||
 | 
					static Display *dpy;
 | 
				
			||||||
 | 
					static Window parent, win;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "draw.c"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					cleanup(void) {
 | 
				
			||||||
 | 
						dccleanup();
 | 
				
			||||||
 | 
						XDestroyWindow(dpy, win);
 | 
				
			||||||
 | 
						XUngrabKeyboard(dpy, CurrentTime);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					drawcursor(void) {
 | 
				
			||||||
 | 
						XRectangle r = { dc.x, dc.y + 2, 1, dc.font.height - 2 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						r.x += textnw(text, cursor) + dc.font.height / 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						XSetForeground(dpy, dc.gc, dc.norm[ColFG]);
 | 
				
			||||||
 | 
						XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					drawinput(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						dc.x = 0;
 | 
				
			||||||
 | 
						dc.y = 0;
 | 
				
			||||||
 | 
						dc.w = mw;
 | 
				
			||||||
 | 
						dc.h = mh;
 | 
				
			||||||
 | 
						drawtext(NULL, dc.norm);
 | 
				
			||||||
 | 
						/* print prompt? */
 | 
				
			||||||
 | 
						if(prompt) {
 | 
				
			||||||
 | 
							dc.w = promptw;
 | 
				
			||||||
 | 
							drawtext(prompt, dc.sel);
 | 
				
			||||||
 | 
							dc.x += dc.w;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						dc.w = mw - dc.x;
 | 
				
			||||||
 | 
						drawtext(*text ? text : NULL, dc.norm);
 | 
				
			||||||
 | 
						drawcursor();
 | 
				
			||||||
 | 
						XCopyArea(dpy, dc.drawable, win, dc.gc, 0, 0, mw, mh, 0, 0);
 | 
				
			||||||
 | 
						XFlush(dpy);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					eprint(const char *errstr, ...) {
 | 
				
			||||||
 | 
						va_list ap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						va_start(ap, errstr);
 | 
				
			||||||
 | 
						vfprintf(stderr, errstr, ap);
 | 
				
			||||||
 | 
						va_end(ap);
 | 
				
			||||||
 | 
						exit(EXIT_FAILURE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Bool
 | 
				
			||||||
 | 
					grabkeyboard(void) {
 | 
				
			||||||
 | 
						unsigned int len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for(len = 1000; len; len--) {
 | 
				
			||||||
 | 
							if(XGrabKeyboard(dpy, parent, True, GrabModeAsync, GrabModeAsync, CurrentTime)
 | 
				
			||||||
 | 
							== GrabSuccess)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							usleep(1000);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return len > 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					kpress(XKeyEvent * e) {
 | 
				
			||||||
 | 
						char buf[sizeof text];
 | 
				
			||||||
 | 
						int num;
 | 
				
			||||||
 | 
						unsigned int i, len;
 | 
				
			||||||
 | 
						KeySym ksym;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						len = strlen(text);
 | 
				
			||||||
 | 
						num = XLookupString(e, buf, sizeof buf, &ksym, NULL);
 | 
				
			||||||
 | 
						if(ksym == XK_KP_Enter)
 | 
				
			||||||
 | 
							ksym = XK_Return;
 | 
				
			||||||
 | 
						else if(ksym >= XK_KP_0 && ksym <= XK_KP_9)
 | 
				
			||||||
 | 
							ksym = (ksym - XK_KP_0) + XK_0;
 | 
				
			||||||
 | 
						else if(IsFunctionKey(ksym) || IsKeypadKey(ksym)
 | 
				
			||||||
 | 
						|| IsMiscFunctionKey(ksym) || IsPFKey(ksym)
 | 
				
			||||||
 | 
						|| IsPrivateKeypadKey(ksym))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						/* first check if a control mask is omitted */
 | 
				
			||||||
 | 
						if(e->state & ControlMask) {
 | 
				
			||||||
 | 
							switch(tolower(ksym)) {
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							case XK_a:
 | 
				
			||||||
 | 
								ksym = XK_Home;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case XK_b:
 | 
				
			||||||
 | 
								ksym = XK_Left;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case XK_c:
 | 
				
			||||||
 | 
								ksym = XK_Escape;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case XK_e:
 | 
				
			||||||
 | 
								ksym = XK_End;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case XK_f:
 | 
				
			||||||
 | 
								ksym = XK_Right;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case XK_h:
 | 
				
			||||||
 | 
								ksym = XK_BackSpace;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case XK_j:
 | 
				
			||||||
 | 
								ksym = XK_Return;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case XK_k:
 | 
				
			||||||
 | 
								text[cursor] = '\0';
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case XK_u:
 | 
				
			||||||
 | 
								memmove(text, text + cursor, sizeof text - cursor + 1);
 | 
				
			||||||
 | 
								cursor = 0;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case XK_w:
 | 
				
			||||||
 | 
								if(cursor > 0) {
 | 
				
			||||||
 | 
									i = cursor;
 | 
				
			||||||
 | 
									while(i-- > 0 && text[i] == ' ');
 | 
				
			||||||
 | 
									while(i-- > 0 && text[i] != ' ');
 | 
				
			||||||
 | 
									memmove(text + i + 1, text + cursor, sizeof text - cursor + 1);
 | 
				
			||||||
 | 
									cursor = i + 1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case XK_y:
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									FILE *fp;
 | 
				
			||||||
 | 
									char *s;
 | 
				
			||||||
 | 
									if(!(fp = popen("sselp", "r")))
 | 
				
			||||||
 | 
										eprint("dinput: cannot popen sselp\n");
 | 
				
			||||||
 | 
									s = fgets(buf, sizeof buf, fp);
 | 
				
			||||||
 | 
									pclose(fp);
 | 
				
			||||||
 | 
									if(s == NULL)
 | 
				
			||||||
 | 
										return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								num = strlen(buf);
 | 
				
			||||||
 | 
								if(num && buf[num-1] == '\n')
 | 
				
			||||||
 | 
									buf[--num] = '\0';
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						switch(ksym) {
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							num = MIN(num, sizeof text - cursor);
 | 
				
			||||||
 | 
							if(num && !iscntrl((int) buf[0])) {
 | 
				
			||||||
 | 
								memmove(text + cursor + num, text + cursor, sizeof text - cursor - num);
 | 
				
			||||||
 | 
								memcpy(text + cursor, buf, num);
 | 
				
			||||||
 | 
								cursor += num;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case XK_BackSpace:
 | 
				
			||||||
 | 
							if(cursor == 0)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							for(i = 1; cursor - i > 0 && !IS_UTF8_1ST_CHAR(text[cursor - i]); i++);
 | 
				
			||||||
 | 
							memmove(text + cursor - i, text + cursor, sizeof text - cursor + i);
 | 
				
			||||||
 | 
							cursor -= i;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case XK_Delete:
 | 
				
			||||||
 | 
							if(cursor == len)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							for(i = 1; cursor + i < len && !IS_UTF8_1ST_CHAR(text[cursor + i]); i++);
 | 
				
			||||||
 | 
							memmove(text + cursor, text + cursor + i, sizeof text - cursor);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case XK_End:
 | 
				
			||||||
 | 
							cursor = len;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case XK_Escape:
 | 
				
			||||||
 | 
							ret = 1;
 | 
				
			||||||
 | 
							running = False;
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						case XK_Home:
 | 
				
			||||||
 | 
							cursor = 0;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case XK_Left:
 | 
				
			||||||
 | 
							if(cursor == 0)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							while(cursor-- > 0 && !IS_UTF8_1ST_CHAR(text[cursor]));
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case XK_Return:
 | 
				
			||||||
 | 
							fprintf(stdout, "%s", text);
 | 
				
			||||||
 | 
							fflush(stdout);
 | 
				
			||||||
 | 
							running = False;
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						case XK_Right:
 | 
				
			||||||
 | 
							if(cursor == len)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							while(cursor++ < len && !IS_UTF8_1ST_CHAR(text[cursor]));
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						drawinput();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					run(void) {
 | 
				
			||||||
 | 
						XEvent ev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* main event loop */
 | 
				
			||||||
 | 
						while(running && !XNextEvent(dpy, &ev))
 | 
				
			||||||
 | 
							switch (ev.type) {
 | 
				
			||||||
 | 
							case KeyPress:
 | 
				
			||||||
 | 
								kpress(&ev.xkey);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case Expose:
 | 
				
			||||||
 | 
								if(ev.xexpose.count == 0)
 | 
				
			||||||
 | 
									drawinput();
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case VisibilityNotify:
 | 
				
			||||||
 | 
								if (ev.xvisibility.state != VisibilityUnobscured)
 | 
				
			||||||
 | 
									XRaiseWindow(dpy, win);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					setup(Bool topbar) {
 | 
				
			||||||
 | 
						int i, j, x, y;
 | 
				
			||||||
 | 
					#if XINERAMA
 | 
				
			||||||
 | 
						int n;
 | 
				
			||||||
 | 
						XineramaScreenInfo *info = NULL;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						XModifierKeymap *modmap;
 | 
				
			||||||
 | 
						XSetWindowAttributes wa;
 | 
				
			||||||
 | 
						XWindowAttributes pwa;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* init modifier map */
 | 
				
			||||||
 | 
						modmap = XGetModifierMapping(dpy);
 | 
				
			||||||
 | 
						for(i = 0; i < 8; i++)
 | 
				
			||||||
 | 
							for(j = 0; j < modmap->max_keypermod; j++) {
 | 
				
			||||||
 | 
								if(modmap->modifiermap[i * modmap->max_keypermod + j]
 | 
				
			||||||
 | 
								== XKeysymToKeycode(dpy, XK_Num_Lock))
 | 
				
			||||||
 | 
									numlockmask = (1 << i);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						XFreeModifiermap(modmap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* style */
 | 
				
			||||||
 | 
						dc.norm[ColBG] = getcolor(normbgcolor);
 | 
				
			||||||
 | 
						dc.norm[ColFG] = getcolor(normfgcolor);
 | 
				
			||||||
 | 
						dc.sel[ColBG] = getcolor(selbgcolor);
 | 
				
			||||||
 | 
						dc.sel[ColFG] = getcolor(selfgcolor);
 | 
				
			||||||
 | 
						initfont(font);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* menu window */
 | 
				
			||||||
 | 
						wa.override_redirect = True;
 | 
				
			||||||
 | 
						wa.background_pixmap = ParentRelative;
 | 
				
			||||||
 | 
						wa.event_mask = ExposureMask | ButtonPressMask | KeyPressMask | VisibilityChangeMask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* menu window geometry */
 | 
				
			||||||
 | 
						mh = (dc.font.height + 2);
 | 
				
			||||||
 | 
					#if XINERAMA
 | 
				
			||||||
 | 
						if(parent == RootWindow(dpy, screen) && XineramaIsActive(dpy) && (info = XineramaQueryScreens(dpy, &n))) {
 | 
				
			||||||
 | 
							i = 0;
 | 
				
			||||||
 | 
							if(n > 1) {
 | 
				
			||||||
 | 
								int di;
 | 
				
			||||||
 | 
								unsigned int dui;
 | 
				
			||||||
 | 
								Window dummy;
 | 
				
			||||||
 | 
								if(XQueryPointer(dpy, parent, &dummy, &dummy, &x, &y, &di, &di, &dui))
 | 
				
			||||||
 | 
									for(i = 0; i < n; i++)
 | 
				
			||||||
 | 
										if(INRECT(x, y, info[i].x_org, info[i].y_org, info[i].width, info[i].height))
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							x = info[i].x_org;
 | 
				
			||||||
 | 
							y = topbar ? info[i].y_org : info[i].y_org + info[i].height - mh;
 | 
				
			||||||
 | 
							mw = info[i].width;
 | 
				
			||||||
 | 
							XFree(info);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							XGetWindowAttributes(dpy, parent, &pwa);
 | 
				
			||||||
 | 
							x = 0;
 | 
				
			||||||
 | 
							y = topbar ? 0 : pwa.height - mh;
 | 
				
			||||||
 | 
							mw = pwa.width;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						win = XCreateWindow(dpy, parent, x, y, mw, mh, 0,
 | 
				
			||||||
 | 
								DefaultDepth(dpy, screen), CopyFromParent,
 | 
				
			||||||
 | 
								DefaultVisual(dpy, screen),
 | 
				
			||||||
 | 
								CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* pixmap */
 | 
				
			||||||
 | 
						dcsetup();
 | 
				
			||||||
 | 
						if(prompt)
 | 
				
			||||||
 | 
							promptw = MIN(textw(prompt), mw / 5);
 | 
				
			||||||
 | 
						cursor = strlen(text);
 | 
				
			||||||
 | 
						XMapRaised(dpy, win);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main(int argc, char *argv[]) {
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
						Bool topbar = True;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* command line args */
 | 
				
			||||||
 | 
						for(i = 1; i < argc; i++)
 | 
				
			||||||
 | 
							if(!strcmp(argv[i], "-b"))
 | 
				
			||||||
 | 
								topbar = False;
 | 
				
			||||||
 | 
							else if(!strcmp(argv[i], "-e")) {
 | 
				
			||||||
 | 
								if(++i < argc) parent = atoi(argv[i]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else if(!strcmp(argv[i], "-fn")) {
 | 
				
			||||||
 | 
								if(++i < argc) font = argv[i];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else if(!strcmp(argv[i], "-nb")) {
 | 
				
			||||||
 | 
								if(++i < argc) normbgcolor = argv[i];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else if(!strcmp(argv[i], "-nf")) {
 | 
				
			||||||
 | 
								if(++i < argc) normfgcolor = argv[i];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else if(!strcmp(argv[i], "-p")) {
 | 
				
			||||||
 | 
								if(++i < argc) prompt = argv[i];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else if(!strcmp(argv[i], "-sb")) {
 | 
				
			||||||
 | 
								if(++i < argc) selbgcolor = argv[i];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else if(!strcmp(argv[i], "-sf")) {
 | 
				
			||||||
 | 
								if(++i < argc) selfgcolor = argv[i];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else if(!strcmp(argv[i], "-v"))
 | 
				
			||||||
 | 
								eprint("dinput-"VERSION", © 2006-2010 dinput engineers, see LICENSE for details\n");
 | 
				
			||||||
 | 
							else if(!*text)
 | 
				
			||||||
 | 
								strncpy(text, argv[i], sizeof text);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								eprint("usage: dinput [-b] [-e <xid>] [-fn <font>] [-nb <color>] [-nf <color>]\n"
 | 
				
			||||||
 | 
								       "              [-p <prompt>] [-sb <color>] [-sf <color>] [-v] [<text>]\n");
 | 
				
			||||||
 | 
						if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
 | 
				
			||||||
 | 
							fprintf(stderr, "dinput: warning: no locale support\n");
 | 
				
			||||||
 | 
						if(!(dpy = XOpenDisplay(NULL)))
 | 
				
			||||||
 | 
							eprint("dinput: cannot open display\n");
 | 
				
			||||||
 | 
						screen = DefaultScreen(dpy);
 | 
				
			||||||
 | 
						if(!parent)
 | 
				
			||||||
 | 
							parent = RootWindow(dpy, screen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						running = grabkeyboard();
 | 
				
			||||||
 | 
						setup(topbar);
 | 
				
			||||||
 | 
						drawinput();
 | 
				
			||||||
 | 
						XSync(dpy, False);
 | 
				
			||||||
 | 
						run();
 | 
				
			||||||
 | 
						cleanup();
 | 
				
			||||||
 | 
						XCloseDisplay(dpy);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										213
									
								
								dmenu.c
									
									
									
									
									
								
							
							
						
						
									
										213
									
								
								dmenu.c
									
									
									
									
									
								
							@@ -21,25 +21,6 @@
 | 
				
			|||||||
#define MAX(a, b)               ((a) > (b) ? (a) : (b))
 | 
					#define MAX(a, b)               ((a) > (b) ? (a) : (b))
 | 
				
			||||||
#define IS_UTF8_1ST_CHAR(c)     ((((c) & 0xc0) == 0xc0) || !((c) & 0x80))
 | 
					#define IS_UTF8_1ST_CHAR(c)     ((((c) & 0xc0) == 0xc0) || !((c) & 0x80))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* enums */
 | 
					 | 
				
			||||||
enum { ColFG, ColBG, ColLast };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* typedefs */
 | 
					 | 
				
			||||||
typedef struct {
 | 
					 | 
				
			||||||
	int x, y, w, h;
 | 
					 | 
				
			||||||
	unsigned long norm[ColLast];
 | 
					 | 
				
			||||||
	unsigned long sel[ColLast];
 | 
					 | 
				
			||||||
	Drawable drawable;
 | 
					 | 
				
			||||||
	GC gc;
 | 
					 | 
				
			||||||
	struct {
 | 
					 | 
				
			||||||
		XFontStruct *xfont;
 | 
					 | 
				
			||||||
		XFontSet set;
 | 
					 | 
				
			||||||
		int ascent;
 | 
					 | 
				
			||||||
		int descent;
 | 
					 | 
				
			||||||
		int height;
 | 
					 | 
				
			||||||
	} font;
 | 
					 | 
				
			||||||
} DC; /* draw context */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct Item Item;
 | 
					typedef struct Item Item;
 | 
				
			||||||
struct Item {
 | 
					struct Item {
 | 
				
			||||||
	char *text;
 | 
						char *text;
 | 
				
			||||||
@@ -53,22 +34,16 @@ static void calcoffsetsh(void);
 | 
				
			|||||||
static void calcoffsetsv(void);
 | 
					static void calcoffsetsv(void);
 | 
				
			||||||
static char *cistrstr(const char *s, const char *sub);
 | 
					static char *cistrstr(const char *s, const char *sub);
 | 
				
			||||||
static void cleanup(void);
 | 
					static void cleanup(void);
 | 
				
			||||||
static void drawcursor(void);
 | 
					 | 
				
			||||||
static void drawmenu(void);
 | 
					static void drawmenu(void);
 | 
				
			||||||
static void drawmenuh(void);
 | 
					static void drawmenuh(void);
 | 
				
			||||||
static void drawmenuv(void);
 | 
					static void drawmenuv(void);
 | 
				
			||||||
static void drawtext(const char *text, unsigned long col[ColLast]);
 | 
					 | 
				
			||||||
static void eprint(const char *errstr, ...);
 | 
					static void eprint(const char *errstr, ...);
 | 
				
			||||||
static unsigned long getcolor(const char *colstr);
 | 
					 | 
				
			||||||
static Bool grabkeyboard(void);
 | 
					static Bool grabkeyboard(void);
 | 
				
			||||||
static void initfont(const char *fontstr);
 | 
					 | 
				
			||||||
static void kpress(XKeyEvent * e);
 | 
					static void kpress(XKeyEvent * e);
 | 
				
			||||||
static void match(char *pattern);
 | 
					static void match(char *pattern);
 | 
				
			||||||
static void readstdin(void);
 | 
					static void readstdin(void);
 | 
				
			||||||
static void run(void);
 | 
					static void run(void);
 | 
				
			||||||
static void setup(Bool topbar);
 | 
					static void setup(Bool topbar);
 | 
				
			||||||
static int textnw(const char *text, unsigned int len);
 | 
					 | 
				
			||||||
static int textw(const char *text);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -81,11 +56,9 @@ static int promptw = 0;
 | 
				
			|||||||
static int ret = 0;
 | 
					static int ret = 0;
 | 
				
			||||||
static int screen;
 | 
					static int screen;
 | 
				
			||||||
static unsigned int mw, mh;
 | 
					static unsigned int mw, mh;
 | 
				
			||||||
static unsigned int cursor = 0;
 | 
					 | 
				
			||||||
static unsigned int numlockmask = 0;
 | 
					static unsigned int numlockmask = 0;
 | 
				
			||||||
static Bool running = True;
 | 
					static Bool running = True;
 | 
				
			||||||
static Display *dpy;
 | 
					static Display *dpy;
 | 
				
			||||||
static DC dc;
 | 
					 | 
				
			||||||
static Item *allitems = NULL;  /* first of all items */
 | 
					static Item *allitems = NULL;  /* first of all items */
 | 
				
			||||||
static Item *item = NULL;      /* first of pattern matching items */
 | 
					static Item *item = NULL;      /* first of pattern matching items */
 | 
				
			||||||
static Item *sel = NULL;
 | 
					static Item *sel = NULL;
 | 
				
			||||||
@@ -98,6 +71,8 @@ static char *(*fstrstr)(const char *, const char *) = strstr;
 | 
				
			|||||||
static unsigned int lines = 0;
 | 
					static unsigned int lines = 0;
 | 
				
			||||||
static void (*calcoffsets)(void) = calcoffsetsh;
 | 
					static void (*calcoffsets)(void) = calcoffsetsh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "draw.c"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
appenditem(Item *i, Item **list, Item **last) {
 | 
					appenditem(Item *i, Item **list, Item **last) {
 | 
				
			||||||
	if(!(*last))
 | 
						if(!(*last))
 | 
				
			||||||
@@ -161,26 +136,11 @@ cistrstr(const char *s, const char *sub) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
cleanup(void) {
 | 
					cleanup(void) {
 | 
				
			||||||
	if(dc.font.set)
 | 
						dccleanup();
 | 
				
			||||||
		XFreeFontSet(dpy, dc.font.set);
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		XFreeFont(dpy, dc.font.xfont);
 | 
					 | 
				
			||||||
	XFreePixmap(dpy, dc.drawable);
 | 
					 | 
				
			||||||
	XFreeGC(dpy, dc.gc);
 | 
					 | 
				
			||||||
	XDestroyWindow(dpy, win);
 | 
						XDestroyWindow(dpy, win);
 | 
				
			||||||
	XUngrabKeyboard(dpy, CurrentTime);
 | 
						XUngrabKeyboard(dpy, CurrentTime);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					 | 
				
			||||||
drawcursor(void) {
 | 
					 | 
				
			||||||
	XRectangle r = { dc.x, dc.y + 2, 1, dc.font.height - 2 };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	r.x += textnw(text, cursor) + dc.font.height / 2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	XSetForeground(dpy, dc.gc, dc.norm[ColFG]);
 | 
					 | 
				
			||||||
	XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
drawmenu(void) {
 | 
					drawmenu(void) {
 | 
				
			||||||
	dc.x = 0;
 | 
						dc.x = 0;
 | 
				
			||||||
@@ -199,7 +159,6 @@ drawmenu(void) {
 | 
				
			|||||||
	if(cmdw && item && lines == 0)
 | 
						if(cmdw && item && lines == 0)
 | 
				
			||||||
		dc.w = cmdw;
 | 
							dc.w = cmdw;
 | 
				
			||||||
	drawtext(*text ? text : NULL, dc.norm);
 | 
						drawtext(*text ? text : NULL, dc.norm);
 | 
				
			||||||
	drawcursor();
 | 
					 | 
				
			||||||
	if(curr) {
 | 
						if(curr) {
 | 
				
			||||||
		if(lines > 0)
 | 
							if(lines > 0)
 | 
				
			||||||
			drawmenuv();
 | 
								drawmenuv();
 | 
				
			||||||
@@ -243,34 +202,6 @@ drawmenuv(void) {
 | 
				
			|||||||
	drawtext(NULL, dc.norm);
 | 
						drawtext(NULL, dc.norm);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					 | 
				
			||||||
drawtext(const char *text, unsigned long col[ColLast]) {
 | 
					 | 
				
			||||||
	char buf[256];
 | 
					 | 
				
			||||||
	int i, x, y, h, len, olen;
 | 
					 | 
				
			||||||
	XRectangle r = { dc.x, dc.y, dc.w, dc.h };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	XSetForeground(dpy, dc.gc, col[ColBG]);
 | 
					 | 
				
			||||||
	XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
 | 
					 | 
				
			||||||
	if(!text)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	olen = strlen(text);
 | 
					 | 
				
			||||||
	h = dc.font.height;
 | 
					 | 
				
			||||||
	y = dc.y + ((h+2) / 2) - (h / 2) + dc.font.ascent;
 | 
					 | 
				
			||||||
	x = dc.x + (h / 2);
 | 
					 | 
				
			||||||
	/* shorten text if necessary */
 | 
					 | 
				
			||||||
	for(len = MIN(olen, sizeof buf); len && textnw(text, len) > dc.w - h; len--);
 | 
					 | 
				
			||||||
	if(!len)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	memcpy(buf, text, len);
 | 
					 | 
				
			||||||
	if(len < olen)
 | 
					 | 
				
			||||||
		for(i = len; i && i > len - 3; buf[--i] = '.');
 | 
					 | 
				
			||||||
	XSetForeground(dpy, dc.gc, col[ColFG]);
 | 
					 | 
				
			||||||
	if(dc.font.set)
 | 
					 | 
				
			||||||
		XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
eprint(const char *errstr, ...) {
 | 
					eprint(const char *errstr, ...) {
 | 
				
			||||||
	va_list ap;
 | 
						va_list ap;
 | 
				
			||||||
@@ -281,16 +212,6 @@ eprint(const char *errstr, ...) {
 | 
				
			|||||||
	exit(EXIT_FAILURE);
 | 
						exit(EXIT_FAILURE);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
unsigned long
 | 
					 | 
				
			||||||
getcolor(const char *colstr) {
 | 
					 | 
				
			||||||
	Colormap cmap = DefaultColormap(dpy, screen);
 | 
					 | 
				
			||||||
	XColor color;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
 | 
					 | 
				
			||||||
		eprint("dmenu: cannot allocate color '%s'\n", colstr);
 | 
					 | 
				
			||||||
	return color.pixel;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Bool
 | 
					Bool
 | 
				
			||||||
grabkeyboard(void) {
 | 
					grabkeyboard(void) {
 | 
				
			||||||
	unsigned int len;
 | 
						unsigned int len;
 | 
				
			||||||
@@ -304,37 +225,6 @@ grabkeyboard(void) {
 | 
				
			|||||||
	return len > 0;
 | 
						return len > 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					 | 
				
			||||||
initfont(const char *fontstr) {
 | 
					 | 
				
			||||||
	char *def, **missing = NULL;
 | 
					 | 
				
			||||||
	int i, n;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if(!fontstr || fontstr[0] == '\0')
 | 
					 | 
				
			||||||
		eprint("dmenu: cannot load font: '%s'\n", fontstr);
 | 
					 | 
				
			||||||
	dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
 | 
					 | 
				
			||||||
	if(missing)
 | 
					 | 
				
			||||||
		XFreeStringList(missing);
 | 
					 | 
				
			||||||
	if(dc.font.set) {
 | 
					 | 
				
			||||||
		XFontStruct **xfonts;
 | 
					 | 
				
			||||||
		char **font_names;
 | 
					 | 
				
			||||||
		dc.font.ascent = dc.font.descent = 0;
 | 
					 | 
				
			||||||
		n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
 | 
					 | 
				
			||||||
		for(i = 0; i < n; i++) {
 | 
					 | 
				
			||||||
			dc.font.ascent = MAX(dc.font.ascent, (*xfonts)->ascent);
 | 
					 | 
				
			||||||
			dc.font.descent = MAX(dc.font.descent, (*xfonts)->descent);
 | 
					 | 
				
			||||||
			xfonts++;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	else {
 | 
					 | 
				
			||||||
		if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr))
 | 
					 | 
				
			||||||
		&& !(dc.font.xfont = XLoadQueryFont(dpy, "fixed")))
 | 
					 | 
				
			||||||
			eprint("dmenu: cannot load font: '%s'\n", fontstr);
 | 
					 | 
				
			||||||
		dc.font.ascent = dc.font.xfont->ascent;
 | 
					 | 
				
			||||||
		dc.font.descent = dc.font.xfont->descent;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	dc.font.height = dc.font.ascent + dc.font.descent;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
kpress(XKeyEvent * e) {
 | 
					kpress(XKeyEvent * e) {
 | 
				
			||||||
	char buf[sizeof text];
 | 
						char buf[sizeof text];
 | 
				
			||||||
@@ -381,9 +271,6 @@ kpress(XKeyEvent * e) {
 | 
				
			|||||||
		case XK_j:
 | 
							case XK_j:
 | 
				
			||||||
			ksym = XK_Return;
 | 
								ksym = XK_Return;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case XK_k:
 | 
					 | 
				
			||||||
			text[cursor] = '\0';
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case XK_n:
 | 
							case XK_n:
 | 
				
			||||||
			ksym = XK_Down;
 | 
								ksym = XK_Down;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
@@ -391,67 +278,42 @@ kpress(XKeyEvent * e) {
 | 
				
			|||||||
			ksym = XK_Up;
 | 
								ksym = XK_Up;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case XK_u:
 | 
							case XK_u:
 | 
				
			||||||
			memmove(text, text + cursor, sizeof text - cursor + 1);
 | 
								text[0] = '\0';
 | 
				
			||||||
			cursor = 0;
 | 
					 | 
				
			||||||
			match(text);
 | 
								match(text);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case XK_w:
 | 
							case XK_w:
 | 
				
			||||||
			if(cursor > 0) {
 | 
								if(len == 0)
 | 
				
			||||||
				i = cursor;
 | 
									return;
 | 
				
			||||||
 | 
								i = len;
 | 
				
			||||||
			while(i-- > 0 && text[i] == ' ');
 | 
								while(i-- > 0 && text[i] == ' ');
 | 
				
			||||||
			while(i-- > 0 && text[i] != ' ');
 | 
								while(i-- > 0 && text[i] != ' ');
 | 
				
			||||||
				memmove(text + i + 1, text + cursor, sizeof text - cursor + 1);
 | 
								text[++i] = '\0';
 | 
				
			||||||
				cursor = i + 1;
 | 
					 | 
				
			||||||
			match(text);
 | 
								match(text);
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case XK_y:
 | 
							case XK_x:
 | 
				
			||||||
			{
 | 
								execlp("dinput", "dinput", text, NULL); /* todo: argv */
 | 
				
			||||||
				FILE *fp;
 | 
								eprint("dmenu: cannot exec dinput:");
 | 
				
			||||||
				char *s;
 | 
					 | 
				
			||||||
				if(!(fp = popen("sselp", "r")))
 | 
					 | 
				
			||||||
					eprint("dmenu: cannot popen sselp\n");
 | 
					 | 
				
			||||||
				s = fgets(buf, sizeof buf, fp);
 | 
					 | 
				
			||||||
				pclose(fp);
 | 
					 | 
				
			||||||
				if(s == NULL)
 | 
					 | 
				
			||||||
					return;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			num = strlen(buf);
 | 
					 | 
				
			||||||
			if(num && buf[num-1] == '\n')
 | 
					 | 
				
			||||||
				buf[--num] = '\0';
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	switch(ksym) {
 | 
						switch(ksym) {
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		num = MIN(num, sizeof text - cursor);
 | 
							num = MIN(num, sizeof text);
 | 
				
			||||||
		if(num && !iscntrl((int) buf[0])) {
 | 
							if(num && !iscntrl((int) buf[0])) {
 | 
				
			||||||
			memmove(text + cursor + num, text + cursor, sizeof text - cursor - num);
 | 
								memcpy(text + len, buf, num + 1);
 | 
				
			||||||
			memcpy(text + cursor, buf, num);
 | 
								len += num;
 | 
				
			||||||
			cursor += num;
 | 
					 | 
				
			||||||
			match(text);
 | 
								match(text);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case XK_BackSpace:
 | 
						case XK_BackSpace:
 | 
				
			||||||
		if(cursor == 0)
 | 
							if(len == 0)
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		for(i = 1; cursor - i > 0 && !IS_UTF8_1ST_CHAR(text[cursor - i]); i++);
 | 
							for(i = 1; len - i > 0 && !IS_UTF8_1ST_CHAR(text[len - i]); i++);
 | 
				
			||||||
		memmove(text + cursor - i, text + cursor, sizeof text - cursor + i);
 | 
							len -= i;
 | 
				
			||||||
		cursor -= i;
 | 
							text[len] = '\0';
 | 
				
			||||||
		match(text);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case XK_Delete:
 | 
					 | 
				
			||||||
		if(cursor == len)
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		for(i = 1; cursor + i < len && !IS_UTF8_1ST_CHAR(text[cursor + i]); i++);
 | 
					 | 
				
			||||||
		memmove(text + cursor, text + cursor + i, sizeof text - cursor);
 | 
					 | 
				
			||||||
		match(text);
 | 
							match(text);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case XK_End:
 | 
						case XK_End:
 | 
				
			||||||
		if(cursor < len) {
 | 
					 | 
				
			||||||
			cursor = len;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		while(next) {
 | 
							while(next) {
 | 
				
			||||||
			sel = curr = next;
 | 
								sel = curr = next;
 | 
				
			||||||
			calcoffsets();
 | 
								calcoffsets();
 | 
				
			||||||
@@ -464,20 +326,10 @@ kpress(XKeyEvent * e) {
 | 
				
			|||||||
		running = False;
 | 
							running = False;
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	case XK_Home:
 | 
						case XK_Home:
 | 
				
			||||||
		if(sel == item) {
 | 
					 | 
				
			||||||
			cursor = 0;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		sel = curr = item;
 | 
							sel = curr = item;
 | 
				
			||||||
		calcoffsets();
 | 
							calcoffsets();
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case XK_Left:
 | 
						case XK_Left:
 | 
				
			||||||
		if(cursor > 0 && (!sel || !sel->left || lines > 0)) {
 | 
					 | 
				
			||||||
			while(cursor-- > 0 && !IS_UTF8_1ST_CHAR(text[cursor]));
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if(lines > 0)
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
	case XK_Up:
 | 
						case XK_Up:
 | 
				
			||||||
		if(!sel || !sel->left)
 | 
							if(!sel || !sel->left)
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
@@ -508,12 +360,6 @@ kpress(XKeyEvent * e) {
 | 
				
			|||||||
		running = False;
 | 
							running = False;
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	case XK_Right:
 | 
						case XK_Right:
 | 
				
			||||||
		if(cursor < len) {
 | 
					 | 
				
			||||||
			while(cursor++ < len && !IS_UTF8_1ST_CHAR(text[cursor]));
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if(lines > 0)
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
	case XK_Down:
 | 
						case XK_Down:
 | 
				
			||||||
		if(!sel || !sel->right)
 | 
							if(!sel || !sel->right)
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
@@ -527,7 +373,6 @@ kpress(XKeyEvent * e) {
 | 
				
			|||||||
		if(!sel)
 | 
							if(!sel)
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		strncpy(text, sel->text, sizeof text);
 | 
							strncpy(text, sel->text, sizeof text);
 | 
				
			||||||
		cursor = strlen(text);
 | 
					 | 
				
			||||||
		match(text);
 | 
							match(text);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -690,11 +535,7 @@ setup(Bool topbar) {
 | 
				
			|||||||
			CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
 | 
								CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* pixmap */
 | 
						/* pixmap */
 | 
				
			||||||
	dc.drawable = XCreatePixmap(dpy, parent, mw, mh, DefaultDepth(dpy, screen));
 | 
						dcsetup();
 | 
				
			||||||
	dc.gc = XCreateGC(dpy, parent, 0, NULL);
 | 
					 | 
				
			||||||
	XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
 | 
					 | 
				
			||||||
	if(!dc.font.set)
 | 
					 | 
				
			||||||
		XSetFont(dpy, dc.gc, dc.font.xfont->fid);
 | 
					 | 
				
			||||||
	if(maxname)
 | 
						if(maxname)
 | 
				
			||||||
		cmdw = MIN(textw(maxname), mw / 3);
 | 
							cmdw = MIN(textw(maxname), mw / 3);
 | 
				
			||||||
	if(prompt)
 | 
						if(prompt)
 | 
				
			||||||
@@ -704,22 +545,6 @@ setup(Bool topbar) {
 | 
				
			|||||||
	XMapRaised(dpy, win);
 | 
						XMapRaised(dpy, win);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int
 | 
					 | 
				
			||||||
textnw(const char *text, unsigned int len) {
 | 
					 | 
				
			||||||
	XRectangle r;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if(dc.font.set) {
 | 
					 | 
				
			||||||
		XmbTextExtents(dc.font.set, text, len, NULL, &r);
 | 
					 | 
				
			||||||
		return r.width;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return XTextWidth(dc.font.xfont, text, len);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
textw(const char *text) {
 | 
					 | 
				
			||||||
	return textnw(text, strlen(text)) + dc.font.height;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
main(int argc, char *argv[]) {
 | 
					main(int argc, char *argv[]) {
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										143
									
								
								draw.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								draw.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,143 @@
 | 
				
			|||||||
 | 
					/* See LICENSE file for copyright and license details. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* enums */
 | 
				
			||||||
 | 
					enum { ColFG, ColBG, ColLast };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* typedefs */
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
						int x, y, w, h;
 | 
				
			||||||
 | 
						unsigned long norm[ColLast];
 | 
				
			||||||
 | 
						unsigned long sel[ColLast];
 | 
				
			||||||
 | 
						Drawable drawable;
 | 
				
			||||||
 | 
						GC gc;
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							XFontStruct *xfont;
 | 
				
			||||||
 | 
							XFontSet set;
 | 
				
			||||||
 | 
							int ascent;
 | 
				
			||||||
 | 
							int descent;
 | 
				
			||||||
 | 
							int height;
 | 
				
			||||||
 | 
						} font;
 | 
				
			||||||
 | 
					} DC; /* draw context */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* forward declarations */
 | 
				
			||||||
 | 
					static void dccleanup(void);
 | 
				
			||||||
 | 
					static void dcsetup(void);
 | 
				
			||||||
 | 
					static void drawtext(const char *text, unsigned long col[ColLast]);
 | 
				
			||||||
 | 
					static unsigned long getcolor(const char *colstr);
 | 
				
			||||||
 | 
					static void initfont(const char *fontstr);
 | 
				
			||||||
 | 
					static int textnw(const char *text, unsigned int len);
 | 
				
			||||||
 | 
					static int textw(const char *text);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static DC dc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					dccleanup(void) {
 | 
				
			||||||
 | 
						if(dc.font.set)
 | 
				
			||||||
 | 
							XFreeFontSet(dpy, dc.font.set);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							XFreeFont(dpy, dc.font.xfont);
 | 
				
			||||||
 | 
						XFreePixmap(dpy, dc.drawable);
 | 
				
			||||||
 | 
						XFreeGC(dpy, dc.gc);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					dcsetup() {
 | 
				
			||||||
 | 
						/* style */
 | 
				
			||||||
 | 
						dc.norm[ColBG] = getcolor(normbgcolor);
 | 
				
			||||||
 | 
						dc.norm[ColFG] = getcolor(normfgcolor);
 | 
				
			||||||
 | 
						dc.sel[ColBG] = getcolor(selbgcolor);
 | 
				
			||||||
 | 
						dc.sel[ColFG] = getcolor(selfgcolor);
 | 
				
			||||||
 | 
						initfont(font);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* pixmap */
 | 
				
			||||||
 | 
						dc.drawable = XCreatePixmap(dpy, parent, mw, mh, DefaultDepth(dpy, screen));
 | 
				
			||||||
 | 
						dc.gc = XCreateGC(dpy, parent, 0, NULL);
 | 
				
			||||||
 | 
						XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
 | 
				
			||||||
 | 
						if(!dc.font.set)
 | 
				
			||||||
 | 
							XSetFont(dpy, dc.gc, dc.font.xfont->fid);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					drawtext(const char *text, unsigned long col[ColLast]) {
 | 
				
			||||||
 | 
						char buf[256];
 | 
				
			||||||
 | 
						int i, x, y, h, len, olen;
 | 
				
			||||||
 | 
						XRectangle r = { dc.x, dc.y, dc.w, dc.h };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						XSetForeground(dpy, dc.gc, col[ColBG]);
 | 
				
			||||||
 | 
						XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
 | 
				
			||||||
 | 
						if(!text)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						olen = strlen(text);
 | 
				
			||||||
 | 
						h = dc.font.height;
 | 
				
			||||||
 | 
						y = dc.y + ((h+2) / 2) - (h / 2) + dc.font.ascent;
 | 
				
			||||||
 | 
						x = dc.x + (h / 2);
 | 
				
			||||||
 | 
						/* shorten text if necessary */
 | 
				
			||||||
 | 
						for(len = MIN(olen, sizeof buf); len && textnw(text, len) > dc.w - h; len--);
 | 
				
			||||||
 | 
						if(!len)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						memcpy(buf, text, len);
 | 
				
			||||||
 | 
						if(len < olen)
 | 
				
			||||||
 | 
							for(i = len; i && i > len - 3; buf[--i] = '.');
 | 
				
			||||||
 | 
						XSetForeground(dpy, dc.gc, col[ColFG]);
 | 
				
			||||||
 | 
						if(dc.font.set)
 | 
				
			||||||
 | 
							XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsigned long
 | 
				
			||||||
 | 
					getcolor(const char *colstr) {
 | 
				
			||||||
 | 
						Colormap cmap = DefaultColormap(dpy, screen);
 | 
				
			||||||
 | 
						XColor color;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
 | 
				
			||||||
 | 
							eprint("drawtext: cannot allocate color '%s'\n", colstr);
 | 
				
			||||||
 | 
						return color.pixel;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					initfont(const char *fontstr) {
 | 
				
			||||||
 | 
						char *def, **missing = NULL;
 | 
				
			||||||
 | 
						int i, n;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(!fontstr || fontstr[0] == '\0')
 | 
				
			||||||
 | 
							eprint("drawtext: cannot load font: '%s'\n", fontstr);
 | 
				
			||||||
 | 
						dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
 | 
				
			||||||
 | 
						if(missing)
 | 
				
			||||||
 | 
							XFreeStringList(missing);
 | 
				
			||||||
 | 
						if(dc.font.set) {
 | 
				
			||||||
 | 
							XFontStruct **xfonts;
 | 
				
			||||||
 | 
							char **font_names;
 | 
				
			||||||
 | 
							dc.font.ascent = dc.font.descent = 0;
 | 
				
			||||||
 | 
							n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
 | 
				
			||||||
 | 
							for(i = 0; i < n; i++) {
 | 
				
			||||||
 | 
								dc.font.ascent = MAX(dc.font.ascent, (*xfonts)->ascent);
 | 
				
			||||||
 | 
								dc.font.descent = MAX(dc.font.descent, (*xfonts)->descent);
 | 
				
			||||||
 | 
								xfonts++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else {
 | 
				
			||||||
 | 
							if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr))
 | 
				
			||||||
 | 
							&& !(dc.font.xfont = XLoadQueryFont(dpy, "fixed")))
 | 
				
			||||||
 | 
								eprint("drawtext: cannot load font: '%s'\n", fontstr);
 | 
				
			||||||
 | 
							dc.font.ascent = dc.font.xfont->ascent;
 | 
				
			||||||
 | 
							dc.font.descent = dc.font.xfont->descent;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						dc.font.height = dc.font.ascent + dc.font.descent;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					textnw(const char *text, unsigned int len) {
 | 
				
			||||||
 | 
						XRectangle r;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(dc.font.set) {
 | 
				
			||||||
 | 
							XmbTextExtents(dc.font.set, text, len, NULL, &r);
 | 
				
			||||||
 | 
							return r.width;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return XTextWidth(dc.font.xfont, text, len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					textw(const char *text) {
 | 
				
			||||||
 | 
						return textnw(text, strlen(text)) + dc.font.height;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user