[vte] pty: Use packet mode on the PTY
- From: Christian Persch <chpe src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vte] pty: Use packet mode on the PTY
- Date: Sun, 29 Nov 2015 19:58:17 +0000 (UTC)
commit 3720b4d27a1d79247db9e368c09572beb42580b1
Author: Egmont Koblinger <egmont gmail com>
Date: Sun Nov 29 20:57:54 2015 +0100
pty: Use packet mode on the PTY
This allows us to get informed when scroll lock changes.
https://bugzilla.gnome.org/show_bug.cgi?id=755371
src/pty.cc | 26 ++++++++++++++++++++++++
src/vte.cc | 56 +++++++++++++++++++++++++++++++++++++++++++++++++--
src/vteinternal.hh | 6 ++++-
3 files changed, 84 insertions(+), 4 deletions(-)
---
diff --git a/src/pty.cc b/src/pty.cc
index aef4079..0bd0b0b 100644
--- a/src/pty.cc
+++ b/src/pty.cc
@@ -762,6 +762,19 @@ _vte_pty_getpt(GError **error)
return -1;
}
+ /* tty_ioctl(4) -> every read() gives an extra byte at the beginning
+ * notifying us of stop/start (^S/^Q) events. */
+ int one = 1;
+ if (ioctl(fd, TIOCPKT, &one) < 0) {
+ int errsv = errno;
+ g_set_error(error, VTE_PTY_ERROR,
+ VTE_PTY_ERROR_PTY98_FAILED,
+ "%s failed: %s", "ioctl(TIOCPKT)", g_strerror(errsv));
+ close(fd);
+ errno = errsv;
+ return -1;
+ }
+
return fd;
}
@@ -884,6 +897,19 @@ _vte_pty_open_bsd(VtePty *pty,
return FALSE;
}
+ /* tty_ioctl(4) -> every read() gives an extra byte at the beginning
+ * notifying us of stop/start (^S/^Q) events. */
+ int one = 1;
+ if (ioctl(parentfd, TIOCPKT, &one) < 0) {
+ int errsv = errno;
+ g_set_error(error, G_IO_ERROR, g_io_error_from_errno(errsv),
+ "%s failed: %s", "ioctl(TIOCPKT)", g_strerror(errsv));
+ close(parentfd);
+ close(childfd);
+ errno = errsv;
+ return FALSE;
+ }
+
priv->pty_fd = parentfd;
priv->child_setup_data.mode = TTY_OPEN_BY_FD;
priv->child_setup_data.tty.fd = childfd;
diff --git a/src/vte.cc b/src/vte.cc
index a7c91a1..eb6702e 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -53,6 +53,12 @@
#include <new> /* placement new */
+/* Some sanity checks */
+/* FIXMEchpe: move this to there when splitting _vte_incoming_chunk into its own file */
+static_assert(sizeof(struct _vte_incoming_chunk) <= VTE_INPUT_CHUNK_SIZE, "_vte_incoming_chunk too large");
+static_assert(offsetof(struct _vte_incoming_chunk, data) == offsetof(struct _vte_incoming_chunk,
dataminusone) + 1, "_vte_incoming_chunk layout wrong");
+
+
#ifndef HAVE_ROUND
static inline double round(double x) {
if(x - floor(x) < 0.5) {
@@ -3420,7 +3426,7 @@ VteTerminalPrivate::connect_pty_read()
m_pty_input_source =
g_io_add_watch_full(m_pty_channel,
VTE_CHILD_INPUT_PRIORITY,
- (GIOCondition)(G_IO_IN | G_IO_HUP),
+ (GIOCondition)(G_IO_IN | G_IO_PRI | G_IO_HUP),
(GIOFunc) vte_terminal_io_read,
m_terminal,
(GDestroyNotify) mark_input_source_invalid);
@@ -3483,6 +3489,20 @@ VteTerminalPrivate::disconnect_pty_write()
}
}
+void
+VteTerminalPrivate::pty_termios_changed()
+{
+ _vte_debug_print(VTE_DEBUG_IO, "Termios changed\n");
+}
+
+void
+VteTerminalPrivate::pty_scroll_lock_changed(bool locked)
+{
+ _vte_debug_print(VTE_DEBUG_IO, "Output %s (^%c)\n",
+ locked ? "stopped" : "started",
+ locked ? 'Q' : 'S');
+}
+
/*
* VteTerminalPrivate::watch_child:
* @child_pid: a #GPid
@@ -4094,7 +4114,7 @@ vte_terminal_io_read(GIOChannel *channel,
eof = condition & G_IO_HUP;
/* Read some data in from this channel. */
- if (condition & G_IO_IN) {
+ if (condition & (G_IO_IN | G_IO_PRI)) {
struct _vte_incoming_chunk *chunk, *chunks = NULL;
const int fd = g_io_channel_unix_get_fd (channel);
guchar *bp;
@@ -4129,7 +4149,16 @@ vte_terminal_io_read(GIOChannel *channel,
bp = chunk->data + chunk->len;
len = 0;
do {
- int ret = read (fd, bp, rem);
+ /* We'd like to read (fd, bp, rem); but due to TIOCPKT mode
+ * there's an extra input byte returned at the beginning.
+ * We need to see what that byte is, but otherwise drop it
+ * and write continuously to chunk->data.
+ */
+ char pkt_header;
+ char save = bp[-1];
+ int ret = read (fd, bp - 1, rem + 1);
+ pkt_header = bp[-1];
+ bp[-1] = save;
switch (ret){
case -1:
err = errno;
@@ -4138,6 +4167,27 @@ vte_terminal_io_read(GIOChannel *channel,
eof = TRUE;
goto out;
default:
+ ret--;
+
+ if (pkt_header & TIOCPKT_IOCTL) {
+ /* We'd like to always be informed when the termios
change,
+ * so we can e.g. detect when no-echo is en/disabled
and
+ * change the cursor/input method/etc., but
unfortunately
+ * the kernel only sends this flag when (old or new)
'local flags'
+ * include EXTPROC, which is not used often, and due
to its side
+ * effects, cannot be enabled by vte by default.
+ *
+ * FIXME: improve the kernel! see discussion in bug
755371
+ * starting at comment 12
+ */
+ terminal->pvt->pty_termios_changed();
+ }
+ if (pkt_header & TIOCPKT_STOP) {
+ terminal->pvt->pty_scroll_lock_changed(true);
+ } else if (pkt_header & TIOCPKT_START) {
+ terminal->pvt->pty_scroll_lock_changed(false);
+ }
+
bp += ret;
rem -= ret;
len += ret;
diff --git a/src/vteinternal.hh b/src/vteinternal.hh
index a37382c..8448ec2 100644
--- a/src/vteinternal.hh
+++ b/src/vteinternal.hh
@@ -125,7 +125,8 @@ typedef struct _vte_incoming_chunk _vte_incoming_chunk_t;
struct _vte_incoming_chunk{
_vte_incoming_chunk_t *next;
guint len;
- guchar data[VTE_INPUT_CHUNK_SIZE - 2 * sizeof(void *)];
+ guchar dataminusone; /* Hack: Keep it right before data, so that data[-1] is valid and usable */
+ guchar data[VTE_INPUT_CHUNK_SIZE - 2 * sizeof(void *) - 1];
};
typedef struct _VteScreen VteScreen;
@@ -512,6 +513,9 @@ public:
void connect_pty_write();
void disconnect_pty_write();
+ void pty_termios_changed();
+ void pty_scroll_lock_changed(bool locked);
+
void watch_child (GPid child_pid);
bool spawn_sync(VtePtyFlags pty_flags,
const char *working_directory,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]