Index: ChangeLog
===================================================================
--- ChangeLog	(revision 1630)
+++ ChangeLog	(working copy)
@@ -8,6 +8,18 @@
 gcalctool change history.
 =========================
 
+2007-08-04 Rich Burridge <rich.burridge@sun.com>
+
+    * From Afief Halumi <afief DOT h AT gmail.com>
+      gcalctool/history.c:    (new)
+      gcalctool/history.h:    (new)
+      gcalctool/functions.c:
+      gcalctool/gtk.c:
+      gcalctool/calctool.h:
+      gcalctool/get.c:
+      gcalctool/Makefile.am:
+      Fixed bug #327590 – Added a History view to gcalctool.
+
 2007-07-30 Rich Burridge <rich.burridge@sun.com>
 
     * Released a gcalctool tarball for GNOME 2.19.6.
Index: gcalctool/history.c
===================================================================
--- gcalctool/history.c	(revision 0)
+++ gcalctool/history.c	(revision 0)
@@ -0,0 +1,122 @@
+
+/*  $Header$
+ *
+ *  Copyright (c) 2007 Afief Halumi. All Rights Reserved.
+ *
+ *  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, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ *  02111-1307, USA.
+ */
+
+#include "history.h"
+#include <string.h>
+#include <stdlib.h>
+
+static item *head = NULL;     /* head is the LAST item that was inserted. */
+
+
+item *
+history_get_head()
+{
+    return(head);
+}
+
+
+item *
+history_get_previous(item *current)
+{
+    if (current == NULL) {
+        return(NULL);
+    }
+    if (current->previous == NULL) {
+        return(current);
+    } else {
+        return(current->previous);
+    }
+}
+
+
+item *
+history_get_next(item *current)
+{
+    if (current == NULL) {
+        return(NULL);    
+    }
+    if (current->next == NULL) {
+        return(current);
+    } else {
+        return(current->next);
+    }
+}
+
+
+char *
+history_get_data(item* current)
+{
+    if (current == NULL) {
+        return(NULL);
+    }
+
+    return(current->expr);
+}
+
+
+int
+add_to_linked_list(char *expr)
+{
+    item *newitem;
+    
+    newitem = malloc(sizeof(item));
+    if (newitem == NULL) {
+        return(1);
+    }
+    
+    newitem->expr = malloc(strlen(expr) + 1);
+    strcpy(newitem->expr, expr);
+    
+    newitem->next = NULL;
+    newitem->previous = NULL;
+    
+    if (head == NULL) {
+        head = newitem;
+    } else {
+        head->previous = newitem;
+        newitem->next = head;
+        head = newitem;
+    }
+    
+    return(0);
+}
+
+
+int
+history_add(char *expr)
+{
+    add_to_linked_list(expr);
+
+    return(0);
+}
+
+void
+free_history()
+{
+    item *i = head;
+    item *tmp;
+
+    while (i != NULL) {
+        tmp = i->next;
+        free(i);
+        i = tmp;
+    }
+}
Index: gcalctool/history.h
===================================================================
--- gcalctool/history.h	(revision 0)
+++ gcalctool/history.h	(revision 0)
@@ -0,0 +1,41 @@
+
+/*  $Header$
+ *
+ *  Copyright (c) 2007 Afief Halumi. All Rights Reserved.
+ *
+ *  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, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ *  02111-1307, USA.
+ */
+
+#ifndef HISTORY_H
+#define HISTORY_H
+
+typedef struct item
+{
+    char *expr;
+    struct item *previous;
+    struct item *next;
+} item;
+
+
+char *history_get_data(item *);
+
+int history_add(char *);
+
+item *history_get_head();
+item *history_get_previous(item *);
+item *history_get_next(item *);
+
+#endif /*HISTORY_H*/
Index: gcalctool/functions.c
===================================================================
--- gcalctool/functions.c	(revision 1630)
+++ gcalctool/functions.c	(working copy)
@@ -28,6 +28,7 @@
 
 #include "functions.h"
 #include "calctool.h"
+#include "history.h"
 #include "mpmath.h"
 #include "ce_parser.h"
 #include "lr_parser.h"
