summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNalin Dahyabhai <nalin@src.gnome.org>2002-04-30 22:06:35 +0000
committerNalin Dahyabhai <nalin@src.gnome.org>2002-04-30 22:06:35 +0000
commitcdf1940aa5107ae317b8f3696e6bb0808f8c422f (patch)
treeec002fdd076fc1f7ecb68d02f3f7024b3dfd95c6
parent2c418085fcfbb5fbefcdc840b5b5ba516d4af849 (diff)
downloadvte-cdf1940aa5107ae317b8f3696e6bb0808f8c422f.tar.gz
Track and free idle task tags properly. Change F11 and F12 capabilitiesvte_0_3
* 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.
-rw-r--r--ChangeLog18
-rw-r--r--README2
-rw-r--r--configure.in1
-rw-r--r--src/Makefile.am6
-rw-r--r--src/pty.c1
-rw-r--r--src/vte.c545
-rw-r--r--src/vte.h47
-rw-r--r--src/vteaccess.c675
-rw-r--r--src/vteaccess.h63
-rw-r--r--vte.spec9
10 files changed, 1241 insertions, 126 deletions
diff --git a/ChangeLog b/ChangeLog
index b731771c..2bc13279 100644
--- 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 18dc1503..a8bb936e 100644
--- 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
diff --git a/configure.in b/configure.in
index b64d94d1..b2944f50 100644
--- a/configure.in
+++ b/configure.in
@@ -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)
diff --git a/src/Makefile.am b/src/Makefile.am
index 4a3ac42d..6714333b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -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
diff --git a/src/pty.c b/src/pty.c
index 42c7e3ee..1119e6b6 100644
--- 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) {
diff --git a/src/vte.c b/src/vte.c
index fca4c3b6..27a2ca6b 100644
--- 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);
+}
diff --git a/src/vte.h b/src/vte.h
index b5b8d769..0cc263f1 100644
--- 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
index 00000000..6d1a7d48
--- /dev/null
+++ b/src/vteaccess.c
@@ -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
index 00000000..6ee06f91
--- /dev/null
+++ b/src/vteaccess.h
@@ -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
diff --git a/vte.spec b/vte.spec
index 46327a82..7b60b185 100644
--- 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