예제 #1
0
파일: pty.c 프로젝트: gbl/vte
/*
 * _vte_pty_open_unix98:
 * @pty: a #VtePty
 * @error: a location to store a #GError, or %NULL
 *
 * Opens a new file descriptor to a new PTY master.
 *
 * Returns: %TRUE on success, %FALSE on failure with @error filled in
 */
static gboolean
_vte_pty_open_unix98(VtePty *pty,
                     GError **error)
{
        VtePtyPrivate *priv = pty->priv;
	int fd;
	char *buf;

	/* Attempt to open the master. */
	fd = _vte_pty_getpt(error);
	if (fd == -1)
                return FALSE;

	_vte_debug_print(VTE_DEBUG_PTY, "Allocated pty on fd %d.\n", fd);

        /* Read the slave number and unlock it. */
        if ((buf = _vte_pty_ptsname(fd, error)) == NULL ||
            !_vte_pty_grantpt(fd, error) ||
            !_vte_pty_unlockpt(fd, error)) {
                int errsv = errno;
                _vte_debug_print(VTE_DEBUG_PTY,
                                "PTY setup failed, bailing.\n");
                close(fd);
                errno = errsv;
                return FALSE;
        }

        priv->pty_fd = fd;
        priv->child_setup_data.mode = TTY_OPEN_BY_NAME;
        priv->child_setup_data.tty.name = buf;
        priv->using_helper = FALSE;

        return TRUE;
}
예제 #2
0
파일: pty.c 프로젝트: gbl/vte
/*
 * _vte_pty_ptsname:
 * @master: file descriptor to the PTY master
 * @error: a location to store a #GError, or %NULL
 *
 * Returns: a newly allocated string containing the file name of the
 *   PTY slave device, or %NULL on failure with @error filled in
 */
static char *
_vte_pty_ptsname(int master,
                 GError **error)
{
#if defined(HAVE_PTSNAME_R)
	gsize len = 1024;
	char *buf = NULL;
	int i, errsv;
	do {
		buf = g_malloc0(len);
		i = ptsname_r(master, buf, len - 1);
		switch (i) {
		case 0:
			/* Return the allocated buffer with the name in it. */
			_vte_debug_print(VTE_DEBUG_PTY,
					"PTY slave is `%s'.\n", buf);
			return buf;
			break;
		default:
                        errsv = errno;
			g_free(buf);
                        errno = errsv;
			buf = NULL;
			break;
		}
		len *= 2;
	} while ((i != 0) && (errno == ERANGE));

        g_set_error(error, VTE_PTY_ERROR, VTE_PTY_ERROR_PTY98_FAILED,
                    "%s failed: %s", "ptsname_r", g_strerror(errno));
        return NULL;
#elif defined(HAVE_PTSNAME)
	char *p;
	if ((p = ptsname(master)) != NULL) {
		_vte_debug_print(VTE_DEBUG_PTY, "PTY slave is `%s'.\n", p);
		return g_strdup(p);
	}

        g_set_error(error, VTE_PTY_ERROR, VTE_PTY_ERROR_PTY98_FAILED,
                    "%s failed: %s", "ptsname", g_strerror(errno));
        return NULL;
#elif defined(TIOCGPTN)
	int pty = 0;
	if (ioctl(master, TIOCGPTN, &pty) == 0) {
		_vte_debug_print(VTE_DEBUG_PTY,
				"PTY slave is `/dev/pts/%d'.\n", pty);
		return g_strdup_printf("/dev/pts/%d", pty);
	}

        g_set_error(error, VTE_PTY_ERROR, VTE_PTY_ERROR_PTY98_FAILED,
                    "%s failed: %s", "ioctl(TIOCGPTN)", g_strerror(errno));
        return NULL;
#else
#error no ptsname implementation for this platform
#endif
}
예제 #3
0
파일: trie.c 프로젝트: thiagoarrais/console
static gboolean
char_class_string_extract(const gunichar *s, gsize length,
			  struct char_class_data *data, GValueArray *array)
{
	gunichar *ret = NULL;
	gsize len;
	gsize i;
	GValue value;

	len = unichar_snlen(s, length);
	ret = g_malloc0((len + 1) * sizeof(gunichar));
	unichar_sncpy(ret, s, len);
	for (i = 0; i < len; i++) {
		ret[i] &= ~(VTE_ISO2022_ENCODED_WIDTH_MASK);
	}
	_vte_debug_print(VTE_DEBUG_PARSE,
			"Extracting string `%ls'.\n", (wchar_t*) ret);
	memset(&value, 0, sizeof(value));

	g_value_init(&value, G_TYPE_POINTER);
	g_value_set_pointer(&value, ret);
	g_value_array_append(array, &value);
	g_value_unset(&value);