@@ -536,7 +537,8 @@
 		  int ret = ce_parse(e->expression, MPval);
 
 		  if (!ret) {
-			mpstr(MPval, e->ans);
+			history_add(e->expression);
+                        mpstr(MPval, e->ans);
 			exp_replace("Ans");
 		  } else {
 			char *message = NULL;
@@ -594,6 +596,10 @@
     double dval, dres;
     int MP1[MP_SIZE], MP2[MP_SIZE];
 
+    if (v->display == NULL) {
+        FPRINTF(stdout, _("NULL\n"));
+    }
+
     if (!(v->opsptr && !v->show_paren)) {  /* Don't do if processing parens. */
         if (key_equal(v->current, KEY_EQ) && 
             IS_KEY(v->old_cal_value, KEY_EQ.value[0])) {
Index: gcalctool/gtk.c
===================================================================
--- gcalctool/gtk.c	(revision 1630)
+++ gcalctool/gtk.c	(working copy)
@@ -37,6 +37,7 @@
 #include <gdk/gdkkeysyms.h>
 #include <gconf/gconf-client.h>
 #include "ce_parser.h"
+#include "history.h"
 #include "mpmath.h"
 
 #define BUT_0_BAS     X->bas_buttons[16]       /* 0 - in "Basic" mode */
@@ -97,6 +98,10 @@
     GtkWidget *cm_dialog;              /* Change Mode dialog. */
     GtkWidget *con_dialog;             /* Edit constants dialog. */
     GtkWidget *disp[MAXDISPMODES];     /* Numeric display mode. */
+    GtkWidget *display_hbox;
+    GtkWidget *history_vbox;
+    GtkWidget *history_up;             /* History up button. */
+    GtkWidget *history_down;           /* History down button. */
     GtkWidget *fun_dialog;             /* Edit functions dialog. */
     GtkWidget *hyp;                    /* Hyperbolic mode. */
     GtkWidget *inv;                    /* Inverse mode. */
@@ -142,6 +147,7 @@
 
     const gchar *mode_name;       /* Name of the new mode. */
     int menuval;                  /* Index to button array at menu time. */
+    item *history_current;
     char *lnp;                    /* Localized numerical point (UTF8 format) */
     struct button *mrec[MAXMENUS];
 };
@@ -193,6 +199,9 @@
 static void create_con_fun_menu(enum menu_type);
 static void create_menu_item_with_markup(char *, int, int);
 static void disp_cb(GtkToggleButton *, gpointer);
+static void history_proc(GtkAction *);
+static void history_down_cb(GtkWidget *, gpointer);
+static void history_up_cb(GtkWidget *, gpointer);
 static void hyp_cb(GtkToggleButton *, gpointer);
 static void inv_cb(GtkToggleButton *, gpointer);
 static void mb_proc(GtkAction *action);
@@ -341,6 +350,8 @@
       N_("Show memory registers"),    G_CALLBACK(mb_proc),   FALSE },
     { "Show",      NULL, N_("Show _Trailing Zeroes"),     "<control>T",
       N_("Show trailing zeroes"),     G_CALLBACK(astz_proc), FALSE },
+    { "History",   NULL, N_("Show _History"),             "<control>H",
+      N_("Show History"),             G_CALLBACK(history_proc), FALSE },
 };
 
 static const GtkRadioActionEntry acc_radio_entries[] = {
@@ -412,6 +423,8 @@
 "      <separator/>"
 "      <menuitem action='Memory'/>"
 "      <separator/>"
+"      <menuitem action='History'/>"
+"      <separator/>"
 "      <menuitem action='LeftRightPrecedence'/>"
 "      <menuitem action='ArithmeticPrecedence'/>"
 "    </menu>"
@@ -1520,6 +1533,16 @@
     g_object_set(gtk_ui_manager_get_action(X->ui, "/MenuBar/ViewMenu/Memory"),
                  "sensitive", (v->modetype != BASIC), NULL);
 
+    X->display_hbox = gtk_hbox_new(FALSE, 0);
+    X->history_up = gtk_button_new_with_label(_("Up"));
+    X->history_down = gtk_button_new_with_label(_("Down"));
+    X->history_vbox = gtk_vbox_new(FALSE, 0);
+
+    g_signal_connect(G_OBJECT(X->history_down), "clicked",
+                     G_CALLBACK(history_down_cb), NULL);
+    g_signal_connect(G_OBJECT(X->history_up), "clicked",
+                     G_CALLBACK(history_up_cb), NULL);
+
     X->scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
     gtk_widget_show(X->scrolledwindow);
     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (X->scrolledwindow), 
@@ -1561,7 +1584,18 @@
 
     gtk_widget_ref(X->display_item);
     gtk_container_set_border_width(GTK_CONTAINER(X->display_item), 2);
-    gtk_container_add(GTK_CONTAINER(event_box), X->scrolledwindow);
+
+    gtk_container_add(GTK_CONTAINER(event_box), X->display_hbox);
+    gtk_box_pack_start(GTK_BOX(X->display_hbox), X->scrolledwindow, 
+                       TRUE, TRUE, 0);
+
+    gtk_box_pack_start(GTK_BOX(X->display_hbox), X->history_vbox, 
+                       FALSE, TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(X->history_vbox), X->history_up, 
+                       TRUE, TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(X->history_vbox), X->history_down, 
+                       TRUE, TRUE, 0);
+
     gtk_widget_show(X->display_item);
     gtk_box_pack_start(GTK_BOX(X->kvbox), event_box, FALSE, TRUE, 0);
     gtk_widget_show(event_box);
@@ -1638,6 +1672,11 @@
     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(view_widget), TRUE);
     gcalc_window_get_menu_items(X);
 
