mew

fork with password patch and nord colorscheme
git clone https://git.awy.one/mew.git
Log | Files | Refs | README | LICENSE

mew.c (26858B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <errno.h>
      3 #include <ctype.h>
      4 #include <locale.h>
      5 #include <poll.h>
      6 #include <stdarg.h>
      7 #include <stdio.h>
      8 #include <stdlib.h>
      9 #include <string.h>
     10 #include <strings.h>
     11 #include <sys/timerfd.h>
     12 #include <wayland-client.h>
     13 #include <xkbcommon/xkbcommon.h>
     14 
     15 #define MAX(A, B)             ((A) > (B) ? (A) : (B))
     16 #define MIN(A, B)             ((A) < (B) ? (A) : (B))
     17 #define BETWEEN(X, A, B)      ((A) <= (X) && (X) <= (B))
     18 #define LENGTH(X)             (sizeof (X) / sizeof (X)[0])
     19 
     20 #include "drwl.h"
     21 #include "bufpool.h"
     22 #include "xdg-activation-v1-protocol.h"
     23 #include "wlr-layer-shell-unstable-v1-protocol.h"
     24 
     25 #define TEXTW(X)              (drwl_font_getwidth(drw, (X)) + lrpad)
     26 
     27 enum { SchemeNorm, SchemeSel, SchemeOut }; /* color schemes */
     28 
     29 struct item {
     30 	char *text;
     31 	struct item *left, *right;
     32 	int out;
     33 };
     34 
     35 static struct {
     36 	struct wl_keyboard *wl_keyboard;
     37 	struct xkb_context *xkb_context;
     38 	struct xkb_keymap *xkb_keymap;
     39 	struct xkb_state *xkb_state;
     40 
     41 	struct {
     42 		int delay;
     43 		int period;
     44 		int timer;
     45 		enum wl_keyboard_key_state key_state;
     46 		xkb_keysym_t sym;
     47 	} repeat;
     48 
     49 	int ctrl, shift, alt;
     50 } kbd;
     51 
     52 static char text[BUFSIZ] = "";
     53 static int bh, mw, mh;
     54 static int inputw = 0, promptw, passwd = 0;
     55 static int32_t scale = 1;
     56 static int lrpad; /* sum of left and right padding */
     57 static size_t cursor;
     58 static struct item *items = NULL;
     59 static struct item *matches, *matchend;
     60 static struct item *prev, *curr, *next, *sel;
     61 static int running = 0;
     62 
     63 static struct wl_display *display;
     64 static struct wl_compositor *compositor;
     65 static struct wl_seat *seat;
     66 static struct wl_shm *shm;
     67 static struct wl_data_device_manager *data_device_manager;
     68 static struct wl_data_device *data_device;
     69 static struct wl_data_offer *data_offer;
     70 static struct zwlr_layer_shell_v1 *layer_shell;
     71 static struct zwlr_layer_surface_v1 *layer_surface;
     72 static struct xdg_activation_v1 *activation;
     73 static struct wl_surface *surface;
     74 static struct wl_registry *registry;
     75 static Drwl *drw;
     76 static BufPool pool;
     77 static struct wl_callback *frame_callback;
     78 /* default output supplied by compositor */
     79 static struct wl_output *output = NULL;
     80 
     81 #include "config.h"
     82 
     83 static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
     84 static char *(*fstrstr)(const char *, const char *) = strstr;
     85 static int (*submit)(const char*) = puts;
     86 
     87 static void
     88 noop()
     89 {
     90 	/*
     91 	 * meow :3c
     92 	 */
     93 }
     94 
     95 static void
     96 die(const char *fmt, ...)
     97 {
     98 	va_list ap;
     99 
    100 	va_start(ap, fmt);
    101 	vfprintf(stderr, fmt, ap);
    102 	va_end(ap);
    103 
    104 	if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
    105 		fputc(' ', stderr);
    106 		perror(NULL);
    107 	} else {
    108 		fputc('\n', stderr);
    109 	}
    110 
    111 	exit(EXIT_FAILURE);
    112 }
    113 
    114 static void
    115 activation_token_handle_done(void *data,
    116 	struct xdg_activation_token_v1 *activation_token, const char *token)
    117 {
    118 	char *argv[] = {"/bin/sh", "-c", (char*)data, NULL};
    119 
    120 	xdg_activation_token_v1_destroy(activation_token);
    121 
    122 	switch (fork()) {
    123 	case -1:
    124 		die("fork:");
    125 	case 0:
    126 		setenv("XDG_ACTIVATION_TOKEN", token, 1);
    127 		execv(argv[0], argv);
    128 		die("execvp:");
    129 	}
    130 
    131 	running = 0;
    132 }
    133 
    134 static const struct xdg_activation_token_v1_listener activation_token_listener = {
    135 	.done = activation_token_handle_done,
    136 };
    137 
    138 static int
    139 exec_cmd(const char *text)
    140 {
    141 	struct xdg_activation_token_v1 *activation_token;
    142 
    143 	activation_token = xdg_activation_v1_get_activation_token(activation);
    144 	xdg_activation_token_v1_set_surface(activation_token, surface);
    145 	xdg_activation_token_v1_add_listener(activation_token,
    146 		&activation_token_listener, (void *)text);
    147 	xdg_activation_token_v1_commit(activation_token);
    148 
    149 	return 0;
    150 }
    151 
    152 static void
    153 parse_color(uint32_t *dest, const char *src)
    154 {
    155 	int len;
    156 
    157 	if (src[0] == '#')
    158 		src++;
    159 	len = strlen(src);
    160 	if (len != 6 && len != 8)
    161 		die("bad color: %s", src);
    162 
    163 	*dest = strtoul(src, NULL, 16);
    164 	if (len == 6)
    165 		*dest = (*dest << 8) | 0xFF;
    166 }
    167 
    168 static void
    169 loadfonts(void)
    170 {
    171 	char fontattrs[12];
    172 
    173 	drwl_font_destroy(drw->font);
    174 	snprintf(fontattrs, sizeof(fontattrs), "dpi=%d", 96 * scale);
    175 	if (!(drwl_font_create(drw, LENGTH(fonts), fonts, fontattrs)))
    176 		die("no fonts could be loaded");
    177 
    178 	lrpad = drw->font->height;
    179 	bh = drw->font->height + 2;
    180 	lines = MAX(lines, 0);
    181 	mh = (lines + 1) * bh;
    182 	promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
    183 }
    184 
    185 static unsigned int
    186 textw_clamp(const char *str, unsigned int n)
    187 {
    188 	unsigned int w = drwl_font_getwidth_clamp(drw, str, n) + lrpad;
    189 	return MIN(w, n);
    190 }
    191 
    192 static void
    193 appenditem(struct item *item, struct item **list, struct item **last)
    194 {
    195 	if (*last)
    196 		(*last)->right = item;
    197 	else
    198 		*list = item;
    199 
    200 	item->left = *last;
    201 	item->right = NULL;
    202 	*last = item;
    203 }
    204 
    205 static void
    206 calcoffsets(void)
    207 {
    208 	int i, n;
    209 
    210 	if (lines > 0)
    211 		n = lines * bh;
    212 	else
    213 		n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">"));
    214 	/* calculate which items will begin the next page and previous page */
    215 	for (i = 0, next = curr; next; next = next->right)
    216 		if ((i += (lines > 0) ? bh : textw_clamp(next->text, n)) > n)
    217 			break;
    218 	for (i = 0, prev = curr; prev && prev->left; prev = prev->left)
    219 		if ((i += (lines > 0) ? bh : textw_clamp(prev->left->text, n)) > n)
    220 			break;
    221 }
    222 
    223 static void
    224 cleanup(void)
    225 {
    226 	size_t i;
    227 
    228 	for (i = 0; items && items[i].text; ++i)
    229 		free(items[i].text);
    230 	free(items);
    231 
    232 	bufpool_cleanup(&pool);
    233 	drwl_setimage(drw, NULL);
    234 	drwl_destroy(drw);
    235 	drwl_fini();
    236 
    237 	wl_data_device_release(data_device);
    238 	zwlr_layer_shell_v1_destroy(layer_shell);
    239 	xdg_activation_v1_destroy(activation);
    240 	wl_shm_destroy(shm);
    241 	wl_compositor_destroy(compositor);
    242 	wl_registry_destroy(registry);
    243 	wl_display_disconnect(display);
    244 }
    245 
    246 static char *
    247 cistrstr(const char *h, const char *n)
    248 {
    249 	size_t i;
    250 
    251 	if (!n[0])
    252 		return (char *)h;
    253 
    254 	for (; *h; ++h) {
    255 		for (i = 0; n[i] && tolower((unsigned char)n[i]) ==
    256 		            tolower((unsigned char)h[i]); ++i)
    257 			;
    258 		if (n[i] == '\0')
    259 			return (char *)h;
    260 	}
    261 	return NULL;
    262 }
    263 
    264 static int
    265 drawitem(struct item *item, int x, int y, int w)
    266 {
    267 	if (item == sel)
    268 		drwl_setscheme(drw, colors[SchemeSel]);
    269 	else if (item->out)
    270 		drwl_setscheme(drw, colors[SchemeOut]);
    271 	else
    272 		drwl_setscheme(drw, colors[SchemeNorm]);
    273 
    274 	return drwl_text(drw, x, y, w, bh, lrpad / 2, item->text, 0);
    275 }
    276 
    277 static void
    278 drawmenu(void)
    279 {
    280 	unsigned int curpos;
    281 	struct item *item;
    282 	int x = 0, y = 0, w;
    283 	char *censort;
    284 	DrwBuf *buf;
    285 
    286 	errno = 0;
    287 	if (!(buf = bufpool_getbuf(&pool, shm, mw, mh)))
    288 		die(errno ? "bufpool_getbuf:" : "no buffer available");
    289 	drwl_setimage(drw, buf->image);
    290 
    291 	drwl_setscheme(drw, colors[SchemeNorm]);
    292 	drwl_rect(drw, 0, 0, mw, mh, 1, 1);
    293 
    294 	if (prompt && *prompt) {
    295 		drwl_setscheme(drw, colors[SchemeSel]);
    296 		x = drwl_text(drw, x, 0, promptw, bh, lrpad / 2, prompt, 0);
    297 	}
    298 	/* draw input field */
    299 	w = (lines > 0 || !matches) ? mw - x : inputw;
    300 	drwl_setscheme(drw, colors[SchemeNorm]);
    301 	if (passwd) {
    302 	        censort = calloc(1, sizeof(text));
    303 		memset(censort, '*', strlen(text));
    304 		drwl_text(drw, x, 0, w, bh, lrpad / 2, censort, 0);
    305 		free(censort);
    306 	} else drwl_text(drw, x, 0, w, bh, lrpad / 2, text, 0);
    307 
    308 	curpos = TEXTW(text) - TEXTW(&text[cursor]);
    309 	if ((curpos += lrpad / 2 - 1) < w) {
    310 		drwl_setscheme(drw, colors[SchemeNorm]);
    311 		drwl_rect(drw, x + curpos, (bh - drw->font->height) / 2 + 1,
    312 			2, drw->font->height - 2, 1, 0);
    313 	}
    314 
    315 	if (lines > 0) {
    316 		/* draw vertical list */
    317 		for (item = curr; item != next; item = item->right)
    318 			drawitem(item, x, y += bh, mw - x);
    319 	} else if (matches) {
    320 		/* draw horizontal list */
    321 		x += inputw;
    322 		w = TEXTW("<");
    323 		if (curr->left) {
    324 			drwl_setscheme(drw, colors[SchemeNorm]);
    325 			drwl_text(drw, x, 0, w, bh, lrpad / 2, "<", 0);
    326 		}
    327 		x += w;
    328 		for (item = curr; item != next; item = item->right)
    329 			x = drawitem(item, x, 0, textw_clamp(item->text, mw - x - TEXTW(">")));
    330 		if (next) {
    331 			w = TEXTW(">");
    332 			drwl_setscheme(drw, colors[SchemeNorm]);
    333 			drwl_text(drw, mw - w, 0, w, bh, lrpad / 2, ">", 0);
    334 		}
    335 	}
    336 
    337 	drwl_setimage(drw, NULL);
    338 	wl_surface_set_buffer_scale(surface, scale);
    339 	wl_surface_attach(surface, buf->wl_buf, 0, 0);
    340 	wl_surface_damage_buffer(surface, 0, 0, mw, mh);
    341 	wl_surface_commit(surface);
    342 }
    343 
    344 static void
    345 frame_callback_handle_done(void *data, struct wl_callback *callback,
    346 		uint32_t time)
    347 {
    348 	wl_callback_destroy(frame_callback);
    349 	frame_callback = NULL;
    350 	drawmenu();
    351 }
    352 
    353 static const struct wl_callback_listener frame_callback_listener = {
    354 	.done = frame_callback_handle_done,
    355 };
    356 
    357 static void
    358 redraw()
    359 {
    360 	if (frame_callback)
    361 		return;
    362 	frame_callback = wl_surface_frame(surface);
    363 	wl_callback_add_listener(frame_callback, &frame_callback_listener, NULL);
    364 	wl_surface_commit(surface);
    365 }
    366 
    367 static void
    368 match(void)
    369 {
    370 	static char **tokv = NULL;
    371 	static int tokn = 0;
    372 
    373 	char buf[sizeof text], *s;
    374 	int i, tokc = 0;
    375 	size_t len, textsize;
    376 	struct item *item, *lprefix, *lsubstr, *prefixend, *substrend;
    377 
    378 	strcpy(buf, text);
    379 	/* separate input text into tokens to be matched individually */
    380 	for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " "))
    381 		if (++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv)))
    382 			die("cannot realloc %zu bytes:", tokn * sizeof *tokv);
    383 	len = tokc ? strlen(tokv[0]) : 0;
    384 
    385 	matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL;
    386 	textsize = strlen(text) + 1;
    387 	for (item = items; item && item->text; item++) {
    388 		for (i = 0; i < tokc; i++)
    389 			if (!fstrstr(item->text, tokv[i]))
    390 				break;
    391 		if (i != tokc) /* not all tokens match */
    392 			continue;
    393 		/* exact matches go first, then prefixes, then substrings */
    394 		if (!tokc || !fstrncmp(text, item->text, textsize))
    395 			appenditem(item, &matches, &matchend);
    396 		else if (!fstrncmp(tokv[0], item->text, len))
    397 			appenditem(item, &lprefix, &prefixend);
    398 		else
    399 			appenditem(item, &lsubstr, &substrend);
    400 	}
    401 	if (lprefix) {
    402 		if (matches) {
    403 			matchend->right = lprefix;
    404 			lprefix->left = matchend;
    405 		} else
    406 			matches = lprefix;
    407 		matchend = prefixend;
    408 	}
    409 	if (lsubstr) {
    410 		if (matches) {
    411 			matchend->right = lsubstr;
    412 			lsubstr->left = matchend;
    413 		} else
    414 			matches = lsubstr;
    415 		matchend = substrend;
    416 	}
    417 	curr = sel = matches;
    418 	calcoffsets();
    419 }
    420 
    421 static void
    422 insert(const char *str, ssize_t n)
    423 {
    424 	if (strlen(text) + n > sizeof text - 1)
    425 		return;
    426 	/* move existing text out of the way, insert new text, and update cursor */
    427 	memmove(&text[cursor + n], &text[cursor], sizeof text - cursor - MAX(n, 0));
    428 	if (str)
    429 		memcpy(&text[cursor], str, n);
    430 	cursor += n;
    431 	match();
    432 }
    433 
    434 static size_t
    435 nextrune(int inc)
    436 {
    437 	ssize_t n;
    438 
    439 	/* return location of next utf8 rune in the given direction (+1 or -1) */
    440 	for (n = cursor + inc; n + inc >= 0 && (text[n] & 0xc0) == 0x80; n += inc)
    441 		;
    442 	return n;
    443 }
    444 
    445 static void
    446 movewordedge(int dir)
    447 {
    448 	if (dir < 0) { /* move cursor to the start of the word*/
    449 		while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)]))
    450 			cursor = nextrune(-1);
    451 		while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)]))
    452 			cursor = nextrune(-1);
    453 	} else { /* move cursor to the end of the word */
    454 		while (text[cursor] && strchr(worddelimiters, text[cursor]))
    455 			cursor = nextrune(+1);
    456 		while (text[cursor] && !strchr(worddelimiters, text[cursor]))
    457 			cursor = nextrune(+1);
    458 	}
    459 }
    460 
    461 static void
    462 paste(void)
    463 {
    464 	int fds[2];
    465 	ssize_t n;
    466 	char buf[1024];
    467 
    468 	if (!data_offer)
    469 		return;
    470 
    471 	if (pipe(fds) < 0)
    472 		die("pipe");
    473 
    474 	wl_data_offer_receive(data_offer, "text/plain", fds[1]);
    475 	close(fds[1]);
    476 
    477 	wl_display_roundtrip(display);
    478 
    479 	for (;;) {
    480 		n = read(fds[0], buf, sizeof(buf));
    481 		if (n <= 0)
    482 			break;
    483 		insert(buf, n);
    484 	}
    485 	close(fds[0]);
    486 
    487 	wl_data_offer_destroy(data_offer);
    488 }
    489 
    490 static void
    491 keyboard_keypress(enum wl_keyboard_key_state state, xkb_keysym_t sym)
    492 {
    493 	char buf[8];
    494 
    495 	if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
    496 		return;
    497 
    498 	if (kbd.ctrl) {
    499 		switch (xkb_keysym_to_lower(sym)) {
    500 		case XKB_KEY_a: sym = XKB_KEY_Home; break;
    501 		case XKB_KEY_b: sym = XKB_KEY_Left; break;
    502 		case XKB_KEY_c: sym = XKB_KEY_Escape; break;
    503 		case XKB_KEY_d: sym = XKB_KEY_Delete; break;
    504 		case XKB_KEY_e: sym = XKB_KEY_End; break;
    505 		case XKB_KEY_f: sym = XKB_KEY_BackSpace; break;
    506 		case XKB_KEY_g: sym = XKB_KEY_Escape; break;
    507 		case XKB_KEY_h: sym = XKB_KEY_BackSpace; break;
    508 		case XKB_KEY_i: sym = XKB_KEY_Tab; break;
    509 		case XKB_KEY_j: /* fallthrough */
    510 		case XKB_KEY_J: /* fallthrough */
    511 		case XKB_KEY_m: /* fallthrough */
    512 		case XKB_KEY_M: sym = XKB_KEY_Return; break;
    513 		case XKB_KEY_n: sym = XKB_KEY_Right; break;
    514 		case XKB_KEY_p: sym = XKB_KEY_Up; break;
    515 
    516 		case XKB_KEY_k: /* delete right */
    517 			text[cursor] = '\0';
    518 			match();
    519 			goto draw;
    520 		case XKB_KEY_u: /* delete left */
    521 			insert(NULL, 0 - cursor);
    522 			goto draw;
    523 		case XKB_KEY_w: /* delete word */
    524 			while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)]))
    525 				insert(NULL, nextrune(-1) - cursor);
    526 			while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)]))
    527 				insert(NULL, nextrune(-1) - cursor);
    528 			goto draw;
    529 		case XKB_KEY_y: /* paste selection */
    530 		case XKB_KEY_Y:
    531 			paste();
    532 			goto draw;
    533 		case XKB_KEY_Left:
    534 		case XKB_KEY_KP_Left:
    535 			movewordedge(-1);
    536 			goto draw;
    537 		case XKB_KEY_Right:
    538 		case XKB_KEY_KP_Right:
    539 			movewordedge(+1);
    540 			goto draw;
    541 		case XKB_KEY_Return:
    542 		case XKB_KEY_KP_Enter:
    543 			break;
    544 		case XKB_KEY_bracketleft:
    545 			cleanup();
    546 			exit(EXIT_FAILURE);
    547 		default:
    548 			return;
    549 		}
    550 	} else if (kbd.alt) {
    551 		switch(sym) {
    552 		case XKB_KEY_b:
    553 			movewordedge(-1);
    554 			goto draw;
    555 		case XKB_KEY_f:
    556 			movewordedge(+1);
    557 			goto draw;
    558 		case XKB_KEY_g: sym = XKB_KEY_Home;  break;
    559 		case XKB_KEY_G: sym = XKB_KEY_End;   break;
    560 		case XKB_KEY_h: sym = XKB_KEY_Up;    break;
    561 		case XKB_KEY_j: sym = XKB_KEY_Next;  break;
    562 		case XKB_KEY_k: sym = XKB_KEY_Prior; break;
    563 		case XKB_KEY_l: sym = XKB_KEY_Down;  break;
    564 		default:
    565 			return;
    566 		}
    567 	}
    568 
    569 	switch (sym) {
    570 	case XKB_KEY_Delete:
    571 	case XKB_KEY_KP_Delete:
    572 		if (text[cursor] == '\0')
    573 			return;
    574 		cursor = nextrune(+1);
    575 		/* fallthrough */
    576 	case XKB_KEY_BackSpace:
    577 		if (cursor == 0)
    578 			return;
    579 		insert(NULL, nextrune(-1) - cursor);
    580 		break;
    581 	case XKB_KEY_End:
    582 	case XKB_KEY_KP_End:
    583 		if (text[cursor] != '\0') {
    584 			cursor = strlen(text);
    585 			break;
    586 		}
    587 		if (next) {
    588 			/* jump to end of list and position items in reverse */
    589 			curr = matchend;
    590 			calcoffsets();
    591 			curr = prev;
    592 			calcoffsets();
    593 			while (next && (curr = curr->right))
    594 				calcoffsets();
    595 		}
    596 		sel = matchend;
    597 		break;
    598 	case XKB_KEY_Escape:
    599 		cleanup();
    600 		exit(EXIT_FAILURE);
    601 	case XKB_KEY_Home:
    602 	case XKB_KEY_KP_Home:
    603 		if (sel == matches) {
    604 			cursor = 0;
    605 			break;
    606 		}
    607 		sel = curr = matches;
    608 		calcoffsets();
    609 		break;
    610 	case XKB_KEY_Left:
    611 	case XKB_KEY_KP_Left:
    612 		if (cursor > 0 && (!sel || !sel->left || lines > 0)) {
    613 			cursor = nextrune(-1);
    614 			break;
    615 		}
    616 		if (lines > 0)
    617 			return;
    618 		/* fallthrough */
    619 	case XKB_KEY_Up:
    620 	case XKB_KEY_KP_Up:
    621 		if (sel && sel->left && (sel = sel->left)->right == curr) {
    622 			curr = prev;
    623 			calcoffsets();
    624 		}
    625 		break;
    626 	case XKB_KEY_Next:
    627 	case XKB_KEY_KP_Next:
    628 		if (!next)
    629 			return;
    630 		sel = curr = next;
    631 		calcoffsets();
    632 		break;
    633 	case XKB_KEY_Prior:
    634 	case XKB_KEY_KP_Prior:
    635 		if (!prev)
    636 			return;
    637 		sel = curr = prev;
    638 		calcoffsets();
    639 		break;
    640 	case XKB_KEY_Return:
    641 	case XKB_KEY_KP_Enter:
    642 		submit((sel && !kbd.shift) ? sel->text : text);
    643 		if (!kbd.ctrl && submit != exec_cmd) {
    644 			running = 0;
    645 			return;
    646 		}
    647 		if (sel)
    648 			sel->out = 1;
    649 		break;
    650 	case XKB_KEY_Right:
    651 	case XKB_KEY_KP_Right:
    652 		if (text[cursor] != '\0') {
    653 			cursor = nextrune(+1);
    654 			break;
    655 		}
    656 		if (lines > 0)
    657 			return;
    658 		/* fallthrough */
    659 	case XKB_KEY_Down:
    660 	case XKB_KEY_KP_Down:
    661 		if (sel && sel->right && (sel = sel->right) == next) {
    662 			curr = next;
    663 			calcoffsets();
    664 		}
    665 		break;
    666 	case XKB_KEY_Tab:
    667 		if (!sel)
    668 			return;
    669 		cursor = strnlen(sel->text, sizeof text - 1);
    670 		memcpy(text, sel->text, cursor);
    671 		text[cursor] = '\0';
    672 		match();
    673 		break;
    674 	default:
    675 		if (xkb_keysym_to_utf8(sym, buf, 8))
    676 			insert(buf, strnlen(buf, 8));
    677 	}
    678 draw:
    679 	redraw();
    680 }
    681 
    682 static void
    683 keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard,
    684 		uint32_t format, int32_t fd, uint32_t size)
    685 {
    686 	char *map_shm;
    687 
    688 	if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
    689 		die("unknown keymap");
    690 
    691 	map_shm = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
    692 	if (map_shm == MAP_FAILED)
    693 		die("mmap:");
    694 
    695 	kbd.xkb_keymap = xkb_keymap_new_from_string(kbd.xkb_context, map_shm,
    696 		XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
    697 	munmap(map_shm, size);
    698 	close(fd);
    699 
    700 	kbd.xkb_state = xkb_state_new(kbd.xkb_keymap);
    701 }
    702 
    703 static void
    704 keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard,
    705 		uint32_t serial, struct wl_surface *surface)
    706 {
    707 	/*
    708 	 * In dmenu(1), if the keyboard cannot be grabbed, it will
    709 	 * immediately exit. This is done before dmenu is initialized,
    710 	 * but can't be the same for Wayland. If a new layer surface
    711 	 * wants keyboard, it will get keyboard, set_exclusivity doesn't
    712 	 * seem to work.
    713 	 */
    714 	 die("lost keyboard");
    715 }
    716 
    717 static void
    718 keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard,
    719 		uint32_t serial, uint32_t time, uint32_t key, uint32_t _key_state)
    720 {
    721 	struct itimerspec spec = { 0 };
    722 	enum wl_keyboard_key_state key_state = _key_state;
    723 	xkb_keysym_t sym = xkb_state_key_get_one_sym(kbd.xkb_state, key + 8);
    724 
    725 	keyboard_keypress(key_state, sym);
    726 
    727 	if (key_state == WL_KEYBOARD_KEY_STATE_PRESSED && kbd.repeat.period >= 0) {
    728 		kbd.repeat.key_state = key_state;
    729 		kbd.repeat.sym = sym;
    730 		spec.it_value.tv_sec = kbd.repeat.delay / 1000;
    731 		spec.it_value.tv_nsec = (kbd.repeat.delay % 1000) * 1000000l;
    732 	}
    733 	timerfd_settime(kbd.repeat.timer, 0, &spec, NULL);
    734 }
    735 
    736 static void
    737 keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard,
    738 		uint32_t serial, uint32_t mods_depressed,
    739 		uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
    740 {
    741 	xkb_state_update_mask(kbd.xkb_state,
    742 		mods_depressed, mods_latched, mods_locked, 0, 0, group);
    743 	kbd.ctrl = xkb_state_mod_name_is_active(kbd.xkb_state,
    744 		XKB_MOD_NAME_CTRL,
    745 		XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED);
    746 	kbd.shift = xkb_state_mod_name_is_active(kbd.xkb_state,
    747 		XKB_MOD_NAME_SHIFT,
    748 		XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED);
    749 	kbd.alt = xkb_state_mod_name_is_active(kbd.xkb_state,
    750 		XKB_MOD_NAME_ALT,
    751 		XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED);
    752 }
    753 
    754 static void
    755 keyboard_repeat(void)
    756 {
    757 	struct itimerspec spec = { 0 };
    758 
    759 	keyboard_keypress(kbd.repeat.key_state, kbd.repeat.sym);
    760 
    761 	spec.it_value.tv_sec = kbd.repeat.period / 1000;
    762 	spec.it_value.tv_nsec = (kbd.repeat.period % 1000) * 1000000l;
    763 	timerfd_settime(kbd.repeat.timer, 0, &spec, NULL);
    764 }
    765 
    766 static void
    767 keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
    768 		int32_t rate, int32_t delay)
    769 {
    770 	kbd.repeat.delay = delay;
    771 	kbd.repeat.period = rate >= 0 ? 1000 / rate : -1;
    772 }
    773 
    774 static const struct wl_keyboard_listener keyboard_listener = {
    775 	.keymap = keyboard_handle_keymap,
    776 	.enter = noop,
    777 	.leave = keyboard_handle_leave,
    778 	.key = keyboard_handle_key,
    779 	.modifiers = keyboard_handle_modifiers,
    780 	.repeat_info = keyboard_handle_repeat_info,
    781 };
    782 
    783 static void
    784 layer_surface_handle_configure(void *data, struct zwlr_layer_surface_v1 *layer_surface,
    785 		uint32_t serial, uint32_t width, uint32_t height)
    786 {
    787 	if (mw / scale == width && mh / scale == height)
    788 		return;
    789 
    790 	mw = width * scale;
    791 	mh = height * scale;
    792 	inputw = mw / 3; /* input width: ~33% of output width */
    793 	match();
    794 	zwlr_layer_surface_v1_ack_configure(layer_surface, serial);
    795 	drawmenu();
    796 }
    797 
    798 static void
    799 layer_surface_handle_closed(void *data, struct zwlr_layer_surface_v1 *surface)
    800 {
    801 	running = 0;
    802 }
    803 
    804 static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
    805 	.configure = layer_surface_handle_configure,
    806 	.closed = layer_surface_handle_closed,
    807 };
    808 
    809 static void
    810 surface_handle_preferred_scale(void *data,
    811 	struct wl_surface *wl_surface, int32_t factor)
    812 {
    813 	if (scale == factor)
    814 		return;
    815 	scale = factor;
    816 	loadfonts();
    817 
    818 	/* the scale of the surface is only known after an initial draw, not before :( */
    819 	zwlr_layer_surface_v1_set_size(layer_surface, 0, mh / scale);
    820 	redraw();
    821 }
    822 
    823 static const struct wl_surface_listener surface_listener = {
    824 	.enter = noop,
    825 	.leave = noop,
    826 	.preferred_buffer_scale = surface_handle_preferred_scale,
    827 	.preferred_buffer_transform = noop,
    828 };
    829 
    830 static void
    831 data_device_handle_selection(void *data, struct wl_data_device *data_device,
    832 		struct wl_data_offer *_data_offer)
    833 {
    834 	data_offer = _data_offer;
    835 }
    836 
    837 static const struct wl_data_device_listener data_device_listener = {
    838 	.data_offer = noop,
    839 	.selection = data_device_handle_selection,
    840 };
    841 
    842 static void
    843 output_handle_name(void *data, struct wl_output *wl_output, const char *name)
    844 {
    845 	if (output_name && !strcmp(name, output_name))
    846 		output = wl_output;
    847 	else
    848 		wl_output_destroy(wl_output);
    849 }
    850 
    851 static const struct wl_output_listener output_listener = {
    852 	.geometry = noop,
    853 	.mode = noop,
    854 	.done = noop,
    855 	.scale = noop,
    856 	.name = output_handle_name,
    857 	.description = noop,
    858 };
    859 
    860 static void
    861 seat_handle_capabilities(void *data, struct wl_seat *wl_seat, enum wl_seat_capability caps)
    862 {
    863 	if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD))
    864 		return;
    865 
    866 	kbd.wl_keyboard = wl_seat_get_keyboard(seat);
    867 	if (!(kbd.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS)))
    868 		die("xkb_context_new failed");
    869 	if ((kbd.repeat.timer = timerfd_create(CLOCK_MONOTONIC, 0)) < 0)
    870 		die("timerfd_create:");
    871 	wl_keyboard_add_listener(kbd.wl_keyboard, &keyboard_listener, NULL);
    872 }
    873 
    874 static const struct wl_seat_listener seat_listener = {
    875 	.capabilities = seat_handle_capabilities,
    876 	.name = noop,
    877 };
    878 
    879 static void
    880 registry_handle_global(void *data, struct wl_registry *registry,
    881 		uint32_t name, const char *interface, uint32_t version)
    882 {
    883 	if (!strcmp(interface, wl_compositor_interface.name))
    884 		compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 6);
    885  	else if (!strcmp(interface, wl_shm_interface.name))
    886 		shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
    887 	else if (!strcmp(interface, zwlr_layer_shell_v1_interface.name))
    888 		layer_shell = wl_registry_bind(registry, name,
    889 			&zwlr_layer_shell_v1_interface, 1);
    890 	else if (!strcmp(interface, wl_data_device_manager_interface.name))
    891 		data_device_manager = wl_registry_bind(registry, name,
    892 			&wl_data_device_manager_interface, 3);
    893 	else if (!strcmp(interface, xdg_activation_v1_interface.name))
    894 		activation = wl_registry_bind(registry, name, &xdg_activation_v1_interface, 1);
    895 	else if (!strcmp(interface, wl_output_interface.name)) {
    896 		struct wl_output *output = wl_registry_bind(registry, name,
    897 			&wl_output_interface, 4);
    898 		wl_output_add_listener(output, &output_listener, NULL);
    899 	} else if (!strcmp(interface, wl_seat_interface.name)) {
    900 		seat = wl_registry_bind (registry, name, &wl_seat_interface, 4);
    901 		wl_seat_add_listener(seat, &seat_listener, NULL);
    902 	}
    903 }
    904 
    905 static const struct wl_registry_listener registry_listener = {
    906 	.global = registry_handle_global,
    907 	.global_remove = noop,
    908 };
    909 
    910 static void
    911 readstdin(void)
    912 {
    913 	char *line = NULL;
    914 	size_t i, itemsiz = 0, linesiz = 0;
    915 	ssize_t len;
    916 	if(passwd){
    917     	inputw = lines = 0;
    918     	return;
    919   	}
    920 
    921 	/* read each line from stdin and add it to the item list */
    922 	for (i = 0; (len = getline(&line, &linesiz, stdin)) != -1; i++) {
    923 		if (i + 1 >= itemsiz) {
    924 			itemsiz += 256;
    925 			if (!(items = realloc(items, itemsiz * sizeof(*items))))
    926 				die("cannot realloc %zu bytes:", itemsiz * sizeof(*items));
    927 		}
    928 		if (line[len - 1] == '\n')
    929 			line[len - 1] = '\0';
    930 		if (!(items[i].text = strdup(line)))
    931 			die("strdup:");
    932 
    933 		items[i].out = 0;
    934 	}
    935 	free(line);
    936 	if (items)
    937 		items[i].text = NULL;
    938 	lines = MIN(lines, i);
    939 }
    940 
    941 static void
    942 run(void)
    943 {
    944 	struct pollfd pfds[] = {
    945 		{ wl_display_get_fd(display), POLLIN },
    946 		{ kbd.repeat.timer, POLLIN },
    947 	};
    948 
    949 	running = 1;
    950 	while (running) {
    951 		wl_display_flush(display);
    952 
    953 		if (poll(pfds, LENGTH(pfds), -1) < 0)
    954 			die("poll:");
    955 
    956 		if (pfds[0].revents & POLLIN)
    957 			if (wl_display_dispatch(display) < 0)
    958 				die("display dispatch failed");
    959 
    960 		if (pfds[1].revents & POLLIN)
    961 			keyboard_repeat();
    962 	}
    963 }
    964 
    965 static void
    966 setup(void)
    967 {
    968 	if (!(display = wl_display_connect(NULL)))
    969 		die("failed to connect to wayland");
    970 
    971 	registry = wl_display_get_registry(display);
    972 	wl_registry_add_listener(registry, &registry_listener, NULL);
    973 	wl_display_roundtrip(display);
    974 	wl_display_roundtrip(display); /* output & seat listeners */
    975 
    976 	if (!compositor)
    977 		die("wl_compositor not available");
    978 	if (!shm)
    979 		die("wl_shm not available");
    980 	if (!layer_shell)
    981 		die("layer_shell not available");
    982 	if (!data_device_manager)
    983 		die("data_device_manager not available");
    984 
    985 	if (output_name && !output)
    986 		die("output %s not found", output_name);
    987 
    988 	data_device = wl_data_device_manager_get_data_device(
    989 		data_device_manager, seat);
    990 	wl_data_device_add_listener(data_device, &data_device_listener, NULL);
    991 
    992 	drwl_init();
    993 	if (!(drw = drwl_create()))
    994 		die("cannot create drwl drawing context");
    995 	loadfonts();
    996 
    997 	surface = wl_compositor_create_surface(compositor);
    998 	wl_surface_add_listener(surface, &surface_listener, NULL);
    999 
   1000 	layer_surface = zwlr_layer_shell_v1_get_layer_surface(layer_shell,
   1001 				surface, output, ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "mew");
   1002 	zwlr_layer_surface_v1_set_size(layer_surface, 0, mh);
   1003 	zwlr_layer_surface_v1_set_anchor(layer_surface,
   1004 		(top ? ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP : ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ) |
   1005 		ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT);
   1006 	zwlr_layer_surface_v1_set_exclusive_zone(layer_surface, -1);
   1007 	zwlr_layer_surface_v1_set_keyboard_interactivity(layer_surface, 1);
   1008 	zwlr_layer_surface_v1_add_listener(layer_surface, &layer_surface_listener, NULL);
   1009 
   1010 	wl_surface_commit(surface);
   1011 }
   1012 
   1013 static void
   1014 usage(void)
   1015 {
   1016 	die("usage: mew [-beivP] [-l lines] [-p prompt] [-f font] [-o output]\n"
   1017 	    "           [-nb color] [-nf color] [-sb color] [-sf color]");
   1018 }
   1019 
   1020 int
   1021 main(int argc, char *argv[])
   1022 {
   1023 	int i;
   1024 
   1025 	for (i = 1; i < argc; i++) {
   1026 		/* these options take no arguments */
   1027 		if (!strcmp(argv[i], "-v")) {
   1028 			puts("mew-"VERSION);
   1029 			exit(0);
   1030 		} else if (!strcmp(argv[i], "-b"))
   1031 			top = 0;
   1032 		else if (!strcmp(argv[i], "-e"))
   1033 			submit = exec_cmd;
   1034 		else if (!strcmp(argv[i], "-i")) {
   1035 			fstrncmp = strncasecmp;
   1036 			fstrstr = cistrstr;
   1037 		} else if (!strcmp(argv[i], "-P"))   /* is the input a password */
   1038 			passwd = 1;
   1039 		else if (i + 1 == argc)
   1040 			usage();
   1041 		else if (!strcmp(argv[i], "-l"))
   1042 			lines = atoi(argv[++i]);
   1043 		else if (!strcmp(argv[i], "-o"))
   1044 			output_name = argv[++i];
   1045 		else if (!strcmp(argv[i], "-p"))
   1046 			prompt = argv[++i];
   1047 		else if (!strcmp(argv[i], "-f"))
   1048 			fonts[0] = argv[++i];
   1049 		else if (!strcmp(argv[i], "-nb"))
   1050 			parse_color(&colors[SchemeNorm][ColBg], argv[++i]);
   1051 		else if (!strcmp(argv[i], "-nf"))
   1052 			parse_color(&colors[SchemeNorm][ColFg], argv[++i]);
   1053 		else if (!strcmp(argv[i], "-sb"))
   1054 			parse_color(&colors[SchemeSel][ColBg], argv[++i]);
   1055 		else if (!strcmp(argv[i], "-sf"))
   1056 			parse_color(&colors[SchemeSel][ColFg], argv[++i]);
   1057 		else
   1058 			usage();
   1059 	}
   1060 
   1061 	readstdin();
   1062 #ifdef __OpenBSD__
   1063 	if (pledge("stdio rpath", NULL) == -1)
   1064 		die("pledge");
   1065 #endif
   1066 	setup();
   1067 	run();
   1068 	cleanup();
   1069 
   1070 	return EXIT_SUCCESS;
   1071 }
   1072