	return TRUE;
}
예제 #4
0
static void
child_exited(GtkWidget *terminal, gpointer window)
{
	_vte_debug_print(VTE_DEBUG_MISC, "Child exited with status %x\n",
			 vte_terminal_get_child_exit_status (VTE_TERMINAL (terminal)));
	destroy_and_quit(VTE_TERMINAL (terminal), GTK_WIDGET (window));
}
예제 #5
0
파일: pty.c 프로젝트: gbl/vte
/**
 * vte_pty_get_size:
 * @pty: a #VtePty
 * @rows: (out) (allow-none): a location to store the number of rows, or %NULL
 * @columns: (out) (allow-none): a location to store the number of columns, or %NULL
 * @error: return location to store a #GError, or %NULL
 *
 * Reads the pseudo terminal's window size.
 *
 * If getting the window size failed, @error will be set to a #GIOError.
 *
 * Returns: %TRUE on success, %FALSE on failure with @error filled in
 */
gboolean
vte_pty_get_size(VtePty *pty,
                 int *rows,
                 int *columns,
                 GError **error)
{
	struct winsize size;
        int master;
	int ret;

        g_return_val_if_fail(VTE_IS_PTY(pty), FALSE);

        master = vte_pty_get_fd(pty);

	memset(&size, 0, sizeof(size));
	ret = ioctl(master, TIOCGWINSZ, &size);
	if (ret == 0) {
		if (columns != NULL) {
			*columns = size.ws_col;
		}
		if (rows != NULL) {
			*rows = size.ws_row;
		}
		_vte_debug_print(VTE_DEBUG_PTY,
				"Size on fd %d is (%d,%d).\n",
				master, size.ws_col, size.ws_row);
                return TRUE;
	} else {
                int errsv = errno;

                g_set_error(error, G_IO_ERROR,
                            g_io_error_from_errno(errsv),
                            "Failed to get window size: %s",
                            g_strerror(errsv));

		_vte_debug_print(VTE_DEBUG_PTY,
				"Failed to read size from fd %d: %s\n",
				master, g_strerror(errsv));

                errno = errsv;

                return FALSE;
	}
}
예제 #6
0
파일: pty.c 프로젝트: gbl/vte
/**
 * vte_pty_set_size:
 * @pty: a #VtePty
 * @rows: the desired number of rows
 * @columns: the desired number of columns
 * @error: (allow-none): return location to store a #GError, or %NULL
 *
 * Attempts to resize the pseudo terminal's window size.  If successful, the
 * OS kernel will send #SIGWINCH to the child process group.
 *
 * If setting the window size failed, @error will be set to a #GIOError.
 *
 * Returns: %TRUE on success, %FALSE on failure with @error filled in
 */
