1436 lines
44 KiB
C
1436 lines
44 KiB
C
/*
|
|
* mooterm/mooterm.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/mooterm-private.h"
|
|
#include "mooterm/mootermparser.h"
|
|
#include "mooterm/mootermpt.h"
|
|
#include "mooterm/mootermbuffer-private.h"
|
|
#include "mooutils/moocompat.h"
|
|
#include "mooutils/moomarshals.h"
|
|
|
|
|
|
static void moo_term_finalize (GObject *object);
|
|
|
|
static void moo_term_realize (GtkWidget *widget);
|
|
static void moo_term_size_allocate (GtkWidget *widget,
|
|
GtkAllocation *allocation);
|
|
|
|
static gboolean moo_term_popup_menu (GtkWidget *widget);
|
|
static gboolean moo_term_scroll (GtkWidget *widget,
|
|
GdkEventScroll *event);
|
|
|
|
static void moo_term_set_scroll_adjustments (GtkWidget *widget,
|
|
GtkAdjustment *hadj,
|
|
GtkAdjustment *vadj);
|
|
|
|
static void update_adjustment (MooTerm *term);
|
|
static void update_adjustment_value (MooTerm *term);
|
|
static void adjustment_value_changed (MooTerm *term);
|
|
static void queue_adjustment_changed (MooTerm *term,
|
|
gboolean now);
|
|
static void queue_adjustment_value_changed (MooTerm *term,
|
|
gboolean now);
|
|
static gboolean emit_adjustment_changed (MooTerm *term);
|
|
static gboolean emit_adjustment_value_changed (MooTerm *term);
|
|
static void scroll_abs (MooTerm *term,
|
|
guint line,
|
|
gboolean update_adj);
|
|
static void scroll_to_bottom (MooTerm *term,
|
|
gboolean update_adj);
|
|
|
|
static void scrollback_changed (MooTerm *term,
|
|
GParamSpec *pspec,
|
|
MooTermBuffer *buf);
|
|
static void width_changed (MooTerm *term,
|
|
GParamSpec *pspec);
|
|
static void height_changed (MooTerm *term,
|
|
GParamSpec *pspec);
|
|
|
|
static void im_preedit_start (MooTerm *term);
|
|
static void im_preedit_end (MooTerm *term);
|
|
|
|
static void child_died (MooTerm *term);
|
|
|
|
|
|
enum {
|
|
SET_SCROLL_ADJUSTMENTS,
|
|
SET_WINDOW_TITLE,
|
|
SET_ICON_NAME,
|
|
BELL,
|
|
CHILD_DIED,
|
|
POPULATE_POPUP,
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
enum {
|
|
PROP_0 = 0,
|
|
LAST_PROP
|
|
};
|
|
|
|
|
|
/* MOO_TYPE_TERM */
|
|
G_DEFINE_TYPE (MooTerm, moo_term, GTK_TYPE_WIDGET)
|
|
static guint signals[LAST_SIGNAL];
|
|
|
|
|
|
static void moo_term_class_init (MooTermClass *klass)
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
|
|
|
gobject_class->finalize = moo_term_finalize;
|
|
|
|
widget_class->realize = moo_term_realize;
|
|
widget_class->size_allocate = moo_term_size_allocate;
|
|
widget_class->expose_event = moo_term_expose_event;
|
|
widget_class->key_press_event = moo_term_key_press;
|
|
widget_class->key_release_event = moo_term_key_release;
|
|
widget_class->popup_menu = moo_term_popup_menu;
|
|
widget_class->scroll_event = moo_term_scroll;
|
|
widget_class->button_press_event = moo_term_button_press;
|
|
widget_class->button_release_event = moo_term_button_release;
|
|
widget_class->motion_notify_event = moo_term_motion_notify;
|
|
|
|
klass->set_scroll_adjustments = moo_term_set_scroll_adjustments;
|
|
|
|
signals[SET_SCROLL_ADJUSTMENTS] =
|
|
g_signal_new ("set-scroll-adjustments",
|
|
G_OBJECT_CLASS_TYPE (gobject_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (MooTermClass, set_scroll_adjustments),
|
|
NULL, NULL,
|
|
_moo_marshal_VOID__OBJECT_OBJECT,
|
|
G_TYPE_NONE, 2,
|
|
GTK_TYPE_ADJUSTMENT,
|
|
GTK_TYPE_ADJUSTMENT);
|
|
widget_class->set_scroll_adjustments_signal = signals[SET_SCROLL_ADJUSTMENTS];
|
|
|
|
signals[SET_WINDOW_TITLE] =
|
|
g_signal_new ("set-window-title",
|
|
G_OBJECT_CLASS_TYPE (gobject_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (MooTermClass, 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 (MooTermClass, set_icon_name),
|
|
NULL, NULL,
|
|
_moo_marshal_VOID__STRING,
|
|
G_TYPE_NONE, 1,
|
|
G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE);
|
|
|
|
signals[BELL] =
|
|
g_signal_new ("bell",
|
|
G_OBJECT_CLASS_TYPE (gobject_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (MooTermClass, bell),
|
|
NULL, NULL,
|
|
_moo_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
|
|
signals[CHILD_DIED] =
|
|
g_signal_new ("child-died",
|
|
G_OBJECT_CLASS_TYPE (gobject_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (MooTermClass, child_died),
|
|
NULL, NULL,
|
|
_moo_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
|
|
signals[POPULATE_POPUP] =
|
|
g_signal_new ("populate-popup",
|
|
G_OBJECT_CLASS_TYPE (gobject_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (MooTermClass, populate_popup),
|
|
NULL, NULL,
|
|
_moo_marshal_VOID__OBJECT,
|
|
G_TYPE_NONE, 1,
|
|
GTK_TYPE_MENU);
|
|
}
|
|
|
|
|
|
static void moo_term_init (MooTerm *term)
|
|
{
|
|
term->priv = g_new0 (MooTermPrivate, 1);
|
|
|
|
term->priv->pt = moo_term_pt_new (term);
|
|
g_signal_connect_swapped (term->priv->pt, "child-died",
|
|
G_CALLBACK (child_died), term);
|
|
|
|
term->priv->parser = moo_term_parser_new (term);
|
|
|
|
term->priv->primary_buffer = moo_term_buffer_new (80, 24);
|
|
term->priv->alternate_buffer = moo_term_buffer_new (80, 24);
|
|
term->priv->buffer = term->priv->primary_buffer;
|
|
|
|
term->priv->saved_cursor = g_array_new (FALSE, FALSE, sizeof(guint));
|
|
|
|
term->priv->width = 80;
|
|
term->priv->height = 24;
|
|
|
|
term->priv->selection = term_selection_new ();
|
|
|
|
term->priv->cursor_visible = TRUE;
|
|
|
|
term->priv->settings.hide_pointer_on_keypress = TRUE;
|
|
term->priv->settings.meta_sends_escape = TRUE;
|
|
term->priv->settings.scroll_on_keystroke = TRUE;
|
|
term->priv->settings.backspace_binding = MOO_TERM_ERASE_AUTO;
|
|
term->priv->settings.delete_binding = MOO_TERM_ERASE_AUTO;
|
|
|
|
term->priv->pointer_visible = TRUE;
|
|
|
|
set_default_modes (term->priv->modes);
|
|
set_default_modes (term->priv->saved_modes);
|
|
|
|
g_signal_connect_swapped (term->priv->primary_buffer,
|
|
"notify::scrollback",
|
|
G_CALLBACK (scrollback_changed),
|
|
term);
|
|
g_signal_connect_swapped (term->priv->alternate_buffer,
|
|
"notify::scrollback",
|
|
G_CALLBACK (scrollback_changed),
|
|
term);
|
|
|
|
g_signal_connect_swapped (term->priv->buffer,
|
|
"notify::screen-width",
|
|
G_CALLBACK (width_changed),
|
|
term);
|
|
g_signal_connect_swapped (term->priv->buffer,
|
|
"notify::screen-height",
|
|
G_CALLBACK (height_changed),
|
|
term);
|
|
|
|
g_signal_connect_swapped (term->priv->primary_buffer,
|
|
"changed",
|
|
G_CALLBACK (moo_term_buf_content_changed),
|
|
term);
|
|
g_signal_connect_swapped (term->priv->alternate_buffer,
|
|
"changed",
|
|
G_CALLBACK (moo_term_buf_content_changed),
|
|
term);
|
|
|
|
g_signal_connect_swapped (term->priv->primary_buffer,
|
|
"cursor-moved",
|
|
G_CALLBACK (moo_term_cursor_moved),
|
|
term);
|
|
g_signal_connect_swapped (term->priv->alternate_buffer,
|
|
"cursor-moved",
|
|
G_CALLBACK (moo_term_cursor_moved),
|
|
term);
|
|
|
|
g_signal_connect_swapped (term->priv->primary_buffer,
|
|
"feed-child",
|
|
G_CALLBACK (moo_term_feed_child),
|
|
term);
|
|
g_signal_connect_swapped (term->priv->alternate_buffer,
|
|
"feed-child",
|
|
G_CALLBACK (moo_term_feed_child),
|
|
term);
|
|
}
|
|
|
|
|
|
static void moo_term_finalize (GObject *object)
|
|
{
|
|
guint i, j;
|
|
MooTerm *term = MOO_TERM (object);
|
|
|
|
g_object_unref (term->priv->pt);
|
|
moo_term_parser_free (term->priv->parser);
|
|
|
|
g_object_unref (term->priv->primary_buffer);
|
|
g_object_unref (term->priv->alternate_buffer);
|
|
|
|
term_selection_free (term->priv->selection);
|
|
term_font_info_free (term->priv->font_info);
|
|
|
|
g_array_free (term->priv->saved_cursor, TRUE);
|
|
|
|
g_object_unref (term->priv->back_pixmap);
|
|
|
|
if (term->priv->changed_content)
|
|
gdk_region_destroy (term->priv->changed_content);
|
|
|
|
if (term->priv->pending_expose)
|
|
g_source_remove (term->priv->pending_expose);
|
|
|
|
g_object_unref (term->priv->clip);
|
|
g_object_unref (term->priv->layout);
|
|
|
|
g_object_unref (term->priv->im);
|
|
|
|
if (term->priv->adjustment)
|
|
g_object_unref (term->priv->adjustment);
|
|
|
|
for (i = 0; i < POINTERS_NUM; ++i)
|
|
if (term->priv->pointer[i])
|
|
gdk_cursor_unref (term->priv->pointer[i]);
|
|
|
|
/* TODO TODO TODO */
|
|
for (i = 0; i < 1; ++i)
|
|
for (j = 0; j <= MOO_TERM_COLOR_MAX; ++j)
|
|
{
|
|
g_object_unref (term->priv->fg[i][j]);
|
|
g_object_unref (term->priv->bg[i][j]);
|
|
}
|
|
g_object_unref (term->priv->fg[1][MOO_TERM_COLOR_MAX]);
|
|
g_object_unref (term->priv->bg[1][MOO_TERM_COLOR_MAX]);
|
|
g_object_unref (term->priv->fg[2][MOO_TERM_COLOR_MAX]);
|
|
g_object_unref (term->priv->bg[2][MOO_TERM_COLOR_MAX]);
|
|
|
|
g_free (term->priv);
|
|
G_OBJECT_CLASS (moo_term_parent_class)->finalize (object);
|
|
}
|
|
|
|
|
|
static void moo_term_size_allocate (GtkWidget *widget,
|
|
GtkAllocation *allocation)
|
|
{
|
|
int old_width, old_height;
|
|
MooTerm *term = MOO_TERM (widget);
|
|
|
|
old_width = widget->allocation.width;
|
|
old_height = widget->allocation.height;
|
|
widget->allocation = *allocation;
|
|
|
|
if (GTK_WIDGET_REALIZED (widget))
|
|
{
|
|
gdk_window_move_resize (widget->window,
|
|
allocation->x, allocation->y,
|
|
allocation->width, allocation->height);
|
|
|
|
if (old_width != allocation->width || old_height != allocation->height)
|
|
moo_term_size_changed (term);
|
|
}
|
|
}
|
|
|
|
|
|
static void moo_term_realize (GtkWidget *widget)
|
|
{
|
|
MooTerm *term;
|
|
GdkWindowAttr attributes;
|
|
gint attributes_mask;
|
|
GdkDisplay *display;
|
|
GdkBitmap *empty_bitmap;
|
|
GdkColor useless = {0, 0, 0, 0};
|
|
char invisible_cursor_bits[] = { 0x0 };
|
|
|
|
term = MOO_TERM (widget);
|
|
|
|
empty_bitmap = gdk_bitmap_create_from_data (NULL, invisible_cursor_bits, 1, 1);
|
|
term->priv->pointer[POINTER_NONE] =
|
|
gdk_cursor_new_from_pixmap (empty_bitmap,
|
|
empty_bitmap,
|
|
&useless,
|
|
&useless, 0, 0);
|
|
|
|
display = gtk_widget_get_display (widget);
|
|
term->priv->pointer[POINTER_TEXT] =
|
|
gdk_cursor_new_for_display (display, GDK_XTERM);
|
|
term->priv->pointer[POINTER_NORMAL] = NULL;
|
|
|
|
attributes.window_type = GDK_WINDOW_CHILD;
|
|
attributes.x = widget->allocation.x;
|
|
attributes.y = widget->allocation.y;
|
|
attributes.width = widget->allocation.width;
|
|
attributes.height = widget->allocation.height;
|
|
attributes.wclass = GDK_INPUT_OUTPUT;
|
|
attributes.visual = gtk_widget_get_visual (widget);
|
|
attributes.colormap = gtk_widget_get_colormap (widget);
|
|
attributes.cursor = term->priv->pointer[POINTER_TEXT];
|
|
attributes.event_mask = gtk_widget_get_events (widget) |
|
|
GDK_EXPOSURE_MASK |
|
|
GDK_BUTTON_PRESS_MASK |
|
|
GDK_BUTTON_RELEASE_MASK |
|
|
GDK_POINTER_MOTION_HINT_MASK |
|
|
GDK_POINTER_MOTION_MASK |
|
|
GDK_KEY_PRESS_MASK |
|
|
GDK_KEY_RELEASE_MASK;
|
|
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL |
|
|
GDK_WA_COLORMAP | GDK_WA_CURSOR;
|
|
|
|
GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED | GTK_CAN_FOCUS | GTK_CAN_DEFAULT);
|
|
widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
|
|
&attributes, attributes_mask);
|
|
gdk_window_set_user_data (widget->window, widget);
|
|
|
|
widget->style = gtk_style_attach (widget->style, widget->window);
|
|
|
|
gtk_widget_set_double_buffered (widget, FALSE);
|
|
|
|
moo_term_setup_palette (term);
|
|
moo_term_init_font_stuff (term);
|
|
moo_term_init_back_pixmap (term);
|
|
moo_term_size_changed (term);
|
|
|
|
gdk_window_set_background (widget->window, &(widget->style->white));
|
|
|
|
term->priv->im = gtk_im_multicontext_new ();
|
|
gtk_im_context_set_client_window (term->priv->im, widget->window);
|
|
gtk_im_context_set_use_preedit (term->priv->im, FALSE);
|
|
g_signal_connect (term->priv->im, "commit",
|
|
G_CALLBACK (moo_term_im_commit), term);
|
|
g_signal_connect_swapped (term->priv->im, "preedit-start",
|
|
G_CALLBACK (im_preedit_start), term);
|
|
g_signal_connect_swapped (term->priv->im, "preedit-end",
|
|
G_CALLBACK (im_preedit_end), term);
|
|
gtk_im_context_focus_in (term->priv->im);
|
|
}
|
|
|
|
|
|
static void im_preedit_start (MooTerm *term)
|
|
{
|
|
term->priv->im_preedit_active = TRUE;
|
|
}
|
|
|
|
|
|
static void im_preedit_end (MooTerm *term)
|
|
{
|
|
term->priv->im_preedit_active = FALSE;
|
|
}
|
|
|
|
|
|
static void child_died (MooTerm *term)
|
|
{
|
|
g_signal_emit (term, signals[CHILD_DIED], 0);
|
|
}
|
|
|
|
|
|
static void moo_term_set_scroll_adjustments (GtkWidget *widget,
|
|
G_GNUC_UNUSED GtkAdjustment *hadj,
|
|
GtkAdjustment *vadj)
|
|
{
|
|
moo_term_set_adjustment (MOO_TERM (widget), vadj);
|
|
}
|
|
|
|
|
|
void moo_term_set_adjustment (MooTerm *term,
|
|
GtkAdjustment *vadj)
|
|
{
|
|
if (term->priv->adjustment == vadj)
|
|
return;
|
|
|
|
if (term->priv->adjustment)
|
|
{
|
|
g_signal_handlers_disconnect_by_func (term->priv->adjustment,
|
|
(gpointer) adjustment_value_changed,
|
|
term);
|
|
g_object_unref (term->priv->adjustment);
|
|
}
|
|
|
|
term->priv->adjustment = vadj;
|
|
|
|
if (term->priv->adjustment)
|
|
{
|
|
g_object_ref (term->priv->adjustment);
|
|
gtk_object_sink (GTK_OBJECT (term->priv->adjustment));
|
|
|
|
update_adjustment (term);
|
|
g_signal_connect_swapped (term->priv->adjustment,
|
|
"value-changed",
|
|
G_CALLBACK (adjustment_value_changed),
|
|
term);
|
|
}
|
|
}
|
|
|
|
|
|
static void scrollback_changed (MooTerm *term,
|
|
G_GNUC_UNUSED GParamSpec *pspec,
|
|
MooTermBuffer *buf)
|
|
{
|
|
g_assert (!strcmp (pspec->name, "scrollback"));
|
|
|
|
if (buf == term->priv->buffer)
|
|
{
|
|
guint scrollback = buf_scrollback (term->priv->buffer);
|
|
|
|
if (term->priv->_scrolled && term->priv->_top_line > scrollback)
|
|
scroll_to_bottom (term, TRUE);
|
|
else
|
|
update_adjustment (term);
|
|
}
|
|
}
|
|
|
|
|
|
static void width_changed (MooTerm *term,
|
|
G_GNUC_UNUSED GParamSpec *pspec)
|
|
{
|
|
g_assert (!strcmp (pspec->name, "screen-width"));
|
|
|
|
term->priv->width = buf_screen_width (term->priv->buffer);
|
|
|
|
if (GTK_WIDGET_REALIZED (term))
|
|
moo_term_resize_back_pixmap (term);
|
|
|
|
term_selection_set_width (term, term->priv->width);
|
|
term_selection_clear (term);
|
|
}
|
|
|
|
|
|
static void height_changed (MooTerm *term,
|
|
G_GNUC_UNUSED GParamSpec *pspec)
|
|
{
|
|
guint scrollback = buf_scrollback (term->priv->buffer);
|
|
|
|
g_assert (!strcmp (pspec->name, "screen-height"));
|
|
|
|
term->priv->height = buf_screen_height (term->priv->buffer);
|
|
|
|
if (!term->priv->_scrolled || term->priv->_top_line > scrollback)
|
|
scroll_to_bottom (term, TRUE);
|
|
else
|
|
update_adjustment (term);
|
|
|
|
if (GTK_WIDGET_REALIZED (term))
|
|
moo_term_resize_back_pixmap (term);
|
|
|
|
term_selection_clear (term);
|
|
moo_term_invalidate_all (term);
|
|
}
|
|
|
|
|
|
#define equal(a, b) (ABS((a)-(b)) < 0.4)
|
|
|
|
static void update_adjustment (MooTerm *term)
|
|
{
|
|
double upper, value, page_size;
|
|
GtkAdjustment *adj = term->priv->adjustment;
|
|
gboolean now = FALSE;
|
|
|
|
if (!adj)
|
|
return;
|
|
|
|
upper = buf_total_height (term->priv->buffer);
|
|
value = term_top_line (term);
|
|
page_size = term->priv->height;
|
|
|
|
if ((ABS (upper - term->priv->adjustment->upper) >
|
|
ADJUSTMENT_DELTA * page_size) ||
|
|
(ABS (value - term->priv->adjustment->value) >
|
|
ADJUSTMENT_DELTA * page_size))
|
|
{
|
|
now = TRUE;
|
|
}
|
|
|
|
if (!equal (adj->lower, 0.0) || !equal (adj->upper, upper) ||
|
|
!equal (adj->value, value) || !equal (adj->page_size, page_size) ||
|
|
!equal (adj->page_increment, page_size) || !equal (adj->step_increment, 1.0))
|
|
{
|
|
adj->lower = 0.0;
|
|
adj->upper = upper;
|
|
adj->value = value;
|
|
adj->page_size = page_size;
|
|
adj->page_increment = page_size;
|
|
adj->step_increment = 1.0;
|
|
|
|
queue_adjustment_changed (term, now);
|
|
}
|
|
}
|
|
|
|
|
|
static void update_adjustment_value (MooTerm *term)
|
|
{
|
|
double value = term_top_line (term);
|
|
gboolean now = FALSE;
|
|
|
|
if (!term->priv->adjustment)
|
|
return;
|
|
|
|
if (ABS (value - term->priv->adjustment->value) >
|
|
ADJUSTMENT_DELTA * term->priv->height)
|
|
{
|
|
now = TRUE;
|
|
}
|
|
|
|
if (!equal (term->priv->adjustment->value, value))
|
|
{
|
|
term->priv->adjustment->value = value;
|
|
queue_adjustment_value_changed (term, now);
|
|
}
|
|
}
|
|
|
|
|
|
static void adjustment_value_changed (MooTerm *term)
|
|
{
|
|
guint val, real_val;
|
|
|
|
g_assert (term->priv->adjustment != NULL);
|
|
|
|
val = term->priv->adjustment->value;
|
|
real_val = term_top_line (term);
|
|
|
|
if (val == real_val)
|
|
return;
|
|
|
|
g_return_if_fail (val <= buf_scrollback (term->priv->buffer));
|
|
|
|
scroll_abs (term, val, FALSE);
|
|
}
|
|
|
|
|
|
static void queue_adjustment_changed (MooTerm *term,
|
|
gboolean now)
|
|
{
|
|
if (now)
|
|
{
|
|
if (term->priv->pending_adjustment_changed)
|
|
g_source_remove (term->priv->pending_adjustment_changed);
|
|
term->priv->pending_adjustment_changed = 0;
|
|
emit_adjustment_changed (term);
|
|
}
|
|
else if (!term->priv->pending_adjustment_changed)
|
|
{
|
|
term->priv->pending_adjustment_changed =
|
|
g_idle_add_full (ADJUSTMENT_PRIORITY,
|
|
(GSourceFunc) emit_adjustment_changed,
|
|
term,
|
|
NULL);
|
|
}
|
|
}
|
|
|
|
|
|
static void queue_adjustment_value_changed (MooTerm *term,
|
|
gboolean now)
|
|
{
|
|
if (now)
|
|
{
|
|
if (term->priv->pending_adjustment_value_changed)
|
|
g_source_remove (term->priv->pending_adjustment_value_changed);
|
|
term->priv->pending_adjustment_value_changed = 0;
|
|
emit_adjustment_value_changed (term);
|
|
}
|
|
else if (!term->priv->pending_adjustment_value_changed)
|
|
{
|
|
term->priv->pending_adjustment_value_changed =
|
|
g_idle_add_full(ADJUSTMENT_PRIORITY,
|
|
(GSourceFunc) emit_adjustment_value_changed,
|
|
term,
|
|
NULL);
|
|
}
|
|
}
|
|
|
|
|
|
static gboolean emit_adjustment_changed (MooTerm *term)
|
|
{
|
|
term->priv->pending_adjustment_changed = 0;
|
|
gtk_adjustment_changed (term->priv->adjustment);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static gboolean emit_adjustment_value_changed (MooTerm *term)
|
|
{
|
|
term->priv->pending_adjustment_value_changed = 0;
|
|
gtk_adjustment_value_changed (term->priv->adjustment);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static void scroll_abs (MooTerm *term,
|
|
guint line,
|
|
gboolean update_adj)
|
|
{
|
|
if (term_top_line (term) == line)
|
|
{
|
|
if (update_adj)
|
|
update_adjustment_value (term);
|
|
|
|
return;
|
|
}
|
|
|
|
if (line >= buf_scrollback (term->priv->buffer))
|
|
return scroll_to_bottom (term, update_adj);
|
|
|
|
term->priv->_top_line = line;
|
|
term->priv->_scrolled = TRUE;
|
|
|
|
moo_term_invalidate_content_all (term);
|
|
moo_term_invalidate_all (term);
|
|
|
|
if (update_adj)
|
|
update_adjustment_value (term);
|
|
}
|
|
|
|
|
|
static void scroll_to_bottom (MooTerm *term,
|
|
gboolean update_adj)
|
|
{
|
|
guint scrollback = buf_scrollback (term->priv->buffer);
|
|
gboolean update_full = FALSE;
|
|
|
|
if (!term->priv->_scrolled && term->priv->_top_line <= scrollback)
|
|
{
|
|
if (update_adj)
|
|
update_adjustment_value (term);
|
|
return;
|
|
}
|
|
|
|
if (term->priv->_top_line > scrollback)
|
|
{
|
|
term->priv->_top_line = scrollback;
|
|
update_full = TRUE;
|
|
}
|
|
|
|
term->priv->_scrolled = FALSE;
|
|
|
|
moo_term_invalidate_content_all (term);
|
|
moo_term_invalidate_all (term);
|
|
|
|
if (update_full)
|
|
update_adjustment (term);
|
|
else if (update_adj)
|
|
update_adjustment_value (term);
|
|
}
|
|
|
|
|
|
void moo_term_size_changed (MooTerm *term)
|
|
{
|
|
GtkWidget *widget = GTK_WIDGET (term);
|
|
TermFontInfo *font_info = term->priv->font_info;
|
|
guint width, height;
|
|
guint old_width, old_height;
|
|
|
|
width = widget->allocation.width / font_info->width;
|
|
height = widget->allocation.height / font_info->height;
|
|
old_width = term->priv->width;
|
|
old_height = term->priv->height;
|
|
|
|
if (width == old_width && height == old_height)
|
|
return;
|
|
|
|
moo_term_buffer_set_screen_size (term->priv->primary_buffer,
|
|
width, height);
|
|
moo_term_buffer_set_screen_size (term->priv->alternate_buffer,
|
|
width, height);
|
|
moo_term_pt_set_size (term->priv->pt, width, height);
|
|
}
|
|
|
|
|
|
gboolean moo_term_fork_command (MooTerm *term,
|
|
const char *cmd,
|
|
const char *working_dir,
|
|
char **envp)
|
|
{
|
|
g_return_val_if_fail (MOO_IS_TERM (term), FALSE);
|
|
|
|
return moo_term_pt_fork_command (term->priv->pt,
|
|
cmd, working_dir, envp);
|
|
}
|
|
|
|
|
|
void moo_term_feed_child (MooTerm *term,
|
|
const char *string,
|
|
int len)
|
|
{
|
|
g_return_if_fail (MOO_IS_TERM (term) && string != NULL);
|
|
moo_term_pt_write (term->priv->pt, string, len);
|
|
}
|
|
|
|
|
|
void moo_term_copy_clipboard (MooTerm *term)
|
|
{
|
|
char *text = term_selection_get_text (term);
|
|
|
|
if (text && *text)
|
|
gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
|
|
text, -1);
|
|
|
|
if (text)
|
|
{
|
|
g_assert (*text);
|
|
g_free (text);
|
|
}
|
|
}
|
|
|
|
|
|
void moo_term_ctrl_c (MooTerm *term)
|
|
{
|
|
moo_term_pt_send_intr (term->priv->pt);
|
|
}
|
|
|
|
|
|
void moo_term_paste_clipboard (MooTerm *term)
|
|
{
|
|
GtkClipboard *cb;
|
|
char *text;
|
|
|
|
g_return_if_fail (MOO_IS_TERM (term));
|
|
|
|
cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
|
|
text = gtk_clipboard_wait_for_text (cb);
|
|
|
|
if (text)
|
|
{
|
|
moo_term_pt_write (term->priv->pt, text, -1);
|
|
g_free (text);
|
|
}
|
|
}
|
|
|
|
|
|
void moo_term_feed (MooTerm *term,
|
|
const char *data,
|
|
int len)
|
|
{
|
|
if (!len)
|
|
return;
|
|
|
|
g_return_if_fail (data != NULL);
|
|
|
|
if (len < 0)
|
|
len = strlen (data);
|
|
|
|
moo_term_parser_parse (term->priv->parser, data, len);
|
|
}
|
|
|
|
|
|
void moo_term_scroll_to_top (MooTerm *term)
|
|
{
|
|
scroll_abs (term, 0, TRUE);
|
|
}
|
|
|
|
void moo_term_scroll_to_bottom (MooTerm *term)
|
|
{
|
|
scroll_to_bottom (term, TRUE);
|
|
}
|
|
|
|
void moo_term_scroll_lines (MooTerm *term,
|
|
int lines)
|
|
{
|
|
int top = term_top_line (term);
|
|
|
|
top += lines;
|
|
|
|
if (top < 0)
|
|
top = 0;
|
|
|
|
scroll_abs (term, top, TRUE);
|
|
}
|
|
|
|
void moo_term_scroll_pages (MooTerm *term,
|
|
int pages)
|
|
{
|
|
int top = term_top_line (term);
|
|
|
|
top += pages * term->priv->height;
|
|
|
|
if (top < 0)
|
|
top = 0;
|
|
|
|
scroll_abs (term, top, TRUE);
|
|
}
|
|
|
|
|
|
void moo_term_set_window_title (MooTerm *term,
|
|
const char *title)
|
|
{
|
|
g_signal_emit (term, signals[SET_WINDOW_TITLE], 0, title);
|
|
}
|
|
|
|
|
|
void moo_term_set_icon_name (MooTerm *term,
|
|
const char *title)
|
|
{
|
|
g_signal_emit (term, signals[SET_ICON_NAME], 0, title);
|
|
}
|
|
|
|
|
|
void moo_term_bell (MooTerm *term)
|
|
{
|
|
g_signal_emit (term, signals[BELL], 0);
|
|
}
|
|
|
|
|
|
void moo_term_decid (MooTerm *term)
|
|
{
|
|
moo_term_feed_child (term, TERM_VT_DECID_STRING, -1);
|
|
}
|
|
|
|
|
|
void moo_term_set_dec_modes (MooTerm *term,
|
|
int *modes,
|
|
guint n_modes,
|
|
gboolean set)
|
|
{
|
|
guint i;
|
|
|
|
g_return_if_fail (n_modes != 0); /* ??? */
|
|
|
|
for (i = 0; i < n_modes; ++i)
|
|
{
|
|
int mode = -1;
|
|
|
|
switch (modes[i])
|
|
{
|
|
case 47:
|
|
moo_term_set_alternate_buffer (term, set);
|
|
break;
|
|
|
|
default:
|
|
GET_DEC_MODE (modes[i], mode);
|
|
|
|
if (mode >= 0)
|
|
moo_term_set_mode (term, mode, set);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void moo_term_save_dec_modes (MooTerm *term,
|
|
int *modes,
|
|
guint n_modes)
|
|
{
|
|
guint i;
|
|
|
|
g_return_if_fail (n_modes != 0); /* ??? */
|
|
|
|
for (i = 0; i < n_modes; ++i)
|
|
{
|
|
int mode = -1;
|
|
|
|
GET_DEC_MODE (modes[i], mode);
|
|
|
|
if (mode >= 0)
|
|
term->priv->saved_modes[mode] = term->priv->modes[mode];
|
|
}
|
|
}
|
|
|
|
|
|
void moo_term_restore_dec_modes (MooTerm *term,
|
|
int *modes,
|
|
guint n_modes)
|
|
{
|
|
guint i;
|
|
|
|
g_return_if_fail (n_modes != 0); /* ??? */
|
|
|
|
for (i = 0; i < n_modes; ++i)
|
|
{
|
|
int mode = -1;
|
|
|
|
GET_DEC_MODE (modes[i], mode);
|
|
|
|
if (mode >= 0)
|
|
moo_term_set_mode (term, mode, term->priv->saved_modes[mode]);
|
|
}
|
|
}
|
|
|
|
|
|
void moo_term_set_ansi_modes (MooTerm *term,
|
|
int *modes,
|
|
guint n_modes,
|
|
gboolean set)
|
|
{
|
|
guint i;
|
|
|
|
g_return_if_fail (n_modes != 0); /* ??? */
|
|
|
|
for (i = 0; i < n_modes; ++i)
|
|
{
|
|
int mode = -1;
|
|
|
|
GET_ANSI_MODE (modes[i], mode);
|
|
|
|
if (mode >= 0)
|
|
moo_term_set_mode (term, mode, set);
|
|
}
|
|
}
|
|
|
|
|
|
void moo_term_set_mode (MooTerm *term,
|
|
int mode,
|
|
gboolean set)
|
|
{
|
|
#if 1
|
|
switch (mode)
|
|
{
|
|
case MODE_DECSCNM:
|
|
g_message ("set MODE_DECSCNM %s", set ? "TRUE" : "FALSE");
|
|
break;
|
|
#if 0
|
|
case MODE_DECTCEM:
|
|
g_message ("set MODE_DECTCEM %s", set ? "TRUE" : "FALSE");
|
|
break;
|
|
#endif
|
|
case MODE_CA:
|
|
g_message ("set MODE_CA %s", set ? "TRUE" : "FALSE");
|
|
break;
|
|
case MODE_REVERSE_WRAPAROUND:
|
|
g_message ("set MODE_REVERSE_WRAPAROUND %s", set ? "TRUE" : "FALSE");
|
|
break;
|
|
case MODE_PRESS_TRACKING:
|
|
g_message ("set MODE_PRESS_TRACKING %s", set ? "TRUE" : "FALSE");
|
|
break;
|
|
case MODE_PRESS_AND_RELEASE_TRACKING:
|
|
g_message ("set MODE_PRESS_AND_RELEASE_TRACKING %s", set ? "TRUE" : "FALSE");
|
|
break;
|
|
case MODE_HILITE_MOUSE_TRACKING:
|
|
g_message ("set MODE_HILITE_MOUSE_TRACKING %s", set ? "TRUE" : "FALSE");
|
|
break;
|
|
case MODE_SRM:
|
|
g_message ("set MODE_SRM %s", set ? "TRUE" : "FALSE");
|
|
break;
|
|
case MODE_LNM:
|
|
g_message ("set MODE_LNM %s", set ? "TRUE" : "FALSE");
|
|
break;
|
|
#if 0
|
|
case MODE_DECNKM:
|
|
g_message ("set MODE_DECNKM %s", set ? "TRUE" : "FALSE");
|
|
break;
|
|
case MODE_DECCKM:
|
|
g_message ("set MODE_DECCKM %s", set ? "TRUE" : "FALSE");
|
|
break;
|
|
#endif
|
|
case MODE_DECANM:
|
|
g_message ("set MODE_DECANM %s", set ? "TRUE" : "FALSE");
|
|
break;
|
|
case MODE_DECBKM:
|
|
g_message ("set MODE_DECBKM %s", set ? "TRUE" : "FALSE");
|
|
break;
|
|
case MODE_DECKPM:
|
|
g_message ("set MODE_DECKPM %s", set ? "TRUE" : "FALSE");
|
|
break;
|
|
case MODE_IRM:
|
|
g_message ("set MODE_IRM %s", set ? "TRUE" : "FALSE");
|
|
break;
|
|
case MODE_DECOM:
|
|
g_message ("set MODE_DECOM %s", set ? "TRUE" : "FALSE");
|
|
break;
|
|
case MODE_DECAWM:
|
|
g_message ("set MODE_DECAWM %s", set ? "TRUE" : "FALSE");
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
switch (mode)
|
|
{
|
|
case MODE_DECSCNM:
|
|
term->priv->modes[mode] = set;
|
|
moo_term_buffer_set_mode (term->priv->buffer, mode, set);
|
|
moo_term_invert_colors (term, set);
|
|
break;
|
|
|
|
case MODE_DECTCEM:
|
|
term->priv->modes[mode] = set;
|
|
moo_term_buffer_set_mode (term->priv->buffer, mode, set);
|
|
moo_term_set_cursor_visible (term, set);
|
|
break;
|
|
|
|
case MODE_CA:
|
|
term->priv->modes[mode] = set;
|
|
moo_term_buffer_set_mode (term->priv->buffer, mode, set);
|
|
moo_term_set_ca_mode (term, set);
|
|
break;
|
|
|
|
case MODE_PRESS_TRACKING:
|
|
case MODE_PRESS_AND_RELEASE_TRACKING:
|
|
case MODE_HILITE_MOUSE_TRACKING:
|
|
if (set)
|
|
moo_term_set_mouse_tracking (term, mode);
|
|
else
|
|
moo_term_set_mouse_tracking (term, -1);
|
|
term->priv->modes[mode] = set;
|
|
moo_term_buffer_set_mode (term->priv->buffer, mode, set);
|
|
break;
|
|
|
|
/* these do not require anything special, just record the value */
|
|
case MODE_SRM:
|
|
case MODE_LNM:
|
|
case MODE_DECNKM:
|
|
case MODE_DECCKM:
|
|
case MODE_DECANM:
|
|
case MODE_DECBKM:
|
|
case MODE_DECKPM:
|
|
case MODE_REVERSE_WRAPAROUND:
|
|
term->priv->modes[mode] = set;
|
|
moo_term_buffer_set_mode (term->priv->buffer, mode, set);
|
|
break;
|
|
|
|
/* these are ignored */
|
|
case MODE_IRM:
|
|
case MODE_DECOM:
|
|
case MODE_DECAWM:
|
|
term->priv->modes[mode] = set;
|
|
moo_term_buffer_set_mode (term->priv->buffer, mode, set);
|
|
break;
|
|
|
|
default:
|
|
g_warning ("%s: unknown mode %d", G_STRFUNC, mode);
|
|
}
|
|
}
|
|
|
|
|
|
static void save_cursor (MooTerm *term)
|
|
{
|
|
g_array_append_val (term->priv->saved_cursor,
|
|
term->priv->cursor_row);
|
|
g_array_append_val (term->priv->saved_cursor,
|
|
term->priv->cursor_col);
|
|
}
|
|
|
|
static void restore_cursor (MooTerm *term)
|
|
{
|
|
guint row = 0;
|
|
guint col = 0;
|
|
|
|
if (term->priv->saved_cursor->len)
|
|
{
|
|
row = g_array_index (term->priv->saved_cursor, guint,
|
|
term->priv->saved_cursor->len - 2);
|
|
col = g_array_index (term->priv->saved_cursor, guint,
|
|
term->priv->saved_cursor->len - 1);
|
|
g_array_set_size (term->priv->saved_cursor,
|
|
term->priv->saved_cursor->len - 2);
|
|
}
|
|
|
|
moo_term_buffer_cursor_move_to (term->priv->buffer, row, col);
|
|
}
|
|
|
|
|
|
void moo_term_set_ca_mode (MooTerm *term,
|
|
gboolean set)
|
|
{
|
|
if (set)
|
|
{
|
|
save_cursor (term);
|
|
moo_term_set_alternate_buffer (term, TRUE);
|
|
moo_term_buffer_erase_in_display (term->priv->buffer, 2);
|
|
moo_term_buffer_set_ca_mode (term->priv->buffer, TRUE);
|
|
}
|
|
else
|
|
{
|
|
moo_term_set_alternate_buffer (term, FALSE);
|
|
moo_term_buffer_set_ca_mode (term->priv->buffer, FALSE);
|
|
restore_cursor (term);
|
|
}
|
|
}
|
|
|
|
|
|
void moo_term_set_alternate_buffer (MooTerm *term,
|
|
gboolean alternate)
|
|
{
|
|
g_message ("set alternate buffer %s", alternate ? "TRUE" : "FALSE");
|
|
|
|
if ((alternate && term->priv->buffer == term->priv->alternate_buffer) ||
|
|
(!alternate && term->priv->buffer == term->priv->primary_buffer))
|
|
return;
|
|
|
|
if (alternate)
|
|
term->priv->buffer = term->priv->alternate_buffer;
|
|
else
|
|
term->priv->buffer = term->priv->primary_buffer;
|
|
|
|
moo_term_invalidate_content_all (term);
|
|
moo_term_invalidate_all (term);
|
|
moo_term_buffer_scrollback_changed (term->priv->buffer);
|
|
}
|
|
|
|
|
|
void moo_term_da1 (MooTerm *term)
|
|
{
|
|
moo_term_feed_child (term, "\033[?64;1;c", -1);
|
|
|
|
/*
|
|
1 132 columns
|
|
2 Printer port
|
|
4 Sixel
|
|
6 Selective erase
|
|
7 Soft character set (DRCS) TODO
|
|
8 User-defined keys (UDKs) TODO
|
|
9 National replacement character sets (NRCS)
|
|
(International terminal only) TODO
|
|
12 Yugoslavian (SCS)
|
|
15 Technical character set TODO
|
|
18 Windowing capability TODO
|
|
21 Horizontal scrolling TODO
|
|
23 Greek
|
|
24 Turkish
|
|
42 ISO Latin-2 character set
|
|
44 PCTerm TODO
|
|
45 Soft key map TODO
|
|
46 ASCII emulation TODO
|
|
*/
|
|
}
|
|
|
|
void moo_term_da2 (MooTerm *term)
|
|
{
|
|
/* TODO */
|
|
moo_term_feed_child (term, "\033[>61;20;1;c", -1);
|
|
}
|
|
|
|
void moo_term_da3 (MooTerm *term)
|
|
{
|
|
/* TODO */
|
|
moo_term_feed_child (term, "\033P!|FFFFFFFF\033\\", -1);
|
|
}
|
|
|
|
|
|
#define make_DECRQSS(c) \
|
|
answer = g_strdup_printf ("\033P%s$r" FINAL_##c "\033\\", ps)
|
|
|
|
void moo_term_setting_request (MooTerm *term,
|
|
int setting)
|
|
{
|
|
DECRQSSCode code = setting;
|
|
char *ps = NULL, *answer = NULL;
|
|
|
|
switch (code)
|
|
{
|
|
case CODE_DECSASD: /* Select Active Status Display*/
|
|
ps = g_strdup ("0");
|
|
make_DECRQSS (DECSASD);
|
|
break;
|
|
case CODE_DECSCL: /* Set Conformance Level */
|
|
ps = g_strdup ("61");
|
|
make_DECRQSS (DECSCL);
|
|
break;
|
|
case CODE_DECSCPP: /* Set Columns Per Page */
|
|
ps = g_strdup_printf ("%d", term->priv->width);
|
|
make_DECRQSS (DECSCPP);
|
|
break;
|
|
case CODE_DECSLPP: /* Set Lines Per Page */
|
|
ps = g_strdup_printf ("%d", term->priv->height);
|
|
make_DECRQSS (DECSLPP);
|
|
break;
|
|
case CODE_DECSNLS: /* Set Number of Lines per Screen */
|
|
ps = g_strdup_printf ("%d", term->priv->height);
|
|
make_DECRQSS (DECSNLS);
|
|
break;
|
|
case CODE_DECSTBM: /* Set Top and Bottom Margins */
|
|
ps = g_strdup_printf ("%d;%d",
|
|
term->priv->buffer->priv->top_margin + 1,
|
|
term->priv->buffer->priv->bottom_margin + 1);
|
|
make_DECRQSS (DECSTBM);
|
|
break;
|
|
}
|
|
|
|
moo_term_feed_child (term, answer, -1);
|
|
g_free (answer);
|
|
g_free (ps);
|
|
}
|
|
|
|
|
|
void moo_term_reset (MooTerm *term)
|
|
{
|
|
moo_term_buffer_freeze_changed_notify (term->priv->primary_buffer);
|
|
moo_term_buffer_freeze_cursor_notify (term->priv->primary_buffer);
|
|
|
|
term->priv->buffer = term->priv->primary_buffer;
|
|
moo_term_buffer_reset (term->priv->primary_buffer);
|
|
moo_term_buffer_reset (term->priv->alternate_buffer);
|
|
set_default_modes (term->priv->modes);
|
|
set_default_modes (term->priv->saved_modes);
|
|
|
|
moo_term_buffer_thaw_changed_notify (term->priv->primary_buffer);
|
|
moo_term_buffer_thaw_cursor_notify (term->priv->primary_buffer);
|
|
moo_term_buffer_changed (term->priv->primary_buffer);
|
|
moo_term_buffer_cursor_moved (term->priv->primary_buffer);
|
|
}
|
|
|
|
|
|
void moo_term_soft_reset (MooTerm *term)
|
|
{
|
|
moo_term_buffer_freeze_changed_notify (term->priv->buffer);
|
|
moo_term_buffer_freeze_cursor_notify (term->priv->buffer);
|
|
|
|
moo_term_buffer_soft_reset (term->priv->buffer);
|
|
set_default_modes (term->priv->modes);
|
|
set_default_modes (term->priv->saved_modes);
|
|
|
|
moo_term_buffer_thaw_changed_notify (term->priv->primary_buffer);
|
|
moo_term_buffer_thaw_cursor_notify (term->priv->primary_buffer);
|
|
moo_term_buffer_changed (term->priv->primary_buffer);
|
|
moo_term_buffer_cursor_moved (term->priv->primary_buffer);
|
|
}
|
|
|
|
|
|
void moo_term_dsr (MooTerm *term,
|
|
int type,
|
|
int arg,
|
|
gboolean extended)
|
|
{
|
|
char *answer = NULL;
|
|
MooTermBuffer *buf = term->priv->buffer;
|
|
|
|
switch (type)
|
|
{
|
|
case 6:
|
|
if (extended)
|
|
answer = g_strdup_printf ("\233%d;%d;0R",
|
|
buf_cursor_row (buf) + 1,
|
|
buf_cursor_col (buf) + 1);
|
|
else
|
|
answer = g_strdup_printf ("\233%d;%dR",
|
|
buf_cursor_row (buf) + 1,
|
|
buf_cursor_col (buf) + 1);
|
|
break;
|
|
|
|
break;
|
|
case 75:
|
|
answer = g_strdup ("\233?70n");
|
|
break;
|
|
case 26:
|
|
answer = g_strdup ("\233?27;1;0;5n");
|
|
break;
|
|
case 62:
|
|
answer = g_strdup ("\2330*{");
|
|
break;
|
|
case 63:
|
|
if (arg > 0)
|
|
answer = g_strdup_printf ("\220%d!~30303030\234", arg);
|
|
else
|
|
answer = g_strdup ("\220!~30303030\234");
|
|
break;
|
|
case 5:
|
|
answer = g_strdup ("\2330n");
|
|
break;
|
|
case 15:
|
|
answer = g_strdup ("\233?13n");
|
|
break;
|
|
case 25:
|
|
answer = g_strdup ("\233?21n");
|
|
break;
|
|
|
|
default:
|
|
g_warning ("%s: unknown request", G_STRFUNC);
|
|
}
|
|
|
|
if (answer)
|
|
{
|
|
moo_term_feed_child (term, answer, -1);
|
|
g_free (answer);
|
|
}
|
|
}
|
|
|
|
|
|
void moo_term_update_pointer (MooTerm *term)
|
|
{
|
|
if (term->priv->pointer_visible)
|
|
{
|
|
if (term->priv->tracking_mouse)
|
|
gdk_window_set_cursor (GTK_WIDGET(term)->window,
|
|
term->priv->pointer[POINTER_NORMAL]);
|
|
else
|
|
gdk_window_set_cursor (GTK_WIDGET(term)->window,
|
|
term->priv->pointer[POINTER_TEXT]);
|
|
}
|
|
else
|
|
{
|
|
gdk_window_set_cursor (GTK_WIDGET(term)->window,
|
|
term->priv->pointer[POINTER_NONE]);
|
|
}
|
|
}
|
|
|
|
|
|
void moo_term_set_pointer_visible (MooTerm *term,
|
|
gboolean visible)
|
|
{
|
|
g_return_if_fail (GTK_WIDGET_REALIZED (term));
|
|
|
|
if (visible != term->priv->pointer_visible)
|
|
{
|
|
term->priv->pointer_visible = visible;
|
|
moo_term_update_pointer (term);
|
|
}
|
|
}
|
|
|
|
|
|
static gboolean moo_term_popup_menu (GtkWidget *widget)
|
|
{
|
|
moo_term_do_popup_menu (MOO_TERM (widget), NULL);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static void menu_position_func (G_GNUC_UNUSED GtkMenu *menu,
|
|
gint *px,
|
|
gint *py,
|
|
gboolean *push_in,
|
|
MooTerm *term)
|
|
{
|
|
guint cursor_row, cursor_col;
|
|
GdkWindow *window;
|
|
|
|
window = GTK_WIDGET(term)->window;
|
|
gdk_window_get_origin (window, px, py);
|
|
|
|
cursor_col = buf_cursor_col (term->priv->buffer);
|
|
cursor_row = buf_cursor_row (term->priv->buffer);
|
|
cursor_row += buf_scrollback (term->priv->buffer);
|
|
|
|
if (cursor_row >= term_top_line (term))
|
|
{
|
|
cursor_row -= term_top_line (term);
|
|
*px += (cursor_col + 1) * term_char_width (term);
|
|
*py += (cursor_row + 1) * term_char_height (term);
|
|
}
|
|
else
|
|
{
|
|
int x, y, width, height;
|
|
GdkModifierType mask;
|
|
gdk_window_get_pointer (window, &x, &y, &mask);
|
|
gdk_drawable_get_size (GDK_DRAWABLE (window), &width, &height);
|
|
*px += CLAMP (x, 2, width - 2);
|
|
*py += CLAMP (x, 2, height - 2);
|
|
}
|
|
|
|
*push_in = TRUE;
|
|
}
|
|
|
|
|
|
void moo_term_do_popup_menu (MooTerm *term,
|
|
GdkEventButton *event)
|
|
{
|
|
GtkWidget *menu;
|
|
|
|
menu = gtk_menu_new ();
|
|
g_signal_connect (menu, "deactivate",
|
|
G_CALLBACK (gtk_widget_destroy), NULL);
|
|
|
|
/* TODO: add copy/paste */
|
|
g_signal_emit (term, signals[POPULATE_POPUP], 0, menu);
|
|
|
|
if (event)
|
|
gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
|
|
event->button, event->time);
|
|
else
|
|
gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
|
|
(GtkMenuPositionFunc) menu_position_func,
|
|
term, 0, gtk_get_current_event_time ());
|
|
}
|
|
|
|
|
|
static gboolean moo_term_scroll (GtkWidget *widget,
|
|
GdkEventScroll *event)
|
|
{
|
|
switch (event->direction)
|
|
{
|
|
case GDK_SCROLL_UP:
|
|
moo_term_scroll_lines (MOO_TERM (widget), -SCROLL_GRANULARITY);
|
|
return TRUE;
|
|
|
|
case GDK_SCROLL_DOWN:
|
|
moo_term_scroll_lines (MOO_TERM (widget), SCROLL_GRANULARITY);
|
|
return TRUE;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|