Commit 5cff4182 authored by Behdad Esfahbod's avatar Behdad Esfahbod Committed by Behdad Esfahbod
Browse files

Bug 549835 – Feature Request: Configurable cursor appearance

2008-10-14  Behdad Esfahbod  <behdad@gnome.org>

        Bug 549835 – Feature Request: Configurable cursor appearance

        * src/vte.h:
        New public api:

                VteTerminalCursorShape
                vte_terminal_set_cursor_shape
                vte_terminal_get_cursor_shape

        * src/vte-private.h:
        * src/vte.c (_vte_terminal_insert_char), (vte_terminal_init),
        (vte_terminal_paint_cursor), (vte_terminal_paint),
        (vte_terminal_set_cursor_shape), (vte_terminal_get_cursor_shape):
        Implement new API.  Also clean up cursor drawing in general.

        * doc/reference/Makefile.am:
        * doc/reference/tmpl/reaper.sgml:
        * doc/reference/tmpl/vte-unused.sgml:
        * doc/reference/tmpl/vte.sgml:
        * doc/reference/vte-sections.txt:
        Doc new symbols.  Also add some missing docs.


svn path=/trunk/; revision=2116
parent d1986f30
2008-10-14 Behdad Esfahbod <behdad@gnome.org>
Bug 549835 Feature Request: Configurable cursor appearance
* src/vte.h:
New public api:
VteTerminalCursorShape
vte_terminal_set_cursor_shape
vte_terminal_get_cursor_shape
* src/vte-private.h:
* src/vte.c (_vte_terminal_insert_char), (vte_terminal_init),
(vte_terminal_paint_cursor), (vte_terminal_paint),
(vte_terminal_set_cursor_shape), (vte_terminal_get_cursor_shape):
Implement new API. Also clean up cursor drawing in general.
* doc/reference/Makefile.am:
* doc/reference/tmpl/reaper.sgml:
* doc/reference/tmpl/vte-unused.sgml:
* doc/reference/tmpl/vte.sgml:
* doc/reference/vte-sections.txt:
Doc new symbols. Also add some missing docs.
2008-10-13 Christian Persch <chpe@gnome.org>
* src/vte.c: Add gobject property infrastructure.
......
......@@ -6,6 +6,9 @@ DOC_MODULE=vte
# The top-level SGML file.
DOC_MAIN_SGML_FILE=vte-docs.sgml
# Extra options to supply to gtkdoc-scan
SCAN_OPTIONS=--deprecated-guards="VTE_DISABLE_DEPRECATED"
# The directory containing the source code. Relative to $(srcdir)
DOC_SOURCE_DIR=../../src
......
......@@ -23,35 +23,3 @@ a proxy for glib's own functionality.
<!-- ##### SECTION Stability_Level ##### -->
<!-- ##### STRUCT VteReaper ##### -->
<para>
This should not be accessed directly.
</para>
<!-- ##### SIGNAL VteReaper::child-exited ##### -->
<para>
Emitted when the #VteReaper object detects that a child of the current process has exited.
</para>
@vtereaper: the object which received the signal.
@arg1: the process ID of the exited child.
@arg2: the status of the exited child, as returned by waitpid().
<!-- ##### FUNCTION vte_reaper_get ##### -->
<para>
</para>
@Returns:
<!-- ##### FUNCTION vte_reaper_add_child ##### -->
<para>
</para>
@pid:
@Returns:
......@@ -172,6 +172,21 @@ VteBg
@VTE_DEBUG_KEYBOARD:
@VTE_DEBUG_LIFECYCLE:
<!-- ##### STRUCT VteReaper ##### -->
<para>
This should not be accessed directly.
</para>
<!-- ##### SIGNAL VteReaper::child-exited ##### -->
<para>
Emitted when the #VteReaper object detects that a child of the current process has exited.
</para>
@vtereaper: the object which received the signal.
@arg1: the process ID of the exited child.
@arg2: the status of the exited child, as returned by waitpid().
<!-- ##### STRUCT VteReaperClass ##### -->
<para>
......@@ -333,6 +348,21 @@ VteBg
@rows:
@Returns:
<!-- ##### FUNCTION vte_reaper_add_child ##### -->
<para>
</para>
@pid:
@Returns:
<!-- ##### FUNCTION vte_reaper_get ##### -->
<para>
</para>
@Returns:
<!-- ##### FUNCTION vte_ring_append ##### -->
<para>
......
......@@ -35,7 +35,7 @@ All of these fields should be considered read-only.
<!-- ##### SIGNAL VteTerminal::beep ##### -->
<para>
This signal is emitted when the a child sends a beep request to the terminal.
</para>
@vteterminal: the object which received the signal.
......@@ -288,6 +288,27 @@ keys.
@VTE_ERASE_ASCII_DELETE: Send an ASCII delete character (0x7F).
@VTE_ERASE_DELETE_SEQUENCE: Send the "@@7" control sequence.
<!-- ##### ENUM VteTerminalCursorShape ##### -->
<para>
An enumerated type which can be used to indicate what should the terminal
draw at the cursor position.
</para>
@VTE_CURSOR_SHAPE_BLOCK: Draw a block cursor. This is the default.
@VTE_CURSOR_SHAPE_IBEAM: Draw a vertical bar on the left side of character.
This is similar to the default cursor for other GTK+ widgets.
@VTE_CURSOR_SHAPE_UNDERLINE: Draw a horizontal bar below the character.
<!-- ##### ENUM VteTerminalCursorBlinkMode ##### -->
<para>
An enumerated type which can be used to indicate the cursor blink mode
for the terminal.
</para>
@VTE_CURSOR_BLINK_SYSTEM: Follow GTK+ settings for cursor blinking.
@VTE_CURSOR_BLINK_ON: Cursor blinks.
@VTE_CURSOR_BLINK_OFF: Cursor does not blink.
<!-- ##### FUNCTION vte_terminal_new ##### -->
<para>
</para>
......@@ -341,6 +362,15 @@ keys.
@pty_master:
<!-- ##### FUNCTION vte_terminal_get_pty ##### -->
<para>
</para>
@terminal:
@Returns:
<!-- ##### FUNCTION vte_terminal_feed ##### -->
<para>
......@@ -371,6 +401,15 @@ keys.
@length:
<!-- ##### FUNCTION vte_terminal_get_child_exit_status ##### -->
<para>
</para>
@terminal:
@Returns:
<!-- ##### FUNCTION vte_terminal_select_all ##### -->
<para>
......@@ -638,6 +677,24 @@ keys.
@scroll:
<!-- ##### FUNCTION vte_terminal_set_cursor_shape ##### -->
<para>
</para>
@terminal:
@shape:
<!-- ##### FUNCTION vte_terminal_get_cursor_shape ##### -->
<para>
</para>
@terminal:
@Returns:
<!-- ##### FUNCTION vte_terminal_set_cursor_blinks ##### -->
<para>
......
......@@ -3,14 +3,18 @@
<TITLE>VteTerminal</TITLE>
VteTerminal
VteTerminalEraseBinding
VteTerminalCursorShape
VteTerminalCursorBlinkMode
vte_terminal_new
vte_terminal_im_append_menuitems
vte_terminal_fork_command
vte_terminal_forkpty
vte_terminal_set_pty
vte_terminal_get_pty
vte_terminal_feed
vte_terminal_feed_child
vte_terminal_feed_child_binary
vte_terminal_get_child_exit_status
vte_terminal_select_all
vte_terminal_select_none
vte_terminal_copy_clipboard
......@@ -41,6 +45,8 @@ vte_terminal_set_background_saturation
vte_terminal_set_background_transparent
vte_terminal_set_background_tint_color
vte_terminal_set_scroll_background
vte_terminal_set_cursor_shape
vte_terminal_get_cursor_shape
vte_terminal_set_cursor_blinks
vte_terminal_get_cursor_blink_mode
vte_terminal_set_cursor_blink_mode
......@@ -79,6 +85,10 @@ vte_terminal_get_encoding
vte_terminal_get_status_line
vte_terminal_get_padding
<SUBSECTION Standard>
vte_terminal_cursor_blink_mode_get_type
vte_terminal_cursor_shape_get_type
VTE_TYPE_TERMINAL_CURSOR_BLINK_MODE
VTE_TYPE_TERMINAL_CURSOR_SHAPE
vte_terminal_erase_binding_get_type
VTE_TYPE_TERMINAL_ERASE_BINDING
VTE_IS_TERMINAL_ERASE_BINDING
......
......@@ -315,6 +315,9 @@ struct _VteTerminalPrivate {
gboolean scroll_on_keystroke;
long scrollback_lines;
/* Cursor shape */
VteTerminalCursorShape cursor_shape;
/* Cursor blinking. */
VteTerminalCursorBlinkMode cursor_blink_mode;
gboolean cursor_blink_state;
......
......@@ -2870,6 +2870,7 @@ _vte_terminal_insert_char(VteTerminal *terminal, gunichar c,
VteScreen *screen;
gboolean line_wrapped = FALSE; /* cursor moved before char inserted */
g_message ("insert %04X", c);
screen = terminal->pvt->screen;
insert |= screen->insert_mode;
invalidate_now |= insert;
......@@ -2906,6 +2907,7 @@ _vte_terminal_insert_char(VteTerminal *terminal, gunichar c,
_vte_debug_print(VTE_DEBUG_ADJ,
"Autowrapping before character\n");
/* Wrap. */
/* XXX clear to the end of line */
col = screen->cursor_current.col = 0;
/* Mark this line as soft-wrapped. */
row = _vte_terminal_ensure_row(terminal);
......@@ -7839,6 +7841,9 @@ vte_terminal_init(VteTerminal *terminal)
pvt->nrc_mode = TRUE;
vte_terminal_set_default_tabstops(terminal);
/* Cursor shape. */
pvt->cursor_shape = VTE_CURSOR_SHAPE_BLOCK;
/* Cursor blinking. */
pvt->cursor_visible = TRUE;
pvt->cursor_blink_timeout = 500;
......@@ -10313,18 +10318,163 @@ vte_terminal_paint_area (VteTerminal *terminal, const GdkRectangle *area)
height);
}
static void
vte_terminal_paint_cursor(VteTerminal *terminal)
{
VteScreen *screen;
GdkColor color;
struct vte_charcell *cell;
struct _vte_draw_text_request item;
int row, drow, col;
long width, height, delta, cursor_width;
int fore, back, x, y;
gboolean blink, selected, focus;
if (!terminal->pvt->cursor_visible)
return;
screen = terminal->pvt->screen;
delta = screen->scroll_delta;
col = screen->cursor_current.col;
drow = screen->cursor_current.row;
row = drow - delta;
width = terminal->char_width;
height = terminal->char_height;
if ((CLAMP(col, 0, terminal->column_count - 1) != col) ||
(CLAMP(row, 0, terminal->row_count - 1) != row))
return;
focus = GTK_WIDGET_HAS_FOCUS(terminal);
blink = terminal->pvt->cursor_blink_state ^ terminal->pvt->screen->reverse_mode;
if (focus && !blink)
return;
/* Find the character "under" the cursor. */
cell = vte_terminal_find_charcell(terminal, col, drow);
while ((cell != NULL) && (cell->attr.fragment) && (col > 0)) {
col--;
cell = vte_terminal_find_charcell(terminal, col, drow);
}
/* Draw the cursor. */
item.c = (cell && cell->c) ? cell->c : ' ';
item.columns = cell ? cell->attr.columns : 1;
item.x = col * width;
item.y = row * height;
cursor_width = item.columns * width;
if (cell && cell->c != 0) {
gint cw = _vte_draw_get_char_width (terminal->pvt->draw,
cell->c, cell->attr.columns);
cursor_width = MAX(cursor_width, cw);
cursor_width += cell->attr.bold; /* for pseudo-bolding */
}
selected = vte_cell_is_selected(terminal, col, drow, NULL);
vte_terminal_determine_colors(terminal, cell,
TRUE^selected, selected, TRUE,
&fore, &back);
x = item.x + VTE_PAD_WIDTH;
y = item.y + VTE_PAD_WIDTH;
switch (terminal->pvt->cursor_shape) {
case VTE_CURSOR_SHAPE_IBEAM:
vte_terminal_draw_line(terminal, &terminal->pvt->palette[back],
x - 2,
y,
x - 2,
y + height - 1);
break;
case VTE_CURSOR_SHAPE_UNDERLINE:
vte_terminal_draw_line(terminal, &terminal->pvt->palette[back],
x,
y + height - 1,
x + cursor_width - 1,
y + height - 1);
break;
case VTE_CURSOR_SHAPE_BLOCK:
color.red = terminal->pvt->palette[back].red;
color.green = terminal->pvt->palette[back].green;
color.blue = terminal->pvt->palette[back].blue;
if (selected || focus) {
/* just reverse the character under the cursor */
_vte_draw_fill_rectangle(terminal->pvt->draw,
x,
y,
cursor_width,
height,
&color,
VTE_DRAW_OPAQUE);
if (!vte_terminal_unichar_is_local_graphic(terminal, item.c) ||
!vte_terminal_draw_graphic(terminal,
item.c,
fore, back,
TRUE,
item.x,
item.y,
width,
item.columns,
height)) {
gboolean hilite = FALSE;
if (cell && terminal->pvt->show_match) {
hilite = vte_cell_is_between(col, row,
terminal->pvt->match_start.column,
terminal->pvt->match_start.row,
terminal->pvt->match_end.column,
terminal->pvt->match_end.row,
TRUE);
}
if (cell && cell->c != 0 && cell->c != ' ') {
vte_terminal_draw_cells(terminal,
&item, 1,
fore, back, TRUE, FALSE,
cell->attr.bold,
cell->attr.underline,
cell->attr.strikethrough,
hilite,
FALSE,
width,
height);
}
}
} else {
/* draw a box around the character */
_vte_draw_draw_rectangle(terminal->pvt->draw,
x - VTE_CURSOR_OUTLINE,
y - VTE_CURSOR_OUTLINE,
cursor_width + 2*VTE_CURSOR_OUTLINE,
height + 2*VTE_CURSOR_OUTLINE,
&color,
VTE_DRAW_OPAQUE);
}
break;
}
}
/* Draw the widget. */
static void
vte_terminal_paint(GtkWidget *widget, GdkRegion *region)
{
VteTerminal *terminal;
VteScreen *screen;
struct vte_charcell *cell;
struct _vte_draw_text_request item;
int row, drow, col, columns;
long width, height, ascent, descent, delta, cursor_width;
long width, height, ascent, descent, delta;
int i, len, fore, back, x, y;
gboolean blink, selected;
_vte_debug_print(VTE_DEBUG_LIFECYCLE, "vte_terminal_paint()\n");
_vte_debug_print(VTE_DEBUG_WORK, "=");
......@@ -10409,157 +10559,7 @@ vte_terminal_paint(GtkWidget *widget, GdkRegion *region)
g_free (rectangles);
}
/* Draw the cursor. */
if (terminal->pvt->cursor_visible &&
(CLAMP(screen->cursor_current.col, 0, terminal->column_count - 1) ==
screen->cursor_current.col) &&
(CLAMP(screen->cursor_current.row,
delta, delta + terminal->row_count - 1) ==
screen->cursor_current.row)) {
/* Get the location of the cursor. */
col = screen->cursor_current.col;
drow = screen->cursor_current.row;
row = drow - delta;
/* Find the character "under" the cursor. */
cell = vte_terminal_find_charcell(terminal, col, drow);
while ((cell != NULL) && (cell->attr.fragment) && (col > 0)) {
col--;
cell = vte_terminal_find_charcell(terminal, col, drow);
}
/* Draw the cursor. */
item.c = (cell && cell->c) ? cell->c : ' ';
item.columns = cell ? cell->attr.columns : 1;
item.x = col * width;
item.y = row * height;
cursor_width = item.columns * width;
if (cell && cell->c != 0) {
gint cw = _vte_draw_get_char_width (terminal->pvt->draw,
cell->c, cell->attr.columns);
cursor_width = MAX(cursor_width, cw);
cursor_width += cell->attr.bold; /* pseudo-bolding */
}
selected = vte_cell_is_selected(terminal, col, drow, NULL);
if (GTK_WIDGET_HAS_FOCUS(terminal)) {
blink = terminal->pvt->cursor_blink_state ^
terminal->pvt->screen->reverse_mode;
vte_terminal_determine_colors(terminal, cell,
blink | selected,
selected,
blink,
&fore, &back);
if (blink) {
GdkColor color;
if (selected) {
goto draw_cursor_outline;
}
color.red = terminal->pvt->palette[back].red;
color.green = terminal->pvt->palette[back].green;
color.blue = terminal->pvt->palette[back].blue;
_vte_draw_fill_rectangle(terminal->pvt->draw,
item.x + VTE_PAD_WIDTH,
item.y + VTE_PAD_WIDTH,
cursor_width,
height,
&color,
VTE_DRAW_OPAQUE);
if (!vte_terminal_unichar_is_local_graphic(terminal, item.c) ||
!vte_terminal_draw_graphic(terminal,
item.c,
fore, back,
TRUE,
item.x,
item.y,
width,
item.columns,
height)) {
gboolean hilite = FALSE;
if (cell && terminal->pvt->show_match) {
hilite = vte_cell_is_between(col, row,
terminal->pvt->match_start.column,
terminal->pvt->match_start.row,
terminal->pvt->match_end.column,
terminal->pvt->match_end.row,
TRUE);
}
if (cell && cell->c != 0 && cell->c != ' ') {
vte_terminal_draw_cells(terminal,
&item, 1,
fore, back, TRUE, FALSE,
cell->attr.bold,
cell->attr.underline,
cell->attr.strikethrough,
hilite,
FALSE,
width,
height);
}
}
}
} else {
GdkColor color;
draw_cursor_outline:
_vte_draw_clear(terminal->pvt->draw,
col * width + VTE_PAD_WIDTH,
row * height + VTE_PAD_WIDTH,
cursor_width, height);
vte_terminal_determine_colors(terminal, cell,
terminal->pvt->screen->reverse_mode,
selected,
TRUE,
&fore, &back);
if (!vte_terminal_unichar_is_local_graphic(terminal, item.c) ||
!vte_terminal_draw_graphic(terminal,
item.c,
fore, back,
TRUE,
item.x,
item.y,
width,
item.columns,
height)) {
gboolean hilite = FALSE;
if (cell && terminal->pvt->show_match) {
hilite = vte_cell_is_between(col, row,
terminal->pvt->match_start.column,
terminal->pvt->match_start.row,
terminal->pvt->match_end.column,
terminal->pvt->match_end.row,
TRUE);
}
/* Draw it as a hollow rectangle overtop character. */
if (cell && cell->c != 0 && cell->c != ' ') {
vte_terminal_draw_cells(terminal,
&item, 1,
fore, back, TRUE, FALSE,
cell->attr.bold,
cell->attr.underline,
cell->attr.strikethrough,
hilite,
FALSE,
width,
height);
}
}
vte_terminal_determine_colors(terminal, cell,
!terminal->pvt->screen->reverse_mode,
selected,
TRUE,
&fore, &back);
color.red = terminal->pvt->palette[back].red;
color.green = terminal->pvt->palette[back].green;
color.blue = terminal->pvt->palette[back].blue;
_vte_draw_draw_rectangle(terminal->pvt->draw,
item.x + VTE_PAD_WIDTH - VTE_CURSOR_OUTLINE,
item.y + VTE_PAD_WIDTH - VTE_CURSOR_OUTLINE,
cursor_width + 2*VTE_CURSOR_OUTLINE,
height + 2*VTE_CURSOR_OUTLINE,
&color,
VTE_DRAW_OPAQUE);
}
}
vte_terminal_paint_cursor(terminal);
/* Draw the pre-edit string (if one exists) over the cursor. */
if (terminal->pvt->im_preedit) {
......@@ -11907,7 +11907,9 @@ vte_terminal_set_cursor_blink_mode(VteTerminal *terminal, VteTerminalCursorBlink
* vte_terminal_get_cursor_blink_mode:
* @terminal: a #VteTerminal
*
* Returns the cursor blink mode.
* Returns the currently set cursor blink mode.
*
* Return value: cursor blink mode.
*
* Since: 0.16.15
*/
......@@ -11919,6 +11921,47 @@ vte_terminal_get_cursor_blink_mode(VteTerminal *terminal)
return terminal->pvt->cursor_blink_mode;
}