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 >k_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, ®_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