blob: 8e878e717519633ecfc0ebfeae25405dabbca1ba [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øgsberg0ac16f02009-01-15 11:37:43 -050036#include <cairo-drm.h>
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -050037
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -050038#include "wayland-client.h"
39#include "wayland-glib.h"
40
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -050041#include "window.h"
42
Kristian Høgsberg0395f302008-12-22 12:14:50 -050043static int option_fullscreen;
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -050044static const char gem_device[] = "/dev/dri/card0";
45static const char socket_name[] = "\0wayland";
46
Kristian Høgsberg6e83d582008-12-08 00:01:36 -050047#define MOD_SHIFT 0x01
48#define MOD_ALT 0x02
49#define MOD_CTRL 0x04
50
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -050051struct terminal {
52 struct window *window;
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -050053 struct display *display;
Kristian Høgsbergd2412e22008-12-15 20:35:24 -050054 struct wl_compositor *compositor;
Kristian Høgsberg721f09f2008-12-08 11:13:26 -050055 int redraw_scheduled, redraw_pending;
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -050056 char *data;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -050057 int width, height, start, row, column;
Kristian Høgsberg6e83d582008-12-08 00:01:36 -050058 int fd, master;
Kristian Høgsberg0ac16f02009-01-15 11:37:43 -050059 cairo_surface_t *surface;
Kristian Høgsberg269d6e32008-12-07 23:17:31 -050060 GIOChannel *channel;
Kristian Høgsberg6e83d582008-12-08 00:01:36 -050061 uint32_t modifiers;
Kristian Høgsberg17809b12008-12-08 12:20:40 -050062 char escape[64];
63 int escape_length;
Kristian Høgsbergf04e8382008-12-08 00:07:49 -050064 int state;
Kristian Høgsberg1584c572008-12-08 12:59:37 -050065 int margin;
Kristian Høgsberg0395f302008-12-22 12:14:50 -050066 int fullscreen;
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -050067 int focused;
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;
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500129 cairo_t *cr;
130 cairo_font_extents_t extents;
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500131 int i, top_margin, side_margin;
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500132 double d;
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500133
134 window_get_child_rectangle(terminal->window, &rectangle);
135
Kristian Høgsberg0ac16f02009-01-15 11:37:43 -0500136 terminal->surface =
137 window_create_surface(terminal->window, &rectangle);
138 cr = cairo_create(terminal->surface);
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500139 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øgsberg0395f302008-12-22 12:14:50 -0500151 side_margin = (rectangle.width - terminal->width * extents.max_x_advance) / 2;
152 top_margin = (rectangle.height - terminal->height * extents.height) / 2;
153
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500154 for (i = 0; i < terminal->height; i++) {
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500155 cairo_move_to(cr, side_margin,
156 top_margin + extents.ascent + extents.height * i);
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500157 cairo_show_text(cr, terminal_get_row(terminal, i));
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500158 }
Kristian Høgsbergb0b82e22009-02-21 15:42:25 -0500159
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500160 d = terminal->focused ? 0 : 0.5;
161
162 cairo_set_line_width(cr, 1);
163 cairo_move_to(cr, side_margin + terminal->column * extents.max_x_advance + d,
164 top_margin + terminal->row * extents.height + d);
165 cairo_rel_line_to(cr, extents.max_x_advance - 2 * d, 0);
166 cairo_rel_line_to(cr, 0, extents.height - 2 * d);
167 cairo_rel_line_to(cr, -extents.max_x_advance + 2 * d, 0);
Kristian Høgsbergb0b82e22009-02-21 15:42:25 -0500168 cairo_close_path(cr);
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500169
170 if (terminal->focused)
171 cairo_fill(cr);
172 else
173 cairo_stroke(cr);
Kristian Høgsbergb0b82e22009-02-21 15:42:25 -0500174
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500175 cairo_destroy(cr);
176
Kristian Høgsberg0ac16f02009-01-15 11:37:43 -0500177 window_copy_surface(terminal->window,
178 &rectangle,
179 terminal->surface);
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500180}
181
182static void
183terminal_draw(struct terminal *terminal)
184{
Kristian Høgsberg22106762008-12-08 13:50:07 -0500185 struct rectangle rectangle;
186 cairo_surface_t *surface;
187 cairo_font_extents_t extents;
188 cairo_t *cr;
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500189 int32_t width, height;
Kristian Høgsberg22106762008-12-08 13:50:07 -0500190
191 window_get_child_rectangle(terminal->window, &rectangle);
192
193 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0);
194 cr = cairo_create(surface);
195 cairo_select_font_face (cr, "mono",
196 CAIRO_FONT_SLANT_NORMAL,
197 CAIRO_FONT_WEIGHT_NORMAL);
198 cairo_set_font_size(cr, 14);
199 cairo_font_extents(cr, &extents);
200 cairo_destroy(cr);
201 cairo_surface_destroy(surface);
202
203 width = (rectangle.width - 2 * terminal->margin) / (int32_t) extents.max_x_advance;
204 height = (rectangle.height - 2 * terminal->margin) / (int32_t) extents.height;
205 terminal_resize(terminal, width, height);
206
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500207 if (!terminal->fullscreen) {
208 rectangle.width = terminal->width * extents.max_x_advance + 2 * terminal->margin;
209 rectangle.height = terminal->height * extents.height + 2 * terminal->margin;
210 window_set_child_size(terminal->window, &rectangle);
211 }
Kristian Høgsberg22106762008-12-08 13:50:07 -0500212
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500213 window_draw(terminal->window);
214 terminal_draw_contents(terminal);
Kristian Høgsbergd2412e22008-12-15 20:35:24 -0500215 wl_compositor_commit(terminal->compositor, 0);
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500216}
217
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500218static gboolean
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500219idle_redraw(void *data)
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500220{
221 struct terminal *terminal = data;
222
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500223 terminal_draw(terminal);
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500224
225 return FALSE;
226}
227
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500228#define STATE_NORMAL 0
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500229#define STATE_ESCAPE 1
230
231static void
232terminal_data(struct terminal *terminal, const char *data, size_t length);
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500233
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500234static void
Kristian Høgsberg721f09f2008-12-08 11:13:26 -0500235terminal_schedule_redraw(struct terminal *terminal)
236{
237 if (!terminal->redraw_scheduled) {
238 g_idle_add(idle_redraw, terminal);
239 terminal->redraw_scheduled = 1;
240 } else {
241 terminal->redraw_pending = 1;
242 }
243}
244
245static void
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500246handle_escape(struct terminal *terminal)
247{
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500248 char *row, *p;
249 int i, count;
250 int args[10], set[10] = { 0, };
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500251
252 terminal->escape[terminal->escape_length++] = '\0';
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500253 i = 0;
254 p = &terminal->escape[2];
255 while ((isdigit(*p) || *p == ';') && i < 10) {
256 if (*p == ';') {
257 p++;
258 i++;
259 } else {
260 args[i] = strtol(p, &p, 10);
261 set[i] = 1;
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500262 }
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500263 }
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500264
265 switch (*p) {
266 case 'A':
267 count = set[0] ? args[0] : 1;
268 if (terminal->row - count >= 0)
269 terminal->row -= count;
270 else
271 terminal->row = 0;
272 break;
273 case 'B':
274 count = set[0] ? args[0] : 1;
275 if (terminal->row + count < terminal->height)
276 terminal->row += count;
277 else
278 terminal->row = terminal->height;
279 break;
280 case 'C':
281 count = set[0] ? args[0] : 1;
282 if (terminal->column + count < terminal->width)
283 terminal->column += count;
284 else
285 terminal->column = terminal->width;
286 break;
287 case 'D':
288 count = set[0] ? args[0] : 1;
289 if (terminal->column - count >= 0)
290 terminal->column -= count;
291 else
292 terminal->column = 0;
293 break;
294 case 'J':
295 row = terminal_get_row(terminal, terminal->row);
296 memset(&row[terminal->column], 0, terminal->width - terminal->column);
297 for (i = terminal->row + 1; i < terminal->height; i++)
298 memset(terminal_get_row(terminal, i), 0, terminal->width);
299 break;
300 case 'G':
301 if (set[0])
302 terminal->column = args[0] - 1;
303 break;
304 case 'H':
305 case 'f':
306 terminal->row = set[0] ? args[0] - 1 : 0;
307 terminal->column = set[1] ? args[1] - 1 : 0;
308 break;
309 case 'K':
310 row = terminal_get_row(terminal, terminal->row);
311 memset(&row[terminal->column], 0, terminal->width - terminal->column);
312 break;
313 case 'm':
314 /* color, blink, bold etc*/
315 break;
316 case '?':
317 if (strcmp(p, "?25l") == 0) {
318 /* hide cursor */
319 } else if (strcmp(p, "?25h") == 0) {
320 /* show cursor */
321 }
322 break;
323 default:
324 terminal_data(terminal,
325 terminal->escape + 1,
326 terminal->escape_length - 2);
327 break;
328 }
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500329}
330
331static void
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500332terminal_data(struct terminal *terminal, const char *data, size_t length)
333{
334 int i;
335 char *row;
336
337 for (i = 0; i < length; i++) {
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500338 row = terminal_get_row(terminal, terminal->row);
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500339
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500340 if (terminal->state == STATE_ESCAPE) {
341 terminal->escape[terminal->escape_length++] = data[i];
342 if (terminal->escape_length == 2 && data[i] != '[') {
343 /* Bad escape sequence. */
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500344 terminal->state = STATE_NORMAL;
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500345 goto cancel_escape;
346 }
347
348 if (isalpha(data[i])) {
349 terminal->state = STATE_NORMAL;
350 handle_escape(terminal);
351 }
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500352 continue;
353 }
354
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500355 cancel_escape:
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500356 switch (data[i]) {
357 case '\r':
358 terminal->column = 0;
359 break;
360 case '\n':
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500361 terminal->column = 0;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500362 if (terminal->row + 1 < terminal->height) {
363 terminal->row++;
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500364 } else {
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500365 terminal->start++;
366 if (terminal->start == terminal->height)
367 terminal->start = 0;
368 memset(terminal_get_row(terminal, terminal->row),
369 0, terminal->width);
Kristian Høgsbergb29415e2008-12-08 00:16:39 -0500370 }
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500371
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500372 break;
373 case '\t':
374 memset(&row[terminal->column], ' ', -terminal->column & 7);
375 terminal->column = (terminal->column + 7) & ~7;
376 break;
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500377 case '\e':
Kristian Høgsberg17809b12008-12-08 12:20:40 -0500378 terminal->state = STATE_ESCAPE;
379 terminal->escape[0] = '\e';
380 terminal->escape_length = 1;
Kristian Høgsbergf04e8382008-12-08 00:07:49 -0500381 break;
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500382 case '\b':
383 if (terminal->column > 0)
384 terminal->column--;
385 break;
386 case '\a':
387 /* Bell */
388 break;
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500389 default:
390 if (terminal->column < terminal->width)
Kristian Høgsbergdbd54642008-12-08 22:22:25 -0500391 row[terminal->column++] = data[i] < 32 ? data[i] + 64 : data[i];
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500392 break;
393 }
394 }
Kristian Høgsberg721f09f2008-12-08 11:13:26 -0500395
396 terminal_schedule_redraw(terminal);
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500397}
398
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500399static void
Kristian Høgsberg22106762008-12-08 13:50:07 -0500400resize_handler(struct window *window, void *data)
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500401{
402 struct terminal *terminal = data;
403
Kristian Høgsberg721f09f2008-12-08 11:13:26 -0500404 terminal_schedule_redraw(terminal);
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500405}
406
407static void
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500408handle_acknowledge(void *data,
409 struct wl_compositor *compositor,
410 uint32_t key, uint32_t frame)
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500411{
412 struct terminal *terminal = data;
413
Kristian Høgsberg721f09f2008-12-08 11:13:26 -0500414 terminal->redraw_scheduled = 0;
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500415 if (key == 0)
Kristian Høgsberg0ac16f02009-01-15 11:37:43 -0500416 cairo_surface_destroy(terminal->surface);
Kristian Høgsberg721f09f2008-12-08 11:13:26 -0500417
418 if (terminal->redraw_pending) {
419 terminal->redraw_pending = 0;
420 terminal_schedule_redraw(terminal);
421 }
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500422}
423
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500424static void
425handle_frame(void *data,
426 struct wl_compositor *compositor,
427 uint32_t frame, uint32_t timestamp)
428{
429}
430
431static const struct wl_compositor_listener compositor_listener = {
432 handle_acknowledge,
433 handle_frame,
434};
435
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500436static void
Kristian Høgsberg55444912009-02-21 14:31:09 -0500437key_handler(struct window *window, uint32_t key, uint32_t unicode,
438 uint32_t state, uint32_t modifiers, void *data)
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500439{
440 struct terminal *terminal = data;
Kristian Høgsberg55444912009-02-21 14:31:09 -0500441 char ch = unicode;
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500442
443 switch (key) {
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500444 case KEY_F11:
445 if (!state)
446 break;
447 terminal->fullscreen ^= 1;
448 window_set_fullscreen(window, terminal->fullscreen);
449 terminal_schedule_redraw(terminal);
450 break;
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500451 default:
Kristian Høgsberg55444912009-02-21 14:31:09 -0500452 if (state && unicode)
453 write(terminal->master, &ch, 1);
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500454 break;
455 }
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500456}
457
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500458static void
459keyboard_focus_handler(struct window *window,
460 struct wl_input_device *device, void *data)
461{
462 struct terminal *terminal = data;
463
464 terminal->focused = (device != NULL);
465 terminal_schedule_redraw(terminal);
466}
467
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500468static struct terminal *
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -0500469terminal_create(struct display *display, int fullscreen)
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500470{
471 struct terminal *terminal;
472
473 terminal = malloc(sizeof *terminal);
474 if (terminal == NULL)
475 return terminal;
476
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500477 memset(terminal, 0, sizeof *terminal);
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500478 terminal->fullscreen = fullscreen;
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -0500479 terminal->window = window_create(display, "Wayland Terminal",
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500480 500, 100, 500, 400);
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500481 terminal->display = display;
Kristian Høgsberg721f09f2008-12-08 11:13:26 -0500482 terminal->redraw_scheduled = 1;
Kristian Høgsberg1584c572008-12-08 12:59:37 -0500483 terminal->margin = 5;
Kristian Høgsberg44e3c5e2008-12-07 21:51:58 -0500484
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -0500485 terminal->compositor = display_get_compositor(display);
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500486 window_set_fullscreen(terminal->window, terminal->fullscreen);
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500487 window_set_resize_handler(terminal->window, resize_handler, terminal);
Kristian Høgsberg94448c02008-12-30 11:03:33 -0500488
489 wl_compositor_add_listener(terminal->compositor,
490 &compositor_listener, terminal);
491
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500492 window_set_key_handler(terminal->window, key_handler, terminal);
Kristian Høgsberg3c248cc2009-02-22 23:01:35 -0500493 window_set_keyboard_focus_handler(terminal->window,
494 keyboard_focus_handler, terminal);
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500495
Kristian Høgsberg22106762008-12-08 13:50:07 -0500496 terminal_draw(terminal);
497
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500498 return terminal;
499}
500
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500501static gboolean
502io_handler(GIOChannel *source,
503 GIOCondition condition,
504 gpointer data)
505{
506 struct terminal *terminal = data;
507 gchar buffer[256];
508 gsize bytes_read;
509 GError *error = NULL;
510
511 g_io_channel_read_chars(source, buffer, sizeof buffer,
512 &bytes_read, &error);
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500513
514 terminal_data(terminal, buffer, bytes_read);
515
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500516 return TRUE;
517}
518
519static int
520terminal_run(struct terminal *terminal, const char *path)
521{
Kristian Høgsbergf0c7b202008-12-12 13:39:03 -0500522 int master;
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500523 pid_t pid;
524
525 pid = forkpty(&master, NULL, NULL, NULL);
526 if (pid == 0) {
Kristian Høgsbergc8c5d582008-12-18 14:50:08 -0500527 setenv("TERM", "vt100", 1);
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500528 if (execl(path, path, NULL)) {
529 printf("exec failed: %m\n");
530 exit(EXIT_FAILURE);
531 }
Kristian Høgsbergf0c7b202008-12-12 13:39:03 -0500532 } else if (pid < 0) {
533 fprintf(stderr, "failed to fork and create pty (%m).\n");
534 return -1;
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500535 }
536
Kristian Høgsberg6e83d582008-12-08 00:01:36 -0500537 terminal->master = master;
Kristian Høgsberg269d6e32008-12-07 23:17:31 -0500538 terminal->channel = g_io_channel_unix_new(master);
539 fcntl(master, F_SETFL, O_NONBLOCK);
540 g_io_add_watch(terminal->channel, G_IO_IN,
541 io_handler, terminal);
542
543 return 0;
544}
545
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500546static const GOptionEntry option_entries[] = {
547 { "fullscreen", 'f', 0, G_OPTION_ARG_NONE,
548 &option_fullscreen, "Run in fullscreen mode" },
549 { NULL }
550};
551
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500552int main(int argc, char *argv[])
553{
554 struct wl_display *display;
555 int fd;
556 GMainLoop *loop;
557 GSource *source;
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -0500558 struct display *d;
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500559 struct terminal *terminal;
Kristian Høgsberg0395f302008-12-22 12:14:50 -0500560 GOptionContext *context;
561 GError *error;
562
563 context = g_option_context_new(NULL);
564 g_option_context_add_main_entries(context, option_entries, "Wayland Terminal");
565 if (!g_option_context_parse(context, &argc, &argv, &error)) {
566 fprintf(stderr, "option parsing failed: %s\n", error->message);
567 exit(EXIT_FAILURE);
568 }
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500569
570 fd = open(gem_device, O_RDWR);
571 if (fd < 0) {
572 fprintf(stderr, "drm open failed: %m\n");
573 return -1;
574 }
575
576 display = wl_display_create(socket_name, sizeof socket_name);
577 if (display == NULL) {
578 fprintf(stderr, "failed to create display: %m\n");
579 return -1;
580 }
581
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -0500582 d = display_create(display, fd);
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500583 loop = g_main_loop_new(NULL, FALSE);
584 source = wl_glib_source_new(display);
585 g_source_attach(source, NULL);
586
Kristian Høgsberg43c28ee2009-01-26 23:42:46 -0500587 terminal = terminal_create(d, option_fullscreen);
Kristian Høgsbergf0c7b202008-12-12 13:39:03 -0500588 if (terminal_run(terminal, "/bin/bash"))
589 exit(EXIT_FAILURE);
Kristian Høgsberg0c4457f2008-12-07 19:59:11 -0500590
591 g_main_loop_run(loop);
592
593 return 0;
594}