blob: 60da93af365a95521acd95d0a088646b6313b43f [file] [log] [blame]
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001/*
2 * Copyright © 2008 Kristian Høgsberg
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23#include <stdint.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <fcntl.h>
28#include <unistd.h>
29#include <math.h>
30#include <time.h>
Kristian Høgsberg269d6e32008-12-07 23:17:31 -050031#include <pty.h>
Kristian Høgsbergf04e8382008-12-08 00:07:49 -050032#include <ctype.h>
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -050033#include <cairo.h>
34#include <glib.h>
35
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -040036#include <X11/keysym.h>
37
Kristian Høgsberg12308a42009-09-28 13:08:50 -040038#include "wayland-util.h"
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -050039#include "wayland-client.h"
40#include "wayland-glib.h"
41
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -050042#include "window.h"
43
Kristian Høgsberg0395f302008-12-22 12:14:50 -050044static int option_fullscreen;
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -050045
Kristian Høgsberg6e83d582008-12-08 00:01:36 -050046#define MOD_SHIFT 0x01
47#define MOD_ALT 0x02
48#define MOD_CTRL 0x04
49
Callum Lowcay30eeae52011-01-07 19:46:55 +000050#define ATTRMASK_BOLD 0x01
51#define ATTRMASK_UNDERLINE 0x02
52#define ATTRMASK_BLINK 0x04
53#define ATTRMASK_INVERSE 0x08
54
Callum Lowcayb8609ad2011-01-07 19:46:57 +000055/* Buffer sizes */
56#define MAX_RESPONSE 11
57#define MAX_ESCAPE 64
58
Callum Lowcay8e57dd52011-01-07 19:46:59 +000059/* Terminal modes */
60#define MODE_SHOW_CURSOR 0x00000001
61#define MODE_INVERSE 0x00000002
62#define MODE_AUTOWRAP 0x00000004
63#define MODE_AUTOREPEAT 0x00000008
64#define MODE_LF_NEWLINE 0x00000010
65
Callum Lowcay15bdc5d2011-01-07 19:46:54 +000066union utf8_char {
67 unsigned char byte[4];
68 uint32_t ch;
69};
70
71enum utf8_state {
72 utf8state_start,
73 utf8state_accept,
74 utf8state_reject,
75 utf8state_expect3,
76 utf8state_expect2,
77 utf8state_expect1
78};
79
80struct utf8_state_machine {
81 enum utf8_state state;
82 int len;
83 union utf8_char s;
84};
85
86static void
87init_state_machine(struct utf8_state_machine *machine)
88{
89 machine->state = utf8state_start;
90 machine->len = 0;
91 machine->s.ch = 0;
92}
93
94static enum utf8_state
95utf8_next_char(struct utf8_state_machine *machine, char c)
96{
97 switch(machine->state) {
98 case utf8state_start:
99 case utf8state_accept:
100 case utf8state_reject:
101 machine->s.ch = 0;
102 machine->len = 0;
103 if(c == 0xC0 || c == 0xC1) {
104 /* overlong encoding, reject */
105 machine->state = utf8state_reject;
106 } else if((c & 0x80) == 0) {
107 /* single byte, accept */
108 machine->s.byte[machine->len++] = c;
109 machine->state = utf8state_accept;
110 } else if((c & 0xC0) == 0x80) {
111 /* parser out of sync, ignore byte */
112 machine->state = utf8state_start;
113 } else if((c & 0xE0) == 0xC0) {
114 /* start of two byte sequence */
115 machine->s.byte[machine->len++] = c;
116 machine->state = utf8state_expect1;
117 } else if((c & 0xF0) == 0xE0) {
118 /* start of three byte sequence */
119 machine->s.byte[machine->len++] = c;
120 machine->state = utf8state_expect2;
121 } else if((c & 0xF8) == 0xF0) {
122 /* start of four byte sequence */
123 machine->s.byte[machine->len++] = c;
124 machine->state = utf8state_expect3;
125 } else {
126 /* overlong encoding, reject */
127 machine->state = utf8state_reject;
128 }
129 break;
130 case utf8state_expect3:
131 machine->s.byte[machine->len++] = c;
132 if((c & 0xC0) == 0x80) {
133 /* all good, continue */
134 machine->state = utf8state_expect2;
135 } else {
136 /* missing extra byte, reject */
137 machine->state = utf8state_reject;
138 }
139 break;
140 case utf8state_expect2:
141 machine->s.byte[machine->len++] = c;
142 if((c & 0xC0) == 0x80) {
143 /* all good, continue */
144 machine->state = utf8state_expect1;
145 } else {
146 /* missing extra byte, reject */
147 machine->state = utf8state_reject;
148 }
149 break;
150 case utf8state_expect1:
151 machine->s.byte[machine->len++] = c;
152 if((c & 0xC0) == 0x80) {
153 /* all good, accept */
154 machine->state = utf8state_accept;
155 } else {
156 /* missing extra byte, reject */
157 machine->state = utf8state_reject;
158 }
159 break;
160 default:
161 machine->state = utf8state_reject;
162 break;
163 }
164
165 return machine->state;
166}
167
Callum Lowcay30eeae52011-01-07 19:46:55 +0000168struct terminal_color { double r, g, b, a; };
169struct attr {
170 unsigned char fg, bg;
171 char a; /* attributes format:
172 * 76543210
173 * ilub */
174 char r; /* reserved */
175};
176struct color_scheme {
177 struct terminal_color palette[16];
178 struct terminal_color border;
179 struct attr default_attr;
180};
181
182static void
183attr_init(struct attr *data_attr, struct attr attr, int n)
184{
185 int i;
186 for (i = 0; i < n; i++) {
187 data_attr[i] = attr;
188 }
189}
190
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500191struct terminal {
192 struct window *window;
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -0500193 struct display *display;
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000194 union utf8_char *data;
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000195 char *tab_ruler;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000196 struct attr *data_attr;
197 struct attr curr_attr;
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000198 uint32_t mode;
Callum Lowcaybbeac602011-01-07 19:46:58 +0000199 char origin_mode;
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000200 char saved_origin_mode;
201 struct attr saved_attr;
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000202 union utf8_char last_char;
Callum Lowcaybbeac602011-01-07 19:46:58 +0000203 int margin_top, margin_bottom;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000204 int data_pitch, attr_pitch; /* The width in bytes of a line */
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500205 int width, height, start, row, column;
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000206 int saved_row, saved_column;
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500207 int fd, master;
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500208 GIOChannel *channel;
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500209 uint32_t modifiers;
Callum Lowcayb8609ad2011-01-07 19:46:57 +0000210 char escape[MAX_ESCAPE];
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500211 int escape_length;
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500212 int state;
Callum Lowcayb8609ad2011-01-07 19:46:57 +0000213 int qmark_flag;
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000214 struct utf8_state_machine state_machine;
Kristian Høgsberg1584c572008-12-08 12:59:37 -0500215 int margin;
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500216 int fullscreen;
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500217 int focused;
Kristian Høgsberg12308a42009-09-28 13:08:50 -0400218 struct color_scheme *color_scheme;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000219 struct terminal_color color_table[256];
Kristian Høgsberg09531622010-06-14 23:22:15 -0400220 cairo_font_extents_t extents;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000221 cairo_font_face_t *font_normal, *font_bold;
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500222};
223
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000224/* Create default tab stops, every 8 characters */
225static void
226terminal_init_tabs(struct terminal *terminal)
227{
228 int i = 0;
229
230 while (i < terminal->width) {
231 if (i % 8 == 0)
232 terminal->tab_ruler[i] = 1;
233 else
234 terminal->tab_ruler[i] = 0;
235 i++;
236 }
237}
238
Callum Lowcay30eeae52011-01-07 19:46:55 +0000239static void
240terminal_init(struct terminal *terminal)
241{
242 terminal->curr_attr = terminal->color_scheme->default_attr;
Callum Lowcaybbeac602011-01-07 19:46:58 +0000243 terminal->origin_mode = 0;
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000244 terminal->mode = MODE_SHOW_CURSOR |
245 MODE_AUTOREPEAT |
246 MODE_AUTOWRAP;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000247
248 terminal->row = 0;
249 terminal->column = 0;
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000250
251 terminal->saved_attr = terminal->curr_attr;
252 terminal->saved_origin_mode = terminal->origin_mode;
253 terminal->saved_row = terminal->row;
254 terminal->saved_column = terminal->column;
255
256 if (terminal->tab_ruler != NULL) terminal_init_tabs(terminal);
Callum Lowcay30eeae52011-01-07 19:46:55 +0000257}
258
259static void
260init_color_table(struct terminal *terminal)
261{
262 int c, r;
263 struct terminal_color *color_table = terminal->color_table;
264
265 for (c = 0; c < 256; c ++) {
266 if (c < 16) {
267 color_table[c] = terminal->color_scheme->palette[c];
268 } else if (c < 232) {
269 r = c - 16;
270 color_table[c].b = ((double)(r % 6) / 6.0); r /= 6;
271 color_table[c].g = ((double)(r % 6) / 6.0); r /= 6;
272 color_table[c].r = ((double)(r % 6) / 6.0);
273 color_table[c].a = 1.0;
274 } else {
275 r = (c - 232) * 10 + 8;
276 color_table[c].r = ((double) r) / 256.0;
277 color_table[c].g = color_table[c].r;
278 color_table[c].b = color_table[c].r;
279 color_table[c].a = 1.0;
280 }
281 }
282}
283
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000284static union utf8_char *
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500285terminal_get_row(struct terminal *terminal, int row)
286{
287 int index;
288
289 index = (row + terminal->start) % terminal->height;
290
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000291 return &terminal->data[index * terminal->width];
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500292}
293
Callum Lowcay30eeae52011-01-07 19:46:55 +0000294static struct attr*
295terminal_get_attr_row(struct terminal *terminal, int row) {
296 int index;
297
298 index = (row + terminal->start) % terminal->height;
299
300 return &terminal->data_attr[index * terminal->width];
301}
302
303static struct attr
304terminal_get_attr(struct terminal *terminal, int row, int col) {
305 return terminal_get_attr_row(terminal, row)[col];
306}
307
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500308static void
Callum Lowcaybbeac602011-01-07 19:46:58 +0000309terminal_scroll_buffer(struct terminal *terminal, int d)
310{
311 int i;
312
313 d = d % (terminal->height + 1);
314 terminal->start = (terminal->start + d) % terminal->height;
315 if (terminal->start < 0) terminal->start = terminal->height + terminal->start;
316 if(d < 0) {
317 d = 0 - d;
318 for(i = 0; i < d; i++) {
319 memset(terminal_get_row(terminal, i), 0, terminal->data_pitch);
320 attr_init(terminal_get_attr_row(terminal, i),
321 terminal->curr_attr, terminal->width);
322 }
323 } else {
324 for(i = terminal->height - d; i < terminal->height; i++) {
325 memset(terminal_get_row(terminal, i), 0, terminal->data_pitch);
326 attr_init(terminal_get_attr_row(terminal, i),
327 terminal->curr_attr, terminal->width);
328 }
329 }
330}
331
332static void
333terminal_scroll_window(struct terminal *terminal, int d)
334{
335 int i;
336 int window_height;
337 int from_row, to_row;
338 struct attr *dup_attr;
339
340 // scrolling range is inclusive
341 window_height = terminal->margin_bottom - terminal->margin_top + 1;
342 d = d % (window_height + 1);
343 if(d < 0) {
344 d = 0 - d;
345 to_row = terminal->margin_bottom;
346 from_row = terminal->margin_bottom - d;
347
348 for (i = 0; i < (window_height - d); i++) {
349 memcpy(terminal_get_row(terminal, to_row - i),
350 terminal_get_row(terminal, from_row - i),
351 terminal->data_pitch);
352 memcpy(terminal_get_attr_row(terminal, to_row - i),
353 terminal_get_attr_row(terminal, from_row - i),
354 terminal->attr_pitch);
355 }
356 dup_attr = terminal_get_attr_row(terminal, terminal->margin_top);
357 for (i = terminal->margin_top; i < (terminal->margin_top + d); i++) {
358 memset(terminal_get_row(terminal, i), 0, terminal->data_pitch);
359 if (i > terminal->margin_top) {
360 memcpy(terminal_get_attr_row(terminal, i),
361 dup_attr, terminal->attr_pitch);
362 }
363 }
364 } else {
365 to_row = terminal->margin_top;
366 from_row = terminal->margin_top + d;
367
368 for (i = 0; i < (window_height - d); i++) {
369 memcpy(terminal_get_row(terminal, to_row + i),
370 terminal_get_row(terminal, from_row + i),
371 terminal->data_pitch);
372 memcpy(terminal_get_attr_row(terminal, to_row + i),
373 terminal_get_attr_row(terminal, from_row + i),
374 terminal->attr_pitch);
375 }
376 dup_attr = terminal_get_attr_row(terminal, terminal->margin_bottom);
377 for (i = terminal->margin_bottom - d + 1; i <= terminal->margin_bottom; i++) {
378 memset(terminal_get_row(terminal, i), 0, terminal->data_pitch);
379 if (i < terminal->margin_bottom) {
380 memcpy(terminal_get_attr_row(terminal, i),
381 dup_attr, terminal->attr_pitch);
382 }
383 }
384 }
385}
386
387static void
388terminal_scroll(struct terminal *terminal, int d)
389{
390 if(terminal->margin_top == 0 && terminal->margin_bottom == terminal->height - 1)
391 terminal_scroll_buffer(terminal, d);
392 else
393 terminal_scroll_window(terminal, d);
394}
395
396static void
Kristian Høgsberg22106762008-12-08 13:50:07 -0500397terminal_resize(struct terminal *terminal, int width, int height)
398{
399 size_t size;
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000400 union utf8_char *data;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000401 struct attr *data_attr;
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000402 char *tab_ruler;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000403 int data_pitch, attr_pitch;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500404 int i, l, total_rows, start;
Callum Lowcaya0ee21c2011-01-07 19:46:56 +0000405 struct rectangle rectangle;
406 struct winsize ws;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500407
408 if (terminal->width == width && terminal->height == height)
409 return;
410
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000411 data_pitch = width * sizeof(union utf8_char);
412 size = data_pitch * height;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500413 data = malloc(size);
Callum Lowcay30eeae52011-01-07 19:46:55 +0000414 attr_pitch = width * sizeof(struct attr);
415 data_attr = malloc(attr_pitch * height);
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000416 tab_ruler = malloc(width);
Kristian Høgsberg22106762008-12-08 13:50:07 -0500417 memset(data, 0, size);
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000418 memset(tab_ruler, 0, width);
Callum Lowcay30eeae52011-01-07 19:46:55 +0000419 attr_init(data_attr, terminal->curr_attr, width * height);
420 if (terminal->data && terminal->data_attr) {
Kristian Høgsberg22106762008-12-08 13:50:07 -0500421 if (width > terminal->width)
422 l = terminal->width;
423 else
424 l = width;
425
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500426 if (terminal->height > height) {
Kristian Høgsberg22106762008-12-08 13:50:07 -0500427 total_rows = height;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500428 start = terminal->height - height;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500429 } else {
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500430 total_rows = terminal->height;
431 start = 0;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500432 }
433
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000434 for (i = 0; i < total_rows; i++) {
435 memcpy(&data[width * i],
436 terminal_get_row(terminal, i),
437 l * sizeof(union utf8_char));
Callum Lowcay30eeae52011-01-07 19:46:55 +0000438 memcpy(&data_attr[width * i],
439 terminal_get_attr_row(terminal, i),
440 l * sizeof(struct attr));
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000441 }
Kristian Høgsberg22106762008-12-08 13:50:07 -0500442
443 free(terminal->data);
Callum Lowcay30eeae52011-01-07 19:46:55 +0000444 free(terminal->data_attr);
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000445 free(terminal->tab_ruler);
Kristian Høgsberg22106762008-12-08 13:50:07 -0500446 }
447
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000448 terminal->data_pitch = data_pitch;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000449 terminal->attr_pitch = attr_pitch;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500450 terminal->width = width;
451 terminal->height = height;
Callum Lowcaybbeac602011-01-07 19:46:58 +0000452 if(terminal->margin_bottom >= terminal->height)
453 terminal->margin_bottom = terminal->height - 1;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500454 terminal->data = data;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000455 terminal->data_attr = data_attr;
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000456 terminal->tab_ruler = tab_ruler;
457 terminal_init_tabs(terminal);
Kristian Høgsberg22106762008-12-08 13:50:07 -0500458
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500459 if (terminal->row >= terminal->height)
460 terminal->row = terminal->height - 1;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500461 if (terminal->column >= terminal->width)
462 terminal->column = terminal->width - 1;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500463 terminal->start = 0;
Callum Lowcaya0ee21c2011-01-07 19:46:56 +0000464
465 if (!terminal->fullscreen) {
466 rectangle.width = terminal->width *
467 terminal->extents.max_x_advance + 2 * terminal->margin;
468 rectangle.height = terminal->height *
469 terminal->extents.height + 2 * terminal->margin;
470 window_set_child_size(terminal->window, &rectangle);
471 }
472
473 /* Update the window size */
474 ws.ws_row = terminal->height;
475 ws.ws_col = terminal->width;
476 window_get_child_rectangle(terminal->window, &rectangle);
477 ws.ws_xpixel = rectangle.width;
478 ws.ws_ypixel = rectangle.height;
479 ioctl(terminal->master, TIOCSWINSZ, &ws);
Kristian Høgsberg22106762008-12-08 13:50:07 -0500480}
481
Callum Lowcay30eeae52011-01-07 19:46:55 +0000482struct color_scheme DEFAULT_COLORS = {
483 {
484 {0, 0, 0, 1}, /* black */
485 {0.66, 0, 0, 1}, /* red */
486 {0 , 0.66, 0, 1}, /* green */
487 {0.66, 0.33, 0, 1}, /* orange (nicer than muddy yellow) */
488 {0 , 0 , 0.66, 1}, /* blue */
489 {0.66, 0 , 0.66, 1}, /* magenta */
490 {0, 0.66, 0.66, 1}, /* cyan */
491 {0.66, 0.66, 0.66, 1}, /* light grey */
492 {0.22, 0.33, 0.33, 1}, /* dark grey */
493 {1, 0.33, 0.33, 1}, /* high red */
494 {0.33, 1, 0.33, 1}, /* high green */
495 {1, 1, 0.33, 1}, /* high yellow */
496 {0.33, 0.33, 1, 1}, /* high blue */
497 {1, 0.33, 1, 1}, /* high magenta */
498 {0.33, 1, 1, 1}, /* high cyan */
499 {1, 1, 1, 1} /* white */
500 },
501 {0, 0, 0, 1}, /* black border */
502 {7, 0, 0, } /* bg:black (0), fg:light gray (7) */
503};
Kristian Høgsberg12308a42009-09-28 13:08:50 -0400504
Kristian Høgsberg22106762008-12-08 13:50:07 -0500505static void
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500506terminal_draw_contents(struct terminal *terminal)
507{
508 struct rectangle rectangle;
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500509 cairo_t *cr;
510 cairo_font_extents_t extents;
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000511 int top_margin, side_margin;
512 int row, col;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000513 struct attr attr;
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000514 union utf8_char *p_row;
515 struct utf8_chars {
516 union utf8_char c;
517 char null;
518 } toShow;
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000519 int foreground, background, bold, underline, tmp;
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000520 int text_x, text_y;
Kristian Høgsberg2aac3022009-12-21 10:04:53 -0500521 cairo_surface_t *surface;
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500522 double d;
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500523
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000524 toShow.null = 0;
525
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500526 window_get_child_rectangle(terminal->window, &rectangle);
527
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400528 surface = display_create_surface(terminal->display, &rectangle);
Kristian Høgsberg2aac3022009-12-21 10:04:53 -0500529 cr = cairo_create(surface);
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500530 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Kristian Høgsberg12308a42009-09-28 13:08:50 -0400531 cairo_set_source_rgba(cr,
Callum Lowcay30eeae52011-01-07 19:46:55 +0000532 terminal->color_scheme->border.r,
533 terminal->color_scheme->border.g,
534 terminal->color_scheme->border.b,
535 terminal->color_scheme->border.a);
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500536 cairo_paint(cr);
537 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500538
Callum Lowcay30eeae52011-01-07 19:46:55 +0000539 cairo_set_font_face(cr, terminal->font_normal);
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500540 cairo_set_font_size(cr, 14);
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500541
542 cairo_font_extents(cr, &extents);
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500543 side_margin = (rectangle.width - terminal->width * extents.max_x_advance) / 2;
544 top_margin = (rectangle.height - terminal->height * extents.height) / 2;
545
Callum Lowcay30eeae52011-01-07 19:46:55 +0000546 cairo_set_line_width(cr, 1.0);
547
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000548 for (row = 0; row < terminal->height; row++) {
549 p_row = terminal_get_row(terminal, row);
550 for (col = 0; col < terminal->width; col++) {
Callum Lowcay30eeae52011-01-07 19:46:55 +0000551 /* get the attributes for this character cell */
552 attr = terminal_get_attr(terminal, row, col);
553 if ((attr.a & ATTRMASK_INVERSE) ||
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000554 ((terminal->mode & MODE_SHOW_CURSOR) &&
555 terminal->focused && terminal->row == row &&
556 terminal->column == col))
Callum Lowcay30eeae52011-01-07 19:46:55 +0000557 {
558 foreground = attr.bg;
559 background = attr.fg;
560 } else {
561 foreground = attr.fg;
562 background = attr.bg;
563 }
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000564 if (terminal->mode & MODE_INVERSE) {
565 tmp = foreground;
566 foreground = background;
567 background = tmp;
568 }
Callum Lowcay30eeae52011-01-07 19:46:55 +0000569 bold = attr.a & (ATTRMASK_BOLD | ATTRMASK_BLINK);
570 underline = attr.a & ATTRMASK_UNDERLINE;
571
572 /* paint the background */
573 cairo_set_source_rgba(cr,
574 terminal->color_table[background].r,
575 terminal->color_table[background].g,
576 terminal->color_table[background].b,
577 terminal->color_table[background].a);
578 cairo_move_to(cr, side_margin + (col * extents.max_x_advance),
579 top_margin + (row * extents.height));
580 cairo_rel_line_to(cr, extents.max_x_advance, 0);
581 cairo_rel_line_to(cr, 0, extents.height);
582 cairo_rel_line_to(cr, -extents.max_x_advance, 0);
583 cairo_close_path(cr);
584 cairo_fill(cr);
585
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000586 /* paint the foreground */
Callum Lowcay30eeae52011-01-07 19:46:55 +0000587 if (bold)
588 cairo_set_font_face(cr, terminal->font_bold);
589 else
590 cairo_set_font_face(cr, terminal->font_normal);
591 cairo_set_source_rgba(cr,
592 terminal->color_table[foreground].r,
593 terminal->color_table[foreground].g,
594 terminal->color_table[foreground].b,
595 terminal->color_table[foreground].a);
596
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000597 text_x = side_margin + col * extents.max_x_advance;
598 text_y = top_margin + extents.ascent + row * extents.height;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000599 if (underline) {
600 cairo_move_to(cr, text_x, text_y + 2);
601 cairo_line_to(cr, text_x + extents.max_x_advance, text_y + 2);
602 cairo_stroke(cr);
603 }
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000604 cairo_move_to(cr, text_x, text_y);
605
606 toShow.c = p_row[col];
607 cairo_show_text(cr, (char *) toShow.c.byte);
608 }
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500609 }
Kristian Høgsbergb0b82e22009-02-21 15:42:25 -0500610
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000611 if ((terminal->mode & MODE_SHOW_CURSOR) && !terminal->focused) {
Callum Lowcay30eeae52011-01-07 19:46:55 +0000612 d = 0.5;
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500613
Callum Lowcay30eeae52011-01-07 19:46:55 +0000614 cairo_set_line_width(cr, 1);
615 cairo_move_to(cr, side_margin + terminal->column * extents.max_x_advance + d,
616 top_margin + terminal->row * extents.height + d);
617 cairo_rel_line_to(cr, extents.max_x_advance - 2 * d, 0);
618 cairo_rel_line_to(cr, 0, extents.height - 2 * d);
619 cairo_rel_line_to(cr, -extents.max_x_advance + 2 * d, 0);
620 cairo_close_path(cr);
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500621
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500622 cairo_stroke(cr);
Callum Lowcay30eeae52011-01-07 19:46:55 +0000623 }
Kristian Høgsbergb0b82e22009-02-21 15:42:25 -0500624
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500625 cairo_destroy(cr);
626
Kristian Høgsberg0ac16f02009-01-15 11:37:43 -0500627 window_copy_surface(terminal->window,
628 &rectangle,
Kristian Høgsberg2aac3022009-12-21 10:04:53 -0500629 surface);
630
631 cairo_surface_destroy(surface);
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500632}
633
634static void
635terminal_draw(struct terminal *terminal)
636{
Kristian Høgsberg22106762008-12-08 13:50:07 -0500637 struct rectangle rectangle;
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500638 int32_t width, height;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500639
640 window_get_child_rectangle(terminal->window, &rectangle);
641
Kristian Høgsberg09531622010-06-14 23:22:15 -0400642 width = (rectangle.width - 2 * terminal->margin) /
643 (int32_t) terminal->extents.max_x_advance;
644 height = (rectangle.height - 2 * terminal->margin) /
645 (int32_t) terminal->extents.height;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500646 terminal_resize(terminal, width, height);
647
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500648 window_draw(terminal->window);
649 terminal_draw_contents(terminal);
Kristian Høgsberg9d69f8e2010-09-03 14:46:38 -0400650 window_flush(terminal->window);
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500651}
652
Kristian Høgsberg80d746f2010-06-14 23:52:50 -0400653static void
654redraw_handler(struct window *window, void *data)
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500655{
656 struct terminal *terminal = data;
657
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500658 terminal_draw(terminal);
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500659}
660
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500661#define STATE_NORMAL 0
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500662#define STATE_ESCAPE 1
Callum Lowcayb8609ad2011-01-07 19:46:57 +0000663#define STATE_ESCAPE_SPECIAL 2
664#define STATE_ESCAPE_CSI 3
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500665
666static void
667terminal_data(struct terminal *terminal, const char *data, size_t length);
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500668
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500669static void
Callum Lowcayb8609ad2011-01-07 19:46:57 +0000670handle_char(struct terminal *terminal, union utf8_char utf8);
671
672static void
Callum Lowcay30eeae52011-01-07 19:46:55 +0000673handle_sgr(struct terminal *terminal, int code);
674
675static void
Callum Lowcaybbeac602011-01-07 19:46:58 +0000676handle_term_parameter(struct terminal *terminal, int code, int sr)
677{
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000678 int i;
679
Callum Lowcaybbeac602011-01-07 19:46:58 +0000680 if (terminal->qmark_flag) {
681 switch(code) {
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000682 case 3: /* DECCOLM */
683 if (sr)
684 terminal_resize(terminal, 132, 24);
685 else
686 terminal_resize(terminal, 80, 24);
687
688 /* set columns, but also home cursor and clear screen */
689 terminal->row = 0; terminal->column = 0;
690 for (i = 0; i < terminal->height; i++) {
691 memset(terminal_get_row(terminal, i),
692 0, terminal->data_pitch);
693 attr_init(terminal_get_attr_row(terminal, i),
694 terminal->curr_attr, terminal->width);
695 }
696 break;
697 case 5: /* DECSCNM */
698 if (sr) terminal->mode |= MODE_INVERSE;
699 else terminal->mode &= ~MODE_INVERSE;
700 break;
Callum Lowcaybbeac602011-01-07 19:46:58 +0000701 case 6: /* DECOM */
702 terminal->origin_mode = sr;
703 if (terminal->origin_mode)
704 terminal->row = terminal->margin_top;
705 else
706 terminal->row = 0;
707 terminal->column = 0;
708 break;
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000709 case 7: /* DECAWM */
710 if (sr) terminal->mode |= MODE_AUTOWRAP;
711 else terminal->mode &= ~MODE_AUTOWRAP;
712 break;
713 case 8: /* DECARM */
714 if (sr) terminal->mode |= MODE_AUTOREPEAT;
715 else terminal->mode &= ~MODE_AUTOREPEAT;
716 break;
717 case 25:
718 if (sr) terminal->mode |= MODE_SHOW_CURSOR;
719 else terminal->mode &= ~MODE_SHOW_CURSOR;
720 break;
Callum Lowcaybbeac602011-01-07 19:46:58 +0000721 default:
722 fprintf(stderr, "Unknown parameter: ?%d\n", code);
723 break;
724 }
725 } else {
726 switch(code) {
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000727 case 20: /* LNM */
728 if (sr) terminal->mode |= MODE_LF_NEWLINE;
729 else terminal->mode &= ~MODE_LF_NEWLINE;
730 break;
Callum Lowcaybbeac602011-01-07 19:46:58 +0000731 default:
732 fprintf(stderr, "Unknown parameter: %d\n", code);
733 break;
734 }
735 }
736}
737
738static void
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500739handle_escape(struct terminal *terminal)
740{
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000741 union utf8_char *row;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000742 struct attr *attr_row;
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000743 char *p;
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000744 int i, count, x, y, top, bottom;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500745 int args[10], set[10] = { 0, };
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000746 char response[MAX_RESPONSE] = {0, };
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500747
748 terminal->escape[terminal->escape_length++] = '\0';
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500749 i = 0;
750 p = &terminal->escape[2];
751 while ((isdigit(*p) || *p == ';') && i < 10) {
752 if (*p == ';') {
Callum Lowcay30eeae52011-01-07 19:46:55 +0000753 if (!set[i]) {
754 args[i] = 0;
755 set[i] = 1;
756 }
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500757 p++;
758 i++;
759 } else {
760 args[i] = strtol(p, &p, 10);
761 set[i] = 1;
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500762 }
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500763 }
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500764
765 switch (*p) {
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000766 case 'A': /* CUU */
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500767 count = set[0] ? args[0] : 1;
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000768 if (count == 0) count = 1;
769 if (terminal->row - count >= terminal->margin_top)
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500770 terminal->row -= count;
771 else
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000772 terminal->row = terminal->margin_top;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500773 break;
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000774 case 'B': /* CUD */
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500775 count = set[0] ? args[0] : 1;
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000776 if (count == 0) count = 1;
777 if (terminal->row + count <= terminal->margin_bottom)
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500778 terminal->row += count;
779 else
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000780 terminal->row = terminal->margin_bottom;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500781 break;
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000782 case 'C': /* CUF */
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500783 count = set[0] ? args[0] : 1;
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000784 if (count == 0) count = 1;
785 if ((terminal->column + count) < terminal->width)
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500786 terminal->column += count;
787 else
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000788 terminal->column = terminal->width - 1;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500789 break;
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000790 case 'D': /* CUB */
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500791 count = set[0] ? args[0] : 1;
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000792 if (count == 0) count = 1;
793 if ((terminal->column - count) >= 0)
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500794 terminal->column -= count;
795 else
796 terminal->column = 0;
797 break;
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000798 case 'E': /* CNL */
799 count = set[0] ? args[0] : 1;
800 if (terminal->row + count <= terminal->margin_bottom)
801 terminal->row += count;
802 else
803 terminal->row = terminal->margin_bottom;
804 terminal->column = 0;
805 break;
806 case 'F': /* CPL */
807 count = set[0] ? args[0] : 1;
808 if (terminal->row - count >= terminal->margin_top)
809 terminal->row -= count;
810 else
811 terminal->row = terminal->margin_top;
812 terminal->column = 0;
813 break;
814 case 'G': /* CHA */
815 y = set[0] ? args[0] : 1;
816 y = y <= 0 ? 1 : y > terminal->width ? terminal->width : y;
817
818 terminal->column = y - 1;
819 break;
820 case 'f': /* HVP */
821 case 'H': /* CUP */
822 x = (set[1] ? args[1] : 1) - 1;
823 x = x < 0 ? 0 :
824 (x >= terminal->width ? terminal->width - 1 : x);
825
826 y = (set[0] ? args[0] : 1) - 1;
827 if (terminal->origin_mode) {
828 y += terminal->margin_top;
829 y = y < terminal->margin_top ? terminal->margin_top :
830 (y > terminal->margin_bottom ? terminal->margin_bottom : y);
831 } else {
832 y = y < 0 ? 0 :
833 (y >= terminal->height ? terminal->height - 1 : y);
834 }
835
836 terminal->row = y;
837 terminal->column = x;
838 break;
839 case 'I': /* CHT */
840 count = set[0] ? args[0] : 1;
841 if (count == 0) count = 1;
842 while (count > 0 && terminal->column < terminal->width) {
843 if (terminal->tab_ruler[terminal->column]) count--;
844 terminal->column++;
845 }
846 terminal->column--;
847 break;
848 case 'J': /* ED */
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500849 row = terminal_get_row(terminal, terminal->row);
Callum Lowcay30eeae52011-01-07 19:46:55 +0000850 attr_row = terminal_get_attr_row(terminal, terminal->row);
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000851 if (!set[0] || args[0] == 0 || args[0] > 2) {
852 memset(&row[terminal->column],
853 0, (terminal->width - terminal->column) * sizeof(union utf8_char));
854 attr_init(&attr_row[terminal->column],
855 terminal->curr_attr, terminal->width - terminal->column);
856 for (i = terminal->row + 1; i < terminal->height; i++) {
857 memset(terminal_get_row(terminal, i),
858 0, terminal->data_pitch);
859 attr_init(terminal_get_attr_row(terminal, i),
860 terminal->curr_attr, terminal->width);
861 }
862 } else if (args[0] == 1) {
863 memset(row, 0, (terminal->column+1) * sizeof(union utf8_char));
864 attr_init(attr_row, terminal->curr_attr, terminal->column+1);
865 for (i = 0; i < terminal->row; i++) {
866 memset(terminal_get_row(terminal, i),
867 0, terminal->data_pitch);
868 attr_init(terminal_get_attr_row(terminal, i),
869 terminal->curr_attr, terminal->width);
870 }
871 } else if (args[0] == 2) {
872 for (i = 0; i < terminal->height; i++) {
873 memset(terminal_get_row(terminal, i),
874 0, terminal->data_pitch);
875 attr_init(terminal_get_attr_row(terminal, i),
876 terminal->curr_attr, terminal->width);
877 }
Callum Lowcay30eeae52011-01-07 19:46:55 +0000878 }
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500879 break;
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000880 case 'K': /* EL */
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500881 row = terminal_get_row(terminal, terminal->row);
Callum Lowcay30eeae52011-01-07 19:46:55 +0000882 attr_row = terminal_get_attr_row(terminal, terminal->row);
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000883 if (!set[0] || args[0] == 0 || args[0] > 2) {
884 memset(&row[terminal->column], 0,
885 (terminal->width - terminal->column) * sizeof(union utf8_char));
886 attr_init(&attr_row[terminal->column], terminal->curr_attr,
887 terminal->width - terminal->column);
888 } else if (args[0] == 1) {
889 memset(row, 0, (terminal->column+1) * sizeof(union utf8_char));
890 attr_init(attr_row, terminal->curr_attr, terminal->column+1);
891 } else if (args[0] == 2) {
892 memset(row, 0, terminal->data_pitch);
893 attr_init(attr_row, terminal->curr_attr, terminal->width);
894 }
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500895 break;
Callum Lowcaybbeac602011-01-07 19:46:58 +0000896 case 'S': /* SU */
897 terminal_scroll(terminal, set[0] ? args[0] : 1);
898 break;
899 case 'T': /* SD */
900 terminal_scroll(terminal, 0 - (set[0] ? args[0] : 1));
901 break;
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000902 case 'Z': /* CBT */
903 count = set[0] ? args[0] : 1;
904 if (count == 0) count = 1;
905 while (count > 0 && terminal->column >= 0) {
906 if (terminal->tab_ruler[terminal->column]) count--;
907 terminal->column--;
908 }
909 terminal->column++;
910 break;
911 case '`': /* HPA */
912 y = set[0] ? args[0] : 1;
913 y = y <= 0 ? 1 : y > terminal->width ? terminal->width : y;
914
915 terminal->column = y - 1;
916 break;
917 case 'b': /* REP */
918 count = set[0] ? args[0] : 1;
919 if (count == 0) count = 1;
920 if (terminal->last_char.byte[0])
921 for (i = 0; i < count; i++)
922 handle_char(terminal, terminal->last_char);
923 terminal->last_char.byte[0] = 0;
924 break;
925 case 'c': /* Primary DA */
926 write(terminal->master, "\e[?1;2c", 7);
927 sleep(1);
928 break;
929 case 'd': /* VPA */
930 x = set[0] ? args[0] : 1;
931 x = x <= 0 ? 1 : x > terminal->height ? terminal->height : x;
932
933 terminal->row = x - 1;
934 break;
935 case 'g': /* TBC */
936 if (!set[0] || args[0] == 0) {
937 terminal->tab_ruler[terminal->column] = 0;
938 } else if (args[0] == 3) {
939 memset(terminal->tab_ruler, 0, terminal->width);
940 }
941 break;
Callum Lowcaybbeac602011-01-07 19:46:58 +0000942 case 'h': /* SM */
943 for(i = 0; i < 10 && set[i]; i++) {
944 handle_term_parameter(terminal, args[i], 1);
945 }
946 break;
947 case 'l': /* RM */
948 for(i = 0; i < 10 && set[i]; i++) {
949 handle_term_parameter(terminal, args[i], 0);
950 }
951 break;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000952 case 'm': /* SGR */
953 if (set[0] && set[1] && set[2] && args[1] == 5) {
954 if (args[0] == 38) {
955 handle_sgr(terminal, args[2] + 256);
956 break;
957 } else if (args[0] == 48) {
958 handle_sgr(terminal, args[2] + 512);
959 break;
960 }
961 }
962 for(i = 0; i < 10; i++) {
963 if(set[i]) {
964 handle_sgr(terminal, args[i]);
965 } else if(i == 0) {
966 handle_sgr(terminal, 0);
967 break;
968 } else {
969 break;
970 }
971 }
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500972 break;
Callum Lowcay8e57dd52011-01-07 19:46:59 +0000973 case 'n': /* DSR */
974 i = set[0] ? args[0] : 0;
975 if (i == 0 || i == 5) {
976 write(terminal->master, "\e[0n", 4);
977 } else if (i == 6) {
978 snprintf(response, MAX_RESPONSE, "\e[%d;%dR",
979 terminal->origin_mode ?
980 terminal->row+terminal->margin_top : terminal->row+1,
981 terminal->column+1);
982 write(terminal->master, response, strlen(response));
983 }
984 sleep(1); /* is this required? why? */
985 break;
Callum Lowcaybbeac602011-01-07 19:46:58 +0000986 case 'r':
987 if(!set[0]) {
988 terminal->margin_top = 0;
989 terminal->margin_bottom = terminal->height-1;
990 terminal->row = 0;
991 terminal->column = 0;
992 } else {
993 top = (set[0] ? args[0] : 1) - 1;
994 top = top < 0 ? 0 :
995 (top >= terminal->height ? terminal->height - 1 : top);
996 bottom = (set[1] ? args[1] : 1) - 1;
997 bottom = bottom < 0 ? 0 :
998 (bottom >= terminal->height ? terminal->height - 1 : bottom);
999 if(bottom > top) {
1000 terminal->margin_top = top;
1001 terminal->margin_bottom = bottom;
1002 } else {
1003 terminal->margin_top = 0;
1004 terminal->margin_bottom = terminal->height-1;
1005 }
1006 if(terminal->origin_mode)
1007 terminal->row = terminal->margin_top;
1008 else
1009 terminal->row = 0;
1010 terminal->column = 0;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -05001011 }
1012 break;
Callum Lowcay8e57dd52011-01-07 19:46:59 +00001013 case 's':
1014 terminal->saved_row = terminal->row;
1015 terminal->saved_column = terminal->column;
1016 break;
1017 case 'u':
1018 terminal->row = terminal->saved_row;
1019 terminal->column = terminal->saved_column;
1020 break;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -05001021 default:
Callum Lowcayb8609ad2011-01-07 19:46:57 +00001022 fprintf(stderr, "Unknown CSI escape: %c\n", *p);
Kristian Høgsbergdbd54642008-12-08 22:22:25 -05001023 break;
1024 }
Kristian Høgsberg17809b12008-12-08 12:20:40 -05001025}
1026
1027static void
Callum Lowcayb8609ad2011-01-07 19:46:57 +00001028handle_non_csi_escape(struct terminal *terminal, char code)
1029{
Callum Lowcaybbeac602011-01-07 19:46:58 +00001030 switch(code) {
1031 case 'M': /* RI */
1032 terminal->row -= 1;
1033 if(terminal->row < terminal->margin_top) {
1034 terminal->row = terminal->margin_top;
1035 terminal_scroll(terminal, -1);
1036 }
1037 break;
1038 case 'E': /* NEL */
1039 terminal->column = 0;
1040 // fallthrough
1041 case 'D': /* IND */
1042 terminal->row += 1;
1043 if(terminal->row > terminal->margin_bottom) {
1044 terminal->row = terminal->margin_bottom;
1045 terminal_scroll(terminal, +1);
1046 }
1047 break;
Callum Lowcay8e57dd52011-01-07 19:46:59 +00001048 case 'c': /* RIS */
1049 terminal_init(terminal);
1050 break;
1051 case 'H': /* HTS */
1052 terminal->tab_ruler[terminal->column] = 1;
1053 break;
1054 case '7': /* DECSC */
1055 terminal->saved_row = terminal->row;
1056 terminal->saved_column = terminal->column;
1057 terminal->saved_attr = terminal->curr_attr;
1058 terminal->saved_origin_mode = terminal->origin_mode;
1059 break;
1060 case '8': /* DECRC */
1061 terminal->row = terminal->saved_row;
1062 terminal->column = terminal->saved_column;
1063 terminal->curr_attr = terminal->saved_attr;
1064 terminal->origin_mode = terminal->saved_origin_mode;
1065 break;
Callum Lowcaybbeac602011-01-07 19:46:58 +00001066 default:
1067 fprintf(stderr, "Unknown escape code: %c\n", code);
1068 break;
1069 }
Callum Lowcayb8609ad2011-01-07 19:46:57 +00001070}
1071
1072static void
1073handle_special_escape(struct terminal *terminal, char special, char code)
1074{
Callum Lowcay8e57dd52011-01-07 19:46:59 +00001075 int i, numChars;
1076
1077 if (special == '#') {
1078 switch(code) {
1079 case '8':
1080 /* fill with 'E', no cheap way to do this */
1081 memset(terminal->data, 0, terminal->data_pitch * terminal->height);
1082 numChars = terminal->width * terminal->height;
1083 for(i = 0; i < numChars; i++) {
1084 terminal->data[i].byte[0] = 'E';
1085 }
1086 break;
1087 default:
1088 fprintf(stderr, "Unknown HASH escape #%c\n", code);
1089 break;
1090 }
1091 } else {
1092 fprintf(stderr, "Unknown special escape %c%c\n", special, code);
1093 }
Callum Lowcayb8609ad2011-01-07 19:46:57 +00001094}
1095
1096static void
Callum Lowcay30eeae52011-01-07 19:46:55 +00001097handle_sgr(struct terminal *terminal, int code)
1098{
1099 switch(code) {
1100 case 0:
1101 terminal->curr_attr = terminal->color_scheme->default_attr;
1102 break;
1103 case 1:
1104 terminal->curr_attr.a |= ATTRMASK_BOLD;
1105 if (terminal->curr_attr.fg < 8)
1106 terminal->curr_attr.fg += 8;
1107 break;
1108 case 4:
1109 terminal->curr_attr.a |= ATTRMASK_UNDERLINE;
1110 break;
1111 case 5:
1112 terminal->curr_attr.a |= ATTRMASK_BLINK;
1113 break;
1114 case 2:
1115 case 21:
1116 case 22:
1117 terminal->curr_attr.a &= ~ATTRMASK_BOLD;
1118 if (terminal->curr_attr.fg < 16 && terminal->curr_attr.fg >= 8)
1119 terminal->curr_attr.fg -= 8;
1120 break;
1121 case 24:
1122 terminal->curr_attr.a &= ~ATTRMASK_UNDERLINE;
1123 break;
1124 case 25:
1125 terminal->curr_attr.a &= ~ATTRMASK_BLINK;
1126 break;
1127 case 7:
1128 case 26:
1129 terminal->curr_attr.a |= ATTRMASK_INVERSE;
1130 break;
1131 case 27:
1132 terminal->curr_attr.a &= ~ATTRMASK_INVERSE;
1133 break;
1134 case 39:
1135 terminal->curr_attr.fg = terminal->color_scheme->default_attr.fg;
1136 break;
1137 case 49:
1138 terminal->curr_attr.bg = terminal->color_scheme->default_attr.bg;
1139 break;
1140 default:
1141 if(code >= 30 && code <= 37) {
1142 terminal->curr_attr.fg = code - 30;
1143 if (terminal->curr_attr.a & ATTRMASK_BOLD)
1144 terminal->curr_attr.fg += 8;
1145 } else if(code >= 40 && code <= 47) {
1146 terminal->curr_attr.bg = code - 40;
1147 } else if(code >= 256 && code < 512) {
1148 terminal->curr_attr.fg = code - 256;
1149 } else if(code >= 512 && code < 768) {
1150 terminal->curr_attr.bg = code - 512;
1151 } else {
1152 fprintf(stderr, "Unknown SGR code: %d\n", code);
1153 }
1154 break;
1155 }
1156}
1157
Callum Lowcayb8609ad2011-01-07 19:46:57 +00001158/* Returns 1 if c was special, otherwise 0 */
1159static int
1160handle_special_char(struct terminal *terminal, char c)
1161{
1162 union utf8_char *row;
1163 struct attr *attr_row;
1164
1165 row = terminal_get_row(terminal, terminal->row);
1166 attr_row = terminal_get_attr_row(terminal, terminal->row);
1167
1168 switch(c) {
1169 case '\r':
1170 terminal->column = 0;
1171 break;
1172 case '\n':
Callum Lowcay8e57dd52011-01-07 19:46:59 +00001173 if (terminal->mode & MODE_LF_NEWLINE) {
1174 terminal->column = 0;
1175 }
Callum Lowcayb8609ad2011-01-07 19:46:57 +00001176 /* fallthrough */
1177 case '\v':
1178 case '\f':
Callum Lowcaybbeac602011-01-07 19:46:58 +00001179 terminal->row++;
1180 if(terminal->row > terminal->margin_bottom) {
1181 terminal->row = terminal->margin_bottom;
1182 terminal_scroll(terminal, +1);
Callum Lowcayb8609ad2011-01-07 19:46:57 +00001183 }
1184
1185 break;
1186 case '\t':
Callum Lowcay8e57dd52011-01-07 19:46:59 +00001187 while (terminal->column < terminal->width) {
1188 if (terminal->tab_ruler[terminal->column]) break;
1189 row[terminal->column].byte[0] = ' ';
1190 row[terminal->column].byte[1] = '\0';
1191 attr_row[terminal->column] = terminal->curr_attr;
1192 terminal->column++;
1193 }
1194 if (terminal->column >= terminal->width) {
1195 terminal->column = terminal->width - 1;
1196 }
1197
Callum Lowcayb8609ad2011-01-07 19:46:57 +00001198 break;
1199 case '\b':
Callum Lowcay8e57dd52011-01-07 19:46:59 +00001200 if (terminal->column >= terminal->width) {
1201 terminal->column = terminal->width - 2;
1202 } else if (terminal->column > 0) {
Callum Lowcayb8609ad2011-01-07 19:46:57 +00001203 terminal->column--;
Callum Lowcay8e57dd52011-01-07 19:46:59 +00001204 } else if (terminal->mode & MODE_AUTOWRAP) {
1205 terminal->column = terminal->width - 1;
1206 terminal->row -= 1;
1207 if (terminal->row < terminal->margin_top) {
1208 terminal->row = terminal->margin_top;
1209 terminal_scroll(terminal, -1);
1210 }
1211 }
1212
Callum Lowcayb8609ad2011-01-07 19:46:57 +00001213 break;
1214 case '\a':
1215 /* Bell */
1216 break;
1217 default:
1218 return 0;
1219 }
1220
1221 return 1;
1222}
1223
1224static void
1225handle_char(struct terminal *terminal, union utf8_char utf8)
1226{
1227 union utf8_char *row;
1228 struct attr *attr_row;
1229
1230 if (handle_special_char(terminal, utf8.byte[0])) return;
1231
1232 /* There are a whole lot of non-characters, control codes,
1233 * and formatting codes that should probably be ignored,
1234 * for example: */
1235 if (strncmp((char*) utf8.byte, "\xEF\xBB\xBF", 3) == 0) {
1236 /* BOM, ignore */
1237 return;
1238 }
1239
1240 /* Some of these non-characters should be translated, e.g.: */
1241 if (utf8.byte[0] < 32) {
1242 utf8.byte[0] = utf8.byte[0] + 64;
1243 }
1244
1245 /* handle right margin effects */
1246 if (terminal->column >= terminal->width) {
Callum Lowcay8e57dd52011-01-07 19:46:59 +00001247 if (terminal->mode & MODE_AUTOWRAP) {
1248 terminal->column = 0;
1249 terminal->row += 1;
1250 if (terminal->row > terminal->margin_bottom) {
1251 terminal->row = terminal->margin_bottom;
1252 terminal_scroll(terminal, +1);
1253 }
1254 } else {
1255 terminal->column--;
1256 }
1257 }
Callum Lowcayb8609ad2011-01-07 19:46:57 +00001258
1259 row = terminal_get_row(terminal, terminal->row);
1260 attr_row = terminal_get_attr_row(terminal, terminal->row);
1261
1262 row[terminal->column] = utf8;
1263 attr_row[terminal->column++] = terminal->curr_attr;
1264
1265 if (utf8.ch != terminal->last_char.ch)
1266 terminal->last_char = utf8;
1267}
1268
Callum Lowcay30eeae52011-01-07 19:46:55 +00001269static void
Kristian Høgsberg269d6e32008-12-07 23:17:31 -05001270terminal_data(struct terminal *terminal, const char *data, size_t length)
1271{
1272 int i;
Callum Lowcay15bdc5d2011-01-07 19:46:54 +00001273 union utf8_char utf8;
1274 enum utf8_state parser_state;
Kristian Høgsberg269d6e32008-12-07 23:17:31 -05001275
1276 for (i = 0; i < length; i++) {
Callum Lowcay15bdc5d2011-01-07 19:46:54 +00001277 parser_state =
1278 utf8_next_char(&terminal->state_machine, data[i]);
1279 switch(parser_state) {
1280 case utf8state_accept:
1281 utf8.ch = terminal->state_machine.s.ch;
1282 break;
1283 case utf8state_reject:
1284 /* the unicode replacement character */
1285 utf8.byte[0] = 0xEF;
1286 utf8.byte[1] = 0xBF;
1287 utf8.byte[2] = 0xBD;
1288 utf8.byte[3] = 0x00;
1289 break;
1290 default:
1291 continue;
1292 }
1293
Callum Lowcayb8609ad2011-01-07 19:46:57 +00001294 /* assume escape codes never use non-ASCII characters */
Kristian Høgsberg17809b12008-12-08 12:20:40 -05001295 if (terminal->state == STATE_ESCAPE) {
Callum Lowcay15bdc5d2011-01-07 19:46:54 +00001296 terminal->escape[terminal->escape_length++] = utf8.byte[0];
Callum Lowcayb8609ad2011-01-07 19:46:57 +00001297 if (utf8.byte[0] == '[') {
1298 terminal->state = STATE_ESCAPE_CSI;
1299 continue;
1300 } else if (utf8.byte[0] == '#' || utf8.byte[0] == '(' ||
1301 utf8.byte[0] == ')')
1302 {
1303 terminal->state = STATE_ESCAPE_SPECIAL;
1304 continue;
1305 } else {
Kristian Høgsbergf04e8382008-12-08 00:07:49 -05001306 terminal->state = STATE_NORMAL;
Callum Lowcayb8609ad2011-01-07 19:46:57 +00001307 handle_non_csi_escape(terminal, utf8.byte[0]);
1308 continue;
Kristian Høgsberg17809b12008-12-08 12:20:40 -05001309 }
Callum Lowcayb8609ad2011-01-07 19:46:57 +00001310 } else if (terminal->state == STATE_ESCAPE_SPECIAL) {
1311 terminal->escape[terminal->escape_length++] = utf8.byte[0];
1312 terminal->state = STATE_NORMAL;
1313 if (isdigit(utf8.byte[0]) || isalpha(utf8.byte[0])) {
1314 handle_special_escape(terminal, terminal->escape[1],
1315 utf8.byte[0]);
1316 continue;
1317 }
1318 } else if (terminal->state == STATE_ESCAPE_CSI) {
1319 if (handle_special_char(terminal, utf8.byte[0]) != 0) {
1320 /* do nothing */
1321 } else if (utf8.byte[0] == '?') {
1322 terminal->qmark_flag = 1;
1323 } else {
1324 /* Don't overflow the buffer */
1325 if (terminal->escape_length < MAX_ESCAPE)
1326 terminal->escape[terminal->escape_length++] = utf8.byte[0];
1327 if (terminal->escape_length >= MAX_ESCAPE)
1328 terminal->state = STATE_NORMAL;
1329 }
1330
1331 if (isalpha(utf8.byte[0]) || utf8.byte[0] == '@' ||
1332 utf8.byte[0] == '`')
1333 {
Kristian Høgsberg17809b12008-12-08 12:20:40 -05001334 terminal->state = STATE_NORMAL;
1335 handle_escape(terminal);
Callum Lowcayb8609ad2011-01-07 19:46:57 +00001336 continue;
1337 } else {
1338 continue;
1339 }
Kristian Høgsbergf04e8382008-12-08 00:07:49 -05001340 }
1341
Callum Lowcayb8609ad2011-01-07 19:46:57 +00001342 /* this is valid, because ASCII characters are never used to
1343 * introduce a multibyte sequence in UTF-8 */
1344 if (utf8.byte[0] == '\e') {
Kristian Høgsberg17809b12008-12-08 12:20:40 -05001345 terminal->state = STATE_ESCAPE;
1346 terminal->escape[0] = '\e';
1347 terminal->escape_length = 1;
Callum Lowcayb8609ad2011-01-07 19:46:57 +00001348 terminal->qmark_flag = 0;
1349 } else {
1350 handle_char(terminal, utf8);
1351 } /* if */
1352 } /* for */
Kristian Høgsberg721f09f2008-12-08 11:13:26 -05001353
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04001354 window_schedule_redraw(terminal->window);
Kristian Høgsberg6e83d582008-12-08 00:01:36 -05001355}
1356
1357static void
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04001358key_handler(struct window *window, uint32_t key, uint32_t sym,
Kristian Høgsberg55444912009-02-21 14:31:09 -05001359 uint32_t state, uint32_t modifiers, void *data)
Kristian Høgsberg6e83d582008-12-08 00:01:36 -05001360{
1361 struct terminal *terminal = data;
Callum Lowcay8e57dd52011-01-07 19:46:59 +00001362 char ch[MAX_RESPONSE];
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04001363 int len = 0;
Kristian Høgsberg6e83d582008-12-08 00:01:36 -05001364
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04001365 switch (sym) {
1366 case XK_F11:
Kristian Høgsberg0395f302008-12-22 12:14:50 -05001367 if (!state)
1368 break;
1369 terminal->fullscreen ^= 1;
1370 window_set_fullscreen(window, terminal->fullscreen);
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04001371 window_schedule_redraw(terminal->window);
Kristian Høgsberg0395f302008-12-22 12:14:50 -05001372 break;
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04001373
1374 case XK_Delete:
1375 sym = 0x04;
1376 case XK_BackSpace:
1377 case XK_Tab:
1378 case XK_Linefeed:
1379 case XK_Clear:
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04001380 case XK_Pause:
1381 case XK_Scroll_Lock:
1382 case XK_Sys_Req:
1383 case XK_Escape:
1384 ch[len++] = sym & 0x7f;
1385 break;
1386
Callum Lowcay8e57dd52011-01-07 19:46:59 +00001387 case XK_Return:
1388 if (terminal->mode & MODE_LF_NEWLINE) {
1389 ch[len++] = 0x0D;
1390 ch[len++] = 0x0A;
1391 } else {
1392 ch[len++] = 0x0D;
1393 }
1394 break;
1395
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04001396 case XK_Shift_L:
1397 case XK_Shift_R:
1398 case XK_Control_L:
1399 case XK_Control_R:
1400 case XK_Alt_L:
1401 case XK_Alt_R:
1402 break;
1403
Kristian Høgsberg6e83d582008-12-08 00:01:36 -05001404 default:
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04001405 if (modifiers & WINDOW_MODIFIER_CONTROL)
1406 sym = sym & 0x1f;
1407 else if (modifiers & WINDOW_MODIFIER_ALT)
1408 ch[len++] = 0x1b;
1409 if (sym < 256)
1410 ch[len++] = sym;
Kristian Høgsberg6e83d582008-12-08 00:01:36 -05001411 break;
1412 }
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -04001413
1414 if (state && len > 0)
1415 write(terminal->master, ch, len);
Kristian Høgsberg6e83d582008-12-08 00:01:36 -05001416}
1417
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -05001418static void
1419keyboard_focus_handler(struct window *window,
Kristian Høgsberg43788b12010-07-28 23:50:12 -04001420 struct input *device, void *data)
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -05001421{
1422 struct terminal *terminal = data;
1423
1424 terminal->focused = (device != NULL);
Kristian Høgsberg80d746f2010-06-14 23:52:50 -04001425 window_schedule_redraw(terminal->window);
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -05001426}
1427
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001428static struct terminal *
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001429terminal_create(struct display *display, int fullscreen)
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001430{
1431 struct terminal *terminal;
Kristian Høgsberg09531622010-06-14 23:22:15 -04001432 cairo_surface_t *surface;
1433 cairo_t *cr;
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001434
1435 terminal = malloc(sizeof *terminal);
1436 if (terminal == NULL)
1437 return terminal;
1438
Kristian Høgsberg269d6e32008-12-07 23:17:31 -05001439 memset(terminal, 0, sizeof *terminal);
Kristian Høgsberg0395f302008-12-22 12:14:50 -05001440 terminal->fullscreen = fullscreen;
Callum Lowcay30eeae52011-01-07 19:46:55 +00001441 terminal->color_scheme = &DEFAULT_COLORS;
1442 terminal_init(terminal);
Callum Lowcaybbeac602011-01-07 19:46:58 +00001443 terminal->margin_top = 0;
1444 terminal->margin_bottom = 10000; /* much too large, will be trimmed down
1445 * by terminal_resize */
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001446 terminal->window = window_create(display, "Wayland Terminal",
Kristian Høgsberg82da52b2010-12-17 09:53:12 -05001447 500, 400);
Callum Lowcay15bdc5d2011-01-07 19:46:54 +00001448
1449 init_state_machine(&terminal->state_machine);
Callum Lowcay30eeae52011-01-07 19:46:55 +00001450 init_color_table(terminal);
Callum Lowcay15bdc5d2011-01-07 19:46:54 +00001451
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001452 terminal->display = display;
Kristian Høgsberg1584c572008-12-08 12:59:37 -05001453 terminal->margin = 5;
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -05001454
Kristian Høgsberg0395f302008-12-22 12:14:50 -05001455 window_set_fullscreen(terminal->window, terminal->fullscreen);
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04001456 window_set_user_data(terminal->window, terminal);
1457 window_set_redraw_handler(terminal->window, redraw_handler);
Kristian Høgsberg94448c02008-12-30 11:03:33 -05001458
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04001459 window_set_key_handler(terminal->window, key_handler);
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -05001460 window_set_keyboard_focus_handler(terminal->window,
Kristian Høgsbergc8c37342010-06-25 11:19:22 -04001461 keyboard_focus_handler);
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001462
Kristian Høgsberg09531622010-06-14 23:22:15 -04001463 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0);
1464 cr = cairo_create(surface);
Callum Lowcay30eeae52011-01-07 19:46:55 +00001465 terminal->font_bold = cairo_toy_font_face_create ("mono",
1466 CAIRO_FONT_SLANT_NORMAL,
1467 CAIRO_FONT_WEIGHT_BOLD);
1468 cairo_font_face_reference(terminal->font_bold);
1469 terminal->font_normal = cairo_toy_font_face_create ("mono",
1470 CAIRO_FONT_SLANT_NORMAL,
1471 CAIRO_FONT_WEIGHT_NORMAL);
1472 cairo_font_face_reference(terminal->font_normal);
1473 cairo_set_font_face(cr, terminal->font_normal);
Kristian Høgsberg09531622010-06-14 23:22:15 -04001474 cairo_set_font_size(cr, 14);
1475 cairo_font_extents(cr, &terminal->extents);
1476 cairo_destroy(cr);
1477 cairo_surface_destroy(surface);
1478
Callum Lowcaya0ee21c2011-01-07 19:46:56 +00001479 terminal_resize(terminal, 80, 24);
Kristian Høgsberg22106762008-12-08 13:50:07 -05001480 terminal_draw(terminal);
1481
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001482 return terminal;
1483}
1484
Kristian Høgsberg269d6e32008-12-07 23:17:31 -05001485static gboolean
1486io_handler(GIOChannel *source,
1487 GIOCondition condition,
1488 gpointer data)
1489{
1490 struct terminal *terminal = data;
1491 gchar buffer[256];
1492 gsize bytes_read;
1493 GError *error = NULL;
1494
1495 g_io_channel_read_chars(source, buffer, sizeof buffer,
1496 &bytes_read, &error);
Kristian Høgsberg269d6e32008-12-07 23:17:31 -05001497
1498 terminal_data(terminal, buffer, bytes_read);
1499
Kristian Høgsberg269d6e32008-12-07 23:17:31 -05001500 return TRUE;
1501}
1502
1503static int
1504terminal_run(struct terminal *terminal, const char *path)
1505{
Kristian Høgsbergf0c7b202008-12-12 13:39:03 -05001506 int master;
Kristian Høgsberg269d6e32008-12-07 23:17:31 -05001507 pid_t pid;
1508
1509 pid = forkpty(&master, NULL, NULL, NULL);
1510 if (pid == 0) {
Kristian Høgsbergc8c5d582008-12-18 14:50:08 -05001511 setenv("TERM", "vt100", 1);
Kristian Høgsberg269d6e32008-12-07 23:17:31 -05001512 if (execl(path, path, NULL)) {
1513 printf("exec failed: %m\n");
1514 exit(EXIT_FAILURE);
1515 }
Kristian Høgsbergf0c7b202008-12-12 13:39:03 -05001516 } else if (pid < 0) {
1517 fprintf(stderr, "failed to fork and create pty (%m).\n");
1518 return -1;
Kristian Høgsberg269d6e32008-12-07 23:17:31 -05001519 }
1520
Kristian Høgsberg6e83d582008-12-08 00:01:36 -05001521 terminal->master = master;
Kristian Høgsberg269d6e32008-12-07 23:17:31 -05001522 terminal->channel = g_io_channel_unix_new(master);
1523 fcntl(master, F_SETFL, O_NONBLOCK);
1524 g_io_add_watch(terminal->channel, G_IO_IN,
1525 io_handler, terminal);
1526
1527 return 0;
1528}
1529
Kristian Høgsberg0395f302008-12-22 12:14:50 -05001530static const GOptionEntry option_entries[] = {
1531 { "fullscreen", 'f', 0, G_OPTION_ARG_NONE,
1532 &option_fullscreen, "Run in fullscreen mode" },
1533 { NULL }
1534};
1535
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001536int main(int argc, char *argv[])
1537{
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001538 struct display *d;
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001539 struct terminal *terminal;
Kristian Høgsberg0395f302008-12-22 12:14:50 -05001540
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001541 d = display_create(&argc, &argv, option_entries);
Yuval Fledele9f5e362010-11-22 21:34:19 +02001542 if (d == NULL) {
1543 fprintf(stderr, "failed to create display: %m\n");
1544 return -1;
1545 }
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001546
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -05001547 terminal = terminal_create(d, option_fullscreen);
Kristian Høgsbergf0c7b202008-12-12 13:39:03 -05001548 if (terminal_run(terminal, "/bin/bash"))
1549 exit(EXIT_FAILURE);
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001550
Kristian Høgsberg7824d812010-06-08 14:59:44 -04001551 display_run(d);
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -05001552
1553 return 0;
1554}