blob: 3c7be253bedffe4d85759855e91d1ee6d2abf616 [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 Lowcay15bdc5d2011-01-07 19:46:54 +000055union utf8_char {
56 unsigned char byte[4];
57 uint32_t ch;
58};
59
60enum utf8_state {
61 utf8state_start,
62 utf8state_accept,
63 utf8state_reject,
64 utf8state_expect3,
65 utf8state_expect2,
66 utf8state_expect1
67};
68
69struct utf8_state_machine {
70 enum utf8_state state;
71 int len;
72 union utf8_char s;
73};
74
75static void
76init_state_machine(struct utf8_state_machine *machine)
77{
78 machine->state = utf8state_start;
79 machine->len = 0;
80 machine->s.ch = 0;
81}
82
83static enum utf8_state
84utf8_next_char(struct utf8_state_machine *machine, char c)
85{
86 switch(machine->state) {
87 case utf8state_start:
88 case utf8state_accept:
89 case utf8state_reject:
90 machine->s.ch = 0;
91 machine->len = 0;
92 if(c == 0xC0 || c == 0xC1) {
93 /* overlong encoding, reject */
94 machine->state = utf8state_reject;
95 } else if((c & 0x80) == 0) {
96 /* single byte, accept */
97 machine->s.byte[machine->len++] = c;
98 machine->state = utf8state_accept;
99 } else if((c & 0xC0) == 0x80) {
100 /* parser out of sync, ignore byte */
101 machine->state = utf8state_start;
102 } else if((c & 0xE0) == 0xC0) {
103 /* start of two byte sequence */
104 machine->s.byte[machine->len++] = c;
105 machine->state = utf8state_expect1;
106 } else if((c & 0xF0) == 0xE0) {
107 /* start of three byte sequence */
108 machine->s.byte[machine->len++] = c;
109 machine->state = utf8state_expect2;
110 } else if((c & 0xF8) == 0xF0) {
111 /* start of four byte sequence */
112 machine->s.byte[machine->len++] = c;
113 machine->state = utf8state_expect3;
114 } else {
115 /* overlong encoding, reject */
116 machine->state = utf8state_reject;
117 }
118 break;
119 case utf8state_expect3:
120 machine->s.byte[machine->len++] = c;
121 if((c & 0xC0) == 0x80) {
122 /* all good, continue */
123 machine->state = utf8state_expect2;
124 } else {
125 /* missing extra byte, reject */
126 machine->state = utf8state_reject;
127 }
128 break;
129 case utf8state_expect2:
130 machine->s.byte[machine->len++] = c;
131 if((c & 0xC0) == 0x80) {
132 /* all good, continue */
133 machine->state = utf8state_expect1;
134 } else {
135 /* missing extra byte, reject */
136 machine->state = utf8state_reject;
137 }
138 break;
139 case utf8state_expect1:
140 machine->s.byte[machine->len++] = c;
141 if((c & 0xC0) == 0x80) {
142 /* all good, accept */
143 machine->state = utf8state_accept;
144 } else {
145 /* missing extra byte, reject */
146 machine->state = utf8state_reject;
147 }
148 break;
149 default:
150 machine->state = utf8state_reject;
151 break;
152 }
153
154 return machine->state;
155}
156
Callum Lowcay30eeae52011-01-07 19:46:55 +0000157struct terminal_color { double r, g, b, a; };
158struct attr {
159 unsigned char fg, bg;
160 char a; /* attributes format:
161 * 76543210
162 * ilub */
163 char r; /* reserved */
164};
165struct color_scheme {
166 struct terminal_color palette[16];
167 struct terminal_color border;
168 struct attr default_attr;
169};
170
171static void
172attr_init(struct attr *data_attr, struct attr attr, int n)
173{
174 int i;
175 for (i = 0; i < n; i++) {
176 data_attr[i] = attr;
177 }
178}
179
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500180struct terminal {
181 struct window *window;
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -0500182 struct display *display;
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000183 union utf8_char *data;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000184 struct attr *data_attr;
185 struct attr curr_attr;
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000186 union utf8_char last_char;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000187 int data_pitch, attr_pitch; /* The width in bytes of a line */
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500188 int width, height, start, row, column;
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500189 int fd, master;
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500190 GIOChannel *channel;
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500191 uint32_t modifiers;
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500192 char escape[64];
193 int escape_length;
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500194 int state;
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000195 struct utf8_state_machine state_machine;
Kristian Høgsberg1584c572008-12-08 12:59:37 -0500196 int margin;
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500197 int fullscreen;
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500198 int focused;
Kristian Høgsberg12308a42009-09-28 13:08:50 -0400199 struct color_scheme *color_scheme;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000200 struct terminal_color color_table[256];
Kristian Høgsberg09531622010-06-14 23:22:15 -0400201 cairo_font_extents_t extents;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000202 cairo_font_face_t *font_normal, *font_bold;
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500203};
204
Callum Lowcay30eeae52011-01-07 19:46:55 +0000205static void
206terminal_init(struct terminal *terminal)
207{
208 terminal->curr_attr = terminal->color_scheme->default_attr;
209
210 terminal->row = 0;
211 terminal->column = 0;
212}
213
214static void
215init_color_table(struct terminal *terminal)
216{
217 int c, r;
218 struct terminal_color *color_table = terminal->color_table;
219
220 for (c = 0; c < 256; c ++) {
221 if (c < 16) {
222 color_table[c] = terminal->color_scheme->palette[c];
223 } else if (c < 232) {
224 r = c - 16;
225 color_table[c].b = ((double)(r % 6) / 6.0); r /= 6;
226 color_table[c].g = ((double)(r % 6) / 6.0); r /= 6;
227 color_table[c].r = ((double)(r % 6) / 6.0);
228 color_table[c].a = 1.0;
229 } else {
230 r = (c - 232) * 10 + 8;
231 color_table[c].r = ((double) r) / 256.0;
232 color_table[c].g = color_table[c].r;
233 color_table[c].b = color_table[c].r;
234 color_table[c].a = 1.0;
235 }
236 }
237}
238
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000239static union utf8_char *
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500240terminal_get_row(struct terminal *terminal, int row)
241{
242 int index;
243
244 index = (row + terminal->start) % terminal->height;
245
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000246 return &terminal->data[index * terminal->width];
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500247}
248
Callum Lowcay30eeae52011-01-07 19:46:55 +0000249static struct attr*
250terminal_get_attr_row(struct terminal *terminal, int row) {
251 int index;
252
253 index = (row + terminal->start) % terminal->height;
254
255 return &terminal->data_attr[index * terminal->width];
256}
257
258static struct attr
259terminal_get_attr(struct terminal *terminal, int row, int col) {
260 return terminal_get_attr_row(terminal, row)[col];
261}
262
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500263static void
Kristian Høgsberg22106762008-12-08 13:50:07 -0500264terminal_resize(struct terminal *terminal, int width, int height)
265{
266 size_t size;
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000267 union utf8_char *data;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000268 struct attr *data_attr;
269 int data_pitch, attr_pitch;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500270 int i, l, total_rows, start;
Callum Lowcaya0ee21c2011-01-07 19:46:56 +0000271 struct rectangle rectangle;
272 struct winsize ws;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500273
274 if (terminal->width == width && terminal->height == height)
275 return;
276
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000277 data_pitch = width * sizeof(union utf8_char);
278 size = data_pitch * height;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500279 data = malloc(size);
Callum Lowcay30eeae52011-01-07 19:46:55 +0000280 attr_pitch = width * sizeof(struct attr);
281 data_attr = malloc(attr_pitch * height);
Kristian Høgsberg22106762008-12-08 13:50:07 -0500282 memset(data, 0, size);
Callum Lowcay30eeae52011-01-07 19:46:55 +0000283 attr_init(data_attr, terminal->curr_attr, width * height);
284 if (terminal->data && terminal->data_attr) {
Kristian Høgsberg22106762008-12-08 13:50:07 -0500285 if (width > terminal->width)
286 l = terminal->width;
287 else
288 l = width;
289
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500290 if (terminal->height > height) {
Kristian Høgsberg22106762008-12-08 13:50:07 -0500291 total_rows = height;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500292 start = terminal->height - height;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500293 } else {
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500294 total_rows = terminal->height;
295 start = 0;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500296 }
297
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000298 for (i = 0; i < total_rows; i++) {
299 memcpy(&data[width * i],
300 terminal_get_row(terminal, i),
301 l * sizeof(union utf8_char));
Callum Lowcay30eeae52011-01-07 19:46:55 +0000302 memcpy(&data_attr[width * i],
303 terminal_get_attr_row(terminal, i),
304 l * sizeof(struct attr));
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000305 }
Kristian Høgsberg22106762008-12-08 13:50:07 -0500306
307 free(terminal->data);
Callum Lowcay30eeae52011-01-07 19:46:55 +0000308 free(terminal->data_attr);
Kristian Høgsberg22106762008-12-08 13:50:07 -0500309 }
310
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000311 terminal->data_pitch = data_pitch;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000312 terminal->attr_pitch = attr_pitch;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500313 terminal->width = width;
314 terminal->height = height;
315 terminal->data = data;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000316 terminal->data_attr = data_attr;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500317
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500318 if (terminal->row >= terminal->height)
319 terminal->row = terminal->height - 1;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500320 if (terminal->column >= terminal->width)
321 terminal->column = terminal->width - 1;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500322 terminal->start = 0;
Callum Lowcaya0ee21c2011-01-07 19:46:56 +0000323
324 if (!terminal->fullscreen) {
325 rectangle.width = terminal->width *
326 terminal->extents.max_x_advance + 2 * terminal->margin;
327 rectangle.height = terminal->height *
328 terminal->extents.height + 2 * terminal->margin;
329 window_set_child_size(terminal->window, &rectangle);
330 }
331
332 /* Update the window size */
333 ws.ws_row = terminal->height;
334 ws.ws_col = terminal->width;
335 window_get_child_rectangle(terminal->window, &rectangle);
336 ws.ws_xpixel = rectangle.width;
337 ws.ws_ypixel = rectangle.height;
338 ioctl(terminal->master, TIOCSWINSZ, &ws);
Kristian Høgsberg22106762008-12-08 13:50:07 -0500339}
340
Callum Lowcay30eeae52011-01-07 19:46:55 +0000341struct color_scheme DEFAULT_COLORS = {
342 {
343 {0, 0, 0, 1}, /* black */
344 {0.66, 0, 0, 1}, /* red */
345 {0 , 0.66, 0, 1}, /* green */
346 {0.66, 0.33, 0, 1}, /* orange (nicer than muddy yellow) */
347 {0 , 0 , 0.66, 1}, /* blue */
348 {0.66, 0 , 0.66, 1}, /* magenta */
349 {0, 0.66, 0.66, 1}, /* cyan */
350 {0.66, 0.66, 0.66, 1}, /* light grey */
351 {0.22, 0.33, 0.33, 1}, /* dark grey */
352 {1, 0.33, 0.33, 1}, /* high red */
353 {0.33, 1, 0.33, 1}, /* high green */
354 {1, 1, 0.33, 1}, /* high yellow */
355 {0.33, 0.33, 1, 1}, /* high blue */
356 {1, 0.33, 1, 1}, /* high magenta */
357 {0.33, 1, 1, 1}, /* high cyan */
358 {1, 1, 1, 1} /* white */
359 },
360 {0, 0, 0, 1}, /* black border */
361 {7, 0, 0, } /* bg:black (0), fg:light gray (7) */
362};
Kristian Høgsberg12308a42009-09-28 13:08:50 -0400363
Kristian Høgsberg22106762008-12-08 13:50:07 -0500364static void
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500365terminal_draw_contents(struct terminal *terminal)
366{
367 struct rectangle rectangle;
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500368 cairo_t *cr;
369 cairo_font_extents_t extents;
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000370 int top_margin, side_margin;
371 int row, col;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000372 struct attr attr;
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000373 union utf8_char *p_row;
374 struct utf8_chars {
375 union utf8_char c;
376 char null;
377 } toShow;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000378 int foreground, background, bold, underline;
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000379 int text_x, text_y;
Kristian Høgsberg2aac3022009-12-21 10:04:53 -0500380 cairo_surface_t *surface;
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500381 double d;
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500382
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000383 toShow.null = 0;
384
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500385 window_get_child_rectangle(terminal->window, &rectangle);
386
Kristian Høgsbergdcb71b62010-06-15 17:16:35 -0400387 surface = display_create_surface(terminal->display, &rectangle);
Kristian Høgsberg2aac3022009-12-21 10:04:53 -0500388 cr = cairo_create(surface);
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500389 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Kristian Høgsberg12308a42009-09-28 13:08:50 -0400390 cairo_set_source_rgba(cr,
Callum Lowcay30eeae52011-01-07 19:46:55 +0000391 terminal->color_scheme->border.r,
392 terminal->color_scheme->border.g,
393 terminal->color_scheme->border.b,
394 terminal->color_scheme->border.a);
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500395 cairo_paint(cr);
396 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500397
Callum Lowcay30eeae52011-01-07 19:46:55 +0000398 cairo_set_font_face(cr, terminal->font_normal);
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500399 cairo_set_font_size(cr, 14);
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500400
401 cairo_font_extents(cr, &extents);
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500402 side_margin = (rectangle.width - terminal->width * extents.max_x_advance) / 2;
403 top_margin = (rectangle.height - terminal->height * extents.height) / 2;
404
Callum Lowcay30eeae52011-01-07 19:46:55 +0000405 cairo_set_line_width(cr, 1.0);
406
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000407 for (row = 0; row < terminal->height; row++) {
408 p_row = terminal_get_row(terminal, row);
409 for (col = 0; col < terminal->width; col++) {
Callum Lowcay30eeae52011-01-07 19:46:55 +0000410 /* get the attributes for this character cell */
411 attr = terminal_get_attr(terminal, row, col);
412 if ((attr.a & ATTRMASK_INVERSE) ||
413 (terminal->focused &&
414 terminal->row == row && terminal->column == col))
415 {
416 foreground = attr.bg;
417 background = attr.fg;
418 } else {
419 foreground = attr.fg;
420 background = attr.bg;
421 }
422 bold = attr.a & (ATTRMASK_BOLD | ATTRMASK_BLINK);
423 underline = attr.a & ATTRMASK_UNDERLINE;
424
425 /* paint the background */
426 cairo_set_source_rgba(cr,
427 terminal->color_table[background].r,
428 terminal->color_table[background].g,
429 terminal->color_table[background].b,
430 terminal->color_table[background].a);
431 cairo_move_to(cr, side_margin + (col * extents.max_x_advance),
432 top_margin + (row * extents.height));
433 cairo_rel_line_to(cr, extents.max_x_advance, 0);
434 cairo_rel_line_to(cr, 0, extents.height);
435 cairo_rel_line_to(cr, -extents.max_x_advance, 0);
436 cairo_close_path(cr);
437 cairo_fill(cr);
438
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000439 /* paint the foreground */
Callum Lowcay30eeae52011-01-07 19:46:55 +0000440 if (bold)
441 cairo_set_font_face(cr, terminal->font_bold);
442 else
443 cairo_set_font_face(cr, terminal->font_normal);
444 cairo_set_source_rgba(cr,
445 terminal->color_table[foreground].r,
446 terminal->color_table[foreground].g,
447 terminal->color_table[foreground].b,
448 terminal->color_table[foreground].a);
449
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000450 text_x = side_margin + col * extents.max_x_advance;
451 text_y = top_margin + extents.ascent + row * extents.height;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000452 if (underline) {
453 cairo_move_to(cr, text_x, text_y + 2);
454 cairo_line_to(cr, text_x + extents.max_x_advance, text_y + 2);
455 cairo_stroke(cr);
456 }
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000457 cairo_move_to(cr, text_x, text_y);
458
459 toShow.c = p_row[col];
460 cairo_show_text(cr, (char *) toShow.c.byte);
461 }
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500462 }
Kristian Høgsbergb0b82e22009-02-21 15:42:25 -0500463
Callum Lowcay30eeae52011-01-07 19:46:55 +0000464 if (!terminal->focused) {
465 d = 0.5;
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500466
Callum Lowcay30eeae52011-01-07 19:46:55 +0000467 cairo_set_line_width(cr, 1);
468 cairo_move_to(cr, side_margin + terminal->column * extents.max_x_advance + d,
469 top_margin + terminal->row * extents.height + d);
470 cairo_rel_line_to(cr, extents.max_x_advance - 2 * d, 0);
471 cairo_rel_line_to(cr, 0, extents.height - 2 * d);
472 cairo_rel_line_to(cr, -extents.max_x_advance + 2 * d, 0);
473 cairo_close_path(cr);
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500474
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500475 cairo_stroke(cr);
Callum Lowcay30eeae52011-01-07 19:46:55 +0000476 }
Kristian Høgsbergb0b82e22009-02-21 15:42:25 -0500477
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500478 cairo_destroy(cr);
479
Kristian Høgsberg0ac16f02009-01-15 11:37:43 -0500480 window_copy_surface(terminal->window,
481 &rectangle,
Kristian Høgsberg2aac3022009-12-21 10:04:53 -0500482 surface);
483
484 cairo_surface_destroy(surface);
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500485}
486
487static void
488terminal_draw(struct terminal *terminal)
489{
Kristian Høgsberg22106762008-12-08 13:50:07 -0500490 struct rectangle rectangle;
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500491 int32_t width, height;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500492
493 window_get_child_rectangle(terminal->window, &rectangle);
494
Kristian Høgsberg09531622010-06-14 23:22:15 -0400495 width = (rectangle.width - 2 * terminal->margin) /
496 (int32_t) terminal->extents.max_x_advance;
497 height = (rectangle.height - 2 * terminal->margin) /
498 (int32_t) terminal->extents.height;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500499 terminal_resize(terminal, width, height);
500
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500501 window_draw(terminal->window);
502 terminal_draw_contents(terminal);
Kristian Høgsberg9d69f8e2010-09-03 14:46:38 -0400503 window_flush(terminal->window);
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500504}
505
Kristian Høgsberg80d746f2010-06-14 23:52:50 -0400506static void
507redraw_handler(struct window *window, void *data)
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500508{
509 struct terminal *terminal = data;
510
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500511 terminal_draw(terminal);
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500512}
513
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500514#define STATE_NORMAL 0
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500515#define STATE_ESCAPE 1
516
517static void
518terminal_data(struct terminal *terminal, const char *data, size_t length);
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500519
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500520static void
Callum Lowcay30eeae52011-01-07 19:46:55 +0000521handle_sgr(struct terminal *terminal, int code);
522
523static void
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500524handle_escape(struct terminal *terminal)
525{
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000526 union utf8_char *row;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000527 struct attr *attr_row;
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000528 char *p;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500529 int i, count;
530 int args[10], set[10] = { 0, };
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500531
532 terminal->escape[terminal->escape_length++] = '\0';
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500533 i = 0;
534 p = &terminal->escape[2];
535 while ((isdigit(*p) || *p == ';') && i < 10) {
536 if (*p == ';') {
Callum Lowcay30eeae52011-01-07 19:46:55 +0000537 if (!set[i]) {
538 args[i] = 0;
539 set[i] = 1;
540 }
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500541 p++;
542 i++;
543 } else {
544 args[i] = strtol(p, &p, 10);
545 set[i] = 1;
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500546 }
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500547 }
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500548
549 switch (*p) {
550 case 'A':
551 count = set[0] ? args[0] : 1;
552 if (terminal->row - count >= 0)
553 terminal->row -= count;
554 else
555 terminal->row = 0;
556 break;
557 case 'B':
558 count = set[0] ? args[0] : 1;
559 if (terminal->row + count < terminal->height)
560 terminal->row += count;
561 else
562 terminal->row = terminal->height;
563 break;
564 case 'C':
565 count = set[0] ? args[0] : 1;
566 if (terminal->column + count < terminal->width)
567 terminal->column += count;
568 else
569 terminal->column = terminal->width;
570 break;
571 case 'D':
572 count = set[0] ? args[0] : 1;
573 if (terminal->column - count >= 0)
574 terminal->column -= count;
575 else
576 terminal->column = 0;
577 break;
578 case 'J':
579 row = terminal_get_row(terminal, terminal->row);
Callum Lowcay30eeae52011-01-07 19:46:55 +0000580 attr_row = terminal_get_attr_row(terminal, terminal->row);
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000581 memset(&row[terminal->column], 0, (terminal->width - terminal->column) * sizeof(union utf8_char));
Callum Lowcay30eeae52011-01-07 19:46:55 +0000582 attr_init(&attr_row[terminal->column], terminal->curr_attr, (terminal->width - terminal->column));
583 for (i = terminal->row + 1; i < terminal->height; i++) {
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000584 memset(terminal_get_row(terminal, i), 0, terminal->width * sizeof(union utf8_char));
Callum Lowcay30eeae52011-01-07 19:46:55 +0000585 attr_init(terminal_get_attr_row(terminal, i), terminal->curr_attr, terminal->width);
586 }
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500587 break;
588 case 'G':
589 if (set[0])
590 terminal->column = args[0] - 1;
591 break;
592 case 'H':
593 case 'f':
594 terminal->row = set[0] ? args[0] - 1 : 0;
595 terminal->column = set[1] ? args[1] - 1 : 0;
596 break;
597 case 'K':
598 row = terminal_get_row(terminal, terminal->row);
Callum Lowcay30eeae52011-01-07 19:46:55 +0000599 attr_row = terminal_get_attr_row(terminal, terminal->row);
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000600 memset(&row[terminal->column], 0, (terminal->width - terminal->column) * sizeof(union utf8_char));
Callum Lowcay30eeae52011-01-07 19:46:55 +0000601 attr_init(&attr_row[terminal->column], terminal->curr_attr, (terminal->width - terminal->column));
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500602 break;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000603 case 'm': /* SGR */
604 if (set[0] && set[1] && set[2] && args[1] == 5) {
605 if (args[0] == 38) {
606 handle_sgr(terminal, args[2] + 256);
607 break;
608 } else if (args[0] == 48) {
609 handle_sgr(terminal, args[2] + 512);
610 break;
611 }
612 }
613 for(i = 0; i < 10; i++) {
614 if(set[i]) {
615 handle_sgr(terminal, args[i]);
616 } else if(i == 0) {
617 handle_sgr(terminal, 0);
618 break;
619 } else {
620 break;
621 }
622 }
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500623 break;
624 case '?':
625 if (strcmp(p, "?25l") == 0) {
626 /* hide cursor */
627 } else if (strcmp(p, "?25h") == 0) {
628 /* show cursor */
629 }
630 break;
631 default:
632 terminal_data(terminal,
633 terminal->escape + 1,
634 terminal->escape_length - 2);
635 break;
636 }
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500637}
638
639static void
Callum Lowcay30eeae52011-01-07 19:46:55 +0000640handle_sgr(struct terminal *terminal, int code)
641{
642 switch(code) {
643 case 0:
644 terminal->curr_attr = terminal->color_scheme->default_attr;
645 break;
646 case 1:
647 terminal->curr_attr.a |= ATTRMASK_BOLD;
648 if (terminal->curr_attr.fg < 8)
649 terminal->curr_attr.fg += 8;
650 break;
651 case 4:
652 terminal->curr_attr.a |= ATTRMASK_UNDERLINE;
653 break;
654 case 5:
655 terminal->curr_attr.a |= ATTRMASK_BLINK;
656 break;
657 case 2:
658 case 21:
659 case 22:
660 terminal->curr_attr.a &= ~ATTRMASK_BOLD;
661 if (terminal->curr_attr.fg < 16 && terminal->curr_attr.fg >= 8)
662 terminal->curr_attr.fg -= 8;
663 break;
664 case 24:
665 terminal->curr_attr.a &= ~ATTRMASK_UNDERLINE;
666 break;
667 case 25:
668 terminal->curr_attr.a &= ~ATTRMASK_BLINK;
669 break;
670 case 7:
671 case 26:
672 terminal->curr_attr.a |= ATTRMASK_INVERSE;
673 break;
674 case 27:
675 terminal->curr_attr.a &= ~ATTRMASK_INVERSE;
676 break;
677 case 39:
678 terminal->curr_attr.fg = terminal->color_scheme->default_attr.fg;
679 break;
680 case 49:
681 terminal->curr_attr.bg = terminal->color_scheme->default_attr.bg;
682 break;
683 default:
684 if(code >= 30 && code <= 37) {
685 terminal->curr_attr.fg = code - 30;
686 if (terminal->curr_attr.a & ATTRMASK_BOLD)
687 terminal->curr_attr.fg += 8;
688 } else if(code >= 40 && code <= 47) {
689 terminal->curr_attr.bg = code - 40;
690 } else if(code >= 256 && code < 512) {
691 terminal->curr_attr.fg = code - 256;
692 } else if(code >= 512 && code < 768) {
693 terminal->curr_attr.bg = code - 512;
694 } else {
695 fprintf(stderr, "Unknown SGR code: %d\n", code);
696 }
697 break;
698 }
699}
700
701static void
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500702terminal_data(struct terminal *terminal, const char *data, size_t length)
703{
704 int i;
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000705 union utf8_char utf8;
706 enum utf8_state parser_state;
707 union utf8_char *row;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000708 struct attr *attr_row;
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500709
710 for (i = 0; i < length; i++) {
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000711 parser_state =
712 utf8_next_char(&terminal->state_machine, data[i]);
713 switch(parser_state) {
714 case utf8state_accept:
715 utf8.ch = terminal->state_machine.s.ch;
716 break;
717 case utf8state_reject:
718 /* the unicode replacement character */
719 utf8.byte[0] = 0xEF;
720 utf8.byte[1] = 0xBF;
721 utf8.byte[2] = 0xBD;
722 utf8.byte[3] = 0x00;
723 break;
724 default:
725 continue;
726 }
727
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500728 row = terminal_get_row(terminal, terminal->row);
Callum Lowcay30eeae52011-01-07 19:46:55 +0000729 attr_row = terminal_get_attr_row(terminal, terminal->row);
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500730
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500731 if (terminal->state == STATE_ESCAPE) {
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000732 terminal->escape[terminal->escape_length++] = utf8.byte[0];
733 if (terminal->escape_length == 2 && utf8.byte[0] != '[') {
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500734 /* Bad escape sequence. */
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500735 terminal->state = STATE_NORMAL;
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500736 goto cancel_escape;
737 }
738
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000739 if (isalpha(utf8.byte[0])) {
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500740 terminal->state = STATE_NORMAL;
741 handle_escape(terminal);
742 }
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500743 continue;
744 }
745
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500746 cancel_escape:
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000747 switch (utf8.byte[0]) {
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500748 case '\r':
749 terminal->column = 0;
750 break;
751 case '\n':
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500752 terminal->column = 0;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500753 if (terminal->row + 1 < terminal->height) {
754 terminal->row++;
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500755 } else {
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500756 terminal->start++;
757 if (terminal->start == terminal->height)
758 terminal->start = 0;
759 memset(terminal_get_row(terminal, terminal->row),
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000760 0, terminal->width * sizeof(union utf8_char));
Callum Lowcay30eeae52011-01-07 19:46:55 +0000761 attr_init(terminal_get_attr_row(terminal, terminal->row),
762 terminal->curr_attr, terminal->width);
Kristian Høgsbergb29415e2008-12-08 00:16:39 -0500763 }
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500764
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500765 break;
766 case '\t':
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000767 memset(&row[terminal->column], ' ', (-terminal->column & 7) * sizeof(union utf8_char));
Callum Lowcay30eeae52011-01-07 19:46:55 +0000768 attr_init(&attr_row[terminal->column], terminal->curr_attr, -terminal->column & 7);
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500769 terminal->column = (terminal->column + 7) & ~7;
770 break;
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500771 case '\e':
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500772 terminal->state = STATE_ESCAPE;
773 terminal->escape[0] = '\e';
774 terminal->escape_length = 1;
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500775 break;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500776 case '\b':
777 if (terminal->column > 0)
778 terminal->column--;
779 break;
780 case '\a':
781 /* Bell */
782 break;
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500783 default:
784 if (terminal->column < terminal->width)
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000785 if (utf8.byte[0] < 32) utf8.byte[0] += 64;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000786 row[terminal->column] = utf8;
787 attr_row[terminal->column++] = terminal->curr_attr;
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500788 break;
789 }
790 }
Kristian Høgsberg721f09f2008-12-08 11:13:26 -0500791
Kristian Høgsberg80d746f2010-06-14 23:52:50 -0400792 window_schedule_redraw(terminal->window);
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500793}
794
795static void
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -0400796key_handler(struct window *window, uint32_t key, uint32_t sym,
Kristian Høgsberg55444912009-02-21 14:31:09 -0500797 uint32_t state, uint32_t modifiers, void *data)
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500798{
799 struct terminal *terminal = data;
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -0400800 char ch[2];
801 int len = 0;
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500802
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -0400803 switch (sym) {
804 case XK_F11:
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500805 if (!state)
806 break;
807 terminal->fullscreen ^= 1;
808 window_set_fullscreen(window, terminal->fullscreen);
Kristian Høgsberg80d746f2010-06-14 23:52:50 -0400809 window_schedule_redraw(terminal->window);
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500810 break;
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -0400811
812 case XK_Delete:
813 sym = 0x04;
814 case XK_BackSpace:
815 case XK_Tab:
816 case XK_Linefeed:
817 case XK_Clear:
818 case XK_Return:
819 case XK_Pause:
820 case XK_Scroll_Lock:
821 case XK_Sys_Req:
822 case XK_Escape:
823 ch[len++] = sym & 0x7f;
824 break;
825
826 case XK_Shift_L:
827 case XK_Shift_R:
828 case XK_Control_L:
829 case XK_Control_R:
830 case XK_Alt_L:
831 case XK_Alt_R:
832 break;
833
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500834 default:
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -0400835 if (modifiers & WINDOW_MODIFIER_CONTROL)
836 sym = sym & 0x1f;
837 else if (modifiers & WINDOW_MODIFIER_ALT)
838 ch[len++] = 0x1b;
839 if (sym < 256)
840 ch[len++] = sym;
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500841 break;
842 }
Kristian Høgsberg94adf6c2010-06-25 16:50:05 -0400843
844 if (state && len > 0)
845 write(terminal->master, ch, len);
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500846}
847
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500848static void
849keyboard_focus_handler(struct window *window,
Kristian Høgsberg43788b12010-07-28 23:50:12 -0400850 struct input *device, void *data)
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500851{
852 struct terminal *terminal = data;
853
854 terminal->focused = (device != NULL);
Kristian Høgsberg80d746f2010-06-14 23:52:50 -0400855 window_schedule_redraw(terminal->window);
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500856}
857
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500858static struct terminal *
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -0500859terminal_create(struct display *display, int fullscreen)
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500860{
861 struct terminal *terminal;
Kristian Høgsberg09531622010-06-14 23:22:15 -0400862 cairo_surface_t *surface;
863 cairo_t *cr;
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500864
865 terminal = malloc(sizeof *terminal);
866 if (terminal == NULL)
867 return terminal;
868
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500869 memset(terminal, 0, sizeof *terminal);
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500870 terminal->fullscreen = fullscreen;
Callum Lowcay30eeae52011-01-07 19:46:55 +0000871 terminal->color_scheme = &DEFAULT_COLORS;
872 terminal_init(terminal);
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -0500873 terminal->window = window_create(display, "Wayland Terminal",
Kristian Høgsberg82da52b2010-12-17 09:53:12 -0500874 500, 400);
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000875
876 init_state_machine(&terminal->state_machine);
Callum Lowcay30eeae52011-01-07 19:46:55 +0000877 init_color_table(terminal);
Callum Lowcay15bdc5d2011-01-07 19:46:54 +0000878
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500879 terminal->display = display;
Kristian Høgsberg1584c572008-12-08 12:59:37 -0500880 terminal->margin = 5;
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500881
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500882 window_set_fullscreen(terminal->window, terminal->fullscreen);
Kristian Høgsbergc8c37342010-06-25 11:19:22 -0400883 window_set_user_data(terminal->window, terminal);
884 window_set_redraw_handler(terminal->window, redraw_handler);
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500885
Kristian Høgsbergc8c37342010-06-25 11:19:22 -0400886 window_set_key_handler(terminal->window, key_handler);
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500887 window_set_keyboard_focus_handler(terminal->window,
Kristian Høgsbergc8c37342010-06-25 11:19:22 -0400888 keyboard_focus_handler);
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500889
Kristian Høgsberg09531622010-06-14 23:22:15 -0400890 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0);
891 cr = cairo_create(surface);
Callum Lowcay30eeae52011-01-07 19:46:55 +0000892 terminal->font_bold = cairo_toy_font_face_create ("mono",
893 CAIRO_FONT_SLANT_NORMAL,
894 CAIRO_FONT_WEIGHT_BOLD);
895 cairo_font_face_reference(terminal->font_bold);
896 terminal->font_normal = cairo_toy_font_face_create ("mono",
897 CAIRO_FONT_SLANT_NORMAL,
898 CAIRO_FONT_WEIGHT_NORMAL);
899 cairo_font_face_reference(terminal->font_normal);
900 cairo_set_font_face(cr, terminal->font_normal);
Kristian Høgsberg09531622010-06-14 23:22:15 -0400901 cairo_set_font_size(cr, 14);
902 cairo_font_extents(cr, &terminal->extents);
903 cairo_destroy(cr);
904 cairo_surface_destroy(surface);
905
Callum Lowcaya0ee21c2011-01-07 19:46:56 +0000906 terminal_resize(terminal, 80, 24);
Kristian Høgsberg22106762008-12-08 13:50:07 -0500907 terminal_draw(terminal);
908
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500909 return terminal;
910}
911
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500912static gboolean
913io_handler(GIOChannel *source,
914 GIOCondition condition,
915 gpointer data)
916{
917 struct terminal *terminal = data;
918 gchar buffer[256];
919 gsize bytes_read;
920 GError *error = NULL;
921
922 g_io_channel_read_chars(source, buffer, sizeof buffer,
923 &bytes_read, &error);
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500924
925 terminal_data(terminal, buffer, bytes_read);
926
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500927 return TRUE;
928}
929
930static int
931terminal_run(struct terminal *terminal, const char *path)
932{
Kristian Høgsbergf0c7b202008-12-12 13:39:03 -0500933 int master;
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500934 pid_t pid;
935
936 pid = forkpty(&master, NULL, NULL, NULL);
937 if (pid == 0) {
Kristian Høgsbergc8c5d582008-12-18 14:50:08 -0500938 setenv("TERM", "vt100", 1);
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500939 if (execl(path, path, NULL)) {
940 printf("exec failed: %m\n");
941 exit(EXIT_FAILURE);
942 }
Kristian Høgsbergf0c7b202008-12-12 13:39:03 -0500943 } else if (pid < 0) {
944 fprintf(stderr, "failed to fork and create pty (%m).\n");
945 return -1;
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500946 }
947
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500948 terminal->master = master;
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500949 terminal->channel = g_io_channel_unix_new(master);
950 fcntl(master, F_SETFL, O_NONBLOCK);
951 g_io_add_watch(terminal->channel, G_IO_IN,
952 io_handler, terminal);
953
954 return 0;
955}
956
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500957static const GOptionEntry option_entries[] = {
958 { "fullscreen", 'f', 0, G_OPTION_ARG_NONE,
959 &option_fullscreen, "Run in fullscreen mode" },
960 { NULL }
961};
962
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500963int main(int argc, char *argv[])
964{
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -0500965 struct display *d;
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500966 struct terminal *terminal;
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500967
Kristian Høgsberg7824d812010-06-08 14:59:44 -0400968 d = display_create(&argc, &argv, option_entries);
Yuval Fledele9f5e362010-11-22 21:34:19 +0200969 if (d == NULL) {
970 fprintf(stderr, "failed to create display: %m\n");
971 return -1;
972 }
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500973
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -0500974 terminal = terminal_create(d, option_fullscreen);
Kristian Høgsbergf0c7b202008-12-12 13:39:03 -0500975 if (terminal_run(terminal, "/bin/bash"))
976 exit(EXIT_FAILURE);
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500977
Kristian Høgsberg7824d812010-06-08 14:59:44 -0400978 display_run(d);
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500979
980 return 0;
981}