summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNalin Dahyabhai <nalin@src.gnome.org>2002-04-23 19:54:08 +0000
committerNalin Dahyabhai <nalin@src.gnome.org>2002-04-23 19:54:08 +0000
commit6484fcbc85aa95f11cee920e4434b062ff3b7c21 (patch)
tree81b9fee9235df15dfa44b3d14fe1b2f63c76e09e
parentbf831313bd700377003fef57a698fced01ef1241 (diff)
autogen.sh: Default to include optimization, even for debugging.
configure.in: Move AM_CONFIG_HEADER to the top. src/pty.c: Create non-login shells by default (when argv is NULL). src/vte.c: Add mostly-complete input method support. src/vte.h: Add vte_terminal_im_append_menuitems().
-rwxr-xr-xautogen.sh2
-rw-r--r--configure.in3
-rw-r--r--src/pty.c6
-rw-r--r--src/vte.c760
-rw-r--r--src/vte.h5
5 files changed, 555 insertions, 221 deletions
diff --git a/autogen.sh b/autogen.sh
index b8240d6..80192e8 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -1,5 +1,5 @@
#!/bin/bash -e
-CFLAGS="${CFLAGS:--g3 -Wall}" ; export CFLAGS
+CFLAGS="${CFLAGS:--g3 -O -Wall}" ; export CFLAGS
set -x
libtoolize -f
autoheader
diff --git a/configure.in b/configure.in
index 2db1b6d..016c5d9 100644
--- a/configure.in
+++ b/configure.in
@@ -1,5 +1,6 @@
AC_INIT(configure.in)
AM_INIT_AUTOMAKE(vte,0.1)
+AM_CONFIG_HEADER(config.h)
AM_PROG_LIBTOOL
AC_EGREP_CPP(glibc,
[
@@ -50,6 +51,4 @@ fi
if test x$VTE_DEBUG = x1 ; then
AC_DEFINE(VTE_DEBUG,,[Enable debugging of unrecognized sequences.])
fi
-
-AM_CONFIG_HEADER(config.h)
AC_OUTPUT([Makefile src/Makefile vte.pc])
diff --git a/src/pty.c b/src/pty.c
index 2216005..8e72cea 100644
--- a/src/pty.c
+++ b/src/pty.c
@@ -104,11 +104,10 @@ vte_pty_fork_on_fd(const char *path, const char **env_add,
execv(command, args);
} else {
if (strchr(command, '/')) {
- arg = g_strdup(strrchr(command, '/'));
+ arg = g_strdup(strrchr(command, '/') + 1);
} else {
- arg = g_strdup_printf("/%s", command);
+ arg = g_strdup_printf("%s", command);
}
- arg[0] = '-';
execl(command, arg, NULL);
}
@@ -203,6 +202,7 @@ static int
vte_pty_open_old_school(pid_t *child, const char **env_add,
const char *command, const char **argv)
{
+ /* FIXME */
return -1;
}
diff --git a/src/vte.c b/src/vte.c
index 6428052..3f6ab70 100644
--- a/src/vte.c
+++ b/src/vte.c
@@ -195,6 +195,10 @@ struct _VteTerminalPrivate {
GdkPixbuf *bg_image;
guint bg_saturation; /* out of VTE_SATURATION_MAX */
+
+ GtkIMContext *im_context;
+ char *im_preedit;
+ int im_preedit_cursor;
};
/* A function which can handle a terminal control sequence. */
@@ -296,14 +300,20 @@ static gboolean
vte_invalidate_cursor_once(gpointer data)
{
VteTerminal *terminal;
+ size_t preedit_length;
if (!VTE_IS_TERMINAL(data)) {
return FALSE;
}
terminal = VTE_TERMINAL(data);
if (GTK_WIDGET_REALIZED(GTK_WIDGET(terminal))) {
+ if (terminal->pvt->im_preedit != NULL) {
+ preedit_length = strlen(terminal->pvt->im_preedit);
+ } else {
+ preedit_length = 0;
+ }
vte_invalidate_cells(terminal,
terminal->pvt->screen->cursor_current.col,
- 1,
+ 1 + preedit_length,
terminal->pvt->screen->cursor_current.row,
1);
}
@@ -1155,8 +1165,9 @@ vte_sequence_handler_do(VteTerminal *terminal,
/* Move the cursor down. */
screen->cursor_current.row++;
- /* Make sure that the bottom row is visible. This usually
- * causes the top row to become a history 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(screen->row_data->len,
screen->cursor_current.row + 1);
delta = MAX(0, rows - terminal->row_count);
@@ -2698,7 +2709,7 @@ vte_terminal_set_colors(VteTerminal *terminal,
size_t palette_size)
{
int i;
- GdkColor color;
+ GdkColor color;
GtkWidget *widget;
Display *display;
GdkColormap *gcolormap;
@@ -2767,11 +2778,11 @@ vte_terminal_set_colors(VteTerminal *terminal,
}
/* Get an Xlib color. */
- gdk_rgb_find_color (gcolormap, &color); /* fill in pixel */
- terminal->pvt->palette[i].red = color.red;
- terminal->pvt->palette[i].green = color.green;
- terminal->pvt->palette[i].blue = color.blue;
- terminal->pvt->palette[i].pixel = color.pixel;
+ gdk_rgb_find_color(gcolormap, &color); /* fill in pixel */
+ terminal->pvt->palette[i].red = color.red;
+ terminal->pvt->palette[i].green = color.green;
+ terminal->pvt->palette[i].blue = color.blue;
+ terminal->pvt->palette[i].pixel = color.pixel;
#ifdef HAVE_XFT
if (terminal->pvt->use_xft) {
@@ -2781,12 +2792,13 @@ vte_terminal_set_colors(VteTerminal *terminal,
terminal->pvt->palette[i].rcolor.blue = color.blue;
terminal->pvt->palette[i].rcolor.alpha = 0xffff;
- /* FIXME this probably needs to be freed somewhere */
+ /* FIXME this should probably use a color from the
+ * color cube. */
if (!XftColorAllocValue(display,
- visual,
- colormap,
- &terminal->pvt->palette[i].rcolor,
- &terminal->pvt->palette[i].ftcolor)) {
+ visual,
+ colormap,
+ &terminal->pvt->palette[i].rcolor,
+ &terminal->pvt->palette[i].ftcolor)) {
terminal->pvt->use_xft = FALSE;
}
}
@@ -2948,10 +2960,15 @@ vte_terminal_insert_char(GtkWidget *widget, wchar_t c)
screen->cursor_current.row, 2);
}
- /* And take a step to the to the right. We invalidated this
- * part of the screen already, so no need to do it again. */
+ /* And take a step to the to the right, making sure we redraw
+ * both where the cursor was moved from. */
+ vte_invalidate_cursor_once(terminal);
screen->cursor_current.col++;
}
+
+ /* Redraw where the cursor has moved to. */
+ vte_invalidate_cursor_once(terminal);
+
#ifdef VTE_DEBUG
#ifdef VTE_DEBUG_INSERT
fprintf(stderr, "Insertion delta = %ld.\n", (long)screen->insert_delta);
@@ -3055,6 +3072,7 @@ vte_terminal_fork_command(VteTerminal *terminal, const char *command,
colorterm = g_strdup("COLORTERM=" PACKAGE);
env_add[0] = term;
env_add[1] = colorterm;
+ env_add[2] = NULL;
terminal->pvt->pty_master = vte_pty_open(&terminal->pvt->pty_pid,
env_add,
command ?:
@@ -3108,6 +3126,7 @@ vte_terminal_process_incoming(gpointer data)
GValueArray *params;
VteTerminal *terminal;
GtkWidget *widget;
+ GdkRectangle rect;
char *ibuf, *obuf, *obufptr, *ubuf, *ubufptr;
size_t icount, ocount, ucount;
wchar_t *wbuf, c;
@@ -3229,7 +3248,11 @@ vte_terminal_process_incoming(gpointer data)
break;
}
if (match[0] != '\0') {
- /* A terminal sequence. */
+ /* 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,
@@ -3307,10 +3330,23 @@ vte_terminal_process_incoming(gpointer data)
if (terminal->pvt->scroll_on_output || bottom) {
vte_terminal_scroll_on_something(terminal);
}
+
+ /* The cursor moved, so force it to be redrawn. */
+ vte_invalidate_cursor_once(terminal);
+
/* Deselect any existing selection. */
vte_terminal_deselect_all(terminal);
}
+ /* Tell the input method where the cursor is. */
+ rect.x = terminal->pvt->screen->cursor_current.col *
+ terminal->char_width;
+ rect.width = terminal->char_width;
+ rect.y = terminal->pvt->screen->cursor_current.row *
+ terminal->char_height;
+ rect.height = terminal->char_height;
+ gtk_im_context_set_cursor_location(terminal->pvt->im_context, &rect);
+
#ifdef VTE_DEBUG
fprintf(stderr, "%d bytes left to process.\n",
terminal->pvt->n_incoming);
@@ -3571,6 +3607,78 @@ vte_terminal_feed_child(VteTerminal *terminal, const char *text, size_t length)
vte_terminal_send(terminal, "UTF-8", text, length);
}
+/* Send text from the input method to the child. */
+static void
+vte_terminal_im_commit(GtkIMContext *im_context, gchar *text, gpointer data)
+{
+ g_return_if_fail(VTE_IS_TERMINAL(data));
+#ifdef VTE_DEBUG
+ fprintf(stderr, "Input method committed `%s'.\n", text);
+#endif
+ vte_terminal_send(VTE_TERMINAL(data), "UTF-8", text, strlen(text));
+}
+
+/* We've started pre-editing. */
+static void
+vte_terminal_im_preedit_start(GtkIMContext *im_context, gpointer data)
+{
+ VteTerminal *terminal;
+
+ g_return_if_fail(VTE_IS_TERMINAL(data));
+ terminal = VTE_TERMINAL(data);
+ g_return_if_fail(GTK_IS_IM_CONTEXT(im_context));
+
+#ifdef VTE_DEBUG
+ fprintf(stderr, "Input method pre-edit started.\n");
+#endif
+}
+
+/* We've stopped pre-editing. */
+static void
+vte_terminal_im_preedit_end(GtkIMContext *im_context, gpointer data)
+{
+ VteTerminal *terminal;
+
+ g_return_if_fail(VTE_IS_TERMINAL(data));
+ terminal = VTE_TERMINAL(data);
+ g_return_if_fail(GTK_IS_IM_CONTEXT(im_context));
+
+#ifdef VTE_DEBUG
+ fprintf(stderr, "Input method pre-edit ended.\n");
+#endif
+}
+
+/* The pre-edit string changed. */
+static void
+vte_terminal_im_preedit_changed(GtkIMContext *im_context, gpointer data)
+{
+ gchar *str;
+ PangoAttrList *attrs;
+ VteTerminal *terminal;
+ gint cursor;
+
+ g_return_if_fail(VTE_IS_TERMINAL(data));
+ terminal = VTE_TERMINAL(data);
+ g_return_if_fail(GTK_IS_IM_CONTEXT(im_context));
+
+ gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor);
+#ifdef VTE_DEBUG
+ fprintf(stderr, "Input method pre-edit changed (%s,%d).\n",
+ str, cursor);
+#endif
+
+ vte_invalidate_cursor_once(terminal);
+
+ pango_attr_list_unref(attrs);
+ if (terminal->pvt->im_preedit != NULL) {
+ g_free(terminal->pvt->im_preedit);
+ }
+ terminal->pvt->im_preedit = str;
+ terminal->pvt->im_preedit_cursor = cursor;
+
+ vte_invalidate_cursor_once(terminal);
+}
+
/* Handle the toplevel being reconfigured. */
static gboolean
vte_terminal_configure_toplevel(GtkWidget *widget, GdkEventConfigure *event,
@@ -3635,17 +3743,27 @@ vte_terminal_key_press(GtkWidget *widget, GdkEventKey *event)
g_return_val_if_fail(VTE_IS_TERMINAL(widget), FALSE);
terminal = VTE_TERMINAL(widget);
+ /* If it's a keypress, record that we got the event, in case the
+ * input method takes the event from us. */
+ if (event->type == GDK_KEY_PRESS) {
+ if (gettimeofday(&tv, &tz) == 0) {
+ terminal->pvt->last_keypress_time =
+ (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+ }
+ }
+
+ /* Let the input method at this one first. */
+ if (gtk_im_context_filter_keypress(terminal->pvt->im_context, event)) {
+ return TRUE;
+ }
+
+ /* Now figure out what to send to the child. */
if (event->type == GDK_KEY_PRESS) {
/* Read the modifiers. */
if (gdk_event_get_state((GdkEvent*)event,
&modifiers) == FALSE) {
modifiers = 0;
}
- /* Record the last time the a key was pressed. */
- if (gettimeofday(&tv, &tz) == 0) {
- terminal->pvt->last_keypress_time =
- (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
- }
/* Map the key to a sequence name if we can. */
switch (event->keyval) {
case GDK_BackSpace:
@@ -4279,6 +4397,7 @@ vte_terminal_focus_in(GtkWidget *widget, GdkEventFocus *event)
{
g_return_val_if_fail(GTK_IS_WIDGET(widget), 0);
GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
+ gtk_im_context_focus_in((VTE_TERMINAL(widget))->pvt->im_context);
vte_invalidate_cursor_once(VTE_TERMINAL(widget));
return TRUE;
}
@@ -4288,53 +4407,128 @@ vte_terminal_focus_out(GtkWidget *widget, GdkEventFocus *event)
{
g_return_val_if_fail(GTK_WIDGET(widget), 0);
GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
+ gtk_im_context_focus_out((VTE_TERMINAL(widget))->pvt->im_context);
vte_invalidate_cursor_once(VTE_TERMINAL(widget));
return TRUE;
}
+static void
+vte_terminal_font_complain(const char *font,
+ char **missing_charset_list,
+ int missing_charset_count)
+{
+ int i;
+ char *charsets, *tmp;
+ if ((missing_charset_count > 0) && (missing_charset_list != NULL)) {
+ charsets = NULL;
+ for (i = 0; i < missing_charset_count; i++) {
+ if (charsets == NULL) {
+ tmp = g_strdup(missing_charset_list[i]);
+ } else {
+ tmp = g_strconcat(charsets, ", ",
+ missing_charset_list[i],
+ NULL);
+ g_free(charsets);
+ }
+ charsets = tmp;
+ tmp = NULL;
+ }
+ g_warning("Warning: using fontset \"%s\", which is missing "
+ "these character sets: %s.\n", font, charsets);
+ g_free(charsets);
+ }
+}
+
static int
xft_weight_from_pango_weight (int weight)
{
- /* cut-and-pasted from Pango */
- if (weight < (PANGO_WEIGHT_NORMAL + PANGO_WEIGHT_LIGHT) / 2)
- return XFT_WEIGHT_LIGHT;
- else if (weight < (PANGO_WEIGHT_NORMAL + 600) / 2)
- return XFT_WEIGHT_MEDIUM;
- else if (weight < (600 + PANGO_WEIGHT_BOLD) / 2)
- return XFT_WEIGHT_DEMIBOLD;
- else if (weight < (PANGO_WEIGHT_BOLD + PANGO_WEIGHT_ULTRABOLD) / 2)
- return XFT_WEIGHT_BOLD;
- else
- return XFT_WEIGHT_BLACK;
+ /* cut-and-pasted from Pango */
+ if (weight < (PANGO_WEIGHT_NORMAL + PANGO_WEIGHT_LIGHT) / 2)
+ return XFT_WEIGHT_LIGHT;
+ else if (weight < (PANGO_WEIGHT_NORMAL + 600) / 2)
+ return XFT_WEIGHT_MEDIUM;
+ else if (weight < (600 + PANGO_WEIGHT_BOLD) / 2)
+ return XFT_WEIGHT_DEMIBOLD;
+ else if (weight < (PANGO_WEIGHT_BOLD + PANGO_WEIGHT_ULTRABOLD) / 2)
+ return XFT_WEIGHT_BOLD;
+ else
+ return XFT_WEIGHT_BLACK;
}
static int
xft_slant_from_pango_style (int style)
{
- switch (style) {
- case PANGO_STYLE_NORMAL:
- return XFT_SLANT_ROMAN;
- break;
- case PANGO_STYLE_ITALIC:
- return XFT_SLANT_ITALIC;
- break;
- case PANGO_STYLE_OBLIQUE:
- return XFT_SLANT_OBLIQUE;
- break;
- }
+ switch (style) {
+ case PANGO_STYLE_NORMAL:
+ return XFT_SLANT_ROMAN;
+ break;
+ case PANGO_STYLE_ITALIC:
+ return XFT_SLANT_ITALIC;
+ break;
+ case PANGO_STYLE_OBLIQUE:
+ return XFT_SLANT_OBLIQUE;
+ break;
+ }
- return XFT_SLANT_ROMAN;
+ return XFT_SLANT_ROMAN;
}
+#ifdef HAVE_XFT
+/* Create an Xft pattern from a Pango font description. */
+static XftPattern *
+xft_pattern_from_pango_font_description(const PangoFontDescription *font_desc)
+{
+ XftPattern *pattern;
+ const char *family = "mono";
+ int pango_mask = 0;
+ int weight, style;
+ double size = 12.0;
+
+ if (font_desc != NULL) {
+ pango_mask = pango_font_description_get_set_fields (font_desc);
+ }
+
+ pattern = XftPatternCreate ();
+
+ /* Set the family for the pattern, or use a sensible default. */
+ if (pango_mask & PANGO_FONT_MASK_FAMILY) {
+ family = pango_font_description_get_family (font_desc);
+ }
+ XftPatternAddString (pattern, XFT_FAMILY, family);
+
+ /* Set the font size for the pattern, or use a sensible default. */
+ if (pango_mask & PANGO_FONT_MASK_SIZE) {
+ size = (double) pango_font_description_get_size (font_desc);
+ size /= (double) PANGO_SCALE;
+ }
+ XftPatternAddDouble (pattern, XFT_SIZE, size);
+
+ /* There aren'ty any fallbacks for these, so just omit them from the
+ * pattern if they're not set in the pango font. */
+ if (pango_mask & PANGO_FONT_MASK_WEIGHT) {
+ weight = pango_font_description_get_weight (font_desc);
+ XftPatternAddInteger (pattern, XFT_WEIGHT,
+ xft_weight_from_pango_weight (weight));
+ }
+ if (pango_mask & PANGO_FONT_MASK_STYLE) {
+ style = pango_font_description_get_style (font_desc);
+ XftPatternAddInteger (pattern, XFT_SLANT,
+ xft_slant_from_pango_style (style));
+ }
+
+ return pattern;
+}
+#endif
+
/* Set the fontset used for rendering text into the widget. */
static void
vte_terminal_setup_font(VteTerminal *terminal, const char *xlfds,
- const PangoFontDescription *font_desc)
+ const PangoFontDescription *font_desc)
{
long width, height, ascent, descent;
GtkWidget *widget;
XFontStruct **font_struct_list, font_struct;
- char **missing_charset_list, *def_string;
+ char **missing_charset_list, *def_string, *tmp;
int missing_charset_count;
char **font_name_list;
@@ -4344,137 +4538,132 @@ vte_terminal_setup_font(VteTerminal *terminal, const char *xlfds,
/* Choose default font metrics. I like '10x20' as a terminal font. */
if (xlfds == NULL) {
- xlfds = "-*-mincho-*-r-*-*-20-*-*-*-*-*-*-*";
- xlfds = "10x20";
+ xlfds = "-misc-fixed-medium-r-normal--20-*-*-*-*-*-*-*";
}
width = 10;
height = 20;
descent = 0;
ascent = height - descent;
-
+
#ifdef HAVE_XFT
if (terminal->pvt->use_xft) {
- XftFont *new_font;
- XftPattern *pattern;
- XftPattern *matched_pattern;
- XftResult result;
- PangoFontMask pango_mask;
+ XftFont *new_font;
+ XftPattern *pattern;
+ XftPattern *matched_pattern;
+ XftResult result;
#ifdef VTE_DEBUG
- if (font_desc) {
- char *debug;
- debug = pango_font_description_to_string (font_desc);
- fprintf (stderr, "pango font is \"%s\"\n", debug);
- g_free (debug);
- } else {
- fprintf (stderr, "pango font is null\n");
- }
+ if (font_desc) {
+ 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
-
- pango_mask = font_desc ? pango_font_description_get_set_fields (font_desc) : 0;
-
- /* Create Xft pattern */
- pattern = XftPatternCreate ();
-
- if (pango_mask & PANGO_FONT_MASK_FAMILY)
- XftPatternAddString (pattern, XFT_FAMILY,
- pango_font_description_get_family (font_desc));
- else
- XftPatternAddString (pattern, XFT_FAMILY, "mono");
-
- if (pango_mask & PANGO_FONT_MASK_SIZE)
- XftPatternAddDouble (pattern, XFT_SIZE,
- (double) pango_font_description_get_size (font_desc) / (double) PANGO_SCALE);
- else
- XftPatternAddDouble (pattern, XFT_SIZE, 12.0);
-
- /* No fallbacks for these, just omit them from the pattern if not set in the
- * pango font
- */
- if (pango_mask & PANGO_FONT_MASK_WEIGHT)
- XftPatternAddInteger (pattern, XFT_WEIGHT,
- xft_weight_from_pango_weight (pango_font_description_get_weight (font_desc)));
-
- if (pango_mask & PANGO_FONT_MASK_STYLE)
- XftPatternAddInteger (pattern, XFT_SLANT,
- xft_slant_from_pango_style (pango_font_description_get_style (font_desc)));
-
-
- /* Xft is on a lot of crack here - it fills in
- * "result" when it feels like it, and leaves it
- * uninitialized the rest of the time. Whether it's
- * filled in is impossible to determine afaict. We
- * don't care about its value anyhow.
- */
- result = 0xffff; /* some bogus value to help in debugging */
- matched_pattern = XftFontMatch (GDK_DISPLAY (),
- gdk_x11_get_default_screen (),
- pattern, &result);
-#ifdef VTE_DEBUG
- if (matched_pattern) {
- char buf[256];
- if (!XftNameUnparse (matched_pattern, buf, sizeof(buf)-1))
- buf[0] = '\0';
- fprintf (stderr, "Match pattern \"%s\"\n", buf);
- }
-#endif
+ pattern = xft_pattern_from_pango_font_description(font_desc);
+
+ /* Xft is on a lot of crack here - it fills in "result" when it
+ * feels like it, and leaves it uninitialized the rest of the
+ * time. Whether it's filled in is impossible to determine
+ * afaict. We don't care about its value anyhow. */
+ result = 0xffff; /* some bogus value to help in debugging */
+ matched_pattern = XftFontMatch (GDK_DISPLAY(),
+ gdk_x11_get_default_screen(),
+ pattern, &result);
#ifdef VTE_DEBUG
- fprintf (stderr, "font match result = %d\n", result);
+ if (matched_pattern != NULL) {
+ char buf[256];
+ if (!XftNameUnparse (matched_pattern, buf, sizeof(buf)-1)) {
+ buf[0] = '\0';
+ }
+ buf[sizeof(buf) - 1] = '\0';
+ fprintf (stderr, "Matched pattern \"%s\".\n", buf);
+ }
+
+ switch (result) {
+ case XftResultMatch:
+ fprintf(stderr, "matched.\n");
+ break;
+ case XftResultNoMatch:
+ fprintf(stderr, "no match.\n");
+ break;
+ case XftResultTypeMismatch:
+ fprintf(stderr, "type mismatch.\n");
+ break;
+ case XftResultNoId:
+ fprintf(stderr, "no ID.\n");
+ break;
+ default:
+ fprintf(stderr, "undefined/bogus result.\n");
+ break;
+ }
#endif
-
- if (matched_pattern) {
- g_assert (matched_pattern);
- /* More Xft crackrock - it appears to "adopt" matched_pattern
- * as new_font->pattern; whether it does this reliably
- * or not, or does another unpredictable bogosity
- * like the "result" field above, I don't know.
- */
- new_font = XftFontOpenPattern (GDK_DISPLAY (),
- matched_pattern);
- } else {
- new_font = NULL;
- }
-
- if (new_font == NULL) {
- char buf[256];
- if (!XftNameUnparse (matched_pattern, buf, sizeof(buf)-1))
- buf[0] = '\0';
-
- g_warning("Failed to load Xft font pattern \"%s\", falling back to default font.",
- buf);
-
- /* Try a fallback */
- new_font = XftFontOpen(GDK_DISPLAY(),
- gdk_x11_get_default_screen(),
- XFT_FAMILY, XftTypeString, "mono",
- XFT_SIZE, XftTypeDouble, 12.0,
- 0);
- }
-
- g_assert (pattern != new_font->pattern);
- XftPatternDestroy (pattern);
- if (matched_pattern && matched_pattern != new_font->pattern) {
- g_assert (matched_pattern != new_font->pattern);
- XftPatternDestroy (matched_pattern);
- }
-
- if (new_font) {
- char buf[256];
- if (!XftNameUnparse (new_font->pattern, buf, sizeof(buf)-1))
- buf[0] = '\0';
-
+
+ if (matched_pattern != NULL) {
+ /* More Xft crackrock - it appears to "adopt"
+ * matched_pattern as new_font->pattern; whether it
+ * does this reliably or not, or does another
+ * unpredictable bogosity like the "result" field
+ * above, I don't know.
+ */
+ new_font = XftFontOpenPattern(GDK_DISPLAY(),
+ matched_pattern);
+ } else {
+ new_font = NULL;
+ }
+
+ if (new_font == NULL) {
+ char buf[256];
+ if (!XftNameUnparse(matched_pattern, buf, sizeof(buf)-1)) {
+ buf[0] = '\0';
+ }
+ buf[sizeof(buf) - 1] = '\0';
+
+ g_warning("Failed to load Xft font pattern \"%s\", "
+ "falling back to default font.", buf);
+
+ /* Try to use the deafult font. */
+ new_font = XftFontOpen(GDK_DISPLAY(),
+ gdk_x11_get_default_screen(),
+ XFT_FAMILY, XftTypeString,
+ "mono",
+ XFT_SIZE, XftTypeDouble, 12.0,
+ 0);
+ }
+ if (new_font == NULL) {
+ g_warning("Failed to load default Xft font.");
+ }
+
+ g_assert (pattern != new_font->pattern);
+ XftPatternDestroy (pattern);
+ if ((matched_pattern != NULL) &&
+ (matched_pattern != new_font->pattern)) {
+ XftPatternDestroy (matched_pattern);
+ }
+
+ if (new_font) {
+ char buf[256];
+ if (!XftNameUnparse (new_font->pattern, buf, sizeof(buf)-1)) {
+ buf[0] = '\0';
+ }
+ buf[sizeof(buf) - 1] = '\0';
+
#ifdef VTE_DEBUG
- fprintf (stderr, "Opened new font %s\n", buf);
+ fprintf (stderr, "Opened new font `%s'.\n", buf);
#endif
-
- if (terminal->pvt->ftfont != NULL) {
- XftFontClose(GDK_DISPLAY(), terminal->pvt->ftfont);
- }
- terminal->pvt->ftfont = new_font;
- }
-
+
+ /* Dispose of any previously-opened font. */
+ if (terminal->pvt->ftfont != NULL) {
+ XftFontClose(GDK_DISPLAY(),
+ terminal->pvt->ftfont);
+ }
+ terminal->pvt->ftfont = new_font;
+ }
+
+ /* Read the metrics for the current font. */
if (terminal->pvt->ftfont != NULL) {
ascent = terminal->pvt->ftfont->ascent;
descent = terminal->pvt->ftfont->descent;
@@ -4487,38 +4676,65 @@ vte_terminal_setup_font(VteTerminal *terminal, const char *xlfds,
}
#endif
- if (!terminal->pvt->use_xft) {
- /* Load the font set, freeing another one if we loaded one before. */
- if (terminal->pvt->fontset) {
- XFreeFontSet(GDK_DISPLAY(), terminal->pvt->fontset);
- }
- terminal->pvt->fontset = XCreateFontSet(GDK_DISPLAY(),
- xlfds,
- &missing_charset_list,
- &missing_charset_count,
- &def_string);
- g_return_if_fail(terminal->pvt->fontset != NULL);
- XFreeStringList(missing_charset_list);
- missing_charset_list = NULL;
- /* Read the font metrics. */
- if (XFontsOfFontSet(terminal->pvt->fontset,
- &font_struct_list,
- &font_name_list)) {
- if (font_struct_list) {
- if (font_struct_list[0]) {
- font_struct = font_struct_list[0][0];
- width = font_struct.max_bounds.width;
- ascent = font_struct.max_bounds.ascent;
- descent = font_struct.max_bounds.descent;
- height = ascent + descent;
- }
- }
- XFreeStringList(font_name_list);
- font_name_list = NULL;
- }
- }
-
- /* Now save the values. */
+ if (!terminal->pvt->use_xft) {
+ /* Load the font set, freeing another one if we loaded one
+ * before. */
+ if (terminal->pvt->fontset) {
+ XFreeFontSet(GDK_DISPLAY(), terminal->pvt->fontset);
+ }
+ terminal->pvt->fontset = XCreateFontSet(GDK_DISPLAY(),
+ xlfds,
+ &missing_charset_list,
+ &missing_charset_count,
+ &def_string);
+ if (terminal->pvt->fontset != NULL) {
+ vte_terminal_font_complain(xlfds, missing_charset_list,
+ missing_charset_count);
+ } else {
+ g_warning("Failed to load font set \"%s\", "
+ "falling back to default font.", xlfds);
+ if (missing_charset_list != NULL) {
+ XFreeStringList(missing_charset_list);
+ missing_charset_list = NULL;
+ }
+ terminal->pvt->fontset = XCreateFontSet(GDK_DISPLAY(),
+ "fixed",
+ &missing_charset_list,
+ &missing_charset_count,
+ &def_string);
+ if (terminal->pvt->fontset == NULL) {
+ g_warning("Failed to load default font, "
+ "crashing or behaving abnormally.\n");
+ } else {
+ vte_terminal_font_complain(xlfds,
+ missing_charset_list,
+ missing_charset_count);
+ }
+ }
+ g_return_if_fail(terminal->pvt->fontset != NULL);
+ if (missing_charset_list != NULL) {
+ XFreeStringList(missing_charset_list);
+ missing_charset_list = NULL;
+ }
+ /* Read the font metrics. */
+ if (XFontsOfFontSet(terminal->pvt->fontset,
+ &font_struct_list,
+ &font_name_list)) {
+ if (font_struct_list) {
+ if (font_struct_list[0]) {
+ font_struct = font_struct_list[0][0];
+ width = font_struct.max_bounds.width;
+ ascent = font_struct.max_bounds.ascent;
+ descent = font_struct.max_bounds.descent;
+ height = ascent + descent;
+ }
+ }
+ XFreeStringList(font_name_list);
+ font_name_list = NULL;
+ }
+ }
+
+ /* Now save the values. */
terminal->char_width = width;
terminal->char_height = height;
terminal->char_ascent = ascent;
@@ -4532,10 +4748,10 @@ vte_terminal_setup_font(VteTerminal *terminal, const char *xlfds,
}
void
-vte_terminal_set_font (VteTerminal *terminal,
- const PangoFontDescription *font_desc)
+vte_terminal_set_font(VteTerminal *terminal,
+ const PangoFontDescription *font_desc)
{
- vte_terminal_setup_font (terminal, NULL, font_desc);
+ vte_terminal_setup_font (terminal, NULL, font_desc);
}
/* A comparison function which helps sort quarks. */
@@ -4867,6 +5083,9 @@ vte_terminal_init(VteTerminal *terminal)
g_signal_connect(G_OBJECT(terminal), "hierarchy-changed",
G_CALLBACK(vte_terminal_hierarchy_changed),
NULL);
+
+ /* Set up input method support. */
+ pvt->im_context = NULL;
}
/* Tell GTK+ how much space we need. */
@@ -4940,6 +5159,10 @@ vte_terminal_unrealize(GtkWidget *widget)
g_return_if_fail(VTE_IS_TERMINAL(widget));
terminal = VTE_TERMINAL(widget);
+ /* Shut down input methods. */
+ g_object_unref(G_OBJECT(terminal->pvt->im_context));
+ terminal->pvt->im_context = NULL;
+
/* Free the color palette. */
;
@@ -5080,6 +5303,18 @@ vte_terminal_finalize(GObject *object)
}
}
+/* Reset the input method context. */
+static void
+vte_terminal_im_reset(VteTerminal *terminal)
+{
+ g_return_if_fail(VTE_IS_TERMINAL(terminal));
+ gtk_im_context_reset(terminal->pvt->im_context);
+ if (terminal->pvt->im_preedit != NULL) {
+ g_free(terminal->pvt->im_preedit);
+ terminal->pvt->im_preedit = NULL;
+ }
+}
+
/* Handle realizing the widget. Most of this is copy-paste from GGAD. */
static void
vte_terminal_realize(GtkWidget *widget)
@@ -5133,6 +5368,24 @@ vte_terminal_realize(GtkWidget *widget)
vte_terminal_filter_property_changes,
terminal);
+ /* Set up input method support. FIXME: do we need to handle the
+ * "retrieve-surrounding" and "delete-surrounding" events? */
+ terminal->pvt->im_context = gtk_im_multicontext_new();
+ gtk_im_context_set_client_window(terminal->pvt->im_context,
+ widget->window);
+ g_signal_connect(G_OBJECT(terminal->pvt->im_context), "commit",
+ GTK_SIGNAL_FUNC(vte_terminal_im_commit), terminal);
+ g_signal_connect(G_OBJECT(terminal->pvt->im_context), "preedit-start",
+ GTK_SIGNAL_FUNC(vte_terminal_im_preedit_start),
+ terminal);
+ g_signal_connect(G_OBJECT(terminal->pvt->im_context), "preedit-changed",
+ GTK_SIGNAL_FUNC(vte_terminal_im_preedit_changed),
+ terminal);
+ g_signal_connect(G_OBJECT(terminal->pvt->im_context), "preedit-end",
+ GTK_SIGNAL_FUNC(vte_terminal_im_preedit_end),
+ terminal);
+ gtk_im_context_set_use_preedit(terminal->pvt->im_context, TRUE);
+
/* Grab input focus. */
gtk_widget_grab_focus(widget);
}
@@ -5524,7 +5777,7 @@ vte_terminal_paint(GtkWidget *widget, GdkRectangle *area)
Visual *visual;
GdkGC *ggc;
GC gc;
- struct vte_charcell *cell;
+ struct vte_charcell *cell, im_cell;
int row, drow, col, row_stop, col_stop, x_offs = 0, y_offs = 0;
long width, height, ascent, descent, delta;
struct timezone tz;
@@ -5585,21 +5838,6 @@ vte_terminal_paint(GtkWidget *widget, GdkRectangle *area)
}
#endif
-#if 0
- /* Paint the background for this area, using a filled rectangle. We
- * have to do this even when the GDK background matches, otherwise
- * we may miss character removals before an area is re-exposed. */
- if (terminal->pvt->bg_image == NULL) {
- XSetForeground(display, gc,
- terminal->pvt->palette[VTE_DEF_BG].pixel);
- XFillRectangle(display, drawable, gc,
- area->x - x_offs,
- area->y - y_offs,
- area->width,
- area->height);
- }
-#endif
-
/* Keep local copies of rendering information. */
width = terminal->char_width;
height = terminal->char_height;
@@ -5673,9 +5911,13 @@ vte_terminal_paint(GtkWidget *widget, GdkRectangle *area)
#endif
/* Get the character under the cursor. */
col = screen->cursor_current.col;
+ if (terminal->pvt->im_preedit != NULL) {
+ col += terminal->pvt->im_preedit_cursor;
+ }
drow = screen->cursor_current.row;
row = drow - delta;
cell = vte_terminal_find_charcell(terminal, drow, col);
+
/* Draw the cursor. */
delta = screen->scroll_delta;
if (GTK_WIDGET_HAS_FOCUS(GTK_WIDGET(terminal))) {
@@ -5710,6 +5952,80 @@ vte_terminal_paint(GtkWidget *widget, GdkRectangle *area)
}
}
+ /* Draw the pre-edit string (if one exists) over the cursor. */
+ if (terminal->pvt->im_preedit) {
+ int i, len;
+ char *preedit;
+ drow = screen->cursor_current.row;
+ row = drow - delta;
+ memset(&im_cell, 0, sizeof(im_cell));
+ im_cell.fore = screen->defaults.fore;
+ im_cell.back = screen->defaults.back;
+ im_cell.columns = 1;
+
+ /* If the pre-edit string won't fit on the screen, drop initial
+ * characters until it does. */
+ preedit = terminal->pvt->im_preedit;
+ len = strlen(preedit);
+ col = screen->cursor_current.col;
+ if ((col + len) > terminal->column_count) {
+ preedit += ((col + len) - terminal->column_count);
+ }
+ len = strlen(preedit);
+
+ /* Draw the preedit string, one character at a time. Fill the
+ * background to prevent double-draws. */
+ for (i = 0; i < len; i++) {
+ im_cell.c = preedit[i];
+ col = screen->cursor_current.col + i;
+#ifdef VTE_DEBUG
+#ifdef VTE_DEBUG_DRAW
+ fprintf(stderr, "Drawing preedit[%d] = %c.\n",
+ i + (preedit - terminal->pvt->im_preedit),
+ preedit[i]);
+#endif
+#endif
+ XSetForeground(display, gc,
+ terminal->pvt->palette[im_cell.back].pixel);
+ XFillRectangle(display,
+ drawable,
+ gc,
+ col * width - x_offs,
+ row * height - y_offs,
+ width,
+ height);
+ vte_terminal_draw_char(terminal, screen, &im_cell,
+ col,
+ drow,
+ col * width - x_offs,
+ row * height - y_offs,
+ width, height,
+ ascent, descent,
+ display,
+ gdrawable, drawable,
+ gcolormap, colormap,
+ gvisual, visual,
+ gc,
+#ifdef HAVE_XFT
+ ftdraw,
+#endif
+ FALSE);
+ }
+ if (len > 0) {
+ /* Draw a rectangle around the pre-edit string, to help
+ * distinguish it from other text. */
+ XSetForeground(display, gc,
+ terminal->pvt->palette[im_cell.fore].pixel);
+ XDrawRectangle(display,
+ drawable,
+ gc,
+ screen->cursor_current.col * width - x_offs,
+ row * height - y_offs,
+ len * width - 1,
+ height - 1);
+ }
+ }
+
/* Done with various structures. */
#ifdef HAVE_XFT
if (ftdraw != NULL) {
@@ -5869,6 +6185,16 @@ vte_terminal_paste_clipboard(VteTerminal *terminal)
vte_terminal_paste(terminal, GDK_SELECTION_CLIPBOARD);
}
+/* Append the menu items for our input method context to the given shell. */
+void
+vte_terminal_im_append_menuitems(VteTerminal *terminal, GtkMenuShell *menushell)
+{
+ GtkIMMulticontext *context;
+ g_return_if_fail(VTE_IS_TERMINAL(terminal));
+ context = GTK_IM_MULTICONTEXT(terminal->pvt->im_context);
+ gtk_im_multicontext_append_menuitems(context, menushell);
+}
+
/* Set up whatever background we want. */
static void
vte_terminal_setup_background(VteTerminal *terminal, gboolean fresh_transparent)
@@ -6160,9 +6486,17 @@ vte_terminal_set_background_transparent(VteTerminal *terminal, gboolean setting)
gboolean
vte_terminal_get_has_selection(VteTerminal *terminal)
{
+ g_return_val_if_fail(VTE_IS_TERMINAL(terminal), FALSE);
return (terminal->pvt->selection != FALSE);
}
+gboolean
+vte_terminal_get_using_xft(VteTerminal *terminal)
+{
+ g_return_val_if_fail(VTE_IS_TERMINAL(terminal), FALSE);
+ return (terminal->pvt->use_xft);
+}
+
void
vte_terminal_set_cursor_blinks(VteTerminal *terminal, gboolean blink)
{
diff --git a/src/vte.h b/src/vte.h
index e870476..e96cf1d 100644
--- a/src/vte.h
+++ b/src/vte.h
@@ -111,7 +111,6 @@ void vte_terminal_set_colors(VteTerminal *terminal,
size_t palette_size);
void vte_terminal_set_default_colors(VteTerminal *terminal);
void vte_terminal_set_background_image(VteTerminal *terminal, GdkPixbuf *image);
-void vte_terminal_set_background_image(VteTerminal *terminal, GdkPixbuf *image);
void vte_terminal_set_background_image_file(VteTerminal *terminal,
const char *path);
void vte_terminal_set_background_saturation(VteTerminal *terminal,
@@ -121,7 +120,9 @@ void vte_terminal_set_background_transparent(VteTerminal *terminal,
void vte_terminal_set_cursor_blinks(VteTerminal *terminal, gboolean blink);
void vte_terminal_set_blink_period(VteTerminal *terminal, guint period);
gboolean vte_terminal_get_has_selection(VteTerminal *terminal);
-
+gboolean vte_terminal_get_using_xft(VteTerminal *terminal);
+void vte_terminal_im_append_menuitems(VteTerminal *terminal,
+ GtkMenuShell *menushell);
void vte_terminal_set_font (VteTerminal *terminal,
const PangoFontDescription *font_desc);