medit/moo/mooterm/mootermbuffer.c

1214 lines
45 KiB
C

/*
* mooterm/mootermbuffer.c
*
* Copyright (C) 2004-2005 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* See COPYING file that comes with this distribution.
*/
#define MOOTERM_COMPILATION
#include "mooterm/mootermbuffer-private.h"
#include "mooutils/moocompat.h"
#include "mooutils/moomarshals.h"
#define ACS_STERLING "\302\243" /* U+00A3 POUND SIGN */
#define ACS_DARROW "\342\206\223" /* U+2193 DOWNWARDS ARROW */
#define ACS_LARROW "\342\206\220" /* U+2190 LEFTWARDS ARROW */
#define ACS_RARROW "\342\206\222" /* U+2192 RIGHTWARDS ARROW */
#define ACS_UARROW "\342\206\221" /* U+2191 UPWARDS ARROW */
#define ACS_BOARD "#" /* ??? */
#define ACS_BULLET "\342\200\242" /* U+2022 BULLET */
#define ACS_CKBOARD "\342\226\223" /* U+2593 DARK SHADE */
#define ACS_DEGREE "\302\260" /* U+00B0 DEGREE SIGN */
#define ACS_DIAMOND "\342\227\206" /* U+25C6 BLACK DIAMOND */
#define ACS_GEQUAL "\342\211\245" /* U+2265 GREATER-THAN OR EQUAL TO */
#define ACS_PI "\317\200" /* U+03C0 GREEK SMALL LETTER PI */
#define ACS_HLINE "\342\224\200" /* U+2500 BOX DRAWINGS LIGHT HORIZONTAL */
#define ACS_LANTERN "\347\201\257" /* U+706F CJK UNIFIED IDEOGRAPH-706F ??? */
#define ACS_PLUS "\342\224\274" /* U+253C BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
#define ACS_LEQUAL "\342\211\244" /* U+2264 LESS-THAN OR EQUAL TO */
#define ACS_LLCORNER "\342\224\224" /* U+2514 BOX DRAWINGS LIGHT UP AND RIGHT */
#define ACS_LRCORNER "\342\224\230" /* U+2518 BOX DRAWINGS LIGHT UP AND LEFT */
#define ACS_NEQUAL "\342\211\240" /* U+2260 NOT EQUAL TO */
#define ACS_PLMINUS "\302\261" /* U+00B1 PLUS-MINUS SIGN */
#define ACS_S1 "\342\216\272" /* U+23BA HORIZONTAL SCAN LINE-1 */
#define ACS_S3 "\342\216\273" /* U+23BB HORIZONTAL SCAN LINE-3 */
#define ACS_S7 "\342\216\274" /* U+23BC HORIZONTAL SCAN LINE-7 */
#define ACS_S9 "\342\216\275" /* U+23BD HORIZONTAL SCAN LINE-9 */
#define ACS_BLOCK "\342\226\210" /* U+2588 FULL BLOCK */
#define ACS_TTEE "\342\224\254" /* U+252C BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */
#define ACS_RTEE "\342\224\244" /* U+2524 BOX DRAWINGS LIGHT VERTICAL AND LEFT */
#define ACS_LTEE "\342\224\234" /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
#define ACS_BTEE "\342\224\264" /* U+2534 BOX DRAWINGS LIGHT UP AND HORIZONTAL */
#define ACS_ULCORNER "\342\224\214" /* U+250C BOX DRAWINGS LIGHT DOWN AND RIGHT */
#define ACS_URCORNER "\342\224\220" /* U+2510 BOX DRAWINGS LIGHT DOWN AND LEFT */
#define ACS_VLINE "\342\224\202" /* U+2502 BOX DRAWINGS LIGHT VERTICAL */
/*
blank " " " " _
diamond ACS_DIAMOND "+" `
checker board (stipple) ACS_CKBOARD ":" a
horizontal tab "\t" "\t" b
form feed "\014" "\014" c
carriage return "\r" "\r" d
line feed "\n" "\n" e
degree symbol ACS_DEGREE "\" f
plus/minus ACS_PLMINUS "#" g
board of squares ACS_BOARD "#" h
lantern symbol ACS_LANTERN "#" i
lower right corner ACS_LRCORNER "+" j
upper right corner ACS_URCORNER "+" k
upper left corner ACS_ULCORNER "+" l
lower left corner ACS_LLCORNER "+" m
large plus or crossover ACS_PLUS "+" n
scan line 1 ACS_S1 "~" o
scan line 3 ACS_S3 "-" p
horizontal line ACS_HLINE "-" q
scan line 7 ACS_S7 "-" r
scan line 9 ACS_S9 "_" s
tee pointing right ACS_LTEE "+" t
tee pointing left ACS_RTEE "+" u
tee pointing up ACS_BTEE "+" v
tee pointing down ACS_TTEE "+" w
vertical line ACS_VLINE "|" x
less-than-or-equal-to ACS_LEQUAL "<" y
greater-than-or-equal-to ACS_GEQUAL ">" z
greek pi ACS_PI "*" {
not-equal ACS_NEQUAL "!" |
UK pound sign ACS_STERLING "f" }
bullet ACS_BULLET "o" ~
*/
/* drawing chars are _`a-z{|}~ -- 0x5F - 0x7E */
#define MAX_GRAPH 126
static const char *DRAWING_SET_STRINGS[MAX_GRAPH + 1] = {
/* 95 nulls */
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* do we need control characters here? */
" ", ACS_DIAMOND, ACS_CKBOARD, "?", "?", "?", "?", ACS_DEGREE, ACS_PLMINUS, ACS_BOARD,
ACS_LANTERN, ACS_LRCORNER, ACS_URCORNER, ACS_ULCORNER, ACS_LLCORNER, ACS_PLUS, ACS_S1, ACS_S3,
ACS_HLINE, ACS_S7, ACS_S9, ACS_LTEE, ACS_RTEE, ACS_BTEE, ACS_TTEE, ACS_VLINE, ACS_LEQUAL,
ACS_GEQUAL, ACS_PI, ACS_NEQUAL, ACS_STERLING, ACS_BULLET
};
static gunichar ASCII_DRAWING_SET[MAX_GRAPH + 1] = {
/* 95 zeros */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
' ', '+', ':', '?', '?', '?', '?', '\\', '#', '#', '#', '+', '+', '+', '+', '+', '~', '-',
'-', '-', '_', '+', '+', '+', '+', '|', '<', '>', '*', '!', 'f', 'o'
};
static gunichar DRAWING_SET[MAX_GRAPH + 1];
static void init_drawing_sets (void);
#define MIN_WIDTH (10)
#define MIN_HEIGHT (10)
static void moo_term_buffer_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void moo_term_buffer_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static GObject *moo_term_buffer_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_param);
static void moo_term_buffer_finalize (GObject *object);
/* MOO_TYPE_TERM_BUFFER */
G_DEFINE_TYPE (MooTermBuffer, moo_term_buffer, G_TYPE_OBJECT)
enum {
CHANGED,
SCREEN_SIZE_CHANGED,
CURSOR_MOVED,
BELL,
SET_WINDOW_TITLE,
SET_ICON_NAME,
FEED_CHILD,
FULL_RESET,
LAST_SIGNAL
};
enum {
PROP_0,
PROP_SCREEN_WIDTH,
PROP_SCREEN_HEIGHT,
PROP_SCROLLBACK,
PROP_MAX_SCROLLBACK,
PROP_CURSOR_VISIBLE,
PROP_MODE_IRM,
PROP_MODE_LNM,
PROP_MODE_DECCKM,
PROP_MODE_DECSCNM,
PROP_MODE_DECOM,
PROP_MODE_DECAWM,
PROP_MODE_MOUSE_TRACKING,
PROP_MODE_HILITE_MOUSE_TRACKING,
PROP_MODE_KEYPAD_NUMERIC,
PROP_SCROLLING_REGION_SET
};
static guint signals[LAST_SIGNAL];
static void moo_term_buffer_class_init (MooTermBufferClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
init_drawing_sets ();
gobject_class->set_property = moo_term_buffer_set_property;
gobject_class->get_property = moo_term_buffer_get_property;
gobject_class->constructor = moo_term_buffer_constructor;
gobject_class->finalize = moo_term_buffer_finalize;
klass->changed = buf_changed_clear;
signals[CHANGED] =
g_signal_new ("changed",
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (MooTermBufferClass, changed),
NULL, NULL,
_moo_marshal_VOID__VOID,
G_TYPE_NONE, 0);
signals[CURSOR_MOVED] =
g_signal_new ("cursor-moved",
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (MooTermBufferClass, cursor_moved),
NULL, NULL,
_moo_marshal_VOID__UINT_UINT,
G_TYPE_NONE, 2,
G_TYPE_UINT, G_TYPE_UINT);
signals[BELL] =
g_signal_new ("bell",
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (MooTermBufferClass, bell),
NULL, NULL,
_moo_marshal_VOID__VOID,
G_TYPE_NONE, 0);
signals[SCREEN_SIZE_CHANGED] =
g_signal_new ("screen-size-changed",
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (MooTermBufferClass, screen_size_changed),
NULL, NULL,
_moo_marshal_VOID__UINT_UINT,
G_TYPE_NONE, 2,
G_TYPE_UINT, G_TYPE_UINT);
signals[SET_WINDOW_TITLE] =
g_signal_new ("set-window-title",
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (MooTermBufferClass, set_window_title),
NULL, NULL,
_moo_marshal_VOID__STRING,
G_TYPE_NONE, 1,
G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE);
signals[SET_ICON_NAME] =
g_signal_new ("set-icon-name",
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (MooTermBufferClass, set_icon_name),
NULL, NULL,
_moo_marshal_VOID__STRING,
G_TYPE_NONE, 1,
G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE);
signals[FEED_CHILD] =
g_signal_new ("feed-child",
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (MooTermBufferClass, feed_child),
NULL, NULL,
_moo_marshal_VOID__STRING_INT,
G_TYPE_NONE, 2,
G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE,
G_TYPE_INT);
signals[FULL_RESET] =
g_signal_new ("full-reset",
G_OBJECT_CLASS_TYPE (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (MooTermBufferClass, full_reset),
NULL, NULL,
_moo_marshal_VOID__VOID,
G_TYPE_NONE, 0);
g_object_class_install_property (gobject_class,
PROP_SCREEN_WIDTH,
g_param_spec_uint ("screen-width",
"screen-width",
"screen-width",
0, 1000000, 80,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_SCREEN_HEIGHT,
g_param_spec_uint ("screen-height",
"screen-height",
"screen-height",
0, 1000000, 24,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_MAX_SCROLLBACK,
g_param_spec_int ("max-scrollback",
"max-scrollback",
"max-scrollback",
-1, 1000000, -1,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_SCROLLBACK,
g_param_spec_uint ("scrollback",
"scrollback",
"scrollback",
0, 1000000, 0,
G_PARAM_READABLE));
g_object_class_install_property (gobject_class,
PROP_CURSOR_VISIBLE,
g_param_spec_boolean ("cursor-visible",
"cursor-visible",
"cursor-visible",
TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_MODE_IRM,
g_param_spec_boolean ("mode-IRM",
"mode-IRM",
"Insertion-Replacement Mode",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_MODE_LNM,
g_param_spec_boolean ("mode-LNM",
"mode-LNM",
"Linefeed/New Line Mode",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_MODE_DECCKM,
g_param_spec_boolean ("mode-DECCKM",
"mode-DECCKM",
"Cursor Key Mode",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_MODE_DECSCNM,
g_param_spec_boolean ("mode-DECSCNM",
"mode-DECSCNM",
"Screen Mode",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_MODE_DECOM,
g_param_spec_boolean ("mode-DECOM",
"mode-DECOM",
"Origin Mode",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_MODE_DECAWM,
g_param_spec_boolean ("mode-DECAWM",
"mode-DECAWM",
"Auto Wrap Mode",
TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_MODE_MOUSE_TRACKING,
g_param_spec_boolean ("mode-MOUSE-TRACKING",
"mode-MOUSE_TRACKING",
"Send mouse X & Y on button press and release",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_MODE_HILITE_MOUSE_TRACKING,
g_param_spec_boolean ("mode-HILITE-MOUSE-TRACKING",
"mode-HILITE_MOUSE_TRACKING",
"Use Hilite Mouse Tracking",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_MODE_KEYPAD_NUMERIC,
g_param_spec_boolean ("mode-KEYPAD-NUMERIC",
"mode-KEYPAD-NUMERIC",
"mode-KEYPAD-NUMERIC",
TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_SCROLLING_REGION_SET,
g_param_spec_boolean ("scrolling-region-set",
"scrolling-region-set",
"scrolling-region-set",
FALSE,
G_PARAM_READABLE));
}
static void moo_term_buffer_init (MooTermBuffer *buf)
{
buf->priv = g_new0 (MooTermBufferPrivate, 1);
buf->priv->lines = g_ptr_array_new ();
buf->priv->changed = NULL;
buf->priv->changed_all = FALSE;
buf->priv->parser = moo_term_parser_new (buf);
buf->priv->single_shift = -1;
buf->priv->graph_sets[0] = buf->priv->graph_sets[1] =
buf->priv->graph_sets[2] = buf->priv->graph_sets[3] = NULL;
buf->priv->current_graph_set = NULL;
}
static void moo_term_buffer_finalize (GObject *object)
{
guint i;
MooTermBuffer *buf = MOO_TERM_BUFFER (object);
for (i = 0; i < buf->priv->lines->len; ++i)
term_line_free (buf_line (buf, i));
g_ptr_array_free (buf->priv->lines, TRUE);
g_list_free (buf->priv->tab_stops);
if (buf->priv->changed)
buf_region_destroy (buf->priv->changed);
moo_term_parser_free (buf->priv->parser);
g_free (buf->priv);
G_OBJECT_CLASS (moo_term_buffer_parent_class)->finalize (object);
}
#define set_mode(modes, m, val) \
{ \
if (val) \
modes |= m; \
else \
modes &= ~m; \
}
static void moo_term_buffer_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MooTermBuffer *buf = MOO_TERM_BUFFER (object);
switch (prop_id) {
case PROP_SCREEN_WIDTH:
if (buf->priv->constructed)
moo_term_buffer_set_screen_size (buf, g_value_get_uint (value), 0);
else
buf->priv->screen_width = g_value_get_uint (value);
break;
case PROP_SCREEN_HEIGHT:
if (buf->priv->constructed)
moo_term_buffer_set_screen_size (buf, 0, g_value_get_uint (value));
else
buf->priv->screen_height = g_value_get_uint (value);
break;
case PROP_MAX_SCROLLBACK:
if (buf->priv->constructed)
moo_term_buffer_set_max_scrollback (buf, g_value_get_int (value));
else
buf->priv->max_height = g_value_get_int (value);
break;
case PROP_CURSOR_VISIBLE:
moo_term_buffer_set_cursor_visible (buf, g_value_get_boolean (value));
break;
case PROP_MODE_IRM:
set_mode (buf->priv->modes, IRM, g_value_get_boolean (value));
g_object_notify (G_OBJECT (buf), "mode-IRM");
break;
case PROP_MODE_LNM:
set_mode (buf->priv->modes, LNM, g_value_get_boolean (value));
g_object_notify (G_OBJECT (buf), "mode-LNM");
break;
case PROP_MODE_DECCKM:
set_mode (buf->priv->modes, DECCKM, g_value_get_boolean (value));
g_object_notify (G_OBJECT (buf), "mode-DECCKM");
break;
case PROP_MODE_DECSCNM:
set_mode (buf->priv->modes, DECSCNM, g_value_get_boolean (value));
g_object_notify (G_OBJECT (buf), "mode-DECSCNM");
break;
case PROP_MODE_DECOM:
set_mode (buf->priv->modes, DECOM, g_value_get_boolean (value));
g_object_notify (G_OBJECT (buf), "mode-DECOM");
break;
case PROP_MODE_DECAWM:
set_mode (buf->priv->modes, DECAWM, g_value_get_boolean (value));
g_object_notify (G_OBJECT (buf), "mode-DECAWM");
break;
case PROP_MODE_MOUSE_TRACKING:
set_mode (buf->priv->modes, MOUSE_TRACKING, g_value_get_boolean (value));
g_object_notify (G_OBJECT (buf), "mode-MOUSE-TRACKING");
break;
case PROP_MODE_HILITE_MOUSE_TRACKING:
set_mode (buf->priv->modes, HILITE_MOUSE_TRACKING, g_value_get_boolean (value));
g_object_notify (G_OBJECT (buf), "mode-HILITE-MOUSE-TRACKING");
break;
case PROP_MODE_KEYPAD_NUMERIC:
set_mode (buf->priv->modes, KEYPAD_NUMERIC, g_value_get_boolean (value));
g_object_notify (G_OBJECT (buf), "mode-KEYPAD-NUMERIC");
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void moo_term_buffer_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MooTermBuffer *buf = MOO_TERM_BUFFER (object);
switch (prop_id) {
case PROP_SCREEN_WIDTH:
g_value_set_uint (value, buf->priv->screen_width);
break;
case PROP_SCREEN_HEIGHT:
g_value_set_uint (value, buf->priv->screen_height);
break;
case PROP_SCROLLBACK:
g_value_set_uint (value, buf_screen_offset (buf));
break;
case PROP_MAX_SCROLLBACK:
g_value_set_int (value, buf->priv->max_height);
break;
case PROP_CURSOR_VISIBLE:
g_value_set_boolean (value, buf->priv->cursor_visible);
break;
case PROP_MODE_IRM:
g_value_set_boolean (value, buf->priv->modes & IRM);
break;
case PROP_MODE_LNM:
g_value_set_boolean (value, buf->priv->modes & LNM);
break;
case PROP_MODE_DECCKM:
g_value_set_boolean (value, buf->priv->modes & DECCKM);
break;
case PROP_MODE_DECSCNM:
g_value_set_boolean (value, buf->priv->modes & DECSCNM);
break;
case PROP_MODE_DECOM:
g_value_set_boolean (value, buf->priv->modes & DECOM);
break;
case PROP_MODE_DECAWM:
g_value_set_boolean (value, buf->priv->modes & DECAWM);
break;
case PROP_MODE_MOUSE_TRACKING:
g_value_set_boolean (value, buf->priv->modes & MOUSE_TRACKING);
break;
case PROP_MODE_HILITE_MOUSE_TRACKING:
g_value_set_boolean (value, buf->priv->modes & HILITE_MOUSE_TRACKING);
break;
case PROP_MODE_KEYPAD_NUMERIC:
g_value_set_boolean (value, buf->priv->modes & KEYPAD_NUMERIC);
break;
case PROP_SCROLLING_REGION_SET:
g_value_set_boolean (value, buf->priv->scrolling_region_set);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GObject *moo_term_buffer_constructor (GType type,
guint n_props,
GObjectConstructParam *props)
{
MooTermBuffer *buf;
GObject *object;
guint i;
object = G_OBJECT_CLASS(moo_term_buffer_parent_class)->constructor (type, n_props, props);
buf = MOO_TERM_BUFFER (object);
buf->priv->constructed = TRUE;
if (buf->priv->max_height <= MIN_HEIGHT)
buf->priv->max_height = -1;
buf->priv->current_attr.mask = 0;
if (buf->priv->screen_width < MIN_WIDTH)
buf->priv->screen_width = MIN_WIDTH;
if (buf->priv->screen_height < MIN_HEIGHT)
buf->priv->screen_height = MIN_HEIGHT;
buf->priv->screen_offset = 0;
buf->priv->top_margin = 0;
buf->priv->bottom_margin = buf->priv->screen_height - 1;
buf->priv->scrolling_region_set = FALSE;
for (i = 0; i < buf->priv->screen_height; ++i)
{
g_ptr_array_add (buf->priv->lines,
term_line_new (buf->priv->screen_width));
}
return object;
}
void moo_term_buffer_set_cursor_visible (MooTermBuffer *buf,
gboolean visible)
{
buf->priv->cursor_visible = visible;
g_object_notify (G_OBJECT (buf), "cursor-visible");
}
void moo_term_buffer_bell (MooTermBuffer *buf)
{
g_signal_emit (buf, signals[BELL], 0);
}
void moo_term_buffer_changed (MooTermBuffer *buf)
{
if (!buf->priv->freeze_changed_notify)
g_signal_emit (buf, signals[CHANGED], 0);
}
void moo_term_buffer_scrollback_changed (MooTermBuffer *buf)
{
g_object_notify (G_OBJECT (buf), "scrollback");
}
static void buf_set_screen_width (MooTermBuffer *buf,
guint width)
{
buf->priv->screen_width = width;
if (buf->priv->cursor_col >= width)
moo_term_buffer_cursor_move_to (buf, -1, width - 1);
g_object_notify (G_OBJECT (buf), "screen-width");
g_signal_emit (buf, signals[SCREEN_SIZE_CHANGED], 0,
width,
buf_screen_height (buf));
moo_term_buffer_reset_tab_stops (buf);
buf_changed_set_all (buf);
moo_term_buffer_changed (buf);
}
static void buf_set_screen_height (MooTermBuffer *buf,
guint height)
{
guint old_height = buf_screen_height (buf);
guint width = buf_screen_width (buf);
buf->priv->screen_height = height;
if (height > old_height)
{
if (buf->priv->screen_offset < height - old_height)
{
guint add = height - old_height - buf->priv->screen_offset;
guint i;
for (i = 0; i < add; ++i)
g_ptr_array_add (buf->priv->lines,
term_line_new (width));
if (buf->priv->screen_offset)
{
guint cursor_row =
buf->priv->screen_offset + buf->priv->cursor_row;
buf->priv->screen_offset = 0;
moo_term_buffer_cursor_move_to (buf, cursor_row, -1);
moo_term_buffer_scrollback_changed (buf);
}
}
else
{
buf->priv->screen_offset -= (height - old_height);
moo_term_buffer_cursor_move_to (buf,
buf->priv->cursor_row + height - old_height, -1);
moo_term_buffer_scrollback_changed (buf);
}
}
else
{
buf->priv->screen_offset += (old_height - height);
if (buf->priv->cursor_row > old_height - height)
moo_term_buffer_cursor_move_to (buf,
buf->priv->cursor_row + height - old_height, -1);
else
moo_term_buffer_cursor_move_to (buf, 0, -1);
moo_term_buffer_scrollback_changed (buf);
}
g_object_notify (G_OBJECT (buf), "screen-height");
g_signal_emit (buf, signals[SCREEN_SIZE_CHANGED], 0,
buf_screen_width (buf),
height);
if (buf->priv->scrolling_region_set)
{
if (buf->priv->top_margin >= height)
{
buf->priv->top_margin = 0;
buf->priv->bottom_margin = height - 1;
buf->priv->scrolling_region_set = FALSE;
g_object_notify (G_OBJECT (buf), "scrolling-region-set");
}
else if (buf->priv->bottom_margin >= height)
{
buf->priv->bottom_margin = height - 1;
}
}
buf_changed_set_all (buf);
moo_term_buffer_changed (buf);
}
void moo_term_buffer_set_screen_size (MooTermBuffer *buf,
guint width,
guint height)
{
if (height >= MIN_HEIGHT && height != buf_screen_height (buf))
buf_set_screen_height (buf, height);
if (width >= MIN_WIDTH && width != buf_screen_width (buf))
buf_set_screen_width (buf, width);
}
void moo_term_buffer_set_max_scrollback (G_GNUC_UNUSED MooTermBuffer *buf,
G_GNUC_UNUSED int lines)
{
g_warning ("%s: implement me", G_STRLOC);
}
void moo_term_buffer_cursor_move (MooTermBuffer *buf,
int rows,
int cols)
{
int width = buf_screen_width (buf);
int height = buf_screen_height (buf);
int cursor_row = buf_cursor_row (buf);
int cursor_col = buf_cursor_col (buf);
if (rows && cursor_row + rows >= 0 && cursor_row + rows < height)
cursor_row += rows;
if (cols && cursor_col + cols >= 0 && cursor_col + cols < width)
cursor_col += cols;
moo_term_buffer_cursor_move_to (buf, cursor_row, cursor_col);
}
static void moo_term_buffer_cursor_moved (MooTermBuffer *buf,
guint old_row,
guint old_col)
{
if (!buf->priv->freeze_cursor_notify)
g_signal_emit (buf, signals[CURSOR_MOVED], 0,
old_row, old_col);
}
void moo_term_buffer_cursor_move_to (MooTermBuffer *buf,
int row,
int col)
{
guint old_row = buf_cursor_row (buf);
guint old_col = buf_cursor_col (buf);
g_return_if_fail (row < (int) buf_screen_height (buf));
g_return_if_fail (col < (int) buf_screen_width (buf));
if (row < 0)
row = old_row;
if (col < 0)
col = old_col;
buf->priv->cursor_row = row;
buf->priv->cursor_col = col;
moo_term_buffer_cursor_moved (buf, old_row, old_col);
}
void moo_term_buffer_write (MooTermBuffer *buf,
const char *data,
int len)
{
guint old_cursor_row = buf_cursor_row (buf);
guint old_cursor_col = buf_cursor_col (buf);
buf_freeze_changed_notify (buf);
buf_freeze_cursor_notify (buf);
moo_term_parser_parse (buf->priv->parser, data, len);
buf_thaw_changed_notify (buf);
buf_thaw_cursor_notify (buf);
moo_term_buffer_changed (buf);
moo_term_buffer_cursor_moved (buf, old_cursor_row, old_cursor_col);
}
/* chars must be valid unicode string */
static void buf_print_chars_real (MooTermBuffer *buf,
const char *chars,
guint len)
{
guint width = buf_screen_width (buf);
guint cursor_row = buf_cursor_row (buf);
MooTermTextAttr *attr =
buf->priv->current_attr.mask ? &buf->priv->current_attr : NULL;
const char *p = chars;
const char *end = chars + len;
g_assert (p < end);
for (p = chars; p < end; p = g_utf8_next_char (p))
{
gunichar c = g_utf8_get_char (p);
if (c <= MAX_GRAPH)
{
if (buf->priv->single_shift >= 0)
{
if (buf->priv->graph_sets[buf->priv->single_shift])
{
if (buf->priv->graph_sets[buf->priv->single_shift][c])
c = buf->priv->graph_sets[buf->priv->single_shift][c];
else
g_warning ("%s: using regular character while in "
"graphics mode", G_STRLOC);
}
buf->priv->single_shift = -1;
}
else if (buf->priv->current_graph_set)
{
if (buf->priv->current_graph_set[c])
c = buf->priv->current_graph_set[c];
else
g_warning ("%s: using regular character while in "
"graphics mode", G_STRLOC);
}
}
if (buf->priv->modes & IRM)
{
term_line_insert_unichar (buf_screen_line (buf, cursor_row),
buf->priv->cursor_col++,
c, 1, attr, width);
buf_changed_add_range (buf, cursor_row,
buf->priv->cursor_col - 1,
width - buf->priv->cursor_col + 1);
}
else
{
term_line_set_unichar (buf_screen_line (buf, cursor_row),
buf->priv->cursor_col++,
c, 1, attr, width);
buf_changed_add_range (buf, cursor_row,
buf->priv->cursor_col - 1, 1);
}
if (buf->priv->cursor_col == width)
{
buf->priv->cursor_col--;
if (buf->priv->modes & DECAWM)
moo_term_buffer_new_line (buf);
}
}
}
/* chars must be valid unicode string */
void moo_term_buffer_print_chars (MooTermBuffer *buf,
const char *chars,
int len)
{
const char *p = chars;
const char *s;
g_return_if_fail (len != 0 && chars != NULL);
while ((len > 0 && p != chars + len) || (len < 0 && *p != 0))
{
for (s = p; ((len > 0 && s != chars + len) || (len < 0 && *s != 0))
&& *s && (*s & 0x80 || (' ' <= *s && *s <= '~')); ++s) ;
if (s != p)
{
buf_print_chars_real (buf, p, s - p);
p = s;
}
else if (!*s)
{
++p;
}
else if (*s == 0x7F)
{
buf_print_chars_real (buf, "~", -1);
++p;
}
else
{
static char ar[2] = {'^'};
ar[1] = *s + 0x40;
buf_print_chars_real (buf, ar, 2);
}
}
}
MooTermBuffer *moo_term_buffer_new (guint width,
guint height)
{
return MOO_TERM_BUFFER (g_object_new (MOO_TYPE_TERM_BUFFER,
"screen-width", width,
"screen-height", height,
NULL));
}
void moo_term_buffer_set_window_title (MooTermBuffer *buf,
const char *title)
{
g_signal_emit (buf, signals[SET_WINDOW_TITLE], 0, title);
}
void moo_term_buffer_set_icon_name (MooTermBuffer *buf,
const char *icon)
{
g_signal_emit (buf, signals[SET_ICON_NAME], 0, icon);
}
void moo_term_buffer_index (MooTermBuffer *buf)
{
guint cursor_row = buf_cursor_row (buf);
guint screen_height = buf_screen_height (buf);
g_assert (cursor_row < screen_height);
if (cursor_row == screen_height - 1)
{
_buf_add_lines (buf, 1);
buf_changed_set_all (buf);
moo_term_buffer_changed (buf);
moo_term_buffer_scrollback_changed (buf);
}
else
{
moo_term_buffer_cursor_move (buf, 1, 0);
}
}
void moo_term_buffer_new_line (MooTermBuffer *buf)
{
moo_term_buffer_index (buf);
moo_term_buffer_cursor_move_to (buf, -1, 0);
}
void moo_term_buffer_full_reset (MooTermBuffer *buf)
{
g_signal_emit (buf, signals[FULL_RESET], 0);
buf->priv->top_margin = 0;
buf->priv->bottom_margin = buf->priv->screen_height - 1;
buf->priv->scrolling_region_set = FALSE;
g_object_notify (G_OBJECT (buf), "scrolling-region-set");
moo_term_buffer_erase_display (buf);
moo_term_buffer_cursor_move_to (buf, 0, 0);
g_object_set (buf,
"mode-IRM", FALSE,
"mode-LNM", FALSE,
"mode-DECCKM", FALSE,
"mode-DECSCNM", FALSE,
"mode-DECOM", FALSE,
"mode-DECAWM", TRUE,
"mode-MOUSE-TRACKING", FALSE,
"mode-HILITE-MOUSE-TRACKING", FALSE,
"mode-KEYPAD-NUMERIC", TRUE,
NULL);
}
void moo_term_buffer_feed_child (MooTermBuffer *buf,
const char *string,
int len)
{
g_signal_emit (buf, signals[FEED_CHILD], 0, string, len);
}
void moo_term_buffer_erase_display (MooTermBuffer *buf)
{
guint screen_height = buf_screen_height (buf);
guint i;
for (i = 0; i < screen_height; ++i)
term_line_erase (buf_screen_line (buf, i));
buf_changed_set_all (buf);
moo_term_buffer_changed (buf);
}
void moo_term_buffer_set_keypad_numeric (MooTermBuffer *buf,
gboolean setting)
{
if (setting)
buf->priv->modes |= KEYPAD_NUMERIC;
else
buf->priv->modes &= ~KEYPAD_NUMERIC;
g_object_notify (G_OBJECT (buf), "mode-KEYPAD-NUMERIC");
}
void moo_term_buffer_reset_tab_stops (MooTermBuffer *buf)
{
guint i;
guint width = buf_screen_width (buf);
g_list_free (buf->priv->tab_stops);
buf->priv->tab_stops = NULL;
for (i = 0; i < (width + 7) / 8; ++i)
buf->priv->tab_stops = g_list_append (buf->priv->tab_stops,
GUINT_TO_POINTER (8 * i));
}
guint moo_term_buffer_next_tab_stop (MooTermBuffer *buf,
guint current)
{
GList *l;
for (l = buf->priv->tab_stops;
l != NULL && GPOINTER_TO_UINT (l->data) <= current;
l = l->next) ;
if (l && GPOINTER_TO_UINT (l->data) > current)
return GPOINTER_TO_UINT (l->data);
else
return buf_screen_width (buf) - 1;
}
guint moo_term_buffer_prev_tab_stop (MooTermBuffer *buf,
guint current)
{
GList *l;
for (l = buf->priv->tab_stops;
l != NULL && GPOINTER_TO_UINT (l->data) < current;
l = l->next) ;
if (l && l->prev && GPOINTER_TO_UINT (l->prev->data) < current)
return GPOINTER_TO_UINT (l->prev->data);
else
return 0;
}
void moo_term_buffer_clear_tab_stop (MooTermBuffer *buf)
{
buf->priv->tab_stops =
g_list_remove (buf->priv->tab_stops,
GUINT_TO_POINTER (buf_cursor_col (buf)));
}
static int cmp_guints (gconstpointer a, gconstpointer b)
{
if (GPOINTER_TO_UINT (a) < GPOINTER_TO_UINT (b))
return -1;
else if (a == b)
return 0;
else
return 1;
}
void moo_term_buffer_set_tab_stop (MooTermBuffer *buf)
{
guint cursor = buf_cursor_col (buf);
if (!g_list_find (buf->priv->tab_stops, GUINT_TO_POINTER (cursor)))
buf->priv->tab_stops =
g_list_insert_sorted (buf->priv->tab_stops,
GUINT_TO_POINTER (cursor),
cmp_guints);
}
static void init_drawing_sets (void)
{
guint i;
for (i = 0; i <= MAX_GRAPH; ++i)
{
if (DRAWING_SET_STRINGS[i])
DRAWING_SET[i] = g_utf8_get_char (DRAWING_SET_STRINGS[i]);
}
}
void moo_term_buffer_select_charset (MooTermBuffer *buf,
guint set_num,
guint charset)
{
g_return_if_fail (set_num < 4 && charset < 5);
switch (charset)
{
case 0:
if (buf->priv->use_ascii_graphics)
buf->priv->graph_sets[set_num] = ASCII_DRAWING_SET;
else
buf->priv->graph_sets[set_num] = DRAWING_SET;
break;
case 2:
g_warning ("%s: choosing graphics instead of"
"Alternate Character ROM Special Set", G_STRLOC);
if (buf->priv->use_ascii_graphics)
buf->priv->graph_sets[set_num] = ASCII_DRAWING_SET;
else
buf->priv->graph_sets[set_num] = DRAWING_SET;
break;
case 1:
g_warning ("%s: choosing regular charset instead of"
"Alternate Character ROM Standard Set", G_STRLOC);
buf->priv->graph_sets[set_num] = NULL;
break;
case 3:
g_warning ("%s: choosing regular charset instead of"
"United Kingdom", G_STRLOC);
buf->priv->graph_sets[set_num] = NULL;
break;
case 4:
buf->priv->graph_sets[set_num] = NULL;
break;
}
}
void moo_term_buffer_shift (MooTermBuffer *buf,
guint set)
{
g_return_if_fail (set < 4);
buf->priv->current_graph_set = buf->priv->graph_sets[set];
}
void moo_term_buffer_single_shift (MooTermBuffer *buf,
guint set)
{
g_return_if_fail (set < 4);
buf->priv->single_shift = set;
}