1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <stdbool.h>
5 #include <assert.h>
6 #include <ctype.h>
7 
8 #include <errno.h>
9 #include <limits.h>
10 #include <time.h>
11 #include <sys/mman.h>
12 #include <sys/epoll.h>
13 #include <sys/timerfd.h>
14 #include <fcntl.h>
15 #include <unistd.h>
16 #ifdef __linux__
17 #include <pty.h>
18 #elif defined(__FreeBSD__) || defined(__DragonFly__)
19 #include <sys/ttycom.h>
20 #include <sys/types.h>
21 #include <sys/ioctl.h>
22 #include <termios.h>
23 #include <libutil.h>
24 #endif
25 
26 
27 #include <xkbcommon/xkbcommon-compose.h>
28 #include <wayland-client-core.h>
29 #include <wayland-client-protocol.h>
30 #include <wayland-cursor.h>
31 
32 #include "tsm/libtsm.h"
33 #include "xdg-shell.h"
34 #include "gtk-primary-selection.h"
35 
36 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
37 
38 int font_init(int, char *, int *, int *);
39 void font_deinit(void);
40 unsigned char *get_glyph(uint32_t, uint32_t, int);
41 
42 static struct {
43 	bool die;
44 	bool configured;
45 	bool need_redraw;
46 	bool can_redraw;
47 	int resize;
48 
49 	int fd, master_fd;
50 
51 	struct wl_display *display;
52 	struct wl_registry *registry;
53 	struct wl_compositor *cp;
54 	struct wl_shm *shm;
55 	bool shm_argb;
56 	struct xdg_wm_base *wm_base;
57 	struct wl_seat *seat;
58 
59 	struct wl_surface *surf;
60 	struct xdg_surface *xdgsurf;
61 	struct xdg_toplevel *toplvl;
62 
63 	struct buffer {
64 		struct wl_buffer *b;
65 		void *data;
66 		int size;
67 		bool busy;
68 		tsm_age_t age;
69 	} buf[2];
70 	struct wl_callback *cb;
71 
72 	int col, row;
73 	int cwidth, cheight;
74 	int width, height;
75 	int confwidth, confheight;
76 	struct {
77 		int top, left;
78 	} margin;
79 
80 	struct tsm_screen *screen;
81 	struct tsm_vte *vte;
82 	unsigned int mods;
83 
84 	struct xkb_context *xkb_ctx;
85 	struct xkb_state *xkb_state;
86 	struct xkb_keymap *xkb_keymap;
87 	struct xkb_compose_table *xkb_compose_table;
88 	struct xkb_compose_state *xkb_compose_state;
89 	xkb_mod_index_t xkb_alt;
90 	xkb_mod_index_t xkb_ctrl;
91 	xkb_mod_index_t xkb_shift;
92 
93 	struct wl_keyboard *kbd;
94 	struct wl_pointer *ptr;
95 	wl_fixed_t ptr_x, ptr_y;
96 	int select;
97 
98 	struct {
99 		struct wl_cursor_theme *theme;
100 		struct wl_cursor *current;
101 		long long anim_start;
102 		struct wl_surface *surface;
103 		struct wl_callback *callback;
104 		uint32_t enter_serial;
105 	} cursor;
106 
107 	struct {
108 		int fd;
109 		uint32_t key;
110 		xkb_keysym_t sym;
111 		uint32_t unicode;
112 		void (*action)(void);
113 		struct itimerspec its;
114 	} repeat;
115 
116 	struct wl_data_device_manager *d_dm;
117 	struct wl_data_device *d_d;
118 	struct gtk_primary_selection_device_manager *ps_dm;
119 	struct gtk_primary_selection_device *ps_d;
120 
121 	struct {
122 		struct wl_data_source *source;
123 		char *data;
124 	} d_copy;
125 
126 	struct {
127 		struct gtk_primary_selection_source *source;
128 		char *data;
129 	} ps_copy;
130 
131 	struct {
132 		struct wl_data_offer *d_offer;
133 		struct gtk_primary_selection_offer *ps_offer;
134 		bool d_acceptable;
135 		bool ps_acceptable;
136 
137 		int fd[2];
138 		char buf[200];
139 		size_t len;
140 		bool active;
141 	} paste;
142 
143 	struct {
144 		bool linger;
145 		char *config;
146 		char *display;
147 		char *app_id;
148 	} opt;
149 
150 	struct binding {
151 		struct binding *next;
152 		unsigned int mods;
153 		xkb_keysym_t sym;
154 		void (*action)(void);
155 	} *binding;
156 
157 	struct {
158 		char shell[32];
159 		int col, row;
160 		int scrollback;
161 		bool margin;
162 		unsigned char opacity;
163 		int font_size;
164 		char font_path[512];
165 		uint8_t colors[TSM_COLOR_NUM][3];
166 	} cfg;
167 } term = {
168 	.cfg.shell = "/bin/sh",
169 	.cfg.col = 80,
170 	.cfg.row = 24,
171 	.cfg.scrollback = 0,
172 	.cfg.margin = false,
173 	.cfg.opacity = 0xff,
174 	.cfg.font_size = 18,
175 	.cfg.font_path = "",
176 	.cfg.colors = {
177 		[TSM_COLOR_BLACK]         = {   0,   0,   0 },
178 		[TSM_COLOR_RED]           = { 205,   0,   0 },
179 		[TSM_COLOR_GREEN]         = {   0, 205,   0 },
180 		[TSM_COLOR_YELLOW]        = { 205, 205,   0 },
181 		[TSM_COLOR_BLUE]          = {   0,   0, 238 },
182 		[TSM_COLOR_MAGENTA]       = { 205,   0, 205 },
183 		[TSM_COLOR_CYAN]          = {   0, 205, 205 },
184 		[TSM_COLOR_LIGHT_GREY]    = { 229, 229, 229 },
185 		[TSM_COLOR_DARK_GREY]     = { 127, 127, 127 },
186 		[TSM_COLOR_LIGHT_RED]     = { 255,   0,   0 },
187 		[TSM_COLOR_LIGHT_GREEN]   = {   0, 255,   0 },
188 		[TSM_COLOR_LIGHT_YELLOW]  = { 255, 255,   0 },
189 		[TSM_COLOR_LIGHT_BLUE]    = {  92,  92, 255 },
190 		[TSM_COLOR_LIGHT_MAGENTA] = { 255,   0, 255 },
191 		[TSM_COLOR_LIGHT_CYAN]    = {   0, 255, 255 },
192 		[TSM_COLOR_WHITE]         = { 255, 255, 255 },
193 		[TSM_COLOR_FOREGROUND]    = { 229, 229, 229 },
194 		[TSM_COLOR_BACKGROUND]    = {   0,   0,   0 },
195 	},
196 	.opt.app_id = "havoc"
197 };
198 
wcb(struct tsm_vte * vte,const char * u8,size_t len,void * data)199 static void wcb(struct tsm_vte *vte, const char *u8, size_t len, void *data)
200 {
201 	assert(len <= PIPE_BUF);
202 	if (term.master_fd >= 0 && write(term.master_fd, u8, len) < 0) {
203 		fprintf(stderr, "could not write to pty master: %m\n");
204 		abort();
205 	}
206 }
207 
handle_display(int ev)208 static void handle_display(int ev)
209 {
210 	if (ev & EPOLLHUP) {
211 		term.die = true;
212 	} else if (ev & EPOLLIN) {
213 		if (wl_display_dispatch(term.display) < 0) {
214 			fprintf(stderr, "could not dispatch events: %m\n");
215 			abort();
216 		}
217 	}
218 }
219 
handle_tty(int ev)220 static void handle_tty(int ev)
221 {
222 	char data[256];
223 	int len;
224 
225 	if (ev & EPOLLHUP) {
226 		epoll_ctl(term.fd, EPOLL_CTL_DEL, term.master_fd, NULL);
227 		close(term.master_fd);
228 		term.master_fd = -1;
229 		if (!term.opt.linger)
230 			term.die = true;
231 	} else if (ev & EPOLLIN) {
232 		term.need_redraw = true;
233 		len = read(term.master_fd, data, sizeof(data));
234 		assert(len);
235 		if (len < 0) {
236 			fprintf(stderr, "could not read from pty: %m\n");
237 			abort();
238 		} else {
239 			tsm_vte_input(term.vte, data, len);
240 		}
241 	}
242 }
243 
handle_repeat(int ev)244 static void handle_repeat(int ev)
245 {
246 	uint64_t exp;
247 
248 	if (read(term.repeat.fd, &exp, sizeof exp) < 0)
249 		return;
250 
251 	if (term.repeat.action) {
252 		term.repeat.action();
253 		return;
254 	}
255 
256 	tsm_vte_handle_keyboard(term.vte, term.repeat.sym, XKB_KEY_NoSymbol,
257 				term.mods, term.repeat.unicode);
258 }
259 
now(void)260 static long long now(void)
261 {
262 	struct timespec t;
263 
264 	clock_gettime(CLOCK_MONOTONIC, &t);
265 	return (long long)t.tv_sec * 1000 + t.tv_nsec / 1000000;
266 }
267 
cursor_draw(int frame)268 static void cursor_draw(int frame)
269 {
270 	struct wl_buffer *buffer;
271 	struct wl_cursor_image *image;
272 
273 	if ((int)term.cursor.current->image_count <= frame) {
274 		fprintf(stderr, "cursor frame index out of range\n");
275 		return;
276 	}
277 
278 	image = term.cursor.current->images[frame];
279 	buffer = wl_cursor_image_get_buffer(image);
280 	wl_surface_attach(term.cursor.surface, buffer, 0, 0);
281 	wl_surface_damage(term.cursor.surface, 0, 0,
282 			  image->width, image->height);
283 	wl_surface_commit(term.cursor.surface);
284 	wl_pointer_set_cursor(term.ptr, term.cursor.enter_serial,
285 			      term.cursor.surface,
286 			      image->hotspot_x, image->hotspot_y);
287 }
288 
289 static void cursor_request_frame_callback(void);
290 
cursor_frame_callback(void * data,struct wl_callback * cb,uint32_t time)291 static void cursor_frame_callback(void *data, struct wl_callback *cb,
292 				  uint32_t time)
293 {
294 	int frame = wl_cursor_frame(term.cursor.current,
295 				    now() - term.cursor.anim_start);
296 
297 	assert(cb == term.cursor.callback);
298 	wl_callback_destroy(term.cursor.callback);
299 	cursor_request_frame_callback();
300 	cursor_draw(frame);
301 }
302 
303 static const struct wl_callback_listener cursor_frame_listener = {
304 	cursor_frame_callback
305 };
306 
cursor_request_frame_callback(void)307 static void cursor_request_frame_callback(void)
308 {
309 	term.cursor.callback = wl_surface_frame(term.cursor.surface);
310 	wl_callback_add_listener(term.cursor.callback, &cursor_frame_listener,
311 				 NULL);
312 }
313 
cursor_unset(void)314 static void cursor_unset(void)
315 {
316 	if (term.cursor.callback) {
317 		wl_callback_destroy(term.cursor.callback);
318 		term.cursor.callback = NULL;
319 	}
320 	term.cursor.current = NULL;
321 }
322 
cursor_set(const char * name)323 static void cursor_set(const char *name)
324 {
325 	uint32_t duration;
326 	int frame;
327 
328 	cursor_unset();
329 
330 	if (term.ptr == NULL)
331 		return;
332 
333 	if (term.cursor.theme == NULL)
334 		goto hide;
335 
336 	if (name == NULL)
337 		goto hide;
338 
339 	term.cursor.current = wl_cursor_theme_get_cursor(term.cursor.theme,
340 							 name);
341 	if (term.cursor.current == NULL)
342 		goto hide;
343 
344 	frame = wl_cursor_frame_and_duration(term.cursor.current, 0, &duration);
345 	if (duration) {
346 		term.cursor.anim_start = now();
347 		cursor_request_frame_callback();
348 	}
349 	cursor_draw(frame);
350 
351 	return;
352 hide:
353 	wl_pointer_set_cursor(term.ptr, term.cursor.enter_serial, NULL, 0, 0);
354 }
355 
cursor_init(void)356 static void cursor_init(void)
357 {
358 	int size = 32;
359 	char *size_str = getenv("XCURSOR_SIZE");
360 
361 	if (size_str && *size_str) {
362 		char *end;
363 		long s;
364 
365 		errno = 0;
366 		s = strtol(size_str, &end, 10);
367 		if (errno == 0 && *end == '\0' && s > 0)
368 			size = s;
369 	}
370 
371 	term.cursor.theme = wl_cursor_theme_load(getenv("XCURSOR_THEME"), size,
372 						 term.shm);
373 	if (term.cursor.theme == NULL)
374 		return;
375 
376 	term.cursor.surface = wl_compositor_create_surface(term.cp);
377 	if (term.cursor.surface == NULL) {
378 		wl_cursor_theme_destroy(term.cursor.theme);
379 		term.cursor.theme = NULL;
380 	}
381 }
382 
cursor_free(void)383 static void cursor_free(void)
384 {
385 	if (term.cursor.callback)
386 		wl_callback_destroy(term.cursor.callback);
387 	if (term.cursor.surface)
388 		wl_surface_destroy(term.cursor.surface);
389 	if (term.cursor.theme)
390 		wl_cursor_theme_destroy(term.cursor.theme);
391 }
392 
393 #define REPLACEMENT_CHAR 0x0000fffd
394 
utf8_to_utf32(char const ** utf8,size_t * len,uint32_t * r)395 static int utf8_to_utf32(char const **utf8, size_t *len, uint32_t *r)
396 {
397 	static unsigned char const tail_len[128] = {
398 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
399 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
400 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
401 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
402 		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
403 		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
404 		2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
405 		3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0
406 	};
407 	unsigned char tail, c = *(*utf8)++;
408 
409 	--(*len);
410 	if (c < 0x80) {
411 		*r = c;
412 		return 0;
413 	}
414 
415 	tail = tail_len[c - 0x80];
416 
417 	if (!tail) {
418 		/* middle of a character or tail too long */
419 		*r = REPLACEMENT_CHAR;
420 		return 0;
421 	} else if (tail > *len) {
422 		/* need more input for a complete character */
423 		++(*len), --(*utf8);
424 		return 1;
425 	}
426 
427 	/* remove length specification bits */
428 	*r = c & 0x3f >> tail;
429 
430 	while (tail--) {
431 		c = *(*utf8)++;
432 		--(*len);
433 		if ((c & 0xc0) != 0x80) {
434 			*r = REPLACEMENT_CHAR;
435 			++(*len), --(*utf8);
436 			return 0;
437 		}
438 		*r = (*r << 6) + (c & 0x3f);
439 	}
440 	return 0;
441 }
442 
end_paste(void)443 static void end_paste(void)
444 {
445 	tsm_vte_paste_end(term.vte);
446 	epoll_ctl(term.fd, EPOLL_CTL_DEL, term.paste.fd[0], NULL);
447 	close(term.paste.fd[0]);
448 	term.paste.len = 0;
449 	term.paste.active = false;
450 }
451 
handle_paste(int ev)452 static void handle_paste(int ev)
453 {
454 	if (ev & EPOLLIN) {
455 		uint32_t code;
456 		ssize_t len;
457 		char const *p = &term.paste.buf[0];
458 
459 		len = read(term.paste.fd[0],
460 			   term.paste.buf + term.paste.len,
461 			   sizeof(term.paste.buf) - term.paste.len);
462 
463 		if (len <= 0) {
464 			end_paste();
465 			return;
466 		}
467 
468 		term.need_redraw = true;
469 		term.paste.len += len;
470 		while (term.paste.len > 0) {
471 			if (utf8_to_utf32(&p, &term.paste.len, &code)) {
472 				memcpy(&term.paste.buf, p, term.paste.len);
473 				break;
474 			}
475 			tsm_vte_handle_keyboard(term.vte, XKB_KEY_NoSymbol,
476 						XKB_KEY_NoSymbol, 0, code);
477 		}
478 	} else if (ev & EPOLLHUP) {
479 		end_paste();
480 	}
481 }
482 
483 static struct epcb {
484 	void (*f)(int);
485 } dfp = { handle_display }
486 , tfp = { handle_tty }
487 , rfp = { handle_repeat }
488 , pfp = { handle_paste };
489 
buffer_release(void * data,struct wl_buffer * b)490 static void buffer_release(void *data, struct wl_buffer *b)
491 {
492 	struct buffer *buffer = data;
493 
494 	buffer->busy = false;
495 }
496 
497 static const struct wl_buffer_listener buffer_listener = {
498 	buffer_release
499 };
500 
buffer_init(struct buffer * buf)501 static int buffer_init(struct buffer *buf)
502 {
503 	struct wl_shm_pool *pool;
504 	char shm_name[14];
505 	int fd, stride;
506 	int max = 100;
507 
508 	assert(!buf->busy);
509 
510 	stride = term.width * 4;
511 	buf->size = stride * term.height;
512 
513 	srand(time(NULL));
514 	do {
515 		sprintf(shm_name, "/havoc-%d", rand() % 1000000);
516 		fd = shm_open(shm_name, O_RDWR | O_CREAT | O_EXCL, 0600);
517 	} while (fd < 0 && errno == EEXIST && --max);
518 
519 	if (fd < 0) {
520 		fprintf(stderr, "shm_open failed: %m\n");
521 		return -1;
522 	}
523 	shm_unlink(shm_name);
524 
525 	if (ftruncate(fd, buf->size) < 0) {
526 		fprintf(stderr, "ftruncate failed: %m\n");
527 		close(fd);
528 		return -1;
529 	}
530 
531 	buf->data = mmap(NULL, buf->size, PROT_READ | PROT_WRITE, MAP_SHARED,
532 			 fd, 0);
533 
534 	if (buf->data == MAP_FAILED) {
535 		fprintf(stderr, "mmap failed: %m\n");
536 		close(fd);
537 		return -1;
538 	}
539 
540 	pool = wl_shm_create_pool(term.shm, fd, buf->size);
541 	buf->b = wl_shm_pool_create_buffer(pool, 0, term.width, term.height,
542 					   stride, WL_SHM_FORMAT_ARGB8888);
543 	wl_buffer_add_listener(buf->b, &buffer_listener, buf);
544 	wl_shm_pool_destroy(pool);
545 	close(fd);
546 
547 	buf->age = 0;
548 
549 	return 0;
550 }
551 
buffer_unmap(struct buffer * buf)552 static void buffer_unmap(struct buffer *buf)
553 {
554 	if (buf->b) {
555 		wl_buffer_destroy(buf->b);
556 		munmap(buf->data, buf->size);
557 	}
558 }
559 
swap_buffers(void)560 static struct buffer *swap_buffers(void)
561 {
562 	struct buffer *buf;
563 
564 	assert(term.configured);
565 
566 	if (!term.buf[0].busy)
567 		buf = &term.buf[0];
568 	else if (!term.buf[1].busy)
569 		buf = &term.buf[1];
570 	else
571 		abort();
572 
573 	if (term.resize) {
574 		buffer_unmap(buf);
575 		if (buffer_init(buf) < 0)
576 			abort();
577 	}
578 
579 	return buf;
580 }
581 
582 #define mul(a, b) (((a) * (b) + 255) >> 8)
583 #define join(a, r, g, b) ((a) << 24 | (r) << 16 | (g) << 8 | (b))
584 
585 typedef uint_fast8_t uf8;
586 
blank(uint32_t * dst,int w,uf8 br,uf8 bg,uf8 bb,uf8 ba)587 static void blank(uint32_t *dst, int w, uf8 br, uf8 bg, uf8 bb, uf8 ba)
588 {
589 	int i;
590 	uint32_t b;
591 	int h = term.cheight;
592 
593 	b = join(ba, mul(br, ba), mul(bg, ba), mul(bb, ba));
594 	w *= term.cwidth;
595 
596 	while (h--) {
597 		for (i = 0; i < w; ++i)
598 			dst[i] = b;
599 		dst += term.width;
600 	}
601 }
602 
print(uint32_t * dst,int w,uf8 br,uf8 bg,uf8 bb,uf8 fr,uf8 fg,uf8 fb,uf8 ba,unsigned char * glyph)603 static void print(uint32_t *dst, int w,
604 		  uf8 br, uf8 bg, uf8 bb,
605 		  uf8 fr, uf8 fg, uf8 fb,
606 		  uf8 ba, unsigned char *glyph)
607 {
608 	int i;
609 	int h = term.cheight;
610 
611 	w *= term.cwidth;
612 
613 	br = mul(br, ba);
614 	bg = mul(bg, ba);
615 	bb = mul(bb, ba);
616 	while (h--) {
617 		for (i = 0; i < w; ++i) {
618 			uf8 fa = glyph[i];
619 			if (fa == 0) {
620 				dst[i] = join(ba, br, bg, bb);
621 			} else if (fa == 0xff) {
622 				dst[i] = join(0xff, fr, fg, fb);
623 			} else {
624 				uf8 ca = 255 - fa;
625 				dst[i] = join(fa + mul(ba, ca),
626 					mul(fr, fa) + mul(br, ca),
627 					mul(fg, fa) + mul(bg, ca),
628 					mul(fb, fa) + mul(bb, ca));
629 			}
630 		}
631 
632 		glyph += w;
633 		dst += term.width;
634 	}
635 }
636 
draw_cell(struct tsm_screen * tsm,uint32_t id,const uint32_t * ch,size_t len,int char_width,int x,int y,const struct tsm_screen_attr * a,tsm_age_t age,void * data)637 static int draw_cell(struct tsm_screen *tsm, uint32_t id, const uint32_t *ch,
638 		     size_t len, int char_width, int x, int y,
639 		     const struct tsm_screen_attr *a, tsm_age_t age,
640 		     void *data)
641 {
642 	struct buffer *buffer = data;
643 	uint32_t *dst = buffer->data;
644 
645 	if (age && age <= buffer->age)
646 		return 0;
647 
648 	dst += term.margin.top * term.width + term.margin.left;
649 	dst = &dst[y * term.cheight * term.width + x * term.cwidth];
650 
651 	if (len == 0) {
652 		if (a->inverse)
653 			blank(dst, char_width,
654 			      ~a->br, ~a->bg, ~a->bb, term.cfg.opacity);
655 		else
656 			blank(dst, char_width,
657 			      a->br, a->bg, a->bb, term.cfg.opacity);
658 	} else {
659 		/* todo, combining marks */
660 		unsigned char *g = get_glyph(id, ch[0], char_width);
661 
662 		if (a->inverse)
663 			print(dst, char_width,
664 			      ~a->br, ~a->bg, ~a->bb,
665 			      ~a->fr, ~a->fg, ~a->fb,
666 			      term.cfg.opacity, g);
667 		else
668 			print(dst, char_width,
669 			      a->br, a->bg, a->bb,
670 			      a->fr, a->fg, a->fb,
671 			      term.cfg.opacity, g);
672 	}
673 
674 	return 0;
675 }
676 
draw_margin(struct buffer * buffer)677 static void draw_margin(struct buffer *buffer)
678 {
679 	uint32_t *dst = buffer->data;
680 	uint8_t a = term.cfg.opacity;
681 	uint8_t *rgb = term.cfg.colors[TSM_COLOR_BACKGROUND];
682 	uint32_t c = join(a, mul(rgb[0], a), mul(rgb[1], a), mul(rgb[2], a));
683 	int inw = term.col * term.cwidth;
684 	int inh = term.row * term.cheight;
685 	int i, j;
686 
687 	for (i = 0; i < term.width * term.margin.top; ++i)
688 		dst[i] = c;
689 
690 	for (i = (term.margin.top + inh) * term.width;
691 	     i < term.height * term.width;
692 	     ++i)
693 		dst[i] = c;
694 
695 	for (i = term.margin.top; i < term.margin.top + inh; ++i) {
696 		for (j = 0; j < term.margin.left; ++j)
697 			dst[i * term.width + j] = c;
698 
699 		for (j = term.margin.left + inw; j < term.width; ++j)
700 			dst[i * term.width + j] = c;
701 	}
702 }
703 
frame_callback(void * data,struct wl_callback * cb,uint32_t time)704 static void frame_callback(void *data, struct wl_callback *cb, uint32_t time)
705 {
706 	assert(term.cb == cb);
707 	wl_callback_destroy(cb);
708 	term.cb = NULL;
709 	term.can_redraw = true;
710 }
711 
712 static const struct wl_callback_listener frame_listener = {
713 	frame_callback
714 };
715 
redraw(void)716 static void redraw(void)
717 {
718 	struct buffer *buffer = swap_buffers();
719 
720 	wl_surface_attach(term.surf, buffer->b, 0, 0);
721 	buffer->age = tsm_screen_draw(term.screen, draw_cell, buffer);
722 	if (buffer->age == 0)
723 		term.buf[0].age = term.buf[1].age = 0;
724 	wl_surface_damage(term.surf, 0, 0, term.width, term.height);
725 
726 	term.cb = wl_surface_frame(term.surf);
727 	wl_callback_add_listener(term.cb, &frame_listener, NULL);
728 	wl_surface_commit(term.surf);
729 
730 	buffer->busy = true;
731 	term.can_redraw = false;
732 	term.need_redraw = false;
733 	if (term.resize) {
734 		--term.resize;
735 
736 		if (term.cfg.margin)
737 			draw_margin(buffer);
738 	}
739 }
740 
paste(bool primary)741 static void paste(bool primary)
742 {
743 	struct epoll_event ee;
744 
745 	if (primary) {
746 		if (!term.ps_dm || !term.paste.ps_acceptable)
747 			return;
748 	} else {
749 		if (!term.d_dm || !term.paste.d_acceptable)
750 			return;
751 	}
752 
753 	if (term.paste.active)
754 		end_paste();
755 
756 	if (pipe(term.paste.fd) < 0)
757 		return;
758 
759 	if (primary) {
760 		gtk_primary_selection_offer_receive(term.paste.ps_offer,
761 						    "UTF8_STRING",
762 						    term.paste.fd[1]);
763 	} else {
764 		wl_data_offer_receive(term.paste.d_offer, "UTF8_STRING",
765 				      term.paste.fd[1]);
766 	}
767 	close(term.paste.fd[1]);
768 
769 	ee.events = EPOLLIN;
770 	ee.data.ptr = &pfp;
771 	epoll_ctl(term.fd, EPOLL_CTL_ADD, term.paste.fd[0], &ee);
772 
773 	term.paste.active = true;
774 	tsm_vte_paste_begin(term.vte);
775 }
776 
action_paste(void)777 static void action_paste(void)
778 {
779 	paste(false);
780 }
781 
ds_target(void * d,struct wl_data_source * ds,const char * mt)782 static void ds_target(void *d, struct wl_data_source *ds, const char *mt)
783 {
784 }
785 
ds_send(void * data,struct wl_data_source * ds,const char * mime_type,int32_t fd)786 static void ds_send(void *data, struct wl_data_source *ds,
787 		    const char *mime_type, int32_t fd)
788 {
789 	write(fd, term.d_copy.data, strlen(term.d_copy.data));
790 	close(fd);
791 }
792 
ds_cancelled(void * data,struct wl_data_source * source)793 static void ds_cancelled(void *data, struct wl_data_source *source)
794 {
795 	wl_data_source_destroy(term.d_copy.source);
796 	term.d_copy.source = NULL;
797 	free(term.d_copy.data);
798 }
799 
ds_dnd_drop_performed(void * data,struct wl_data_source * ds)800 static void ds_dnd_drop_performed(void *data, struct wl_data_source *ds)
801 {
802 }
803 
ds_dnd_finished(void * data,struct wl_data_source * ds)804 static void ds_dnd_finished(void *data, struct wl_data_source *ds)
805 {
806 }
807 
ds_action(void * data,struct wl_data_source * ds,uint32_t a)808 static void ds_action(void *data, struct wl_data_source *ds, uint32_t a)
809 {
810 }
811 
812 static struct wl_data_source_listener ds_listener = {
813 	ds_target,
814 	ds_send,
815 	ds_cancelled,
816 	ds_dnd_drop_performed,
817 	ds_dnd_finished,
818 	ds_action
819 };
820 
d_copy(uint32_t serial)821 static void d_copy(uint32_t serial)
822 {
823 	if (!term.d_dm)
824 		return;
825 
826 	if (tsm_screen_selection_copy(term.screen, &term.d_copy.data) < 0)
827 		return;
828 
829 	term.d_copy.source =
830 		wl_data_device_manager_create_data_source(term.d_dm);
831 	wl_data_source_offer(term.d_copy.source, "UTF8_STRING");
832 	wl_data_source_add_listener(term.d_copy.source, &ds_listener, NULL);
833 	wl_data_device_set_selection(term.d_d, term.d_copy.source, serial);
834 }
835 
d_uncopy(void)836 static void d_uncopy(void)
837 {
838 	if (!term.d_dm)
839 		return;
840 
841 	if (!term.d_copy.source)
842 		return;
843 
844 	ds_cancelled(NULL, term.d_copy.source);
845 }
846 
847 static uint32_t action_copy_serial;
action_copy(void)848 static void action_copy(void)
849 {
850 	d_uncopy();
851 	if (term.select == 3)
852 		d_copy(action_copy_serial);
853 }
854 
reset_repeat(void)855 static void reset_repeat(void)
856 {
857 	struct itimerspec its = {
858 		{ 0, 0 }, { 0, 0 }
859 	};
860 
861 	timerfd_settime(term.repeat.fd, 0, &its, NULL);
862 }
863 
setup_compose(void)864 static void setup_compose(void)
865 {
866 	struct xkb_compose_table *compose_table;
867 	struct xkb_compose_state *compose_state;
868 	char *lang = getenv("LANG");
869 
870 	if (lang == NULL)
871 		return;
872 
873 	compose_table =
874 		xkb_compose_table_new_from_locale(term.xkb_ctx,
875 						  lang,
876 						  XKB_COMPOSE_COMPILE_NO_FLAGS);
877 	if (!compose_table) {
878 		fprintf(stderr, "could not create XKB compose table "
879 				"for locale '%s'.\n", lang);
880 		return;
881 	}
882 
883 	compose_state = xkb_compose_state_new(compose_table,
884 					      XKB_COMPOSE_STATE_NO_FLAGS);
885 	if (!compose_state) {
886 		fprintf(stderr, "could not create XKB compose state. "
887 				"Disabling compose.\n");
888 		xkb_compose_table_unref(compose_table);
889 		return;
890 	}
891 
892 	xkb_compose_table_unref(term.xkb_compose_table);
893 	xkb_compose_state_unref(term.xkb_compose_state);
894 	term.xkb_compose_table = compose_table;
895 	term.xkb_compose_state = compose_state;
896 }
897 
kbd_keymap(void * data,struct wl_keyboard * k,uint32_t fmt,int32_t fd,uint32_t size)898 static void kbd_keymap(void *data, struct wl_keyboard *k, uint32_t fmt,
899 		       int32_t fd, uint32_t size)
900 {
901 	struct xkb_keymap *keymap;
902 	struct xkb_state *state;
903 	char *map;
904 
905 	if (fmt != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
906 		close(fd);
907 		return;
908 	}
909 
910 	map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
911 	if (map == MAP_FAILED) {
912 		close(fd);
913 		return;
914 	}
915 
916 	keymap = xkb_keymap_new_from_string(term.xkb_ctx, map,
917 					    XKB_KEYMAP_FORMAT_TEXT_V1,
918 					    XKB_KEYMAP_COMPILE_NO_FLAGS);
919 	munmap(map, size);
920 	close(fd);
921 
922 	if (!keymap) {
923 		fprintf(stderr, "failed to compile keymap\n");
924 		return;
925 	}
926 
927 	state = xkb_state_new(keymap);
928 	if (!state) {
929 		fprintf(stderr, "failed to create XKB state\n");
930 		xkb_keymap_unref(keymap);
931 		return;
932 	}
933 
934 	xkb_keymap_unref(term.xkb_keymap);
935 	xkb_state_unref(term.xkb_state);
936 	term.xkb_keymap = keymap;
937 	term.xkb_state = state;
938 
939 	setup_compose();
940 
941 	term.xkb_ctrl = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL);
942 	term.xkb_alt = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_ALT);
943 	term.xkb_shift = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT);
944 }
945 
kbd_enter(void * data,struct wl_keyboard * k,uint32_t serial,struct wl_surface * surf,struct wl_array * keys)946 static void kbd_enter(void *data, struct wl_keyboard *k, uint32_t serial,
947 		      struct wl_surface *surf, struct wl_array *keys)
948 {
949 }
950 
kbd_leave(void * data,struct wl_keyboard * k,uint32_t serial,struct wl_surface * surf)951 static void kbd_leave(void *data, struct wl_keyboard *k, uint32_t serial,
952 		      struct wl_surface *surf)
953 {
954 	reset_repeat();
955 }
956 
compose(xkb_keysym_t sym)957 static xkb_keysym_t compose(xkb_keysym_t sym)
958 {
959 	if (!term.xkb_compose_state)
960 		return sym;
961 	if (sym == XKB_KEY_NoSymbol)
962 		return sym;
963 	if (xkb_compose_state_feed(term.xkb_compose_state,
964 				   sym) != XKB_COMPOSE_FEED_ACCEPTED)
965 		return sym;
966 
967 	switch (xkb_compose_state_get_status(term.xkb_compose_state)) {
968 	case XKB_COMPOSE_COMPOSED:
969 		return xkb_compose_state_get_one_sym(term.xkb_compose_state);
970 	case XKB_COMPOSE_COMPOSING:
971 	case XKB_COMPOSE_CANCELLED:
972 		return XKB_KEY_NoSymbol;
973 	case XKB_COMPOSE_NOTHING:
974 	default:
975 		return sym;
976 	}
977 }
978 
kbd_key(void * data,struct wl_keyboard * k,uint32_t serial,uint32_t time,uint32_t key,uint32_t state)979 static void kbd_key(void *data, struct wl_keyboard *k, uint32_t serial,
980 		    uint32_t time, uint32_t key, uint32_t state)
981 {
982 	xkb_keysym_t sym, lsym;
983 	uint32_t unicode;
984 	struct binding *b;
985 	void (*action)(void) = NULL;
986 
987 	if (!term.xkb_keymap || !term.xkb_state)
988 		return;
989 
990 	if (state == WL_KEYBOARD_KEY_STATE_RELEASED) {
991 		if (term.repeat.key == key)
992 			reset_repeat();
993 		return;
994 	}
995 
996 	cursor_set(NULL);
997 
998 	sym = compose(xkb_state_key_get_one_sym(term.xkb_state, key + 8));
999 
1000 	unicode = xkb_keysym_to_utf32(sym);
1001 	if (unicode == 0)
1002 		unicode = TSM_VTE_INVALID;
1003 
1004 	lsym = xkb_keysym_to_lower(sym);
1005 	action_copy_serial = serial;
1006 	b = term.binding;
1007 	while (b) {
1008 		if (term.mods == b->mods && lsym == b->sym) {
1009 			b->action();
1010 			action = b->action;
1011 			break;
1012 		}
1013 		b = b->next;
1014 	}
1015 
1016 	if (!action)
1017 		tsm_vte_handle_keyboard(term.vte, sym, XKB_KEY_NoSymbol,
1018 					term.mods, unicode);
1019 
1020 	if (xkb_keymap_key_repeats(term.xkb_keymap, key + 8)) {
1021 		term.repeat.key = key;
1022 		term.repeat.sym = sym;
1023 		term.repeat.unicode = unicode;
1024 		term.repeat.action = action;
1025 		timerfd_settime(term.repeat.fd, 0, &term.repeat.its, NULL);
1026 	}
1027 }
1028 
kbd_mods(void * data,struct wl_keyboard * k,uint32_t serial,uint32_t depressed,uint32_t latched,uint32_t locked,uint32_t group)1029 static void kbd_mods(void *data, struct wl_keyboard *k, uint32_t serial,
1030 		     uint32_t depressed, uint32_t latched, uint32_t locked,
1031 		     uint32_t group)
1032 {
1033 	if (!term.xkb_keymap || !term.xkb_state)
1034 		return;
1035 
1036 	xkb_state_update_mask(term.xkb_state, depressed, latched, locked,
1037 			      0, 0, group);
1038 
1039 	term.mods = 0;
1040 	if (xkb_state_mod_index_is_active(term.xkb_state, term.xkb_alt,
1041 					  XKB_STATE_MODS_EFFECTIVE) == 1)
1042 		term.mods |= TSM_ALT_MASK;
1043 	if (xkb_state_mod_index_is_active(term.xkb_state, term.xkb_ctrl,
1044 					  XKB_STATE_MODS_EFFECTIVE) == 1)
1045 		term.mods |= TSM_CONTROL_MASK;
1046 	if (xkb_state_mod_index_is_active(term.xkb_state, term.xkb_shift,
1047 					  XKB_STATE_MODS_EFFECTIVE) == 1)
1048 		term.mods |= TSM_SHIFT_MASK;
1049 
1050 	reset_repeat();
1051 }
1052 
kbd_repeat(void * data,struct wl_keyboard * k,int32_t rate,int32_t delay)1053 static void kbd_repeat(void *data, struct wl_keyboard *k,
1054 		       int32_t rate, int32_t delay)
1055 {
1056 	if (rate == 0)
1057 		return;
1058 	else if (rate == 1)
1059 		term.repeat.its.it_interval.tv_sec = 1;
1060 	else
1061 		term.repeat.its.it_interval.tv_nsec = 1000000000 / rate;
1062 
1063 	term.repeat.its.it_value.tv_sec = delay / 1000;
1064 	delay -= term.repeat.its.it_value.tv_sec * 1000;
1065 	term.repeat.its.it_value.tv_nsec = delay * 1000 * 1000;
1066 }
1067 
1068 static struct wl_keyboard_listener kbd_listener = {
1069 	kbd_keymap,
1070 	kbd_enter,
1071 	kbd_leave,
1072 	kbd_key,
1073 	kbd_mods,
1074 	kbd_repeat
1075 };
1076 
pss_send(void * data,struct gtk_primary_selection_source * source,const char * mime_type,int32_t fd)1077 static void pss_send(void *data,
1078 		     struct gtk_primary_selection_source *source,
1079 		     const char *mime_type,
1080 		     int32_t fd)
1081 {
1082 	write(fd, term.ps_copy.data, strlen(term.ps_copy.data));
1083 	close(fd);
1084 }
1085 
pss_cancelled(void * data,struct gtk_primary_selection_source * source)1086 static void pss_cancelled(void *data,
1087 			  struct gtk_primary_selection_source *source)
1088 {
1089 	gtk_primary_selection_source_destroy(term.ps_copy.source);
1090 	term.ps_copy.source = NULL;
1091 	free(term.ps_copy.data);
1092 }
1093 
1094 static struct gtk_primary_selection_source_listener pss_listener = {
1095 	pss_send,
1096 	pss_cancelled
1097 };
1098 
ps_copy(uint32_t serial)1099 static void ps_copy(uint32_t serial)
1100 {
1101 	if (!term.ps_dm)
1102 		return;
1103 
1104 	if (tsm_screen_selection_copy(term.screen, &term.ps_copy.data) < 0)
1105 		return;
1106 
1107 	term.ps_copy.source =
1108 		gtk_primary_selection_device_manager_create_source(term.ps_dm);
1109 	gtk_primary_selection_source_offer(term.ps_copy.source, "UTF8_STRING");
1110 	gtk_primary_selection_source_add_listener(term.ps_copy.source,
1111 						  &pss_listener, NULL);
1112 	gtk_primary_selection_device_set_selection(term.ps_d,
1113 						   term.ps_copy.source,
1114 						   serial);
1115 }
1116 
ps_uncopy(void)1117 static void ps_uncopy(void)
1118 {
1119 	if (!term.ps_dm)
1120 		return;
1121 
1122 	if (!term.ps_copy.source)
1123 		return;
1124 
1125 	pss_cancelled(NULL, term.ps_copy.source);
1126 }
1127 
grid_x(void)1128 static inline int grid_x(void)
1129 {
1130 	return (wl_fixed_to_double(term.ptr_x) - term.margin.left) / term.cwidth;
1131 }
1132 
grid_y(void)1133 static inline int grid_y(void)
1134 {
1135 	return (wl_fixed_to_double(term.ptr_y) - term.margin.top) / term.cheight;
1136 }
1137 
ptr_enter(void * data,struct wl_pointer * wl_pointer,uint32_t serial,struct wl_surface * surface,wl_fixed_t x,wl_fixed_t y)1138 static void ptr_enter(void *data, struct wl_pointer *wl_pointer,
1139 		      uint32_t serial, struct wl_surface *surface,
1140 		      wl_fixed_t x, wl_fixed_t y)
1141 {
1142 	term.ptr_x = x;
1143 	term.ptr_y = y;
1144 
1145 	term.cursor.enter_serial = serial;
1146 	cursor_set("text");
1147 }
1148 
ptr_leave(void * data,struct wl_pointer * wl_pointer,uint32_t serial,struct wl_surface * surface)1149 static void ptr_leave(void *data, struct wl_pointer *wl_pointer,
1150 		      uint32_t serial, struct wl_surface *surface)
1151 {
1152 	cursor_unset();
1153 }
1154 
ptr_motion(void * data,struct wl_pointer * wl_pointer,uint32_t time,wl_fixed_t x,wl_fixed_t y)1155 static void ptr_motion(void *data, struct wl_pointer *wl_pointer,
1156 		       uint32_t time, wl_fixed_t x, wl_fixed_t y)
1157 {
1158 	term.ptr_x = x;
1159 	term.ptr_y = y;
1160 
1161 	switch (term.select) {
1162 	case 1:
1163 		ps_uncopy();
1164 		term.select = 2;
1165 		tsm_screen_selection_start(term.screen, grid_x(), grid_y());
1166 		term.need_redraw = true;
1167 		break;
1168 	case 2:
1169 		tsm_screen_selection_target(term.screen, grid_x(), grid_y());
1170 		term.need_redraw = true;
1171 	}
1172 
1173 	if (term.cursor.current == NULL)
1174 		cursor_set("text");
1175 }
1176 
ptr_button(void * data,struct wl_pointer * wl_pointer,uint32_t serial,uint32_t time,uint32_t button,uint32_t state)1177 static void ptr_button(void *data, struct wl_pointer *wl_pointer,
1178 		       uint32_t serial, uint32_t time, uint32_t button,
1179 		       uint32_t state)
1180 {
1181 	if (button == 0x110) {
1182 		switch (state) {
1183 		case WL_POINTER_BUTTON_STATE_PRESSED:
1184 			if (term.select == 3) {
1185 				tsm_screen_selection_reset(term.screen);
1186 				term.need_redraw = true;
1187 			}
1188 			term.select = 1;
1189 			break;
1190 		case WL_POINTER_BUTTON_STATE_RELEASED:
1191 			if (term.select == 2) {
1192 				ps_copy(serial);
1193 				term.select = 3;
1194 			} else {
1195 				term.select = 0;
1196 			}
1197 		}
1198 	} else if (button == 0x112 &&
1199 		   state == WL_POINTER_BUTTON_STATE_RELEASED) {
1200 		paste(true);
1201 	}
1202 
1203 	if (term.cursor.current == NULL)
1204 		cursor_set("text");
1205 }
1206 
ptr_axis(void * data,struct wl_pointer * wl_pointer,uint32_t time,uint32_t axis,wl_fixed_t value)1207 static void ptr_axis(void *data, struct wl_pointer *wl_pointer,
1208 		     uint32_t time, uint32_t axis, wl_fixed_t value)
1209 {
1210 	int v = wl_fixed_to_double(value) / 3;
1211 
1212 	if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL)
1213 		return;
1214 
1215 	if (v > 0)
1216 		tsm_screen_sb_down(term.screen, v);
1217 	else
1218 		tsm_screen_sb_up(term.screen, -v);
1219 	term.need_redraw = true;
1220 }
1221 
ptr_frame(void * data,struct wl_pointer * wl_pointer)1222 static void ptr_frame(void *data, struct wl_pointer *wl_pointer)
1223 {
1224 }
1225 
ptr_axis_source(void * data,struct wl_pointer * wl_pointer,uint32_t axis_source)1226 static void ptr_axis_source(void *data, struct wl_pointer *wl_pointer,
1227 			    uint32_t axis_source)
1228 {
1229 }
1230 
ptr_axis_stop(void * data,struct wl_pointer * wl_pointer,uint32_t time,uint32_t axis)1231 static void ptr_axis_stop(void *data, struct wl_pointer *wl_pointer,
1232 			  uint32_t time, uint32_t axis)
1233 {
1234 }
1235 
ptr_axis_discrete(void * data,struct wl_pointer * wl_pointer,uint32_t axis,int32_t discrete)1236 static void ptr_axis_discrete(void *data, struct wl_pointer *wl_pointer,
1237 			      uint32_t axis, int32_t discrete)
1238 {
1239 }
1240 
1241 static struct wl_pointer_listener ptr_listener = {
1242 	ptr_enter,
1243 	ptr_leave,
1244 	ptr_motion,
1245 	ptr_button,
1246 	ptr_axis,
1247 	ptr_frame,
1248 	ptr_axis_source,
1249 	ptr_axis_stop,
1250 	ptr_axis_discrete
1251 };
1252 
seat_capabilities(void * data,struct wl_seat * seat,uint32_t caps)1253 static void seat_capabilities(void *data, struct wl_seat *seat, uint32_t caps)
1254 {
1255 	if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !term.kbd) {
1256 		term.kbd = wl_seat_get_keyboard(seat);
1257 		wl_keyboard_add_listener(term.kbd, &kbd_listener, NULL);
1258 	} else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && term.kbd) {
1259 		wl_keyboard_release(term.kbd);
1260 		term.kbd = NULL;
1261 	}
1262 
1263 	if ((caps & WL_SEAT_CAPABILITY_POINTER) && !term.ptr) {
1264 		term.ptr = wl_seat_get_pointer(term.seat);
1265 		wl_pointer_add_listener(term.ptr, &ptr_listener, NULL);
1266 	} else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && term.ptr) {
1267 		wl_pointer_release(term.ptr);
1268 		term.ptr = NULL;
1269 		cursor_unset();
1270 	}
1271 }
1272 
seat_name(void * data,struct wl_seat * seat,const char * name)1273 static void seat_name(void *data, struct wl_seat *seat, const char *name)
1274 {
1275 }
1276 
1277 static const struct wl_seat_listener seat_listener = {
1278 	seat_capabilities,
1279 	seat_name
1280 };
1281 
do_offer(void * d,struct wl_data_offer * o,const char * mime_type)1282 static void do_offer(void *d, struct wl_data_offer *o, const char *mime_type)
1283 {
1284 	if (strcmp(mime_type, "UTF8_STRING") == 0)
1285 		term.paste.d_acceptable = true;
1286 }
1287 
do_source_actions(void * d,struct wl_data_offer * o,uint32_t sa)1288 static void do_source_actions(void *d, struct wl_data_offer *o, uint32_t sa)
1289 {
1290 }
1291 
do_action(void * d,struct wl_data_offer * o,uint32_t dnd_action)1292 static void do_action(void *d, struct wl_data_offer *o, uint32_t dnd_action)
1293 {
1294 }
1295 
1296 static const struct wl_data_offer_listener do_listener = {
1297 	do_offer,
1298 	do_source_actions,
1299 	do_action
1300 };
1301 
dd_data_offer(void * data,struct wl_data_device * wl_data_device,struct wl_data_offer * offer)1302 static void dd_data_offer(void *data, struct wl_data_device *wl_data_device,
1303 			  struct wl_data_offer *offer)
1304 {
1305 	if (term.paste.d_offer)
1306 		wl_data_offer_destroy(term.paste.d_offer);
1307 	term.paste.d_offer = offer;
1308 	term.paste.d_acceptable = false;
1309 	wl_data_offer_add_listener(offer, &do_listener, NULL);
1310 }
1311 
dd_enter(void * data,struct wl_data_device * wl_data_device,uint32_t serial,struct wl_surface * surface,wl_fixed_t x,wl_fixed_t y,struct wl_data_offer * id)1312 static void dd_enter(void *data, struct wl_data_device *wl_data_device,
1313 		     uint32_t serial, struct wl_surface *surface,
1314 		     wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *id)
1315 {
1316 }
1317 
dd_leave(void * data,struct wl_data_device * wl_data_device)1318 static void dd_leave(void *data, struct wl_data_device *wl_data_device)
1319 {
1320 }
1321 
dd_motion(void * data,struct wl_data_device * wl_data_device,uint32_t time,wl_fixed_t x,wl_fixed_t y)1322 static void dd_motion(void *data, struct wl_data_device *wl_data_device,
1323 		      uint32_t time, wl_fixed_t x, wl_fixed_t y)
1324 {
1325 }
1326 
dd_drop(void * data,struct wl_data_device * wl_data_device)1327 static void dd_drop(void *data, struct wl_data_device *wl_data_device)
1328 {
1329 }
1330 
dd_selection(void * data,struct wl_data_device * wl_data_device,struct wl_data_offer * id)1331 static void dd_selection(void *data, struct wl_data_device *wl_data_device,
1332 			 struct wl_data_offer *id)
1333 {
1334 	if (id == NULL && term.paste.d_offer) {
1335 		wl_data_offer_destroy(term.paste.d_offer);
1336 		term.paste.d_offer = NULL;
1337 		term.paste.d_acceptable = false;
1338 	}
1339 }
1340 
1341 static const struct wl_data_device_listener dd_listener = {
1342 	dd_data_offer,
1343 	dd_enter,
1344 	dd_leave,
1345 	dd_motion,
1346 	dd_drop,
1347 	dd_selection
1348 };
1349 
pso_offer(void * data,struct gtk_primary_selection_offer * offer,const char * mime_type)1350 static void pso_offer(void *data,
1351 		      struct gtk_primary_selection_offer *offer,
1352 		      const char *mime_type)
1353 {
1354 	if (strcmp(mime_type, "UTF8_STRING") == 0)
1355 		term.paste.ps_acceptable = true;
1356 }
1357 
1358 static const struct gtk_primary_selection_offer_listener pso_listener = {
1359 	pso_offer
1360 };
1361 
psd_data_offer(void * data,struct gtk_primary_selection_device * ps_d,struct gtk_primary_selection_offer * offer)1362 static void psd_data_offer(void *data,
1363 			   struct gtk_primary_selection_device *ps_d,
1364 			   struct gtk_primary_selection_offer *offer)
1365 {
1366 	if (term.paste.ps_offer)
1367 		gtk_primary_selection_offer_destroy(term.paste.ps_offer);
1368 	term.paste.ps_offer = offer;
1369 	term.paste.ps_acceptable = false;
1370 	gtk_primary_selection_offer_add_listener(offer, &pso_listener, NULL);
1371 }
1372 
psd_selection(void * data,struct gtk_primary_selection_device * ps_d,struct gtk_primary_selection_offer * id)1373 static void psd_selection(void *data,
1374 			  struct gtk_primary_selection_device *ps_d,
1375 			  struct gtk_primary_selection_offer *id)
1376 {
1377 	if (id == NULL && term.paste.ps_offer) {
1378 		gtk_primary_selection_offer_destroy(term.paste.ps_offer);
1379 		term.paste.ps_offer = NULL;
1380 		term.paste.ps_acceptable = false;
1381 	}
1382 }
1383 
1384 static const struct gtk_primary_selection_device_listener psd_listener = {
1385 	psd_data_offer,
1386 	psd_selection
1387 };
1388 
toplvl_configure(void * data,struct xdg_toplevel * xdg_toplevel,int32_t width,int32_t height,struct wl_array * state)1389 static void toplvl_configure(void *data, struct xdg_toplevel *xdg_toplevel,
1390 			     int32_t width, int32_t height,
1391 			     struct wl_array *state)
1392 {
1393 	term.configured = false;
1394 	term.confwidth = width ? width : term.cfg.col * term.cwidth;
1395 	term.confheight = height ? height : term.cfg.row * term.cheight;
1396 }
1397 
toplvl_close(void * data,struct xdg_toplevel * t)1398 static void toplvl_close(void *data, struct xdg_toplevel *t)
1399 {
1400 	term.die = true;
1401 }
1402 
1403 static const struct xdg_toplevel_listener toplvl_listener = {
1404 	toplvl_configure,
1405 	toplvl_close
1406 };
1407 
configure(void * d,struct xdg_surface * surf,uint32_t serial)1408 static void configure(void *d, struct xdg_surface *surf, uint32_t serial)
1409 {
1410 	xdg_surface_ack_configure(surf, serial);
1411 	int col = term.confwidth / term.cwidth;
1412 	int row = term.confheight / term.cheight;
1413 	struct winsize ws = {
1414 		row, col, 0, 0
1415 	};
1416 
1417 	assert(!term.configured);
1418 	term.configured = true;
1419 
1420 	if (col == 0 || row == 0)
1421 		return;
1422 
1423 	if (term.width == term.confwidth && term.height == term.confheight)
1424 		return;
1425 
1426 	if (term.cfg.margin) {
1427 		term.width = term.confwidth;
1428 		term.height = term.confheight;
1429 		term.margin.left = (term.width - col * term.cwidth) / 2;
1430 		term.margin.top = (term.height - row * term.cheight) / 2;
1431 		term.need_redraw = true;
1432 		term.resize = 2;
1433 	} else {
1434 		term.width = col * term.cwidth;
1435 		term.height = row * term.cheight;
1436 	}
1437 
1438 	if (term.col == col && term.row == row)
1439 		return;
1440 
1441 	term.col = col;
1442 	term.row = row;
1443 	tsm_screen_resize(term.screen, col, row);
1444 	if (term.master_fd >= 0 && ioctl(term.master_fd, TIOCSWINSZ, &ws) < 0)
1445 		fprintf(stderr, "could not resize pty: %m\n");
1446 
1447 	term.need_redraw = true;
1448 	term.resize = 2;
1449 }
1450 
1451 static const struct xdg_surface_listener surf_listener = {
1452 	configure
1453 };
1454 
ping(void * data,struct xdg_wm_base * wm_base,uint32_t serial)1455 static void ping(void *data, struct xdg_wm_base *wm_base, uint32_t serial)
1456 {
1457 	xdg_wm_base_pong(wm_base, serial);
1458 }
1459 
1460 static const struct xdg_wm_base_listener wm_base_listener = {
1461 	ping
1462 };
1463 
shm_format(void * data,struct wl_shm * shm,uint32_t format)1464 static void shm_format(void *data, struct wl_shm *shm, uint32_t format)
1465 {
1466 	if (format == WL_SHM_FORMAT_ARGB8888)
1467 		term.shm_argb = true;
1468 }
1469 
1470 static const struct wl_shm_listener shm_listener = {
1471 	shm_format
1472 };
1473 
registry_get(void * data,struct wl_registry * r,uint32_t id,const char * i,uint32_t version)1474 static void registry_get(void *data, struct wl_registry *r, uint32_t id,
1475 			 const char *i, uint32_t version)
1476 {
1477 	if (strcmp(i, "wl_compositor") == 0) {
1478 		term.cp = wl_registry_bind(r, id, &wl_compositor_interface, 1);
1479 	} else if (strcmp(i, "wl_shm") == 0) {
1480 		term.shm = wl_registry_bind(r, id, &wl_shm_interface, 1);
1481 		wl_shm_add_listener(term.shm, &shm_listener, NULL);
1482 	} else if (strcmp(i, "xdg_wm_base") == 0) {
1483 		term.wm_base = wl_registry_bind(r, id, &xdg_wm_base_interface,
1484 						1);
1485 		xdg_wm_base_add_listener(term.wm_base, &wm_base_listener, NULL);
1486 	} else if (strcmp(i, "wl_seat") == 0) {
1487 		term.seat = wl_registry_bind(r, id, &wl_seat_interface, 5);
1488 		wl_seat_add_listener(term.seat, &seat_listener, NULL);
1489 	} else if (strcmp(i, "wl_data_device_manager") == 0) {
1490 		term.d_dm = wl_registry_bind(r, id,
1491 			&wl_data_device_manager_interface, 2);
1492 	} else if (strcmp(i, "gtk_primary_selection_device_manager") == 0) {
1493 		term.ps_dm = wl_registry_bind(r, id,
1494 			&gtk_primary_selection_device_manager_interface, 1);
1495 	}
1496 }
1497 
registry_loose(void * data,struct wl_registry * r,uint32_t name)1498 static void registry_loose(void *data, struct wl_registry *r, uint32_t name)
1499 {
1500 }
1501 
1502 static const struct wl_registry_listener reg_listener = {
1503 	registry_get,
1504 	registry_loose
1505 };
1506 
setup_pty(char * argv[])1507 static void setup_pty(char *argv[])
1508 {
1509 	pid_t pid = forkpty(&term.master_fd, NULL, NULL, NULL);
1510 
1511 	if (pid < 0) {
1512 		fprintf(stderr, "forkpty failed: %m");
1513 		exit(EXIT_FAILURE);
1514 	} else if (pid == 0) {
1515 		char *prog;
1516 		setenv("TERM", "xterm-256color", 1);
1517 		if (*argv) {
1518 			execvp(*argv, argv);
1519 			prog = *argv;
1520 		} else {
1521 			execlp(term.cfg.shell, term.cfg.shell, (char *) NULL);
1522 			prog = term.cfg.shell;
1523 		}
1524 		fprintf(stderr, "could not execute %s: %m", prog);
1525 		pause();
1526 		exit(EXIT_FAILURE);
1527 	}
1528 	fcntl(term.master_fd, F_SETFL, O_NONBLOCK);
1529 }
1530 
action_reset(void)1531 static void action_reset(void)
1532 {
1533 	tsm_vte_reset(term.vte);
1534 }
1535 
action_hard_reset(void)1536 static void action_hard_reset(void)
1537 {
1538 	tsm_vte_hard_reset(term.vte);
1539 	term.need_redraw = true;
1540 }
1541 
action_scroll_up(void)1542 static void action_scroll_up(void)
1543 {
1544 	tsm_screen_sb_up(term.screen, 1);
1545 	term.need_redraw = true;
1546 }
1547 
action_scroll_down(void)1548 static void action_scroll_down(void)
1549 {
1550 	tsm_screen_sb_down(term.screen, 1);
1551 	term.need_redraw = true;
1552 }
1553 
action_scroll_up_page(void)1554 static void action_scroll_up_page(void)
1555 {
1556 	tsm_screen_sb_page_up(term.screen, 1);
1557 	term.need_redraw = true;
1558 }
1559 
action_scroll_down_page(void)1560 static void action_scroll_down_page(void)
1561 {
1562 	tsm_screen_sb_page_down(term.screen, 1);
1563 	term.need_redraw = true;
1564 }
1565 
action_scroll_to_top(void)1566 static void action_scroll_to_top(void)
1567 {
1568 	tsm_screen_sb_up(term.screen, term.cfg.scrollback);
1569 	term.need_redraw = true;
1570 }
1571 
action_scroll_to_bottom(void)1572 static void action_scroll_to_bottom(void)
1573 {
1574 	tsm_screen_sb_reset(term.screen);
1575 	term.need_redraw = true;
1576 }
1577 
1578 
1579 static struct {
1580 	char *name;
1581 	void (*f)(void);
1582 } actions[] = {
1583 	{ "copy", &action_copy },
1584 	{ "paste", &action_paste },
1585 	{ "reset", &action_reset },
1586 	{ "hard reset", &action_hard_reset },
1587 	{ "scroll up", &action_scroll_up },
1588 	{ "scroll down", &action_scroll_down },
1589 	{ "scroll up page", &action_scroll_up_page },
1590 	{ "scroll down page", &action_scroll_down_page },
1591 	{ "scroll to top", &action_scroll_to_top },
1592 	{ "scroll to bottom", &action_scroll_to_bottom },
1593 };
1594 
1595 #define CONF_FILE "havoc.cfg"
1596 
cfg_num(const char * nptr,int base,long long min,long long max)1597 static long long cfg_num(const char *nptr, int base,
1598 			 long long min, long long max)
1599 {
1600 	long long n;
1601 
1602 	n = strtoll(nptr, NULL, base);
1603 	return n < min ? min : n > max ? max : n;
1604 }
1605 
child_config(char * key,char * val)1606 static void child_config(char *key, char *val)
1607 {
1608 	if (strcmp(key, "program") == 0)
1609 		strncpy(term.cfg.shell, val, sizeof(term.cfg.shell) - 1);
1610 }
1611 
window_config(char * key,char * val)1612 static void window_config(char *key, char *val)
1613 {
1614 	if (strcmp(key, "opacity") == 0)
1615 		term.cfg.opacity = cfg_num(val, 10, 0, 255);
1616 	else if (strcmp(key, "margin") == 0)
1617 		term.cfg.margin = strcmp(val, "yes") == 0;
1618 }
1619 
terminal_config(char * key,char * val)1620 static void terminal_config(char *key, char *val)
1621 {
1622 	if (strcmp(key, "rows") == 0)
1623 		term.cfg.row = cfg_num(val, 10, 1, 1000);
1624 	else if (strcmp(key, "columns") == 0)
1625 		term.cfg.col = cfg_num(val, 10, 1, 1000);
1626 	else if (strcmp(key, "scrollback") == 0)
1627 		term.cfg.scrollback = cfg_num(val, 10, 0, INT_MAX);
1628 }
1629 
font_config(char * key,char * val)1630 static void font_config(char *key, char *val)
1631 {
1632 	if (strcmp(key, "size") == 0)
1633 		term.cfg.font_size = cfg_num(val, 10, 6, 300);
1634 	else if (strcmp(key, "path") == 0)
1635 		strncpy(term.cfg.font_path, val,
1636 			sizeof(term.cfg.font_path) - 1);
1637 }
1638 
bind_config(char * key,char * val)1639 static void bind_config(char *key, char *val)
1640 {
1641 	unsigned int mods = 0;
1642 	xkb_keysym_t k;
1643 	struct binding *b;
1644 	size_t i;
1645 
1646 	if (key[0] == '\0')
1647 		return;
1648 
1649 	while (key[1] == '-') {
1650 		switch (key[0]) {
1651 		case 'S':
1652 			mods |= TSM_SHIFT_MASK;
1653 			break;
1654 		case 'C':
1655 			mods |= TSM_CONTROL_MASK;
1656 			break;
1657 		case 'A':
1658 			mods |= TSM_ALT_MASK;
1659 			break;
1660 		}
1661 		key += 2;
1662 	}
1663 
1664 	k = xkb_keysym_from_name(key, XKB_KEYSYM_NO_FLAGS);
1665 	k = xkb_keysym_to_lower(k);
1666 	if (k == XKB_KEY_NoSymbol)
1667 		return;
1668 
1669 	b = malloc(sizeof *b);
1670 	if (b == NULL)
1671 		return;
1672 
1673 	b->mods = mods;
1674 	b->sym = k;
1675 
1676 	for (i = 0; i < ARRAY_LENGTH(actions); ++i) {
1677 		if (strcmp(val, actions[i].name) == 0)
1678 			b->action = actions[i].f;
1679 	}
1680 	b->next = term.binding;
1681 	term.binding = b;
1682 }
1683 
set_color(enum tsm_vte_color field,uint32_t val)1684 static void set_color(enum tsm_vte_color field, uint32_t val)
1685 {
1686 	term.cfg.colors[field][2] = val;
1687 	term.cfg.colors[field][1] = val >> 8;
1688 	term.cfg.colors[field][0] = val >> 16;
1689 }
1690 
color_config(char * key,char * val)1691 static void color_config(char *key, char *val)
1692 {
1693 	uint32_t color = 0;
1694 
1695 	if (*val == '#')
1696 		color = cfg_num(++val, 16, 0, 0xffffff);
1697 
1698 	if (strcmp(key, "foreground") == 0) {
1699 		set_color(TSM_COLOR_FOREGROUND, color);
1700 	} else if (strcmp(key, "background") == 0) {
1701 		set_color(TSM_COLOR_BACKGROUND, color);
1702 	} else if (strstr(key, "color") == key && *(key + 5) != '\0') {
1703 		char *p;
1704 		long i = strtol(key + 5, &p, 10);
1705 		if (*p == '\0' && i >= 0 && i < 16)
1706 			set_color(i, color);
1707 	}
1708 }
1709 
open_config(void)1710 static FILE *open_config(void)
1711 {
1712 	char *dir;
1713 	char path[512];
1714 	FILE *f;
1715 
1716 	if (term.opt.config) {
1717 		if (*term.opt.config == '\0')
1718 			return NULL;
1719 
1720 		f = fopen(term.opt.config, "r");
1721 		if (f == NULL)
1722 			fprintf(stderr, "could not open '%s': %m, "
1723 				"using default configuration\n",
1724 				term.opt.config);
1725 		return f;
1726 	}
1727 
1728 	dir = getenv("XDG_CONFIG_HOME");
1729 	if (dir && *dir != '\0') {
1730 		snprintf(path, sizeof(path), "%s/%s", dir, CONF_FILE);
1731 		f = fopen(path, "r");
1732 		if (f)
1733 			return f;
1734 	}
1735 
1736 	dir = getenv("HOME");
1737 	if (dir && *dir != '\0') {
1738 		snprintf(path, sizeof(path), "%s/.config/%s", dir, CONF_FILE);
1739 		f = fopen(path, "r");
1740 		if (f)
1741 			return f;
1742 	}
1743 
1744 	f = fopen(CONF_FILE, "r");
1745 	return f;
1746 }
1747 
read_config(void)1748 static void read_config(void)
1749 {
1750 	FILE *f = open_config();
1751 	char *key, *val, *p, line[512];
1752 	void (*section)(char *, char *) = NULL;
1753 
1754 	if (f == NULL)
1755 		return;
1756 
1757 	while (fgets(line, sizeof(line), f)) {
1758 		key = line;
1759 		while (isblank(*key))
1760 			++key;
1761 
1762 		switch (*key) {
1763 		case '\n':
1764 		case '#':
1765 			continue;
1766 		case '[':
1767 			p = strchr(key, ']');
1768 			if (p == NULL)
1769 				continue;
1770 			*p = '\0';
1771 			++key;
1772 
1773 			if (strcmp(key, "child") == 0)
1774 				section = &child_config;
1775 			else if (strcmp(key, "window") == 0)
1776 				section = &window_config;
1777 			else if (strcmp(key, "terminal") == 0)
1778 				section = &terminal_config;
1779 			else if (strcmp(key, "font") == 0)
1780 				section = &font_config;
1781 			else if (strcmp(key, "bind") == 0)
1782 				section = &bind_config;
1783 			else if (strcmp(key, "colors") == 0)
1784 				section = &color_config;
1785 			else
1786 				section = NULL;
1787 
1788 			continue;
1789 		default:
1790 			val = strchr(key, '=');
1791 			if (val == NULL)
1792 				continue;
1793 
1794 			p = val - 1;
1795 			while (isblank(*p) && p > key) {
1796 				*p = '\0';
1797 				--p;
1798 			}
1799 
1800 			val[0] = '\0';
1801 			++val;
1802 			while (isblank(*val))
1803 				++val;
1804 
1805 			p = val + strlen(val) - 1;
1806 			while (isspace(*p) && p > val) {
1807 				*p = '\0';
1808 				--p;
1809 			}
1810 
1811 			if (section)
1812 				section(key, val);
1813 		}
1814 	}
1815 
1816 	fclose(f);
1817 }
1818 
usage(void)1819 static void usage(void)
1820 {
1821 	printf("usage: havoc [option...] [program [args...]]\n\n"
1822 	       "  -c <file>  Specify configuration file."
1823 			     " Use empty string for defaults.\n"
1824 	       "  -l         Keep window open after the child process exits.\n"
1825 	       "  -s <name>  Wayland display server to connect to.\n"
1826 	       "  -i <id>    Wayland app ID to use instead of \"havoc\".\n"
1827 	       "  -v         Show version information.\n"
1828 	       "  -h         Show this help.\n");
1829 }
1830 
1831 #define take(s) (*(argv+1) \
1832 	? *++argv \
1833 	: (fprintf(stderr, "missing " s " after option '%s'\n", *argv), \
1834 	  exit(EXIT_FAILURE), NULL))
1835 
main(int argc,char * argv[])1836 int main(int argc, char *argv[])
1837 {
1838 	int display_fd;
1839 	struct epoll_event ee[16];
1840 	int n, i, ret = 1;
1841 	struct binding *b;
1842 
1843 	while (++argv, *argv && **argv == '-') {
1844 retry:
1845 		switch (*++*argv) {
1846 		case 'c':
1847 			term.opt.config = take("config file path");
1848 			break;
1849 		case 'l':
1850 			term.opt.linger = true;
1851 			break;
1852 		case 's':
1853 			term.opt.display = take("display name or socket");
1854 			break;
1855 		case 'i':
1856 			term.opt.app_id = take("wayland app id");
1857 			break;
1858 		case 'v':
1859 			printf("havoc " VERSION "\n");
1860 			return 0;
1861 		case 'h':
1862 			usage();
1863 			return 0;
1864 		case '-':
1865 			goto retry;
1866 		default:
1867 			fprintf(stderr, "unrecognized command line option "
1868 				"'%s'\n", *argv);
1869 			exit(EXIT_FAILURE);
1870 		}
1871 	}
1872 	read_config();
1873 	setup_pty(argv);
1874 
1875 #define fail(e, s) { fprintf(stderr, s "\n"); goto e; }
1876 
1877 	if (font_init(term.cfg.font_size, term.cfg.font_path,
1878 		      &term.cwidth, &term.cheight) < 0)
1879 		fail(efont, "could not load font");
1880 
1881 	term.xkb_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
1882 	if (term.xkb_ctx == NULL)
1883 		fail(exkb, "failed to create xkb context");
1884 
1885 	term.display = wl_display_connect(term.opt.display);
1886 	if (term.display == NULL)
1887 		fail(econnect, "could not connect to display");
1888 
1889 	term.registry = wl_display_get_registry(term.display);
1890 	wl_registry_add_listener(term.registry, &reg_listener, NULL);
1891 
1892 	wl_display_roundtrip(term.display);
1893 	if (!term.cp || !term.shm)
1894 		fail(eglobals, "missing required globals");
1895 	if (!term.wm_base)
1896 		fail(eglobals, "your compositor does not support xdg_wm_base,"
1897 			       " make sure you have the latest version");
1898 
1899 	wl_display_roundtrip(term.display);
1900 	if (term.shm_argb == false)
1901 		fail(eglobals, "missing required ARGB8888 shm format");
1902 
1903 	cursor_init();
1904 
1905 	if (tsm_screen_new(&term.screen) < 0)
1906 		fail(etsm, "failed to create tsm screen");
1907 	tsm_screen_set_max_sb(term.screen, term.cfg.scrollback);
1908 
1909 	if (tsm_vte_new(&term.vte, term.screen, wcb, NULL) < 0)
1910 		fail(evte, "failed to create tsm vte");
1911 	tsm_vte_set_palette(term.vte, term.cfg.colors);
1912 
1913 	term.surf = wl_compositor_create_surface(term.cp);
1914 	if (term.surf == NULL)
1915 		fail(esurf, "could not create surface");
1916 
1917 	term.xdgsurf = xdg_wm_base_get_xdg_surface(term.wm_base, term.surf);
1918 	if (term.xdgsurf == NULL)
1919 		fail(exdgsurf, "could not create xdg_surface");
1920 	xdg_surface_add_listener(term.xdgsurf, &surf_listener, NULL);
1921 
1922 	term.toplvl = xdg_surface_get_toplevel(term.xdgsurf);
1923 	if (term.toplvl == NULL)
1924 		fail(etoplvl, "could not create xdg_toplevel");
1925 	xdg_toplevel_add_listener(term.toplvl, &toplvl_listener, NULL);
1926 	xdg_toplevel_set_title(term.toplvl, "havoc");
1927 	xdg_toplevel_set_app_id(term.toplvl, term.opt.app_id);
1928 
1929 	wl_surface_commit(term.surf);
1930 	term.can_redraw = true;
1931 
1932 	term.repeat.fd = timerfd_create(CLOCK_MONOTONIC,
1933 					TFD_NONBLOCK | TFD_CLOEXEC);
1934 	if (term.repeat.fd < 0)
1935 		fail(etimer, "could not create key repeat timer: %m");
1936 
1937 	if (term.d_dm && term.seat) {
1938 		term.d_d = wl_data_device_manager_get_data_device(
1939 			term.d_dm, term.seat);
1940 		wl_data_device_add_listener(term.d_d, &dd_listener, NULL);
1941 	}
1942 
1943 	if (term.ps_dm && term.seat) {
1944 		term.ps_d = gtk_primary_selection_device_manager_get_device(
1945 			term.ps_dm, term.seat);
1946 		gtk_primary_selection_device_add_listener(term.ps_d,
1947 							  &psd_listener, NULL);
1948 	}
1949 
1950 	display_fd = wl_display_get_fd(term.display);
1951 	term.fd = epoll_create1(EPOLL_CLOEXEC);
1952 
1953 	ee[0].events = EPOLLIN;
1954 
1955 	ee[0].data.ptr = &dfp;
1956 	epoll_ctl(term.fd, EPOLL_CTL_ADD, display_fd, &ee[0]);
1957 
1958 	ee[0].data.ptr = &tfp;
1959 	epoll_ctl(term.fd, EPOLL_CTL_ADD, term.master_fd, &ee[0]);
1960 
1961 	ee[0].data.ptr = &rfp;
1962 	epoll_ctl(term.fd, EPOLL_CTL_ADD, term.repeat.fd, &ee[0]);
1963 
1964 	while (!term.die) {
1965 		if (term.can_redraw && term.need_redraw && term.configured)
1966 			redraw();
1967 
1968 		wl_display_flush(term.display);
1969 
1970 		n = epoll_wait(term.fd, ee, 16, -1);
1971 		for (i = 0; i < n; i++) {
1972 			void (*f)(int) = ((struct epcb *)ee[i].data.ptr)->f;
1973 			if (ee[i].events & EPOLLERR)
1974 				abort();
1975 			f(ee[i].events);
1976 		}
1977 	}
1978 
1979 	ret = 0;
1980 
1981 	buffer_unmap(&term.buf[0]);
1982 	buffer_unmap(&term.buf[1]);
1983 	if (term.cb)
1984 		wl_callback_destroy(term.cb);
1985 
1986 	close(term.repeat.fd);
1987 etimer:
1988 	if (term.d_d)
1989 		wl_data_device_release(term.d_d);
1990 	if (term.ps_d)
1991 		gtk_primary_selection_device_destroy(term.ps_d);
1992 	if (term.ptr)
1993 		wl_pointer_release(term.ptr);
1994 	if (term.kbd)
1995 		wl_keyboard_release(term.kbd);
1996 
1997 	xdg_toplevel_destroy(term.toplvl);
1998 etoplvl:
1999 	xdg_surface_destroy(term.xdgsurf);
2000 exdgsurf:
2001 	wl_surface_destroy(term.surf);
2002 esurf:
2003 	tsm_vte_unref(term.vte);
2004 evte:
2005 	tsm_screen_unref(term.screen);
2006 etsm:
2007 	cursor_free();
2008 eglobals:
2009 	if (term.ps_dm)
2010 		gtk_primary_selection_device_manager_destroy(term.ps_dm);
2011 	if (term.d_dm)
2012 		wl_data_device_manager_destroy(term.d_dm);
2013 	if (term.seat)
2014 		wl_seat_destroy(term.seat);
2015 	if (term.wm_base)
2016 		xdg_wm_base_destroy(term.wm_base);
2017 	if (term.shm)
2018 		wl_shm_destroy(term.shm);
2019 	if (term.cp)
2020 		wl_compositor_destroy(term.cp);
2021 
2022 	wl_registry_destroy(term.registry);
2023 	wl_display_flush(term.display);
2024 	wl_display_disconnect(term.display);
2025 
2026 econnect:
2027 	xkb_context_unref(term.xkb_ctx);
2028 exkb:
2029 	font_deinit();
2030 efont:
2031 	b = term.binding;
2032 	while (b) {
2033 		struct binding *tmp = b;
2034 		b = b->next;
2035 		free(tmp);
2036 	}
2037 	return ret;
2038 }
2039