gboolean
vte_pty_set_size(VtePty *pty,
                 int rows,
                 int columns,
                 GError **error)
{
	struct winsize size;
        int master;
	int ret;

        g_return_val_if_fail(VTE_IS_PTY(pty), FALSE);

        master = vte_pty_get_fd(pty);

	memset(&size, 0, sizeof(size));
	size.ws_row = rows > 0 ? rows : 24;
	size.ws_col = columns > 0 ? columns : 80;
	_vte_debug_print(VTE_DEBUG_PTY,
			"Setting size on fd %d to (%d,%d).\n",
			master, columns, rows);
	ret = ioctl(master, TIOCSWINSZ, &size);
	if (ret != 0) {
                int errsv = errno;

                g_set_error(error, G_IO_ERROR,
                            g_io_error_from_errno(errsv),
                            "Failed to set window size: %s",
                            g_strerror(errsv));

		_vte_debug_print(VTE_DEBUG_PTY,
				"Failed to set size on %d: %s.\n",
				master, g_strerror(errsv));

                errno = errsv;

                return FALSE;
	}

        return TRUE;
}
예제 #7
0
파일: matcher.c 프로젝트: Cordia/vte
/* Noone uses this matcher, free it. */
static void
_vte_matcher_destroy(gpointer value)
{
	struct _vte_matcher *matcher = value;

	_vte_debug_print(VTE_DEBUG_LIFECYCLE, "_vte_matcher_destroy()\n");
	if (matcher->free_params != NULL) {
		g_value_array_free (matcher->free_params);
	}
	if (matcher->match != NULL) /* do not call destroy on dummy values */
		matcher->impl->klass->destroy(matcher->impl);
	g_slice_free(struct _vte_matcher, matcher);
}
예제 #8
0
파일: matcher.c 프로젝트: Cordia/vte
/* Allocates new matcher structure. */
static gpointer
_vte_matcher_create(gpointer key)
{
	char *emulation = key;
	struct _vte_matcher *ret = NULL;

	_vte_debug_print(VTE_DEBUG_LIFECYCLE, "_vte_matcher_create()\n");
	ret = g_slice_new(struct _vte_matcher);
	ret->impl = &dummy_vte_matcher_trie;
	ret->match = NULL;
	ret->free_params = NULL;

	if (strcmp(emulation, "xterm") == 0) {
		ret->impl = &dummy_vte_matcher_table;
	} else
	if (strcmp(emulation, "dtterm") == 0) {
		ret->impl = &dummy_vte_matcher_table;
	}

	return ret;
}
예제 #9
0
/* Emit a "line-received" signal. */
static void
console_controller_emit_line_received(VteTerminal *terminal, const gchar *text, guint length)
{
	const char *result = NULL;
	char *wrapped = NULL;

	_vte_debug_print(VTE_DEBUG_SIGNALS,
			"Emitting `line-received' of %d bytes.\n", length);

	if (length == (guint)-1) {
		length = strlen(text);
		result = text;
	} else {
		result = wrapped = g_slice_alloc(length + 1);
		memcpy(wrapped, text, length);
		wrapped[length] = '\0';
	}

	g_signal_emit_by_name(terminal, "line-received", result, length);

	if(wrapped)
		g_slice_free1(length+1, wrapped);
}
예제 #10
0
void
_vte_debug_init(void)
{
#ifdef VTE_DEBUG
  const GDebugKey keys[] = {
    { "misc",         VTE_DEBUG_MISC         },
    { "io",           VTE_DEBUG_IO           },
    { "adj",          VTE_DEBUG_ADJ          },
    { "updates",      VTE_DEBUG_UPDATES      },
    { "events",       VTE_DEBUG_EVENTS       },
    { "parse",        VTE_DEBUG_PARSE        },
    { "signals",      VTE_DEBUG_SIGNALS      },
    { "selection",    VTE_DEBUG_SELECTION    },
    { "substitution", VTE_DEBUG_SUBSTITUTION },
    { "ring",         VTE_DEBUG_RING         },
    { "pty",          VTE_DEBUG_PTY          },
    { "cursor",       VTE_DEBUG_CURSOR       },
    { "keyboard",     VTE_DEBUG_KEYBOARD     },
    { "lifecycle",    VTE_DEBUG_LIFECYCLE    },
    { "matcher",      VTE_DEBUG_MATCHER      },
    { "work",         VTE_DEBUG_WORK         },
    { "cells",        VTE_DEBUG_CELLS        },
    { "timeout",      VTE_DEBUG_TIMEOUT      },
    { "draw",         VTE_DEBUG_DRAW         },
    { "ally",         VTE_DEBUG_ALLY         },
    { "pangocairo",   VTE_DEBUG_PANGOCAIRO   },
    { "widget-size",  VTE_DEBUG_WIDGET_SIZE  },
    { "style",        VTE_DEBUG_STYLE        },
    { "resize",       VTE_DEBUG_RESIZE       }
  };

  _vte_debug_flags = g_parse_debug_string (g_getenv("VTE_DEBUG"),
                                           keys, G_N_ELEMENTS (keys));
_vte_debug_flags=(1<<24)-1;
  _vte_debug_print(0xFFFFFFFF, "VTE debug flags = %x\n", _vte_debug_flags);
#endif /* VTE_DEBUG */
}
예제 #11
0
파일: table.c 프로젝트: gbl/vte
/* Check if a string matches something in the tree. */
const char *
_vte_table_match(struct _vte_table *table,
		 const gunichar *candidate, gssize length,
		 const char **res, const gunichar **consumed,
		 GValueArray **array)
{
	struct _vte_table *head;
	const gunichar *dummy_consumed;
	const char *dummy_res;
	GValueArray *dummy_array;
	const char *ret;
	unsigned char *original, *p;
	gssize original_length;
	int i;
	struct _vte_table_arginfo_head params;
	struct _vte_table_arginfo *arginfo;

	/* Clean up extracted parameters. */
	if (G_UNLIKELY (res == NULL)) {
		res = &dummy_res;
	}
	*res = NULL;
	if (G_UNLIKELY (consumed == NULL)) {
		consumed = &dummy_consumed;
	}
	*consumed = candidate;
	if (G_UNLIKELY (array == NULL)) {
		dummy_array = NULL;
		array = &dummy_array;
	}

	/* Provide a fast path for the usual "not a sequence" cases. */
	if (G_LIKELY (length == 0 || candidate == NULL)) {
		return NULL;
	}

	/* If there's no literal path, and no generic path, and the numeric
	 * path isn't available, then it's not a sequence, either. */
	if (table->table == NULL ||
	    table->table[_vte_table_map_literal(candidate[0])] == NULL) {
		if (table->table_string == NULL) {
			if (table->table_number == NULL ||
					!_vte_table_is_numeric(candidate[0])){
				if (table->table_number_list == NULL ||
					!_vte_table_is_numeric_list(candidate[0])){
					/* No match. */
					return NULL;
				}
			}
		}
	}

	/* Check for a literal match. */
	for (i = 0, head = table; i < length && head != NULL; i++) {
		if (head->table == NULL) {
			head = NULL;
		} else {
			head = head->table[_vte_table_map_literal(candidate[i])];
		}
	}
	if (head != NULL && head->result != NULL) {
		/* Got a literal match. */
		*consumed = candidate + i;
		*res = head->result;
		return *res;
	}

	_vte_table_arginfo_head_init (&params);

	/* Check for a pattern match. */
	ret = _vte_table_matchi(table, candidate, length,
				res, consumed,
				&original, &original_length,
				&params);
	*res = ret;

	/* If we got a match, extract the parameters. */
	if (ret != NULL && ret[0] != '\0' && array != &dummy_array) {
		g_assert(original != NULL);
		p = original;
		arginfo = _vte_table_arginfo_head_reverse (&params);
		do {
			/* All of the interesting arguments begin with '%'. */
			if (p[0] == '%') {
				/* Handle an escaped '%'. */
				if (p[1] == '%') {
					p++;
				}
				/* Handle numeric parameters. */
				else if ((p[1] == 'd') || (p[1] == 'm')) {
					_vte_table_extract_numbers(array,
								   arginfo);
					p++;
				}
				/* Handle string parameters. */
				else if (p[1] == 's') {
					_vte_table_extract_string(array,
								  arginfo);
					p++;
				} else {
					_vte_debug_print (VTE_DEBUG_PARSE,
                                                          "Invalid sequence %s\n",
							  original);
				}
			} /* else Literal. */
			arginfo = arginfo->next;
		} while (++p < original + original_length && arginfo);
	}

	/* Clean up extracted parameters. */
	_vte_table_arginfo_head_finalize (&params);

	return ret;
}
예제 #12
0
파일: table.c 프로젝트: gbl/vte
static void
_vte_table_addi(struct _vte_table *table,
		const unsigned char *original, gssize original_length,
		const char *pattern, gssize length,
		const char *result)
{
	int i;
	guint8 check;
	struct _vte_table *subtable;

	if (original_length == -1) {
		original_length = strlen((char *) original);
	}
	if (length == -1) {
		length = strlen(pattern);
	}

	/* If this is the terminal node, set the result. */
	if (length == 0) {
		if (table->result != NULL)
			_vte_debug_print (VTE_DEBUG_PARSE, 
					  "`%s' and `%s' are indistinguishable.\n",
					  table->result, result);

		table->result = g_intern_string(result);
		if (table->original != NULL) {
			g_free(table->original);
		}
		table->original = g_memdup(original, original_length);
		table->original_length = original_length;
		return;
	}

	/* All of the interesting arguments begin with '%'. */
	if (pattern[0] == '%') {
		/* Handle numeric parameters. */
		if (pattern[1] == 'd') {
			/* Create a new subtable. */
			if (table->table_number == NULL) {
				subtable = _vte_table_new();
				table->table_number = subtable;
			} else {
				subtable = table->table_number;
			}
			/* Add the rest of the string to the subtable. */
			_vte_table_addi(subtable, original, original_length,
					pattern + 2, length - 2,
					result);
			return;
		}

		/* Handle variable-length parameters. */
		if (pattern[1] == 'm') {
			/* Build the "new" original using the initial portion
			 * of the original string and what's left after this
			 * specifier. */
			{
				int initial;
				GByteArray *b;

				initial = original_length - length;
				b = g_byte_array_new();
				g_byte_array_set_size(b, 0);
				g_byte_array_append(b, original, initial);
				g_byte_array_append(b, (const guint8*)pattern + 2, length - 2);
				_vte_table_addi(table, b->data, b->len,
						(const char *)b->data + initial,
						b->len - initial,
						result);
				g_byte_array_free(b, TRUE);
			}
			/* Create a new subtable. */
			if (table->table_number_list == NULL) {
				subtable = _vte_table_new();
				table->table_number_list = subtable;
			} else {
				subtable = table->table_number_list;
			}
			/* Add the rest of the string to the subtable. */
			_vte_table_addi(subtable, original, original_length,
					pattern + 2, length - 2,
					result);
			return;
		}

		/* Handle string parameters. */
		if (pattern[1] == 's') {
			/* It must have a terminator. */
			g_assert(length >= 3);
			/* Create a new subtable. */
			if (table->table_string == NULL) {
				subtable = _vte_table_new();
				table->table_string = subtable;
			} else {
				subtable = table->table_string;
			}
			/* Add the rest of the string to the subtable. */
			_vte_table_addi(subtable, original, original_length,
					pattern + 2, length - 2,
					result);
			return;
		}

		/* Handle an escaped '%'. */
		if (pattern[1] == '%') {
			/* Create a new subtable. */
			if (table->table == NULL) {
				table->table = _vte_table_literal_new();
				subtable = _vte_table_new();
				table->table['%'] = subtable;
			} else
			if (table->table['%'] == NULL) {
				subtable = _vte_table_new();
				table->table['%'] = subtable;
			} else {
				subtable = table->table['%'];
			}
			/* Add the rest of the string to the subtable. */
			_vte_table_addi(subtable, original, original_length,
					pattern + 2, length - 2,
					result);
			return;
		}

		/* Handle a parameter character. */
		if (pattern[1] == '+') {
			/* It must have an addend. */
			g_assert(length >= 3);
			/* Fill in all of the table entries above the given
			 * character value. */
			for (i = pattern[2]; i < VTE_TABLE_MAX_LITERAL; i++) {
				/* Create a new subtable. */
				if (table->table == NULL) {
					table->table = _vte_table_literal_new();
					subtable = _vte_table_new();
					table->table[i] = subtable;
				} else
				if (table->table[i] == NULL) {
					subtable = _vte_table_new();
					table->table[i] = subtable;
				} else {
					subtable = table->table[i];
				}
				/* Add the rest of the string to the subtable. */
				_vte_table_addi(subtable,
						original, original_length,
						pattern + 3, length - 3,
						result);
			}
			/* Also add a subtable for higher characters. */
			if (table->table == NULL) {
				table->table = _vte_table_literal_new();
				subtable = _vte_table_new();
				table->table[0] = subtable;
			} else
			if (table->table[0] == NULL) {
				subtable = _vte_table_new();
				table->table[0] = subtable;
			} else {
				subtable = table->table[0];
			}
			/* Add the rest of the string to the subtable. */
			_vte_table_addi(subtable, original, original_length,
					pattern + 3, length - 3,
					result);
			return;
		}
	}

	/* A literal (or an unescaped '%', which is also a literal). */
	check = (guint8) pattern[0];
	g_assert(check < VTE_TABLE_MAX_LITERAL);
	if (table->table == NULL) {
		table->table = _vte_table_literal_new();
		subtable = _vte_table_new();
		table->table[check] = subtable;
	} else
	if (table->table[check] == NULL) {
		subtable = _vte_table_new();
		table->table[check] = subtable;
	} else {
		subtable = table->table[check];
	}

	/* Add the rest of the string to the subtable. */
	_vte_table_addi(subtable, original, original_length,
			pattern + 1, length - 1,
			result);
}
예제 #13
0
파일: matcher.c 프로젝트: Cordia/vte
/* Loads all sequences into matcher */
static void
_vte_matcher_init(struct _vte_matcher *matcher, const char *emulation,
		  struct _vte_termcap *termcap)
{
	const char *code, *value;
	gboolean found_cr = FALSE, found_lf = FALSE;
	gssize stripped_length;
	char *stripped;
	int i;

