Run command in a pty and feed output to wayland terminal.
authorKristian Høgsberg <krh@redhat.com>
Mon, 8 Dec 2008 04:17:31 +0000 (23:17 -0500)
committerKristian Høgsberg <krh@redhat.com>
Mon, 8 Dec 2008 04:17:31 +0000 (23:17 -0500)
Makefile.in
terminal.c

index da1e990..ecc357e 100644 (file)
@@ -42,6 +42,8 @@ gears : gears.o window.o wayland-glib.o cairo-util.o
 screenshot : screenshot.o wayland-glib.o
 terminal : terminal.o window.o wayland-glib.o cairo-util.o
 
+terminal : LDLIBS += -lutil
+
 $(clients) : CFLAGS += @CLIENT_CFLAGS@
 $(clients) : LDLIBS += @CLIENT_LIBS@ -L. -lwayland -lrt
 
index 0ecb304..acd4f2b 100644 (file)
@@ -28,6 +28,7 @@
 #include <unistd.h>
 #include <math.h>
 #include <time.h>
+#include <pty.h>
 #include <cairo.h>
 #include <glib.h>
 
@@ -48,9 +49,10 @@ struct terminal {
        struct wl_display *display;
        int resize_scheduled;
        char *data;
-       int width, height;
+       int width, height, tail, row, column;
        int fd;
        struct buffer *buffer;
+       GIOChannel *channel;
 };
 
 static void
@@ -60,7 +62,7 @@ terminal_draw_contents(struct terminal *terminal)
        cairo_surface_t *surface;
        cairo_t *cr;
        cairo_font_extents_t extents;
-       int i;
+       int i, line;
 
        window_get_child_rectangle(terminal->window, &rectangle);
 
@@ -76,11 +78,13 @@ terminal_draw_contents(struct terminal *terminal)
        cairo_select_font_face (cr, "mono",
                                CAIRO_FONT_SLANT_NORMAL,
                                CAIRO_FONT_WEIGHT_NORMAL);
+       cairo_set_font_size(cr, 14);
 
        cairo_font_extents(cr, &extents);
        for (i = 0; i < terminal->height; i++) {
+               line = (terminal->tail + i) % terminal->height;
                cairo_move_to(cr, 0, extents.ascent + extents.height * i);
-               cairo_show_text(cr, &terminal->data[i * (terminal->width + 1)]);
+               cairo_show_text(cr, &terminal->data[line * (terminal->width + 1)]);
        }
        cairo_destroy(cr);
 
@@ -132,16 +136,47 @@ acknowledge_handler(struct window *window, uint32_t key, void *data)
        terminal->resize_scheduled = 0;
 }
 
+static void
+terminal_data(struct terminal *terminal, const char *data, size_t length)
+{
+       int i;
+       char *row;
+
+       for (i = 0; i < length; i++) {
+               row = &terminal->data[terminal->row * (terminal->width + 1)];
+               switch (data[i]) {
+               case '\r':
+                       terminal->column = 0;
+                       break;
+               case '\n':
+                       terminal->row++;
+                       terminal->column = 0;
+                       if (terminal->row == terminal->height)
+                               terminal->row = 0;
+                       break;
+               case '\t':
+                       memset(&row[terminal->column], ' ', -terminal->column & 7);
+                       terminal->column = (terminal->column + 7) & ~7;
+                       break;
+               default:
+                       if (terminal->column < terminal->width)
+                               row[terminal->column++] = data[i];
+                       break;
+               }
+       }
+}
+
 static struct terminal *
 terminal_create(struct wl_display *display, int fd)
 {
        struct terminal *terminal;
-       int size, i;
+       int size;
 
        terminal = malloc(sizeof *terminal);
        if (terminal == NULL)
                return terminal;
 
+       memset(terminal, 0, sizeof *terminal);
        terminal->fd = fd;
        terminal->window = window_create(display, fd, "Wayland Terminal",
                                         500, 100, 500, 400);
@@ -153,17 +188,60 @@ terminal_create(struct wl_display *display, int fd)
        terminal->data = malloc(size);
        memset(terminal->data, 0, size);
 
-       for (i = 0; i < terminal->height; i++) {
-               snprintf(&terminal->data[i * (terminal->width + 1)], terminal->width,
-                        "hello world, line %d", i);
-       }
-
        window_set_resize_handler(terminal->window, resize_handler, terminal);
        window_set_acknowledge_handler(terminal->window, acknowledge_handler, terminal);
 
        return terminal;
 }
 
+static gboolean
+io_handler(GIOChannel   *source,
+          GIOCondition  condition,
+          gpointer      data)
+{
+       struct terminal *terminal = data;
+       gchar buffer[256];
+       gsize bytes_read;
+       GError *error = NULL;
+
+       g_io_channel_read_chars(source, buffer, sizeof buffer,
+                               &bytes_read, &error);
+       printf("got data: %.*s\n", bytes_read, buffer);
+
+       terminal_data(terminal, buffer, bytes_read);
+
+       if (!terminal->resize_scheduled) {
+               g_idle_add(idle_redraw, terminal);
+               terminal->resize_scheduled = 1;
+       }
+
+       return TRUE;
+}
+
+static int
+terminal_run(struct terminal *terminal, const char *path)
+{
+       int master, slave;
+       pid_t pid;
+
+       pid = forkpty(&master, NULL, NULL, NULL);
+       if (pid == 0) {
+               close(master);
+               if (execl(path, path, NULL)) {
+                       printf("exec failed: %m\n");
+                       exit(EXIT_FAILURE);
+               }
+       }
+
+       close(slave);
+       terminal->channel = g_io_channel_unix_new(master);
+       fcntl(master, F_SETFL, O_NONBLOCK);
+       g_io_add_watch(terminal->channel, G_IO_IN,
+                      io_handler, terminal);
+
+       return 0;
+}
+
 int main(int argc, char *argv[])
 {
        struct wl_display *display;
@@ -189,6 +267,7 @@ int main(int argc, char *argv[])
        g_source_attach(source, NULL);
 
        terminal = terminal_create(display, fd);
+       terminal_run(terminal, "/bin/bash");
        terminal_draw(terminal);
 
        g_main_loop_run(loop);