summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNalin Dahyabhai <nalin@src.gnome.org>2002-10-25 22:07:11 +0000
committerNalin Dahyabhai <nalin@src.gnome.org>2002-10-25 22:07:11 +0000
commit25f084882412a537c4a3cc6993027f9707d8cc81 (patch)
treed87932bf93020b30a2d37807922d9ee53de0f55b
parente600d5ea308a700166c9a59e9e88e80ac7f91263 (diff)
snip off final newlines when we're matching, they're usually not wanted.
* src/vte.c (vte_terminal_match_check_internal): snip off final newlines when we're matching, they're usually not wanted. * src/pty.c, src/pty.h: replace the simpler pty_open() function with a logging version, adding the ability to specify a startup directory (Red Hat #76529). * src/vte.c, src/vte.h: replace the simpler fork_command() function with a logging version, adding the ability to specify a startup directory (Red Hat #76529). * src/vteapp.c: modify call to handle new fork_command(). * python/vte.defs: update as above. * python/vte.override: modify call to handle new fork_command(), adding an optional "directory" argument. * src/vte.c: refactor the selection code, cleaning up when selection is cleared/started/extended (#95783). Grab focus whenever we get button press or release or motion events. * src/vte.c: rework how wide characters are stored to allow storing tabs (#95958). * python/vte.override: wrap vte_terminal_get_text() and vte_terminal_get_text_range(). Based on patch from ha shao (#96230). * src/vte.c, src/vte.h: add a user pointer argument to get_text callbacks (#96230). * src/Makefile.am: bump shared library version because we changed a public function's signature. Take the opportunity to replace padding fields which had previously been used up.
-rw-r--r--ChangeLog36
-rw-r--r--Makefile.am5
-rw-r--r--doc/reference/tmpl/pty.sgml36
-rw-r--r--doc/reference/tmpl/vte-unused.sgml73
-rw-r--r--doc/reference/tmpl/vte.sgml15
-rw-r--r--doc/reference/vte-docs.sgml2
-rw-r--r--doc/reference/vte-sections.txt8
-rwxr-xr-xpython/cat.py13
-rw-r--r--python/vte.defs12
-rw-r--r--python/vte.override248
-rw-r--r--src/Makefile.am2
-rw-r--r--src/debug.c3
-rw-r--r--src/debug.h3
-rw-r--r--src/pty.c94
-rw-r--r--src/pty.h22
-rw-r--r--src/vte.c1912
-rw-r--r--src/vte.h25
-rw-r--r--src/vteaccess.c4
-rw-r--r--src/vteapp.c12
-rw-r--r--vte.spec5
20 files changed, 1535 insertions, 995 deletions
diff --git a/ChangeLog b/ChangeLog
index 7d468af..377d34a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,39 @@
-2002-10-21 jacob berkman <jacob@ximian.com>
+2002-10-25 nalin
+ * src/vte.c (vte_terminal_match_check_internal): snip off final
+ newlines when we're matching, they're usually not wanted.
+
+2002-10-24 nalin
+ * src/pty.c, src/pty.h: replace the simpler pty_open() function with
+ a logging version, adding the ability to specify a startup directory
+ (Red Hat #76529).
+ * src/vte.c, src/vte.h: replace the simpler fork_command() function with
+ a logging version, adding the ability to specify a startup directory
+ (Red Hat #76529).
+ * src/vteapp.c: modify call to handle new fork_command().
+ * python/vte.defs: update as above.
+ * python/vte.override: modify call to handle new fork_command(), adding
+ an optional "directory" argument.
+
+2002-10-23 nalin
+ * src/vte.c: refactor the selection code, cleaning up when selection is
+ cleared/started/extended (#95783).
+
+2002-10-22 nalin
+ * src/vte.c: rework how wide characters are stored to allow storing
+ tabs (#95958).
+
+2002-10-21 nalin
+ * python/vte.override: wrap vte_terminal_get_text() and
+ vte_terminal_get_text_range(). Based on patch from ha shao (#96230).
+
+2002-10-21 nalin
+ * src/vte.c, src/vte.h: add a user pointer argument to get_text
+ callbacks (#96230).
+ * src/Makefile.am: bump shared library version because we changed
+ a public function's signature. Take the opportunity to replace padding
+ fields which had previously been used up.
+2002-10-21 jacob berkman <jacob@ximian.com>
* src/Makefile.am (EXTRA_DIST): include decset, osc, and window
2002-10-18 nalin
diff --git a/Makefile.am b/Makefile.am
index e305aaa..a7098fd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,9 +6,12 @@ pkgconfig_DATA = vte.pc
CVSTAG=$(shell echo $(PACKAGE)-$(VERSION) | sed 's,[\.\-],_,g')
-reallytag:
+forcetag:
cvs tag -cFR $(CVSTAG) .
+reallytag:
+ cvs tag -cR $(CVSTAG) .
+
tag:
$(top_srcdir)/autogen.sh
$(MAKE) reallytag
diff --git a/doc/reference/tmpl/pty.sgml b/doc/reference/tmpl/pty.sgml
index 554308a..a50efe8 100644
--- a/doc/reference/tmpl/pty.sgml
+++ b/doc/reference/tmpl/pty.sgml
@@ -16,39 +16,3 @@ pseudo-terminals and to resize psuedo-terminals.
</para>
-<!-- ##### FUNCTION vte_pty_open ##### -->
-<para>
-
-</para>
-
-@child:
-@env_add:
-@command:
-@argv:
-@columns:
-@rows:
-@Returns:
-
-
-<!-- ##### FUNCTION vte_pty_get_size ##### -->
-<para>
-
-</para>
-
-@master:
-@columns:
-@rows:
-@Returns:
-
-
-<!-- ##### FUNCTION vte_pty_set_size ##### -->
-<para>
-
-</para>
-
-@master:
-@columns:
-@rows:
-@Returns:
-
-
diff --git a/doc/reference/tmpl/vte-unused.sgml b/doc/reference/tmpl/vte-unused.sgml
index e69de29..9eefbf6 100644
--- a/doc/reference/tmpl/vte-unused.sgml
+++ b/doc/reference/tmpl/vte-unused.sgml
@@ -0,0 +1,73 @@
+<!-- ##### SECTION ./tmpl/pty.sgml:Long_Description ##### -->
+<para>
+The terminal widget uses these functions to start commands with new controlling
+pseudo-terminals and to resize psuedo-terminals.
+</para>
+
+
+<!-- ##### SECTION ./tmpl/pty.sgml:See_Also ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### SECTION ./tmpl/pty.sgml:Short_Description ##### -->
+Functions for starting a new process on a new pseudo-terminal and for
+manipulating psuedo-terminals.
+
+
+<!-- ##### SECTION ./tmpl/pty.sgml:Title ##### -->
+pty
+
+
+<!-- ##### FUNCTION vte_pty_get_size ##### -->
+<para>
+
+</para>
+
+@master:
+@columns:
+@rows:
+@Returns:
+
+<!-- ##### FUNCTION vte_pty_open ##### -->
+<para>
+
+</para>
+
+@child:
+@env_add:
+@command:
+@argv:
+@directory:
+@columns:
+@rows:
+@lastlog:
+@utmp:
+@wtmp:
+@Returns:
+
+<!-- ##### FUNCTION vte_pty_set_size ##### -->
+<para>
+
+</para>
+
+@master:
+@columns:
+@rows:
+@Returns:
+
+<!-- ##### FUNCTION vte_terminal_fork_logged_command ##### -->
+<para>
+
+</para>
+
+@terminal:
+@command:
+@argv:
+@envv:
+@lastlog:
+@utmp:
+@wtmp:
+@Returns:
+
diff --git a/doc/reference/tmpl/vte.sgml b/doc/reference/tmpl/vte.sgml
index bc70bdc..163c586 100644
--- a/doc/reference/tmpl/vte.sgml
+++ b/doc/reference/tmpl/vte.sgml
@@ -72,18 +72,7 @@ A VteTerminal is a terminal emulator implemented as a GTK2 widget.
@command:
@argv:
@envv:
-@Returns:
-
-
-<!-- ##### FUNCTION vte_terminal_fork_logged_command ##### -->
-<para>
-
-</para>
-
-@terminal:
-@command:
-@argv:
-@envv:
+@directory:
@lastlog:
@utmp:
@wtmp:
@@ -447,6 +436,7 @@ A VteTerminal is a terminal emulator implemented as a GTK2 widget.
@terminal:
@is_selected:
+@data:
@attributes:
@Returns:
@@ -462,6 +452,7 @@ A VteTerminal is a terminal emulator implemented as a GTK2 widget.
@end_row:
@end_col:
@is_selected:
+@data:
@attributes:
@Returns:
diff --git a/doc/reference/vte-docs.sgml b/doc/reference/vte-docs.sgml
index 641e1c2..e8fc617 100644
--- a/doc/reference/vte-docs.sgml
+++ b/doc/reference/vte-docs.sgml
@@ -3,7 +3,6 @@
<!ENTITY vte-vteaccess SYSTEM "sgml/vteaccess.sgml">
<!ENTITY vte-VteReaper SYSTEM "sgml/reaper.sgml">
<!ENTITY vte-caps SYSTEM "sgml/caps.sgml">
-<!ENTITY vte-pty SYSTEM "sgml/pty.sgml">
<!ENTITY vte-termcap SYSTEM "sgml/termcap.sgml">
<!ENTITY vte-trie SYSTEM "sgml/trie.sgml">
<!ENTITY vte-debug SYSTEM "sgml/debug.sgml">
@@ -21,6 +20,5 @@
&vte-VteTerminal;
&vte-vteaccess;
&vte-VteReaper;
- &vte-pty;
</chapter>
</book>
diff --git a/doc/reference/vte-sections.txt b/doc/reference/vte-sections.txt
index 689f3a9..32ba78f 100644
--- a/doc/reference/vte-sections.txt
+++ b/doc/reference/vte-sections.txt
@@ -7,7 +7,6 @@ VteTerminal
vte_terminal_new
vte_terminal_im_append_menuitems
vte_terminal_fork_command
-vte_terminal_fork_logged_command
vte_terminal_feed
vte_terminal_feed_child
vte_terminal_copy_clipboard
@@ -110,10 +109,3 @@ VTE_REAPER_CLASS
VTE_IS_REAPER_CLASS
VTE_REAPER_GET_CLASS
</SECTION>
-
-<SECTION>
-<FILE>pty</FILE>
-vte_pty_open
-vte_pty_get_size
-vte_pty_set_size
-</SECTION>
diff --git a/python/cat.py b/python/cat.py
index ce8f553..c870299 100755
--- a/python/cat.py
+++ b/python/cat.py
@@ -10,9 +10,16 @@ def main_quit(object, *args):
def commit_cb(object, *args):
(text, length) = args
- # Echo the text input by the user to stdout.
- sys.stdout.write(text)
- sys.stdout.flush()
+ # Echo the text input by the user to stdout. Note that the string's
+ # length isn't always going to be right.
+ if (0):
+ sys.stdout.write(text)
+ sys.stdout.flush()
+ else:
+ # Test the get_text() function.
+ for line in (string.splitfields(object.get_text(),"\n")):
+ if (line.__len__() > 0):
+ print line
# Also display it.
object.feed(text, length)
diff --git a/python/vte.defs b/python/vte.defs
index 5d44fb3..4d186e4 100644
--- a/python/vte.defs
+++ b/python/vte.defs
@@ -48,17 +48,7 @@
'("const-char*" "command")
'("char**" "argv")
'("char**" "envv")
- )
-)
-
-(define-method fork_logged_command
- (of-object "VteTerminal")
- (c-name "vte_terminal_fork_logged_command")
- (return-type "pid_t")
- (parameters
- '("const-char*" "command")
- '("char**" "argv")
- '("char**" "envv")
+ '("const-char*" "directory")
'("gboolean" "lastlog")
'("gboolean" "utmp")
'("gboolean" "wtmp")
diff --git a/python/vte.override b/python/vte.override
index 76d3169..8cc2d8f 100644
--- a/python/vte.override
+++ b/python/vte.override
@@ -3,6 +3,7 @@
headers
#include <Python.h>
#include <pygtk/pygtk.h>
+#include <pygobject.h>
#include <gtk/gtk.h>
#include "../src/vte.h"
%%
@@ -10,24 +11,26 @@ import gtk.gdk.Pixbuf as PyGdkPixbuf_Type
import gtk.MenuShell as PyGtkMenuShell_Type
import gtk.Widget as PyGtkWidget_Type
%%
-ignore vte_terminal_get_text
-ignore vte_terminal_get_text_range
-%%
override vte_terminal_fork_command kwargs
+
static PyObject *
_wrap_vte_terminal_fork_command(PyGObject * self, PyObject * args,
PyObject * kwargs)
{
gchar **argv = NULL, **envv = NULL;
- gchar *command = NULL;
- static char *kwlist[] = { "command", "argv", "envv", NULL };
- PyObject *py_argv = NULL, *py_envv = NULL;
+ gchar *command = NULL, *directory = NULL;
+ static char *kwlist[] = { "command", "argv", "envv", "directory",
+ "loglastlog", "logutmp", "logwtmp",
+ NULL };
+ PyObject *py_argv = NULL, *py_envv = NULL,
+ *loglastlog = NULL, *logutmp = NULL, *logwtmp = NULL;
int i, n_args, n_envs;
pid_t pid;
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|sOO:fork_command",
- kwlist, &command, &py_argv,
- &py_envv)) {
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|sOOsOOO:fork_command",
+ kwlist, &command, &py_argv, &py_envv,
+ &directory,
+ &loglastlog, &logutmp, &logwtmp)) {
return NULL;
}
@@ -67,7 +70,13 @@ _wrap_vte_terminal_fork_command(PyGObject * self, PyObject * args,
}
pid = vte_terminal_fork_command(VTE_TERMINAL(self->obj),
- command, argv, envv);
+ command, argv, envv, directory,
+ (loglastlog != NULL) &&
+ PyObject_IsTrue(loglastlog),
+ (logutmp != NULL) &&
+ PyObject_IsTrue(logutmp),
+ (logwtmp != NULL) &&
+ PyObject_IsTrue(logwtmp));
if (argv) {
g_free(argv);
@@ -76,3 +85,222 @@ _wrap_vte_terminal_fork_command(PyGObject * self, PyObject * args,
return PyInt_FromLong(pid);
}
%%
+override vte_terminal_get_text kwargs
+
+static gboolean
+call_callback(VteTerminal *terminal, glong column, glong row, gpointer data)
+{
+ PyObject *cb, *self, *args, *result;
+ gboolean ret;
+ int i;
+ if (!PyArg_ParseTuple(data, "|O:call_callback", &args)) {
+ return FALSE;
+ }
+ args = PyList_New(0);
+ cb = PySequence_GetItem(args, 0); /* INCREFs */
+ Py_DECREF(cb);
+ self = PySequence_GetItem(args, 1); /* INCREFs */
+ Py_DECREF(self);
+ PyList_Append(args, self);
+ PyList_Append(args, PyInt_FromLong(column));
+ PyList_Append(args, PyInt_FromLong(row));
+ for (i = 2; i < PySequence_Length(args); i++) {
+ PyObject *item = PySequence_GetItem(args, i);
+ Py_DECREF(item);
+ PyList_Append(args, item);
+ }
+ result = PyObject_CallObject(cb, args);
+ ret = (result && PyObject_IsTrue(result));
+ Py_DECREF(args);
+ Py_DECREF(result);
+ return ret;
+}
+
+static gboolean
+always_true(VteTerminal *terminal, glong row, glong column, gpointer data)
+{
+ return TRUE;
+}
+static PyObject *
+_wrap_vte_terminal_get_text(PyGObject *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = { "callback", "attributes", "data", NULL };
+ PyObject *callback = NULL, *do_attr = NULL, *data = NULL;
+ PyObject *callback_and_args = NULL;
+ GArray *attrs = NULL;
+ PyObject *text;
+ PyObject *py_attrs;
+ int count;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOO:terminal_get_text",
+ kwlist, &callback, &do_attr, &args)) {
+ return NULL;
+ }
+
+ if (do_attr != NULL && do_attr != Py_None) {
+ attrs = g_array_new(FALSE, TRUE, sizeof(struct vte_char_attributes));
+ } else {
+ attrs = NULL;
+ }
+
+ if ((callback != NULL) && (callback != Py_None)) {
+ if (!PyCallable_Check(callback)) {
+ PyErr_SetString(PyExc_TypeError, "1st argument not callable.");
+ if (attrs) {
+ g_array_free(attrs, TRUE);
+ }
+ return NULL;
+ }
+ } else {
+ callback = NULL;
+ }
+
+ if (callback != NULL) {
+ callback_and_args = PyList_New(0);
+ PyList_Append(callback_and_args, callback);
+ PyList_Append(callback_and_args, (PyObject*) self);
+ if (PyList_Check(data)) {
+ for (count = 0; count < PyList_Size(data); count++) {
+ PyList_Append(callback_and_args, PyList_GetItem(data, count));
+ }
+ } else {
+ PyList_Append(callback_and_args, data);
+ }
+ }
+
+ text = PyString_FromString(vte_terminal_get_text(VTE_TERMINAL(self->obj),
+ callback ?
+ call_callback :
+ always_true,
+ callback ?
+ callback_and_args :
+ NULL,
+ attrs));
+ Py_XDECREF(callback_and_args);
+
+ if (attrs) {
+ py_attrs = PyTuple_New(attrs->len);
+ for (count = 0; count < attrs->len; count++) {
+ struct vte_char_attributes *cht;
+ PyObject *py_char_attr;
+ PyObject *py_gdkcolor;
+
+ cht = &g_array_index(attrs, struct vte_char_attributes, count);
+ py_char_attr = PyDict_New();
+ PyDict_SetItemString(py_char_attr, "row", PyInt_FromLong(cht->row));
+ PyDict_SetItemString(py_char_attr, "column", PyInt_FromLong(cht->column));
+
+ py_gdkcolor = pyg_boxed_new(GDK_TYPE_COLOR, &cht->fore, TRUE, TRUE);
+ PyDict_SetItemString(py_char_attr, "fore", py_gdkcolor);
+ py_gdkcolor = pyg_boxed_new(GDK_TYPE_COLOR, &cht->back, TRUE, TRUE);
+ PyDict_SetItemString(py_char_attr, "back", py_gdkcolor);
+
+ PyDict_SetItemString(py_char_attr, "underline",
+ PyInt_FromLong(cht->underline));
+ PyDict_SetItemString(py_char_attr, "alternate",
+ PyInt_FromLong(cht->alternate));
+
+ PyTuple_SetItem(py_attrs, count, py_char_attr);
+ }
+ g_array_free(attrs, TRUE);
+ return Py_BuildValue("(OO)", text, py_attrs);
+ } else {
+ return Py_BuildValue("O", text);
+ }
+}
+%%
+override vte_terminal_get_text_range kwargs
+static PyObject *
+_wrap_vte_terminal_get_text_range(PyGObject *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = { "callback", "start_row", "start_col", "end_row",
+ "end_col", "attributes", "data", NULL };
+ PyObject *callback = NULL, *do_attr = NULL, *data = NULL;
+ glong start_row, start_col, end_row, end_col;
+ PyObject *callback_and_args = NULL;
+ GArray *attrs = NULL;
+ PyObject *text;
+ PyObject *py_attrs;
+ int count;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|llllOOO:terminal_get_text",
+ kwlist,
+ &start_row, &start_col, &end_row, &end_col,
+ &callback, &do_attr, &args)) {
+ return NULL;
+ }
+
+ if (do_attr != NULL && do_attr != Py_None) {
+ attrs = g_array_new(FALSE, TRUE, sizeof(struct vte_char_attributes));
+ } else {
+ attrs = NULL;
+ }
+
+ if ((callback != NULL) && (callback != Py_None)) {
+ if (!PyCallable_Check(callback)) {
+ PyErr_SetString(PyExc_TypeError, "1st argument not callable.");
+ if (attrs) {
+ g_array_free(attrs, TRUE);
+ }
+ return NULL;
+ }
+ } else {
+ callback = NULL;
+ }
+
+ if (callback != NULL) {
+ callback_and_args = PyList_New(0);
+ PyList_Append(callback_and_args, callback);
+ PyList_Append(callback_and_args, (PyObject*) self);
+ if (PyList_Check(data)) {
+ for (count = 0; count < PyList_Size(data); count++) {
+ PyList_Append(callback_and_args, PyList_GetItem(data, count));
+ }
+ } else {
+ PyList_Append(callback_and_args, data);
+ }
+ }
+
+ text = PyString_FromString(vte_terminal_get_text_range(VTE_TERMINAL(self->obj),
+ start_row, start_col,
+ end_row, end_col,
+ callback ?
+ call_callback :
+ always_true,
+ callback ?
+ callback_and_args :
+ NULL,
+ attrs));
+ Py_XDECREF(callback_and_args);
+
+ if (attrs) {
+ py_attrs = PyTuple_New(attrs->len);
+ for (count = 0; count < attrs->len; count++) {
+ struct vte_char_attributes *cht;
+ PyObject *py_char_attr;
+ PyObject *py_gdkcolor;
+
+ cht = &g_array_index(attrs, struct vte_char_attributes, count);
+ py_char_attr = PyDict_New();
+ PyDict_SetItemString(py_char_attr, "row", PyInt_FromLong(cht->row));
+ PyDict_SetItemString(py_char_attr, "column", PyInt_FromLong(cht->column));
+
+ py_gdkcolor = pyg_boxed_new(GDK_TYPE_COLOR, &cht->fore, TRUE, TRUE);
+ PyDict_SetItemString(py_char_attr, "fore", py_gdkcolor);
+ py_gdkcolor = pyg_boxed_new(GDK_TYPE_COLOR, &cht->back, TRUE, TRUE);
+ PyDict_SetItemString(py_char_attr, "back", py_gdkcolor);
+
+ PyDict_SetItemString(py_char_attr, "underline",
+ PyInt_FromLong(cht->underline));
+ PyDict_SetItemString(py_char_attr, "alternate",
+ PyInt_FromLong(cht->alternate));
+
+ PyTuple_SetItem(py_attrs, count, py_char_attr);
+ }
+ g_array_free(attrs, TRUE);
+ return Py_BuildValue("(OO)", text, py_attrs);
+ } else {
+ return Py_BuildValue("O", text);
+ }
+}
+%%
diff --git a/src/Makefile.am b/src/Makefile.am
index c45df29..7792c10 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -48,7 +48,7 @@ libvte_la_SOURCES = \
vteaccess.h
libvte_la_LIBADD = @LIBS@ @VTE_LIBS@ @X_LIBS@
-libvte_la_LDFLAGS = -version-info 4:0:1
+libvte_la_LDFLAGS = -version-info 4:0:0
CLEANFILES = marshal.c marshal.h
diff --git a/src/debug.c b/src/debug.c
index 3f599ae..6c30eda 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -64,6 +64,9 @@ _vte_debug_parse_string(const char *string)
} else
if (g_ascii_strcasecmp(flags[i], "PTY") == 0) {
_vte_debug_flags |= VTE_DEBUG_PTY;
+ } else
+ if (g_ascii_strcasecmp(flags[i], "CURSOR") == 0) {
+ _vte_debug_flags |= VTE_DEBUG_CURSOR;
}
}
g_strfreev(flags);
diff --git a/src/debug.h b/src/debug.h
index de1efd5..a85f304 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -35,7 +35,8 @@ typedef enum {
VTE_DEBUG_SELECTION = 1 << 6,
VTE_DEBUG_SUBSTITUTION = 1 << 7,
VTE_DEBUG_RING = 1 << 8,
- VTE_DEBUG_PTY = 1 << 9
+ VTE_DEBUG_PTY = 1 << 9,
+ VTE_DEBUG_CURSOR = 1 << 10
} VteDebugFlags;
void _vte_debug_parse_string(const char *string);
diff --git a/src/pty.c b/src/pty.c
index fe7a8ed..ef28fc7 100644
--- a/src/pty.c
+++ b/src/pty.c
@@ -201,7 +201,8 @@ _vte_pty_pipe_open_bi(int *a, int *b, int *c, int *d)
* terminal. */
static int
_vte_pty_run_on_pty(int fd, int ready_reader, int ready_writer,
- char **env_add, const char *command, char **argv)
+ char **env_add, const char *command, char **argv,
+ const char *directory)
{
int i;
char c;
@@ -261,6 +262,11 @@ _vte_pty_run_on_pty(int fd, int ready_reader, int ready_writer,
* weird things to them. */
_vte_pty_reset_signal_handlers();
+ /* Change to the requested directory. */
+ if (directory != NULL) {
+ chdir(directory);
+ }
+
/* Signal to the parent that we've finished setting things up by
* sending an arbitrary byte over the status pipe and waiting for
* a response. This synchronization step ensures that the pty is
@@ -310,6 +316,7 @@ _vte_pty_run_on_pty(int fd, int ready_reader, int ready_writer,
static int
_vte_pty_fork_on_pty_name(const char *path, int parent_fd, char **env_add,
const char *command, char **argv,
+ const char *directory,
int columns, int rows, pid_t *child)
{
int fd, i;
@@ -353,7 +360,7 @@ _vte_pty_fork_on_pty_name(const char *path, int parent_fd, char **env_add,
fprintf(stderr, "Parent received child-ready.\n");
}
#endif
- vte_pty_set_size(parent_fd, columns, rows);
+ _vte_pty_set_size(parent_fd, columns, rows);
#ifdef VTE_DEBUG
if (_vte_debug_on(VTE_DEBUG_PTY)) {
fprintf(stderr, "Parent sending parent-ready.\n");
@@ -389,7 +396,7 @@ _vte_pty_fork_on_pty_name(const char *path, int parent_fd, char **env_add,
return -1;
}
return _vte_pty_run_on_pty(fd, ready_b[0], ready_a[1],
- env_add, command, argv);
+ env_add, command, argv, directory);
}
/* Fork off a child (storing its PID in child), and exec the named command
@@ -397,6 +404,7 @@ _vte_pty_fork_on_pty_name(const char *path, int parent_fd, char **env_add,
static int
_vte_pty_fork_on_pty_fd(int fd, char **env_add,
const char *command, char **argv,
+ const char *directory,
int columns, int rows, pid_t *child)
{
int i;
@@ -441,7 +449,7 @@ _vte_pty_fork_on_pty_fd(int fd, char **env_add,
fprintf(stderr, "Parent received child-ready.\n");
}
#endif
- vte_pty_set_size(fd, columns, rows);
+ _vte_pty_set_size(fd, columns, rows);
#ifdef VTE_DEBUG
if (_vte_debug_on(VTE_DEBUG_PTY)) {
fprintf(stderr, "Parent sending parent-ready.\n");
@@ -484,7 +492,7 @@ _vte_pty_fork_on_pty_fd(int fd, char **env_add,
}
return _vte_pty_run_on_pty(fd, ready_b[0], ready_a[1],
- env_add, command, argv);
+ env_add, command, argv, directory);
}
/**
@@ -499,7 +507,7 @@ _vte_pty_fork_on_pty_fd(int fd, char **env_add,
* Returns: 0 on success, -1 on failure.
*/
int
-vte_pty_set_size(int master, int columns, int rows)
+_vte_pty_set_size(int master, int columns, int rows)
{
struct winsize size;
int ret;
@@ -535,7 +543,7 @@ vte_pty_set_size(int master, int columns, int rows)
* Returns: 0 on success, -1 on failure.
*/
int
-vte_pty_get_size(int master, int *columns, int *rows)
+_vte_pty_get_size(int master, int *columns, int *rows)
{
struct winsize size;
int ret;
@@ -638,8 +646,8 @@ _vte_pty_unlockpt(int fd)
static int
_vte_pty_open_unix98(pid_t *child, char **env_add,
- const char *command, char **argv,
- int columns, int rows)
+ const char *command, char **argv,
+ const char *directory, int columns, int rows)
{
int fd;
char *buf;
@@ -666,7 +674,8 @@ _vte_pty_open_unix98(pid_t *child, char **env_add,
} else {
/* Start up a child process with the given command. */
if (_vte_pty_fork_on_pty_name(buf, fd, env_add, command,
- argv, columns, rows,
+ argv, directory,
+ columns, rows,
child) != 0) {
close(fd);
fd = -1;
@@ -809,6 +818,7 @@ _vte_pty_start_helper(void)
static int
_vte_pty_open_with_helper(pid_t *child, char **env_add,
const char *command, char **argv,
+ const char *directory,
int columns, int rows, int op)
{
GnomePtyOps ops;
@@ -864,7 +874,8 @@ _vte_pty_open_with_helper(pid_t *child, char **env_add,
tag);
/* Start up a child process with the given command. */
if (_vte_pty_fork_on_pty_fd(childfd, env_add, command,
- argv, columns, rows, child) != 0) {
+ argv, directory,
+ columns, rows, child) != 0) {
close(parentfd);
close(childfd);
return -1;
@@ -881,24 +892,26 @@ _vte_pty_open_with_helper(pid_t *child, char **env_add,
* @env_add: a list of environment variables to add to the child's environment
* @command: name of the binary to run
* @argv: arguments to pass to @command
+ * @directory: directory to start the new command in, or NULL
* @columns: desired window columns
* @rows: desired window rows
* @lastlog: TRUE if the lastlog should be updated
* @utmp: TRUE if the utmp or utmpx log should be updated
* @wtmp: TRUE if the wtmp or wtmpx log should be updated
*
- * Starts a new copy of @command running under a psuedo-terminal, with window
- * size set to @rows x @columns and variables in @env_add added to its
- * environment. If any combination of @lastlog, @utmp, and @wtmp is set,
- * then the session is logged in the appropriate system log.
+ * Starts a new copy of @command running under a psuedo-terminal, optionally in
+ * the supplied @directory, with window size set to @rows x @columns
+ * and variables in @env_add added to its environment. If any combination of
+ * @lastlog, @utmp, and @wtmp is set, then the session is logged in the
+ * corresponding system files.
*
* Returns: an open file descriptor for the pty master, -1 on failure
*/
int
-vte_pty_open_with_logging(pid_t *child, char **env_add,
- const char *command, char **argv,
- int columns, int rows,
- gboolean lastlog, gboolean utmp, gboolean wtmp)
+_vte_pty_open(pid_t *child, char **env_add,
+ const char *command, char **argv, const char *directory,
+ int columns, int rows,
+ gboolean lastlog, gboolean utmp, gboolean wtmp)
{
int ret = -1;
int op = 0;
@@ -925,11 +938,12 @@ vte_pty_open_with_logging(pid_t *child, char **env_add,
g_assert(op < G_N_ELEMENTS(opmap));
if (ret == -1) {
ret = _vte_pty_open_with_helper(child, env_add, command, argv,
+ directory,
columns, rows, opmap[op]);
}
if (ret == -1) {
ret = _vte_pty_open_unix98(child, env_add, command, argv,
- columns, rows);
+ directory, columns, rows);
}
#ifdef VTE_DEBUG
if (_vte_debug_on(VTE_DEBUG_PTY)) {
@@ -940,32 +954,6 @@ vte_pty_open_with_logging(pid_t *child, char **env_add,
}
/**
- * vte_pty_open:
- * @child: location to store the new process's ID
- * @env_add: a list of environment variables to add to the child's environment
- * @command: name of the binary to run
- * @argv: arguments to pass to @command
- * @columns: desired window columns
- * @rows: desired window rows
- *
- * Starts a new copy of @command running under a psuedo-terminal, with window
- * size set to @rows x @columns and variables in @env_add added to its
- * environment. A convenience wrapper for vte_pty_open_with_logging().
- *
- * Returns: an open file descriptor for the pty master, -1 on failure
- */
-int
-vte_pty_open(pid_t *child, char **env_add,
- const char *command, char **argv,
- int columns, int rows)
-{
- return vte_pty_open_with_logging(child, env_add, command, argv,
- columns, rows,
- FALSE, FALSE, FALSE);
-}
-
-
-/**
* vte_pty_close:
* @pty: the pty master descriptor.
*
@@ -973,7 +961,7 @@ vte_pty_open(pid_t *child, char **env_add,
* performed for the session. The descriptor itself remains open.
*/
void
-vte_pty_close(int pty)
+_vte_pty_close(int pty)
{
gpointer tag;
GnomePtyOps ops;
@@ -1001,7 +989,7 @@ static void
sigchld_handler(int signum)
{
/* This is very unsafe. Never do it in production code. */
- vte_pty_close(fd);
+ _vte_pty_close(fd);
}
int
@@ -1012,10 +1000,12 @@ main(int argc, char **argv)
int ret;
signal(SIGCHLD, sigchld_handler);
_vte_debug_parse_string(getenv("VTE_DEBUG_FLAGS"));
- fd = vte_pty_open(&child, NULL,
- (argc > 1) ? argv[1] : "/usr/bin/tty",
- (argc > 1) ? argv + 1 : NULL,
- 0, 0);
+ fd = _vte_pty_open(&child, NULL,
+ (argc > 1) ? argv[1] : "/usr/bin/tty",
+ (argc > 1) ? argv + 1 : NULL,
+ NULL,
+ 0, 0,
+ FALSE, FALSE, FALSE);
g_print("Child pid is %d.\n", (int)child);
do {
ret = read(fd, &c, 1);
diff --git a/src/pty.h b/src/pty.h
index ce2f7a7..50d3f70 100644
--- a/src/pty.h
+++ b/src/pty.h
@@ -27,24 +27,20 @@ G_BEGIN_DECLS
/* Start up the given binary (exact path, not interpreted at all) in a
* pseudo-terminal of its own, returning the descriptor for the master
- * side of the PTY pair, storing the child's PID in the given argument. */
-int vte_pty_open(pid_t *child, char **env_add,
- const char *command, char **argv,
- int columns, int rows);
-
-/* As above, but with session logging. */
-int vte_pty_open_with_logging(pid_t *child, char **env_add,
- const char *command, char **argv,
- int columns, int rows,
- gboolean lastlog, gboolean utmp, gboolean wtmp);
+ * side of the PTY pair, logging the session to the specified files, and
+ * storing the child's PID in the given argument. */
+int _vte_pty_open(pid_t *child, char **env_add,
+ const char *command, char **argv, const char *directory,
+ int columns, int rows,
+ gboolean lastlog, gboolean utmp, gboolean wtmp);
/* Set or read the size of a terminal. Returns 0 on success, -1 on failure,
* with errno set to defined return codes from ioctl(). */
-int vte_pty_get_size(int master, int *columns, int *rows);
-int vte_pty_set_size(int master, int columns, int rows);
+int _vte_pty_get_size(int master, int *columns, int *rows);
+int _vte_pty_set_size(int master, int columns, int rows);
/* Close a pty. */
-void vte_pty_close(int pty);
+void _vte_pty_close(int pty);
G_END_DECLS
diff --git a/src/vte.c b/src/vte.c
index dc149a6..66c4efc 100644
--- a/src/vte.c
+++ b/src/vte.c
@@ -118,19 +118,22 @@ typedef gunichar wint_t;
* includes any supported visible attributes. */
struct vte_charcell {
gunichar c; /* The Unicode character. */
- guint16 columns: 2; /* Number of visible columns (as determined
- by g_unicode_iswide(c)). */
- guint16 fore: 5; /* Indices in the color palette for the */
- guint16 back: 5; /* foreground and background of the cell. */
- guint16 standout: 1; /* Single-bit attributes. */
- guint16 underline: 1;
- guint16 reverse: 1;
- guint16 blink: 1;
- guint16 half: 1;
- guint16 bold: 1;
- guint16 invisible: 1;
- guint16 protect: 1;
- guint16 alternate: 1;
+ guint32 columns: 12; /* Number of visible columns (as determined
+ by g_unicode_iswide(c)). Use as many bits
+ as possible without making this structure
+ grow any larger. */
+ guint32 fragment: 1; /* The nth fragment of a wide character. */
+ guint32 fore: 5; /* Indices in the color palette for the */
+ guint32 back: 5; /* foreground and background of the cell. */
+ guint32 standout: 1; /* Single-bit attributes. */
+ guint32 underline: 1;
+ guint32 reverse: 1;
+ guint32 blink: 1;
+ guint32 half: 1;
+ guint32 bold: 1;
+ guint32 invisible: 1;
+ guint32 protect: 1;
+ guint32 alternate: 1;
};
/* A match regex, with a tag. */
@@ -142,6 +145,7 @@ struct vte_match_regex {
/* A drawing request record, for simplicity. */
struct vte_draw_item {
gunichar c;
+ guint16 columns;
guint16 xpad;
};
@@ -244,7 +248,7 @@ struct _VteTerminalPrivate {
gboolean has_selection;
gboolean restart_selection;
char *selection;
- enum {
+ enum vte_selection_type {
selection_type_char,
selection_type_word,
selection_type_line
@@ -252,7 +256,7 @@ struct _VteTerminalPrivate {
struct selection_event_coords {
double x, y;
} selection_origin, selection_last, selection_delayed;
- struct {
+ struct selection_cell_coords {
long x, y;
} selection_start, selection_end;
@@ -318,8 +322,10 @@ struct _VteTerminalPrivate {
VteRenderXlib = 0,
VteRenderPangoX = 1,
VteRenderPango = 2,
+#ifdef HAVE_XFT
VteRenderXft1 = 3,
- VteRenderXft2 = 4
+ VteRenderXft2 = 4,
+#endif
} render_method;
#ifdef HAVE_XFT
XftFont *ftfont;
@@ -375,7 +381,8 @@ static void vte_terminal_ensure_cursor(VteTerminal *terminal, gboolean current);
static void vte_terminal_paste(VteTerminal *terminal, GdkAtom board);
static void vte_terminal_insert_char(VteTerminal *terminal, gunichar c,
gboolean force_insert_mode,
- gboolean invalidate_cells);
+ gboolean invalidate_cells,
+ gint forced_width);
static void vte_sequence_handler_clear_screen(VteTerminal *terminal,
const char *match,
GQuark match_quark,
@@ -459,10 +466,10 @@ vte_free_row_data(gpointer freeing, gpointer data)
static void
vte_g_array_fill(GArray *array, gpointer item, guint final_size)
{
+ g_assert(array != NULL);
if (array->len >= final_size) {
return;
}
- g_assert(array != NULL);
g_assert(item != NULL);
while (array->len < final_size) {
@@ -472,7 +479,7 @@ vte_g_array_fill(GArray *array, gpointer item, guint final_size)
/* Allocate a new line. */
static GArray *
-vte_new_row_data(void)
+vte_new_row_data(VteTerminal *terminal)
{
return g_array_new(FALSE, FALSE, sizeof(struct vte_charcell));
}
@@ -496,7 +503,7 @@ vte_new_row_data_sized(VteTerminal *terminal, gboolean fill)
static gssize
vte_unichar_width(gunichar c)
{
- return g_unichar_isdefined(c) ? (g_unichar_iswide(c) ? 2 : 1) : -1;
+ return g_unichar_isdefined(c) ? (g_unichar_iswide(c) ? 2 : 1) : 1;
}
/* Check how long a string of unichars is. Slow version. */
@@ -590,8 +597,9 @@ static void
vte_terminal_set_default_attributes(VteTerminal *terminal)
{
g_return_if_fail(VTE_IS_TERMINAL(terminal));
- terminal->pvt->screen->defaults.c = 0;
+ terminal->pvt->screen->defaults.c = ' ';
terminal->pvt->screen->defaults.columns = 1;
+ terminal->pvt->screen->defaults.fragment = 0;
terminal->pvt->screen->defaults.fore = VTE_DEF_FG;
terminal->pvt->screen->defaults.back = VTE_DEF_BG;
terminal->pvt->screen->defaults.reverse = 0;
@@ -746,7 +754,7 @@ vte_invalidate_cursor_once(gpointer data)
cell = vte_terminal_find_charcell(terminal,
column,
screen->cursor_current.row);
- while ((cell != NULL) && (cell->columns == 0) && (column > 0)) {
+ while ((cell != NULL) && (cell->fragment) && (column > 0)) {
column--;
cell = vte_terminal_find_charcell(terminal,
column,
@@ -756,10 +764,8 @@ vte_invalidate_cursor_once(gpointer data)
columns = cell->columns;
}
vte_invalidate_cells(terminal,
- column,
- columns + preedit_length,
- screen->cursor_current.row,
- 1);
+ column, columns + preedit_length,
+ screen->cursor_current.row, 1);
#ifdef VTE_DEBUG
if (_vte_debug_on(VTE_DEBUG_UPDATES)) {
fprintf(stderr, "Invalidating cursor at (%ld,%ld-%ld)."
@@ -1095,7 +1101,6 @@ vte_terminal_deselect_all(VteTerminal *terminal)
vte_terminal_emit_selection_changed(terminal);
vte_invalidate_all(terminal);
}
- terminal->pvt->restart_selection = FALSE;
}
/* Reset the set of tab stops to the default. */
@@ -1169,7 +1174,7 @@ vte_terminal_match_contents_clear(VteTerminal *terminal)
g_free(terminal->pvt->match_contents);
terminal->pvt->match_contents = NULL;;
}
- while (terminal->pvt->match_attributes != NULL) {
+ if (terminal->pvt->match_attributes != NULL) {
g_array_free(terminal->pvt->match_attributes, TRUE);
terminal->pvt->match_attributes = NULL;
}
@@ -1178,7 +1183,7 @@ vte_terminal_match_contents_clear(VteTerminal *terminal)
/* Refresh the cache of the screen contents we keep. */
static gboolean
-always_selected(VteTerminal *terminal, glong row, glong column)
+always_selected(VteTerminal *terminal, glong row, glong column, gpointer data)
{
return TRUE;
}
@@ -1191,6 +1196,7 @@ vte_terminal_match_contents_refresh(VteTerminal *terminal)
array = g_array_new(FALSE, TRUE, sizeof(struct vte_char_attributes));
terminal->pvt->match_contents = vte_terminal_get_text(terminal,
always_selected,
+ NULL,
array);
terminal->pvt->match_attributes = array;
}
@@ -1263,6 +1269,12 @@ vte_terminal_match_check_internal(VteTerminal *terminal,
struct vte_char_attributes *attr = NULL;
gssize coffset;
regmatch_t matches[256];
+#ifdef VTE_DEBUG
+ if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
+ fprintf(stderr, "Checking for match at (%ld,%ld).\n",
+ row, column);
+ }
+#endif
if (tag != NULL) {
*tag = -1;
}
@@ -1283,12 +1295,10 @@ vte_terminal_match_check_internal(VteTerminal *terminal,
attr = &g_array_index(terminal->pvt->match_attributes,
struct vte_char_attributes,
offset);
- if (attr != NULL) {
- if ((row == attr->row) &&
- (column == attr->column) &&
- !g_ascii_isspace(terminal->pvt->match_contents[offset])) {
- break;
- }
+ if ((row == attr->row) &&
+ (column == attr->column) &&
+ (terminal->pvt->match_contents[offset] != ' ')) {
+ break;
}
}
#ifdef VTE_DEBUG
@@ -1300,10 +1310,12 @@ vte_terminal_match_check_internal(VteTerminal *terminal,
}
}
#endif
+
/* If the pointer isn't on a matchable character, bug out. */
if (offset < 0) {
return NULL;
}
+
/* If the pointer is on a newline, bug out. */
if (g_ascii_isspace(terminal->pvt->match_contents[offset])) {
#ifdef VTE_DEBUG
@@ -1319,76 +1331,83 @@ vte_terminal_match_check_internal(VteTerminal *terminal,
regex = &g_array_index(terminal->pvt->match_regexes,
struct vte_match_regex,
i);
- if (regex != NULL) {
- /* We'll only match the first item in the buffer which
- * matches, so we'll have to skip each match until we
- * stop getting matches. */
- coffset = 0;
- ret = regexec(&regex->reg,
- terminal->pvt->match_contents + coffset,
- G_N_ELEMENTS(matches),
- matches,
- VTE_REGEXEC_FLAGS);
- while (ret == 0) {
- for (j = 0;
- j < G_N_ELEMENTS(matches) &&
- (matches[j].rm_so != -1);
- j++) {
- /* The offsets should be "sane". */
- g_assert(matches[j].rm_so + coffset < terminal->pvt->match_attributes->len);
- g_assert(matches[j].rm_eo + coffset <= terminal->pvt->match_attributes->len);
+ g_assert(regex != NULL);
+ /* We'll only match the first item in the buffer which
+ * matches, so we'll have to skip each match until we
+ * stop getting matches. */
+ coffset = 0;
+ ret = regexec(&regex->reg,
+ terminal->pvt->match_contents + coffset,
+ G_N_ELEMENTS(matches),
+ matches,
+ VTE_REGEXEC_FLAGS);
+ while (ret == 0) {
+ for (j = 0;
+ (j < G_N_ELEMENTS(matches)) &&
+ (matches[j].rm_so != -1);
+ j++) {
+ /* The offsets should be "sane". */
+ g_assert(matches[j].rm_so + coffset <
+ terminal->pvt->match_attributes->len);
+ g_assert(matches[j].rm_eo + coffset <=
+ terminal->pvt->match_attributes->len);
#ifdef VTE_DEBUG
- if (_vte_debug_on(VTE_DEBUG_MISC)) {
- char *match;
- struct vte_char_attributes *sattr, *eattr;
- match = g_strndup(terminal->pvt->match_contents + matches[j].rm_so + coffset,
- matches[j].rm_eo - matches[j].rm_so);
- sattr = &g_array_index(terminal->pvt->match_attributes,
- struct vte_char_attributes,
- matches[j].rm_so + coffset);
- eattr = &g_array_index(terminal->pvt->match_attributes,
- struct vte_char_attributes,
- matches[j].rm_eo + coffset - 1);
- fprintf(stderr, "Match %d `%s' from %d(%ld,%ld) to %d(%ld,%ld) (%d).\n",
- j, match,
- matches[j].rm_so + coffset,
- sattr->column,
- sattr->row,
- matches[j].rm_eo + coffset - 1,
- eattr->column,
- eattr->row,
- offset);
- g_free(match);
+ if (_vte_debug_on(VTE_DEBUG_MISC)) {
+ char *match;
+ struct vte_char_attributes *sattr, *eattr;
+ match = g_strndup(terminal->pvt->match_contents + matches[j].rm_so + coffset,
+ matches[j].rm_eo - matches[j].rm_so);
+ sattr = &g_array_index(terminal->pvt->match_attributes,
+ struct vte_char_attributes,
+ matches[j].rm_so + coffset);
+ eattr = &g_array_index(terminal->pvt->match_attributes,
+ struct vte_char_attributes,
+ matches[j].rm_eo + coffset - 1);
+ fprintf(stderr, "Match %d `%s' from %d(%ld,%ld) to %d(%ld,%ld) (%d).\n",
+ j, match,
+ matches[j].rm_so + coffset,
+ sattr->column,
+ sattr->row,
+ matches[j].rm_eo + coffset - 1,
+ eattr->column,
+ eattr->row,
+ offset);
+ g_free(match);
- }
+ }
#endif
- /* If the pointer is in this substring,
- * then we're done. */
- if ((offset >= matches[j].rm_so + coffset) &&
- (offset < matches[j].rm_eo + coffset)) {
- if (tag != NULL) {
- *tag = regex->tag;
- }
- if (start != NULL) {
- *start = matches[j].rm_so + coffset;
- }
- if (end != NULL) {
- *end = matches[j].rm_eo + coffset - 1;
- }
- return g_strndup(terminal->pvt->match_contents + matches[j].rm_so + coffset,
- matches[j].rm_eo - matches[j].rm_so);
+ /* Snip off any final newlines. */
+ while ((matches[j].rm_eo > matches[j].rm_so) &&
+ (terminal->pvt->match_contents[coffset + matches[j].rm_eo - 1] == '\n')) {
+ matches[j].rm_eo--;
+ }
+ /* If the pointer is in this substring,
+ * then we're done. */
+ if ((offset >= (matches[j].rm_so + coffset)) &&
+ (offset < (matches[j].rm_eo + coffset))) {
+ if (tag != NULL) {
+ *tag = regex->tag;
+ }
+ if (start != NULL) {
+ *start = coffset +
+ matches[j].rm_so;
+ }
+ if (end != NULL) {
+ *end = coffset +
+ matches[j].rm_eo - 1;
}
+ return g_strndup(terminal->pvt->match_contents + coffset + matches[j].rm_so,
+ matches[j].rm_eo - matches[j].rm_so);
}
- /* Skip past the beginning of this match to
- * look for more. */
- coffset += (matches[0].rm_so + 1);
- ret = regexec(&regex->reg,
- terminal->pvt->match_contents +
- coffset,
- G_N_ELEMENTS(matches),
- matches,
- VTE_REGEXEC_FLAGS);
}
+ /* Skip past the beginning of this match to
+ * look for more. */
+ coffset += (matches[0].rm_so + 1);
+ ret = regexec(&regex->reg,
+ terminal->pvt->match_contents + coffset,
+ G_N_ELEMENTS(matches),
+ matches,
+ VTE_REGEXEC_FLAGS);
}
}
return NULL;
@@ -1591,6 +1610,8 @@ vte_terminal_scroll_pages(VteTerminal *terminal, gint pages)
gtk_adjustment_set_value(terminal->adjustment, destination);
/* Clear dingus match set. */
vte_terminal_match_contents_clear(terminal);
+ /* Notify viewers that the contents have changed. */
+ vte_terminal_emit_contents_changed(terminal);
}
/* Scroll so that the scroll delta is the insertion delta. */
@@ -2444,7 +2465,7 @@ vte_terminal_ensure_cursor(VteTerminal *terminal, gboolean current)
if (fill) {
array = vte_new_row_data_sized(terminal, TRUE);
} else {
- array = vte_new_row_data();
+ array = vte_new_row_data(terminal);
}
_vte_ring_append(screen->row_data, array);
readjust = TRUE;
@@ -2658,7 +2679,7 @@ vte_sequence_handler_ic(VteTerminal *terminal,
save = screen->cursor_current;
- vte_terminal_insert_char(terminal, ' ', TRUE, TRUE);
+ vte_terminal_insert_char(terminal, ' ', TRUE, TRUE, -1);
screen->cursor_current = save;
}
@@ -3231,23 +3252,14 @@ vte_sequence_handler_ta(VteTerminal *terminal,
newcol = terminal->column_count - 1;
}
- /* Wrap to the next line if need be. */
- if (newcol >= terminal->column_count) {
- if (terminal->pvt->flags.am) {
- /* Move to the next line. */
- terminal->pvt->screen->cursor_current.col = 0;
- vte_sequence_handler_sf(terminal, match,
- match_quark, params);
- } else {
- /* Stay in the rightmost column. */
- newcol = terminal->column_count - 1;
- }
- } else {
- terminal->pvt->screen->cursor_current.col = newcol;
- }
+ /* Insert a tab character with the right width. */
+ vte_terminal_insert_char(terminal, '\t',
+ FALSE, FALSE,
+ newcol -
+ terminal->pvt->screen->cursor_current.col);
#ifdef VTE_DEBUG
if (_vte_debug_on(VTE_DEBUG_PARSE)) {
- fprintf(stderr, "Moving cursor to column %ld.\n", (long)newcol);
+ fprintf(stderr, "Inserting tab.\n");
}
#endif
}
@@ -3308,7 +3320,7 @@ vte_sequence_handler_uc(VteTerminal *terminal,
cell = vte_terminal_find_charcell(terminal,
column,
screen->cursor_current.row);
- while ((cell != NULL) && (cell->columns == 0) && (column > 0)) {
+ while ((cell != NULL) && (cell->fragment) && (column > 0)) {
column--;
cell = vte_terminal_find_charcell(terminal,
column,
@@ -3836,14 +3848,14 @@ vte_terminal_set_pointer_visible(VteTerminal *terminal, gboolean visible)
terminal->pvt->mouse_cell_motion_tracking ||
terminal->pvt->mouse_all_motion_tracking) {
#ifdef VTE_DEBUG
- if (_vte_debug_on(VTE_DEBUG_IO)) {
+ if (_vte_debug_on(VTE_DEBUG_CURSOR)) {
fprintf(stderr, "Setting mousing cursor.\n");
}
#endif
cursor = terminal->pvt->mouse_mousing_cursor;
} else {
#ifdef VTE_DEBUG
- if (_vte_debug_on(VTE_DEBUG_IO)) {
+ if (_vte_debug_on(VTE_DEBUG_CURSOR)) {
fprintf(stderr, "Setting default mouse "
"cursor.\n");
}
@@ -3852,7 +3864,7 @@ vte_terminal_set_pointer_visible(VteTerminal *terminal, gboolean visible)
}
} else {
#ifdef VTE_DEBUG
- if (_vte_debug_on(VTE_DEBUG_IO)) {
+ if (_vte_debug_on(VTE_DEBUG_CURSOR)) {
fprintf(stderr, "Setting to invisible cursor.\n");
}
#endif
@@ -4144,6 +4156,10 @@ vte_sequence_handler_decset_internal(VteTerminal *terminal,
/* Reset scrollbars and repaint everything. */
vte_terminal_adjust_adjustments(terminal, TRUE);
vte_invalidate_all(terminal);
+ /* Clear the matching view. */
+ vte_terminal_match_contents_clear(terminal);
+ /* Notify viewers that the contents have changed. */
+ vte_terminal_emit_contents_changed(terminal);
break;
case 9:
case 1000:
@@ -4711,7 +4727,7 @@ vte_sequence_handler_screen_alignment_test(VteTerminal *terminal,
row++) {
/* Find this row. */
while (_vte_ring_next(screen->row_data) <= row) {
- rowdata = vte_new_row_data();
+ rowdata = vte_new_row_data(terminal);
_vte_ring_append(screen->row_data, rowdata);
}
vte_terminal_adjust_adjustments(terminal, TRUE);
@@ -5641,16 +5657,16 @@ vte_terminal_set_color_background(VteTerminal *terminal,
* @palette: the color palette
* @palette_size: the number of entries in @palette
*
- * The terminal widget uses a 19-color model comprised of the default foreground
- * and background colors, the bold foreground color, an eight color palette, and
- * bold versions of the eight color palette.
+ * The terminal widget uses a 20-color model comprised of the default foreground
+ * and background colors, the bold foreground color, the cursor foreground
+ * color,an eight color palette, and bold versions of the eight color palette.
*
* @palette_size must be either 0, 8, or 16. If @foreground is NULL and
* @palette_size is greater than 0, the new foreground color is taken from
* @palette[7]. If @background is NULL and @palette_size is greater than 0,
- * the new background color is taken from @palette[0]. If @palette_size is
- * 8, the second 8-color palette is extrapolated from the new background
- * color and the items in @palette.
+ * the new background color is taken from @palette[0]. If
+ * @palette_size is 8, the second 8-color palette is extrapolated from the new
+ * background color and the items in @palette.
*
*/
void
@@ -5773,7 +5789,8 @@ vte_terminal_set_default_colors(VteTerminal *terminal)
/* Insert a single character into the stored data array. */
static void
vte_terminal_insert_char(VteTerminal *terminal, gunichar c,
- gboolean force_insert_mode, gboolean invalidate_cells)
+ gboolean force_insert_mode, gboolean invalidate_cells,
+ gint forced_width)
{
GArray *array;
struct vte_charcell cell, *pcell;
@@ -5805,11 +5822,15 @@ vte_terminal_insert_char(VteTerminal *terminal, gunichar c,
}
/* Figure out how many columns this character should occupy. */
- columns = vte_unichar_width(c);
- if (columns < 0) {
- g_warning(_("Character 0x%x is undefined, allocating one "
- "column."), c);
- columns = 1;
+ if (forced_width == -1) {
+ columns = vte_unichar_width(c);
+ if (columns < 0) {
+ g_warning(_("Character 0x%x is undefined, allocating "
+ "one column."), c);
+ columns = 1;
+ }
+ } else {
+ columns = forced_width;
}
/* If we're autowrapping here, do it. */
@@ -5862,9 +5883,12 @@ vte_terminal_insert_char(VteTerminal *terminal, gunichar c,
*pcell = screen->defaults;
pcell->c = cell.c;
pcell->columns = cell.columns;
+ pcell->fragment = cell.fragment;
/* Now set the character and column count. */
if (i == 0) {
+ /* This is an entire character or the first column of
+ * a multi-column character. */
if ((pcell->c != 0) &&
(c == '_') &&
(terminal->pvt->flags.ul)) {
@@ -5874,27 +5898,13 @@ vte_terminal_insert_char(VteTerminal *terminal, gunichar c,
/* Insert the character. */
pcell->c = c;
pcell->columns = columns;
+ pcell->fragment = 0;
}
} else {
/* This is a continuation cell. */
- pcell->columns = 0;
- }
-
- /* Signal that this part of the window needs drawing. */
- if (invalidate_cells) {
- if (insert) {
- vte_invalidate_cells(terminal,
- col,
- terminal->column_count -
- col,
- screen->cursor_current.row,
- 2);
- } else {
- vte_invalidate_cells(terminal,
- col, 1,
- screen->cursor_current.row,
- 2);
- }
+ pcell->c = c;
+ pcell->columns = columns;
+ pcell->fragment = 1;
}
/* And take a step to the to the right. */
@@ -5908,6 +5918,20 @@ vte_terminal_insert_char(VteTerminal *terminal, gunichar c,
}
}
+ /* Signal that this part of the window needs drawing. */
+ if (invalidate_cells) {
+ col = screen->cursor_current.col - columns;
+ if (insert) {
+ vte_invalidate_cells(terminal,
+ col, terminal->column_count - col,
+ screen->cursor_current.row, 1);
+ } else {
+ vte_invalidate_cells(terminal,
+ col, columns,
+ screen->cursor_current.row, 1);
+ }
+ }
+
/* Make sure the location the cursor is on exists. */
vte_terminal_ensure_cursor(terminal, FALSE);
@@ -6017,12 +6041,13 @@ vte_terminal_catch_child_exited(VteReaper *reaper, int pid, int status,
}
/**
- * vte_terminal_fork_logged_command:
+ * vte_terminal_fork_command:
* @terminal: a #VteTerminal
* @command: the name of a binary to run
* @argv: the argument list to be passed to @command
* @envv: a list of environment variables to be added to the environment before
* starting @command
+ * @directory: the name of a directory the command should start in, or NULL
* @lastlog: TRUE if the session should be logged to the lastlog
* @utmp: TRUE if the session should be logged to the utmp/utmpx log
* @wtmp: TRUE if the session should be logged to the wtmp/wtmpx log
@@ -6035,9 +6060,9 @@ vte_terminal_catch_child_exited(VteReaper *reaper, int pid, int status,
* Returns: the ID of the new process
*/
pid_t
-vte_terminal_fork_logged_command(VteTerminal *terminal, const char *command,
- char **argv, char **envv,
- gboolean lastlog, gboolean utmp, gboolean wtmp)
+vte_terminal_fork_command(VteTerminal *terminal, const char *command,
+ char **argv, char **envv, const char *directory,
+ gboolean lastlog, gboolean utmp, gboolean wtmp)
{
char **env_add;
int i;
@@ -6062,17 +6087,18 @@ vte_terminal_fork_logged_command(VteTerminal *terminal, const char *command,
env_add[i + 1] = NULL;
if (terminal->pvt->pty_master != -1) {
- vte_pty_close(terminal->pvt->pty_master);
- }
- terminal->pvt->pty_master = vte_pty_open_with_logging(&pid,
- env_add,
- command,
- argv,
- terminal->column_count,
- terminal->row_count,
- lastlog,
- utmp,
- wtmp);
+ _vte_pty_close(terminal->pvt->pty_master);
+ }
+ terminal->pvt->pty_master = _vte_pty_open(&pid,
+ env_add,
+ command,
+ argv,
+ directory,
+ terminal->column_count,
+ terminal->row_count,
+ lastlog,
+ utmp,
+ wtmp);
for (i = 0; env_add[i] != NULL; i++) {
g_free(env_add[i]);
@@ -6117,28 +6143,6 @@ vte_terminal_fork_logged_command(VteTerminal *terminal, const char *command,
return pid;
}
-/**
- * vte_terminal_fork_command:
- * @terminal: a #VteTerminal
- * @command: the name of a binary to run
- * @argv: the argument list to be passed to @command
- * @envv: a list of environment variables to be added to the environment before
- * starting @command
- *
- * Starts the specified command under a newly-alllocated control
- * pseudo-terminal. TERM is automatically set to reflect the terminal widget's
- * emulation setting.
- *
- * Returns: the ID of the new process
- */
-pid_t
-vte_terminal_fork_command(VteTerminal *terminal, const char *command,
- char **argv, char **envv)
-{
- return vte_terminal_fork_logged_command(terminal, command, argv, envv,
- FALSE, FALSE, FALSE);
-}
-
/* Handle an EOF from the client. */
static void
vte_terminal_eof(GIOChannel *channel, gpointer data)
@@ -6386,7 +6390,7 @@ vte_terminal_process_incoming(gpointer data)
if (c != 0) {
/* Insert the character. */
vte_terminal_insert_char(terminal, c,
- FALSE, FALSE);
+ FALSE, FALSE, -1);
}
modified = TRUE;
start++;
@@ -6511,7 +6515,6 @@ vte_terminal_process_incoming(gpointer data)
if (terminal->pvt->scroll_on_output || bottom) {
vte_terminal_scroll_to_bottom(terminal);
}
-
/* Deselect any existing selection. */
vte_terminal_deselect_all(terminal);
}
@@ -6519,6 +6522,7 @@ vte_terminal_process_incoming(gpointer data)
if (modified || (screen != terminal->pvt->screen)) {
/* Signal that the visible contents changed. */
vte_terminal_match_contents_clear(terminal);
+ /* Notify viewers that the contents have changed. */
vte_terminal_emit_contents_changed(terminal);
}
@@ -7398,23 +7402,6 @@ vte_cell_is_between(glong col, glong row,
glong acol, glong arow, glong bcol, glong brow,
gboolean inclusive)
{
- long t;
- /* Sort endpoints on the same row properly. */
- if (arow == brow) {
- if (acol > bcol) {
- t = acol;
- acol = bcol;
- bcol = t;
- }
- } else
- if (arow > brow) {
- t = arow;
- arow = brow;
- brow = t;
- t = acol;
- acol = bcol;
- bcol = t;
- }
/* No zero-length between allowed. */
if ((row == arow) && (row == brow) && (col == acol) && (col == bcol)) {
return FALSE;
@@ -7424,32 +7411,42 @@ vte_cell_is_between(glong col, glong row,
* or any of the lines in between. */
if ((row > arow) && (row < brow)) {
return TRUE;
- } else
+ }
/* It's also between the two points if they're on the same row
- * the cell lies between the start and end columns (which may not
- * be in the more obvious of two possible orders). */
+ * the cell lies between the start and end columns. */
if ((row == arow) && (row == brow)) {
if (col >= acol) {
if (col < bcol) {
return TRUE;
- } else
- if ((col == bcol) && inclusive) {
- return TRUE;
+ } else {
+ if ((col == bcol) && inclusive) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
}
+ } else {
+ return FALSE;
}
- } else
+ }
/* It's also "between" if it's on the line where the area starts and
* at or after the start column, or on the line where the area ends and
* before the end column. */
if ((row == arow) && (col >= acol)) {
return TRUE;
- } else
- if (row == brow) {
- if (col < bcol) {
- return TRUE;
- } else
- if ((col == bcol) && inclusive) {
- return TRUE;
+ } else {
+ if (row == brow) {
+ if (col < bcol) {
+ return TRUE;
+ } else {
+ if ((col == bcol) && inclusive) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+ } else {
+ return FALSE;
}
}
return FALSE;
@@ -7457,9 +7454,13 @@ vte_cell_is_between(glong col, glong row,
/* Check if a cell is selected or not. */
static gboolean
-vte_cell_is_selected(VteTerminal *terminal, glong col, glong row)
+vte_cell_is_selected(VteTerminal *terminal, glong col, glong row, gpointer data)
{
- long scol, ecol;
+ long i;
+ GArray *rowdata;
+ struct vte_charcell *cell;
+ struct selection_cell_coords ss, se;
+ VteScreen *screen;
/* If there's nothing selected, it's an easy question to answer. */
if (!terminal->pvt->has_selection) {
@@ -7468,21 +7469,87 @@ vte_cell_is_selected(VteTerminal *terminal, glong col, glong row)
/* Sort the two columns, for the cases where the selection is
* entirely within a single line. */
- scol = MIN(terminal->pvt->selection_start.x,
- terminal->pvt->selection_end.x);
- ecol = MAX(terminal->pvt->selection_start.x,
- terminal->pvt->selection_end.x);
+ ss = terminal->pvt->selection_start;
+ se = terminal->pvt->selection_end;
+ screen = terminal->pvt->screen;
+
+ /* Adjust the endpoint so that it it's an inclusive range. */
+ if (se.x > 0) {
+ se.x--;
+ }
+
+ /* Retrieve this row's data. */
+ if (!_vte_ring_contains(screen->row_data, row)) {
+ return FALSE;
+ }
+ rowdata = _vte_ring_index(screen->row_data, GArray*, row);
+
+ /* Handle end-of-line selection wackiness. */
+ if ((row == ss.y) && (row == se.y)) {
+ /* It's not selected if the both the start and end are after
+ * the end of the line. */
+ if ((ss.x >= rowdata->len) &&
+ (se.x >= rowdata->len) &&
+ (col >= rowdata->len)) {
+ return FALSE;
+ }
+ }
+ /* Checks for if we're at the start of the selection. */
+ if (row == ss.y) {
+ /* It's selected if the both the start of the selection and the
+ * current column are after the end. */
+ if ((ss.x >= rowdata->len) && (col >= rowdata->len)) {
+ return TRUE;
+ }
+ /* Also selected if it's before the start of the selection and
+ * there's nothing between here and the end of the line but
+ * spaces. */
+ if ((col < ss.x) && (ss.x < rowdata->len)) {
+ for (i = col; i < rowdata->len; i++) {
+ cell = &g_array_index(rowdata,
+ struct vte_charcell,
+ i);
+ if ((cell->c != 0) && (cell->c != ' ')) {
+ break;
+ }
+ }
+ if (i >= rowdata->len) {
+ return TRUE;
+ }
+ }
+ }
+ /* Checks for if we're at the end of the selection. */
+ if (row == se.y) {
+ /* It's selected if the both the end of the selection and the
+ * current column are after the end. */
+ if ((se.x >= rowdata->len) && (col >= rowdata->len)) {
+ return TRUE;
+ }
+ /* Also selected if it's past the end of the selection and
+ * there's nothing between here and the end of the line but
+ * spaces. */
+ if ((se.x < rowdata->len) && (se.x < col)) {
+ for (i = se.x; i < rowdata->len; i++) {
+ cell = &g_array_index(rowdata,
+ struct vte_charcell,
+ i);
+ if ((cell->c != 0) && (cell->c != ' ')) {
+ break;
+ }
+ }
+ if (i >= rowdata->len) {
+ return TRUE;
+ }
+ }
+ }
switch (terminal->pvt->selection_type) {
case selection_type_char:
/* A cell is selected if it's between the start and
* endpoints of the selection. */
if (vte_cell_is_between(col, row,
- terminal->pvt->selection_start.x,
- terminal->pvt->selection_start.y,
- terminal->pvt->selection_end.x,
- terminal->pvt->selection_end.y,
- FALSE)) {
+ ss.x, ss.y, se.x, se.y,
+ TRUE)) {
return TRUE;
}
break;
@@ -7490,35 +7557,33 @@ vte_cell_is_selected(VteTerminal *terminal, glong col, glong row)
/* A cell is selected if it's on the line where the
* selected area starts, or the line where it ends,
* or any of the lines in between. */
- if ((row > terminal->pvt->selection_start.y) &&
- (row < terminal->pvt->selection_end.y)) {
+ if ((row > ss.y) && (row < se.y)) {
return TRUE;
} else
/* It's also selected if the selection is confined to
* one line and the character lies between the start
* and end columns (which may not be in the more obvious
* of two possible orders). */
- if ((terminal->pvt->selection_start.y == row) &&
- (terminal->pvt->selection_end.y == row)) {
- if ((col >= scol) && (col <= ecol)) {
+ if ((ss.y == row) && (se.y == row)) {
+ if ((col >= ss.x) && (col <= se.x)) {
return TRUE;
} else
/* If the character is before the beginning of
* the region, it's also selected if it and
* everything else in between belongs to the
* same character class. */
- if (col < scol) {
+ if (col < ss.x) {
if (vte_uniform_class(terminal,
row,
col,
- scol)) {
+ ss.x)) {
return TRUE;
}
} else
- if (col > ecol) {
+ if (col > se.x) {
if (vte_uniform_class(terminal,
row,
- ecol,
+ se.x,
col)) {
return TRUE;
}
@@ -7528,24 +7593,24 @@ vte_cell_is_selected(VteTerminal *terminal, glong col, glong row)
* selected area starts and it's after the start column,
* or on the line where the selection ends, after the
* last selected column. */
- if (row == terminal->pvt->selection_start.y) {
- if (col >= terminal->pvt->selection_start.x) {
+ if (row == ss.y) {
+ if (col >= ss.x) {
return TRUE;
} else
if (vte_uniform_class(terminal,
row,
col,
- terminal->pvt->selection_start.x)) {
+ ss.x)) {
return TRUE;
}
} else
- if (row == terminal->pvt->selection_end.y) {
- if (col < terminal->pvt->selection_end.x) {
+ if (row == se.y) {
+ if (col <= se.x) {
return TRUE;
} else
if (vte_uniform_class(terminal,
row,
- terminal->pvt->selection_end.x,
+ se.x,
col)) {
return TRUE;
}
@@ -7555,8 +7620,7 @@ vte_cell_is_selected(VteTerminal *terminal, glong col, glong row)
/* A cell is selected if it's on the line where the
* selected area starts, or the line where it ends,
* or any of the lines in between. */
- if ((row >= terminal->pvt->selection_start.y) &&
- (row <= terminal->pvt->selection_end.y)) {
+ if ((row >= ss.y) && (row <= se.y)) {
return TRUE;
}
break;
@@ -7657,7 +7721,8 @@ vte_terminal_send_mouse_button_internal(VteTerminal *terminal,
/* Send a mouse button click/release notification. */
static void
-vte_terminal_send_mouse_button(VteTerminal *terminal, GdkEventButton *event)
+vte_terminal_maybe_send_mouse_button(VteTerminal *terminal,
+ GdkEventButton *event)
{
GdkModifierType modifiers;
@@ -7666,6 +7731,24 @@ vte_terminal_send_mouse_button(VteTerminal *terminal, GdkEventButton *event)
modifiers = 0;
}
+ /* Decide whether or not to do anything. */
+ switch (event->type) {
+ case GDK_BUTTON_PRESS:
+ if (!terminal->pvt->mouse_send_xy_on_button &&
+ !terminal->pvt->mouse_send_xy_on_click) {
+ return;
+ }
+ break;
+ case GDK_BUTTON_RELEASE:
+ if (!terminal->pvt->mouse_send_xy_on_button) {
+ return;
+ }
+ break;
+ default:
+ return;
+ break;
+ }
+
/* Encode the parameters and send them to the app. */
vte_terminal_send_mouse_button_internal(terminal,
(event->type == GDK_BUTTON_PRESS) ?
@@ -7677,7 +7760,7 @@ vte_terminal_send_mouse_button(VteTerminal *terminal, GdkEventButton *event)
/* Send a mouse motion notification. */
static void
-vte_terminal_send_mouse_drag(VteTerminal *terminal, GdkEventMotion *event)
+vte_terminal_maybe_send_mouse_drag(VteTerminal *terminal, GdkEventMotion *event)
{
unsigned char cb = 0, cx = 0, cy = 0;
char buf[LINE_MAX];
@@ -7686,19 +7769,31 @@ vte_terminal_send_mouse_drag(VteTerminal *terminal, GdkEventMotion *event)
g_return_if_fail(VTE_IS_TERMINAL(terminal));
/* First determine if we even want to send notification. */
- if (!terminal->pvt->mouse_cell_motion_tracking &&
- !terminal->pvt->mouse_all_motion_tracking) {
- return;
- }
- if (terminal->pvt->mouse_cell_motion_tracking) {
- if (((event->x - VTE_PAD_WIDTH) / terminal->char_width ==
- terminal->pvt->mouse_last_x / terminal->char_width) &&
- ((event->y - VTE_PAD_WIDTH) / terminal->char_height ==
- terminal->pvt->mouse_last_y / terminal->char_height)) {
+ switch (event->type) {
+ case GDK_MOTION_NOTIFY:
+ if (!terminal->pvt->mouse_cell_motion_tracking &&
+ !terminal->pvt->mouse_all_motion_tracking) {
return;
}
+ if (terminal->pvt->mouse_cell_motion_tracking) {
+ if (((event->x - VTE_PAD_WIDTH) /
+ terminal->char_width ==
+ terminal->pvt->mouse_last_x /
+ terminal->char_width) &&
+ ((event->y - VTE_PAD_WIDTH) /
+ terminal->char_height ==
+ terminal->pvt->mouse_last_y /
+ terminal->char_height)) {
+ return;
+ }
+ }
+ break;
+ default:
+ return;
+ break;
}
+
/* Read the modifiers. */
if (gdk_event_get_state((GdkEvent*)event, &modifiers) == FALSE) {
modifiers = 0;
@@ -7736,7 +7831,8 @@ vte_terminal_send_mouse_drag(VteTerminal *terminal, GdkEventMotion *event)
cb += 64; /* 32 for normal, 32 for movement */
/* Encode the cursor coordinates. */
- cx = 32 + 1 + ((event->x - VTE_PAD_WIDTH) / terminal->char_width);
+ cx = 32 + 1 + ((event->x - VTE_PAD_WIDTH + terminal->char_width / 2) /
+ terminal->char_width);
cy = 32 + 1 + ((event->y - VTE_PAD_WIDTH) / terminal->char_height);
/* Send the event to the child. */
@@ -7765,10 +7861,8 @@ vte_terminal_match_hilite_clear(VteTerminal *terminal)
}
#endif
vte_invalidate_cells(terminal,
- 0,
- terminal->column_count,
- srow,
- erow - srow + 1);
+ 0, terminal->column_count,
+ srow, erow - srow + 1);
}
}
@@ -7844,274 +7938,11 @@ vte_terminal_match_hilite(VteTerminal *terminal, double x, double y)
#endif
/* Repaint what used to be hilited, if anything. */
vte_invalidate_cells(terminal,
- 0,
- terminal->column_count,
+ 0, terminal->column_count,
rows, rowe - rows + 1);
}
}
-/* Recalculate the start- and endpoints of the selected text, using the
- * selection origin and "last" coordinate sets. */
-static void
-vte_terminal_selection_recompute(VteTerminal *terminal)
-{
- struct {
- long x, y;
- } origin, last, start, end;
- long width, height;
-
- g_return_if_fail(VTE_IS_TERMINAL(terminal));
-
- width = terminal->char_width;
- height = terminal->char_height;
- origin.x = (terminal->pvt->selection_origin.x + width / 2) / width;
- origin.y = (terminal->pvt->selection_origin.y) / height;
- last.x = (terminal->pvt->selection_last.x + width / 2) / width;
- last.y = (terminal->pvt->selection_last.y) / height;
- start.x = start.y = end.x = end.y = 0;
-
- if (last.y > origin.y) {
- start.x = origin.x;
- start.y = origin.y;
- end.x = last.x;
- end.y = last.y;
- } else
- if (last.y < origin.y) {
- start.x = last.x;
- start.y = last.y;
- end.x = origin.x;
- end.y = origin.y;
- } else
- /* last.y == origin.y */
- if (last.x > origin.x) {
- start.x = origin.x;
- start.y = origin.y;
- end.x = last.x;
- end.y = last.y;
- } else {
- start.x = last.x;
- start.y = last.y;
- end.x = origin.x;
- end.y = origin.y;
- }
-
- terminal->pvt->selection_start.x = start.x;
- terminal->pvt->selection_start.y = start.y;
- terminal->pvt->selection_end.x = end.x;
- terminal->pvt->selection_end.y = end.y;
-}
-
-static int
-vte_terminal_autoscroll(gpointer data)
-{
- VteTerminal *terminal;
- GtkWidget *widget;
- double adj;
- long row;
-
- terminal = VTE_TERMINAL(data);
- widget = GTK_WIDGET(terminal);
- /* Provide immediate autoscroll for mouse wigglers. */
- if (terminal->pvt->mouse_last_y < widget->allocation.y) {
- if (terminal->adjustment) {
- adj = CLAMP(terminal->adjustment->value - 1,
- terminal->adjustment->lower,
- terminal->adjustment->upper -
- terminal->row_count);
- gtk_adjustment_set_value(terminal->adjustment,
- adj);
- terminal->pvt->selection_last.x =
- terminal->pvt->mouse_last_x;
- terminal->pvt->selection_last.y =
- terminal->pvt->mouse_last_y +
- terminal->char_height * adj;
- row = terminal->pvt->selection_start.y;
- vte_terminal_selection_recompute(terminal);
- terminal->pvt->selection_start.x = 0;
- terminal->pvt->selection_start.y = adj;
- vte_invalidate_cells(terminal,
- 0,
- terminal->column_count,
- terminal->pvt->selection_start.y,
- row + 1 -
- terminal->pvt->selection_start.y);
- }
-#ifdef VTE_DEBUG
- if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
- fprintf(stderr, "Autoscrolling down.\n");
- }
-#endif
- } else
- if (terminal->pvt->mouse_last_y + 2 * VTE_PAD_WIDTH >
- widget->allocation.height) {
- adj = CLAMP(terminal->adjustment->value + 1,
- terminal->adjustment->lower,
- terminal->adjustment->upper -
- terminal->row_count);
- gtk_adjustment_set_value(terminal->adjustment,
- adj);
- terminal->pvt->selection_last.x =
- terminal->pvt->mouse_last_x;
- terminal->pvt->selection_last.y =
- terminal->pvt->mouse_last_y +
- terminal->char_height * adj;
- row = terminal->pvt->selection_end.y;
- vte_terminal_selection_recompute(terminal);
- terminal->pvt->selection_end.x =
- terminal->column_count;
- terminal->pvt->selection_end.y =
- adj + terminal->row_count - 1;
- vte_invalidate_cells(terminal,
- 0,
- terminal->column_count,
- row,
- terminal->pvt->selection_end.y -
- row + 1);
-#ifdef VTE_DEBUG
- if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
- fprintf(stderr, "Autoscrolling down.\n");
- }
-#endif
- } else {
- terminal->pvt->mouse_autoscroll_tag = 0;
- }
- return (terminal->pvt->mouse_autoscroll_tag != 0);
-}
-
-/* Read and handle a motion event. */
-static gint
-vte_terminal_motion_notify(GtkWidget *widget, GdkEventMotion *event)
-{
- VteTerminal *terminal;
- long delta;
- GdkModifierType modifiers;
- long top, height;
- double adj;
- gboolean need_autoscroll;
-
- g_return_val_if_fail(VTE_IS_TERMINAL(widget), FALSE);
- terminal = VTE_TERMINAL(widget);
- delta = terminal->pvt->screen->scroll_delta;
-
- /* Show the cursor. */
- vte_terminal_set_pointer_visible(terminal, TRUE);
-
- /* Read the modifiers. */
- if (gdk_event_get_state((GdkEvent*)event, &modifiers) == FALSE) {
- modifiers = 0;
- }
- /* Handle a drag event if we're running a mouse-aware application. */
- if ((terminal->pvt->mouse_last_button != 0) &&
- (terminal->pvt->mouse_send_xy_on_click ||
- terminal->pvt->mouse_send_xy_on_button ||
- terminal->pvt->mouse_hilite_tracking ||
- terminal->pvt->mouse_cell_motion_tracking ||
- terminal->pvt->mouse_all_motion_tracking) &&
- ((modifiers & GDK_SHIFT_MASK) == 0)) {
-#ifdef VTE_DEBUG
- if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
- fprintf(stderr, "Mousing drag.\n");
- }
-#endif
- vte_terminal_send_mouse_drag(terminal, event);
- } else
- if (terminal->pvt->mouse_last_button == 1) {
-#ifdef VTE_DEBUG
- if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
- fprintf(stderr, "Drag.\n");
- }
-#endif
- /* If we delayed resetting selection, reset here. */
- if (terminal->pvt->restart_selection) {
- vte_terminal_deselect_all(terminal);
- terminal->pvt->selection_origin.x =
- terminal->pvt->selection_delayed.x;
- terminal->pvt->selection_origin.y =
- terminal->pvt->selection_delayed.y;
- terminal->pvt->selection_type = selection_type_char;
- }
- terminal->pvt->has_selection = TRUE;
-
- top = MIN(terminal->pvt->selection_last.y,
- event->y - VTE_PAD_WIDTH +
- (delta * terminal->char_height)) /
- terminal->char_height;
- height = (MAX(terminal->pvt->selection_last.y,
- event->y - VTE_PAD_WIDTH +
- (delta * terminal->char_height)) /
- terminal->char_height) - top + 1;
-
- terminal->pvt->selection_last.x = event->x - VTE_PAD_WIDTH;
- terminal->pvt->selection_last.y = event->y - VTE_PAD_WIDTH +
- terminal->char_height * delta;
- vte_terminal_selection_recompute(terminal);
-
-#ifdef VTE_DEBUG
- if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
- fprintf(stderr, "selection is (%ld,%ld) to (%ld,%ld)\n",
- terminal->pvt->selection_start.x,
- terminal->pvt->selection_start.y,
- terminal->pvt->selection_end.x,
- terminal->pvt->selection_end.y);
- fprintf(stderr, "repainting rows %ld to %ld\n",
- top, top + height);
- }
-#endif
- vte_invalidate_cells(terminal, 0, terminal->column_count,
- top, height);
-
- vte_terminal_emit_selection_changed (terminal);
-
- /* Provide immediate autoscroll for mouse wigglers. */
- need_autoscroll = FALSE;
- if (event->y < 0) {
- if (terminal->adjustment) {
- adj = CLAMP(terminal->adjustment->value - 1,
- terminal->adjustment->lower,
- terminal->adjustment->upper -
- terminal->row_count);
- gtk_adjustment_set_value(terminal->adjustment,
- adj);
- need_autoscroll = TRUE;
- }
- } else
- if (event->y >= widget->allocation.height) {
- adj = CLAMP(terminal->adjustment->value + 1,
- terminal->adjustment->lower,
- terminal->adjustment->upper -
- terminal->row_count);
- gtk_adjustment_set_value(terminal->adjustment,
- adj);
- need_autoscroll = TRUE;
- }
- if (need_autoscroll &&
- (terminal->pvt->mouse_autoscroll_tag == 0)) {
- terminal->pvt->mouse_autoscroll_tag = g_timeout_add_full(G_PRIORITY_LOW,
- 50,
- vte_terminal_autoscroll,
- terminal,
- NULL);
- }
- } else {
-#ifdef VTE_DEBUG
- if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
- fprintf(stderr, "Mouse move (button %d).\n",
- terminal->pvt->mouse_last_button);
- }
-#endif
- }
-
- /* Hilite any matches. */
- vte_terminal_match_hilite(terminal,
- event->x - VTE_PAD_WIDTH,
- event->y - VTE_PAD_WIDTH);
-
- /* Save the pointer coordinates for later use. */
- terminal->pvt->mouse_last_x = event->x - VTE_PAD_WIDTH;
- terminal->pvt->mouse_last_y = event->y - VTE_PAD_WIDTH;
-
- return FALSE;
-}
/* Note that the clipboard has cleared. */
static void
@@ -8162,6 +7993,7 @@ vte_terminal_copy_cb(GtkClipboard *clipboard, GtkSelectionData *data,
* @end_row: last row to search for data
* @end_col: last column to search for data
* @is_selected: a callback
+ * @data: user data to be passed to the callback
* @attributes: location for storing text attributes
*
* Extracts a view of the visible part of the string. If @is_selected is not
@@ -8178,15 +8010,17 @@ char *
vte_terminal_get_text_range(VteTerminal *terminal,
glong start_row, glong start_col,
glong end_row, glong end_col,
- gboolean(*is_selected)(VteTerminal *, glong, glong),
+ gboolean(*is_selected)(VteTerminal *, glong, glong,
+ gpointer),
+ gpointer data,
GArray *attributes)
{
- long col, row, spaces;
+ long col, row, last_space, last_nonspace, last_nonspacecol;
VteScreen *screen;
- struct vte_charcell *pcell;
+ struct vte_charcell *pcell = NULL;
GString *string;
struct vte_char_attributes attr;
- struct vte_palette_entry fore, back;
+ struct vte_palette_entry fore, back, *palette;
g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
g_return_val_if_fail(is_selected != NULL, NULL);
@@ -8195,53 +8029,45 @@ vte_terminal_get_text_range(VteTerminal *terminal,
string = g_string_new("");
memset(&attr, 0, sizeof(attr));
+ palette = terminal->pvt->palette;
for (row = start_row; row <= end_row; row++) {
col = (row == start_row) ? start_col : 0;
- spaces = 0;
+ last_space = last_nonspace = last_nonspacecol = -1;
attr.row = row;
+ pcell = NULL;
do {
+ /* If it's not part of a multi-column character,
+ * and passes the selection criterion, add it to
+ * the selection. */
+ attr.column = col;
pcell = vte_terminal_find_charcell(terminal, col, row);
- if (is_selected(terminal, col, row)) {
- if (pcell == NULL) {
- /* If there are no more cells on this
- * line, and we haven't hit the right
- * margin yet, add a newline. */
- if ((col < terminal->column_count) ||
- (spaces > 0)) {
- string = g_string_append_c(string, '\n');
- spaces = 0;
- }
- break;
- } else
- if (pcell->columns == 0) {
- /* Ignore this padding cell. */
- } else
- if ((pcell->c == 0) ||
- (g_unichar_isspace(pcell->c))) {
- /* Count this in case there's something
- * to the right of it. */
- spaces++;
+ if (pcell == NULL) {
+ /* No more characters on this line. */
+ break;
+ }
+ if (!pcell->fragment &&
+ is_selected(terminal, col, row, data)) {
+ /* Store the attributes of this character. */
+ fore = palette[pcell->fore];
+ back = palette[pcell->back];
+ attr.fore.red = fore.red;
+ attr.fore.green = fore.green;
+ attr.fore.blue = fore.blue;
+ attr.back.red = back.red;
+ attr.back.green = back.green;
+ attr.back.blue = back.blue;
+ attr.underline = pcell->underline;
+ attr.alternate = pcell->alternate;
+ /* Store the character. */
+ string = g_string_append_unichar(string,
+ pcell->c);
+ /* Record whether or not this was
+ * whitespace. */
+ if ((pcell->c == ' ') || (pcell->c == '\0')) {
+ last_space = string->len - 1;
} else {
- /* Use the attributes of this
- * character. */
- fore = terminal->pvt->palette[pcell->fore];
- back = terminal->pvt->palette[pcell->back];
- attr.fore.red = fore.red;
- attr.fore.green = fore.green;
- attr.fore.blue = fore.blue;
- attr.back.red = back.red;
- attr.back.green = back.green;
- attr.back.blue = back.blue;
- attr.underline = pcell->underline;
- attr.alternate = pcell->alternate;
- attr.column = col;
- /* Stuff any saved spaces in. */
- while (spaces > 0) {
- string = g_string_append_c(string, ' ');
- spaces--;
- }
- /* Stuff the character in this cell. */
- string = g_string_append_unichar(string, pcell->c);
+ last_nonspace = string->len - 1;
+ last_nonspacecol = col;
}
}
/* If we added a character to the string, record its
@@ -8250,29 +8076,51 @@ vte_terminal_get_text_range(VteTerminal *terminal,
vte_g_array_fill(attributes,
&attr, string->len);
}
- col++;
- if ((col >= terminal->column_count) ||
- ((row == end_row) && (col > end_col))) {
+ /* If we're on the last line, and have just looked in
+ * the last column, stop. */
+ if ((row == end_row) && (col == end_col)) {
break;
}
+ col++;
} while (pcell != NULL);
- /* Extra spaces at the end of a line become newlines unless
- * this is the last row of the selection. */
- if (spaces > 0) {
- if (row != end_row) {
+ /* If the last thing we saw was a space, trim the
+ * trailing spaces off of the line. */
+ if ((last_space != -1) &&
+ (last_nonspace != -1) &&
+ (last_space > last_nonspace)) {
+ g_string_truncate(string, last_nonspace + 1);
+ }
+ /* Make sure that the attributes array is as long as the
+ * string. */
+ if (attributes) {
+ g_array_set_size(attributes, string->len);
+ }
+ /* If the last visible column on this line was selected and
+ * it contained whitespace, append a newline. */
+ if (is_selected(terminal, terminal->column_count - 1,
+ row, data)) {
+ pcell = vte_terminal_find_charcell(terminal,
+ terminal->column_count - 1,
+ row);
+ /* If it's whitespace, we snipped it off, so add a
+ * newline. */
+ if ((pcell == NULL) ||
+ (pcell->c == '\0') ||
+ (pcell->c == ' ')) {
string = g_string_append_c(string, '\n');
- } else {
- string = g_string_append_c(string, ' ');
}
- spaces = 0;
- attr.column = col;
- }
- /* If we broke out of the loop, there might be more characters
- * with missing attributes. */
- if (attributes) {
- vte_g_array_fill(attributes, &attr, string->len);
+ /* Move this newline to the end of the line. */
+ attr.column = MAX(terminal->column_count,
+ attr.column + 1);
+ /* If we broke out of the loop, there's at least one
+ * character with missing attributes. */
+ if (attributes) {
+ vte_g_array_fill(attributes, &attr,
+ string->len);
+ }
}
}
+ /* Sanity check. */
if (attributes) {
g_assert(string->len == attributes->len);
}
@@ -8283,6 +8131,7 @@ vte_terminal_get_text_range(VteTerminal *terminal,
* vte_terminal_get_text:
* @terminal: a #VteTerminal
* @is_selected: a callback
+ * @data: user data to be passed to the callback
* @attributes: location for storing text attributes
*
* Extracts a view of the visible part of the string. If @is_selected is not
@@ -8295,7 +8144,9 @@ vte_terminal_get_text_range(VteTerminal *terminal,
*/
char *
vte_terminal_get_text(VteTerminal *terminal,
- gboolean(*is_selected)(VteTerminal *, glong, glong),
+ gboolean(*is_selected)(VteTerminal *, glong, glong,
+ gpointer),
+ gpointer data,
GArray *attributes)
{
long start_row, start_col, end_row, end_col;
@@ -8308,6 +8159,7 @@ vte_terminal_get_text(VteTerminal *terminal,
end_row, end_col,
is_selected ?
is_selected : always_selected,
+ data,
attributes);
}
@@ -8354,13 +8206,15 @@ vte_terminal_copy(VteTerminal *terminal, GdkAtom board)
if (terminal->pvt->selection != NULL) {
g_free(terminal->pvt->selection);
}
- terminal->pvt->selection = vte_terminal_get_text_range(terminal,
- terminal->pvt->selection_start.y,
- 0,
- terminal->pvt->selection_end.y,
- terminal->column_count,
- vte_cell_is_selected,
- NULL);
+ terminal->pvt->selection =
+ vte_terminal_get_text_range(terminal,
+ terminal->pvt->selection_start.y,
+ 0,
+ terminal->pvt->selection_end.y,
+ terminal->column_count,
+ vte_cell_is_selected,
+ NULL,
+ NULL);
/* Place the text on the clipboard. */
if (terminal->pvt->selection != NULL) {
@@ -8397,6 +8251,400 @@ vte_terminal_paste(VteTerminal *terminal, GdkAtom board)
}
}
+/* Start selection at the location of the event. */
+static void
+vte_terminal_start_selection(GtkWidget *widget, GdkEventButton *event,
+ enum vte_selection_type selection_type)
+{
+ VteTerminal *terminal;
+ long cellx, celly, delta;
+
+ terminal = VTE_TERMINAL(widget);
+
+ /* Convert the event coordinates to cell coordinates. */
+ delta = terminal->pvt->screen->scroll_delta;
+ cellx = (event->x - VTE_PAD_WIDTH) / terminal->char_width;
+ celly = (event->y - VTE_PAD_WIDTH) / terminal->char_height + delta;
+
+ /* Remove our pre-existing selection unless we're performing a
+ * delayed selection start. . */
+ switch (selection_type) {
+ case selection_type_char:
+ terminal->pvt->restart_selection = TRUE;
+ break;
+ case selection_type_word:
+ case selection_type_line:
+ vte_terminal_deselect_all(terminal);
+ terminal->pvt->restart_selection = FALSE;
+ break;
+ }
+
+ /* Record that we have the selection, and where it started. */
+ terminal->pvt->has_selection = TRUE;
+ terminal->pvt->selection_last.x = event->x - VTE_PAD_WIDTH;
+ terminal->pvt->selection_last.y = event->y - VTE_PAD_WIDTH +
+ (terminal->char_height * delta);
+ terminal->pvt->selection_origin = terminal->pvt->selection_last;
+ terminal->pvt->selection_start.x = cellx;
+ terminal->pvt->selection_start.y = celly;
+ terminal->pvt->selection_end = terminal->pvt->selection_start;
+
+ /* Record the selection type. */
+ terminal->pvt->selection_type = selection_type;
+
+ /* Draw the row the selection started on. */
+ vte_invalidate_cells(terminal,
+ 0, terminal->column_count,
+ terminal->pvt->selection_start.y, 1);
+#ifdef VTE_DEBUG
+ if (_vte_debug_on(VTE_DEBUG_SELECTION)) {
+ fprintf(stderr, "Selection started at (%ld,%ld).\n",
+ terminal->pvt->selection_start.x,
+ terminal->pvt->selection_start.y);
+ }
+#endif
+ vte_terminal_emit_selection_changed(terminal);
+}
+
+/* Extend selection to include the given event coordinates. */
+static void
+vte_terminal_extend_selection(GtkWidget *widget, double x, double y,
+ gboolean always_grow)
+{
+ VteTerminal *terminal;
+ long delta, height, width;
+ struct selection_event_coords *origin, *last, *start, *end;
+ struct selection_cell_coords old_start, old_end, *sc, *ec, tc;
+
+ terminal = VTE_TERMINAL(widget);
+ old_start = terminal->pvt->selection_start;
+ old_end = terminal->pvt->selection_end;
+ height = terminal->char_height;
+ width = terminal->char_width;
+
+ /* Convert the event coordinates to cell coordinates. */
+ delta = terminal->pvt->screen->scroll_delta;
+
+ /* If we're restarting selection, set the origin to the last recorded
+ * position for the mouse. */
+ if (terminal->pvt->restart_selection) {
+ vte_terminal_deselect_all(terminal);
+ terminal->pvt->selection_origin.x =
+ terminal->pvt->mouse_last_x;
+ terminal->pvt->selection_origin.y =
+ terminal->pvt->mouse_last_y + (height * delta);
+ terminal->pvt->restart_selection = FALSE;
+ terminal->pvt->has_selection = TRUE;
+#ifdef VTE_DEBUG
+ if (_vte_debug_on(VTE_DEBUG_SELECTION)) {
+ fprintf(stderr, "Selection restarted at (%lf,%lf).\n",
+ terminal->pvt->selection_origin.x / width,
+ terminal->pvt->selection_origin.y / height);
+ }
+#endif
+ }
+
+ /* Extend the selection by moving the "last" pointer to the event's
+ * coordinates. */
+ last = &terminal->pvt->selection_last;
+ if (!always_grow) {
+ last->x = x + width / 2;
+ last->y = y + height * delta;
+ }
+
+ /* Recalculate the selected area. */
+ origin = &terminal->pvt->selection_origin;
+ if ((origin->y / height < last->y / height) ||
+ ((origin->y / height == last->y / height) &&
+ (origin->x / width < last->x / width ))) {
+ /* The origin point is "before" the last point. */
+ start = origin;
+ end = last;
+ } else {
+ /* The last point is "before" the origin point. */
+ start = last;
+ end = origin;
+ }
+
+ /* Extend the selection by moving whichever end of the selection is
+ * closer to the new point. */
+ if (always_grow) {
+ /* New endpoint is before existing selection. */
+ if ((y / height < start->y / height) ||
+ ((y / height == start->y / height) &&
+ (x / width < start->x / width))) {
+ start->x = x;
+ start->y = y + height * delta;
+ } else {
+ /* New endpoint is after existing selection. */
+ end->x = x;
+ end->y = y + height * delta;
+ }
+ }
+
+#ifdef VTE_DEBUG
+ if (_vte_debug_on(VTE_DEBUG_SELECTION)) {
+ fprintf(stderr, "Selection is (%lf,%lf) to (%lf,%lf).\n",
+ start->x, start->y, end->x, end->y);
+ }
+#endif
+
+ /* Recalculate the selection area in terms of cell positions. */
+ terminal->pvt->selection_start.x = start->x / width;
+ terminal->pvt->selection_start.y = start->y / height;
+ terminal->pvt->selection_end.x = end->x / width;
+ terminal->pvt->selection_end.y = end->y / height;
+
+ /* Re-sort. */
+ sc = &terminal->pvt->selection_start;
+ ec = &terminal->pvt->selection_end;
+ if ((sc->y > ec->y) || ((sc->y == ec->y) && (sc->x > ec->x))) {
+ tc = *sc;
+ *sc = *ec;
+ *ec = tc;
+ }
+
+ /* Redraw the rows which have contain cells which have changed their
+ * is-selected status. */
+ if ((old_start.x != terminal->pvt->selection_start.x) ||
+ (old_start.y != terminal->pvt->selection_start.y)) {
+#ifdef VTE_DEBUG
+ if (_vte_debug_on(VTE_DEBUG_SELECTION)) {
+ fprintf(stderr, "Refreshing lines %ld to %ld.\n",
+ MIN(old_start.y,
+ terminal->pvt->selection_start.y),
+ MAX(old_start.y,
+ terminal->pvt->selection_start.y));
+ }
+#endif
+ vte_invalidate_cells(terminal,
+ 0,
+ terminal->column_count,
+ MIN(old_start.y,
+ terminal->pvt->selection_start.y),
+ ABS(old_start.y -
+ terminal->pvt->selection_start.y) + 1);
+ }
+ if ((old_end.x != terminal->pvt->selection_end.x) ||
+ (old_end.y != terminal->pvt->selection_end.y)) {
+#ifdef VTE_DEBUG
+ if (_vte_debug_on(VTE_DEBUG_SELECTION)) {
+ fprintf(stderr, "Refreshing lines %ld to %ld.\n",
+ MIN(old_end.y, terminal->pvt->selection_end.y),
+ MAX(old_end.y, terminal->pvt->selection_end.y));
+ }
+#endif
+ vte_invalidate_cells(terminal,
+ 0,
+ terminal->column_count,
+ MIN(old_end.y,
+ terminal->pvt->selection_end.y),
+ ABS(old_end.y -
+ terminal->pvt->selection_end.y) + 1);
+ }
+
+#ifdef VTE_DEBUG
+ if (_vte_debug_on(VTE_DEBUG_SELECTION)) {
+ fprintf(stderr, "Selection changed to "
+ "(%ld,%ld) to (%ld,%ld).\n",
+ terminal->pvt->selection_start.x,
+ terminal->pvt->selection_start.y,
+ terminal->pvt->selection_end.x,
+ terminal->pvt->selection_end.y);
+ }
+#endif
+ vte_terminal_emit_selection_changed(terminal);
+}
+
+/* Autoscroll a bit. */
+static int
+vte_terminal_autoscroll(gpointer data)
+{
+ VteTerminal *terminal;
+ GtkWidget *widget;
+ gboolean extend = FALSE;
+ gdouble x, y, xmax, ymax;
+ double adj;
+
+ terminal = VTE_TERMINAL(data);
+ widget = GTK_WIDGET(terminal);
+
+ /* Provide an immediate effect for mouse wigglers. */
+ if (terminal->pvt->mouse_last_y < 0) {
+ if (terminal->adjustment) {
+ /* Try to scroll up by one line. */
+ adj = CLAMP(terminal->adjustment->value - 1,
+ terminal->adjustment->lower,
+ terminal->adjustment->upper -
+ terminal->row_count);
+ gtk_adjustment_set_value(terminal->adjustment, adj);
+ extend = TRUE;
+ }
+#ifdef VTE_DEBUG
+ if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
+ fprintf(stderr, "Autoscrolling down.\n");
+ }
+#endif
+ }
+ if (terminal->pvt->mouse_last_y >
+ terminal->row_count * terminal->char_height) {
+ if (terminal->adjustment) {
+ /* Try to scroll up by one line. */
+ adj = CLAMP(terminal->adjustment->value + 1,
+ terminal->adjustment->lower,
+ terminal->adjustment->upper -
+ terminal->row_count);
+ gtk_adjustment_set_value(terminal->adjustment, adj);
+ extend = TRUE;
+ }
+#ifdef VTE_DEBUG
+ if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
+ fprintf(stderr, "Autoscrolling up.\n");
+ }
+#endif
+ }
+ if (extend) {
+ /* Don't select off-screen areas. That just confuses people. */
+ xmax = terminal->column_count * terminal->char_width;
+ ymax = terminal->row_count * terminal->char_height;
+
+ x = CLAMP(terminal->pvt->mouse_last_x, 0, xmax);
+ y = CLAMP(terminal->pvt->mouse_last_y, 0, ymax);
+ /* If we clamped the Y, mess with the X to get the entire
+ * lines. */
+ if (terminal->pvt->mouse_last_y < 0) {
+ x = 0;
+ }
+ if (terminal->pvt->mouse_last_y > ymax) {
+ x = terminal->column_count * terminal->char_width;
+ }
+ /* Extend selection to cover the newly-scrolled area. */
+ vte_terminal_extend_selection(widget, x, y, FALSE);
+ } else {
+ /* Stop autoscrolling. */
+ terminal->pvt->mouse_autoscroll_tag = 0;
+ }
+ return (terminal->pvt->mouse_autoscroll_tag != 0);
+}
+
+/* Start autoscroll. */
+static void
+vte_terminal_start_autoscroll(VteTerminal *terminal)
+{
+ if (terminal->pvt->mouse_autoscroll_tag == 0) {
+ terminal->pvt->mouse_autoscroll_tag =
+ g_timeout_add_full(G_PRIORITY_LOW,
+ 1000 / terminal->row_count,
+ vte_terminal_autoscroll,
+ terminal,
+ NULL);
+ }
+}
+
+/* Stop autoscroll. */
+static void
+vte_terminal_stop_autoscroll(VteTerminal *terminal)
+{
+ if (terminal->pvt->mouse_autoscroll_tag != 0) {
+ g_source_remove(terminal->pvt->mouse_autoscroll_tag);
+ terminal->pvt->mouse_autoscroll_tag = 0;
+ }
+}
+
+/* Read and handle a motion event. */
+static gint
+vte_terminal_motion_notify(GtkWidget *widget, GdkEventMotion *event)
+{
+ VteTerminal *terminal;
+ GdkModifierType modifiers;
+
+ g_return_val_if_fail(VTE_IS_TERMINAL(widget), FALSE);
+ terminal = VTE_TERMINAL(widget);
+
+#ifdef VTE_DEBUG
+ if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
+ fprintf(stderr, "Motion notify (%lf,%lf).\n",
+ event->x, event->y);
+ }
+#endif
+
+ /* Show the cursor. */
+ vte_terminal_set_pointer_visible(terminal, TRUE);
+
+ /* Grab input focus. */
+ if (!GTK_WIDGET_HAS_FOCUS(widget)) {
+ gtk_widget_grab_focus(widget);
+ }
+
+ /* Read the modifiers. */
+ if (gdk_event_get_state((GdkEvent*)event, &modifiers) == FALSE) {
+ modifiers = 0;
+ }
+
+ switch (event->type) {
+ case GDK_MOTION_NOTIFY:
+ switch (terminal->pvt->mouse_last_button) {
+ case 1:
+#ifdef VTE_DEBUG
+ if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
+ fprintf(stderr, "Mousing drag 1.\n");
+ }
+#endif
+ if (((modifiers & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) ||
+ (!terminal->pvt->mouse_send_xy_on_click &&
+ !terminal->pvt->mouse_send_xy_on_button &&
+ !terminal->pvt->mouse_hilite_tracking &&
+ !terminal->pvt->mouse_cell_motion_tracking &&
+ !terminal->pvt->mouse_all_motion_tracking)) {
+ vte_terminal_extend_selection(widget,
+ event->x - VTE_PAD_WIDTH,
+ event->y - VTE_PAD_WIDTH,
+ FALSE);
+ } else {
+ vte_terminal_maybe_send_mouse_drag(terminal,
+ event);
+ }
+ break;
+ case 2:
+ case 3:
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Start scrolling if we need to. */
+ if ((event->y < VTE_PAD_WIDTH) ||
+ (event->y > (widget->allocation.height - VTE_PAD_WIDTH))) {
+ switch (terminal->pvt->mouse_last_button) {
+ case 1:
+ /* Give mouse wigglers something. */
+ vte_terminal_autoscroll(terminal);
+ /* Start a timed autoscroll if we're not doing it
+ * already. */
+ vte_terminal_start_autoscroll(terminal);
+ break;
+ case 2:
+ case 3:
+ default:
+ break;
+ }
+ }
+
+ /* Hilite any matches. */
+ vte_terminal_match_hilite(terminal,
+ event->x - VTE_PAD_WIDTH,
+ event->y - VTE_PAD_WIDTH);
+
+ /* Save the pointer coordinates for later use. */
+ terminal->pvt->mouse_last_x = event->x - VTE_PAD_WIDTH;
+ terminal->pvt->mouse_last_y = event->y - VTE_PAD_WIDTH;
+
+ return FALSE;
+}
+
/* Read and handle a pointing device buttonpress event. */
static gint
vte_terminal_button_press(GtkWidget *widget, GdkEventButton *event)
@@ -8404,9 +8652,9 @@ vte_terminal_button_press(GtkWidget *widget, GdkEventButton *event)
VteTerminal *terminal;
long height, width, delta;
GdkModifierType modifiers;
- gboolean ret = FALSE;
+ gboolean handled = FALSE;
+ gboolean start_selecting = FALSE, extend_selecting = FALSE;
long cellx, celly;
- struct selection_event_coords *start, *end;
g_return_val_if_fail(VTE_IS_TERMINAL(widget), FALSE);
terminal = VTE_TERMINAL(widget);
@@ -8415,6 +8663,11 @@ vte_terminal_button_press(GtkWidget *widget, GdkEventButton *event)
delta = terminal->pvt->screen->scroll_delta;
vte_terminal_set_pointer_visible(terminal, TRUE);
+ /* Grab input focus. */
+ if (!GTK_WIDGET_HAS_FOCUS(widget)) {
+ gtk_widget_grab_focus(widget);
+ }
+
/* Read the modifiers. */
if (gdk_event_get_state((GdkEvent*)event, &modifiers) == FALSE) {
modifiers = 0;
@@ -8424,180 +8677,111 @@ vte_terminal_button_press(GtkWidget *widget, GdkEventButton *event)
cellx = (event->x - VTE_PAD_WIDTH) / width;
celly = (event->y - VTE_PAD_WIDTH) / height + delta;
- if (event->type == GDK_BUTTON_PRESS) {
+ switch (event->type) {
+ case GDK_BUTTON_PRESS:
#ifdef VTE_DEBUG
if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
- char *match;
- int match_tag;
- fprintf(stderr, "Button %d pressed at (%lf,%lf) -> ",
+ fprintf(stderr, "Button %d single-click at (%lf,%lf)\n",
event->button,
event->x - VTE_PAD_WIDTH,
- event->y - VTE_PAD_WIDTH);
- fprintf(stderr, "character cell (%ld,%ld).\n",
- cellx, celly);
- match = vte_terminal_match_check(terminal,
- cellx,
- celly - delta,
- &match_tag);
- if (match != NULL) {
- fprintf(stderr, "Matched string %d = \"%s\".\n",
- match_tag, match);
- g_free(match);
- }
+ event->y - VTE_PAD_WIDTH +
+ (terminal->char_height * delta));
}
#endif
- /* If the child is handling mouse events, send it the event. */
- if ((terminal->pvt->mouse_send_xy_on_button ||
- terminal->pvt->mouse_send_xy_on_click) &&
- ((modifiers & GDK_SHIFT_MASK) == 0)) {
-#ifdef VTE_DEBUG
- if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
- fprintf(stderr, "Sending click to child.\n");
- }
-#endif
- vte_terminal_send_mouse_button(terminal, event);
- } else
/* Handle this event ourselves. */
- if (event->button == 1) {
+ switch (event->button) {
+ case 1:
#ifdef VTE_DEBUG
if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
fprintf(stderr, "Handling click ourselves.\n");
}
#endif
- if (!GTK_WIDGET_HAS_FOCUS(widget)) {
- gtk_widget_grab_focus(widget);
- }
- /* If the user didn't hold down shift, or if the click
- * was in an already-selected cell, we deselect and
- * start over. */
- if (((modifiers & GDK_SHIFT_MASK) == 0) ||
- vte_cell_is_selected(terminal, cellx, celly)) {
- /* Start or restart selection later. */
- terminal->pvt->restart_selection = TRUE;
- terminal->pvt->selection_delayed.x =
- event->x - VTE_PAD_WIDTH;
- terminal->pvt->selection_delayed.y =
- event->y - VTE_PAD_WIDTH +
- (terminal->char_height * delta);
- ret = TRUE;
- } else {
- /* Don't restart selection later -- we're
- * extending it instead. */
- terminal->pvt->restart_selection = FALSE;
-#ifdef VTE_DEBUG
- if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
- fprintf(stderr, "Selection is "
- "(%ld,%ld) to (%ld,%ld).\n",
- terminal->pvt->selection_start.x,
- terminal->pvt->selection_start.y,
- terminal->pvt->selection_end.x,
- terminal->pvt->selection_end.y);
- }
-#endif
- /* Extend the selection by moving either the
- * origin or last pointer to the event's
- * coordinates. */
- if ((terminal->pvt->selection_origin.y <
- terminal->pvt->selection_last.y) ||
- ((terminal->pvt->selection_origin.y ==
- terminal->pvt->selection_last.y) &&
- (terminal->pvt->selection_origin.x <
- terminal->pvt->selection_last.x))) {
- /* The origin point is "before" the end
- * point. */
- start = &terminal->pvt->selection_origin;
- end = &terminal->pvt->selection_last;
- } else {
- /* The end point is "before" the origin
- * point. */
- end = &terminal->pvt->selection_origin;
- start = &terminal->pvt->selection_last;
- }
- /* Move the selection start- or endpoint. */
- if (((event->y - VTE_PAD_WIDTH) < start->y) ||
- (((event->y - VTE_PAD_WIDTH) == start->y) &&
- ((event->x - VTE_PAD_WIDTH) < start->x))) {
- /* The click was "before" the start
- * point. */
- start->x = event->x - VTE_PAD_WIDTH;
- start->y = event->y - VTE_PAD_WIDTH +
- (terminal->char_height * delta);
+
+ /* If the user hit shift, override event mode. */
+ if ((modifiers & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
+ if (terminal->pvt->mouse_send_xy_on_button ||
+ terminal->pvt->mouse_send_xy_on_click) {
+ /* If shift is pressed in event mode,
+ * start selecting. */
+ start_selecting = TRUE;
} else {
- /* The click was "after" the start
- * point. */
- end->x = event->x - VTE_PAD_WIDTH;
- end->y = event->y - VTE_PAD_WIDTH +
- (terminal->char_height * delta);
- }
- /* Recalculate the selection area using the
- * new origin and "last" coordinates. */
- vte_terminal_selection_recompute(terminal);
- /* Redraw the newly-highlited rows. */
- vte_invalidate_cells(terminal,
- 0,
- terminal->column_count,
- terminal->pvt->selection_start.y,
- terminal->pvt->selection_end.y -
- terminal->pvt->selection_start.y + 1);
-
-#ifdef VTE_DEBUG
- if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
- fprintf(stderr, "Selection changed to "
- "(%ld,%ld) to (%ld,%ld).\n",
- terminal->pvt->selection_start.x,
- terminal->pvt->selection_start.y,
- terminal->pvt->selection_end.x,
- terminal->pvt->selection_end.y);
+ /* If shift is pressed in non-event
+ * mode, extend selection if the cell
+ * isn't already selected, otherwise
+ * start selection. */
+ if (!vte_cell_is_selected(terminal,
+ cellx,
+ celly,
+ NULL)) {
+ extend_selecting = TRUE;
+ } else {
+ start_selecting = TRUE;
+ }
}
-#endif
- ret = TRUE;
+ } else {
+ /* If shift isn't set, start selecting. */
+ start_selecting = TRUE;
+ }
+ if (start_selecting) {
+ vte_terminal_deselect_all(terminal);
+ vte_terminal_start_selection(widget,
+ event,
+ selection_type_char);
+ handled = TRUE;
}
- } else
- /* Paste. */
- if (event->button == 2) {
-#ifdef VTE_DEBUG
- if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
- fprintf(stderr, "Handling click ourselves.\n");
+ if (extend_selecting) {
+ vte_terminal_extend_selection(widget,
+ event->x - VTE_PAD_WIDTH,
+ event->y - VTE_PAD_WIDTH,
+ TRUE);
+ handled = TRUE;
}
-#endif
- vte_terminal_paste_primary(terminal);
- ret = TRUE;
+ break;
+ /* Paste if the user pressed shift or we're not sending events
+ * to the app. */
+ case 2:
+ if (((modifiers & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) ||
+ (!terminal->pvt->mouse_send_xy_on_button &&
+ !terminal->pvt->mouse_send_xy_on_click)) {
+ vte_terminal_paste_primary(terminal);
+ handled = TRUE;
+ }
+ break;
+ case 3:
+ default:
+ break;
}
- } else
- if (event->type == GDK_2BUTTON_PRESS) {
+ /* If we haven't done anything yet, try sending the mouse
+ * event to the app. */
+ if (handled == FALSE) {
+ vte_terminal_maybe_send_mouse_button(terminal, event);
+ handled = TRUE;
+ }
+ break;
+ case GDK_2BUTTON_PRESS:
#ifdef VTE_DEBUG
if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
fprintf(stderr, "Button %d double-click at (%lf,%lf)\n",
event->button,
event->x - VTE_PAD_WIDTH,
- event->y - VTE_PAD_WIDTH);
+ event->y - VTE_PAD_WIDTH +
+ (terminal->char_height * delta));
}
#endif
- if (event->button == 1) {
- if (!GTK_WIDGET_HAS_FOCUS(widget)) {
- gtk_widget_grab_focus(widget);
- }
- vte_terminal_deselect_all(terminal);
- terminal->pvt->has_selection = TRUE;
- terminal->pvt->selection_origin.x =
- event->x - VTE_PAD_WIDTH;
- terminal->pvt->selection_origin.y =
- event->y - VTE_PAD_WIDTH +
- (terminal->char_height * delta);
- terminal->pvt->selection_start.x = cellx;
- terminal->pvt->selection_start.y = celly;
- terminal->pvt->selection_end =
- terminal->pvt->selection_start;
- terminal->pvt->selection_type = selection_type_word;
- vte_invalidate_cells(terminal,
- 0,
- terminal->column_count,
- terminal->pvt->selection_start.y,
- 1);
- ret = TRUE;
+ switch (event->button) {
+ case 1:
+ vte_terminal_start_selection(widget,
+ event,
+ selection_type_word);
+ handled = TRUE;
+ break;
+ case 2:
+ case 3:
+ default:
+ break;
}
- } else
- if (event->type == GDK_3BUTTON_PRESS) {
+ break;
+ case GDK_3BUTTON_PRESS:
#ifdef VTE_DEBUG
if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
fprintf(stderr, "Button %d triple-click at (%lf,%lf).\n",
@@ -8607,29 +8791,20 @@ vte_terminal_button_press(GtkWidget *widget, GdkEventButton *event)
(terminal->char_height * delta));
}
#endif
- if (event->button == 1) {
- if (!GTK_WIDGET_HAS_FOCUS(widget)) {
- gtk_widget_grab_focus(widget);
- }
- vte_terminal_deselect_all(terminal);
- terminal->pvt->has_selection = TRUE;
- terminal->pvt->selection_origin.x =
- event->x - VTE_PAD_WIDTH;
- terminal->pvt->selection_origin.y =
- event->y - VTE_PAD_WIDTH +
- (terminal->char_height * delta);
- terminal->pvt->selection_start.x = cellx;
- terminal->pvt->selection_start.y = celly;
- terminal->pvt->selection_end =
- terminal->pvt->selection_start;
- terminal->pvt->selection_type = selection_type_line;
- vte_invalidate_cells(terminal,
- 0,
- terminal->column_count,
- terminal->pvt->selection_start.y,
- 1);
- ret = TRUE;
+ switch (event->button) {
+ case 1:
+ vte_terminal_start_selection(widget,
+ event,
+ selection_type_line);
+ handled = TRUE;
+ break;
+ case 2:
+ case 3:
+ default:
+ break;
}
+ default:
+ break;
}
/* Hilite any matches. */
@@ -8642,7 +8817,7 @@ vte_terminal_button_press(GtkWidget *widget, GdkEventButton *event)
terminal->pvt->mouse_last_x = event->x - VTE_PAD_WIDTH;
terminal->pvt->mouse_last_y = event->y - VTE_PAD_WIDTH;
- return ret;
+ return FALSE;
}
/* Read and handle a pointing device buttonrelease event. */
@@ -8651,12 +8826,27 @@ vte_terminal_button_release(GtkWidget *widget, GdkEventButton *event)
{
VteTerminal *terminal;
GdkModifierType modifiers;
+ gboolean handled = FALSE;
g_return_val_if_fail(VTE_IS_TERMINAL(widget), FALSE);
terminal = VTE_TERMINAL(widget);
vte_terminal_set_pointer_visible(terminal, TRUE);
- if (event->type == GDK_BUTTON_RELEASE) {
+ /* Grab input focus. */
+ if (!GTK_WIDGET_HAS_FOCUS(widget)) {
+ gtk_widget_grab_focus(widget);
+ }
+
+ /* Disconnect from autoscroll requests. */
+ vte_terminal_stop_autoscroll(terminal);
+
+ /* Read the modifiers. */
+ if (gdk_event_get_state((GdkEvent*)event, &modifiers) == FALSE) {
+ modifiers = 0;
+ }
+
+ switch (event->type) {
+ case GDK_BUTTON_RELEASE:
#ifdef VTE_DEBUG
if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
fprintf(stderr, "Button %d released at (%lf,%lf).\n",
@@ -8665,23 +8855,32 @@ vte_terminal_button_release(GtkWidget *widget, GdkEventButton *event)
event->y - VTE_PAD_WIDTH);
}
#endif
- /* Read the modifiers. */
- if (gdk_event_get_state((GdkEvent*)event, &modifiers) == FALSE) {
- modifiers = 0;
- }
- if ((terminal->pvt->mouse_send_xy_on_button) &&
- ((modifiers & GDK_SHIFT_MASK) == 0)) {
- vte_terminal_send_mouse_button(terminal, event);
- } else
- if (event->button == 1) {
- vte_terminal_copy(terminal, GDK_SELECTION_PRIMARY);
+ switch (event->button) {
+ case 1:
+ /* If Shift is held down, or we're not in events mode,
+ * copy the selected text. */
+ if (((modifiers & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) ||
+ (!terminal->pvt->mouse_send_xy_on_button)) {
+ /* Copy only if something was selected. */
+ if (!terminal->pvt->restart_selection) {
+ vte_terminal_copy(terminal,
+ GDK_SELECTION_PRIMARY);
+ }
+ handled = TRUE;
+ }
+ break;
+ case 2:
+ case 3:
+ default:
+ break;
}
-
- /* Disconnect from autoscroll requests. */
- if (terminal->pvt->mouse_autoscroll_tag) {
- g_source_remove(terminal->pvt->mouse_autoscroll_tag);
- terminal->pvt->mouse_autoscroll_tag = 0;
+ if (handled == FALSE) {
+ vte_terminal_maybe_send_mouse_button(terminal, event);
+ handled = TRUE;
}
+ break;
+ default:
+ break;
}
/* Hilite any matches. */
@@ -9662,7 +9861,7 @@ vte_terminal_refresh_size(VteTerminal *terminal)
g_return_if_fail(VTE_IS_TERMINAL(terminal));
if (terminal->pvt->pty_master != -1) {
/* Use an ioctl to read the size of the terminal. */
- if (vte_pty_get_size(terminal->pvt->pty_master, &columns, &rows) != 0) {
+ if (_vte_pty_get_size(terminal->pvt->pty_master, &columns, &rows) != 0) {
g_warning(_("Error reading PTY size, using defaults: "
"%s."), strerror(errno));
} else {
@@ -9698,7 +9897,7 @@ vte_terminal_set_size(VteTerminal *terminal, glong columns, glong rows)
size.ws_row = rows;
size.ws_col = columns;
/* Try to set the terminal size. */
- if (vte_pty_set_size(terminal->pvt->pty_master, columns, rows) != 0) {
+ if (_vte_pty_set_size(terminal->pvt->pty_master, columns, rows) != 0) {
g_warning(_("Error setting PTY size: %s."),
strerror(errno));
}
@@ -10219,7 +10418,6 @@ vte_terminal_init(VteTerminal *terminal, gpointer *klass)
* devel version with fontconfig support or 2.2 or later. */
render_max = VteRenderXft2;
#endif
-#endif
/* Let debugging users have some influence on how we render text. */
if ((render_max == VteRenderXft2) &&
(getenv("VTE_USE_XFT2") != NULL)) {
@@ -10239,6 +10437,7 @@ vte_terminal_init(VteTerminal *terminal, gpointer *klass)
render_max = VteRenderPango;
}
}
+#endif
if ((render_max == VteRenderPango) &&
(getenv("VTE_USE_PANGO") != NULL)) {
if (atol(getenv("VTE_USE_PANGO")) == 0) {
@@ -10256,14 +10455,16 @@ vte_terminal_init(VteTerminal *terminal, gpointer *klass)
#ifdef VTE_DEBUG
if (_vte_debug_on(VTE_DEBUG_MISC)) {
switch (pvt->render_method) {
- case VteRenderXft2:
#ifdef HAVE_XFT2
+ case VteRenderXft2:
fprintf(stderr, "Using Xft2.\n");
break;
#endif
+#ifdef HAVE_XFT
case VteRenderXft1:
fprintf(stderr, "Using Xft1.\n");
break;
+#endif
case VteRenderPango:
fprintf(stderr, "Using Pango.\n");
break;
@@ -10620,10 +10821,7 @@ vte_terminal_finalize(GObject *object)
}
/* Disconnect from autoscroll requests. */
- if (terminal->pvt->mouse_autoscroll_tag) {
- g_source_remove(terminal->pvt->mouse_autoscroll_tag);
- terminal->pvt->mouse_autoscroll_tag = 0;
- }
+ vte_terminal_stop_autoscroll(terminal);
/* Cancel pending adjustment change notifications. */
if (terminal->pvt->adjustment_changed_tag) {
@@ -10726,7 +10924,7 @@ vte_terminal_finalize(GObject *object)
terminal->pvt->pty_output_source = -1;
}
if (terminal->pvt->pty_master != -1) {
- vte_pty_close(terminal->pvt->pty_master);
+ _vte_pty_close(terminal->pvt->pty_master);
terminal->pvt->pty_master = -1;
}
@@ -10897,14 +11095,19 @@ vte_terminal_realize(GtkWidget *widget)
g_object_unref(G_OBJECT(mask));
/* Grab input focus. */
- gtk_widget_grab_focus(widget);
+ if (!GTK_WIDGET_HAS_FOCUS(widget)) {
+ gtk_widget_grab_focus(widget);
+ }
}
static void
vte_terminal_determine_colors(VteTerminal *terminal,
- const struct vte_charcell *cell, gboolean reverse,
- int *fore, int *back)
+ const struct vte_charcell *cell,
+ gboolean reverse, int *fore, int *back)
{
+ g_assert(fore != NULL);
+ g_assert(back != NULL);
+
/* Determine what the foreground and background colors for rendering
* text should be. */
if (reverse ^ ((cell != NULL) && (cell->reverse))) {
@@ -11791,9 +11994,22 @@ vte_terminal_draw_cells(VteTerminal *terminal,
x += VTE_PAD_WIDTH;
y += VTE_PAD_WIDTH;
+#ifdef VTE_DEBUG
+ if (_vte_debug_on(VTE_DEBUG_MISC) && 0) {
+ fprintf(stderr, "Rendering");
+ for (i = 0; i < n; i++) {
+ fprintf(stderr, " (%ld,%ld)",
+ (long) items[i].c,
+ (long) items[i].columns);
+ g_assert(items[i].columns > 0);
+ }
+ fprintf(stderr, ".\n");
+ }
+#endif
+
switch (terminal->pvt->render_method) {
- case VteRenderXft2:
#ifdef HAVE_XFT
+ case VteRenderXft2:
#ifdef HAVE_XFT2
#ifdef VTE_DEBUG
if (_vte_debug_on(VTE_DEBUG_MISC) && 0) {
@@ -11802,7 +12018,7 @@ vte_terminal_draw_cells(VteTerminal *terminal,
#endif
/* Set up the draw request. */
ftcharspecs = g_malloc(sizeof(XftCharSpec) * n);
- for (i = columns = 0; i < n; i++) {
+ for (i = columns = 0; i < n; i++) {
c = items[i].c ? items[i].c : ' ';
ftcharspecs[i].ucs4 = vte_terminal_xft_remap_char(display,
terminal->pvt->ftfont,
@@ -11810,7 +12026,7 @@ vte_terminal_draw_cells(VteTerminal *terminal,
ftcharspecs[i].x = x + (columns * column_width) +
items[i].xpad;
ftcharspecs[i].y = y + ascent;
- columns += g_unichar_iswide(c) ? 2 : 1;
+ columns += items[i].columns;
}
if (ftdraw != NULL) {
/* Draw the background rectangle. */
@@ -11842,10 +12058,10 @@ vte_terminal_draw_cells(VteTerminal *terminal,
fprintf(stderr, "Rendering with Xft1.\n");
}
#endif
- /* Set up the draw request. */
+ /* Set up the draw request -- calculate the total width. */
for (i = columns = 0; i < n; i++) {
c = items[i].c ? items[i].c : ' ';
- columns += g_unichar_iswide(c) ? 2 : 1;
+ columns += items[i].columns;
}
/* Draw the background rectangle. */
if ((back != VTE_DEF_BG) || draw_default_bg) {
@@ -11872,7 +12088,7 @@ vte_terminal_draw_cells(VteTerminal *terminal,
y + ascent,
&ftchar, 1);
}
- columns += g_unichar_iswide(c) ? 2 : 1;
+ columns += items[i].columns;
}
break;
#endif
@@ -11886,7 +12102,7 @@ vte_terminal_draw_cells(VteTerminal *terminal,
if ((back != VTE_DEF_BG) || draw_default_bg) {
for (i = columns = 0; i < n; i++) {
c = items[i].c ? items[i].c : ' ';
- columns += g_unichar_iswide(c) ? 2 : 1;
+ columns += items[i].columns;
}
color.red = terminal->pvt->palette[back].red;
color.blue = terminal->pvt->palette[back].blue;
@@ -11921,7 +12137,7 @@ vte_terminal_draw_cells(VteTerminal *terminal,
y + y_offs,
layout);
}
- columns += g_unichar_iswide(c) ? 2 : 1;
+ columns += items[i].columns;
}
break;
case VteRenderPangoX:
@@ -11934,7 +12150,7 @@ vte_terminal_draw_cells(VteTerminal *terminal,
if ((back != VTE_DEF_BG) || draw_default_bg) {
for (i = columns = 0; i < n; i++) {
c = items[i].c ? items[i].c : ' ';
- columns += g_unichar_iswide(c) ? 2 : 1;
+ columns += items[i].columns;
}
XSetForeground(display, gc, bg->pixel);
XFillRectangle(display, drawable, gc,
@@ -11969,7 +12185,7 @@ vte_terminal_draw_cells(VteTerminal *terminal,
items[i].xpad + 1,
y);
}
- columns += g_unichar_iswide(c) ? 2 : 1;
+ columns += items[i].columns;
}
break;
case VteRenderXlib:
@@ -11982,7 +12198,7 @@ vte_terminal_draw_cells(VteTerminal *terminal,
if ((back != VTE_DEF_BG) || draw_default_bg) {
for (i = columns = 0; i < n; i++) {
c = items[i].c ? items[i].c : ' ';
- columns += g_unichar_iswide(c) ? 2 : 1;
+ columns += items[i].columns;
}
XSetForeground(display, gc, bg->pixel);
XFillRectangle(display, drawable, gc,
@@ -12008,7 +12224,7 @@ vte_terminal_draw_cells(VteTerminal *terminal,
items[i].xpad + 1,
y + ascent, &textitem, 1);
}
- columns += g_unichar_iswide(c) ? 2 : 1;
+ columns += items[i].columns;
}
}
@@ -12071,11 +12287,12 @@ vte_terminal_get_blink_state(VteTerminal *terminal)
terminal->pvt->cursor_force_fg--;
blink = TRUE;
}
- terminal->pvt->cursor_force_fg = FALSE;
return blink;
}
-/* Paint the contents of a given row at the given location. */
+/* Paint the contents of a given row at the given location. Take advantage
+ * of multiple-draw APIs by finding runs of characters with identical
+ * attributes and bundling them together. */
static void
vte_terminal_draw_row(VteTerminal *terminal,
VteScreen *screen,
@@ -12106,23 +12323,22 @@ vte_terminal_draw_row(VteTerminal *terminal,
/* Allocate an array to hold draw requests. */
items = g_array_new(FALSE, FALSE, sizeof(struct vte_draw_item));
- /* Find groups of characters with identical attributes and bundle
- * them together. */
+ /* Back up in case this is a multicolumn character, making the drawing
+ * area a little wider. */
i = column;
-
- /* Back up in case this is a multicolumn character. */
cell = vte_terminal_find_charcell(terminal, i, row);
- if ((cell != NULL) && (cell->columns == 0) && (i > 0)) {
+ if ((cell != NULL) && (cell->fragment) && (i > 0)) {
cell = vte_terminal_find_charcell(terminal, i - 1, row);
column--;
column_count++;
}
+
/* Walk the line. */
while (i < column + column_count) {
/* Get the character cell's contents. */
cell = vte_terminal_find_charcell(terminal, i, row);
/* Find the colors for this cell. */
- reverse = vte_cell_is_selected(terminal, i, row) ^
+ reverse = vte_cell_is_selected(terminal, i, row, NULL) ^
terminal->pvt->screen->reverse_mode;
vte_terminal_determine_colors(terminal, cell, reverse,
&fore, &back);
@@ -12143,6 +12359,7 @@ vte_terminal_draw_row(VteTerminal *terminal,
if ((cell != NULL) &&
(cell->alternate || vte_unichar_isgraphic(cell->c))) {
item.c = cell ? cell->c : ' ';
+ item.columns = cell ? cell->columns : 1;
vte_terminal_draw_graphic(terminal, cell->c, fore, back,
FALSE,
x +
@@ -12155,12 +12372,25 @@ vte_terminal_draw_row(VteTerminal *terminal,
drawable,
ggc,
gc);
- i++;
+ i += item.columns;
continue;
}
/* Add this cell to the draw list. */
item.c = cell ? cell->c : ' ';
+ item.columns = cell ? cell->columns : 1;
+ /* Special case certain whitespace characters which the font
+ * probably can't render correctly, if at all. */
+ switch (item.c) {
+ case '\0':
+ case '\t':
+ item.c = ' ';
+ break;
+ default:
+ break;
+ }
+ /* Compute the left padding necessary to draw this character
+ * in the approximate middle of its columns. */
if (monospaced) {
item.xpad = 0;
} else {
@@ -12177,19 +12407,24 @@ vte_terminal_draw_row(VteTerminal *terminal,
j++) {
/* Don't render fragments of multicolumn characters. */
cell = vte_terminal_find_charcell(terminal, j, row);
- if ((cell != NULL) && (cell->columns == 0)) {
+ if ((cell != NULL) && (cell->fragment)) {
continue;
}
+ /* Graphic characters must be drawn individually. */
if ((cell != NULL) && (cell->alternate)) {
break;
}
if ((cell != NULL) && vte_unichar_isgraphic(cell->c)) {
break;
}
+ /* Special case certain non-printing characters. */
+ if ((cell != NULL) && (cell->c == '\t')) {
+ break;
+ }
/* Resolve attributes to colors where possible and
* compare visual attributes to the first character
* in this chunk. */
- reverse = vte_cell_is_selected(terminal, j, row) ^
+ reverse = vte_cell_is_selected(terminal, j, row, NULL) ^
terminal->pvt->screen->reverse_mode;
vte_terminal_determine_colors(terminal, cell, reverse,
&nfore, &nback);
@@ -12223,7 +12458,8 @@ vte_terminal_draw_row(VteTerminal *terminal,
break;
}
/* Add this cell to the draw list. */
- item.c = cell ? cell->c : ' ';
+ item.c = cell ? (cell->c ? cell->c : ' ') : ' ';
+ item.columns = cell ? cell->columns : 1;
if (monospaced) {
item.xpad = 0;
} else {
@@ -12404,7 +12640,7 @@ vte_terminal_paint(GtkWidget *widget, GdkRectangle *area)
/* Find the character "under" the cursor. */
cell = vte_terminal_find_charcell(terminal, col, drow);
- while ((cell != NULL) && (cell->columns == 0) && (col >= 0)) {
+ while ((cell != NULL) && (cell->fragment) && (col >= 0)) {
col--;
cell = vte_terminal_find_charcell(terminal, col, drow);
}
@@ -12431,6 +12667,7 @@ vte_terminal_paint(GtkWidget *widget, GdkRectangle *area)
gc);
} else {
item.c = cell ? cell->c : ' ';
+ item.columns = cell ? cell->columns : 1;
item.xpad = vte_terminal_get_char_padding(terminal,
display,
item.c);
@@ -12497,7 +12734,8 @@ vte_terminal_paint(GtkWidget *widget, GdkRectangle *area)
items[i].xpad = vte_terminal_get_char_padding(terminal,
display,
item.c);
- columns += g_unichar_iswide(items[i].c) ? 2 : 1;
+ items[i].columns = g_unichar_iswide(items[i].c) ? 2 : 1;
+ columns += items[i].columns;
preedit = g_utf8_next_char(preedit);
}
fore = screen->defaults.fore;
@@ -13706,8 +13944,12 @@ gboolean
vte_terminal_get_using_xft(VteTerminal *terminal)
{
g_return_val_if_fail(VTE_IS_TERMINAL(terminal), FALSE);
+#ifdef HAVE_XFT
return (terminal->pvt->render_method == VteRenderXft2) ||
(terminal->pvt->render_method == VteRenderXft1);
+#else
+ return FALSE;
+#endif
}
/**
@@ -13782,6 +14024,10 @@ vte_terminal_set_scrollback_lines(VteTerminal *terminal, glong lines)
low, highd);
screens[i]->cursor_current.row = CLAMP(screens[i]->cursor_current.row,
low, high);
+ /* Clear the matching view. */
+ vte_terminal_match_contents_clear(terminal);
+ /* Notify viewers that the contents have changed. */
+ vte_terminal_emit_contents_changed(terminal);
}
terminal->pvt->scrollback_lines = lines;
@@ -14083,6 +14329,20 @@ vte_terminal_reset(VteTerminal *terminal, gboolean full, gboolean clear_history)
g_assert(terminal->pvt->encoding != NULL);
/* Reset selection. */
vte_terminal_deselect_all(terminal);
+ terminal->pvt->has_selection = FALSE;
+ terminal->pvt->restart_selection = FALSE;
+ if (terminal->pvt->selection != NULL) {
+ g_free(terminal->pvt->selection);
+ terminal->pvt->selection = NULL;
+ memset(&terminal->pvt->selection_origin, 0,
+ sizeof(&terminal->pvt->selection_origin));
+ memset(&terminal->pvt->selection_last, 0,
+ sizeof(&terminal->pvt->selection_last));
+ memset(&terminal->pvt->selection_start, 0,
+ sizeof(&terminal->pvt->selection_start));
+ memset(&terminal->pvt->selection_end, 0,
+ sizeof(&terminal->pvt->selection_end));
+ }
/* Reset mouse motion events. */
terminal->pvt->mouse_send_xy_on_click = FALSE;
terminal->pvt->mouse_send_xy_on_button = FALSE;
diff --git a/src/vte.h b/src/vte.h
index aba8500..e23625a 100644
--- a/src/vte.h
+++ b/src/vte.h
@@ -86,8 +86,9 @@ struct _VteTerminalClass {
guint resize_window_signal;
guint move_window_signal;
guint status_line_changed_signal;
-
guint commit_signal;
+
+ gpointer reserved1;
gpointer reserved2;
gpointer reserved3;
gpointer reserved4;
@@ -133,15 +134,11 @@ GtkType vte_terminal_erase_binding_get_type(void);
/* You can get by with just these two functions. */
GtkWidget *vte_terminal_new(void);
pid_t vte_terminal_fork_command(VteTerminal *terminal,
- const char *command, char **argv, char **envv);
-
-/* If you need the session logged, try this instead. */
-pid_t vte_terminal_fork_logged_command(VteTerminal *terminal,
- const char *command, char **argv,
- char **envv,
- gboolean lastlog,
- gboolean utmp,
- gboolean wtmp);
+ const char *command, char **argv,
+ char **envv, const char *directory,
+ gboolean lastlog,
+ gboolean utmp,
+ gboolean wtmp);
/* Send data to the terminal to display, or to the terminal's forked command
* to handle in some way. If it's 'cat', they should be the same. */
@@ -243,14 +240,18 @@ void vte_terminal_reset(VteTerminal *terminal, gboolean full,
char *vte_terminal_get_text(VteTerminal *terminal,
gboolean(*is_selected)(VteTerminal *terminal,
glong column,
- glong row),
+ glong row,
+ gpointer data),
+ gpointer data,
GArray *attributes);
char *vte_terminal_get_text_range(VteTerminal *terminal,
glong start_row, glong start_col,
glong end_row, glong end_col,
gboolean(*is_selected)(VteTerminal *terminal,
glong column,
- glong row),
+ glong row,
+ gpointer data),
+ gpointer data,
GArray *attributes);
void vte_terminal_get_cursor_position(VteTerminal *terminal,
glong *column, glong *row);
diff --git a/src/vteaccess.c b/src/vteaccess.c
index 5633b0a..f7f6e96 100644
--- a/src/vteaccess.c
+++ b/src/vteaccess.c
@@ -139,7 +139,9 @@ vte_terminal_accessible_update_private_data_if_needed(AtkObject *text)
priv->snapshot_linebreaks = g_array_new(FALSE, TRUE, sizeof(int));
/* Get a new view of the uber-label. */
- priv->snapshot_text = vte_terminal_get_text(terminal, all_selected,
+ priv->snapshot_text = vte_terminal_get_text(terminal,
+ all_selected,
+ NULL,
priv->snapshot_attributes);
if (priv->snapshot_text == NULL) {
/* Aaargh! We're screwed. */
diff --git a/src/vteapp.c b/src/vteapp.c
index b06ffa8..6d4aa16 100644
--- a/src/vteapp.c
+++ b/src/vteapp.c
@@ -106,6 +106,7 @@ main(int argc, char **argv)
const char *font = NULL;
const char *terminal = NULL;
const char *command = NULL;
+ const char *working_directory = NULL;
char **argv2;
int opt;
int i, j;
@@ -152,7 +153,7 @@ main(int argc, char **argv)
argv2[i] = NULL;
g_assert(i < (g_list_length(args) + 2));
/* Parse some command-line options. */
- while ((opt = getopt(argc, argv, "B:DTabc:df:ghn:t:")) != -1) {
+ while ((opt = getopt(argc, argv, "B:DTabc:df:ghn:t:w:")) != -1) {
switch (opt) {
case 'B':
background = optarg;
@@ -190,6 +191,9 @@ main(int argc, char **argv)
case 't':
terminal = optarg;
break;
+ case 'w':
+ working_directory = optarg;
+ break;
case 'h':
default:
g_print(usage, argv[0]);
@@ -283,9 +287,9 @@ main(int argc, char **argv)
strlen(message));
}
#endif
- vte_terminal_fork_logged_command(VTE_TERMINAL(widget),
- command, NULL, env_add,
- TRUE, TRUE, TRUE);
+ vte_terminal_fork_command(VTE_TERMINAL(widget),
+ command, NULL, env_add, working_directory,
+ TRUE, TRUE, TRUE);
if (command == NULL) {
vte_terminal_feed_child(VTE_TERMINAL(widget), "pwd\n", -1);
}
diff --git a/vte.spec b/vte.spec
index e17be25..17bcd0c 100644
--- a/vte.spec
+++ b/vte.spec
@@ -1,5 +1,5 @@
Name: vte
-Version: 0.9.2
+Version: 0.10
Release: 1
Summary: An experimental terminal emulator.
License: LGPL
@@ -64,6 +64,9 @@ rm $RPM_BUILD_ROOT/%{_libdir}/lib%{name}.la
%{_libdir}/pkgconfig/*
%changelog
+* Thu Oct 24 2002 Nalin Dahyabhai <nalin@redhat.com> 0.10-1
+- allow setting the working directory (#76529)
+
* Thu Oct 17 2002 Nalin Dahyabhai <nalin@redhat.com> 0.9.2-1
- fix the crash-on-resize bug (#75871)
- add bold