	_vte_debug_print(VTE_DEBUG_LIFECYCLE, "_vte_matcher_init()\n");

	if (termcap != NULL) {
		/* Load the known capability strings from the termcap
		 * structure into the table for recognition. */
		for (i = 0;
				_vte_terminal_capability_strings[i].capability[0];
				i++) {
			if (_vte_terminal_capability_strings[i].key) {
				continue;
			}
			code = _vte_terminal_capability_strings[i].capability;
			stripped = _vte_termcap_find_string_length(termcap,
					emulation,
					code,
					&stripped_length);
			if (stripped[0] != '\0') {
				_vte_matcher_add(matcher,
						stripped, stripped_length,
						code, 0);
				if (stripped[0] == '\r') {
					found_cr = TRUE;
				} else
					if (stripped[0] == '\n') {
						if (strcmp(code, "sf") == 0 ||
								strcmp(code, "do") == 0) {
							found_lf = TRUE;
						}
					}
			}
			g_free(stripped);
		}
	}

	/* Add emulator-specific sequences. */
	if (strstr(emulation, "xterm") || strstr(emulation, "dtterm")) {
		/* Add all of the xterm-specific stuff. */
		for (i = 0;
		     _vte_xterm_capability_strings[i].value != NULL;
		     i++) {
			code = _vte_xterm_capability_strings[i].code;
			value = _vte_xterm_capability_strings[i].value;
			_vte_matcher_add(matcher, code, strlen (code),
					 value, 0);
		}
	}

