diff options
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | src/interpret.c | 2 | ||||
-rw-r--r-- | src/ring.c | 2 | ||||
-rw-r--r-- | src/trie.c | 127 | ||||
-rw-r--r-- | src/trie.h | 3 | ||||
-rw-r--r-- | src/vte.c | 490 | ||||
-rw-r--r-- | src/vte.h | 13 | ||||
-rw-r--r-- | src/vteaccess.c | 5 | ||||
-rw-r--r-- | src/vteapp.c | 2 | ||||
-rw-r--r-- | vte.spec | 2 |
10 files changed, 496 insertions, 160 deletions
@@ -1,3 +1,13 @@ +2002-05-02 nalin + * src/trie.c: Rework trie matching to return the address of the + character which ended the match attempt, which should cut down on + useless initial-substring checks. Remove several gdk_window_scroll() + calls which apparently aren't buffered. Convert invalid multibyte + characters to '?' instead of just dropping them. Provide a means of + setting the backspace/delete bindings. Add a poor xlfd_from_pango + mapping function which would need serious work to be useful. Get rid + of warnings when we're transparent and the root widnow pixmap isn't as + big as the root window because it's tiled. 2002-05-01 nalin * src/vte.c: Try @pkgdatadir@/termcap/$TERM when reading termcap files. This fixes the app on systems with no /etc/termcap, and also speeds up diff --git a/src/interpret.c b/src/interpret.c index 8eabdd6..c393314 100644 --- a/src/interpret.c +++ b/src/interpret.c @@ -100,7 +100,7 @@ main(int argc, char **argv) size_t wbuflen; convert_mbstowcs(array->data, i, wbuf, &wbuflen); vte_trie_match(trie, wbuf, wbuflen, - &tmp, &quark, &values); + &tmp, NULL, &quark, &values); if (tmp != NULL) { if (strlen(tmp) > 0) { int j; @@ -30,6 +30,7 @@ struct _VteRing { long delta, length, max; }; +#ifdef VTE_DEBUG static void vte_ring_validate(VteRing *ring) { @@ -39,6 +40,7 @@ vte_ring_validate(VteRing *ring) g_assert(ring->array[i % ring->max] != NULL); } } +#endif VteRing * vte_ring_new(long max_elements, VteRingFreeFunc free, gpointer data) @@ -36,7 +36,7 @@ /* Structures and whatnot for tracking character classes. */ struct char_class_data { - wchar_t c; /* A character. */ + wchar_t c; /* A character. */ int i; /* An integer. */ char *s; /* A string. */ int inc; /* An increment value. */ @@ -474,7 +474,8 @@ vte_trie_add(struct vte_trie *trie, const char *pattern, size_t length, * works, and the result string if we have an exact match. */ static const char * vte_trie_matchx(struct vte_trie *trie, const wchar_t *pattern, size_t length, - const char **res, GQuark *quark, GValueArray *array) + const char **res, const wchar_t **consumed, + GQuark *quark, GValueArray *array) { unsigned int i; const char *hres; @@ -482,6 +483,7 @@ vte_trie_matchx(struct vte_trie *trie, const wchar_t *pattern, size_t length, const char *best = NULL; GValueArray *bestarray = NULL; GQuark bestquark = 0; + const wchar_t *bestconsumed = pattern; /* Make sure that attempting to save output values doesn't kill us. */ if (res == NULL) { @@ -494,15 +496,18 @@ vte_trie_matchx(struct vte_trie *trie, const wchar_t *pattern, size_t length, if (trie->result) { *res = trie->result; *quark = trie->quark; + *consumed = pattern; return *res; } else { if (trie->trie_path_count > 0) { *res = ""; *quark = g_quark_from_static_string(""); + *consumed = pattern; return *res; } else { *res = NULL; *quark = 0; + *consumed = pattern; return *res; } } @@ -542,6 +547,7 @@ vte_trie_matchx(struct vte_trie *trie, const wchar_t *pattern, size_t length, prospect, length - (prospect - pattern), &tmp, + consumed, &tmpquark, tmparray); /* If it's a better match than any we've seen @@ -556,6 +562,7 @@ vte_trie_matchx(struct vte_trie *trie, const wchar_t *pattern, size_t length, } bestarray = tmparray; bestquark = tmpquark; + bestconsumed = *consumed; } else { g_value_array_free(tmparray); tmparray = NULL; @@ -579,6 +586,7 @@ vte_trie_matchx(struct vte_trie *trie, const wchar_t *pattern, size_t length, #endif *quark = bestquark; *res = best; + *consumed = bestconsumed; return *res; } @@ -586,13 +594,15 @@ vte_trie_matchx(struct vte_trie *trie, const wchar_t *pattern, size_t length, * empty string on a partial initial match, a NULL if there's no match in the * works, and the result string if we have an exact match. */ TRIE_MAYBE_STATIC const char * -vte_trie_match(struct vte_trie *trie, wchar_t *pattern, size_t length, - const char **res, GQuark *quark, GValueArray **array) +vte_trie_match(struct vte_trie *trie, const wchar_t *pattern, size_t length, + const char **res, const wchar_t **consumed, + GQuark *quark, GValueArray **array) { const char *ret = NULL; GQuark tmpquark; GValueArray *valuearray; GValue *value; + const wchar_t *dummyconsumed; gpointer ptr; int i; @@ -602,7 +612,13 @@ vte_trie_match(struct vte_trie *trie, wchar_t *pattern, size_t length, } *quark = 0; - ret = vte_trie_matchx(trie, pattern, length, res, quark, valuearray); + if (consumed == NULL) { + consumed = &dummyconsumed; + } + *consumed = pattern; + + ret = vte_trie_matchx(trie, pattern, length, res, consumed, + quark, valuearray); if (((ret == NULL) || (ret[0] == '\0')) || (valuearray->n_values == 0)){ if (valuearray != NULL) { @@ -689,7 +705,6 @@ TRIE_MAYBE_STATIC void vte_trie_print(struct vte_trie *trie) { vte_trie_printx(trie, ""); - g_print("\n"); } #ifdef TRIE_MAIN @@ -730,7 +745,7 @@ convert_mbstowcs(const char *i, size_t ilen, if (conv != NULL) { memset(o, 0, max_olen); outlen = max_olen; - iconv(conv, &i, &ilen, &o, &outlen); + iconv(conv, (char**)&i, &ilen, (char**)&o, &outlen); iconv_close(conv); } if (olen) { @@ -745,6 +760,7 @@ main(int argc, char **argv) GValueArray *array = NULL; GQuark quark; wchar_t buf[LINE_MAX]; + const wchar_t *consumed; size_t buflen; g_type_init(); @@ -771,12 +787,14 @@ main(int argc, char **argv) vte_trie_add(trie, "<esc>]2;%sh", 11, "decset-title", g_quark_from_string("decset-title")); vte_trie_print(trie); + g_print("\n"); quark = 0; convert_mbstowcs("abc", 3, buf, &buflen, sizeof(buf)); g_print("`%s' = `%s'\n", "abc", - vte_trie_match(trie, buf, buflen, NULL, &quark, &array)); - g_print("=> `%s'\n", g_quark_to_string(quark)); + vte_trie_match(trie, buf, buflen, + NULL, &consumed, &quark, &array)); + g_print("=> `%s' (%d)\n", g_quark_to_string(quark), consumed - buf); if (array != NULL) { dump_array(array); g_value_array_free(array); @@ -786,8 +804,9 @@ main(int argc, char **argv) quark = 0; convert_mbstowcs("abcdef", 6, buf, &buflen, sizeof(buf)); g_print("`%s' = `%s'\n", "abcdef", - vte_trie_match(trie, buf, buflen, NULL, &quark, &array)); - g_print("=> `%s'\n", g_quark_to_string(quark)); + vte_trie_match(trie, buf, buflen, + NULL, &consumed, &quark, &array)); + g_print("=> `%s' (%d)\n", g_quark_to_string(quark), consumed - buf); if (array != NULL) { dump_array(array); g_value_array_free(array); @@ -797,8 +816,9 @@ main(int argc, char **argv) quark = 0; convert_mbstowcs("abcde", 5, buf, &buflen, sizeof(buf)); g_print("`%s' = `%s'\n", "abcde", - vte_trie_match(trie, buf, buflen, NULL, &quark, &array)); - g_print("=> `%s'\n", g_quark_to_string(quark)); + vte_trie_match(trie, buf, buflen, + NULL, &consumed, &quark, &array)); + g_print("=> `%s' (%d)\n", g_quark_to_string(quark), consumed - buf); if (array != NULL) { dump_array(array); g_value_array_free(array); @@ -808,8 +828,9 @@ main(int argc, char **argv) quark = 0; convert_mbstowcs("abcdeg", 6, buf, &buflen, sizeof(buf)); g_print("`%s' = `%s'\n", "abcdeg", - vte_trie_match(trie, buf, buflen, NULL, &quark, &array)); - g_print("=> `%s'\n", g_quark_to_string(quark)); + vte_trie_match(trie, buf, buflen, + NULL, &consumed, &quark, &array)); + g_print("=> `%s' (%d)\n", g_quark_to_string(quark), consumed - buf); if (array != NULL) { dump_array(array); g_value_array_free(array); @@ -819,8 +840,9 @@ main(int argc, char **argv) quark = 0; convert_mbstowcs("abc%deg", 7, buf, &buflen, sizeof(buf)); g_print("`%s' = `%s'\n", "abc%deg", - vte_trie_match(trie, buf, buflen, NULL, &quark, &array)); - g_print("=> `%s'\n", g_quark_to_string(quark)); + vte_trie_match(trie, buf, buflen, + NULL, &consumed, &quark, &array)); + g_print("=> `%s' (%d)\n", g_quark_to_string(quark), consumed - buf); if (array != NULL) { dump_array(array); g_value_array_free(array); @@ -830,8 +852,9 @@ main(int argc, char **argv) quark = 0; convert_mbstowcs("abc10eg", 7, buf, &buflen, sizeof(buf)); g_print("`%s' = `%s'\n", "abc10eg", - vte_trie_match(trie, buf, buflen, NULL, &quark, &array)); - g_print("=> `%s'\n", g_quark_to_string(quark)); + vte_trie_match(trie, buf, buflen, + NULL, &consumed, &quark, &array)); + g_print("=> `%s' (%d)\n", g_quark_to_string(quark), consumed - buf); if (array != NULL) { dump_array(array); g_value_array_free(array); @@ -841,8 +864,9 @@ main(int argc, char **argv) quark = 0; convert_mbstowcs("abc%eg", 6, buf, &buflen, sizeof(buf)); g_print("`%s' = `%s'\n", "abc%eg", - vte_trie_match(trie, buf, buflen, NULL, &quark, &array)); - g_print("=> `%s'\n", g_quark_to_string(quark)); + vte_trie_match(trie, buf, buflen, + NULL, &consumed, &quark, &array)); + g_print("=> `%s' (%d)\n", g_quark_to_string(quark), consumed - buf); if (array != NULL) { dump_array(array); g_value_array_free(array); @@ -852,8 +876,9 @@ main(int argc, char **argv) quark = 0; convert_mbstowcs("abc%10eg", 8, buf, &buflen, sizeof(buf)); g_print("`%s' = `%s'\n", "abc%10eg", - vte_trie_match(trie, buf, buflen, NULL, &quark, &array)); - g_print("=> `%s'\n", g_quark_to_string(quark)); + vte_trie_match(trie, buf, buflen, + NULL, &consumed, &quark, &array)); + g_print("=> `%s' (%d)\n", g_quark_to_string(quark), consumed - buf); if (array != NULL) { dump_array(array); g_value_array_free(array); @@ -863,8 +888,9 @@ main(int argc, char **argv) quark = 0; convert_mbstowcs("abcBeg", 6, buf, &buflen, sizeof(buf)); g_print("`%s' = `%s'\n", "abcBeg", - vte_trie_match(trie, buf, buflen, NULL, &quark, &array)); - g_print("=> `%s'\n", g_quark_to_string(quark)); + vte_trie_match(trie, buf, buflen, + NULL, &consumed, &quark, &array)); + g_print("=> `%s' (%d)\n", g_quark_to_string(quark), consumed - buf); if (array != NULL) { dump_array(array); g_value_array_free(array); @@ -874,8 +900,9 @@ main(int argc, char **argv) quark = 0; convert_mbstowcs("<esc>[25;26H", 12, buf, &buflen, sizeof(buf)); g_print("`%s' = `%s'\n", "<esc>[25;26H", - vte_trie_match(trie, buf, buflen, NULL, &quark, &array)); - g_print("=> `%s'\n", g_quark_to_string(quark)); + vte_trie_match(trie, buf, buflen, + NULL, &consumed, &quark, &array)); + g_print("=> `%s' (%d)\n", g_quark_to_string(quark), consumed - buf); if (array != NULL) { dump_array(array); g_value_array_free(array); @@ -883,10 +910,22 @@ main(int argc, char **argv) } quark = 0; + convert_mbstowcs("<esc>[25;2", 10, buf, &buflen, sizeof(buf)); + g_print("`%s' = `%s'\n", "<esc>[25;2", + vte_trie_match(trie, buf, buflen, + NULL, &consumed, &quark, &array)); + g_print("=> `%s' (%d)\n", g_quark_to_string(quark), consumed - buf); + if (array != NULL) { + dump_array(array); + g_value_array_free(array); + } + + quark = 0; convert_mbstowcs("<esc>[25;26L", 12, buf, &buflen, sizeof(buf)); g_print("`%s' = `%s'\n", "<esc>[25;26L", - vte_trie_match(trie, buf, buflen, NULL, &quark, &array)); - g_print("=> `%s'\n", g_quark_to_string(quark)); + vte_trie_match(trie, buf, buflen, + NULL, &consumed, &quark, &array)); + g_print("=> `%s' (%d)\n", g_quark_to_string(quark), consumed - buf); if (array != NULL) { dump_array(array); g_value_array_free(array); @@ -895,8 +934,34 @@ main(int argc, char **argv) quark = 0; convert_mbstowcs("<esc>]2;WoofWoofh", 17, buf, &buflen, sizeof(buf)); g_print("`%s' = `%s'\n", "<esc>]2;WoofWoofh", - vte_trie_match(trie, buf, buflen, NULL, &quark, &array)); - g_print("=> `%s'\n", g_quark_to_string(quark)); + vte_trie_match(trie, buf, buflen, + NULL, &consumed, &quark, &array)); + g_print("=> `%s' (%d)\n", g_quark_to_string(quark), consumed - buf); + if (array != NULL) { + dump_array(array); + g_value_array_free(array); + array = NULL; + } + + quark = 0; + convert_mbstowcs("<esc>]2;WoofWoofh<esc>]2;WoofWoofh", 34, + buf, &buflen, sizeof(buf)); + g_print("`%s' = `%s'\n", "<esc>]2;WoofWoofh<esc>]2;WoofWoofh", + vte_trie_match(trie, buf, buflen, + NULL, &consumed, &quark, &array)); + g_print("=> `%s' (%d)\n", g_quark_to_string(quark), consumed - buf); + if (array != NULL) { + dump_array(array); + g_value_array_free(array); + array = NULL; + } + + quark = 0; + convert_mbstowcs("<esc>]2;WoofWoofhfoo", 20, buf, &buflen, sizeof(buf)); + g_print("`%s' = `%s'\n", "<esc>]2;WoofWoofhfoo", + vte_trie_match(trie, buf, buflen, + NULL, &consumed, &quark, &array)); + g_print("=> `%s' (%d)\n", g_quark_to_string(quark), consumed - buf); if (array != NULL) { dump_array(array); g_value_array_free(array); @@ -48,8 +48,9 @@ void vte_trie_add(struct vte_trie *trie, * passed-in string can not be an initial substring of one of the strings in * the trie, then NULL is returned. */ const char *vte_trie_match(struct vte_trie *trie, - wchar_t *pattern, size_t length, + const wchar_t *pattern, size_t length, const char **res, + const wchar_t **consumed, GQuark *quark, GValueArray **array); @@ -222,6 +222,8 @@ struct _VteTerminalPrivate { GtkIMContext *im_context; char *im_preedit; int im_preedit_cursor; + + VteTerminalEraseBinding backspace_binding, delete_binding; }; /* A function which can handle a terminal control sequence. */ @@ -771,12 +773,12 @@ vte_sequence_handler_al(VteTerminal *terminal, #else vte_invalidate_cells(terminal, 0, terminal->column_count, - start, end + 1); + start, end - start + 1); #endif } else { vte_invalidate_cells(terminal, 0, terminal->column_count, - start, end + 1); + start, end - start + 1); } } @@ -1266,6 +1268,7 @@ vte_sequence_handler_do(VteTerminal *terminal, vte_insert_line_int(terminal, end); if ((terminal->pvt->bg_image == NULL) && (!terminal->pvt->bg_transparent)) { +#if 0 /* Scroll the window. */ gdk_window_scroll(widget->window, 0, @@ -1280,14 +1283,21 @@ vte_sequence_handler_do(VteTerminal *terminal, vte_invalidate_cells(terminal, 0, terminal->column_count, 0, start); +#else + vte_invalidate_cells(terminal, + 0, + terminal->column_count, + start, + end - start + 1); +#endif } else { /* If we have a background image, we need to * redraw the entire window. */ vte_invalidate_cells(terminal, 0, terminal->column_count, - screen->scroll_delta, - terminal->row_count); + start, + end - start + 1); } } else { /* Otherwise, just move the cursor down. */ @@ -1666,6 +1676,7 @@ vte_sequence_handler_up(VteTerminal *terminal, vte_insert_line_int(terminal, start); if ((terminal->pvt->bg_image == NULL) && (!terminal->pvt->bg_transparent)) { +#if 0 /* Scroll the window. */ gdk_window_scroll(widget->window, 0, @@ -1680,14 +1691,16 @@ vte_sequence_handler_up(VteTerminal *terminal, vte_invalidate_cells(terminal, 0, terminal->column_count, end, terminal->row_count); +#endif + vte_invalidate_cells(terminal, + 0, terminal->column_count, + start, end - start + 1); } else { /* If we have a background image, we need to * redraw the entire window. */ vte_invalidate_cells(terminal, - 0, - terminal->column_count, - screen->scroll_delta, - terminal->row_count); + 0, terminal->column_count, + start, end - start + 1); } } else { /* Otherwise, just move the cursor up. */ @@ -1705,6 +1718,7 @@ vte_sequence_handler_up(VteTerminal *terminal, vte_insert_line_int(terminal, start); if ((terminal->pvt->bg_image == NULL) && (!terminal->pvt->bg_transparent)) { +#if 0 /* Scroll the window. */ gdk_window_scroll(widget->window, 0, @@ -1715,6 +1729,13 @@ vte_sequence_handler_up(VteTerminal *terminal, terminal->column_count, terminal->row_count - 1, 1); +#else + vte_invalidate_cells(terminal, + 0, + terminal->column_count, + screen->scroll_delta, + terminal->row_count); +#endif } else { /* If we have a background image, we need to * redraw the entire window. */ @@ -3280,6 +3301,30 @@ vte_terminal_im_reset(VteTerminal *terminal) } } +/* Free a parameter array. Most of the GValue elements can clean up after + * themselves, but we're using gpointers to hold wide character strings, and + * we need to free those ourselves. */ +static void +free_params_array(GValueArray *params) +{ + int i; + GValue *value; + gpointer ptr; + if (params != NULL) { + for (i = 0; i < params->n_values; i++) { + value = g_value_array_get_nth(params, i); + if (G_VALUE_HOLDS_POINTER(value)) { + ptr = g_value_get_pointer(value); + if (ptr != NULL) { + g_free(ptr); + } + g_value_set_pointer(value, NULL); + } + } + g_value_array_free(params); + } +} + /* Process incoming data, first converting it to wide characters, and then * processing escape sequences. */ static gboolean @@ -3294,12 +3339,11 @@ vte_terminal_process_incoming(gpointer data) char *ibuf, *obuf, *obufptr, *ubuf, *ubufptr; size_t icount, ocount, ucount; wchar_t *wbuf, c; - int ind, wcount, start, end; + int wcount, start, end, i; const char *match, *encoding; iconv_t unconv; GQuark quark; - GValue *value; - gpointer ptr; + const wchar_t *next; gboolean leftovers, inserted, again, bottom; g_return_val_if_fail(GTK_IS_WIDGET(data), FALSE); @@ -3340,15 +3384,12 @@ vte_terminal_process_incoming(gpointer data) } } /* Be conservative about discarding data. */ - g_warning("Invalid multibyte sequence detected. Discarding %d bytes of data.", end - start); + g_warning("Invalid multibyte sequence detected. Munging up %d bytes of data.", end - start); /* Remove the offending bytes. */ - obuf = &terminal->pvt->incoming[start]; - ibuf = &terminal->pvt->incoming[end]; - memmove(obuf, ibuf, terminal->pvt->n_incoming - end); - /* Reset the incoming buffer size. */ - terminal->pvt->n_incoming -= end; - /* If we still have data, try again right - * away. */ + for (i = start; i < end; i++) { + terminal->pvt->incoming[i] = '?'; + } + /* Try again right away. */ terminal->pvt->processing = (terminal->pvt->n_incoming > 0); if (terminal->pvt->processing == FALSE) { terminal->pvt->processing_tag = -1; @@ -3382,126 +3423,190 @@ vte_terminal_process_incoming(gpointer data) start = 0; inserted = leftovers = FALSE; while ((start < wcount) && !leftovers) { - for (end = start + 1; end <= wcount; end++) { - /* Check if the contents of the array is a control - * string or not. The match function returns NULL if - * the data is not a control sequence, the name of - * the control sequence if it is one, and an empty - * string if it might be the beginning of a control - * sequence. */ + /* Check if the first character is part of a control + * sequence. */ + vte_trie_match(terminal->pvt->trie, + &wbuf[start], + 1, + &match, + &next, + &quark, + ¶ms); + /* Next now points to the next character in the buffer we're + * uncertain about. The match string falls into one of three + * classes, but only one of them is ambiguous, and we want to + * clear that up if possible. */ + if ((match != NULL) && (match[0] == '\0')) { +#ifdef VTE_DEBUG + fprintf(stderr, "Ambiguous sequence (%d/%d). " + "Resolving.\n", start, wcount); +#endif + /* Try to match the *entire* string. This will set + * "next" to a more useful value. */ + free_params_array(params); + params = NULL; vte_trie_match(terminal->pvt->trie, &wbuf[start], - end - start, + wcount - start, &match, + &next, &quark, ¶ms); + /* Now check just the number of bytes we know about + * to determine what we're doing in this iteration. */ if (match == NULL) { - /* Nothing interesting here, so insert this - * character into the buffer. */ - c = wbuf[start]; #ifdef VTE_DEBUG - if (c > 255) { - fprintf(stderr, "%ld\n", (long) c); - } else { - if (c > 127) { - fprintf(stderr, "%ld = ", - (long) c); + fprintf(stderr, + "Looks like a sequence (%d).\n", + next - (wbuf + start)); +#endif + free_params_array(params); + params = NULL; + vte_trie_match(terminal->pvt->trie, + &wbuf[start], + next - (wbuf + start), + &match, + &next, + &quark, + ¶ms); + if ((match != NULL) && (match[0] == '\0')) { + vte_trie_match(terminal->pvt->trie, + &wbuf[start], + next - (wbuf + start) + 1, + &match, + &next, + &quark, + ¶ms); + } + } +#ifdef VTE_DEBUG + if ((match != NULL) && (match[0] != '\0')) { + fprintf(stderr, + "Ambiguity resolved -- sequence "); + } + if ((match != NULL) && (match[0] == '\0')) { + int i; + fprintf(stderr, + "Ambiguity resolved -- incomplete `"); + for (i = 0; i < wcount; i++) { + if (i == start) { + fprintf(stderr, "=>"); } - if (c < 32) { - fprintf(stderr, "^%lc\n", - (wint_t)c + 64); + if ((wbuf[i] < 32) || (wbuf[i] > 127)) { + fprintf(stderr, "{%ld}", + (long) wbuf[i]); } else { - fprintf(stderr, "`%lc'\n", - (wint_t)c); + fprintf(stderr, "%lc", + (wint_t) wbuf[i]); } + if (i == (next - wbuf)) { + fprintf(stderr, "<="); + } + } + if (i == (next - wbuf)) { + fprintf(stderr, "<="); } + fprintf(stderr, "'.\n"); + } + if (match == NULL) { + fprintf(stderr, + "Ambiguity resolved -- plain data "); + } + fprintf(stderr, "(%d).\n", next - wbuf); #endif - vte_terminal_insert_char(widget, c); - inserted = TRUE; - start++; - break; + } + +#ifdef VTE_DEBUG + else { + if ((match != NULL) && (match[0] != '\0')) { + fprintf(stderr, + "Sequence (%d).\n", next - wbuf); } - if (match[0] != '\0') { - /* A terminal sequence, force the current - * position of the cursor to be redrawn, run - * the sequence handler, and then draw the - * cursor again. */ - vte_invalidate_cursor_once(terminal); - vte_terminal_handle_sequence(GTK_WIDGET(terminal), - match, - quark, - params); - /* Skip over the proper number of wide chars. */ - start = end; - /* Check if the encoding's changed. */ - if (strcmp(encoding, terminal->pvt->encoding)) { - leftovers = TRUE; - } - inserted = TRUE; - break; - } else { - /* Empty string. */ - if (end == wcount) { - /* We have the initial portion of a - * control sequence, but no more - * data. */ - leftovers = TRUE; - g_warning("Unhandled data (%s).\n", - terminal->pvt->incoming + start); - } + if ((match != NULL) && (match[0] == '\0')) { + fprintf(stderr, + "Incomplete (%d).\n", next - wbuf); } - /* Free any wide-character strings we got. */ - if (params != NULL) { - for (ind = 0; ind < params->n_values; ind++) { - value = g_value_array_get_nth(params, - ind); - if (G_VALUE_HOLDS_POINTER(value)) { - ptr = g_value_get_pointer(value); - if (ptr != NULL) { - g_free(ptr); - } - g_value_set_pointer(value, - NULL); - } - } - g_value_array_free(params); - params = NULL; + if (match == NULL) { + fprintf(stderr, + "Plain data (%d).\n", next - wbuf); } } - /* Free any wide-character strings we got if we broke out - * of the loop. */ - if (params != NULL) { - for (ind = 0; ind < params->n_values; ind++) { - value = g_value_array_get_nth(params, ind); - if (G_VALUE_HOLDS_POINTER(value)) { - ptr = g_value_get_pointer(value); - if (ptr != NULL) { - g_free(ptr); - } - g_value_set_pointer(value, NULL); +#endif + /* We're in one of three possible situations now. + * First, the match string is a non-empty string and next + * points to the first character which isn't part of this + * sequence. */ + if ((match != NULL) && (match[0] != '\0')) { + vte_invalidate_cursor_once(terminal); + vte_terminal_handle_sequence(GTK_WIDGET(terminal), + match, + quark, + params); + /* Skip over the proper number of wide chars. */ + start = (next - wbuf); + /* Check if the encoding's changed. If it has, we need + * to force our caller to call us again to parse the + * rest of the data. */ + if (strcmp(encoding, terminal->pvt->encoding)) { + leftovers = TRUE; + } + inserted = TRUE; + } else + /* Second, we have a NULL match, and next points the very + * next character in the buffer. Insert the character we're + * which we're currently examining. */ + if (match == NULL) { + c = wbuf[start]; +#ifdef VTE_DEBUG + if (c > 255) { + fprintf(stderr, "%ld\n", (long) c); + } else { + if (c > 127) { + fprintf(stderr, "%ld = ", (long) c); + } + if (c < 32) { + fprintf(stderr, "^%lc\n", + (wint_t)c + 64); + } else { + fprintf(stderr, "`%lc'\n", (wint_t)c); } } - g_value_array_free(params); - params = NULL; +#endif + vte_terminal_insert_char(widget, c); + inserted = TRUE; + start++; + } else { + /* Case three: the read broke in the middle of a + * control sequence, so we're undecided with no more + * data to consult. */ + leftovers = TRUE; } + /* Free any parameters we don't care about any more. */ + free_params_array(params); + params = NULL; } - again = TRUE; + if (leftovers) { /* There are leftovers, so convert them back to the terminal's - * encoding and save them for later. */ + * old encoding and save them for later. */ unconv = iconv_open(encoding, "WCHAR_T"); if (unconv != NULL) { icount = sizeof(wchar_t) * (wcount - start); ibuf = (char*) &wbuf[start]; - ucount = VTE_UTF8_BPC * (wcount - start + 1); + ucount = VTE_UTF8_BPC * (wcount - start) + 1; ubuf = ubufptr = g_malloc(ucount); if (iconv(unconv, &ibuf, &icount, &ubuf, &ucount) != -1) { /* Store it. */ - g_free(terminal->pvt->incoming); + if (terminal->pvt->incoming) { + g_free(terminal->pvt->incoming); + } terminal->pvt->incoming = ubufptr; terminal->pvt->n_incoming = ubuf - ubufptr; *ubuf = '\0'; + /* If we're doing this because the encoding + * was changed out from under us, we need to + * keep trying to process the incoming data. */ if (strcmp(encoding, terminal->pvt->encoding)) { again = TRUE; } else { @@ -3514,15 +3619,22 @@ vte_terminal_process_incoming(gpointer data) (long) (sizeof(wchar_t) * (wcount - start)), strerror(errno)); #endif + if (terminal->pvt->incoming) { + g_free(terminal->pvt->incoming); + } + terminal->pvt->incoming = NULL; + terminal->pvt->n_incoming = 0; g_free(ubufptr); again = FALSE; } iconv_close(unconv); } else { /* Discard the data, we can't use it. */ - terminal->pvt->n_incoming = 0; - g_free(terminal->pvt->incoming); + if (terminal->pvt->incoming != NULL) { + g_free(terminal->pvt->incoming); + } terminal->pvt->incoming = NULL; + terminal->pvt->n_incoming = 0; again = FALSE; } } else { @@ -3553,6 +3665,7 @@ vte_terminal_process_incoming(gpointer data) /* 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. */ @@ -3572,6 +3685,8 @@ vte_terminal_process_incoming(gpointer data) fprintf(stderr, "%d bytes left to process.\n", terminal->pvt->n_incoming); #endif + /* Decide if we're going to keep on processing data, and if not, + * note that our source tag is about to become invalid. */ terminal->pvt->processing = again && (terminal->pvt->n_incoming > 0); if (terminal->pvt->processing == FALSE) { terminal->pvt->processing_tag = -1; @@ -4003,16 +4118,46 @@ vte_terminal_key_press(GtkWidget *widget, GdkEventKey *event) /* Map the key to a sequence name if we can. */ switch (event->keyval) { case GDK_BackSpace: - /* Use the tty's erase character. */ - if (tcgetattr(terminal->pvt->pty_master, - &tio) != -1) { - normal = g_strdup_printf("%c", - tio.c_cc[VERASE]); - normal_length = 1; + switch (terminal->pvt->backspace_binding) { + case VTE_ERASE_ASCII_BACKSPACE: + normal = g_strdup(""); + normal_length = 1; + break; + case VTE_ERASE_ASCII_DELETE: + normal = g_strdup(""); + normal_length = 1; + break; + case VTE_ERASE_DELETE_SEQUENCE: + special = "kD"; + break; + /* Use the tty's erase character. */ + case VTE_ERASE_AUTO: + default: + if (tcgetattr(terminal->pvt->pty_master, + &tio) != -1) { + normal = g_strdup_printf("%c", + tio.c_cc[VERASE]); + normal_length = 1; + } + break; } break; case GDK_Delete: - special = "kD"; + switch (terminal->pvt->delete_binding) { + case VTE_ERASE_ASCII_BACKSPACE: + normal = g_strdup(""); + normal_length = 1; + break; + case VTE_ERASE_ASCII_DELETE: + normal = g_strdup(""); + normal_length = 1; + break; + case VTE_ERASE_DELETE_SEQUENCE: + case VTE_ERASE_AUTO: + default: + special = "kD"; + break; + } break; case GDK_KP_Home: case GDK_Home: @@ -4811,6 +4956,69 @@ xft_pattern_from_pango_font_description(const PangoFontDescription *font_desc) } #endif +static char * +xlfd_from_pango_font_description(const PangoFontDescription *fontdesc) +{ + int weighti, stylei, stretchi, size, count; + const char *weight, *style, *stretch, *family; + char *ret = NULL; + char **fonts; + + family = pango_font_description_get_family(fontdesc); + weighti = pango_font_description_get_weight(fontdesc); + if (weighti > ((PANGO_WEIGHT_NORMAL + PANGO_WEIGHT_BOLD) / 2)) { + weight = "bold"; + } else { + weight = "medium"; + } + stylei = pango_font_description_get_style(fontdesc); + switch (stylei) { + case PANGO_STYLE_ITALIC: + style = "i"; + break; + case PANGO_STYLE_OBLIQUE: + style = "o"; + break; + default: + style = "r"; + break; + } + stretchi = pango_font_description_get_stretch(fontdesc); + if (stretchi <= PANGO_STRETCH_CONDENSED) { + stretch = "condensed"; + } else + if (stretchi <= PANGO_STRETCH_SEMI_CONDENSED) { + stretch = "semicondensed"; + } else { + stretch = "normal"; + } + + size = pango_font_description_get_size(fontdesc); + + ret = g_strdup_printf("-*-%s*-%s-%s-%s--%d-*-*-*-*-*-*-*", + family, weight, style, stretch, + PANGO_PIXELS(size)); + fonts = XListFonts(GDK_DISPLAY(), ret, 1, &count); + if (fonts != NULL) { +#ifdef VTE_DEBUG + int i; + char *desc = pango_font_description_to_string(fontdesc); + for (i = 0; i < count; i++) { + fprintf(stderr, "Font `%s' matched `%s'.\n", + desc, fonts[i]); + } + g_free(desc); +#endif + XFreeFontNames(fonts); + } + if (count > 0) { + return ret; + } else { + g_free(ret); + return NULL; + } +} + /* Set the fontset used for rendering text into the widget. */ void vte_terminal_set_font(VteTerminal *terminal, @@ -4819,7 +5027,7 @@ vte_terminal_set_font(VteTerminal *terminal, long width, height, ascent, descent; GtkWidget *widget; XFontStruct **font_struct_list, font_struct; - char *xlfds = NULL; + char *xlfds; char **missing_charset_list = NULL, *def_string = NULL; int missing_charset_count = 0; char **font_name_list = NULL; @@ -4829,9 +5037,6 @@ vte_terminal_set_font(VteTerminal *terminal, widget = GTK_WIDGET(terminal); /* Choose default font metrics. I like '10x20' as a terminal font. */ - if (xlfds == NULL) { - xlfds = "-misc-fixed-medium-r-normal--20-*-*-*-*-*-*-*"; - } width = 10; height = 20; descent = 0; @@ -5033,6 +5238,24 @@ vte_terminal_set_font(VteTerminal *terminal, if (!terminal->pvt->use_xft && !terminal->pvt->use_pango) { /* Load the font set, freeing another one if we loaded one * before. */ +#ifdef VTE_DEBUG + if (font_desc) { + char *tmp; + tmp = pango_font_description_to_string (font_desc); + fprintf (stderr, "Using pango font \"%s\".\n", tmp); + g_free (tmp); + } else { + fprintf (stderr, "Using default pango font.\n"); + } +#endif + if (font_desc) { + xlfds = xlfd_from_pango_font_description(font_desc); + } else { + xlfds = "-misc-fixed-medium-r-normal--12-*-*-*-*-*-*-*"; + } + if (xlfds == NULL) { + xlfds = "-misc-fixed-medium-r-normal--12-*-*-*-*-*-*-*"; + } if (terminal->pvt->fontset != NULL) { XFreeFontSet(GDK_DISPLAY(), terminal->pvt->fontset); } @@ -5466,7 +5689,7 @@ vte_terminal_init(VteTerminal *terminal, gpointer *klass) } } } - if (!pvt->use_pango) { + if (pvt->use_pango) { if (getenv("VTE_USE_PANGO") != NULL) { if (atol(getenv("VTE_USE_PANGO")) == 0) { pvt->use_pango = FALSE; @@ -5527,6 +5750,10 @@ vte_terminal_init(VteTerminal *terminal, gpointer *klass) /* Set up input method support. */ pvt->im_context = NULL; + + /* Set backspace/delete bindings. */ + pvt->backspace_binding = VTE_ERASE_AUTO; + pvt->delete_binding = VTE_ERASE_AUTO; } /* Tell GTK+ how much space we need. */ @@ -6891,7 +7118,7 @@ vte_terminal_setup_background(VteTerminal *terminal, } /* If we need a new copy of the desktop, get it. */ if (refresh_transparent) { - guint width, height; + guint width, height, pwidth, pheight; #ifdef VTE_DEBUG fprintf(stderr, "Fetching new background pixmap.\n"); @@ -6923,14 +7150,15 @@ vte_terminal_setup_background(VteTerminal *terminal, /* If we got a pixmap, create a pixbuf for * us to work with. */ if (GDK_IS_PIXMAP(pixmap)) { + gdk_drawable_get_size(GDK_DRAWABLE(pixmap), &pwidth, &pheight); colormap = gdk_drawable_get_colormap(window); pixbuf = gdk_pixbuf_get_from_drawable(NULL, pixmap, colormap, 0, 0, 0, 0, - width, - height); + MIN(width, pwidth), + MIN(pheight, height)); /* Get rid of the pixmap. */ g_object_unref(G_OBJECT(pixmap)); pixmap = NULL; @@ -7492,3 +7720,19 @@ vte_terminal_set_word_chars(VteTerminal *terminal, const char *spec) g_free(ibufptr); g_free(obufptr); } + +void +vte_terminal_set_backspace_binding(VteTerminal *terminal, + VteTerminalEraseBinding binding) +{ + g_return_if_fail(VTE_IS_TERMINAL(terminal)); + terminal->pvt->backspace_binding = binding; +} + +void +vte_terminal_set_delete_binding(VteTerminal *terminal, + VteTerminalEraseBinding binding) +{ + g_return_if_fail(VTE_IS_TERMINAL(terminal)); + terminal->pvt->delete_binding = binding; +} @@ -92,6 +92,13 @@ typedef struct _VteTerminalSnapshot { } **contents; } VteTerminalSnapshot; +typedef enum { + VTE_ERASE_AUTO, + VTE_ERASE_ASCII_BACKSPACE, + VTE_ERASE_ASCII_DELETE, + VTE_ERASE_DELETE_SEQUENCE, +} VteTerminalEraseBinding; + /* The widget's type. */ GtkType vte_terminal_get_type(void); @@ -108,7 +115,6 @@ GtkType vte_terminal_get_type(void); VTE_TYPE_TERMINAL) #define VTE_TERMINAL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), VTE_TYPE_TERMINAL, VteTerminalClass)) - GtkWidget *vte_terminal_new(void); pid_t vte_terminal_fork_command(VteTerminal *terminal, const char *command, @@ -155,6 +161,11 @@ 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); +void vte_terminal_set_backspace_binding(VteTerminal *terminal, + VteTerminalEraseBinding binding); +void vte_terminal_set_delete_binding(VteTerminal *terminal, + VteTerminalEraseBinding binding); + VteTerminalSnapshot *vte_terminal_get_snapshot(VteTerminal *terminal); void vte_terminal_free_snapshot(VteTerminalSnapshot *snapshot); diff --git a/src/vteaccess.c b/src/vteaccess.c index 6d1a7d4..9e2dfcf 100644 --- a/src/vteaccess.c +++ b/src/vteaccess.c @@ -242,7 +242,10 @@ vte_terminal_accessible_get_text_somewhere(AtkText *text, break; case ATK_TEXT_BOUNDARY_WORD_START: case ATK_TEXT_BOUNDARY_WORD_END: - /* Find the wordstart before the requested point. */ + /* Find the wordstart before the requested point. + * FIXME: use pango_break or g_unichar_break_type to + * find word boundaries. For now, this should work + * only for some locales. */ c = g_array_index(priv->snapshot_cells, struct VteTerminalSnapshotCell, offset).c; diff --git a/src/vteapp.c b/src/vteapp.c index 404cb90..4c1bd2f 100644 --- a/src/vteapp.c +++ b/src/vteapp.c @@ -131,7 +131,7 @@ main(int argc, char **argv) /* Set the default font. */ vte_terminal_set_font_from_string(VTE_TERMINAL(widget), - "fixed semi-condensed 12"); + "fixed 12"); /* Launch a shell. */ #ifdef VTE_DEBUG @@ -1,5 +1,5 @@ Name: vte -Version: 0.3.2 +Version: 0.3.3 Release: 1 Summary: An experimental terminal emulator. License: LGPL |