/*************************************************************************
*
* GTK Euler : the notebook widget
*
*************************************************************************/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <gdk/gdkkeysyms.h>
#include "term.h"
#include "sysdep.h"
#include "stack.h"
#include "builtin.h"
#include "command.h"
#include "edit.h"
#include "rc.h"
#define TERM_MINWIDTH_DEFAULT 80
#define TERM_MINHEIGHT_DEFAULT 24
int linelength = E_TWIDTH_DEFAULT;
static char deadkey; /* for deadkey handling (^ and ¨) */
#define PADDING 2
enum {
GTK_TERM_CHANGED,
GTK_TERM_SAVED,
GTK_TERM_EDITING,
GTK_TERM_INTERPRETING,
LAST_SIGNAL
};
static guint gtk_term_signals[LAST_SIGNAL] = {0,0,0,0};
static GtkWidgetClass *parent_class = NULL;
static void gtk_term_class_init (GtkTermClass *klass);
static void gtk_term_init (GtkTerm *term);
/* GtkObject and GtkWidget virtual methods */
static void gtk_term_destroy (GtkObject *object);
static void gtk_term_realize (GtkWidget *widget);
static void gtk_term_unrealize (GtkWidget *widget);
static void gtk_term_size_request (GtkWidget *widget, GtkRequisition *requisition);
static void gtk_term_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
static gint gtk_term_expose (GtkWidget *widget, GdkEventExpose *event);
static void gtk_term_map (GtkWidget *widget);
static gint gtk_term_focus_in(GtkWidget *widget, GdkEventFocus *event);
static gint gtk_term_focus_out(GtkWidget *widget, GdkEventFocus *event);
static gint gtk_term_key_press (GtkWidget *widget, GdkEventKey *event);
static gint gtk_term_button_press (GtkWidget *widget, GdkEventButton *event);
static gint gtk_term_button_release (GtkWidget *widget, GdkEventButton *event);
static gint gtk_term_motion_notify (GtkWidget *widget, GdkEventMotion *event);
static gint gtk_term_selection_clear(GtkWidget *widget, GdkEventSelection *event);
static void gtk_term_selection_get(GtkWidget *widget, GtkSelectionData *selection_data, guint info, guint time);
static void gtk_term_selection_received(GtkWidget *widget, GtkSelectionData *selection_data, guint time);
/* private methods */
static void gtk_term_adjustment_safe_set_value(GtkTerm *term, gfloat value);
static void gtk_term_scrollbar_moved (GtkAdjustment *adj, GtkWidget *widget);
static void gtk_term_scroll(GtkWidget* widget, GdkEventScroll* event, gpointer user_data);
static void gtk_term_cursor_up(GtkTerm *term);
static void gtk_term_cursor_down(GtkTerm *term);
static void gtk_term_update_caret(GtkTerm *term);
static gint gtk_term_blink_caret(gpointer data);
static void gtk_term_draw_caret(GtkTerm *term, guint state);
static void gtk_term_scroll_to_pos(GtkTerm *term);
static void gtk_term_draw_text(GtkTerm *term);
static void gtk_term_redraw_current(GtkTerm *term);
static void gtk_term_redraw_below(GtkTerm *term, int index);
GType gtk_term_get_type()
{
static GType term_type = 0;
if (!term_type)
{
GTypeInfo term_info =
{
sizeof (GtkTermClass),
NULL,
NULL,
(GClassInitFunc) gtk_term_class_init,
NULL,
NULL,
sizeof (GtkTerm),
0,
(GInstanceInitFunc) gtk_term_init
};
term_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkTerm",
&term_info, 0);
}
return term_type;
}
/*
* init of new signals and virtual methods
*/
static void gtk_term_class_init(GtkTermClass *klass)
{
GtkObjectClass *object_class = (GtkObjectClass*)klass;
GtkWidgetClass *widget_class = (GtkWidgetClass*)klass;
/*
* save a copy of parent class structure to keep access to
* its methods
*/
parent_class = gtk_type_class (gtk_widget_get_type ());
/*
* define new signals
*/
gtk_term_signals[GTK_TERM_CHANGED] = g_signal_new ("term_changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTermClass, changed),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
gtk_term_signals[GTK_TERM_SAVED] = g_signal_new ("term_saved",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTermClass, saved),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
gtk_term_signals[GTK_TERM_EDITING] = g_signal_new("term_editing",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTermClass, editing),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
gtk_term_signals[GTK_TERM_INTERPRETING] = g_signal_new("term_interpreting",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTermClass, interpreting),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/*
* define virtual methods
*/
object_class->destroy = gtk_term_destroy;
widget_class->realize = gtk_term_realize;
widget_class->unrealize = gtk_term_unrealize;
widget_class->size_request = gtk_term_size_request;
widget_class->size_allocate = gtk_term_size_allocate;
widget_class->expose_event = gtk_term_expose;
widget_class->map = gtk_term_map;
widget_class->button_press_event = gtk_term_button_press;
widget_class->button_release_event = gtk_term_button_release;
widget_class->motion_notify_event = gtk_term_motion_notify;
widget_class->focus_in_event = gtk_term_focus_in;
widget_class->focus_out_event = gtk_term_focus_out;
widget_class->key_press_event = gtk_term_key_press;
widget_class->selection_clear_event = gtk_term_selection_clear;
widget_class->selection_received = gtk_term_selection_received;
widget_class->selection_get = gtk_term_selection_get;
}
/*
* init of object parameters, create subwidgets
*/
static void gtk_term_init(GtkTerm *term)
{
GTK_WIDGET_SET_FLAGS(term, GTK_CAN_FOCUS);
term->name = g_string_new("");
term->a = e_new();
e_append(term->a,"",E_OUTPUT);
term->top = term->cur = term->pos = term->epos = 0;
term->promptlen = 1;
term->xoff = 0;
term->xcaret = term->ycaret = 0;
term->twidth = 0;
term->theight = 0;
term->tfont = g_string_new("");
term->font = NULL;
term->cwidth = 0;
term->cheight = 0;
term->cursor = NULL;
term->scan = 0;
term->code = 0;
term->commentGC = term->outputGC = term->promptGC = term->udfGC = term->highlightGC = NULL;
/* scrollbar set up */
term->v_adj = GTK_ADJUSTMENT(gtk_adjustment_new (0.0, 0.0, 0.0, 1.0, (gfloat)term->theight -1.0, (gfloat)term->theight));
gtk_object_ref ((gpointer)(term->v_adj));
gtk_object_sink (GTK_OBJECT (term->v_adj));
g_signal_connect ((gpointer) (term->v_adj),"value_changed",
G_CALLBACK (gtk_term_scrollbar_moved),term);
g_signal_connect ((gpointer) (term), "scroll_event",
G_CALLBACK (gtk_term_scroll), NULL);
/* caret timer */
term->timeout_id = -1;
term->caret_blink_state = 0;
/* command history set up */
term->history = e_new();
e_append(term->history,"",0);
term->max_history = 32;
term->hist = 0;
/* clipboard */
term->clipboard = g_string_new("");
/* flags */
term->editing = 0;
term->initializing = 1;
term->selecting = 0;
term->changed = 0;
term->menu = NULL;
gtk_selection_add_target(GTK_WIDGET(term),GDK_SELECTION_PRIMARY,GDK_SELECTION_TYPE_STRING,1);
}
/************************************************************************
* PUBLIC INTERFACE
************************************************************************/
/*
* create a term widget with cols columns and rows rows
*/
GtkWidget* gtk_term_new(guint cols, guint rows, char *font)
{
GtkTerm *term = gtk_type_new (gtk_term_get_type ());
g_string_assign(term->tfont,font);
term->twidth = cols;
term->theight = rows;
return GTK_WIDGET (term);
}
/*
* load a notebook
*/
gint gtk_term_load(GtkWidget *widget, gchar *filename)
{
GtkTerm * term;
int i;
g_return_val_if_fail (widget != NULL,0);
g_return_val_if_fail (GTK_IS_TERM (widget),0);
term = GTK_TERM (widget);
if (!e_load(term->a,filename)) return 0;
term->v_adj->value = 0.0;
term->v_adj->lower = 0.0;
term->v_adj->upper = (gfloat)(e_get_length(term->a));
term->v_adj->step_increment = 1.0;
term->v_adj->page_increment = (gfloat)(term->theight-1);
term->v_adj->page_size = (gfloat)term->theight;
gtk_adjustment_changed(term->v_adj);
term->top = 0;
/* find out for the first command */
for (i=0 ; i<e_get_length(term->a) ; i++)
if (e_get_type(term->a,i)==E_PROMPT) {
term->cur = i;
term->pos = term->epos = term->promptlen;
term->xoff = 0;
gtk_term_update_caret(term);
break;
}
gdk_window_clear(term->text);
gtk_term_draw_text(term);
g_string_assign(term->name,filename);
term->changed = 0;
g_signal_emit(GTK_OBJECT(term),gtk_term_signals[GTK_TERM_SAVED],0);
return 1;
}
/*
* save the terminal to a notebook
*/
gint gtk_term_save(GtkWidget *widget, gchar *filename)
{
GtkTerm *term;
gchar *file;
g_return_val_if_fail (widget != NULL,0);
g_return_val_if_fail (GTK_IS_TERM (widget),0);
term = GTK_TERM (widget);
if (filename)
file = filename;
else
file = term->name->str;
if (!e_save(term->a,file)) return 0;
if (filename) g_string_assign(term->name,filename);
term->changed = 0;
g_signal_emit(GTK_OBJECT(term),gtk_term_signals[GTK_TERM_SAVED],0);
return 1;
}
/*
* clear the terminal
*/
void gtk_term_clear(GtkWidget *widget)
{
GtkTerm *term;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
term = GTK_TERM (widget);
e_clear(term->a);
e_append(term->a,"",0);
term->cur = term->top = 0;
term->v_adj->value = 0.0;
term->v_adj->lower = 0.0;
term->v_adj->upper = (gfloat)(e_get_length(term->a));
term->v_adj->step_increment = 1.0;
term->v_adj->page_increment = (gfloat)(term->theight-1);
term->v_adj->page_size = (gfloat)term->theight;
gtk_adjustment_changed(term->v_adj);
gdk_window_clear(term->text);
if (!term->changed) {
g_signal_emit(GTK_OBJECT(term),gtk_term_signals[GTK_TERM_CHANGED],0);
term->changed = 1;
}
}
void gtk_term_clear_new(GtkWidget *widget)
{
GtkTerm *term;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
term = GTK_TERM (widget);
gtk_term_draw_caret(term,0);
e_clear(term->a);
e_append(term->a,">",E_PROMPT);
term->cur = term->top = 0;
term->pos = term->epos = term->promptlen;
gtk_term_update_caret(term);
term->v_adj->value = 0.0;
term->v_adj->lower = 0.0;
term->v_adj->upper = (gfloat)(e_get_length(term->a));
term->v_adj->step_increment = 1.0;
term->v_adj->page_increment = (gfloat)(term->theight-1);
term->v_adj->page_size = (gfloat)term->theight;
gtk_adjustment_changed(term->v_adj);
gdk_window_clear(term->text);
gtk_term_draw_text(term);
term->changed = 0;
g_string_assign(term->name,"");
g_signal_emit(GTK_OBJECT(term),gtk_term_signals[GTK_TERM_SAVED],0);
gtk_term_draw_caret(term,1);
}
/* gtk_term_copy
* copy the current selection to the clipboard
*/
void gtk_term_copy(GtkWidget *widget)
{
GtkTerm *term;
gchar *s;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
term = GTK_TERM (widget);
if (term->epos!=term->pos) {
if(gtk_selection_owner_set(widget,GDK_SELECTION_PRIMARY,GDK_CURRENT_TIME)){
if (term->epos>term->pos)
s = g_strndup(&((e_get_text(term->a,term->cur))[term->pos]),term->epos-term->pos);
else
s = g_strndup(&((e_get_text(term->a,term->cur))[term->epos]),term->pos-term->epos);
g_string_assign(term->clipboard,s);
g_free(s);
} else {
g_print("euler could not own the selection");
}
}
//else g_string_assign(term->clipboard,"");
}
/* gtk_term_cut
* cut the current selection to the clipboard
*/
void gtk_term_cut(GtkWidget *widget)
{
GtkTerm *term;
gchar *s;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
term = GTK_TERM (widget);
if (term->epos!=term->pos) {
if(gtk_selection_owner_set(widget,GDK_SELECTION_PRIMARY,GDK_CURRENT_TIME)) {
if (term->epos>term->pos) {
s = g_strndup(&((e_get_text(term->a,term->cur))[term->pos]),term->epos-term->pos);
e_remove_text(term->a,term->cur,term->pos,term->epos-term->pos);
term->epos = term->pos;
} else {
s = g_strndup(&((e_get_text(term->a,term->cur))[term->epos]),term->pos-term->epos);
e_remove_text(term->a,term->cur,term->epos,term->pos-term->epos);
term->pos = term->epos;
}
g_string_assign(term->clipboard,s);
g_free(s);
gtk_term_update_caret(term);
gtk_term_scroll_to_pos(term);
if (!term->changed) {
g_signal_emit(GTK_OBJECT(term),gtk_term_signals[GTK_TERM_CHANGED],0);
term->changed = 1;
}
} else {
g_print("euler could not own the selection\n");
}
}
}
/* gtk_term_paste
* paste the clipboard content to the current line
*/
void gtk_term_paste(GtkWidget *widget)
{
GtkTerm *term;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
term = GTK_TERM (widget);
gtk_selection_convert(widget,GDK_SELECTION_PRIMARY,GDK_TARGET_STRING,GDK_CURRENT_TIME);
}
gchar * gtk_term_get_comment(GtkWidget *widget)
{
GtkTerm *term;
gchar *buffer, *next;
int k, i, buffersize = 0;
g_return_val_if_fail (widget != NULL,0);
g_return_val_if_fail (GTK_IS_TERM (widget),0);
term = GTK_TERM (widget);
/* calculate the size of the comment */
k=term->cur;
while (k-1>=0 && e_get_type(term->a,k-1)==E_COMMENT) {
k--;
buffersize += e_get_text_length(term->a,k)-1;
}
if (!buffersize) return NULL;
next = buffer = g_malloc(buffersize);
for (i=k;e_get_type(term->a,i)==E_COMMENT;i++) {
strcpy(next,e_get_text(term->a,i)+2);
next += e_get_text_length(term->a,i)-1;
*(next-1)='\n';
}
*(next-1)=0;
return buffer;
}
void gtk_term_set_comment(GtkWidget *widget, gchar *cmt)
{
GtkTerm *term;
char *s = cmt;
int old_cur, dy;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
term = GTK_TERM (widget);
gtk_term_draw_caret(term,0);
/* delete the current comment */
while (term->cur-1>=0 && e_get_type(term->a,term->cur-1)==E_COMMENT) {
e_remove(term->a,term->cur-1);
term->cur--;
}
old_cur=term->cur;
/* insert the new one if any */
if (strlen(cmt)) {
e_insert(term->a,term->cur,"% ",E_COMMENT);
term->cur++;
while (*s)
{ switch (*s)
{ case '\n' :
e_insert(term->a,term->cur,"% ",E_COMMENT);
term->cur++;
break;
default :
e_append_char(term->a,term->cur-1,*s);
}
s++;
}
}
if (!term->changed) {
g_signal_emit(GTK_OBJECT(term),gtk_term_signals[GTK_TERM_CHANGED],0);
term->changed = 1;
}
/* redraw what is needed */
term->v_adj->value = (gfloat)term->top;
term->v_adj->lower = 0.0;
term->v_adj->upper = (gfloat)(e_get_length(term->a));
term->v_adj->step_increment = 1.0;
term->v_adj->page_increment = (gfloat)(term->theight-1);
term->v_adj->page_size = (gfloat)term->theight;
gtk_adjustment_changed(term->v_adj);
gtk_term_update_caret(term);
gtk_term_redraw_below(term,old_cur);
dy = old_cur - term->top;
if (dy>=term->theight)
gtk_term_adjustment_safe_set_value(term, (gfloat)(old_cur-term->theight+1));
else if (dy<0)
gtk_term_adjustment_safe_set_value(term, (gfloat)old_cur);
gtk_term_draw_caret(term,1);
}
gchar* gtk_term_get_name(GtkWidget *widget)
{
GtkTerm *term;
g_return_val_if_fail (widget != NULL,0);
g_return_val_if_fail (GTK_IS_TERM (widget),0);
term = GTK_TERM (widget);
return term->name->str;
}
gint gtk_term_is_named(GtkWidget *widget)
{
GtkTerm *term;
g_return_val_if_fail (widget != NULL,0);
g_return_val_if_fail (GTK_IS_TERM (widget),0);
term = GTK_TERM (widget);
return (term->name->len!=0);
}
gint gtk_term_is_changed(GtkWidget *widget)
{
GtkTerm *term;
g_return_val_if_fail (widget != NULL,0);
g_return_val_if_fail (GTK_IS_TERM (widget),0);
term = GTK_TERM (widget);
return term->changed;
}
gint gtk_term_is_initialized(GtkWidget *widget)
{
GtkTerm *term;
g_return_val_if_fail (widget != NULL,0);
g_return_val_if_fail (GTK_IS_TERM (widget),0);
term = GTK_TERM (widget);
return !term->initializing;
}
gint gtk_term_is_editing(GtkWidget *widget)
{
GtkTerm *term;
g_return_val_if_fail (widget != NULL,0);
g_return_val_if_fail (GTK_IS_TERM (widget),0);
term = GTK_TERM (widget);
return term->editing;
}
void gtk_term_print(GtkWidget *widget, gchar *s)
{
GtkTerm * term;
int i,n;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
g_return_if_fail (s != NULL);
term = GTK_TERM (widget);
while (*s)
{ switch (*s)
{ case '\n' :
term->pos = term->epos = 0;
gtk_term_update_caret(term);
gtk_term_redraw_current(term);
e_insert(term->a,term->cur+1,"",E_OUTPUT);
term->cur++;
term->v_adj->value = (gfloat)term->top;
term->v_adj->lower = 0.0;
term->v_adj->upper = (gfloat)(e_get_length(term->a));
term->v_adj->step_increment = 1.0;
term->v_adj->page_increment = (gfloat)(term->theight-1);
term->v_adj->page_size = (gfloat)term->theight;
gtk_adjustment_changed(term->v_adj);
gtk_term_scroll_to_pos(term);
break;
case 9 :
n=4-(term->pos%4);
for (i=0; i<n; i++)
{
e_append_char(term->a,term->cur,' ');
term->pos++;
term->epos++;
}
break;
default :
e_append_char(term->a,term->cur,*s);
// gtk_term_update_caret(term);
// gtk_term_redraw_current(term);
term->pos++;
term->epos++;
}
s++;
}
if (!term->changed && !term->initializing) {
g_signal_emit(GTK_OBJECT(term),gtk_term_signals[GTK_TERM_CHANGED],0);
term->changed = 1;
}
}
void gtk_term_edit_on(GtkWidget *widget)
{
GtkTerm * term;
char ch;
int i, type = E_OUTPUT, oldcur;;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
term = GTK_TERM (widget);
ch =(e_get_text(term->a,term->cur))[term->pos-1];
if (ch=='>') {
term->promptlen = term->pos;
if (term->promptlen==1) {
e_set_type(term->a,term->cur,E_PROMPT);
type = E_PROMPT;
}
} else if (ch=='$') {
e_set_type(term->a,term->cur,E_UDF);
type = E_UDF;
}
oldcur = term->cur;
for (i=term->cur+1;i<e_get_length(term->a);i++) {
if (e_get_type(term->a,i)==type) {
e_remove(term->a,term->cur);
term->cur=i-1;
break;
}
}
term->v_adj->value = (gfloat)term->top;
term->v_adj->lower = 0.0;
term->v_adj->upper = (gfloat)(e_get_length(term->a));
term->v_adj->step_increment = 1.0;
term->v_adj->page_increment = (gfloat)(term->theight-1);
term->v_adj->page_size = (gfloat)term->theight;
gtk_adjustment_changed(term->v_adj);
gtk_term_scroll_to_pos(term);
gtk_term_redraw_below(term,oldcur-1>=0? oldcur:0);
term->editing = 1;
if (term->timeout_id == -1 && term->editing && GTK_WIDGET_HAS_FOCUS(widget)) {
term->timeout_id = gtk_timeout_add (500, gtk_term_blink_caret, term);
gtk_term_draw_caret(term,1);
}
g_signal_emit(GTK_OBJECT(term),gtk_term_signals[GTK_TERM_EDITING],0);
if (term->initializing) term->initializing = 0;
}
void gtk_term_edit_off(GtkWidget *widget)
{
GtkTerm * term;
int type;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
term = GTK_TERM (widget);
g_signal_emit(GTK_OBJECT(term),gtk_term_signals[GTK_TERM_INTERPRETING],0);
term->editing = 0;
if (term->timeout_id != -1)
{
g_source_remove(term->timeout_id);
term->timeout_id = -1;
}
type = e_get_type(term->a,term->cur);
if (type==E_COMMENT ||
(!strncmp(e_get_text(term->a,term->cur),">function",9) &&
term->cur+1<e_get_length(term->a) &&
e_get_type(term->a,term->cur+1)==E_UDF) ||
(type==E_UDF &&
strncmp(e_get_text(term->a,term->cur),"$endfunction",12))) return;
/* the line will be evaluated : remove the old output results */
while (term->cur+1<e_get_length(term->a)) {
type = e_get_type(term->a,term->cur+1);
if (type==E_PROMPT || type==E_COMMENT) break;
e_remove(term->a,term->cur+1);
}
term->v_adj->value = (gfloat)term->top;
term->v_adj->lower = 0.0;
term->v_adj->upper = (gfloat)(e_get_length(term->a));
term->v_adj->step_increment = 1.0;
term->v_adj->page_increment = (gfloat)(term->theight-1);
term->v_adj->page_size = (gfloat)term->theight;
gtk_adjustment_changed(term->v_adj);
}
void gtk_term_insert_command(GtkWidget *widget, char *text)
{
int type;
GtkTerm * term;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
term = GTK_TERM (widget);
type = e_get_type(term->a,term->cur);
if (type!=E_PROMPT && type!=E_UDF) return;
gtk_term_draw_caret(term,0);
if (type==E_PROMPT) {
int i = term->cur;
while (i-1>=0 && e_get_type(term->a,i-1)==E_COMMENT) i--;
term->cur = i;
e_insert(term->a,term->cur,">",E_PROMPT);
} else {
e_insert(term->a,term->cur,"$",E_UDF);
}
term->pos = term->epos = term->promptlen;
term->v_adj->upper = (gfloat)(e_get_length(term->a));
gtk_adjustment_changed(term->v_adj);
if (term->cur < term->top) {
gtk_term_scroll_to_pos(term);
} else {
gtk_term_update_caret(term);
gtk_term_redraw_below(term,term->cur);
}
gtk_term_update_caret(term);
gtk_term_draw_caret(term,1);
if (!term->changed) {
g_signal_emit(GTK_OBJECT(term),gtk_term_signals[GTK_TERM_CHANGED],0);
term->changed = 1;
}
}
void gtk_term_delete_command(GtkWidget *widget)
{
GtkTerm * term;
int i;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
term = GTK_TERM (widget);
if (e_get_type(term->a,term->cur)==E_UDF)
{
if (term->cur==e_get_length(term->a)-1 || e_get_type(term->a,term->cur+1)!=E_UDF)
return;
gtk_term_draw_caret(term,0);
e_remove(term->a,term->cur);
term->pos = term->epos = term->promptlen;
// term->v_adj->value = 0.0;
term->v_adj->lower = 0.0;
term->v_adj->upper = (gfloat)(e_get_length(term->a));
term->v_adj->step_increment = 1.0;
term->v_adj->page_increment = (gfloat)(term->theight-1);
term->v_adj->page_size = (gfloat)term->theight;
gtk_adjustment_changed(term->v_adj);
gtk_term_update_caret(term);
gtk_term_redraw_below(term,term->cur);
gtk_term_draw_caret(term,1);
return;
}
/* is there another command line after this one (don't delete
* the last line) ?
*/
for (i=term->cur+1;i<e_get_length(term->a);i++)
if (e_get_type(term->a,i)==E_PROMPT) break;
if (i==e_get_length(term->a)) return;
gtk_term_draw_caret(term,0);
/* delete the comment lines if any */
while(term->cur && e_get_type(term->a,term->cur-1)==E_COMMENT) {
e_remove(term->a,term->cur-1);
term->cur--;
}
/* delete the command line */
e_remove(term->a,term->cur);
/* delete the output and user function definition lines if any */
while (e_get_type(term->a,term->cur)==E_OUTPUT || e_get_type(term->a,term->cur)==E_UDF)
e_remove(term->a,term->cur);
/* set up the new current line (the next prompt) */
while (term->cur<e_get_length(term->a) && e_get_type(term->a,term->cur)!=E_PROMPT)
term->cur++;
term->pos = term->epos = term->promptlen;
// term->v_adj->value = 0.0;
term->v_adj->lower = 0.0;
term->v_adj->upper = (gfloat)(e_get_length(term->a));
term->v_adj->step_increment = 1.0;
term->v_adj->page_increment = (gfloat)(term->theight-1);
term->v_adj->page_size = (gfloat)term->theight;
gtk_adjustment_changed(term->v_adj);
gtk_term_scroll_to_pos(term);
gdk_window_clear(term->text);
gtk_term_draw_text(term);
gtk_term_draw_caret(term,1);
if (!term->changed) {
g_signal_emit(GTK_OBJECT(term),gtk_term_signals[GTK_TERM_CHANGED],0);
term->changed = 1;
}
}
void gtk_term_delete_current_output(GtkWidget *widget)
{
GtkTerm * term;
int i, changed=0;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
term = GTK_TERM (widget);
if (term->editing) {
i = term->cur+1;
while (i<e_get_length(term->a) && e_get_type(term->a,i)==E_OUTPUT) {
e_remove(term->a,i);
changed = 1;
}
if(!changed) return;
// term->v_adj->value = 0.0;
term->v_adj->lower = 0.0;
term->v_adj->upper = (gfloat)(e_get_length(term->a));
term->v_adj->step_increment = 1.0;
term->v_adj->page_increment = (gfloat)(term->theight-1);
term->v_adj->page_size = (gfloat)term->theight;
gtk_adjustment_changed(term->v_adj);
gtk_term_scroll_to_pos(term);
gdk_window_clear(term->text);
gtk_term_draw_text(term);
gtk_term_draw_caret(term,1);
if (!term->changed && changed) {
g_signal_emit(GTK_OBJECT(term),gtk_term_signals[GTK_TERM_CHANGED],0);
term->changed = 1;
}
}
}
void gtk_term_delete_outputs(GtkWidget *widget)
{
GtkTerm * term;
int i, changed=0;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
term = GTK_TERM (widget);
if (term->editing) {
i=0;
while (i<e_get_length(term->a)) {
if (e_get_type(term->a,i)==E_OUTPUT) {
e_remove(term->a,i);
if (i<term->cur) term->cur--;
changed = 1;
}
else
i++;
}
if (!changed) return;
// term->v_adj->value = 0.0;
term->v_adj->lower = 0.0;
term->v_adj->upper = (gfloat)(e_get_length(term->a));
term->v_adj->step_increment = 1.0;
term->v_adj->page_increment = (gfloat)(term->theight-1);
term->v_adj->page_size = (gfloat)term->theight;
gtk_adjustment_changed(term->v_adj);
gtk_term_scroll_to_pos(term);
gdk_window_clear(term->text);
gtk_term_draw_text(term);
gtk_term_draw_caret(term,1);
if (!term->changed && changed) {
g_signal_emit(GTK_OBJECT(term),gtk_term_signals[GTK_TERM_CHANGED],0);
term->changed = 1;
}
}
}
void gtk_term_set_popup(GtkWidget *widget, GtkMenu *menu)
{
GtkTerm *term;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
g_return_if_fail (menu!=NULL);
term = GTK_TERM (widget);
term->menu = menu;
}
void gtk_term_set_scrollbar(GtkWidget *widget, GtkWidget *scroll)
{
GtkTerm *term;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
g_return_if_fail (scroll!=NULL);
term = GTK_TERM (widget);
term->p_scroll = scroll;
}
void gtk_term_set_colors(GtkWidget *widget, GdkColor *cmdColor,
GdkColor *outColor,
GdkColor *cmtColor,
GdkColor *udfColor)
{
GtkTerm *term;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
term = GTK_TERM (widget);
gdk_gc_set_foreground(term->commentGC,cmtColor);
gdk_gc_set_foreground(term->outputGC,outColor);
gdk_gc_set_foreground(term->promptGC,cmdColor);
gdk_gc_set_foreground(term->udfGC,udfColor);
}
/************************************************************************
* PRIVATE METHODS
************************************************************************/
static void gtk_term_cursor_up(GtkTerm *term)
{
int i;
if (e_get_type(term->a,term->cur)==E_UDF) {
if (e_get_type(term->a,term->cur-1)==E_UDF) {
gtk_term_draw_caret(term,0);
term->pos = term->epos = term->promptlen;
gtk_term_update_caret(term);
gtk_term_redraw_current(term);
term->cur--;
gtk_term_scroll_to_pos(term);
gtk_term_draw_caret(term,1);
}
return;
}
if (e_get_type(term->a,term->cur)!=E_PROMPT) return;
for (i=term->cur-1 ; i>=0 ; i--)
if (e_get_type(term->a,i)==E_PROMPT) {
gtk_term_draw_caret(term,0);
term->pos = term->epos = term->promptlen;
gtk_term_update_caret(term);
gtk_term_redraw_current(term);
term->cur = i;
gtk_term_scroll_to_pos(term);
gtk_term_draw_caret(term,1);
break;
}
}
static void gtk_term_cursor_down(GtkTerm *term)
{
int i;
if (e_get_type(term->a,term->cur)==E_UDF) {
if (e_get_type(term->a,term->cur+1)==E_UDF) {
gtk_term_draw_caret(term,0);
term->pos = term->epos = term->promptlen;
gtk_term_update_caret(term);
gtk_term_redraw_current(term);
term->cur++;
gtk_term_scroll_to_pos(term);
gtk_term_draw_caret(term,1);
}
return;
}
if (e_get_type(term->a,term->cur)!=E_PROMPT) return;
for (i=term->cur+1 ; i<e_get_length(term->a) ; i++)
if (e_get_type(term->a,i)==E_PROMPT) {
gtk_term_draw_caret(term,0);
term->pos = term->epos = term->promptlen;
gtk_term_update_caret(term);
gtk_term_redraw_current(term);
term->cur = i;
gtk_term_scroll_to_pos(term);
gtk_term_draw_caret(term,1);
break;
}
}
static void gtk_term_scroll_to_pos(GtkTerm *term)
{
gint w,h,dy;
dy = term->cur - term->top;
if (dy>=term->theight)
gtk_term_adjustment_safe_set_value(term, (gfloat)(term->cur-term->theight+1));
else if (dy<0)
gtk_term_adjustment_safe_set_value(term, (gfloat)term->cur);
else{
gtk_term_adjustment_safe_set_value(term, (gfloat)term->v_adj->value);
gtk_term_update_caret(term);
}
gdk_drawable_get_size(term->text,&w,&h);
term->xcaret = term->xoff+term->pos*term->cwidth+PADDING;
if (term->xcaret>w-40){
while (term->xcaret>w-40) {
term->xoff-=40;
term->xcaret = term->xoff+term->pos*term->cwidth+PADDING;
}
gdk_window_clear(term->text);
gtk_term_draw_text(term);
} else if (term->xcaret<PADDING) {
while(term->xcaret<PADDING) {
term->xoff+=40;
term->xcaret = term->xoff+term->pos*term->cwidth+PADDING;
}
gdk_window_clear(term->text);
gtk_term_draw_text(term);
} else
gtk_term_redraw_current(term);
}
static void gtk_term_update_caret(GtkTerm *term)
{
term->xcaret = term->xoff+term->pos*term->cwidth+PADDING;
term->ycaret = (term->cur-term->top)*term->cheight+PADDING;
}
static void gtk_term_draw_caret(GtkTerm *term, guint state)
{
GdkGC *gc;
if (term->pos==term->epos && term->cur >= term->top && term->cur < (term->top + term->theight)) {
if (state && !term->caret_blink_state) {
gc = ((GtkWidget*)term)->style->black_gc;
gdk_draw_line(term->text,gc,term->xcaret,term->ycaret,term->xcaret,term->ycaret+term->cheight);
} else if (!state && term->caret_blink_state) {
gc = ((GtkWidget*)term)->style->white_gc;
gdk_draw_line(term->text,gc,term->xcaret,term->ycaret,term->xcaret,term->ycaret+term->cheight);
gtk_term_redraw_current(term);
}
term->caret_blink_state = state;
}
}
static gint gtk_term_blink_caret(gpointer data)
{
GtkTerm *term = (GtkTerm*)data;
g_return_val_if_fail (data != NULL, FALSE);
gtk_term_draw_caret(term,!term->caret_blink_state);
return TRUE;
}
/************************************************************************
* GtkObject and GtkWidget VIRTUAL METHODS DEFINITION
************************************************************************/
/*
* GtkObject destroy method
*/
static void gtk_term_destroy (GtkObject *object)
{
GtkTerm *term;
g_return_if_fail (object != NULL);
g_return_if_fail (GTK_IS_TERM (object));
term = GTK_TERM (object);
if (term->timeout_id != -1)
g_source_remove(term->timeout_id);
e_free(term->history);
e_free(term->a);
if (term->cursor) {
gdk_cursor_destroy(term->cursor);
term->cursor = NULL;
}
if (term->font)
{
gdk_font_unref (term->font);
term->font = NULL;
}
if (term->v_adj)
{
gtk_signal_disconnect_by_data (GTK_OBJECT (term->v_adj), term);
gtk_object_unref (GTK_OBJECT (term->v_adj));
term->v_adj = NULL;
}
g_string_free(term->name,TRUE);
g_string_free(term->clipboard,TRUE);
/*
* call widget class destroy method
*/
if (GTK_OBJECT_CLASS (parent_class)->destroy)
(* GTK_OBJECT_CLASS (parent_class)->destroy)(object);
}
/*
* realize / unrealize : set up or destroy the gdk_window
*/
static void gtk_term_realize (GtkWidget *widget)
{
GtkTerm *term;
GdkWindowAttr attributes;
gint attributes_mask;
GdkColormap *cmap;
GdkColor c;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
term = GTK_TERM (widget);
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.window_type = GDK_WINDOW_CHILD;
attributes.event_mask = gtk_widget_get_events (widget)
| GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
| GDK_BUTTON_MOTION_MASK
| GDK_KEY_PRESS_MASK;
attributes.visual = gtk_widget_get_visual (widget);
attributes.colormap = cmap = gtk_widget_get_colormap (widget);
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
/* main window */
widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
&attributes, attributes_mask);
widget->style = gtk_style_attach (widget->style, widget->window);
gdk_window_set_user_data (widget->window, widget);
gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
attributes.x = widget->style->xthickness;
attributes.y = widget->style->ythickness;
attributes.width = MAX (1, (gint)widget->allocation.width - (gint)attributes.x * 2);
attributes.height = MAX (1, (gint)widget->allocation.height - (gint)attributes.y * 2);
attributes.cursor = term->cursor = gdk_cursor_new(GDK_XTERM);
attributes_mask |= GDK_WA_CURSOR;
term->text = gdk_window_new (widget->window, &attributes, attributes_mask);
gdk_window_set_user_data (term->text, term);
gdk_window_set_background (term->text, &widget->style->white);
gdk_window_show(term->text);
term->font = gdk_font_load (term->tfont->str);
if (!term->font) {
fprintf(stderr,"The default font could not be found. Please change it by editing the \"tfont\" symbol in ~/euler/eulerrc\n");
exit(1);
}
term->cwidth = gdk_char_width(term->font,'m');
term->cheight = 2+gdk_string_height(term->font,"abcdefghijklmnopqrstuvwxyz0123456789");
term->commentGC = gdk_gc_new(term->text);
c.red = 0;
c.green = 100<<8;
c.blue = 0;
if (gdk_color_alloc(cmap,&c))
gdk_gc_set_foreground(term->commentGC,&c);
term->outputGC = gdk_gc_new(term->text);
term->udfGC = gdk_gc_new(term->text);
c.red = 0;
c.green = 0;
c.blue = 100<<8;
if (gdk_color_alloc(cmap,&c))
gdk_gc_set_foreground(term->udfGC,&c);
term->promptGC = gdk_gc_new(term->text);
c.red = 100<<8;
c.green = 0;
c.blue = 0;
if (gdk_color_alloc(cmap,&c))
gdk_gc_set_foreground(term->promptGC,&c);
term->highlightGC = gdk_gc_new(term->text);
c.red = 255<<8;
c.green = 153<<8;
c.blue = 41<<8;
if (gdk_color_alloc(cmap,&c))
gdk_gc_set_foreground(term->highlightGC,&c);
term->v_adj->value = 0.0;
term->v_adj->lower = 0.0;
term->v_adj->upper = (gfloat)(e_get_length(term->a));
term->v_adj->step_increment = 1.0;
term->v_adj->page_increment = (gfloat)(term->theight-1);
term->v_adj->page_size = (gfloat)term->theight;
gtk_adjustment_changed(term->v_adj);
}
static void gtk_term_unrealize (GtkWidget *widget)
{
GtkTerm *term;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED);
term = GTK_TERM (widget);
gdk_window_set_user_data (term->text, NULL);
gdk_window_destroy (term->text);
term->text = NULL;
gdk_gc_destroy(term->commentGC);
gdk_gc_destroy(term->outputGC);
gdk_gc_destroy(term->udfGC);
gdk_gc_destroy(term->promptGC);
gdk_gc_destroy(term->highlightGC);
if (GTK_WIDGET_CLASS (parent_class)->unrealize)
(*GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
}
/*
* selection handling
*/
static gint gtk_term_selection_clear(GtkWidget *widget, GdkEventSelection *event)
{
GtkTerm *term;
g_return_val_if_fail (widget != NULL,FALSE);
g_return_val_if_fail (GTK_IS_TERM(widget),FALSE);
term = GTK_TERM(widget);
/* Let the selection handling code know that the selection
* has been changed, since we've overriden the default handler */
if (!gtk_selection_clear (widget, event))
return FALSE;
if (term->clipboard->len!=0)
g_string_assign(term->clipboard,"");
return TRUE;
}
static void gtk_term_selection_get(GtkWidget *widget, GtkSelectionData *selection_data, guint info, guint time)
{
GtkTerm *term;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM(widget));
term = GTK_TERM(widget);
gtk_selection_data_set(selection_data,GDK_SELECTION_TYPE_STRING,8,term->clipboard->str,term->clipboard->len);
}
static void gtk_term_selection_received(GtkWidget *widget, GtkSelectionData *selection_data, guint time)
{
GtkTerm *term;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM(widget));
term = GTK_TERM(widget);
if (selection_data->length<0) return;
if (selection_data->type != GDK_SELECTION_TYPE_STRING) return;
/* if a piece of text is currently selected : delete it */
if (term->editing && (term->pos != term->epos))
{
if (term->epos>term->pos) {
e_remove_text(term->a,term->cur,term->pos,term->epos-term->pos);
term->epos = term->pos;
} else {
e_remove_text(term->a,term->cur,term->epos,term->pos-term->epos);
term->pos = term->epos;
}
}
selection_data->data[selection_data->length] = 0;
e_insert_text(term->a,term->cur,term->pos,(gchar *)selection_data->data);
term->pos += strlen ((gchar *)selection_data->data);
term->epos = term->pos;
gtk_term_update_caret(term);
gtk_term_scroll_to_pos(term);
if (!term->changed) {
g_signal_emit(GTK_OBJECT(term),gtk_term_signals[GTK_TERM_CHANGED],0);
term->changed = 1;
}
}
/*
* size_request : set the minimum widget size : 80 chars * 24 lines
*/
static void gtk_term_size_request (GtkWidget *widget, GtkRequisition *requisition)
{
GtkTerm *term;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
g_return_if_fail (requisition != NULL);
term = GTK_TERM (widget);
requisition->width = (term->twidth * term->cwidth) + (widget->style->xthickness * 2) + 2*PADDING;
requisition->height = (term->theight * term->cheight) + (widget->style->ythickness * 2) + 2*PADDING;
}
/*
* size_allocate : set the actual widget size
*/
static void gtk_term_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
{
GtkTerm *term;
static short count = 1;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
g_return_if_fail (allocation != NULL);
widget->allocation = *allocation;
if (GTK_WIDGET_REALIZED(widget))
{
term = GTK_TERM(widget);
if (count == 2) {
int w = (TERM_MINWIDTH_DEFAULT * term->cwidth) + (widget->style->xthickness * 2) + 2*PADDING;
int h = (TERM_MINHEIGHT_DEFAULT * term->cheight) + (widget->style->ythickness * 2) + 2*PADDING;
gtk_widget_set_size_request(widget, w, h);
count = 0;
}
if (count == 1) count = 2;
gdk_window_move_resize(widget->window,
allocation->x,
allocation->y,
allocation->width,
allocation->height);
gdk_window_move_resize(term->text,
widget->style->xthickness,
widget->style->ythickness,
allocation->width-2*widget->style->xthickness,
allocation->height-2*widget->style->ythickness);
linelength = term->twidth = (allocation->width - (2 * widget->style->xthickness) - 2 * PADDING)/term->cwidth;
term->theight = (allocation->height - (2 * widget->style->ythickness)- 2 * PADDING)/term->cheight;
/*
* resize the scrollbar
*/
term->v_adj->page_increment = (gfloat)(term->theight-1);
term->v_adj->page_size = (gfloat)term->theight;
gtk_adjustment_changed(term->v_adj);
gtk_term_scroll_to_pos(term);
}
}
static void gtk_term_redraw_current(GtkTerm *term)
{
int offy;
GdkGC * gc = NULL;
offy = PADDING+(term->cur-term->top)*term->cheight;
gdk_window_clear_area(term->text,0,offy,2*PADDING+term->twidth*term->cwidth,term->cheight);
if (term->pos!=term->epos) {
if (term->epos>term->pos)
gdk_draw_rectangle(term->text,term->highlightGC,TRUE,term->xcaret,offy,(term->epos-term->pos)*term->cwidth,term->cheight);
else
gdk_draw_rectangle(term->text,term->highlightGC,TRUE,term->xcaret-(term->pos-term->epos)*term->cwidth,offy,(term->pos-term->epos)*term->cwidth,term->cheight);
}
switch (e_get_type(term->a,term->cur))
{
case E_OUTPUT:
gc = term->outputGC;
break;
case E_PROMPT:
gc = term->promptGC;
break;
case E_UDF:
gc = term->udfGC;
break;
case E_COMMENT:
gc = term->commentGC;
}
gdk_draw_string(term->text,term->font,gc,PADDING+term->xoff,offy+term->cheight-term->font->descent-1,e_get_text(term->a,term->cur));
}
static void gtk_term_redraw_below(GtkTerm *term, int index)
{
int offy;
GdkGC * gc = NULL;
int i, last;
offy = PADDING+(index-term->top)*term->cheight;
gdk_window_clear_area(term->text,
0,
offy,
2*PADDING+term->twidth*term->cwidth,
(term->theight-index+term->top)*term->cheight);
last = MIN(term->top+term->theight,e_get_length(term->a));
for (i=index ; i<last ; i++)
{
if (i==term->cur && term->epos!=term->pos) {
if (term->epos>term->pos)
gdk_draw_rectangle(term->text,term->highlightGC,TRUE,term->xcaret,offy,(term->epos-term->pos)*term->cwidth,term->cheight);
else
gdk_draw_rectangle(term->text,term->highlightGC,TRUE,term->xcaret-(term->pos-term->epos)*term->cwidth,offy,(term->pos-term->epos)*term->cwidth,term->cheight);
}
offy+=term->cheight;
switch (e_get_type(term->a,i))
{
case E_OUTPUT:
gc = term->outputGC;
break;
case E_PROMPT:
gc = term->promptGC;
break;
case E_UDF:
gc = term->udfGC;
break;
case E_COMMENT:
gc = term->commentGC;
}
gdk_draw_string(term->text,term->font,gc,
PADDING+term->xoff,
offy-term->font->descent-1,
e_get_text(term->a,i));
}
}
static void gtk_term_draw_text(GtkTerm *term)
{
int offx, offy;
GdkGC * gc = NULL;
int i, last;
if (term->editing) gtk_term_draw_caret(term,0);
offx = PADDING+term->xoff;
offy = PADDING;
last = MIN(term->top+term->theight,e_get_length(term->a));
for (i=term->top ; i<last ; i++)
{
if (i==term->cur && term->epos!=term->pos) {
if (term->epos>term->pos)
gdk_draw_rectangle(term->text,term->highlightGC,TRUE,term->xcaret,offy,(term->epos-term->pos)*term->cwidth,term->cheight);
else
gdk_draw_rectangle(term->text,term->highlightGC,TRUE,term->xcaret-(term->pos-term->epos)*term->cwidth,offy,(term->pos-term->epos)*term->cwidth,term->cheight);
}
offy+=term->cheight;
switch (e_get_type(term->a,i))
{
case E_OUTPUT:
gc = term->outputGC;
break;
case E_PROMPT:
gc = term->promptGC;
break;
case E_UDF:
gc = term->udfGC;
break;
case E_COMMENT:
gc = term->commentGC;
}
// gdk_draw_rectangle(term->text,gc,FALSE,offx,offy-term->cheight,widget->allocation.width-2*(PADDING+widget->style->klass->ythickness),term->cheight);
gdk_draw_string(term->text,term->font,gc,offx,offy-term->font->descent-1,e_get_text(term->a,i));
}
if (term->editing) gtk_term_draw_caret(term,1);
}
/*
* draw / expose : draw or refresh the widget
*/
static gint gtk_term_expose (GtkWidget *widget, GdkEventExpose *event)
{
GtkTerm * term;
g_return_val_if_fail (widget != NULL,FALSE);
g_return_val_if_fail (GTK_IS_TERM (widget),FALSE);
g_return_val_if_fail (event!=NULL,FALSE);
if (GTK_WIDGET_DRAWABLE (widget))
{
term = GTK_TERM (widget);
if (event->window==term->text)
gtk_term_draw_text(term);
else
gtk_draw_shadow (widget->style,widget->window,GTK_STATE_NORMAL,GTK_SHADOW_IN,0,0,widget->allocation.width,widget->allocation.height);
}
return FALSE;
}
static void gtk_term_adjustment_safe_set_value(GtkTerm *term, gfloat value)
{
if (value < term->v_adj->lower || term->v_adj->upper < term->v_adj->page_size)
gtk_adjustment_set_value(term->v_adj, term->v_adj->lower);
else if (value > term->v_adj->upper - term->v_adj->page_size)
gtk_adjustment_set_value(term->v_adj, term->v_adj->upper - term->v_adj->page_size);
else
gtk_adjustment_set_value(term->v_adj, value);
}
/*
* Callback for when the adjustment changes - i.e., the scrollbar
* moves.
*/
static void gtk_term_scrollbar_moved (GtkAdjustment *adj, GtkWidget *widget)
{
GtkTerm *term;
gint dy;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
term = GTK_TERM (widget);
dy = (gint)adj->value - term->top;
if (dy)
{
if (term->editing) gtk_term_draw_caret(term,0);
if (dy>0)
{
gint offx, offy, i;
GdkGC *gc = NULL;
offx = PADDING+term->xoff;
offy = PADDING;
gdk_window_copy_area(term->text,term->outputGC,offx,offy,
term->text,
offx,offy+dy*term->cheight,
term->twidth*term->cwidth+PADDING,
(term->theight-dy)*term->cheight);
gdk_draw_rectangle(term->text,widget->style->white_gc,TRUE,
offx,offy+(term->theight-dy)*term->cheight,
term->twidth*term->cwidth+PADDING,
dy*term->cheight);
for (i=term->top+term->theight; i<term->top+term->theight+dy; i++) {
if (i==term->cur && term->epos!=term->pos) {
if (term->epos>term->pos)
gdk_draw_rectangle(term->text,term->highlightGC,TRUE,term->xcaret,offy+(i-term->top-dy)*term->cheight,(term->epos-term->pos)*term->cwidth+PADDING,term->cheight);
else
gdk_draw_rectangle(term->text,term->highlightGC,TRUE,term->xcaret-(term->pos-term->epos)*term->cwidth,offy+(i-term->top-dy)*term->cheight,(term->pos-term->epos)*term->cwidth+PADDING,term->cheight);
}
switch (e_get_type(term->a,i))
{
case E_OUTPUT:
gc = term->outputGC;
break;
case E_PROMPT:
gc = term->promptGC;
break;
case E_UDF:
gc = term->udfGC;
break;
case E_COMMENT:
gc = term->commentGC;
}
if(e_get_text(term->a,i))
gdk_draw_string(term->text,term->font,gc,
offx,
offy+(i-term->top-dy+1)*term->cheight-term->font->descent-1,
e_get_text(term->a,i));
}
term->top += dy;
}
else
{
gint offx, offy, i;
GdkGC *gc = NULL;
dy = -dy;
offx = PADDING+term->xoff;
offy = PADDING;
gdk_window_copy_area(term->text,term->outputGC,offx,offy+dy*term->cheight,
term->text,
offx,offy,
term->twidth*term->cwidth+PADDING,
(term->theight-dy)*term->cheight);
gdk_draw_rectangle(term->text,widget->style->white_gc,TRUE,
offx,offy,
term->twidth*term->cwidth+PADDING,
dy*term->cheight);
for (i=term->top-dy; i<term->top; i++) {
if (i==term->cur && term->epos!=term->pos) {
if (term->epos>term->pos)
gdk_draw_rectangle(term->text,term->highlightGC,TRUE,term->xcaret,offy+(i-term->top+dy)*term->cheight,(term->epos-term->pos)*term->cwidth+PADDING,term->cheight);
else
gdk_draw_rectangle(term->text,term->highlightGC,TRUE,term->xcaret-(term->pos-term->epos)*term->cwidth,offy+(i-term->top+dy)*term->cheight,(term->pos-term->epos)*term->cwidth+PADDING,term->cheight);
}
switch (e_get_type(term->a,i))
{
case E_OUTPUT:
gc = term->outputGC;
break;
case E_PROMPT:
gc = term->promptGC;
break;
case E_UDF:
gc = term->udfGC;
break;
case E_COMMENT:
gc = term->commentGC;
}
if(e_get_text(term->a,i))
gdk_draw_string(term->text,term->font,gc,offx,
offy+(i-term->top+dy+1)*term->cheight-term->font->descent-1,
e_get_text(term->a,i));
}
term->top -= dy;
}
gtk_term_update_caret(term);
if (term->editing) gtk_term_draw_caret(term,1);
}
}
static void gtk_term_scroll(GtkWidget* widget, GdkEventScroll* event, gpointer user_data)
{
GtkAdjustment* sb_state;
gdouble lower;
gdouble upper;
gdouble far;
GtkTerm *term;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
term = GTK_TERM (widget);
sb_state = gtk_range_get_adjustment(GTK_RANGE(term->p_scroll));
lower = sb_state->lower;
upper = sb_state->upper;
if (sb_state->page_size >= upper)
return;
switch (event->direction) {
case GDK_SCROLL_UP:
if (sb_state->value <= lower)
return;
if ((sb_state->value - lower) < sb_state->step_increment)
far = sb_state->value - lower;
else
far = sb_state->step_increment;
gtk_adjustment_set_value(sb_state, sb_state->value - far);
break;
case GDK_SCROLL_DOWN:
if (sb_state->value >= (upper - sb_state->page_size))
return;
if (((upper - sb_state->page_size) - sb_state->value) < sb_state->step_increment)
far = (upper - sb_state->page_size) - sb_state->value;
else
far = sb_state->step_increment;
gtk_adjustment_set_value(sb_state, sb_state->value + far);
break;
default:{};
}
}
static void gtk_term_map (GtkWidget *widget)
{
GtkTerm *term;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_TERM (widget));
term = GTK_TERM (widget);
if (!GTK_WIDGET_MAPPED (widget))
{
GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
gdk_window_show (widget->window);
if (!GTK_WIDGET_HAS_FOCUS (widget))
gtk_widget_grab_focus (widget);
}
}
static gint gtk_term_button_press (GtkWidget *widget, GdkEventButton *event)
{
GtkTerm * term;
int n, p;
g_return_val_if_fail (widget != NULL,FALSE);
g_return_val_if_fail (GTK_IS_TERM (widget),FALSE);
g_return_val_if_fail (event!=NULL,FALSE);
if (event->button==1) {
term = GTK_TERM (widget);
if (!term->editing) return FALSE;
n = term->top + (event->y - widget->style->ythickness - PADDING)/term->cheight;
p = (event->x - term->xoff - widget->style->xthickness - PADDING)/term->cwidth;
if (n>=e_get_length(term->a) || e_get_type(term->a,n)==E_OUTPUT || e_get_type(term->a,n)==E_COMMENT)
return FALSE;
if (((e_get_type(term->a,term->cur)==E_UDF && term->cur==n) || e_get_type(term->a,n)==E_PROMPT) && !nojump) {
gtk_term_draw_caret(term,0);
term->pos = term->epos = term->promptlen;
gtk_term_update_caret(term);
gtk_term_redraw_current(term);
if (p<term->promptlen) p=term->promptlen;
if (p>e_get_text_length(term->a,n)) p=e_get_text_length(term->a,n);
term->cur = n;
term->pos = term->epos = p;
gtk_term_update_caret(term);
gtk_term_scroll_to_pos(term);
term->selecting = 1;
}
} else if (event->button==3) {
term = GTK_TERM (widget);
if (!term->editing) return FALSE;
n = term->top + (event->y - widget->style->ythickness - PADDING)/term->cheight;
p = (event->x - term->xoff - widget->style->xthickness - PADDING)/term->cwidth;
if (n>=e_get_length(term->a) || e_get_type(term->a,n)==E_OUTPUT || e_get_type(term->a,n)==E_COMMENT)
return FALSE;
if (term->cur!=n)
if (((e_get_type(term->a,term->cur)==E_UDF && term->cur==n) || e_get_type(term->a,n)==E_PROMPT) && !nojump) {
gtk_term_draw_caret(term,0);
term->pos = term->epos = term->promptlen;
gtk_term_update_caret(term);
gtk_term_redraw_current(term);
if (p<term->promptlen) p=term->promptlen;
if (p>e_get_text_length(term->a,n)) p=e_get_text_length(term->a,n);
term->cur = n;
term->pos = term->epos = p;
gtk_term_update_caret(term);
gtk_term_scroll_to_pos(term);
}
gtk_menu_popup(term->menu,NULL,NULL,NULL,NULL,event->button,event->time);
}
return FALSE;
}
static void gtk_term_scroll_to_epos(GtkTerm *term)
{
gint w,h,eposx;
gdk_drawable_get_size(term->text,&w,&h);
eposx = term->xoff+term->epos*term->cwidth+PADDING;
if (eposx>w-40){
term->xoff-=40;
term->xcaret = term->xoff+term->pos*term->cwidth+PADDING;
gdk_window_clear(term->text);
gtk_term_draw_text(term);
} else if (eposx<PADDING) {
term->xoff+=40;
term->xcaret = term->xoff+term->pos*term->cwidth+PADDING;
gdk_window_clear(term->text);
gtk_term_draw_text(term);
} else
gtk_term_redraw_current(term);
}
static gint gtk_term_motion_notify (GtkWidget *widget, GdkEventMotion *event)
{
GtkTerm * term;
int p;
g_return_val_if_fail (widget != NULL,FALSE);
g_return_val_if_fail (GTK_IS_TERM (widget),FALSE);
g_return_val_if_fail (event!=NULL,FALSE);
term = GTK_TERM (widget);
if (!term->editing || !term->selecting) return FALSE;
p = (event->x - term->xoff - widget->style->xthickness - PADDING)/term->cwidth;
if (p<term->promptlen) p=term->promptlen;
if (p>e_get_text_length(term->a,term->cur)) p=e_get_text_length(term->a,term->cur);
term->epos = p;
gtk_term_scroll_to_epos(term);
return FALSE;
}
static gint gtk_term_button_release (GtkWidget *widget, GdkEventButton *event)
{
GtkTerm * term;
g_return_val_if_fail (widget != NULL,FALSE);
g_return_val_if_fail (GTK_IS_TERM (widget),FALSE);
g_return_val_if_fail (event!=NULL,FALSE);
term = GTK_TERM (widget);
switch (event->button) {
case 1:
term->selecting = 0;
gtk_term_redraw_current(term);
gtk_term_draw_caret(term,1);
break;
case 4:
gtk_term_adjustment_safe_set_value(term, term->v_adj->value-term->theight+1);
break;
case 5:
gtk_term_adjustment_safe_set_value(term, (gfloat)MIN(term->top+term->theight-1,e_get_length(term->a)-term->theight));
break;
}
return FALSE;
}
static gint gtk_term_focus_in(GtkWidget *widget, GdkEventFocus *event)
{
GtkTerm *term;
g_return_val_if_fail (widget != NULL, FALSE);
g_return_val_if_fail (GTK_IS_TERM (widget), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
term = GTK_TERM (widget);
GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
if (term->timeout_id == -1 && term->editing) {
term->timeout_id = gtk_timeout_add (500, gtk_term_blink_caret, term);
gtk_term_draw_caret(term,1);
}
return FALSE;
}
static gint gtk_term_focus_out(GtkWidget *widget, GdkEventFocus *event)
{
GtkTerm *term;
g_return_val_if_fail (widget != NULL, FALSE);
g_return_val_if_fail (GTK_IS_TERM (widget), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
term = GTK_TERM (widget);
GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
if (term->timeout_id != -1)
{
g_source_remove(term->timeout_id);
term->timeout_id = -1;
}
gtk_term_draw_caret(term,0);
return FALSE;
}
/* dohelp
* Extend a start string in up to 16 ways to a command or function.
* This function is called from the line editor, whenever the HELP
* key is pressed.
*/
static char helpstart[256];
static char helpextend[16][16];
static int helpn=0,helpnext=0,helphist=-1;
static char *p;
extern commandtyp command_list[];
static int dohelp (char start[256], char extend[16][16])
{
int count=0,ln,l;
header *hd=(header *)ramstart;
builtintyp *b=builtin_list;
commandtyp *c=command_list;
ln=(int)strlen(start);
while (b->name)
{ if (!strncmp(start,b->name,ln))
{ l=(int)strlen(b->name)-ln;
if (l>0 && l<16)
{ strcpy(extend[count],b->name+ln);
count++;
}
if (count>=16) return count;
}
b++;
}
while (hd<(header *)udfend)
{ if (!strncmp(start,hd->name,ln))
{ l=(int)strlen(hd->name)-ln;
if (l>0 && l<16)
{ strcpy(extend[count],hd->name+ln);
count++;
}
if (count>=16) return count;
}
hd=nextof(hd);
}
while (c->name)
{ if (!strncmp(start,c->name,ln))
{ l=(int)strlen(c->name)-ln;
if (l>0 && l<16)
{ strcpy(extend[count],c->name+ln);
count++;
}
if (count>=16) return count;
}
c++;
}
return count;
}
/* extend the command at cursor position */
static void gtk_term_edithelp (GtkTerm *term)
{
char *start,*end,*p;
int i,l;
/* search history */
l=e_get_text_length(term->a,term->cur);
helphist=-1;
for (i=e_get_length(term->history)-1; i>=0; i--)
if (!strncmp(e_get_text(term->history,i),e_get_text(term->a,term->cur),l))
{ helphist=i;
break;
}
/* get the begining of the command to extend */
start=end=p=e_get_text(term->a,term->cur)+term->pos;
while (start>e_get_text(term->a,term->cur) && (isalpha(*(start-1)) || isdigit(*(start-1))))
start--;
while (isdigit(*start)) start++;
while (isalpha(*end) || isdigit(*end)) end++;
if (start>p || start>=end) return;
while (p<end) { term->pos++; p++; }
memmove(helpstart,start,end-start);
helpstart[end-start]=0;
helpn=dohelp(helpstart,helpextend);
helpnext=0;
}
static void gtk_term_fkinsert (GtkTerm *term, int i)
{
char *p = fktext[i];
e_insert_text(term->a,term->cur,term->pos,p);
gtk_term_redraw_current(term);
term->pos += (int)strlen(p);
gtk_term_scroll_to_pos(term);
if (!term->changed) {
g_signal_emit(GTK_OBJECT(term),gtk_term_signals[GTK_TERM_CHANGED],0);
term->changed = 1;
}
}
static void get_scan(GdkEventKey *event, GtkTerm *term)
{
switch (event->keyval) {
case GDK_Escape:
term->scan = escape;
break;
case GDK_KP_Up:
case GDK_Up:
term->scan = cursor_up;
break;
case GDK_KP_Down:
case GDK_Down:
term->scan = cursor_down;
break;
case GDK_KP_Right:
case GDK_Right:
if (event->state & GDK_SHIFT_MASK) {
term->scan = word_right;
} else {
term->scan = cursor_right;
}
break;
case GDK_KP_Left:
case GDK_Left:
if (event->state & GDK_SHIFT_MASK) {
term->scan = word_left;
} else {
term->scan = cursor_left;
}
break;
case GDK_BackSpace:
term->scan = backspace;
break;
case GDK_Delete:
case GDK_KP_Delete:
term->scan = deletekey;
break;
case GDK_KP_Insert:
case GDK_Insert:
break;
case GDK_KP_Home:
case GDK_Home:
term->scan = line_start;
break;
case GDK_KP_End:
case GDK_End:
term->scan = line_end;
break;
case GDK_KP_F1:
case GDK_F1:
term->scan = fk1;
break;
case GDK_KP_F2:
case GDK_F2:
term->scan = fk2;
break;
case GDK_KP_F3:
case GDK_F3:
term->scan = fk3;
break;
case GDK_KP_F4:
case GDK_F4:
term->scan = fk4;
break;
case GDK_F5:
term->scan = fk5;
break;
case GDK_F6:
term->scan = fk6;
break;
case GDK_F7:
term->scan = fk7;
break;
case GDK_F8:
term->scan = fk8;
break;
case GDK_F9:
term->scan = fk9;
break;
case GDK_F10:
term->scan = fk10;
break;
case GDK_F11:
case GDK_F12:
case GDK_F13:
case GDK_F14:
case GDK_F15:
case GDK_F16:
case GDK_F17:
case GDK_F18:
case GDK_F19:
case GDK_F20:
break;
case GDK_KP_Page_Up:
case GDK_Page_Up:
break;
case GDK_KP_Page_Down:
case GDK_Page_Down:
break;
case GDK_Tab:
term->scan = switch_screen;
break;
case GDK_KP_Enter:
case GDK_Return:
term->scan = enter;
term->code = 13;
break;
default:
if (event->string[0] && !(event->state & event->state & GDK_CONTROL_MASK || event->state & GDK_MOD1_MASK)) {
char ch = event->string[0];
if (deadkey) {
switch (deadkey) {
case '^':
switch (ch) {
case ' ':
ch = '^';
break;
case 'a':
ch = 'â';
break;
case 'e':
ch = 'ê';
break;
case 'i':
ch = 'î';
break;
case 'o':
ch = 'ô';
break;
case 'u':
ch = 'û';
break;
case 'A':
ch = 'Â';
break;
case 'E':
ch = 'Ê';
break;
case 'I':
ch = 'Î';
break;
case 'O':
ch = 'Ô';
break;
case 'U':
ch = 'Û';
break;
default:
{};
}
deadkey=0;
break;
case '¨':
switch (ch) {
case ' ':
ch = '¨';
break;
case 'a':
ch = 'ä';
break;
case 'e':
ch = 'ë';
break;
case 'i':
ch = 'ï';
break;
case 'o':
ch = 'ö';
break;
case 'u':
ch = 'ü';
break;
case 'y':
ch = 'ÿ';
break;
case 'A':
ch = 'Ä';
break;
case 'E':
ch = 'Ë';
break;
case 'I':
ch = 'Ï';
break;
case 'O':
ch = 'Ö';
break;
case 'U':
ch = 'Ü';
break;
default:
{};
}
deadkey=0;
break;
}
}
else
if (ch=='^' || ch=='¨') deadkey=ch;
if (!deadkey) {
if (ch==' ') term->scan = space;
term->code = ch;
}
}
break;
}
}
static gint gtk_term_key_press (GtkWidget *widget, GdkEventKey *event)
{
GtkTerm *term;
g_return_val_if_fail (widget != NULL, FALSE);
g_return_val_if_fail (GTK_IS_TERM (widget), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
term = GTK_TERM (widget);
term->code = 0; term->scan = 0;
if (term->editing) {
if (event->keyval!=GDK_KP_Insert && event->keyval!=GDK_Insert) helpn=0;
gtk_term_draw_caret(term,0);
switch (event->keyval)
{
case GDK_Escape:
term->scan = escape;
e_remove_text(term->a,term->cur,term->promptlen,e_get_text_length(term->a,term->cur)-term->promptlen);
term->pos = term->epos = term->promptlen;
if (e_get_type(term->a,term->cur)==E_UDF) {
e_append_text(term->a,term->cur,"endfunction");
term->pos += 11;
term->epos = term->pos;
}
gtk_term_update_caret(term);
gtk_term_scroll_to_pos(term);
if (!term->changed) {
g_signal_emit(GTK_OBJECT(term),gtk_term_signals[GTK_TERM_CHANGED],0);
term->changed = 1;
}
break;
case GDK_KP_Up:
case GDK_Up:
if (event->state & GDK_SHIFT_MASK) {
term->scan = cursor_up;
if (term->hist>0) {
term->hist--;
e_remove_text(term->a,term->cur,term->promptlen,e_get_text_length(term->a,term->cur)-term->promptlen);
e_append_text(term->a,term->cur,e_get_text(term->history,term->hist));
term->pos = term->epos = term->promptlen;
gtk_term_update_caret(term);
gtk_term_redraw_current(term);
term->pos = term->epos = e_get_text_length(term->a,term->cur);
gtk_term_scroll_to_pos(term);
if (!term->changed) {
g_signal_emit(GTK_OBJECT(term),gtk_term_signals[GTK_TERM_CHANGED],0);
term->changed = 1;
}
}
} else {
gtk_term_cursor_up(term);
}
break;
case GDK_KP_Down:
case GDK_Down:
if (event->state & GDK_SHIFT_MASK) {
term->scan = cursor_down;
if (term->hist<e_get_length(term->history)-1) {
term->hist++;
e_remove_text(term->a,term->cur,term->promptlen,e_get_text_length(term->a,term->cur)-term->promptlen);
e_append_text(term->a,term->cur,e_get_text(term->history,term->hist));
term->pos = term->epos = term->promptlen;
gtk_term_update_caret(term);
gtk_term_redraw_current(term);
term->pos = term->epos = e_get_text_length(term->a,term->cur);
gtk_term_scroll_to_pos(term);
if (!term->changed) {
g_signal_emit(GTK_OBJECT(term),gtk_term_signals[GTK_TERM_CHANGED],0);
term->changed = 1;
}
}
} else {
gtk_term_cursor_down(term);
}
break;
case GDK_KP_Right:
case GDK_Right:
if (event->state & GDK_SHIFT_MASK) {
term->scan = word_right;
while ((e_get_text(term->a,term->cur))[term->pos] &&
(e_get_text(term->a,term->cur))[term->pos]!=' ') term->pos++;
while ((e_get_text(term->a,term->cur))[term->pos]==' ') term->pos++;
gtk_term_scroll_to_pos(term);
term->epos = term->pos;
} else {
term->scan = cursor_right;
if (term->epos==term->pos) {
if ((e_get_text(term->a,term->cur))[term->pos]) {
term->pos++;term->epos++;
}
} else {
if (term->epos>term->pos)
term->pos = term->epos;
else
term->epos = term->pos;
}
gtk_term_scroll_to_pos(term);
}
break;
case GDK_KP_Left:
case GDK_Left:
if (event->state & GDK_SHIFT_MASK) {
term->scan = word_left;
while (term->pos>term->promptlen && (e_get_text(term->a,term->cur))[term->pos]==' ')
term->pos--;
while (term->pos>term->promptlen && (e_get_text(term->a,term->cur))[term->pos]!=' ')
term->pos--;
gtk_term_scroll_to_pos(term);
term->epos = term->pos;
} else {
term->scan = cursor_left;
if (term->epos==term->pos) {
if (term->pos>term->promptlen) {
term->pos--;term->epos--;
}
} else {
if (term->epos>term->pos)
term->epos=term->pos;
else
term->pos=term->epos;
}
gtk_term_scroll_to_pos(term);
}
break;
case GDK_BackSpace:
term->scan = backspace;
if (term->pos>term->promptlen) {
if (term->pos==term->epos) {
term->pos--;term->epos--;
gtk_term_update_caret(term);
e_remove_text(term->a,term->cur,term->pos,1);
} else {
if (term->epos>term->pos) {
e_remove_text(term->a,term->cur,term->pos,term->epos-term->pos);
term->epos = term->pos;
} else {
e_remove_text(term->a,term->cur,term->epos,term->pos-term->epos);
term->pos = term->epos;
}
}
gtk_term_scroll_to_pos(term);
if (!term->changed) {
g_signal_emit(GTK_OBJECT(term),gtk_term_signals[GTK_TERM_CHANGED],0);
term->changed = 1;
}
}
break;
case GDK_Delete:
case GDK_KP_Delete:
term->scan = deletekey;
if (term->pos<e_get_text_length(term->a,term->cur)) {
if (term->pos==term->epos) {
e_remove_text(term->a,term->cur,term->pos,1);
} else {
if (term->epos>term->pos) {
e_remove_text(term->a,term->cur,term->pos,term->epos-term->pos);
term->epos = term->pos;
} else {
e_remove_text(term->a,term->cur,term->epos,term->pos-term->epos);
term->pos = term->epos;
}
}
gtk_term_scroll_to_pos(term);
if (!term->changed) {
g_signal_emit(GTK_OBJECT(term),gtk_term_signals[GTK_TERM_CHANGED],0);
term->changed = 1;
}
}
break;
case GDK_KP_Insert:
case GDK_Insert:
if (!helpn && helphist<0)
{ gtk_term_edithelp(term);
p=0;
}
if (helphist>=0)
{
e_remove_text(term->a,term->cur,term->promptlen,e_get_text_length(term->a,term->cur)-term->promptlen);
e_append_text(term->a,term->cur,e_get_text(term->history,helphist));
term->pos = term->epos = term->promptlen;
gtk_term_update_caret(term);
gtk_term_redraw_current(term);
term->pos = term->epos = e_get_text_length(term->a,term->cur);
gtk_term_scroll_to_pos(term);
}
else if (helpnext<helpn)
{
if (p)
{
int l=strlen(p);
term->epos-=l;
e_remove_text(term->a,term->cur,term->pos,l);
gtk_term_update_caret(term);
}
p=helpextend[helpnext++];
e_insert_text(term->a,term->cur,term->pos,p);
term->epos+=strlen(p);
gtk_term_scroll_to_pos(term);
}
if (!term->changed) {
g_signal_emit(GTK_OBJECT(term),gtk_term_signals[GTK_TERM_CHANGED],0);
term->changed = 1;
}
break;
case GDK_KP_Home:
case GDK_Home:
term->scan = line_start;
term->pos = term->epos = term->promptlen;
gtk_term_scroll_to_pos(term);
break;
case GDK_KP_End:
case GDK_End:
term->scan = line_end;
term->pos = term->epos = e_get_text_length(term->a,term->cur);
gtk_term_scroll_to_pos(term);
break;
case GDK_KP_F1:
case GDK_F1:
term->scan = fk1;
gtk_term_fkinsert(term,0);
break;
case GDK_KP_F2:
case GDK_F2:
term->scan = fk2;
gtk_term_fkinsert(term,1);
break;
case GDK_KP_F3:
case GDK_F3:
term->scan = fk3;
gtk_term_fkinsert(term,2);
break;
case GDK_KP_F4:
case GDK_F4:
term->scan = fk4;
gtk_term_fkinsert(term,3);
break;
case GDK_F5:
term->scan = fk5;
gtk_term_fkinsert(term,4);
break;
case GDK_F6:
term->scan = fk6;
gtk_term_fkinsert(term,5);
break;
case GDK_F7:
term->scan = fk7;
gtk_term_fkinsert(term,6);
break;
case GDK_F8:
term->scan = fk8;
gtk_term_fkinsert(term,7);
break;
case GDK_F9:
term->scan = fk9;
gtk_term_fkinsert(term,8);
break;
case GDK_F10:
term->scan = fk10;
gtk_term_fkinsert(term,9);
break;
case GDK_F11:
case GDK_F12:
case GDK_F13:
case GDK_F14:
case GDK_F15:
case GDK_F16:
case GDK_F17:
case GDK_F18:
case GDK_F19:
case GDK_F20:
break;
case GDK_KP_Page_Up:
case GDK_Page_Up:
/* scroll the view a page up */
gtk_term_adjustment_safe_set_value(term, term->v_adj->value-term->theight+1);
break;
case GDK_KP_Page_Down:
case GDK_Page_Down:
gtk_term_adjustment_safe_set_value(term, (gfloat)MIN(term->top+term->theight-1,e_get_length(term->a)-term->theight));
/* scroll the view a page down */
break;
case GDK_Tab:
term->scan = switch_screen;
break;
case GDK_KP_Enter:
case GDK_Return:
term->scan = enter;
e_insert(term->history,e_get_length(term->history)-1,e_get_text(term->a,term->cur)+term->promptlen,0);
if (e_get_length(term->history) > term->max_history)
e_remove(term->history,0);
term->hist=e_get_length(term->history)-1;
set_editline(e_get_text(term->a,term->cur)+term->promptlen);
return TRUE;
default:
if (event->string[0] && !(event->state & event->state & GDK_CONTROL_MASK || event->state & GDK_MOD1_MASK)) {
char ch = event->string[0];
if (deadkey) {
switch (deadkey) {
case '^':
switch (ch) {
case ' ':
ch = '^';
break;
case 'a':
ch = 'â';
break;
case 'e':
ch = 'ê';
break;
case 'i':
ch = 'î';
break;
case 'o':
ch = 'ô';
break;
case 'u':
ch = 'û';
break;
case 'A':
ch = 'Â';
break;
case 'E':
ch = 'Ê';
break;
case 'I':
ch = 'Î';
break;
case 'O':
ch = 'Ô';
break;
case 'U':
ch = 'Û';
break;
default:
{};
}
deadkey=0;
break;
case '¨':
switch (ch) {
case ' ':
ch = '¨';
break;
case 'a':
ch = 'ä';
break;
case 'e':
ch = 'ë';
break;
case 'i':
ch = 'ï';
break;
case 'o':
ch = 'ö';
break;
case 'u':
ch = 'ü';
break;
case 'y':
ch = 'ÿ';
break;
case 'A':
ch = 'Ä';
break;
case 'E':
ch = 'Ë';
break;
case 'I':
ch = 'Ï';
break;
case 'O':
ch = 'Ö';
break;
case 'U':
ch = 'Ü';
break;
default:
{};
}
deadkey=0;
break;
}
}
else
if (ch=='^' || ch=='¨') deadkey=ch;
if (!deadkey) {
if (ch==' ') term->scan = space;
term->code = ch;
if (term->pos!=term->epos) {
if (term->epos>term->pos) {
e_remove_text(term->a,term->cur,term->pos,term->epos-term->pos);
term->epos = term->pos;
} else {
e_remove_text(term->a,term->cur,term->epos,term->pos-term->epos);
term->pos = term->epos;
}
}
e_insert_char(term->a,term->cur,term->pos,ch);
term->pos++;term->epos = term->pos;
gtk_term_scroll_to_pos(term);
if (!term->changed) {
g_signal_emit(GTK_OBJECT(term),gtk_term_signals[GTK_TERM_CHANGED],0);
term->changed = 1;
}
}
}
break;
}
gtk_term_draw_caret(term,1);
}
else get_scan(event,term);
if (event->state & GDK_CONTROL_MASK || event->state & GDK_MOD1_MASK)
return FALSE;
return TRUE;
}
gint gtk_term_redraw(GtkWidget *widget)
{
GtkTerm *term;
g_return_val_if_fail (widget != NULL, FALSE);
g_return_val_if_fail (GTK_IS_TERM (widget), FALSE);
term = GTK_TERM (widget);
gtk_term_redraw_current(term);
return FALSE;
}
syntax highlighted by Code2HTML, v. 0.9.1