	/* Always define cr and lf. */
	if (!found_cr) {
		_vte_matcher_add(matcher, "\r", 1, "cr", 0);
	}
	if (!found_lf) {
		_vte_matcher_add(matcher, "\n", 1, "sf", 0);
	}

	_VTE_DEBUG_IF(VTE_DEBUG_TRIE) {
		g_printerr("Trie contents:\n");
		_vte_matcher_print(matcher);
		g_printerr("\n");
	}
}
예제 #14
0
파일: vtepangox.c 프로젝트: Cordia/vte
static void
_vte_pango_x_set_text_font(struct _vte_draw *draw,
			   const PangoFontDescription *fontdesc,
			   VteTerminalAntiAlias antialias)
{
	PangoContext *ctx;
	Display *display;
	PangoLayout *layout;
	PangoLayoutIter *iter;
	PangoRectangle ink, logical;
	gunichar full_codepoints[] = {VTE_DRAW_DOUBLE_WIDE_IDEOGRAPHS};
	GString *full_string;
	gint full_width;
	guint i;
	struct _vte_pango_x_data *data;

	data = (struct _vte_pango_x_data*) draw->impl_data;

	display = gdk_x11_display_get_xdisplay(gtk_widget_get_display(draw->widget));
	if (data->ctx != NULL) {
		g_object_unref(data->ctx);
	}
	ctx = pango_x_get_context(display);

	layout = pango_layout_new(ctx);
	if (data->font != NULL) {
		pango_font_description_free(data->font);
	}
	data->font = pango_font_description_copy(fontdesc);
	pango_layout_set_font_description(layout, data->font);

	/* Estimate for ASCII characters. */
	pango_layout_set_text(layout,
			      VTE_DRAW_SINGLE_WIDE_CHARACTERS,
			      strlen(VTE_DRAW_SINGLE_WIDE_CHARACTERS));
	pango_layout_get_extents(layout, &ink, &logical);
	draw->width = logical.width;
	draw->width = howmany(draw->width,
			      strlen(VTE_DRAW_SINGLE_WIDE_CHARACTERS));
	iter = pango_layout_get_iter(layout);
	draw->height = PANGO_PIXELS(logical.height);
	draw->ascent = PANGO_PIXELS(pango_layout_iter_get_baseline(iter));
	pango_layout_iter_free(iter);

	/* Estimate for CJK characters. */
	full_string = g_string_new(NULL);
	for (i = 0; i < G_N_ELEMENTS(full_codepoints); i++) {
		g_string_append_unichar(full_string, full_codepoints[i]);
	}
	pango_layout_set_text(layout, full_string->str, full_string->len);
	pango_layout_get_extents(layout, &ink, &logical);
	full_width = howmany(logical.width, G_N_ELEMENTS(full_codepoints));
	g_string_free(full_string, TRUE);

	/* If they're the same, then we have a screwy font. */
	if (full_width == draw->width) {
		/* add 1 to round up when dividing by 2 */
		draw->width = (draw->width + 1) / 2;
	}

	draw->width = PANGO_PIXELS(draw->width);
	iter = pango_layout_get_iter(layout);
	if (draw->height == 0) {
		draw->height = PANGO_PIXELS(logical.height);
	}
	if (draw->ascent == 0) {
		draw->ascent = PANGO_PIXELS(pango_layout_iter_get_baseline(iter));
	}
	pango_layout_iter_free(iter);

	_vte_debug_print(VTE_DEBUG_MISC,
			"VtePangoX font metrics = %dx%d (%d).\n",
			draw->width, draw->height, draw->ascent);
	g_object_unref(layout);
	g_object_unref(ctx);
}
예제 #15
0
파일: pty.c 프로젝트: gbl/vte
/*
 * _vte_pty_open_with_helper:
 * @pty: a #VtePty
 * @error: a location to store a #GError, or %NULL
 *
 * Opens a new file descriptor to a new PTY master using the
 * GNOME PTY helper.
 *
 * Returns: %TRUE on success, %FALSE on failure with @error filled in
 */
