blob: 2dd6b531569252fdbdaa214f2558bec89fa2d81c [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>
Kristian Høgsberg6e83d582008-12-08 00:01:36 -050035#include <linux/input.h>
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -050036
37#include <GL/gl.h>
38#include <eagle.h>
39
40#include "wayland-client.h"
41#include "wayland-glib.h"
42
43#include "cairo-util.h"
44#include "window.h"
45
46static const char gem_device[] = "/dev/dri/card0";
47static const char socket_name[] = "\0wayland";
48
Kristian Høgsberg6e83d582008-12-08 00:01:36 -050049#define MOD_SHIFT 0x01
50#define MOD_ALT 0x02
51#define MOD_CTRL 0x04
52
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -050053struct terminal {
54 struct window *window;
55 struct wl_display *display;
Kristian Høgsbergd2412e22008-12-15 20:35:24 -050056 struct wl_compositor *compositor;
Kristian Høgsberg721f09f2008-12-08 11:13:26 -050057 int redraw_scheduled, redraw_pending;
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -050058 char *data;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -050059 int width, height, start, row, column;
Kristian Høgsberg6e83d582008-12-08 00:01:36 -050060 int fd, master;
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -050061 struct buffer *buffer;
Kristian Høgsberg269d6e32008-12-07 23:17:31 -050062 GIOChannel *channel;
Kristian Høgsberg6e83d582008-12-08 00:01:36 -050063 uint32_t modifiers;
Kristian Høgsberg17809b12008-12-08 12:20:40 -050064 char escape[64];
65 int escape_length;
Kristian Høgsbergf04e8382008-12-08 00:07:49 -050066 int state;
Kristian Høgsberg1584c572008-12-08 12:59:37 -050067 int margin;
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -050068};
69
Kristian Høgsbergdbd54642008-12-08 22:22:25 -050070static char *
71terminal_get_row(struct terminal *terminal, int row)
72{
73 int index;
74
75 index = (row + terminal->start) % terminal->height;
76
77 return &terminal->data[index * (terminal->width + 1)];
78}
79
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -050080static void
Kristian Høgsberg22106762008-12-08 13:50:07 -050081terminal_resize(struct terminal *terminal, int width, int height)
82{
83 size_t size;
84 char *data;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -050085 int i, l, total_rows, start;
Kristian Høgsberg22106762008-12-08 13:50:07 -050086
87 if (terminal->width == width && terminal->height == height)
88 return;
89
90 size = (width + 1) * height;
91 data = malloc(size);
92 memset(data, 0, size);
93 if (terminal->data) {
94 if (width > terminal->width)
95 l = terminal->width;
96 else
97 l = width;
98
Kristian Høgsbergdbd54642008-12-08 22:22:25 -050099 if (terminal->height > height) {
Kristian Høgsberg22106762008-12-08 13:50:07 -0500100 total_rows = height;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500101 start = terminal->height - height;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500102 } else {
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500103 total_rows = terminal->height;
104 start = 0;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500105 }
106
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500107 for (i = 0; i < total_rows; i++)
Kristian Høgsberg22106762008-12-08 13:50:07 -0500108 memcpy(data + (width + 1) * i,
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500109 terminal_get_row(terminal, i), l);
Kristian Høgsberg22106762008-12-08 13:50:07 -0500110
111 free(terminal->data);
Kristian Høgsberg22106762008-12-08 13:50:07 -0500112 }
113
114 terminal->width = width;
115 terminal->height = height;
116 terminal->data = data;
117
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500118 if (terminal->row >= terminal->height)
119 terminal->row = terminal->height - 1;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500120 if (terminal->column >= terminal->width)
121 terminal->column = terminal->width - 1;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500122 terminal->start = 0;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500123}
124
125static void
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500126terminal_draw_contents(struct terminal *terminal)
127{
128 struct rectangle rectangle;
129 cairo_surface_t *surface;
130 cairo_t *cr;
131 cairo_font_extents_t extents;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500132 int i;
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500133
134 window_get_child_rectangle(terminal->window, &rectangle);
135
136 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
137 rectangle.width, rectangle.height);
138 cr = cairo_create(surface);
139 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
140 cairo_set_source_rgba(cr, 0, 0, 0, 0.9);
141 cairo_paint(cr);
142 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
Kristian Høgsberg6e0a2f82008-12-08 14:06:56 -0500143 cairo_set_source_rgba(cr, 0, 0.7, 0, 1);
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500144
145 cairo_select_font_face (cr, "mono",
146 CAIRO_FONT_SLANT_NORMAL,
147 CAIRO_FONT_WEIGHT_NORMAL);
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500148 cairo_set_font_size(cr, 14);
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500149
150 cairo_font_extents(cr, &extents);
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500151 for (i = 0; i < terminal->height; i++) {
Kristian Høgsberg1584c572008-12-08 12:59:37 -0500152 cairo_move_to(cr, terminal->margin,
153 terminal->margin + extents.ascent + extents.height * i);
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500154 cairo_show_text(cr, terminal_get_row(terminal, i));
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500155 }
156 cairo_destroy(cr);
157
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500158 terminal->buffer = buffer_create_from_cairo_surface(terminal->fd, surface);
159 cairo_surface_destroy(surface);
160
161 window_copy(terminal->window,
162 &rectangle,
163 terminal->buffer->name, terminal->buffer->stride);
164}
165
166static void
167terminal_draw(struct terminal *terminal)
168{
Kristian Høgsberg22106762008-12-08 13:50:07 -0500169 struct rectangle rectangle;
170 cairo_surface_t *surface;
171 cairo_font_extents_t extents;
172 cairo_t *cr;
173 int width, height;
174
175 window_get_child_rectangle(terminal->window, &rectangle);
176
177 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0);
178 cr = cairo_create(surface);
179 cairo_select_font_face (cr, "mono",
180 CAIRO_FONT_SLANT_NORMAL,
181 CAIRO_FONT_WEIGHT_NORMAL);
182 cairo_set_font_size(cr, 14);
183 cairo_font_extents(cr, &extents);
184 cairo_destroy(cr);
185 cairo_surface_destroy(surface);
186
187 width = (rectangle.width - 2 * terminal->margin) / (int32_t) extents.max_x_advance;
188 height = (rectangle.height - 2 * terminal->margin) / (int32_t) extents.height;
189 terminal_resize(terminal, width, height);
190
191 rectangle.width = terminal->width * extents.max_x_advance + 2 * terminal->margin;
192 rectangle.height = terminal->height * extents.height + 2 * terminal->margin;
193
194 window_set_child_size(terminal->window, &rectangle);
195
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500196 window_draw(terminal->window);
197 terminal_draw_contents(terminal);
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500198 wl_compositor_commit(terminal->compositor, 0);
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500199}
200
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500201static gboolean
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500202idle_redraw(void *data)
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500203{
204 struct terminal *terminal = data;
205
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500206 terminal_draw(terminal);
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500207
208 return FALSE;
209}
210
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500211#define STATE_NORMAL 0
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500212#define STATE_ESCAPE 1
213
214static void
215terminal_data(struct terminal *terminal, const char *data, size_t length);
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500216
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500217static void
Kristian Høgsberg721f09f2008-12-08 11:13:26 -0500218terminal_schedule_redraw(struct terminal *terminal)
219{
220 if (!terminal->redraw_scheduled) {
221 g_idle_add(idle_redraw, terminal);
222 terminal->redraw_scheduled = 1;
223 } else {
224 terminal->redraw_pending = 1;
225 }
226}
227
228static void
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500229terminal_data(struct terminal *terminal, const char *data, size_t length);
230
231static void
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500232handle_escape(struct terminal *terminal)
233{
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500234 char *row, *p;
235 int i, count;
236 int args[10], set[10] = { 0, };
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500237
238 terminal->escape[terminal->escape_length++] = '\0';
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500239 i = 0;
240 p = &terminal->escape[2];
241 while ((isdigit(*p) || *p == ';') && i < 10) {
242 if (*p == ';') {
243 p++;
244 i++;
245 } else {
246 args[i] = strtol(p, &p, 10);
247 set[i] = 1;
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500248 }
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500249 }
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500250
251 switch (*p) {
252 case 'A':
253 count = set[0] ? args[0] : 1;
254 if (terminal->row - count >= 0)
255 terminal->row -= count;
256 else
257 terminal->row = 0;
258 break;
259 case 'B':
260 count = set[0] ? args[0] : 1;
261 if (terminal->row + count < terminal->height)
262 terminal->row += count;
263 else
264 terminal->row = terminal->height;
265 break;
266 case 'C':
267 count = set[0] ? args[0] : 1;
268 if (terminal->column + count < terminal->width)
269 terminal->column += count;
270 else
271 terminal->column = terminal->width;
272 break;
273 case 'D':
274 count = set[0] ? args[0] : 1;
275 if (terminal->column - count >= 0)
276 terminal->column -= count;
277 else
278 terminal->column = 0;
279 break;
280 case 'J':
281 row = terminal_get_row(terminal, terminal->row);
282 memset(&row[terminal->column], 0, terminal->width - terminal->column);
283 for (i = terminal->row + 1; i < terminal->height; i++)
284 memset(terminal_get_row(terminal, i), 0, terminal->width);
285 break;
286 case 'G':
287 if (set[0])
288 terminal->column = args[0] - 1;
289 break;
290 case 'H':
291 case 'f':
292 terminal->row = set[0] ? args[0] - 1 : 0;
293 terminal->column = set[1] ? args[1] - 1 : 0;
294 break;
295 case 'K':
296 row = terminal_get_row(terminal, terminal->row);
297 memset(&row[terminal->column], 0, terminal->width - terminal->column);
298 break;
299 case 'm':
300 /* color, blink, bold etc*/
301 break;
302 case '?':
303 if (strcmp(p, "?25l") == 0) {
304 /* hide cursor */
305 } else if (strcmp(p, "?25h") == 0) {
306 /* show cursor */
307 }
308 break;
309 default:
310 terminal_data(terminal,
311 terminal->escape + 1,
312 terminal->escape_length - 2);
313 break;
314 }
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500315}
316
317static void
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500318terminal_data(struct terminal *terminal, const char *data, size_t length)
319{
320 int i;
321 char *row;
322
323 for (i = 0; i < length; i++) {
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500324 row = terminal_get_row(terminal, terminal->row);
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500325
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500326 if (terminal->state == STATE_ESCAPE) {
327 terminal->escape[terminal->escape_length++] = data[i];
328 if (terminal->escape_length == 2 && data[i] != '[') {
329 /* Bad escape sequence. */
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500330 terminal->state = STATE_NORMAL;
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500331 goto cancel_escape;
332 }
333
334 if (isalpha(data[i])) {
335 terminal->state = STATE_NORMAL;
336 handle_escape(terminal);
337 }
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500338 continue;
339 }
340
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500341 cancel_escape:
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500342 switch (data[i]) {
343 case '\r':
344 terminal->column = 0;
345 break;
346 case '\n':
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500347 terminal->column = 0;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500348 if (terminal->row + 1 < terminal->height) {
349 terminal->row++;
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500350 } else {
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500351 terminal->start++;
352 if (terminal->start == terminal->height)
353 terminal->start = 0;
354 memset(terminal_get_row(terminal, terminal->row),
355 0, terminal->width);
Kristian Høgsbergb29415e2008-12-08 00:16:39 -0500356 }
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500357
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500358 break;
359 case '\t':
360 memset(&row[terminal->column], ' ', -terminal->column & 7);
361 terminal->column = (terminal->column + 7) & ~7;
362 break;
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500363 case '\e':
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500364 terminal->state = STATE_ESCAPE;
365 terminal->escape[0] = '\e';
366 terminal->escape_length = 1;
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500367 break;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500368 case '\b':
369 if (terminal->column > 0)
370 terminal->column--;
371 break;
372 case '\a':
373 /* Bell */
374 break;
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500375 default:
376 if (terminal->column < terminal->width)
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500377 row[terminal->column++] = data[i] < 32 ? data[i] + 64 : data[i];
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500378 break;
379 }
380 }
Kristian Høgsberg721f09f2008-12-08 11:13:26 -0500381
382 terminal_schedule_redraw(terminal);
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500383}
384
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500385static void
Kristian Høgsberg22106762008-12-08 13:50:07 -0500386resize_handler(struct window *window, void *data)
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500387{
388 struct terminal *terminal = data;
389
Kristian Høgsberg721f09f2008-12-08 11:13:26 -0500390 terminal_schedule_redraw(terminal);
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500391}
392
393static void
394acknowledge_handler(struct window *window, uint32_t key, void *data)
395{
396 struct terminal *terminal = data;
397
Kristian Høgsberg721f09f2008-12-08 11:13:26 -0500398 terminal->redraw_scheduled = 0;
Kristian Høgsbergc47303f2008-12-08 09:57:08 -0500399 buffer_destroy(terminal->buffer, terminal->fd);
Kristian Høgsberg721f09f2008-12-08 11:13:26 -0500400
401 if (terminal->redraw_pending) {
402 terminal->redraw_pending = 0;
403 terminal_schedule_redraw(terminal);
404 }
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500405}
406
407struct key {
Kristian Høgsberg0d77fd42008-12-08 00:23:55 -0500408 int code[4];
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500409} evdev_keymap[] = {
410 { { 0, 0 } }, /* 0 */
411 { { 0x1b, 0x1b } },
412 { { '1', '!' } },
413 { { '2', '@' } },
414 { { '3', '#' } },
415 { { '4', '$' } },
416 { { '5', '%' } },
417 { { '6', '^' } },
418 { { '7', '&' } },
419 { { '8', '*' } },
420 { { '9', '(' } },
421 { { '0', ')' } },
422 { { '-', '_' } },
423 { { '=', '+' } },
424 { { '\b', '\b' } },
425 { { '\t', '\t' } },
426
427 { { 'q', 'Q' } }, /* 16 */
Kristian Høgsberg0d77fd42008-12-08 00:23:55 -0500428 { { 'w', 'W', 0x17 } },
429 { { 'e', 'E', 0x05 } },
430 { { 'r', 'R', 0x12 } },
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500431 { { 't', 'T' } },
432 { { 'y', 'Y' } },
Kristian Høgsberg0d77fd42008-12-08 00:23:55 -0500433 { { 'u', 'U', 0x15 } },
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500434 { { 'i', 'I' } },
435 { { 'o', 'O' } },
Kristian Høgsberg0d77fd42008-12-08 00:23:55 -0500436 { { 'p', 'P', 0x10 } },
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500437 { { '[', '{' } },
438 { { ']', '}' } },
439 { { '\n', '\n' } },
440 { { 0, 0 } },
Kristian Høgsberg0d77fd42008-12-08 00:23:55 -0500441 { { 'a', 'A', 0x01} },
442 { { 's', 'S', 0x13 } },
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500443
Kristian Høgsberg0d77fd42008-12-08 00:23:55 -0500444 { { 'd', 'D', 0x04 } }, /* 32 */
445 { { 'f', 'F', 0x06 } },
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500446 { { 'g', 'G' } },
447 { { 'h', 'H' } },
Kristian Høgsberg0d77fd42008-12-08 00:23:55 -0500448 { { 'j', 'J', 0x0a } },
449 { { 'k', 'K', 0x0b } },
450 { { 'l', 'L', 0x0c } },
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500451 { { ';', ':' } },
452 { { '\'', '"' } },
453 { { '`', '~' } },
454 { { 0, 0 } },
455 { { '\\', '|' } },
456 { { 'z', 'Z' } },
457 { { 'x', 'X' } },
458 { { 'c', 'C' } },
459 { { 'v', 'V' } },
460
Kristian Høgsberg0d77fd42008-12-08 00:23:55 -0500461 { { 'b', 'B', 0x02 } }, /* 48 */
462 { { 'n', 'N', 0x0e } },
463 { { 'm', 'M', 0x0d } },
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500464 { { ',', '<' } },
465 { { '.', '>' } },
466 { { '/', '?' } },
467 { { 0, 0 } },
468 { { '*', '*' } },
469 { { 0, 0 } },
470 { { ' ', ' ' } },
471 { { 0, 0 } }
472
473 /* 59 */
474};
475
476#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
477
478static void
479key_handler(struct window *window, uint32_t key, uint32_t state, void *data)
480{
481 struct terminal *terminal = data;
482 uint32_t mod = 0;
483 char c;
484
485 switch (key) {
486 case KEY_LEFTSHIFT:
487 case KEY_RIGHTSHIFT:
488 mod = MOD_SHIFT;
489 break;
490 case KEY_LEFTCTRL:
491 case KEY_RIGHTCTRL:
492 mod = MOD_CTRL;
493 break;
494 case KEY_LEFTALT:
495 case KEY_RIGHTALT:
496 mod = MOD_ALT;
497 break;
498 default:
499 if (key < ARRAY_LENGTH(evdev_keymap)) {
Kristian Høgsberg0d77fd42008-12-08 00:23:55 -0500500 if (terminal->modifiers & MOD_CTRL)
501 c = evdev_keymap[key].code[2];
502 else if (terminal->modifiers & MOD_SHIFT)
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500503 c = evdev_keymap[key].code[1];
504 else
505 c = evdev_keymap[key].code[0];
506 if (state && c)
507 write(terminal->master, &c, 1);
508 }
509 break;
510 }
511
512 if (state)
513 terminal->modifiers |= mod;
514 else
515 terminal->modifiers &= ~mod;
516}
517
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500518static struct terminal *
519terminal_create(struct wl_display *display, int fd)
520{
521 struct terminal *terminal;
522
523 terminal = malloc(sizeof *terminal);
524 if (terminal == NULL)
525 return terminal;
526
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500527 memset(terminal, 0, sizeof *terminal);
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500528 terminal->fd = fd;
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500529 terminal->window = window_create(display, fd, "Wayland Terminal",
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500530 500, 100, 500, 400);
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500531 terminal->display = display;
Kristian Høgsberg721f09f2008-12-08 11:13:26 -0500532 terminal->redraw_scheduled = 1;
Kristian Høgsberg1584c572008-12-08 12:59:37 -0500533 terminal->margin = 5;
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500534
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500535 terminal->compositor = wl_display_get_compositor(display);
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500536 window_set_resize_handler(terminal->window, resize_handler, terminal);
537 window_set_acknowledge_handler(terminal->window, acknowledge_handler, terminal);
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500538 window_set_key_handler(terminal->window, key_handler, terminal);
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500539
Kristian Høgsberg22106762008-12-08 13:50:07 -0500540 terminal_draw(terminal);
541
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500542 return terminal;
543}
544
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500545static gboolean
546io_handler(GIOChannel *source,
547 GIOCondition condition,
548 gpointer data)
549{
550 struct terminal *terminal = data;
551 gchar buffer[256];
552 gsize bytes_read;
553 GError *error = NULL;
554
555 g_io_channel_read_chars(source, buffer, sizeof buffer,
556 &bytes_read, &error);
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500557
558 terminal_data(terminal, buffer, bytes_read);
559
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500560 return TRUE;
561}
562
563static int
564terminal_run(struct terminal *terminal, const char *path)
565{
Kristian Høgsbergf0c7b202008-12-12 13:39:03 -0500566 int master;
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500567 pid_t pid;
568
569 pid = forkpty(&master, NULL, NULL, NULL);
570 if (pid == 0) {
571 close(master);
Kristian Høgsbergc8c5d582008-12-18 14:50:08 -0500572 setenv("TERM", "vt100", 1);
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500573 if (execl(path, path, NULL)) {
574 printf("exec failed: %m\n");
575 exit(EXIT_FAILURE);
576 }
Kristian Høgsbergf0c7b202008-12-12 13:39:03 -0500577 } else if (pid < 0) {
578 fprintf(stderr, "failed to fork and create pty (%m).\n");
579 return -1;
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500580 }
581
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500582 terminal->master = master;
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500583 terminal->channel = g_io_channel_unix_new(master);
584 fcntl(master, F_SETFL, O_NONBLOCK);
585 g_io_add_watch(terminal->channel, G_IO_IN,
586 io_handler, terminal);
587
588 return 0;
589}
590
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500591int main(int argc, char *argv[])
592{
593 struct wl_display *display;
594 int fd;
595 GMainLoop *loop;
596 GSource *source;
597 struct terminal *terminal;
598
599 fd = open(gem_device, O_RDWR);
600 if (fd < 0) {
601 fprintf(stderr, "drm open failed: %m\n");
602 return -1;
603 }
604
605 display = wl_display_create(socket_name, sizeof socket_name);
606 if (display == NULL) {
607 fprintf(stderr, "failed to create display: %m\n");
608 return -1;
609 }
610
611 loop = g_main_loop_new(NULL, FALSE);
612 source = wl_glib_source_new(display);
613 g_source_attach(source, NULL);
614
615 terminal = terminal_create(display, fd);
Kristian Høgsbergf0c7b202008-12-12 13:39:03 -0500616 if (terminal_run(terminal, "/bin/bash"))
617 exit(EXIT_FAILURE);
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500618
619 g_main_loop_run(loop);
620
621 return 0;
622}