+    gtk_check_menu_item_set_active(
+        GTK_CHECK_MENU_ITEM(gtk_ui_manager_get_widget(X->ui, 
+                            "/MenuBar/ViewMenu/History")),
+                            v->history);
+
     gconf_client_add_dir(X->client, MENU_KEY_DIR,
                          GCONF_CLIENT_PRELOAD_NONE, NULL);
     gconf_client_notify_add(X->client, MENU_KEY_DIR"/menus_have_icons",
@@ -2226,6 +2265,68 @@
 
 /*ARGSUSED*/
 static void
+history_proc(GtkAction *action)
+{
+    char intval[MAXLINE];
+
+    if (!v->started) {      /* ignore if we haven't fully stated up yet. */
+        return;
+    }
+
+    if (v->history == 0) {
+        v->history = 1;
+        gtk_widget_show(X->history_vbox);
+    } else {
+        v->history = 0;
+        gtk_widget_hide(X->history_vbox);
+    }
+
+    SNPRINTF(intval, MAXLINE, "%d", v->history);
+    put_resource(R_HISTORY, intval);
+}
+
+
+/*ARGSUSED*/
+static void 
+history_up_cb(GtkWidget *widget, gpointer   data)
+{
+    char* current;
+    GtkTextBuffer* buffer;
+
+    FPRINTF(stdout,"UP\n");
+    if (X->history_current==NULL) {
+        X->history_current = history_get_head();
+    }
+
+    X->history_current = history_get_next(X->history_current);
+    current = history_get_data(X->history_current);
+
+    buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(X->display_item));
+    gtk_text_buffer_set_text(buffer, current, -1);
+}
+
+
+/*ARGSUSED*/
+static void 
+history_down_cb(GtkWidget *widget, gpointer   data)
+{
+    char* current;
+    GtkTextBuffer* buffer;
+
+    FPRINTF(stdout,"UP\n");
+    if (X->history_current == NULL)
+        X->history_current = history_get_head();
+
+    X->history_current = history_get_previous(X->history_current);
+    current = history_get_data(X->history_current);
+
+    buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(X->display_item));
+    gtk_text_buffer_set_text(buffer, current, -1);
+}
+
+
+/*ARGSUSED*/
+static void
 hyp_cb(GtkToggleButton *button, gpointer user_data)
 {
     v->hyperbolic = !v->hyperbolic;
Index: gcalctool/calctool.h
===================================================================
--- gcalctool/calctool.h	(revision 1630)
+++ gcalctool/calctool.h	(working copy)
@@ -80,7 +80,7 @@
                 R_ZEROES,   R_TSEP, R_SYNTAX,  R_XPOS, R_YPOS,
                 R_REG0,     R_REG1, R_REG2,    R_REG3, R_REG4,
                 R_REG5,     R_REG6, R_REG7,    R_REG8, R_REG9,
-				R_BITCALC
+                R_BITCALC,  R_HISTORY
 };
 
 enum trig_type { DEG, GRAD, RAD };          /* Trigonometric types. */
@@ -355,6 +355,7 @@
     int down;          /* Indicates is a mouse button is down. */
     int error;         /* Indicates some kind of display error. */
     int math_error;    /* Math error (used in expression mode) */
+    int history;       /* Enable or disable history. */
     int hyperbolic;    /* If set, trig functions will be hyperbolic. */
     int iconic;        /* Set if window is currently iconic. */
     int inverse;       /* If set, trig and log functions will be inversed. */
Index: gcalctool/get.c
===================================================================
--- gcalctool/get.c	(revision 1630)
+++ gcalctool/get.c	(working copy)
@@ -252,6 +252,7 @@
     v->dtype         = FIX;    /* Initial number display mode. */
     v->ttype         = DEG;    /* Initial trigonometric type. */
     v->modetype      = BASIC;  /* Initial calculator mode. */
+    v->history       = 0;      /* Don't keep history. */
     v->rstate        = 0;      /* No memory register frame display initially. */
     v->iconic        = FALSE;  /* Calctool not iconic by default. */
     v->MPdebug       = FALSE;  /* No debug info by default. */
@@ -313,6 +314,15 @@
         }
     }
 
+    if (get_int_resource(R_HISTORY, &intval)) {
+        v->history = intval;
+        if (v->history != 0 && v->history != 1) {
+            FPRINTF(stderr, _("%s: history should be in 0 or 1\n"),
+                    v->progname);
+            v->history = 0;
+        }
+    }
+
     for (i = 0; i < MAXREGS; i++) {
         if (get_str_resource(R_REG0 + i, str)) {
             MPstr_to_num(str, DEC, v->MPmvals[i]);
Index: gcalctool/Makefile.am
===================================================================
--- gcalctool/Makefile.am	(revision 1630)
+++ gcalctool/Makefile.am	(working copy)
@@ -26,6 +26,8 @@
 	functions.c \
 	functions.h \
 	graphics.c \
+	history.c \
+	history.h \
 	mp.c \
 	mpmath.c \
 	mpmath.h \