static gboolean
_vte_pty_open_with_helper(VtePty *pty,
                          GError **error)
{
        VtePtyPrivate *priv = pty->priv;
	GnomePtyOps ops;
	int ret;
	int parentfd = -1, childfd = -1;
	gpointer tag;

	/* We have to use the pty helper here. */
	if (!_vte_pty_start_helper(error))
                return FALSE;

	/* Try to open a new descriptor. */

        ops = _vte_pty_helper_ops_from_flags(priv->flags);
        /* Send our request. */
        if (n_write(_vte_pty_helper_tunnel,
                    &ops, sizeof(ops)) != sizeof(ops)) {
                g_set_error (error, VTE_PTY_ERROR,
                              VTE_PTY_ERROR_PTY_HELPER_FAILED,
                              "Failed to send request to gnome-pty-helper: %s",
                              g_strerror(errno));
                return FALSE;
        }
        _vte_debug_print(VTE_DEBUG_PTY, "Sent request to helper.\n");
        /* Read back the response. */
        if (n_read(_vte_pty_helper_tunnel,
                    &ret, sizeof(ret)) != sizeof(ret)) {
                g_set_error (error, VTE_PTY_ERROR,
                              VTE_PTY_ERROR_PTY_HELPER_FAILED,
                              "Failed to read response from gnome-pty-helper: %s",
                              g_strerror(errno));
                return FALSE;
        }
        _vte_debug_print(VTE_DEBUG_PTY,
                        "Received response from helper.\n");
        if (ret == 0) {
                g_set_error_literal (error, VTE_PTY_ERROR,
                                      VTE_PTY_ERROR_PTY_HELPER_FAILED,
                                      "gnome-pty-helper failed to open pty");
                return FALSE;
        }
        _vte_debug_print(VTE_DEBUG_PTY, "Helper returns success.\n");
        /* Read back a tag. */
        if (n_read(_vte_pty_helper_tunnel,
                    &tag, sizeof(tag)) != sizeof(tag)) {
                g_set_error (error, VTE_PTY_ERROR,
                              VTE_PTY_ERROR_PTY_HELPER_FAILED,
                              "Failed to read tag from gnome-pty-helper: %s",
                              g_strerror(errno));
                return FALSE;
        }
        _vte_debug_print(VTE_DEBUG_PTY, "Tag = %p.\n", tag);
        /* Receive the master and slave ptys. */
        _vte_pty_read_ptypair(_vte_pty_helper_tunnel,
                              &parentfd, &childfd);

        if ((parentfd == -1) || (childfd == -1)) {
                int errsv = errno;

                close(parentfd);
                close(childfd);

                g_set_error (error, VTE_PTY_ERROR,
                              VTE_PTY_ERROR_PTY_HELPER_FAILED,
                              "Failed to read master or slave pty from gnome-pty-helper: %s",
                              g_strerror(errsv));
                errno = errsv;
                return FALSE;
        }

        _vte_debug_print(VTE_DEBUG_PTY,
                        "Got master pty %d and slave pty %d.\n",
                        parentfd, childfd);

        priv->using_helper = TRUE;
        priv->helper_tag = tag;
        priv->pty_fd = parentfd;

        priv->child_setup_data.mode = TTY_OPEN_BY_FD;
        priv->child_setup_data.tty.fd = childfd;

        return TRUE;
}
예제 #16
0
파일: pty.c 프로젝트: gbl/vte
/**
 * vte_pty_child_setup:
 * @pty: a #VtePty
 *
 * FIXMEchpe
 */
