Track and free idle task tags properly. Change F11 and F12 capabilities vte_0_3
authorNalin Dahyabhai <nalin@src.gnome.org>
Tue, 30 Apr 2002 22:06:35 +0000 (22:06 +0000)
committerNalin Dahyabhai <nalin@src.gnome.org>
Tue, 30 Apr 2002 22:06:35 +0000 (22:06 +0000)
* src/vte.c: Track and free idle task tags properly.  Change F11 and F12
capabilities from 'k;' and 'F1' to 'F1' and 'F2'.  Send a NUL on
control space. (#80350)  Allow setting and checking of word characters,
and change select-by-word behavior to use the word character list.  Emit
"contents_changed" signals whenever the visible contents change, and
"cursor_moved" when the cursor moves.  Add snapshotting method.  Scroll
when auto-margin handling moves the cursor to the next line.  Assume
that the locale charset is actually ISO-8859-1 when we're in a UTF-8
locale, so we don't toggle from UTF-8 to UTF-8.  Treat GDK_KP_Page_Up
as a GDK_Page_Up, ditto for GDK_KP_Page_Down and GDK_KP_Tab and
GDK_KP_Space.  Add vte_terminal_get_font().  Don't bother messing with
ring buffers if we're resizing them to their current sizes.
* src/pty.c, src/vte.c: Return a pid from vte_terminal_fork_command().
* src/vteaccess.c, src/vteaccess.h: Add VteTerminalAccessible object type.  It
might even work, mostly.

ChangeLog
README
configure.in
src/Makefile.am
src/pty.c
src/vte.c
src/vte.h
src/vteaccess.c [new file with mode: 0644]
src/vteaccess.h [new file with mode: 0644]
vte.spec

index b731771..2bc1327 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,19 @@
-2002-04-29 14:56  nalin
-       * src/vte.c: Track and free idle task tags properly.
+2002-04-30 18:06  nalin
+       * src/vte.c: Track and free idle task tags properly.  Change F11 and
+       F12 capabilities from 'k;' and 'F1' to 'F1' and 'F2'.  Send a NUL on
+       control space. (#80350)  Allow setting and checking of word characters,
+       and change select-by-word behavior to use the word character list.
+       Emit "contents_changed" signals whenever the visible contents change,
+       and "cursor_moved" when the cursor moves.  Add snapshotting method.
+       Scroll when auto-margin handling moves the cursor to the next line.
+       Assume that the locale charset is actually ISO-8859-1 when we're in
+       a UTF-8 locale, so we don't toggle from UTF-8 to UTF-8.  Treat
+       GDK_KP_Page_Up as a GDK_Page_Up, ditto for GDK_KP_Page_Down and
+       GDK_KP_Tab and GDK_KP_Space.  Add vte_terminal_get_font().  Don't bother
+       messing with ring buffers if we're resizing them to their current sizes.
+       * src/pty.c, src/vte.c: Return a pid from vte_terminal_fork_command().
+       * src/vteaccess.c, src/vteaccess.h: Add VteTerminalAccessible object
+       type.  It might even work, mostly.
 
 2002-04-29 14:25  nalin
        * src/vte.c: Handle me() by resetting all attributes (including
diff --git a/README b/README
index 18dc150..a8bb936 100644 (file)
--- a/README
+++ b/README
@@ -19,7 +19,7 @@
   what the widget actually sees after it filters incoming data.
 
 * What's missing?
-- Accessibility isn't started yet.
+- Accessibility isn't completed yet.
 - Mouse tracking isn't started yet.
 - Entries in the termcap file also don't contain the sequences which a terminal
   is supposed to send to the application when a specific sequence is received
index b64d94d..b2944f5 100644 (file)
@@ -17,6 +17,7 @@ AC_DEFINE(G_DISABLE_DEPRECATED,1,[Disable deprecated glib features.])
 AC_DEFINE(GDK_DISABLE_DEPRECATED,1,[Disable deprecated gdk features.])
 AC_DEFINE(GDK_PIXBUF_DISABLE_DEPRECATED,1,[Disable deprecated gdk-pixbuf features.])
 AC_DEFINE(GTK_DISABLE_DEPRECATED,1,[Disable deprecated gtk features.])
+AC_DEFINE(VTE_UTF8_BPC,6,[Maximum number of bytes used per UTF-8 character.])
 AC_DEFINE_UNQUOTED(PACKAGE,"$PACKAGE",[Package name.])
 AC_CHECK_FUNCS(getpt grantpt unlockpt ptsname ptsname_r)
 
index 4a3ac42..6714333 100644 (file)
@@ -1,5 +1,5 @@
 bin_PROGRAMS = vte
-pkginclude_HEADERS = caps.h pty.h ring.h termcap.h trie.h vte.h
+pkginclude_HEADERS = caps.h pty.h ring.h termcap.h trie.h vte.h vteaccess.h
 lib_LTLIBRARIES = libvte.la
 noinst_PROGRAMS = interpret utf8echo utf8mode iso8859mode
 EXTRA_PROGRAMS = pty ring termcap trie
@@ -21,7 +21,9 @@ libvte_la_SOURCES = \
        trie.c \
        trie.h \
        vte.c \
-       vte.h
+       vte.h \
+       vteaccess.c \
+       vteaccess.h
 
 CLEANFILES = marshal.c marshal.h
 
index 42c7e3e..1119e6b 100644 (file)
--- a/src/pty.c
+++ b/src/pty.c
@@ -44,6 +44,7 @@ vte_pty_fork_on_fd(const char *path, const char **env_add,
        pid = fork();
        if (pid == -1) {
                /* Error fork()ing.  Bail. */
+               *child = -1;
                return -1;
        }
        if (pid != 0) {
index fca4c3b..27a2ca6 100644 (file)
--- a/src/vte.c
+++ b/src/vte.c
@@ -51,6 +51,7 @@
 #include "ring.h"
 #include "trie.h"
 #include "vte.h"
+#include "vteaccess.h"
 #include <X11/Xlib.h>
 #ifdef HAVE_XFT
 #include <X11/extensions/Xrender.h>
@@ -59,7 +60,6 @@
 
 #define VTE_TAB_WIDTH  8
 #define VTE_LINE_WIDTH 1
-#define VTE_UTF8_BPC   6
 #define VTE_DEF_FG     16
 #define VTE_DEF_BG     17
 #define VTE_SATURATION_MAX 10000
@@ -91,6 +91,12 @@ typedef enum {
        VTE_KEYPAD_APPLICATION,
 } VteKeypad;
 
+typedef struct _VteScreen VteScreen;
+
+typedef struct _VteWordCharRange {
+       wchar_t start, end;
+} VteWordCharRange;
+
 /* Terminal private data. */
 struct _VteTerminalPrivate {
        /* Emulation setup data. */
@@ -185,6 +191,8 @@ struct _VteTerminalPrivate {
        } selection_start, selection_end;
 
        /* Options. */
+       GArray *word_chars;
+
        gboolean scroll_on_output;
        gboolean scroll_on_keystroke;
        long scrollback_lines;
@@ -322,7 +330,7 @@ vte_terminal_find_charcell(VteTerminal *terminal, long row, long col)
 {
        GArray *rowdata;
        struct vte_charcell *ret = NULL;
-       struct _VteScreen *screen;
+       VteScreen *screen;
        g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
        screen = terminal->pvt->screen;
        if (vte_ring_contains(screen->row_data, row)) {
@@ -339,7 +347,7 @@ static void
 vte_invalidate_cursor_once(gpointer data)
 {
        VteTerminal *terminal;
-       struct _VteScreen *screen;
+       VteScreen *screen;
        struct vte_charcell *cell;
        size_t preedit_length;
        int columns;
@@ -417,6 +425,20 @@ vte_terminal_emit_selection_changed(VteTerminal *terminal)
        g_signal_emit_by_name(terminal, "selection_changed");
 }
 
+/* Emit a "contents_changed" signal. */
+static void
+vte_terminal_emit_contents_changed(VteTerminal *terminal)
+{
+       g_signal_emit_by_name(terminal, "contents_changed");
+}
+
+/* Emit a "cursor_moved" signal. */
+static void
+vte_terminal_emit_cursor_moved(VteTerminal *terminal)
+{
+       g_signal_emit_by_name(terminal, "cursor_moved");
+}
+
 /* Deselect anything which is selected and refresh the screen if needed. */
 static void
 vte_terminal_deselect_all(VteTerminal *terminal)
@@ -535,7 +557,7 @@ vte_terminal_scroll_pages(VteTerminal *terminal, gint pages)
 
 /* Scroll so that the scroll delta is the insertion delta. */
 static void
-vte_terminal_scroll_on_something(VteTerminal *terminal)
+vte_terminal_scroll_to_bottom(VteTerminal *terminal)
 {
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
        if (floor(gtk_adjustment_get_value(terminal->adjustment)) !=
@@ -717,7 +739,7 @@ vte_sequence_handler_al(VteTerminal *terminal,
                        GQuark match_quark,
                        GValueArray *params)
 {
-       struct _VteScreen *screen;
+       VteScreen *screen;
        GtkWidget *widget;
        long start, end;
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
@@ -832,7 +854,7 @@ vte_sequence_handler_cb(VteTerminal *terminal,
 {
        GArray *rowdata;
        long i;
-       struct _VteScreen *screen;
+       VteScreen *screen;
        struct vte_charcell *pcell;
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
        screen = terminal->pvt->screen;
@@ -872,7 +894,7 @@ vte_sequence_handler_cd(VteTerminal *terminal,
 {
        GArray *rowdata;
        long i;
-       struct _VteScreen *screen;
+       VteScreen *screen;
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
        screen = terminal->pvt->screen;
        /* If the cursor is actually on the screen, clear data in the rows
@@ -901,7 +923,7 @@ vte_sequence_handler_ce(VteTerminal *terminal,
                        GValueArray *params)
 {
        GArray *rowdata;
-       struct _VteScreen *screen;
+       VteScreen *screen;
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
        screen = terminal->pvt->screen;
        /* If the cursor is actually on the screen, clear data in the row
@@ -928,7 +950,7 @@ vte_sequence_handler_ch(VteTerminal *terminal,
                        GQuark match_quark,
                        GValueArray *params)
 {
-       struct _VteScreen *screen;
+       VteScreen *screen;
        GValue *value;
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
        screen = terminal->pvt->screen;
@@ -961,7 +983,7 @@ vte_sequence_handler_cm(VteTerminal *terminal,
                        GValueArray *params)
 {
        GValue *row, *col;
-       struct _VteScreen *screen;
+       VteScreen *screen;
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
        screen = terminal->pvt->screen;
        /* We need at least two parameters. */
@@ -986,7 +1008,7 @@ vte_sequence_handler_clear_current_line(VteTerminal *terminal,
                                        GValueArray *params)
 {
        GArray *rowdata;
-       struct _VteScreen *screen;
+       VteScreen *screen;
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
        screen = terminal->pvt->screen;
        /* If the cursor is actually on the screen, clear data in the row
@@ -1056,7 +1078,7 @@ vte_sequence_handler_cv(VteTerminal *terminal,
                        GQuark match_quark,
                        GValueArray *params)
 {
-       struct _VteScreen *screen;
+       VteScreen *screen;
        GValue *value;
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
        screen = terminal->pvt->screen;
@@ -1077,7 +1099,7 @@ vte_sequence_handler_dc(VteTerminal *terminal,
                        GQuark match_quark,
                        GValueArray *params)
 {
-       struct _VteScreen *screen;
+       VteScreen *screen;
        GArray *rowdata;
        long col;
 
@@ -1120,7 +1142,7 @@ vte_sequence_handler_dl(VteTerminal *terminal,
                        GQuark match_quark,
                        GValueArray *params)
 {
-       struct _VteScreen *screen;
+       VteScreen *screen;
        long end;
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
        screen = terminal->pvt->screen;
@@ -1157,7 +1179,7 @@ static void
 vte_terminal_ensure_cursor(VteTerminal *terminal)
 {
        GArray *array;
-       struct _VteScreen *screen;
+       VteScreen *screen;
        struct vte_charcell cell;
 
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
@@ -1184,11 +1206,36 @@ vte_terminal_ensure_cursor(VteTerminal *terminal)
                        array = g_array_append_val(array, cell);
                }
                /* Add one more cell to the end of the line to get
-                * it into the column, and use it. */
+                * one for the column. */
                array = g_array_append_val(array, cell);
        }
 }
 
+static void
+vte_terminal_scroll_insertion(VteTerminal *terminal)
+{
+       long rows, delta;
+       VteScreen *screen;
+
+       g_return_if_fail(VTE_IS_TERMINAL(terminal));
+       screen = terminal->pvt->screen;
+
+       /* Make sure that the bottom row is visible, and that it's in
+        * the buffer (even if it's empty).  This usually causes the
+        * top row to become a history-only row. */
+       rows = MAX(vte_ring_next(screen->row_data),
+                  screen->cursor_current.row + 1);
+       delta = MAX(0, rows - terminal->row_count);
+
+       /* Adjust the insert delta and scroll if needed. */
+       if (delta != screen->insert_delta) {
+               vte_terminal_ensure_cursor(terminal);
+               screen->insert_delta = delta;
+               /* Update scroll bar adjustments. */
+               vte_terminal_adjust_adjustments(terminal);
+       }
+}
+
 /* Scroll forward. */
 static void
 vte_sequence_handler_do(VteTerminal *terminal,
@@ -1197,8 +1244,8 @@ vte_sequence_handler_do(VteTerminal *terminal,
                        GValueArray *params)
 {
        GtkWidget *widget;
-       long rows, col, row, start, end, delta;
-       struct _VteScreen *screen;
+       long col, row, start, end;
+       VteScreen *screen;
 
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
        widget = GTK_WIDGET(terminal);
@@ -1248,19 +1295,10 @@ vte_sequence_handler_do(VteTerminal *terminal,
                /* Move the cursor down. */
                screen->cursor_current.row++;
 
-               /* Make sure that the bottom row is visible, and that it's in
-                * the buffer (even if it's empty).  This usually causes the
-                * top row to become a history-only row. */
-               rows = MAX(vte_ring_next(screen->row_data),
-                          screen->cursor_current.row + 1);
-               delta = MAX(0, rows - terminal->row_count);
-               if (delta != screen->insert_delta) {
-                       vte_terminal_ensure_cursor(terminal);
-               }
-               screen->insert_delta = delta;
-
-               /* Update scroll bar adjustments. */
-               vte_terminal_adjust_adjustments(terminal);
+               /* Adjust the insert delta so that the row the cursor is on
+                * is viewable if the insert delta is equal to the scrolling
+                * delta. */
+               vte_terminal_scroll_insertion(terminal);
        }
 }
 
@@ -1283,7 +1321,7 @@ vte_sequence_handler_ec(VteTerminal *terminal,
                        GQuark match_quark,
                        GValueArray *params)
 {
-       struct _VteScreen *screen;
+       VteScreen *screen;
        GArray *rowdata;
        GValue *value;
        struct vte_charcell *cell;
@@ -1346,7 +1384,7 @@ vte_sequence_handler_ho(VteTerminal *terminal,
                        GQuark match_quark,
                        GValueArray *params)
 {
-       struct _VteScreen *screen;
+       VteScreen *screen;
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
        screen = terminal->pvt->screen;
        screen->cursor_current.row = screen->insert_delta;
@@ -1361,7 +1399,7 @@ vte_sequence_handler_ic(VteTerminal *terminal,
                        GValueArray *params)
 {
        long row, col;
-       struct _VteScreen *screen;
+       VteScreen *screen;
 
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
        screen = terminal->pvt->screen;
@@ -1405,7 +1443,7 @@ vte_sequence_handler_kb(VteTerminal *terminal,
                        GQuark match_quark,
                        GValueArray *params)
 {
-       struct _VteScreen *screen;
+       VteScreen *screen;
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
        screen = terminal->pvt->screen;
        screen->cursor_current.col = MAX(0, screen->cursor_current.col - 1);
@@ -1494,7 +1532,7 @@ vte_sequence_handler_nd(VteTerminal *terminal,
                        GQuark match_quark,
                        GValueArray *params)
 {
-       struct _VteScreen *screen;
+       VteScreen *screen;
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
        screen = terminal->pvt->screen;
        screen->cursor_current.col++;
@@ -1507,7 +1545,7 @@ vte_sequence_handler_rc(VteTerminal *terminal,
                        GQuark match_quark,
                        GValueArray *params)
 {
-       struct _VteScreen *screen;
+       VteScreen *screen;
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
        screen = terminal->pvt->screen;
        screen->cursor_current.col = screen->cursor_saved.col;
@@ -1533,7 +1571,7 @@ vte_sequence_handler_sc(VteTerminal *terminal,
                        GQuark match_quark,
                        GValueArray *params)
 {
-       struct _VteScreen *screen;
+       VteScreen *screen;
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
        screen = terminal->pvt->screen;
        screen->cursor_saved.col = screen->cursor_current.col;
@@ -1607,7 +1645,7 @@ vte_sequence_handler_up(VteTerminal *terminal,
 {
        GtkWidget *widget;
        long col, row, start, end;
-       struct _VteScreen *screen;
+       VteScreen *screen;
 
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
        widget = GTK_WIDGET(terminal);
@@ -1875,7 +1913,7 @@ vte_sequence_handler_clear_above_current(VteTerminal *terminal,
 {
        GArray *rowdata;
        long i;
-       struct _VteScreen *screen;
+       VteScreen *screen;
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
        screen = terminal->pvt->screen;
        /* If the cursor is actually on the screen, clear data in the row
@@ -1905,7 +1943,7 @@ vte_sequence_handler_clear_screen(VteTerminal *terminal,
 {
        GArray *rowdata;
        long i;
-       struct _VteScreen *screen;
+       VteScreen *screen;
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
        screen = terminal->pvt->screen;
        /* If the cursor is actually on the screen, clear data in the row
@@ -2315,7 +2353,7 @@ vte_sequence_handler_insert_lines(VteTerminal *terminal,
                                  GValueArray *params)
 {
        GValue *value;
-       struct _VteScreen *screen;
+       VteScreen *screen;
        long param, end, row;
        int i;
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
@@ -2352,7 +2390,7 @@ vte_sequence_handler_delete_lines(VteTerminal *terminal,
                                  GValueArray *params)
 {
        GValue *value;
-       struct _VteScreen *screen;
+       VteScreen *screen;
        long param, end, row;
        int i;
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
@@ -2417,7 +2455,11 @@ vte_sequence_handler_local_charset(VteTerminal *terminal,
 #ifdef VTE_DEFAULT_ISO_8859_1
        vte_terminal_set_encoding(terminal, "ISO-8859-1");
 #else
-       vte_terminal_set_encoding(terminal, nl_langinfo(CODESET));
+       if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0) {
+               vte_terminal_set_encoding(terminal, "ISO-8859-1");
+       } else {
+               vte_terminal_set_encoding(terminal, nl_langinfo(CODESET));
+       }
 #endif
 }
 
@@ -2944,7 +2986,7 @@ vte_terminal_insert_char(GtkWidget *widget, wchar_t c)
        struct vte_charcell cell, *pcell;
        int columns, i;
        long col;
-       struct _VteScreen *screen;
+       VteScreen *screen;
 
        g_return_if_fail(widget != NULL);
        g_return_if_fail(VTE_IS_TERMINAL(widget));
@@ -3114,7 +3156,7 @@ vte_terminal_handle_sequence(GtkWidget *widget,
 {
        VteTerminal *terminal;
        VteTerminalSequenceHandler handler;
-       struct _VteScreen *screen;
+       VteScreen *screen;
 
        g_return_if_fail(widget != NULL);
        g_return_if_fail(VTE_IS_TERMINAL(widget));
@@ -3152,13 +3194,14 @@ vte_terminal_handle_sequence(GtkWidget *widget,
 }
 
 /* Start up a command in a slave PTY. */
-void
+pid_t
 vte_terminal_fork_command(VteTerminal *terminal, const char *command,
                          const char **argv)
 {
        const char **env_add;
        char *term, *colorterm;
        int i;
+       pid_t pid;
 
        /* Start up the command and get the PTY of the master. */
        env_add = g_malloc0(sizeof(char*) * 3);
@@ -3167,7 +3210,7 @@ vte_terminal_fork_command(VteTerminal *terminal, const char *command,
        env_add[0] = term;
        env_add[1] = colorterm;
        env_add[2] = NULL;
-       terminal->pvt->pty_master = vte_pty_open(&terminal->pvt->pty_pid,
+       terminal->pvt->pty_master = vte_pty_open(&pid,
                                                 env_add,
                                                 command ?:
                                                 terminal->pvt->shell,
@@ -3176,21 +3219,30 @@ vte_terminal_fork_command(VteTerminal *terminal, const char *command,
        g_free(colorterm);
        g_free((char**)env_add);
 
-       /* Set the pty to be non-blocking. */
-       i = fcntl(terminal->pvt->pty_master, F_GETFL);
-       fcntl(terminal->pvt->pty_master, F_SETFL, i | O_NONBLOCK);
+       /* If we started the process, set up to listen for its output. */
+       if (pid != -1) {
+               /* Set this as the child's pid. */
+               terminal->pvt->pty_pid = pid;
+
+               /* Set the pty to be non-blocking. */
+               i = fcntl(terminal->pvt->pty_master, F_GETFL);
+               fcntl(terminal->pvt->pty_master, F_SETFL, i | O_NONBLOCK);
+
+               /* Open a channel to listen for input on. */
+               terminal->pvt->pty_input =
+                       g_io_channel_unix_new(terminal->pvt->pty_master);
+               terminal->pvt->pty_output = NULL;
+               g_io_add_watch_full(terminal->pvt->pty_input,
+                                   G_PRIORITY_LOW,
+                                   G_IO_IN | G_IO_HUP,
+                                   vte_terminal_io_read,
+                                   terminal,
+                                   NULL);
+               g_io_channel_unref(terminal->pvt->pty_input);
+       }
 
-       /* Open a channel to listen for input on. */
-       terminal->pvt->pty_input =
-               g_io_channel_unix_new(terminal->pvt->pty_master);
-       terminal->pvt->pty_output = NULL;
-       g_io_add_watch_full(terminal->pvt->pty_input,
-                           G_PRIORITY_LOW,
-                           G_IO_IN | G_IO_HUP,
-                           vte_terminal_io_read,
-                           terminal,
-                           NULL);
-       g_io_channel_unref(terminal->pvt->pty_input);
+       /* Return the pid to the caller. */
+       return pid;
 }
 
 /* Handle an EOF from the client. */
@@ -3233,6 +3285,8 @@ vte_terminal_process_incoming(gpointer data)
 {
        GValueArray *params = NULL;
        VteTerminal *terminal;
+       VteScreen *screen;
+       long cursor_row, cursor_col;
        GtkWidget *widget;
        GdkRectangle rect;
        char *ibuf, *obuf, *obufptr, *ubuf, *ubufptr;
@@ -3317,6 +3371,11 @@ vte_terminal_process_incoming(gpointer data)
        wcount = (obuf - obufptr) / sizeof(wchar_t);
        wbuf = (wchar_t*) obufptr;
 
+       /* Save the current cursor position. */
+       screen = terminal->pvt->screen;
+       cursor_row = screen->cursor_current.row;
+       cursor_col = screen->cursor_current.col;
+
        /* Try initial substrings. */
        start = 0;
        inserted = leftovers = FALSE;
@@ -3476,8 +3535,9 @@ vte_terminal_process_incoming(gpointer data)
        if (inserted) {
                /* Keep the cursor on-screen if we scroll on output, or if
                 * we're currently at the bottom of the buffer. */
+               vte_terminal_scroll_insertion(terminal);
                if (terminal->pvt->scroll_on_output || bottom) {
-                       vte_terminal_scroll_on_something(terminal);
+                       vte_terminal_scroll_to_bottom(terminal);
                }
 
                /* The cursor moved, so force it to be redrawn. */
@@ -3487,6 +3547,16 @@ vte_terminal_process_incoming(gpointer data)
                vte_terminal_deselect_all(terminal);
        }
 
+       if (inserted || (screen != terminal->pvt->screen)) {
+               /* Signal that the visible contents changed. */
+               vte_terminal_emit_contents_changed(terminal);
+       }
+       if ((cursor_row != terminal->pvt->screen->cursor_current.row) ||
+           (cursor_col != terminal->pvt->screen->cursor_current.col)) {
+               /* Signal that the cursor moved. */
+               vte_terminal_emit_cursor_moved(terminal);
+       }
+
        /* Tell the input method where the cursor is. */
        rect.x = terminal->pvt->screen->cursor_current.col *
                 terminal->char_width;
@@ -3501,12 +3571,14 @@ vte_terminal_process_incoming(gpointer data)
                terminal->pvt->n_incoming);
 #endif
        terminal->pvt->processing = again && (terminal->pvt->n_incoming > 0);
+       if (terminal->pvt->processing == FALSE) {
+               terminal->pvt->processing_tag = -1;
+       }
 #ifdef VTE_DEBUG
        if (terminal->pvt->processing) {
                fprintf(stderr, "Leaving processing handler on.\n");
        } else {
                fprintf(stderr, "Turning processing handler off.\n");
-               terminal->pvt->processing_tag = -1;
        }
 #endif
        return terminal->pvt->processing;
@@ -3921,6 +3993,11 @@ vte_terminal_key_press(GtkWidget *widget, GdkEventKey *event)
                                        &modifiers) == FALSE) {
                        modifiers = 0;
                }
+#ifdef VTE_DEBUG
+               fprintf(stderr, "Keypress, modifiers=%d, keyval=%d, "
+                       "string=`%s'.\n", modifiers, event->keyval,
+                       event->string);
+#endif
                /* Map the key to a sequence name if we can. */
                switch (event->keyval) {
                        case GDK_BackSpace:
@@ -3974,10 +4051,10 @@ vte_terminal_key_press(GtkWidget *widget, GdkEventKey *event)
                                special = "k0";
                                break;
                        case GDK_F11:
-                               special = "k;";
+                               special = "F1";
                                break;
                        case GDK_F12:
-                               special = "F1";
+                               special = "F2";
                                break;
                        /* Cursor keys. */
                        case GDK_KP_Up:
@@ -3996,6 +4073,7 @@ vte_terminal_key_press(GtkWidget *widget, GdkEventKey *event)
                        case GDK_Right:
                                special = "kr";
                                break;
+                       case GDK_KP_Page_Up:
                        case GDK_Page_Up:
                                if (modifiers & GDK_SHIFT_MASK) {
                                        vte_terminal_scroll_pages(terminal, -1);
@@ -4004,6 +4082,7 @@ vte_terminal_key_press(GtkWidget *widget, GdkEventKey *event)
                                        special = "kP";
                                }
                                break;
+                       case GDK_KP_Page_Down:
                        case GDK_Page_Down:
                                if (modifiers & GDK_SHIFT_MASK) {
                                        vte_terminal_scroll_pages(terminal, 1);
@@ -4012,6 +4091,7 @@ vte_terminal_key_press(GtkWidget *widget, GdkEventKey *event)
                                        special = "kN";
                                }
                                break;
+                       case GDK_KP_Tab:
                        case GDK_Tab:
                                if (modifiers & GDK_SHIFT_MASK) {
                                        special = "kB";
@@ -4020,6 +4100,17 @@ vte_terminal_key_press(GtkWidget *widget, GdkEventKey *event)
                                        normal_length = 1;
                                }
                                break;
+                       case GDK_KP_Space:
+                       case GDK_space:
+                               if (modifiers & GDK_CONTROL_MASK) {
+                                       /* Ctrl-Space sends NUL?!?  Madness! */
+                                       normal = g_strdup("");
+                                       normal_length = 1;
+                               } else {
+                                       normal = g_strdup(" ");
+                                       normal_length = 1;
+                               }
+                               break;
                        /* The default is to just send the string. */
                        default:
                                if (event->string != NULL) {
@@ -4068,46 +4159,56 @@ vte_terminal_key_press(GtkWidget *widget, GdkEventKey *event)
                }
                /* Keep the cursor on-screen. */
                if (!scrolled && terminal->pvt->scroll_on_keystroke) {
-                       vte_terminal_scroll_on_something(terminal);
+                       vte_terminal_scroll_to_bottom(terminal);
                }
                return TRUE;
        }
        return FALSE;
 }
 
-/* Classify a wide character with some value, useful only for comparing
- * for equality. */
-static guint
-vte_charclass(wchar_t c)
+/* Check if a particular character is part of a "word" or not. */
+gboolean
+vte_terminal_is_word_char(VteTerminal *terminal, gunichar c)
 {
-       if (iswalnum(c)) {
-               return 1;
-       }
-       if (iswpunct(c)) {
-               return 2;
+       int i;
+       VteWordCharRange *range;
+       g_return_val_if_fail(VTE_IS_TERMINAL(terminal), FALSE);
+       if (terminal->pvt->word_chars == NULL) {
+               return FALSE;
        }
-       if (iswblank(c)) {
-               return 3;
+       /* FIXME: if a gunichar isn't a wchar_t, we're probably screwed, so
+        * should we convert from UCS-4 to WCHAR_T or something here?  (Is a
+        * gunichar even a UCS-4 character)?  Or should we convert to UTF-8
+        * and then to WCHAR_T?  Aaaargh. */
+       for (i = 0; i < terminal->pvt->word_chars->len; i++) {
+               range = &g_array_index(terminal->pvt->word_chars,
+                                      VteWordCharRange,
+                                      i);
+               if ((c >= range->start) && (c <= range->end)) {
+                       return TRUE;
+               }
        }
-       return 0;
+       return FALSE;
 }
 
-/* Check if the characters in the given block are in the same class. */
+/* Check if the characters in the given block are in the same class (word vs.
+ * non-word characters). */
 static gboolean
 vte_uniform_class(VteTerminal *terminal, long row, long scol, long ecol)
 {
        struct vte_charcell *pcell = NULL;
        long col;
-       guint cclass;
+       gboolean word_char;
        g_return_val_if_fail(VTE_IS_TERMINAL(terminal), FALSE);
        if ((pcell = vte_terminal_find_charcell(terminal, row, scol)) != NULL) {
-               cclass = vte_charclass(pcell->c);
-               for (col = scol; col <= ecol; col++) {
+               word_char = vte_terminal_is_word_char(terminal, pcell->c);
+               for (col = scol + 1; col <= ecol; col++) {
                        pcell = vte_terminal_find_charcell(terminal, row, col);
                        if (pcell == NULL) {
                                return FALSE;
                        }
-                       if (cclass != vte_charclass(pcell->c)) {
+                       if (word_char != vte_terminal_is_word_char(terminal,
+                                                                  pcell->c)) {
                                return FALSE;
                        }
                }
@@ -4370,7 +4471,7 @@ vte_terminal_copy(VteTerminal *terminal, GdkAtom board)
        GtkClipboard *clipboard;
        GtkWidget *widget;
        long x, y;
-       struct _VteScreen *screen;
+       VteScreen *screen;
        struct vte_charcell *pcell;
        wchar_t *buffer;
        size_t length;
@@ -5015,6 +5116,13 @@ vte_terminal_set_font_from_string(VteTerminal *terminal, const char *name)
        pango_font_description_free(font_desc);
 }
 
+const PangoFontDescription *
+vte_terminal_get_font(VteTerminal *terminal)
+{
+       g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
+       return terminal->pvt->fontdesc;
+}
+
 /* A comparison function which helps sort quarks. */
 static gint
 vte_compare_direct(gconstpointer a, gconstpointer b)
@@ -5069,7 +5177,7 @@ vte_handle_scroll(VteTerminal *terminal)
 {
        long dy, adj;
        GtkWidget *widget;
-       struct _VteScreen *screen;
+       VteScreen *screen;
        /* Sanity checks. */
        g_return_if_fail(GTK_IS_WIDGET(terminal));
        widget = GTK_WIDGET(terminal);
@@ -5260,7 +5368,7 @@ vte_terminal_reset_rowdata(VteRing **ring, long lines)
  * We need to create a new psuedo-terminal pair, read in the termcap file, and
  * set ourselves up to do the interpretation of sequences. */
 static void
-vte_terminal_init(VteTerminal *terminal)
+vte_terminal_init(VteTerminal *terminal, gpointer *klass)
 {
        struct _VteTerminalPrivate *pvt;
        struct passwd *pwd;
@@ -5293,6 +5401,8 @@ vte_terminal_init(VteTerminal *terminal)
        pvt->n_outgoing = 0;
        pvt->keypad = VTE_KEYPAD_NORMAL;
 
+       vte_terminal_set_word_chars(terminal, "-a-zA-Z0-9");
+
        pvt->scroll_on_output = FALSE;
        pvt->scroll_on_keystroke = TRUE;
        pvt->scrollback_lines = 0;
@@ -5627,6 +5737,9 @@ vte_terminal_finalize(GObject *object)
                terminal->pvt->bg_transparent_image = NULL;
        }
 
+       /* Free the word chars array. */
+       g_array_free(terminal->pvt->word_chars, FALSE);
+
        /* Call the inherited finalize() method. */
        if (G_OBJECT_CLASS(widget_class)->finalize) {
                (G_OBJECT_CLASS(widget_class))->finalize(object);
@@ -5709,10 +5822,41 @@ vte_terminal_realize(GtkWidget *widget)
        gtk_widget_grab_focus(widget);
 }
 
+static void
+vte_terminal_determine_colors(VteTerminal *terminal,
+                             const struct vte_charcell *cell, gboolean reverse,
+                             int *fore, int *back)
+{
+       /* Determine what the foreground and background colors for rendering
+        * text should be. */
+       if (reverse ^ (cell && cell->reverse)) {
+               *fore = cell ? cell->back : VTE_DEF_BG;
+               *back = cell ? cell->fore : VTE_DEF_FG;
+       } else {
+               *fore = cell ? cell->fore : VTE_DEF_FG;
+               *back = cell ? cell->back : VTE_DEF_BG;
+       }
+
+       /* Handle invisible, bold, and standout text by adjusting colors. */
+       if (cell && cell->invisible) {
+               *fore = *back;
+       }
+       if (cell && cell->bold) {
+               if ((*fore != VTE_DEF_FG) && (*fore != VTE_DEF_BG)) {
+                       *fore += 8;
+               }
+       }
+       if (cell && cell->standout) {
+               if ((*back != VTE_DEF_FG) && (*back != VTE_DEF_BG)) {
+                       *back += 8;
+               }
+       }
+}
+
 /* Draw a particular character on the screen. */
 static void
 vte_terminal_draw_char(VteTerminal *terminal,
-                      struct _VteScreen *screen,
+                      VteScreen *screen,
                       struct vte_charcell *cell,
                       long col,
                       long row,
@@ -5759,28 +5903,7 @@ vte_terminal_draw_char(VteTerminal *terminal,
        reverse = cell && cell->reverse;
        reverse = reverse ^ vte_cell_is_selected(terminal, row, col);
        reverse = reverse || cursor;
-       if (reverse) {
-               fore = cell ? cell->back : VTE_DEF_BG;
-               back = cell ? cell->fore : VTE_DEF_FG;
-       } else {
-               fore = cell ? cell->fore : VTE_DEF_FG;
-               back = cell ? cell->back : VTE_DEF_BG;
-       }
-
-       /* Handle invisible, bold, and standout text by adjusting colors. */
-       if (cell && cell->invisible) {
-               fore = back;
-       }
-       if (cell && cell->bold) {
-               if ((fore != VTE_DEF_FG) && (fore != VTE_DEF_BG)) {
-                       fore += 8;
-               }
-       }
-       if (cell && cell->standout) {
-               if ((back != VTE_DEF_FG) && (back != VTE_DEF_BG)) {
-                       back += 8;
-               }
-       }
+       vte_terminal_determine_colors(terminal, cell, reverse, &fore, &back);
 
        /* Paint the background for the cell. */
        if ((back != VTE_DEF_BG) && GTK_WIDGET_REALIZED(GTK_WIDGET(terminal))) {
@@ -6150,7 +6273,7 @@ vte_terminal_paint(GtkWidget *widget, GdkRectangle *area)
        VteTerminal *terminal = NULL;
        GtkSettings *settings = NULL;
        PangoLayout *layout = NULL;
-       struct _VteScreen *screen;
+       VteScreen *screen;
        Display *display;
        GdkDrawable *gdrawable;
        Drawable drawable;
@@ -6520,6 +6643,17 @@ vte_terminal_scroll(GtkWidget *widget, GdkEventScroll *event)
        return TRUE;
 }
 
+/* Create a new accessible object associated with ourselves, and return
+ * it to the caller. */
+static AtkObject *
+vte_terminal_get_accessible(GtkWidget *widget)
+{
+       AtkObject *access;
+       g_return_val_if_fail(VTE_IS_TERMINAL(widget), NULL);
+       access = vte_terminal_accessible_new(VTE_TERMINAL(widget));
+       return access;
+}
+
 /* Initialize methods. */
 static void
 vte_terminal_class_init(VteTerminalClass *klass, gconstpointer data)
@@ -6544,6 +6678,7 @@ vte_terminal_class_init(VteTerminalClass *klass, gconstpointer data)
        widget_class->unrealize = vte_terminal_unrealize;
        widget_class->size_request = vte_terminal_size_request;
        widget_class->size_allocate = vte_terminal_size_allocate;
+       widget_class->get_accessible = vte_terminal_get_accessible;
        
        klass->eof_signal =
                g_signal_new("eof",
@@ -6590,6 +6725,24 @@ vte_terminal_class_init(VteTerminalClass *klass, gconstpointer data)
                              NULL,
                              _vte_marshal_VOID__VOID,
                              G_TYPE_NONE, 0);
+       klass->contents_changed_signal =
+               g_signal_new("contents_changed",
+                            G_OBJECT_CLASS_TYPE(klass),
+                            G_SIGNAL_RUN_LAST,
+                            0,
+                            NULL,
+                            NULL,
+                            _vte_marshal_VOID__VOID,
+                            G_TYPE_NONE, 0);
+       klass->cursor_moved_signal =
+               g_signal_new("cursor_moved",
+                            G_OBJECT_CLASS_TYPE(klass),
+                            G_SIGNAL_RUN_LAST,
+                            0,
+                            NULL,
+                            NULL,
+                            _vte_marshal_VOID__VOID,
+                            G_TYPE_NONE, 0);
 }
 
 GtkType
@@ -7110,7 +7263,7 @@ void
 vte_terminal_set_scrollback_lines(VteTerminal *terminal, long lines)
 {
        long old_delta = 0, new_delta = 0, delta;
-       struct _VteScreen *screens[2];
+       VteScreen *screens[2];
        int i;
 
        g_return_if_fail(VTE_IS_TERMINAL(terminal));
@@ -7150,3 +7303,171 @@ vte_terminal_set_scrollback_lines(VteTerminal *terminal, long lines)
                             0, terminal->column_count,
                             0, terminal->row_count);
 }
+
+/* Get a snapshot of what's in the visible part of the window. */
+VteTerminalSnapshot *
+vte_terminal_get_snapshot(VteTerminal *terminal)
+{
+       VteTerminalSnapshot *ret;
+       int row, column, x;
+       struct vte_charcell *cell;
+       int fore, back;
+
+       g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
+
+       ret = g_malloc0(sizeof(VteTerminalSnapshot));
+
+       /* Save the cursor position and visibility. */
+       ret->cursor.x = terminal->pvt->screen->cursor_current.col;
+       ret->cursor.y = terminal->pvt->screen->cursor_current.row -
+                       terminal->pvt->screen->insert_delta;
+       ret->cursor_visible = terminal->pvt->screen->cursor_visible;
+
+       /* Save the window size. */
+       ret->rows = terminal->row_count;
+       ret->columns = terminal->column_count;
+
+       /* Save the window contents. */
+       ret->contents = g_malloc(sizeof(struct VteTerminalSnapshotCell*) *
+                                (ret->rows + 1));
+       for (row = 0; row < ret->rows; row++) {
+               ret->contents[row] = g_malloc(sizeof(struct VteTerminalSnapshotCell) *
+                                             (ret->columns + 1));
+               column = x = 0;
+               while (column < ret->columns) {
+                       cell = vte_terminal_find_charcell(terminal,
+                                                         row + terminal->pvt->screen->insert_delta,
+                                                         x++);
+                       if (cell == NULL) {
+                               break;
+                       }
+                       if (cell->columns == 0) {
+                               continue;
+                       }
+
+                       /* Get the text. FIXME: convert from wchar_t to
+                        * gunichar when they're not interchangeable. */
+                       ret->contents[row][column].c = cell->c;
+
+                       /* Get text attributes which aren't represented as
+                        * colors. */
+                       ret->contents[row][column].attributes.underline =
+                               cell->underline;
+                       ret->contents[row][column].attributes.alternate =
+                               cell->alternate;
+
+                       /* Get text colors. */
+                       vte_terminal_determine_colors(terminal, cell, FALSE,
+                                                     &fore, &back);
+
+                       ret->contents[row][column].attributes.foreground.red =
+                               terminal->pvt->palette[fore].red;
+                       ret->contents[row][column].attributes.foreground.green =
+                               terminal->pvt->palette[fore].green;
+                       ret->contents[row][column].attributes.foreground.blue =
+                               terminal->pvt->palette[fore].blue;
+
+                       ret->contents[row][column].attributes.background.red =
+                               terminal->pvt->palette[back].red;
+                       ret->contents[row][column].attributes.background.green =
+                               terminal->pvt->palette[back].green;
+                       ret->contents[row][column].attributes.background.blue =
+                               terminal->pvt->palette[back].blue;
+               }
+       }
+       ret->contents[row] = NULL;
+
+       return ret;
+}
+
+void
+vte_terminal_free_snapshot(VteTerminalSnapshot *snapshot)
+{
+       int row;
+       g_return_if_fail(snapshot != NULL);
+       for (row = 0; snapshot->contents[row] != NULL; row++) {
+               memset(snapshot->contents[row], 0,
+                      sizeof(snapshot->contents[row][0]) * snapshot->columns);
+               g_free(snapshot->contents[row]);
+       }
+       g_free(snapshot->contents);
+       memset(snapshot, 0, sizeof(*snapshot));
+       g_free(snapshot);
+}
+
+/* Set the list of characters we consider to be parts of words.  Everything
+ * else will be a non-word character, and we'll use transitions between the
+ * two sets when doing selection-by-words. */
+void
+vte_terminal_set_word_chars(VteTerminal *terminal, const char *spec)
+{
+       iconv_t conv;
+       wchar_t *wbuf;
+       char *ibuf, *ibufptr, *obuf, *obufptr;
+       size_t ilen, olen;
+       VteWordCharRange range;
+       int i;
+
+       g_return_if_fail(VTE_IS_TERMINAL(terminal));
+       /* Allocate a new range array. */
+       if (terminal->pvt->word_chars != NULL) {
+               g_array_free(terminal->pvt->word_chars, FALSE);
+       }
+       terminal->pvt->word_chars = g_array_new(FALSE, TRUE,
+                                               sizeof(VteWordCharRange));
+       /* Convert the spec from UTF-8 to a string of wchar_t. */
+       conv = iconv_open("WCHAR_T", "UTF-8");
+       if (conv == NULL) {
+               /* Aaargh.  We're screwed. */
+               g_warning("iconv_open() failed setting word characters");
+               return;
+       }
+       ilen = strlen(spec);
+       ibuf = ibufptr = g_strdup(spec);
+       olen = (ilen + 1) * sizeof(wchar_t);
+       obuf = obufptr = g_malloc0(sizeof(wchar_t) * (strlen(spec) + 1));
+       wbuf = (wchar_t*) obuf;
+       wbuf[ilen] = '\0';
+       iconv(conv, &ibuf, &ilen, &obuf, &olen);
+       for (i = 0; i < ((obuf - obufptr) / sizeof(wchar_t)); i++) {
+               /* The hyphen character. */
+               if (wbuf[i] == '-') {
+                       range.start = wbuf[i];
+                       range.end = wbuf[i];
+                       g_array_append_val(terminal->pvt->word_chars, range);
+#ifdef VTE_DEBUG
+                       fprintf(stderr, "Word charset includes hyphen.\n");
+#endif
+                       continue;
+               }
+               /* A single character, not the start of a range. */
+               if ((wbuf[i] != '-') && (wbuf[i + 1] != '-')) {
+                       range.start = wbuf[i];
+                       range.end = wbuf[i];
+                       g_array_append_val(terminal->pvt->word_chars, range);
+#ifdef VTE_DEBUG
+                       fprintf(stderr, "Word charset includes `%lc'.\n",
+                               (wint_t) wbuf[i]);
+#endif
+                       continue;
+               }
+               /* The start of a range. */
+               if ((wbuf[i] != '-') &&
+                   (wbuf[i + 1] == '-') &&
+                   (wbuf[i + 2] != '-') &&
+                   (wbuf[i + 2] != 0)) {
+                       range.start = wbuf[i];
+                       range.end = wbuf[i + 2];
+                       g_array_append_val(terminal->pvt->word_chars, range);
+#ifdef VTE_DEBUG
+                       fprintf(stderr, "Word charset includes range from "
+                               "`%lc' to `%lc'.\n", (wint_t) wbuf[i],
+                               (wint_t) wbuf[i + 2]);
+#endif
+                       i += 2;
+                       continue;
+               }
+       }
+       g_free(ibufptr);
+       g_free(obufptr);
+}
index b5b8d76..0cc263f 100644 (file)
--- a/src/vte.h
+++ b/src/vte.h
@@ -68,8 +68,30 @@ typedef struct _VteTerminalClass {
        guint window_title_changed_signal;
        guint icon_title_changed_signal;
        guint selection_changed_signal;
+       guint contents_changed_signal;
+       guint cursor_moved_signal;
 } VteTerminalClass;
 
+/* A snapshot of the screen contents. */
+typedef struct _VteTerminalSnapshot {
+       struct {
+               int x, y;                       /* Location of the cursor. */
+       } cursor;
+       int rows, columns;                      /* Size of the screen[shot]. */
+       gboolean cursor_visible;
+       struct VteTerminalSnapshotCell {
+               gunichar c;                     /* The character itself. */
+               struct {
+                       /* Colors of this character. */
+                       GdkColor foreground, background;
+                       /* Is it underlined? */
+                       gboolean underline;
+                       /* Is it a graphic character? */
+                       gboolean alternate;
+               } attributes;
+       } **contents;
+} VteTerminalSnapshot;
+
 /* The widget's type. */
 GtkType vte_terminal_get_type(void);
 
@@ -88,22 +110,24 @@ GtkType vte_terminal_get_type(void);
 
 
 GtkWidget *vte_terminal_new(void);
-void vte_terminal_fork_command(VteTerminal *terminal,
-                              const char *command,
-                              const char **argv);
+pid_t vte_terminal_fork_command(VteTerminal *terminal,
+                               const char *command,
+                               const char **argv);
 void vte_terminal_feed(VteTerminal *terminal,
                       const char *data,
                       size_t length);
 void vte_terminal_feed_child(VteTerminal *terminal,
                             const char *data,
                             size_t length);
+
+void vte_terminal_copy_clipboard(VteTerminal *terminal);
+void vte_terminal_paste_clipboard(VteTerminal *terminal);
+
 void vte_terminal_set_size(VteTerminal *terminal, long columns, long rows);
 void vte_terminal_set_audible_bell(VteTerminal *terminal, gboolean audible);
 void vte_terminal_set_scroll_on_output(VteTerminal *terminal, gboolean scroll);
 void vte_terminal_set_scroll_on_keystroke(VteTerminal *terminal,
                                          gboolean scroll);
-void vte_terminal_copy_clipboard(VteTerminal *terminal);
-void vte_terminal_paste_clipboard(VteTerminal *terminal);
 void vte_terminal_set_colors(VteTerminal *terminal,
                             const GdkColor *foreground,
                             const GdkColor *background,
@@ -118,14 +142,21 @@ void vte_terminal_set_background_saturation(VteTerminal *terminal,
 void vte_terminal_set_background_transparent(VteTerminal *terminal,
                                             gboolean transparent);
 void vte_terminal_set_cursor_blinks(VteTerminal *terminal, gboolean blink);
-gboolean vte_terminal_get_has_selection(VteTerminal *terminal);
-gboolean vte_terminal_get_using_xft(VteTerminal *terminal);
+void vte_terminal_set_scrollback_lines(VteTerminal *terminal, long lines);
+void vte_terminal_set_word_chars(VteTerminal *terminal, const char *spec);
 void vte_terminal_im_append_menuitems(VteTerminal *terminal,
                                      GtkMenuShell *menushell);
 void vte_terminal_set_font(VteTerminal *terminal,
                            const PangoFontDescription *font_desc);
 void vte_terminal_set_font_from_string(VteTerminal *terminal, const char *name);
-void vte_terminal_set_scrollback_lines(VteTerminal *terminal, long lines);
+
+gboolean vte_terminal_get_has_selection(VteTerminal *terminal);
+gboolean vte_terminal_get_using_xft(VteTerminal *terminal);
+gboolean vte_terminal_is_word_char(VteTerminal *terminal, gunichar c);
+const PangoFontDescription *vte_terminal_get_font(VteTerminal *terminal);
+
+VteTerminalSnapshot *vte_terminal_get_snapshot(VteTerminal *terminal);
+void vte_terminal_free_snapshot(VteTerminalSnapshot *snapshot);
 
 G_END_DECLS
 
diff --git a/src/vteaccess.c b/src/vteaccess.c
new file mode 100644 (file)
index 0000000..6d1a7d4
--- /dev/null
@@ -0,0 +1,675 @@
+/*
+ * Copyright (C) 2002 Red Hat, Inc.
+ *
+ * This is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* VTE accessibility object.  Based heavily on inspection of libzvt's
+ * accessibility code. */
+
+#include "../config.h"
+#include <iconv.h>
+#include <atk/atk.h>
+#include <gtk/gtk.h>
+#include "vte.h"
+#include "vteaccess.h"
+
+#define VTE_TERMINAL_ACCESSIBLE_PRIVATE_DATA "VteTerminalAccessiblePrivateData"
+typedef struct _VteTerminalAccessiblePrivate {
+       gboolean snapshot_invalid;
+       VteTerminalSnapshot *snapshot;
+       GArray *snapshot_cells;
+       GArray *snapshot_linebreaks;
+       gint snapshot_caret;
+} VteTerminalAccessiblePrivate;
+
+static VteTerminalAccessiblePrivate *
+vte_terminal_accessible_new_private_data(void)
+{
+       VteTerminalAccessiblePrivate *priv;
+       priv = g_malloc0(sizeof(*priv));
+       priv->snapshot = NULL;
+       priv->snapshot_cells = NULL;
+       priv->snapshot_linebreaks = NULL;
+       priv->snapshot_caret = 0;
+       priv->snapshot_invalid = TRUE;
+       return priv;
+}
+
+static void
+vte_terminal_accessible_update_private_data_if_needed(AtkObject *text)
+{
+       VteTerminal *terminal;
+       VteTerminalAccessiblePrivate *priv;
+       struct VteTerminalSnapshotCell cell;
+       int row, col, i, caret;
+
+       g_return_if_fail(VTE_IS_TERMINAL_ACCESSIBLE(text));
+
+       /* Retrieve the private data structure. */
+       priv = g_object_get_data(G_OBJECT(text),
+                                VTE_TERMINAL_ACCESSIBLE_PRIVATE_DATA);
+       g_return_if_fail(priv != NULL);
+
+       /* If nothing's changed, just return immediately. */
+       if (priv->snapshot_invalid == FALSE) {
+               return;
+       }
+
+       /* Free the possibly-outdated snapshot. */
+       if (priv->snapshot != NULL) {
+               vte_terminal_free_snapshot(priv->snapshot);
+               priv->snapshot = NULL;
+       }
+       if (priv->snapshot_cells != NULL) {
+               g_array_free(priv->snapshot_cells, FALSE);
+               priv->snapshot_cells = NULL;
+       }
+       if (priv->snapshot_linebreaks != NULL) {
+               g_array_free(priv->snapshot_linebreaks, FALSE);
+               priv->snapshot_linebreaks = NULL;
+       }
+       priv->snapshot_caret = 0;
+
+       /* Get a new snapshot, and munge it into something that might be
+        * mistaken for a continuous-text display widget. */
+       terminal = VTE_TERMINAL((GTK_ACCESSIBLE(text))->widget);
+       priv->snapshot = vte_terminal_get_snapshot(terminal);
+       if (priv->snapshot == NULL) {
+               /* Aaargh!  We're screwed. */
+               return;
+       }
+
+       /* Get the addresses of each of the cells, and add them to a linear
+        * array of characters, tracking where line breaks occur, and setting
+        * the caret to point at the location where the cursor is. */
+       priv->snapshot_cells = g_array_new(FALSE, TRUE, sizeof(cell));
+       priv->snapshot_linebreaks = g_array_new(FALSE, TRUE, sizeof(int));
+       caret = -1;
+       for (row = 0; priv->snapshot->contents[row] != NULL; row++) {
+               for (col = 0;
+                    priv->snapshot->contents[row][col].c != 0;
+                    col++) {
+                       if ((row == priv->snapshot->cursor.y) &&
+                           (col == priv->snapshot->cursor.x)) {
+                               caret = priv->snapshot_cells->len;
+                       }
+                       cell = priv->snapshot->contents[row][col];
+                       g_array_append_val(priv->snapshot_cells, cell);
+
+               }
+               if ((row == priv->snapshot->cursor.y) && (caret == -1)) {
+                       caret = priv->snapshot_cells->len;
+               }
+               i = row;
+               g_array_append_val(priv->snapshot_linebreaks, i);
+       }
+       if (caret == -1) {
+               caret = priv->snapshot_cells->len;
+       }
+       priv->snapshot_caret = caret;
+}
+
+static void
+vte_terminal_accessible_free_private_data(VteTerminalAccessiblePrivate *priv)
+{
+       g_return_if_fail(priv != NULL);
+       if (priv->snapshot != NULL) {
+               vte_terminal_free_snapshot(priv->snapshot);
+               priv->snapshot = NULL;
+       }
+       if (priv->snapshot_cells != NULL) {
+               g_array_free(priv->snapshot_cells, FALSE);
+               priv->snapshot_cells = NULL;
+       }
+       if (priv->snapshot_linebreaks != NULL) {
+               g_array_free(priv->snapshot_linebreaks, FALSE);
+               priv->snapshot_linebreaks = NULL;
+       }
+       g_free(priv);
+}
+
+/* A signal handler to catch "contents_changed" and "cursor_moved" signals. */
+static void
+vte_terminal_accessible_invalidate(VteTerminal *terminal, gpointer data)
+{
+       VteTerminalAccessiblePrivate *priv;
+
+       g_return_if_fail(VTE_IS_TERMINAL_ACCESSIBLE(data));
+       g_return_if_fail(G_IS_OBJECT(data));
+
+       priv = g_object_get_data(G_OBJECT(data),
+                                VTE_TERMINAL_ACCESSIBLE_PRIVATE_DATA);
+       g_return_if_fail(priv != NULL);
+
+       priv->snapshot_invalid = TRUE;
+}
+
+AtkObject *
+vte_terminal_accessible_new(VteTerminal *terminal)
+{
+       GtkAccessible *access;
+       g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
+       access = GTK_ACCESSIBLE(g_object_new(VTE_TYPE_TERMINAL_ACCESSIBLE,
+                                            NULL));
+       atk_object_initialize(ATK_OBJECT(access), G_OBJECT(terminal));
+       access->widget = GTK_WIDGET(terminal);
+
+       g_object_set_data(G_OBJECT(access),
+                         VTE_TERMINAL_ACCESSIBLE_PRIVATE_DATA,
+                         vte_terminal_accessible_new_private_data());
+       g_signal_connect(G_OBJECT(terminal), "contents_changed",
+                        GTK_SIGNAL_FUNC(vte_terminal_accessible_invalidate),
+                        access);
+       g_signal_connect(G_OBJECT(terminal), "cursor_moved",
+                        GTK_SIGNAL_FUNC(vte_terminal_accessible_invalidate),
+                        access);
+
+       return ATK_OBJECT(access);
+}
+
+static gchar *
+vte_terminal_accessible_get_text(AtkText *text,
+                                gint start_offset, gint end_offset)
+{
+       VteTerminalAccessiblePrivate *priv;
+       gchar *buf, *p;
+       int i;
+
+       vte_terminal_accessible_update_private_data_if_needed(ATK_OBJECT(text));
+
+       priv = g_object_get_data(G_OBJECT(text),
+                                VTE_TERMINAL_ACCESSIBLE_PRIVATE_DATA);
+       g_return_val_if_fail(VTE_IS_TERMINAL_ACCESSIBLE(text), NULL);
+
+       /* If the requested area is after all of the text, just return an
+        * empty string. */
+       if (start_offset >= priv->snapshot_cells->len) {
+               return g_strdup("");
+       }
+
+       /* Allocate space to hold as many UTF-8 characters as we have
+        * unicode characters. */
+       p = buf = g_malloc((end_offset - start_offset) * VTE_UTF8_BPC + 1);
+       for (i = start_offset; i < end_offset; i++) {
+               p += g_unichar_to_utf8(g_array_index(priv->snapshot_cells,
+                                                    struct VteTerminalSnapshotCell,
+                                                    i).c,
+                                      p);
+       }
+       *p = '\0';
+       return buf;
+}
+
+static gchar *
+vte_terminal_accessible_get_text_somewhere(AtkText *text,
+                                          gint offset,
+                                          AtkTextBoundary boundary_type,
+                                          gint direction,
+                                          gint *start_offset,
+                                          gint *end_offset)
+{
+       VteTerminalAccessiblePrivate *priv;
+       gunichar c;
+       gboolean word, in_word;
+       int i, line;
+
+       vte_terminal_accessible_update_private_data_if_needed(ATK_OBJECT(text));
+
+       priv = g_object_get_data(G_OBJECT(text),
+                                VTE_TERMINAL_ACCESSIBLE_PRIVATE_DATA);
+
+       switch (boundary_type) {
+               case ATK_TEXT_BOUNDARY_CHAR:
+                       /* We're either looking at the character at this
+                        * position, the one before it, or the one after it. */
+                       offset += direction;
+                       *start_offset = MAX(offset, 0);
+                       *end_offset = MIN(offset + 1,
+                                         priv->snapshot_cells->len);
+                       break;
+               case ATK_TEXT_BOUNDARY_WORD_START:
+               case ATK_TEXT_BOUNDARY_WORD_END:
+                       /* Find the wordstart before the requested point. */
+                       c = g_array_index(priv->snapshot_cells,
+                                         struct VteTerminalSnapshotCell,
+                                         offset).c;
+                       word = in_word = !g_unichar_isspace(c);
+                       *start_offset = offset;
+                       for (i = offset; i >= 0; i--) {
+                               c = g_array_index(priv->snapshot_cells,
+                                                 struct VteTerminalSnapshotCell,
+                                                 i).c;
+                               if (word && g_unichar_isspace(c)) {
+                                       *start_offset = i + 1;
+                                       break;
+                               }
+                               if (i == 0) {
+                                       *start_offset = 0;
+                                       break;
+                               }
+                               word = g_unichar_isspace(c);
+                       }
+                       /* If we started in a word and we're looking for the
+                        * word before this one, keep searching. */
+                       if (in_word && (direction == -1)) {
+                               word = !g_unichar_isspace(c);
+                               for (i = *start_offset; i >= 0; i--) {
+                                       c = g_array_index(priv->snapshot_cells,
+                                                         struct VteTerminalSnapshotCell,
+                                                         i).c;
+                                       if (word && g_unichar_isspace(c)) {
+                                               *start_offset = i + 1;
+                                               break;
+                                       }
+                                       if (i == 0) {
+                                               *start_offset = 0;
+                                               break;
+                                       }
+                               }
+                       }
+                       /* If we're looking for the word after this one,
+                        * search forward. */
+                       if (direction == 1) {
+                               word = g_unichar_isspace(c);
+                               for (i = *start_offset; i < priv->snapshot_cells->len; i--) {
+                                       c = g_array_index(priv->snapshot_cells,
+                                                         struct VteTerminalSnapshotCell,
+                                                         i).c;
+                                       if (!word && !g_unichar_isspace(c)) {
+                                               *start_offset = i;
+                                               break;
+                                       }
+                                       if (i == priv->snapshot_cells->len - 1) {
+                                               *start_offset = i + 1;
+                                               break;
+                                       }
+                               }
+                       }
+                       /* Now find the end of this word. */
+                       word = TRUE;
+                       *end_offset = *start_offset;
+                       for (i = *start_offset; i < priv->snapshot_cells->len; i--) {
+                               c = g_array_index(priv->snapshot_cells,
+                                                 struct VteTerminalSnapshotCell,
+                                                 i).c;
+                               if (!word && !g_unichar_isspace(c)) {
+                                       *end_offset = i;
+                                       break;
+                               }
+                               if (i == priv->snapshot_cells->len - 1) {
+                                       *end_offset = i + 1;
+                                       break;
+                               }
+                       }
+                       break;
+               case ATK_TEXT_BOUNDARY_LINE_START:
+               case ATK_TEXT_BOUNDARY_LINE_END:
+                       /* Figure out which line we're on.  If the end of the
+                        * i'th line is after the offset, then i is the line
+                        * we're looking at. */
+                       line = 0;
+                       for (i = 0; i < priv->snapshot_cells->len; i++) {
+                               if (g_array_index(priv->snapshot_linebreaks,
+                                                 int, i) > offset) {
+                                       line = i;
+                                       break;
+                               }
+                       }
+                       /* Perturb the line number to handle before/at/after. */
+                       line += direction;
+                       line = MAX(0, line);
+                       line = MIN(line, priv->snapshot_linebreaks->len - 1);
+                       /* Read the offsets for this line. */
+                       if (line == 0) {
+                               *start_offset = 0;
+                       } else {
+                               *start_offset = g_array_index(priv->snapshot_linebreaks,
+                                                             int,
+                                                             line - 1);
+                       }
+                       *end_offset = g_array_index(priv->snapshot_linebreaks,
+                                                   int,
+                                                   line);
+                       break;
+               case ATK_TEXT_BOUNDARY_SENTENCE_START:
+               case ATK_TEXT_BOUNDARY_SENTENCE_END:
+                       /* This doesn't make sense.  Fall through. */
+               default:
+                       *start_offset = *end_offset = 0;
+                       break;
+       }
+       return vte_terminal_accessible_get_text(text,
+                                               *start_offset,
+                                               *end_offset);
+}
+
+static gchar *
+vte_terminal_accessible_get_text_before_offset(AtkText *text, gint offset,
+                                              AtkTextBoundary boundary_type,
+                                              gint *start_offset,
+                                              gint *end_offset)
+{
+       g_return_val_if_fail(VTE_IS_TERMINAL_ACCESSIBLE(text), NULL);
+       vte_terminal_accessible_update_private_data_if_needed(ATK_OBJECT(text));
+       return vte_terminal_accessible_get_text_somewhere(text,
+                                                         offset,
+                                                         boundary_type,
+                                                         -1,
+                                                         start_offset,
+                                                         end_offset);
+}
+
+static gchar *
+vte_terminal_accessible_get_text_after_offset(AtkText *text, gint offset,
+                                             AtkTextBoundary boundary_type,
+                                             gint *start_offset,
+                                             gint *end_offset)
+{
+       g_return_val_if_fail(VTE_IS_TERMINAL_ACCESSIBLE(text), NULL);
+       vte_terminal_accessible_update_private_data_if_needed(ATK_OBJECT(text));
+       return vte_terminal_accessible_get_text_somewhere(text,
+                                                         offset,
+                                                         boundary_type,
+                                                         1,
+                                                         start_offset,
+                                                         end_offset);
+}
+
+static gchar *
+vte_terminal_accessible_get_text_at_offset(AtkText *text, gint offset,
+                                          AtkTextBoundary boundary_type,
+                                          gint *start_offset,
+                                          gint *end_offset)
+{
+       g_return_val_if_fail(VTE_IS_TERMINAL_ACCESSIBLE(text), NULL);
+       vte_terminal_accessible_update_private_data_if_needed(ATK_OBJECT(text));
+       return vte_terminal_accessible_get_text_somewhere(text,
+                                                         offset,
+                                                         boundary_type,
+                                                         0,
+                                                         start_offset,
+                                                         end_offset);
+}
+
+static gunichar
+vte_terminal_accessible_get_character_at_offset(AtkText *text, gint offset)
+{
+       VteTerminalAccessiblePrivate *priv;
+
+       vte_terminal_accessible_update_private_data_if_needed(ATK_OBJECT(text));
+
+       priv = g_object_get_data(G_OBJECT(text),
+                                VTE_TERMINAL_ACCESSIBLE_PRIVATE_DATA);
+
+       return g_array_index(priv->snapshot_cells,
+                            struct VteTerminalSnapshotCell,
+                            offset).c;
+}
+
+static gint
+vte_terminal_accessible_get_caret_offset(AtkText *text)
+{
+       VteTerminalAccessiblePrivate *priv;
+
+       vte_terminal_accessible_update_private_data_if_needed(ATK_OBJECT(text));
+
+       priv = g_object_get_data(G_OBJECT(text),
+                                VTE_TERMINAL_ACCESSIBLE_PRIVATE_DATA);
+
+       return priv->snapshot_caret;
+}
+
+static AtkAttributeSet *
+vte_terminal_accessible_get_run_attributes(AtkText *text, gint offset,
+                                          gint *start_offset, gint *end_offset)
+{
+       g_return_val_if_fail(VTE_IS_TERMINAL_ACCESSIBLE(text), NULL);
+       vte_terminal_accessible_update_private_data_if_needed(ATK_OBJECT(text));
+       /* FIXME */
+       return NULL;
+}
+
+static AtkAttributeSet *
+vte_terminal_accessible_get_default_attributes(AtkText *text)
+{
+       g_return_val_if_fail(VTE_IS_TERMINAL_ACCESSIBLE(text), NULL);
+       vte_terminal_accessible_update_private_data_if_needed(ATK_OBJECT(text));
+       /* FIXME */
+       return NULL;
+}
+
+static void
+vte_terminal_accessible_get_character_extents(AtkText *text, gint offset,
+                                             gint *x, gint *y,
+                                             gint *width, gint *height,
+                                             AtkCoordType coords)
+{
+       g_return_if_fail(VTE_IS_TERMINAL_ACCESSIBLE(text));
+       vte_terminal_accessible_update_private_data_if_needed(ATK_OBJECT(text));
+       /* FIXME */
+}
+
+static gint
+vte_terminal_accessible_get_character_count(AtkText *text)
+{
+       VteTerminalAccessiblePrivate *priv;
+
+       vte_terminal_accessible_update_private_data_if_needed(ATK_OBJECT(text));
+
+       priv = g_object_get_data(G_OBJECT(text),
+                                VTE_TERMINAL_ACCESSIBLE_PRIVATE_DATA);
+
+       return priv->snapshot_cells->len;
+}
+
+static gint
+vte_terminal_accessible_get_offset_at_point(AtkText *text,
+                                           gint x, gint y,
+                                           AtkCoordType coords)
+{
+       g_return_val_if_fail(VTE_IS_TERMINAL_ACCESSIBLE(text), 0);
+       vte_terminal_accessible_update_private_data_if_needed(ATK_OBJECT(text));
+       /* FIXME */
+       return 0;
+}
+
+static gint
+vte_terminal_accessible_get_n_selections(AtkText *text)
+{
+       g_return_val_if_fail(VTE_IS_TERMINAL_ACCESSIBLE(text), 0);
+       vte_terminal_accessible_update_private_data_if_needed(ATK_OBJECT(text));
+       /* FIXME? */
+       return 0;
+}
+
+static gchar *
+vte_terminal_accessible_get_selection(AtkText *text, gint selection_number,
+                                     gint *start_offset, gint *end_offset)
+{
+       g_return_val_if_fail(VTE_IS_TERMINAL_ACCESSIBLE(text), NULL);
+       vte_terminal_accessible_update_private_data_if_needed(ATK_OBJECT(text));
+       /* FIXME? */
+       return NULL;
+}
+
+static gboolean
+vte_terminal_accessible_add_selection(AtkText *text,
+                                     gint start_offset, gint end_offset)
+{
+       g_return_val_if_fail(VTE_IS_TERMINAL_ACCESSIBLE(text), FALSE);
+       vte_terminal_accessible_update_private_data_if_needed(ATK_OBJECT(text));
+       /* FIXME? */
+       return FALSE;
+}
+
+static gboolean
+vte_terminal_accessible_remove_selection(AtkText *text,
+                                        gint selection_number)
+{
+       g_return_val_if_fail(VTE_IS_TERMINAL_ACCESSIBLE(text), FALSE);
+       vte_terminal_accessible_update_private_data_if_needed(ATK_OBJECT(text));
+       /* FIXME? */
+       return FALSE;
+}
+
+static gboolean
+vte_terminal_accessible_set_selection(AtkText *text, gint selection_number,
+                                     gint start_offset, gint end_offset)
+{
+       g_return_val_if_fail(VTE_IS_TERMINAL_ACCESSIBLE(text), FALSE);
+       vte_terminal_accessible_update_private_data_if_needed(ATK_OBJECT(text));
+       /* FIXME? */
+       return FALSE;
+}
+
+static gboolean
+vte_terminal_accessible_set_caret_offset(AtkText *text, gint offset)
+{
+       g_return_val_if_fail(VTE_IS_TERMINAL_ACCESSIBLE(text), FALSE);
+       vte_terminal_accessible_update_private_data_if_needed(ATK_OBJECT(text));
+       /* Whoa, very not allowed. */
+       return FALSE;
+}
+
+static void
+vte_terminal_accessible_text_changed(AtkText *text, gint position, gint length)
+{
+       g_return_if_fail(VTE_IS_TERMINAL_ACCESSIBLE(text));
+       vte_terminal_accessible_update_private_data_if_needed(ATK_OBJECT(text));
+}
+
+static void
+vte_terminal_accessible_text_caret_moved(AtkText *text, gint location)
+{
+       g_return_if_fail(VTE_IS_TERMINAL_ACCESSIBLE(text));
+       vte_terminal_accessible_update_private_data_if_needed(ATK_OBJECT(text));
+}
+
+static void
+vte_terminal_accessible_text_selection_changed(AtkText *text)
+{
+       g_return_if_fail(VTE_IS_TERMINAL_ACCESSIBLE(text));
+       vte_terminal_accessible_update_private_data_if_needed(ATK_OBJECT(text));
+}
+
+static void
+vte_terminal_accessible_text_init(gpointer iface, gpointer data)
+{
+       AtkTextIface* text;
+       g_return_if_fail(ATK_IS_TEXT(iface));
+       text = iface;
+       text->get_text = vte_terminal_accessible_get_text;
+       text->get_text_after_offset = vte_terminal_accessible_get_text_after_offset;
+       text->get_text_at_offset = vte_terminal_accessible_get_text_at_offset;
+       text->get_character_at_offset = vte_terminal_accessible_get_character_at_offset;
+       text->get_text_before_offset = vte_terminal_accessible_get_text_before_offset;
+       text->get_caret_offset = vte_terminal_accessible_get_caret_offset;
+       text->get_run_attributes = vte_terminal_accessible_get_run_attributes;
+       text->get_default_attributes = vte_terminal_accessible_get_default_attributes;
+       text->get_character_extents = vte_terminal_accessible_get_character_extents;
+       text->get_character_count = vte_terminal_accessible_get_character_count;
+       text->get_offset_at_point = vte_terminal_accessible_get_offset_at_point;
+       text->get_n_selections = vte_terminal_accessible_get_n_selections;
+       text->get_selection = vte_terminal_accessible_get_selection;
+       text->add_selection = vte_terminal_accessible_add_selection;
+       text->remove_selection = vte_terminal_accessible_remove_selection;
+       text->set_selection = vte_terminal_accessible_set_selection;
+       text->set_caret_offset = vte_terminal_accessible_set_caret_offset;
+       text->text_changed = vte_terminal_accessible_text_changed;
+       text->text_caret_moved = vte_terminal_accessible_text_caret_moved;
+       text->text_selection_changed = vte_terminal_accessible_text_selection_changed;
+}
+
+static void
+vte_terminal_accessible_text_finalize(gpointer iface, gpointer data)
+{
+       GtkAccessibleClass *accessible_class;
+       VteTerminalAccessiblePrivate *priv;
+       accessible_class = g_type_class_peek(GTK_TYPE_ACCESSIBLE); 
+
+       /* Free the private data. */
+       priv = g_object_get_data(G_OBJECT(iface),
+                                VTE_TERMINAL_ACCESSIBLE_PRIVATE_DATA);
+       if (priv) {
+               vte_terminal_accessible_free_private_data(priv);
+               g_object_set_data(G_OBJECT(iface),
+                                 VTE_TERMINAL_ACCESSIBLE_PRIVATE_DATA,
+                                 NULL);
+       }
+
+       if ((G_OBJECT_CLASS(accessible_class))->finalize) {
+               (G_OBJECT_CLASS(accessible_class))->finalize(iface);
+       }
+}
+
+static void
+vte_terminal_accessible_class_init(gpointer *klass)
+{
+        GObjectClass *gobject_class; 
+        AtkObjectClass *atk_object_class; 
+        GtkAccessibleClass *gtk_accessible_class; 
+       GInterfaceInfo text;
+
+        gobject_class = G_OBJECT_CLASS(klass); 
+        atk_object_class = ATK_OBJECT_CLASS(klass); 
+        gtk_accessible_class = GTK_ACCESSIBLE_CLASS(klass); 
+                                
+        /* Add a text interface to this object class. */
+       text.interface_init = vte_terminal_accessible_text_init;
+       text.interface_finalize = vte_terminal_accessible_text_finalize;
+       text.interface_data = NULL;
+       g_type_add_interface_static(VTE_TYPE_TERMINAL_ACCESSIBLE,
+                                   ATK_TYPE_TEXT,
+                                   &text);
+}
+
+static void
+vte_terminal_accessible_init(gpointer *instance, gpointer *klass)
+{
+       /* Mark the role this object plays. The rest of the work is handled
+        * by the AtkText interface the object class exports. */
+       atk_object_set_role(ATK_OBJECT(instance), ATK_ROLE_TERMINAL);
+}
+
+GtkType
+vte_terminal_accessible_get_type(void)
+{
+       static GtkType terminal_accessible_type = 0;
+       static const GTypeInfo terminal_accessible_info = {
+               sizeof(VteTerminalAccessibleClass),
+               (GBaseInitFunc)NULL,
+               (GBaseFinalizeFunc)NULL,
+
+               (GClassInitFunc)vte_terminal_accessible_class_init,
+               (GClassFinalizeFunc)NULL,
+               (gconstpointer)NULL,
+
+               sizeof(VteTerminal),
+               0,
+               (GInstanceInitFunc)vte_terminal_accessible_init,
+
+               (GTypeValueTable*)NULL,
+       };
+
+       if (terminal_accessible_type == 0) {
+               terminal_accessible_type = g_type_register_static(GTK_TYPE_ACCESSIBLE,
+                                                                 "VteTerminalAccessible",
+                                                                 &terminal_accessible_info,
+                                                                 0);
+       }
+
+       return terminal_accessible_type;
+}
diff --git a/src/vteaccess.h b/src/vteaccess.h
new file mode 100644 (file)
index 0000000..6ee06f9
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2002 Red Hat, Inc.
+ *
+ * This is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef vteaccess_h_included
+#define vteaccess_h_included
+
+#ident "$Id$"
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include "vte.h"
+
+G_BEGIN_DECLS
+
+/* The terminal accessibility object itself. */
+typedef struct _VteTerminalAccessible {
+       AtkObject object;
+} VteTerminalAccessible;
+
+/* The object's class structure. */
+typedef struct _VteTerminalAccessibleClass {
+       /*< public > */
+       /* Inherited parent class. */
+       AtkObjectClass parent_class;
+} VteTerminalAccessibleClass;
+
+/* The object's type. */
+GtkType vte_terminal_accessible_get_type(void);
+
+#define VTE_TYPE_TERMINAL_ACCESSIBLE   (vte_terminal_accessible_get_type())
+#define VTE_TERMINAL_ACCESSIBLE(obj)   (GTK_CHECK_CAST((obj),\
+                                                       VTE_TYPE_TERMINAL_ACCESSIBLE,\
+                                                       VteTerminalAccessible))
+#define VTE_TERMINAL_ACCESSIBLE_CLASS(klass)   GTK_CHECK_CLASS_CAST((klass),\
+                                                                    VTE_TYPE_TERMINAL_ACCESSIBLE,\
+                                                                    VteTerminalAccessibleClass)
+#define VTE_IS_TERMINAL_ACCESSIBLE(obj)                GTK_CHECK_TYPE((obj),\
+                                                              VTE_TYPE_TERMINAL_ACCESSIBLE)
+#define VTE_IS_TERMINAL_ACCESSIBLE_CLASS(klass)        GTK_CHECK_CLASS_TYPE((klass),\
+                                                                    VTE_TYPE_TERMINAL_ACCESSIBLE)
+#define VTE_TERMINAL_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), VTE_TYPE_TERMINAL_ACCESSIBLE, VteTerminalAccessibleClass))
+
+
+AtkObject *vte_terminal_accessible_new(VteTerminal *terminal);
+
+G_END_DECLS
+
+#endif
index 46327a8..7b60b18 100644 (file)
--- a/vte.spec
+++ b/vte.spec
@@ -1,5 +1,5 @@
 Name: vte
-Version: 0.2.2
+Version: 0.3
 Release: 1
 Summary: An experimental terminal emulator.
 License: LGPL
@@ -52,6 +52,13 @@ make install DESTDIR=$RPM_BUILD_ROOT
 %{_libdir}/pkgconfig/*
 
 %changelog
+* Tue Apr 30 2002 Nalin Dahyabhai <nalin@redhat.com> 0.3-1
+- add an accessiblity object
+
+* Mon Apr 29 2002 Nalin Dahyabhai <nalin@redhat.com> 0.2.3-1
+- fix color resetting
+- fix idle handlers not being disconnected
+
 * Mon Apr 29 2002 Nalin Dahyabhai <nalin@redhat.com> 0.2.2-1
 - bug fixes