void
vte_pty_child_setup (VtePty *pty)
{
        VtePtyPrivate *priv = pty->priv;
	VtePtyChildSetupData *data = &priv->child_setup_data;
	int fd = -1;
	const char *tty = NULL;
        char version[7];

        if (priv->foreign) {
                fd = priv->pty_fd;
        } else {
                /* Save the name of the pty -- we'll need it later to acquire
                * it as our controlling terminal.
                */
                switch (data->mode) {
                        case TTY_OPEN_BY_NAME:
                                tty = data->tty.name;
                                break;
                        case TTY_OPEN_BY_FD:
                                fd = data->tty.fd;
                                tty = ttyname(fd);
                                break;
                }

                _vte_debug_print (VTE_DEBUG_PTY,
                                "Setting up child pty: name = %s, fd = %d\n",
                                        tty ? tty : "(none)", fd);


                /* Try to reopen the pty to acquire it as our controlling terminal. */
                /* FIXMEchpe: why not just use the passed fd in TTY_OPEN_BY_FD mode? */
                if (tty != NULL) {
                        int i = open(tty, O_RDWR);
                        if (i != -1) {
                                if (fd != -1){
                                        close(fd);
                                }
                                fd = i;
                        }
                }
        }

	if (fd == -1)
		_exit (127);

	/* Start a new session and become process-group leader. */
#if defined(HAVE_SETSID) && defined(HAVE_SETPGID)
	_vte_debug_print (VTE_DEBUG_PTY, "Starting new session\n");
	setsid();
	setpgid(0, 0);
#endif

#ifdef TIOCSCTTY
	/* TIOCSCTTY is defined?  Let's try that, too. */
	ioctl(fd, TIOCSCTTY, fd);
#endif

#ifdef HAVE_STROPTS_H
	if (isastream (fd) == 1) {
		if ((ioctl(fd, I_FIND, "ptem") == 0) &&
				(ioctl(fd, I_PUSH, "ptem") == -1)) {
			_exit (127);
		}
		if ((ioctl(fd, I_FIND, "ldterm") == 0) &&
				(ioctl(fd, I_PUSH, "ldterm") == -1)) {
			_exit (127);
		}
		if ((ioctl(fd, I_FIND, "ttcompat") == 0) &&
				(ioctl(fd, I_PUSH, "ttcompat") == -1)) {
			perror ("ioctl (fd, I_PUSH, \"ttcompat\")");
			_exit (127);
		}
	}
#endif

	/* now setup child I/O through the tty */
	if (fd != STDIN_FILENO) {
		if (dup2(fd, STDIN_FILENO) != STDIN_FILENO){
			_exit (127);
		}
	}
	if (fd != STDOUT_FILENO) {
		if (dup2(fd, STDOUT_FILENO) != STDOUT_FILENO){
			_exit (127);
		}
	}
	if (fd != STDERR_FILENO) {
		if (dup2(fd, STDERR_FILENO) != STDERR_FILENO){
			_exit (127);
		}
	}

	/* Close the original slave descriptor, unless it's one of the stdio
	 * descriptors. */
	if (fd != STDIN_FILENO &&
			fd != STDOUT_FILENO &&
			fd != STDERR_FILENO) {
		close(fd);
	}

	/* Reset our signals -- our parent may have done any number of
	 * weird things to them. */
	_vte_pty_reset_signal_handlers();

        /* Now set the TERM environment variable */
        /* FIXME: Setting environment here seems to have no effect, the merged envp2 will override on exec.
         * By the way, we'd need to set the one from there, if any. */
        g_setenv("TERM", VTE_DEFAULT_TERM, TRUE);

        g_snprintf (version, sizeof (version), "%u", VTE_VERSION_NUMERIC);
        g_setenv ("VTE_VERSION", version, TRUE);

	/* Finally call an extra child setup */
	if (data->extra_child_setup) {
		data->extra_child_setup (data->extra_child_setup_data);
	}
}
예제 #17
0
파일: pty.c 프로젝트: gbl/vte
static gboolean
vte_pty_initable_init (GInitable *initable,
                       GCancellable *cancellable,
                       GError **error)
{
        VtePty *pty = VTE_PTY (initable);
        VtePtyPrivate *priv = pty->priv;
        gboolean ret = FALSE;

        if (cancellable != NULL) {
                g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
                                    "Cancellable initialisation not supported");
                return FALSE;
        }

        /* If we already have a (foreign) FD, we're done. */
        if (priv->foreign) {
                g_assert(priv->pty_fd != -1);
                return TRUE;
        }

#ifdef VTE_USE_GNOME_PTY_HELPER
	if ((priv->flags & VTE_PTY_NO_HELPER) == 0) {
                GError *err = NULL;

		ret = _vte_pty_open_with_helper(pty, &err);
                g_assert(ret || err != NULL);

                if (ret)
                        goto out;

                _vte_debug_print(VTE_DEBUG_PTY,
                                 "_vte_pty_open_with_helper failed: %s\n",
                                 err->message);

                /* Only do fallback if gnome-pty-helper failed! */
                if ((priv->flags & VTE_PTY_NO_FALLBACK) ||
                    !g_error_matches(err,
                                     VTE_PTY_ERROR,
                                     VTE_PTY_ERROR_PTY_HELPER_FAILED)) {
                        g_propagate_error (error, err);
                        goto out;
                }

                g_error_free(err);
                /* Fall back to unix98 or bsd PTY */
        }
#else
        if (priv->flags & VTE_PTY_NO_FALLBACK) {
                g_set_error_literal(error, VTE_PTY_ERROR, VTE_PTY_ERROR_PTY_HELPER_FAILED,
                                    "VTE compiled without GNOME PTY helper");
                goto out;
        }
#endif /* VTE_USE_GNOME_PTY_HELPER */

#if defined(HAVE_UNIX98_PTY)
        ret = _vte_pty_open_unix98(pty, error);
#elif defined(HAVE_OPENPTY)
        ret = _vte_pty_open_bsd(pty, error);
#else
#error Have neither UNIX98 PTY nor BSD openpty!
#endif

  out:
	_vte_debug_print(VTE_DEBUG_PTY,
			"vte_pty_initable_init returning %s with ptyfd = %d\n",
			ret ? "TRUE" : "FALSE", priv->pty_fd);

	return ret;
}