[gcalctool] More GObject refactoring



commit 78da2055527ffbd5dc2cc5780545c694e8f9500f
Author: Robert Ancell <robert ancell gmail com>
Date:   Thu Apr 8 18:46:32 2010 +1000

    More GObject refactoring

 data/buttons-programming.ui |   88 ---
 data/gcalctool.ui           |    2 +-
 src/financial.c             |    2 +-
 src/math-buttons.c          |   67 +-
 src/math-display.c          |  179 ++----
 src/math-equation.c         | 1652 ++++++++++++++++---------------------------
 src/math-equation.h         |   31 +-
 src/mp-convert.c            |    6 +-
 src/mp-equation-lexer.l     |    2 +-
 src/ui.c                    |   11 +
 10 files changed, 732 insertions(+), 1308 deletions(-)
---
diff --git a/data/buttons-programming.ui b/data/buttons-programming.ui
index 41e9931..0554bba 100644
--- a/data/buttons-programming.ui
+++ b/data/buttons-programming.ui
@@ -3113,94 +3113,6 @@
               </packing>
             </child>
             <child>
-              <object class="GtkButton" id="calc_base_2_button">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
-                <property name="border_width">3</property>
-                <property name="focus_on_click">False</property>
-                <child internal-child="accessible">
-                  <object class="AtkObject" id="calc_base_2_button-atkobject">
-                    <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the base 2 button">Base 2</property>
-                  </object>
-                </child>
-                <signal name="clicked" handler="base_cb"/>
-                <child>
-                  <object class="GtkLabel" id="base_2_label">
-                    <property name="visible">True</property>
-                    <property name="label">&lt;i&gt;x&lt;/i&gt;&lt;sub&gt;2&lt;/sub&gt;</property>
-                    <property name="use_markup">True</property>
-                  </object>
-                </child>
-              </object>
-              <packing>
-                <property name="left_attach">3</property>
-                <property name="right_attach">4</property>
-                <property name="top_attach">1</property>
-                <property name="bottom_attach">2</property>
-                <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
-                <property name="y_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton" id="calc_base_8_button">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
-                <property name="border_width">3</property>
-                <property name="focus_on_click">False</property>
-                <child internal-child="accessible">
-                  <object class="AtkObject" id="calc_base_8_button-atkobject">
-                    <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the base 8 button">Base 8</property>
-                  </object>
-                </child>
-                <signal name="clicked" handler="base_cb"/>
-                <child>
-                  <object class="GtkLabel" id="base_8_label">
-                    <property name="visible">True</property>
-                    <property name="label">&lt;i&gt;x&lt;/i&gt;&lt;sub&gt;8&lt;/sub&gt;</property>
-                    <property name="use_markup">True</property>
-                  </object>
-                </child>
-              </object>
-              <packing>
-                <property name="left_attach">4</property>
-                <property name="right_attach">5</property>
-                <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
-                <property name="y_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton" id="calc_base_16_button">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
-                <property name="border_width">3</property>
-                <property name="focus_on_click">False</property>
-                <child internal-child="accessible">
-                  <object class="AtkObject" id="calc_base_16_button-atkobject">
-                    <property name="AtkObject::accessible-name" translatable="yes" comments="Accessible name for the base 16 button">Base 16</property>
-                  </object>
-                </child>
-                <signal name="clicked" handler="base_cb"/>
-                <child>
-                  <object class="GtkLabel" id="base_16_label">
-                    <property name="visible">True</property>
-                    <property name="label">&lt;i&gt;x&lt;/i&gt;&lt;sub&gt;16&lt;/sub&gt;</property>
-                    <property name="use_markup">True</property>
-                  </object>
-                </child>
-              </object>
-              <packing>
-                <property name="left_attach">4</property>
-                <property name="right_attach">5</property>
-                <property name="top_attach">1</property>
-                <property name="bottom_attach">2</property>
-                <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
-                <property name="y_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
-              </packing>
-            </child>
-            <child>
               <object class="GtkButton" id="calc_character_button">
                 <property name="label">&#xE1;</property>
                 <property name="visible">True</property>
diff --git a/data/gcalctool.ui b/data/gcalctool.ui
index 64beae7..30df304 100644
--- a/data/gcalctool.ui
+++ b/data/gcalctool.ui
@@ -10,7 +10,7 @@
     <accel-groups>
       <group name="accelgroup1"/>
     </accel-groups>
-    <signal name="key_press_event" handler="main_window_key_press_cb"/>
+    <signal name="key_press_event" handler="main_window_key_press_cb" after="yes"/>
     <signal name="delete_event" handler="quit_cb"/>
     <child>
       <object class="GtkVBox" id="window_vbox">
diff --git a/src/financial.c b/src/financial.c
index b855f21..94a21c0 100644
--- a/src/financial.c
+++ b/src/financial.c
@@ -290,5 +290,5 @@ do_finc_expression(MathEquation *equation, int function, MPNumber *arg1, MPNumbe
        calc_term(equation, &result, arg1, arg2, arg3);
        break;
     }
-    display_set_number(equation, &result);
+    math_equation_set_number(equation, &result);
 }
diff --git a/src/math-buttons.c b/src/math-buttons.c
index 85656d6..71269c7 100644
--- a/src/math-buttons.c
+++ b/src/math-buttons.c
@@ -49,6 +49,7 @@ struct MathButtonsPrivate
     GList *superscript_toggles;
     GList *subscript_toggles;
 
+    guint64 bits;
     GtkWidget *bit_panel;
     GtkWidget *bit_labels[MAXBITS];
 
@@ -384,9 +385,6 @@ load_mode(MathButtons *buttons, ButtonMode mode)
     set_tint(GET_WIDGET(builder, "subscript_togglebutton"), &buttons->priv->colour_numbers, 2);  
     set_tint(GET_WIDGET(builder, "superscript_togglebutton"), &buttons->priv->colour_numbers, 2);
     set_tint(GET_WIDGET(builder, "calc_exponential_button"), &buttons->priv->colour_numbers, 2);
-    set_tint(GET_WIDGET(builder, "calc_base_2_button"), &buttons->priv->colour_numbers, 1);
-    set_tint(GET_WIDGET(builder, "calc_base_8_button"), &buttons->priv->colour_numbers, 1);
-    set_tint(GET_WIDGET(builder, "calc_base_16_button"), &buttons->priv->colour_numbers, 1);
 
     set_tint(GET_WIDGET(builder, "calc_result_button"), &buttons->priv->colour_action, 2);
     set_tint(GET_WIDGET(builder, "calc_factor_button"), &buttons->priv->colour_action, 2);
@@ -432,11 +430,6 @@ load_mode(MathButtons *buttons, ButtonMode mode)
     set_tint(GET_WIDGET(builder, "calc_twos_complement_button"), &buttons->priv->colour_function, 1);
     set_tint(GET_WIDGET(builder, "calc_not_button"), &buttons->priv->colour_function, 1);  
   
-    /* Set base button data */
-    set_int_data(builder, "calc_base_2_button", "base", 2);
-    set_int_data(builder, "calc_base_8_button", "base", 8);
-    set_int_data(builder, "calc_base_16_button", "base", 16);
-
     if (mode == PROGRAMMING) {
         buttons->priv->character_code_dialog = GET_WIDGET(builder, "character_code_dialog");
         buttons->priv->character_code_entry = GET_WIDGET(builder, "character_code_entry");
@@ -499,14 +492,6 @@ math_buttons_get_mode(MathButtons *buttons)
 
 G_MODULE_EXPORT
 void
-base_cb(GtkWidget *widget, MathButtons *buttons)
-{
-    math_equation_set_base(buttons->priv->equation, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "base")));
-}
-
-
-G_MODULE_EXPORT
-void
 exponent_cb(GtkWidget *widget, MathButtons *buttons)
 {
     math_equation_insert_exponent(buttons->priv->equation);
@@ -1001,7 +986,7 @@ currency_cb(GtkWidget *widget, MathButtons *buttons)
     win = GTK_DIALOG(gtk_builder_get_object(buttons->priv->financial_ui, "currency_dialog"));
     c_amount_upper = GTK_SPIN_BUTTON(gtk_builder_get_object(buttons->priv->financial_ui, "currency_amount_upper"));
     c_amount_lower = GTK_SPIN_BUTTON(gtk_builder_get_object(buttons->priv->financial_ui, "currency_amount_lower"));
-    if (display_is_usable_number(buttons->priv->equation, &display_val)) {
+    if (math_equation_get_number(buttons->priv->equation, &display_val)) {
         double start_val = mp_cast_to_double(&display_val);
         gtk_spin_button_set_value(c_amount_upper, start_val);
     }
@@ -1014,7 +999,7 @@ currency_cb(GtkWidget *widget, MathButtons *buttons)
         mp_set_from_string(result, &display_val);
         g_free(result);
 
-        display_set_number(buttons->priv->equation, &display_val);
+        math_equation_set_number(buttons->priv->equation, &display_val);
     }
 
     gtk_widget_hide(GTK_WIDGET(win));
@@ -1029,8 +1014,23 @@ character_code_dialog_response_cb(GtkWidget *dialog, gint response_id, MathButto
 
     text = gtk_entry_get_text(GTK_ENTRY(buttons->priv->character_code_entry));
 
-    if (response_id == GTK_RESPONSE_OK)
-        math_equation_insert_character(buttons->priv->equation, text);
+    if (response_id == GTK_RESPONSE_OK) {     
+        MPNumber x;
+        int i = 0;
+
+        mp_set_from_integer(0, &x);
+        while (TRUE) {
+            mp_add_integer(&x, text[i], &x);
+            if (text[i+1]) {
+                 mp_shift(&x, 8, &x);
+                 i++;
+            }
+            else
+                break;
+        }
+
+        math_equation_insert_number(buttons->priv->equation, text);
+    }
 
     gtk_widget_hide(dialog);
 }
@@ -1086,20 +1086,31 @@ set_subscript_cb(GtkWidget *widget, MathButtons *buttons)
 
 
 static void
-bitfield_changed_cb(MathEquation *equation, MathButtons *buttons)
+display_changed_cb(MathEquation *equation, MathButtons *buttons)
 {
+    gboolean enabled;
+    MPNumber x;
     int i;
-    const gchar *label;
-    guint64 bits;
 
     if (!buttons->priv->bit_panel)
        return;
 
-    gtk_widget_set_sensitive(buttons->priv->bit_panel, math_equation_get_bitfield_enabled(equation));
+    enabled = math_equation_get_number(equation, &x);
+    if (enabled) {
+        MPNumber max;
 
-    bits = math_equation_get_bitfield(equation);
+        mp_set_from_unsigned_integer(G_MAXUINT64, &max);
+        if (mp_is_negative(&x) || mp_is_greater_than(&x, &max))
+            enabled = FALSE;
+        else
+            buttons->priv->bits = mp_cast_to_unsigned_int(&x);
+    }
+
+    gtk_widget_set_sensitive(buttons->priv->bit_panel, enabled);
     for (i = 0; i < MAXBITS; i++) {
-        if (bits & (1LL << (MAXBITS-i-1)))
+        const gchar *label;
+
+        if (buttons->priv->bits & (1LL << (MAXBITS-i-1)))
             label = " 1";
         else
             label = " 0";
@@ -1141,7 +1152,9 @@ math_buttons_set_property (GObject      *object,
     case PROP_EQUATION:
         self->priv->equation = g_value_get_object (value);
         g_signal_connect(self->priv->equation, "number-mode-changed", G_CALLBACK(number_mode_changed_cb), self);
-        g_signal_connect(self->priv->equation, "bitfield-changed", G_CALLBACK(bitfield_changed_cb), self);
+        g_signal_connect(self->priv->equation, "display-changed", G_CALLBACK(display_changed_cb), self);
+        number_mode_changed_cb(self->priv->equation, self);
+        display_changed_cb(self->priv->equation, self);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
diff --git a/src/math-display.c b/src/math-display.c
index 9724576..a76af4d 100644
--- a/src/math-display.c
+++ b/src/math-display.c
@@ -21,7 +21,6 @@
 #include <gdk/gdkkeysyms.h>
 
 #include "math-display.h"
-#include "ui.h" // FIXME: TEMP
 
 enum {
     PROP_0,
@@ -55,41 +54,42 @@ math_display_get_equation(MathDisplay *display)
 
 
 static gboolean
-check_for_localized_numeric_point(MathDisplay *display, int keyval)
+display_key_press_cb(GtkWidget *widget, GdkEventKey *event, MathDisplay *display)
 {
-    gchar outbuf[10]; /* Minumum size 6. */
-    gunichar ch;
+    int state;
+    guint32 c;
 
-    ch = gdk_keyval_to_unicode(keyval);
-    g_return_val_if_fail(g_unichar_validate(ch), FALSE);
-
-    outbuf[g_unichar_to_utf8(ch, outbuf)] = '\0';
-
-    return (strcmp(outbuf, math_equation_get_numeric_point_text(display->priv->equation)) == 0);
-}
-
-
-// FIXME: Should be able to replace by making display can_default
-G_MODULE_EXPORT
-gboolean
-main_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, GCalctoolUI *ui)
-{
-    MathDisplay *display;
-    int i, state;
-    const char *conversions[]       = {"*", "/", NULL};
-    const char *conversion_values[] = {"�", "÷", NULL };
-  
-    display = ui_get_display(ui);
-
-    /* Only look at the modifiers we use */
     state = event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK);
+    c = gdk_keyval_to_unicode(event->keyval);
 
-    // FIXME: Convert event to character
-    // FIXME: Or safer to intercept characters as they enter the text input (handles input methods)
+    /* Solve on enter */
+    if (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter) {
+        math_equation_solve(display->priv->equation);
+        return TRUE;
+    }
 
-    if (check_for_localized_numeric_point(display, event->keyval) == TRUE) {
-        event->state = 0;
-        event->keyval = GDK_KP_Decimal;
+    /* Clear on escape */
+    if ((event->keyval == GDK_Escape && state == 0) ||
+        (event->keyval == GDK_BackSpace && state == GDK_CONTROL_MASK) ||
+        (event->keyval == GDK_Delete && state == GDK_SHIFT_MASK)) {
+        math_equation_clear(display->priv->equation);
+        return TRUE;
+    }
+
+    /* Substitute */
+    if (state == 0) {
+        if (c == '*') {
+            math_equation_insert(display->priv->equation, "Ã?");
+            return TRUE;
+        }
+        if (c == '/') {
+            math_equation_insert(display->priv->equation, "÷");
+            return TRUE;
+        }
+        if (c == '-') {
+            math_equation_insert_subtract(display->priv->equation);
+            return TRUE;
+        }
     }
 
     /* Shortcuts */
@@ -126,8 +126,12 @@ main_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, GCalctoolUI *ui)
         case GDK_u:
             math_equation_insert(display->priv->equation, "µ");
             return TRUE;
+        case GDK_minus:
+             math_equation_insert(display->priv->equation, "â?»");
+             return TRUE;
         }
     }
+
     if (state == GDK_CONTROL_MASK || math_equation_get_number_mode(display->priv->equation) == SUPERSCRIPT) {
         switch(event->keyval)
         {
@@ -199,105 +203,21 @@ main_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, GCalctoolUI *ui)
         }
     }
 
-    /* Delete in display */
-    if (event->keyval == GDK_Delete && state == 0 && (event->state & GDK_SHIFT_MASK) == 0) {
-        math_equation_delete(display->priv->equation);
-        return TRUE;
-    }
-    if (event->keyval == GDK_BackSpace && state == 0 && (event->state & GDK_SHIFT_MASK) == 0) {
-        math_equation_backspace(display->priv->equation);
-        return TRUE;
-    }
-
-    /* Clear display */
-    if ((event->keyval == GDK_Escape && state == 0) ||
-        (event->keyval == GDK_BackSpace && state == GDK_CONTROL_MASK) ||
-        (event->keyval == GDK_Delete && state == GDK_SHIFT_MASK)) {
-        math_equation_clear(display->priv->equation);
-        return TRUE;
-    }
-
-    /* Solve */
-    if ((event->keyval == GDK_Return && state == 0) ||
-        (event->keyval == GDK_KP_Enter && state == 0)) {
-        if (gtk_widget_has_focus(display->priv->display_item)) {
-            math_equation_solve(display->priv->equation);
-            return TRUE;
-        }
-        else {
-            return FALSE;
-        }
-    }
-
-    if (state == GDK_CONTROL_MASK && event->keyval == GDK_minus) 
-    {
-        math_equation_insert(display->priv->equation, "â?»");
-        return TRUE;
-    }
-
-    if (state != 0)
-        return FALSE;
-
-    // FIXME: event->string deprecated
-
-    if (strcmp(event->string, "-") == 0 || strcmp(event->string, "â??") == 0) {
-        math_equation_insert_subtract(display->priv->equation);
-        return TRUE;
-    }
-
-    for (i = 0; conversions[i]; i++) {
-        if (strcmp(event->string, conversions[i]) == 0) {
-            math_equation_insert(display->priv->equation, conversion_values[i]);
-            return TRUE;
-        }
-    }
-    if (strcmp(event->string, ".") == 0) {
-        math_equation_insert_numeric_point(display->priv->equation);
-        return TRUE;
-    }
-
-    /* Some keyboards use this keyval for '^' (e.g. German) */
-    if (event->keyval == GDK_dead_circumflex) {
-        math_equation_insert(display->priv->equation, "^");
-        return TRUE;
-    }
-
-    switch(*event->string)
-    {
-    case '<':
-        // FIXME: Should open left shift menu (programming mode)
-        return TRUE;
-    case '>':
-        // FIXME: Should open right shift menu (programming mode)
-        return TRUE;
-    case '\n':
-        math_equation_solve(display->priv->equation);
-        return TRUE;
-    }
-  
-    /* Don't override space - it is used in UI */
-    if (event->string[0] == ' ' && !gtk_widget_has_focus(display->priv->display_item))
-        return FALSE;
-
-    if (event->string[0] != '\0') {
-        math_equation_insert(display->priv->equation, event->string);
-        return TRUE;
-    }
-
     return FALSE;
 }
 
 
-// FIXME: Kill this
-static void
-popup_paste_cb(GtkWidget *menu, MathDisplay *display)
+static gboolean
+key_press_cb(MathDisplay *display, GdkEventKey *event)
 {
-    math_equation_paste(display->priv->equation);
+  gboolean result;
+  g_signal_emit_by_name(display->priv->display_item, "key-press-event", event, &result);
+  return result;
 }
 
 
 static gboolean
-middle_click_paste_cb(GtkWidget *widget, GdkEventButton *event, MathDisplay *display)
+button_release_cb(GtkWidget *widget, GdkEventButton *event, MathDisplay *display)
 {
     if (event->button == 2)
         math_equation_paste(display->priv->equation);
@@ -307,13 +227,6 @@ middle_click_paste_cb(GtkWidget *widget, GdkEventButton *event, MathDisplay *dis
 
 
 static void
-paste_cb(GtkWidget *widget, MathDisplay *display)
-{
-    math_equation_paste(display->priv->equation);
-}
-
-
-static void
 status_changed_cb(MathEquation *equation, MathDisplay *display)
 {
     gtk_text_buffer_set_text(display->priv->info_buffer, math_equation_get_status(equation), -1);
@@ -323,17 +236,19 @@ status_changed_cb(MathEquation *equation, MathDisplay *display)
 static void
 create_gui(MathDisplay *display)
 {
-    GtkWidget *vbox, *info_view;
+    GtkWidget *event_box, *info_view;
     PangoFontDescription *font_desc;
+  
+    g_signal_connect(display, "key-press-event", G_CALLBACK(key_press_cb), display);
 
     display->priv->display_item = gtk_text_view_new_with_buffer(GTK_TEXT_BUFFER(display->priv->equation));
-    gtk_text_view_set_editable(GTK_TEXT_VIEW(display->priv->display_item), FALSE);
+    gtk_text_view_set_accepts_tab(GTK_TEXT_VIEW(display->priv->display_item), FALSE);
     gtk_text_view_set_pixels_above_lines(GTK_TEXT_VIEW(display->priv->display_item), 8);
     gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(display->priv->display_item), 2);
     gtk_text_view_set_right_margin(GTK_TEXT_VIEW(display->priv->display_item), 6);
     gtk_text_view_set_justification(GTK_TEXT_VIEW(display->priv->display_item), GTK_JUSTIFY_RIGHT);
-    g_signal_connect(display->priv->display_item, "button-release-event", G_CALLBACK(middle_click_paste_cb), display);
-    g_signal_connect(display->priv->display_item, "paste-clipboard", G_CALLBACK(paste_cb), display);
+    g_signal_connect(display->priv->display_item, "key-press-event", G_CALLBACK(display_key_press_cb), display);
+    g_signal_connect(display->priv->display_item, "button-release-event", G_CALLBACK(button_release_cb), display);
     gtk_box_pack_start(GTK_BOX(display), display->priv->display_item, TRUE, TRUE, 0);
 
     gtk_widget_ensure_style(display->priv->display_item);
diff --git a/src/math-equation.c b/src/math-equation.c
index 2f617ba..ec0b941 100644
--- a/src/math-equation.c
+++ b/src/math-equation.c
@@ -36,48 +36,36 @@
 
 
 enum {
-    STATUS_CHANGED,
-    BITFIELD_CHANGED,
+    STATUS_CHANGED, // FIXME: Use g_object_notify and signal notify::status
+    DISPLAY_CHANGED,
     NUMBER_MODE_CHANGED,
     LAST_SIGNAL
 };
 static guint signals[LAST_SIGNAL] = { 0, };
 
-#define MAX_DIGITS 200
-#define UNDO_HISTORY_LENGTH 16  /* Arithmetic mode undo history length */
-#define MAX_DISPLAY 512
+#define MAX_DIGITS 512
 
 /* Expression mode state */
 typedef struct {
-    MPNumber ans;           /* Previously calculated answer */
-    char *expression;       /* Expression entered by user */
-    int ans_start, ans_end; /* Start and end characters for ans variable in expression */
-    int cursor;
+    MPNumber ans;              /* Previously calculated answer */
+    gchar *expression;         /* Expression entered by user */
+    gint ans_start, ans_end;   /* Start and end characters for ans variable in expression */
+    gint cursor;               /* ??? */
+    NumberMode number_mode;    /* ??? */
+    gboolean can_super_minus;  /* TRUE if entering minus can generate a superscript minus */
+    gboolean entered_multiply; /* Last insert was a multiply character */
 } MathEquationState;
 
-/* Circular list of Arithmetic Precedence Mode states*/
-typedef struct {
-  unsigned int begin;
-  unsigned int end;
-  unsigned int current;
-  MathEquationState e[UNDO_HISTORY_LENGTH];  /* Expression mode state */
-} MathEquationHistory;
-
 struct MathEquationPrivate
 {
-    gchar *status;            /* ??? */
-
-    guint64 bitfield;           // FIXME: Move into ui-buttons.c
-    gboolean bitfield_enabled;  // FIXME: Move into ui-buttons.c
-    char localized[MAX_DIGITS]; // FIXME: Obsolete now a TextBuffer
-    gint cursor;                // FIXME: Obsolete now a TextBuffer
+    gchar *status;            /* Status text */
 
     int show_tsep;            /* Set if the thousands separator should be shown. */
     int show_zeroes;          /* Set if trailing zeroes should be shown. */
     DisplayFormat format;     /* Number display mode. */
     int accuracy;             /* Number of digits to show */
-    int word_size;            /* ??? */
-    MPAngleUnit angle_unit;   /* ??? */
+    int word_size;            /* Word size in bits */
+    MPAngleUnit angle_unit;   /* Units for trigonometric functions */
     NumberMode number_mode;   /* ??? */
     gboolean can_super_minus; /* TRUE if entering minus can generate a superscript minus */
 
@@ -86,10 +74,10 @@ struct MathEquationPrivate
     const char *tsep;         /* Locale specific thousands separator. */
     int tsep_count;           /* Number of digits between separator. */
 
-    char *last_text;          /* Last text entered */
-
-    MathEquationHistory h;    /* History of expression mode states */
+    MathEquationState state;  /* Equation state */
+    GList *history;           /* History of expression mode states */
 
+    // FIXME: Replace with GtkClipboard
     GdkAtom clipboard_atom;   /* ??? */
     GdkAtom primary_atom;     /* ??? */
     char *shelf;              /* PUT selection shelf contents. */
@@ -97,25 +85,6 @@ struct MathEquationPrivate
 
 G_DEFINE_TYPE (MathEquation, math_equation, GTK_TYPE_TEXT_BUFFER);
 
-/* Available functions */
-//FIXME: Obsolete
-enum
-{
-    FN_TEXT,
-    FN_CALCULATE,
-    FN_CLEAR,
-    FN_BACKSPACE,
-    FN_DELETE,
-    FN_TOGGLE_BIT,
-    FN_SHIFT,
-    FN_FACTORIZE,
-    FN_STORE,
-    FN_RECALL,
-    FN_UNDO,
-    FN_REDO,
-    FN_PASTE,
-    FN_INSERT_CHARACTER
-};
 
 MathEquation *
 math_equation_new()
@@ -124,986 +93,524 @@ math_equation_new()
 }
 
 
-const gchar *
-math_equation_get_digit_text(MathEquation *equation, guint digit)
+//FIXME
+static void
+display_refresh(MathEquation *equation)
 {
-    return equation->priv->digits[digit];
-}
-
+    GtkTextIter iter;
 
-const gchar *
-math_equation_get_numeric_point_text(MathEquation *equation)
-{
-    return equation->priv->radix;
+    /*FIXME
+    equation->priv->cursor = display_get_cursor(equation);
+    display_make_text(equation, equation->priv->localized, MAX_DIGITS, &equation->priv->cursor);
+    gtk_text_buffer_set_text(GTK_TEXT_BUFFER(equation), equation->priv->localized, -1);
+    if (equation->priv->cursor < 0)
+        gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(equation), &iter);
+    else
+        gtk_text_buffer_get_iter_at_offset(GTK_TEXT_BUFFER(equation), &iter, equation->priv->cursor);
+    gtk_text_buffer_place_cursor(GTK_TEXT_BUFFER(equation), &iter);*/
 }
 
 
-void
-math_equation_set_status(MathEquation *equation, const gchar *status)
+static void
+display_push(MathEquation *equation)
 {
-    g_free(equation->priv->status);
-    equation->priv->status = g_strdup(status);
-    g_signal_emit(equation, signals[STATUS_CHANGED], 0);
-}
+    MathEquationState *state;
 
+    state = g_malloc0(sizeof(MathEquationState));
+    equation->priv->history = g_list_prepend(equation->priv->history, state);
 
-const gchar *
-math_equation_get_status(MathEquation *equation)
-{
-    return equation->priv->status;
+    mp_set_from_mp(&equation->priv->state.ans, &state->ans);
+    state->expression = math_equation_get_display(equation);
+    state->ans_start = equation->priv->state.ans_start;
+    state->ans_end = equation->priv->state.ans_end;
+    g_object_get(G_OBJECT(equation), "cursor-position", &state->cursor, NULL);
+    state->number_mode = equation->priv->number_mode;
+    state->can_super_minus = equation->priv->can_super_minus;
+    state->entered_multiply = equation->priv->state.entered_multiply;
 }
 
 
 static void
-math_equation_set_bitfield(MathEquation *equation, gboolean enabled, guint64 bitfield)
+display_pop(MathEquation *equation)
 {
-    equation->priv->bitfield_enabled = enabled;
-    equation->priv->bitfield = bitfield;
-    g_signal_emit(equation, signals[BITFIELD_CHANGED], 0);
-}
-
+    GList *link;
+    MathEquationState *state;
+    GtkTextIter cursor;
 
-gboolean
-math_equation_get_bitfield_enabled(MathEquation *equation)
-{
-    return equation->priv->bitfield_enabled;
-}
+    if (!equation->priv->history) {
+        math_equation_set_status(equation,
+                                 /* Error shown when trying to undo with no undo history */
+                                 _("No undo history"));
+        return;
+    }
 
+    link = equation->priv->history;
+    equation->priv->history = g_list_remove_link(equation->priv->history, link);
+    state = link->data;
+    g_list_free(link);
 
-guint64
-math_equation_get_bitfield(MathEquation *equation)
-{
-    return equation->priv->bitfield;
+    gtk_text_buffer_set_text(GTK_TEXT_BUFFER(equation), state->expression, -1);
+    gtk_text_buffer_get_iter_at_offset(GTK_TEXT_BUFFER(equation), &cursor, state->cursor);
+    gtk_text_buffer_place_cursor(GTK_TEXT_BUFFER(equation), &cursor);
+    equation->priv->state.ans_start = state->ans_start;
+    equation->priv->state.ans_end = state->ans_end;
+    math_equation_set_number_mode(equation, state->number_mode);
+    equation->priv->can_super_minus = state->can_super_minus;
+    equation->priv->state.entered_multiply = state->entered_multiply;
+    g_free(state->expression);
+    g_free(state);
 }
 
 
 const gchar *
-math_equation_get_text(MathEquation *equation)
+math_equation_get_digit_text(MathEquation *equation, guint digit)
 {
-    return equation->priv->localized;
+    return equation->priv->digits[digit];
 }
 
 
-gint
-math_equation_get_cursor(MathEquation *equation)
+const gchar *
+math_equation_get_numeric_point_text(MathEquation *equation)
 {
-    return equation->priv->cursor;
+    return equation->priv->radix;
 }
 
 
 void
-math_equation_set_number_mode(MathEquation *equation, NumberMode mode)
-{
-    if (equation->priv->number_mode == mode)
-        return;
-
-    equation->priv->can_super_minus = mode == SUPERSCRIPT;
-
-    equation->priv->number_mode = mode;
-    g_signal_emit(equation, signals[NUMBER_MODE_CHANGED], 0);
-}
-
-
-NumberMode
-math_equation_get_number_mode(MathEquation *equation)
+math_equation_set_accuracy(MathEquation *equation, int accuracy)
 {
-    return equation->priv->number_mode;
+    equation->priv->accuracy = accuracy;
+    display_refresh(equation);
 }
 
 
-static void display_do_function(MathEquation *equation, int function, gpointer arg, int cursor_start, int cursor_end);
-
-static void
-do_button(MathEquation *equation, int function, gpointer arg)
+int
+math_equation_get_accuracy(MathEquation *equation)
 {
-    GtkTextIter start, end;
-    gint cursor_start, cursor_end;
-  
-    /* Can't enter superscript minus after entering digits */
-    if (function == FN_TEXT && (strstr("�¹²³������", (char *)arg) != NULL || strcmp("�", (char *)arg) == 0))
-        equation->priv->can_super_minus = FALSE;
-
-    /* Disable super/subscript mode when finished entering */
-    if (function == FN_CALCULATE ||
-        function == FN_CLEAR ||
-        (function == FN_TEXT && strstr("â?»â?°Â¹Â²Â³â?´â?µâ?¶â?·â?¸â?¹â??â??â??â??â??â??â??â??â??â??", (char *)arg) == NULL)) {
-        math_equation_set_number_mode(equation, NORMAL);
-    }
-
-    if (gtk_text_buffer_get_selection_bounds(GTK_TEXT_BUFFER(equation), &start, &end)) {
-        cursor_start = gtk_text_iter_get_offset(&start);
-        cursor_end = gtk_text_iter_get_offset(&end);
-    }
-    else {
-        g_object_get(G_OBJECT(equation), "cursor-position", &cursor_start, NULL);
-        if (cursor_start == gtk_text_buffer_get_char_count(GTK_TEXT_BUFFER(equation)))
-            cursor_start = -1;
-        cursor_end = cursor_start;
-    }
-
-    /* Some keyboards don't have a '^' button so convert two multiplies to one '^' */
-    if (cursor_start == cursor_end &&
-        function == FN_TEXT && equation->priv->last_text != NULL &&
-        strcmp((char *)arg, "Ã?") == 0 && strcmp(equation->priv->last_text, "Ã?") == 0) {
-        do_button(equation, FN_BACKSPACE, NULL);
-        do_button(equation, FN_TEXT, "^");
-    }
-    else {
-        display_do_function(equation, function, arg, cursor_start, cursor_end);
-        if (function == FN_TEXT)
-            equation->priv->last_text = (char *)arg;
-        else
-            equation->priv->last_text = NULL;
-    }
+    return equation->priv->accuracy;
 }
 
 
 void
-math_equation_copy(MathEquation *equation)
+math_equation_set_show_thousands_separator(MathEquation *equation, gboolean visible)
 {
-    gchar *string = NULL;
-    GtkTextIter start, end;
-
-    if (gtk_text_buffer_get_selection_bounds(GTK_TEXT_BUFFER(equation), &start, &end) == TRUE)
-        string = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(equation), &start, &end, FALSE);
-    else
-        string = equation->priv->localized;
-
-    if (equation->priv->shelf != NULL)
-        g_free(equation->priv->shelf);
-    equation->priv->shelf = g_locale_from_utf8(string, strlen(string), NULL, NULL, NULL);
-    g_free(string);
-
-    gtk_clipboard_set_text(gtk_clipboard_get(equation->priv->clipboard_atom), equation->priv->shelf, -1);
+    equation->priv->show_tsep = visible;
+    display_refresh(equation);
 }
 
 
-static void
-on_paste(GtkClipboard *clipboard, const gchar *text, MathEquation *equation)
+gboolean
+math_equation_get_show_thousands_separator(MathEquation *equation)
 {
-    if (text != NULL)
-        do_button(equation, FN_PASTE, (gpointer) text);
+    return equation->priv->show_tsep;
 }
 
 
 void
-math_equation_paste(MathEquation *equation)
+math_equation_set_show_trailing_zeroes(MathEquation *equation, gboolean visible)
 {
-    gtk_clipboard_request_text(gtk_clipboard_get(equation->priv->clipboard_atom),
-                               (GtkClipboardTextReceivedFunc)on_paste, equation);
+    equation->priv->show_zeroes = visible;
+    display_refresh(equation);
 }
 
 
-void
-math_equation_store(MathEquation *equation, const gchar *name)
+gboolean
+math_equation_get_show_trailing_zeroes(MathEquation *equation)
 {
-    do_button(equation, FN_STORE, (gpointer)name);
+    return equation->priv->show_zeroes;
 }
 
 
 void
-math_equation_recall(MathEquation *equation, const gchar *name)
+math_equation_set_format(MathEquation *equation, DisplayFormat format)
 {
-    do_button(equation, FN_RECALL, (gpointer)name);
+    equation->priv->format = format;
+    display_refresh(equation);
 }
 
 
-void
-math_equation_insert(MathEquation *equation, const gchar *text)
+DisplayFormat
+math_equation_get_format(MathEquation *equation)
 {
-    do_button(equation, FN_TEXT, (gpointer) text);
+    return equation->priv->format;
 }
 
 
 void
-math_equation_insert_digit(MathEquation *equation, unsigned int digit)
+math_equation_set_word_size(MathEquation *equation, int word_size)
 {
-    static const char *subscript_digits[] = {"â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", NULL};
-    static const char *superscript_digits[] = {"�", "¹", "²", "³", "�", "�", "�", "�", "�", "�", NULL};
-
-    if (equation->priv->number_mode == NORMAL || digit >= 10)
-        math_equation_insert(equation, math_equation_get_digit_text(equation, digit));
-    else if (equation->priv->number_mode == SUPERSCRIPT)
-        math_equation_insert(equation, superscript_digits[digit]);
-    else if (equation->priv->number_mode == SUBSCRIPT)
-        math_equation_insert(equation, subscript_digits[digit]);
+    equation->priv->word_size = word_size;
 }
 
 
-void
-math_equation_insert_numeric_point(MathEquation *equation)
+int
+math_equation_get_word_size(MathEquation *equation)
 {
-    math_equation_insert(equation, math_equation_get_numeric_point_text(equation));
+    return equation->priv->word_size;
 }
 
 
 void
-math_equation_insert_exponent(MathEquation *equation)
+math_equation_set_angle_unit(MathEquation *equation, MPAngleUnit angle_unit)
 {
-    math_equation_insert(equation, "Ã?10");
-    math_equation_set_number_mode(equation, SUPERSCRIPT);
+    equation->priv->angle_unit = angle_unit;
 }
 
 
-void
-math_equation_insert_character(MathEquation *equation, const char *character)
+MPAngleUnit
+math_equation_get_angle_unit(MathEquation *equation)
 {
-    do_button(equation, FN_INSERT_CHARACTER, (gpointer)character);
+    return equation->priv->angle_unit;
 }
 
 
 void
-math_equation_insert_subtract(MathEquation *equation)
+math_equation_set_base(MathEquation *equation, gint base)
 {
-    if (equation->priv->number_mode == SUPERSCRIPT && equation->priv->can_super_minus) {
-        math_equation_insert(equation, "â?»");
-        equation->priv->can_super_minus = FALSE;
-    }
-    else {
-        math_equation_insert(equation, "â??");
-        math_equation_set_number_mode(equation, NORMAL);
-    }
+   // FIXME
 }
 
 
-void
-math_equation_solve(MathEquation *equation)
+gint
+math_equation_get_base(MathEquation *equation)
 {
-    do_button(equation, FN_CALCULATE, NULL);
+   // FIXME
+   return 0;
 }
 
 
 void
-math_equation_factorize(MathEquation *equation)
-{
-    do_button(equation, FN_FACTORIZE, NULL);
-}
-
-
-void math_equation_delete(MathEquation *equation)
-{
-    do_button(equation, FN_DELETE, NULL);  
-}
-
-
-void math_equation_backspace(MathEquation *equation)
+math_equation_set_status(MathEquation *equation, const gchar *status)
 {
-    do_button(equation, FN_BACKSPACE, NULL);  
+    g_free(equation->priv->status);
+    equation->priv->status = g_strdup(status);
+    g_signal_emit(equation, signals[STATUS_CHANGED], 0);
 }
 
 
-void
-math_equation_clear(MathEquation *equation)
+const gchar *
+math_equation_get_status(MathEquation *equation)
 {
-    do_button(equation, FN_CLEAR, NULL);  
+    return equation->priv->status;
 }
 
 
-void
-math_equation_shift(MathEquation *equation, gint count)
+gboolean
+math_equation_is_empty(MathEquation *equation)
 {
-    do_button(equation, FN_SHIFT, GINT_TO_POINTER(count));
+    return gtk_text_buffer_get_char_count(GTK_TEXT_BUFFER(equation)) == 0;
 }
 
 
-void
-math_equation_toggle_bit(MathEquation *equation, guint bit)
+gboolean
+math_equation_is_result(MathEquation *equation)
 {
-    do_button(equation, FN_TOGGLE_BIT, GINT_TO_POINTER(bit));
-}
+    char *text;
+    gboolean result;
 
+    text = math_equation_get_equation(equation);
+    result = strcmp(text, "ans") == 0;
+    g_free(text);
 
-static MathEquationState *
-get_state(MathEquation *equation)
-{
-    return &(equation->priv->h.e[equation->priv->h.current]);
+    return result;
 }
 
 
-/* Add in the thousand separators characters if required and if we are
- * currently in the decimal numeric base, use the "right" radix character.
- */
-
-/* Add in the thousand separators characters if required */
-static void
-localize_expression(MathEquation *equation, char *dest, const char *src, int dest_length, int *cursor)
+gchar *
+math_equation_get_display(MathEquation *equation)
 {
-    GString *output;
-    const char *c, *d;
-    int digit_count = -1, read_cursor, new_cursor;
-    gboolean after_radix = FALSE;
-
-    if (cursor) {
-        new_cursor = *cursor;
-    } else {
-        new_cursor = -1;
-    }
-
-    /* Scan expression looking for numbers and inserting separators */
-    output = g_string_sized_new(dest_length);
-    for (c = src, read_cursor = 1; *c; c = g_utf8_next_char(c), read_cursor++) {
-        /* Insert separators between digits */
-        if (*c >= '0' && *c <= '9') {
-            /* Read ahead to find the number of digits */
-            if (digit_count < 0) {
-                digit_count = 1;
-                for (d = c + 1; *d >= '0' && *d <= '9'; d++) {
-                    digit_count++;
-                }
-            }
-
-            g_string_append_unichar(output, g_utf8_get_char(c));
-
-            /* Insert separator after nth digit */
-            if (equation->priv->show_tsep && equation->priv->format == DEC &&
-                !after_radix && digit_count > 1 && digit_count % equation->priv->tsep_count == 1) {
-                g_string_append(output, equation->priv->tsep);
-                if (new_cursor > read_cursor) {
-                    new_cursor++;
-                }
-                read_cursor++;
-            }
-            digit_count--;
-        }
-        /* Ignore digits after the radix */
-        else if (*c == '.') {
-            digit_count = -1;
-            after_radix = TRUE;
-            g_string_append(output, equation->priv->radix);
-            // FIXME: Handle cursor if radix is more than one character?
-        }
-        /* Reset when encountering other characters (e.g. '+') */
-        else {
-            digit_count = -1;
-            after_radix = FALSE;
-            g_string_append_unichar(output, g_utf8_get_char(c));
-        }
-    }
-
-    strncpy(dest, output->str, dest_length - 1);
-    g_string_free(output, TRUE);
+    GtkTextIter start, end;
 
-    if (cursor != NULL && *cursor != -1) {
-        *cursor = new_cursor;
-    }
+    gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(equation), &start, &end);
+    return gtk_text_buffer_get_text(GTK_TEXT_BUFFER(equation), &start, &end, FALSE);
 }
 
 
-static MPNumber *
-display_get_answer(MathEquation *equation)
+gchar *
+math_equation_get_equation(MathEquation *equation)
 {
-    return &get_state(equation)->ans;
-}
+    char *text, *t;
 
+    text = math_equation_get_display(equation);
 
-static int
-display_get_cursor(MathEquation *equation)
-{
-    return get_state(equation)->cursor;
+    /* No ans to substitute */
+    if(equation->priv->state.ans_start < 0)
+        return text;
+  
+    t = g_strdup_printf("%.*sans%s", equation->priv->state.ans_start, text, g_utf8_offset_to_pointer(text, equation->priv->state.ans_end));
+    g_free(text);
+    return t;
 }
 
 
-static gboolean
-display_is_result(MathEquation *equation)
+gboolean
+math_equation_get_number(MathEquation *equation, MPNumber *z)
 {
-    MathEquationState *state;
+    gchar *text;
+    gboolean result;
 
-    state = get_state(equation);
-    if (state->ans_start == 0 && state->ans_end == g_utf8_strlen(state->expression, -1))
-        return TRUE;
+    text = math_equation_get_display(equation);
+    result = !mp_set_from_string(text, z);
+    g_free (text);
 
-    return FALSE;
+    return result;
 }
 
 
-static void
-display_make_text(MathEquation *equation, char *localized, int length, int *cursor)
+void
+math_equation_set_number_mode(MathEquation *equation, NumberMode mode)
 {
-    char *str;
-    MathEquationState *e;
-
-    e = get_state(equation);
+    if (equation->priv->number_mode == mode)
+        return;
 
-    /* Substitute answer register */
-    if (display_is_result(equation)) {
-        char temp[MAX_DIGITS];
-        display_make_number(equation, temp, MAX_DIGITS, &e->ans);
-        str = strdup(temp);
-    }
-    else
-        str = strdup(e->expression);
+    equation->priv->can_super_minus = mode == SUPERSCRIPT;
 
-    localize_expression(equation, localized, str, length, cursor);
-    free(str);
+    equation->priv->number_mode = mode;
+    g_signal_emit(equation, signals[NUMBER_MODE_CHANGED], 0);
 }
 
 
-static void
-display_refresh(MathEquation *equation)
+NumberMode
+math_equation_get_number_mode(MathEquation *equation)
 {
-    GtkTextIter iter;
-
-    equation->priv->cursor = display_get_cursor(equation);
-    display_make_text(equation, equation->priv->localized, MAX_DIGITS, &equation->priv->cursor);
-    gtk_text_buffer_set_text(GTK_TEXT_BUFFER(equation), equation->priv->localized, -1);
-    if (equation->priv->cursor < 0)
-        gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(equation), &iter);
-    else
-        gtk_text_buffer_get_iter_at_offset(GTK_TEXT_BUFFER(equation), &iter, equation->priv->cursor);
-    gtk_text_buffer_place_cursor(GTK_TEXT_BUFFER(equation), &iter);
+    return equation->priv->number_mode;
 }
 
 
-static void
-display_set_string(MathEquation *equation, const char *value, int cursor)
+void
+math_equation_copy(MathEquation *equation)
 {
-    MathEquationState *e;
-
-    if (value[0] == '\0')
-        cursor = -1;
+    gchar *string = NULL;
+    GtkTextIter start, end;
 
-    e = get_state(equation);
-    free(e->expression);
-    e->expression = strdup(value);
-    e->cursor = cursor;
+    if (!gtk_text_buffer_get_selection_bounds(GTK_TEXT_BUFFER(equation), &start, &end))
+        gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(equation), &start, &end);
 
-    display_refresh(equation);
-}
+    string = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(equation), &start, &end, FALSE);
 
-static void
-display_clear(MathEquation *equation)
-{
-    MathEquationState *state;
-
-    state = get_state(equation);
-    display_set_string(equation, "", -1);
-    state->ans_start = -1;
-    state->ans_end = -1;
-}
+    if (equation->priv->shelf != NULL)
+        g_free(equation->priv->shelf);
+    equation->priv->shelf = g_locale_from_utf8(string, strlen(string), NULL, NULL, NULL);
 
+    gtk_clipboard_set_text(gtk_clipboard_get(equation->priv->clipboard_atom), equation->priv->shelf, -1);
 
-static const char *
-get_text(MathEquation *equation)
-{
-    return get_state(equation)->expression;
+    g_free(string);
 }
 
 
-static char *
-get_expression(MathEquation *equation)
+static void
+on_paste(GtkClipboard *clipboard, const gchar *text, MathEquation *equation)
 {
-    MathEquationState *state;
-
-    state = get_state(equation);
-    if(state->ans_start >= 0)
-        return g_strdup_printf("%.*sans%s", state->ans_start, state->expression, g_utf8_offset_to_pointer(state->expression, state->ans_end));
-    else
-        return g_strdup(state->expression);
-}
-
+    const char *input;
+    char c, *output, *clean_text;
+  
+    /* Copy input to modify, no operation can make the clean string longer than
+     * the original string */
+    clean_text = strdup(text);
 
-static gboolean
-display_get_integer(MathEquation *equation, gint64 *value)
-{
-    MPNumber t, min, max;
+    output = clean_text;
+    for (input = text; *input; input++) {
+        /* If the clipboard buffer contains any occurances of the "thousands
+         * separator", remove them.
+         */
+        if (equation->priv->tsep[0] != '\0' && strncmp(input, equation->priv->tsep, strlen(equation->priv->tsep)) == 0) {
+            input += strlen(equation->priv->tsep) - 1;
+            continue;
+        }
 
-    if (!display_is_usable_number(equation, &t))
-        return FALSE;
+        /* Replace radix with "." */
+        else if (strncmp(input, equation->priv->radix, strlen(equation->priv->radix)) == 0) {
+            input += strlen(equation->priv->radix) - 1;
+            c = '.';
+        }
 
-    mp_set_from_integer(G_MININT64, &min);
-    mp_set_from_integer(G_MAXINT64, &max);
-    if (mp_is_less_than(&t, &min) || mp_is_greater_than(&t, &max))
-        return FALSE;
+        /* Replace tabs with spaces */
+        else if (*input == '\t') {
+            c = ' ';
+        }
 
-    *value = mp_cast_to_int(&t);
-    return TRUE;
-}
+        /* Terminate on newlines */
+        else if (*input == '\r' || *input == '\n') {
+            c = '\0';
+        }
 
+        /* If an "A", "B", "C", "D" or "F" character is encountered, it
+         * will be converted to its lowercase equivalent. If an "E" is
+         * found,  and the next character is a "-" or a "+", then it
+         * remains as an upper case "E" (it's assumed to be a possible
+         * exponential number), otherwise its converted to a lower case
+         * "e". See bugs #455889 and #469245 for more details.
+         */
+        else if (*input >= 'A' && *input <= 'F') {
+            c = *input;
+            if (*input == 'E') {
+                if (*(input+1) != '-' && *(input+1) != '+')
+                    c = tolower(*input);
+            }
+            else
+                c = tolower(*input);
+        }
 
-static gboolean
-display_get_unsigned_integer(MathEquation *equation, guint64 *value)
-{
-    MPNumber t, max;
+        else
+            c = *input;
 
-    if (!display_is_usable_number(equation, &t))
-        return FALSE;
-  
-    mp_set_from_unsigned_integer(G_MAXUINT64, &max);
-    char string[MAX_DIGITS];
-    if (mp_is_negative(&t) || mp_is_greater_than(&t, &max))
-        return FALSE;
+        *output++ = c;
+    }
+    *output++ = '\0';
 
-    *value = mp_cast_to_unsigned_int(&t);
-    return TRUE;
+    math_equation_insert(equation, clean_text);
 }
 
 
-// FIXME: Looses accuracy
 void
-display_set_number(MathEquation *equation, const MPNumber *x)
+math_equation_paste(MathEquation *equation)
 {
-    char text[MAX_DISPLAY];
-    int enabled;
-    guint64 bit_value;
-
-    display_make_number(equation, text, MAX_DISPLAY, x);
-    display_set_string(equation, text, -1);
-
-    enabled = display_get_unsigned_integer(equation, &bit_value);
-    math_equation_set_bitfield(equation, enabled, bit_value);
+    gtk_clipboard_request_text(gtk_clipboard_get(equation->priv->clipboard_atom),
+                               (GtkClipboardTextReceivedFunc)on_paste, equation);
 }
 
 
 void
-display_set_answer(MathEquation *equation)
-{
-    MathEquationState *state;
-    char text[MAX_DISPLAY];
-
-    state = get_state(equation);
-    display_make_number(equation, text, MAX_DISPLAY, &state->ans);
-    display_set_string(equation, text, -1);
-    state->ans_start = 0;
-    state->ans_end = g_utf8_strlen(text, -1);
-}
-
-
-static void
-display_set_cursor(MathEquation *equation, int cursor)
-{
-    MathEquationState *e;
-
-    e = get_state(equation);
-    e->cursor = cursor;
-    display_refresh(equation);
-}
-
-
-static void
-display_convert(MathEquation *equation, DisplayFormat format)
+math_equation_store(MathEquation *equation, const gchar *name)
 {
-    DisplayFormat old_format;
-
-    if (!display_is_result (equation))
-        return;
-
-    /* FIXME: A bit hacky... */
-    old_format = equation->priv->format;
-    equation->priv->format = format;
-    display_set_answer(equation);
-    equation->priv->format = old_format;
-}
-
+    MPNumber t;
 
-static void
-copy_state(MathEquationState *dst, MathEquationState *src)
-{
-    memcpy(dst, src, sizeof(MathEquationState));
-    dst->expression = strdup(src->expression);
+    if (!math_equation_get_number(equation, &t))
+        math_equation_set_status(equation, _("No sane value to store"));
+    else
+        register_set_value(name, &t);
 }
 
 
-static void
-display_clear_stack(MathEquation *equation)
+void
+math_equation_recall(MathEquation *equation, const gchar *name)
 {
-    int i = equation->priv->h.begin;
-    while (i != equation->priv->h.end) {
-        if (i != equation->priv->h.current) {
-            free(equation->priv->h.e[i].expression);
-            equation->priv->h.e[i].expression = NULL;
-        }
-        i = ((i + 1) % UNDO_HISTORY_LENGTH);
-    }
-    equation->priv->h.begin = equation->priv->h.end = equation->priv->h.current;
+    math_equation_insert(equation, name);
 }
 
 
-static void
-display_push(MathEquation *equation)
-{
-    int c;
-
-    if (equation->priv->h.current != equation->priv->h.end) {
-        int i = equation->priv->h.current;
-
-        do {
-            i = ((i + 1) % UNDO_HISTORY_LENGTH);
-            free(equation->priv->h.e[i].expression);
-            equation->priv->h.e[i].expression = strdup("ans"); // FIXME: Use actual number
-            equation->priv->h.e[i].ans_start = -1;
-            equation->priv->h.e[i].ans_end = -1;
-        } while (i != equation->priv->h.end);
-    }
-
-    equation->priv->h.end = equation->priv->h.current;
-
-    c = equation->priv->h.current;
-    equation->priv->h.end = equation->priv->h.current = ((equation->priv->h.current + 1) % UNDO_HISTORY_LENGTH);
-    if (equation->priv->h.current == equation->priv->h.begin) {
-        free(equation->priv->h.e[equation->priv->h.begin].expression);
-        equation->priv->h.e[equation->priv->h.begin].expression = NULL;
-        equation->priv->h.begin = ((equation->priv->h.begin + 1) % UNDO_HISTORY_LENGTH);
-    }
-
-    copy_state(&(equation->priv->h.e[equation->priv->h.current]), &(equation->priv->h.e[c]));
-}
-
+void
+math_equation_set(MathEquation *equation, const gchar *text)
 
-static void
-display_pop(MathEquation *equation)
 {
-    if (equation->priv->h.current != equation->priv->h.begin) {
-        equation->priv->h.current = ((equation->priv->h.current - 1) % UNDO_HISTORY_LENGTH);
-        math_equation_set_status(equation, "");
-    } else {
-        math_equation_set_status(equation, _("No undo history"));
-    }
+    display_push(equation);
 
-    display_refresh(equation);
+    gtk_text_buffer_set_text(GTK_TEXT_BUFFER(equation), text, -1);
+    equation->priv->state.ans_start = -1;
+    equation->priv->state.ans_end = -1;
 }
 
 
-static void
-display_unpop(MathEquation *equation)
+void
+math_equation_set_answer(MathEquation *equation)
 {
-    if (equation->priv->h.current != equation->priv->h.end) {
-        equation->priv->h.current = ((equation->priv->h.current + 1) % UNDO_HISTORY_LENGTH);
-        math_equation_set_status(equation, "");
-    } else {
-        math_equation_set_status(equation, _("No redo steps"));
-    }
-    get_state(equation)->cursor = -1;
-    display_refresh(equation);
-}
+    char text[MAX_DIGITS];
 
-
-static gboolean
-display_is_undo_step(MathEquation *equation)
-{
-    return(equation->priv->h.current != equation->priv->h.begin);
+    display_push(equation);
+  
+    display_make_number(equation, text, MAX_DIGITS, &equation->priv->state.ans);
+    math_equation_set(equation, text);
+    equation->priv->state.ans_start = 0;
+    equation->priv->state.ans_end = g_utf8_strlen(text, -1);
 }
 
 
-static void
-display_insert(MathEquation *equation, int cursor_start, int cursor_end, const char *text)
+void
+math_equation_set_number(MathEquation *equation, const MPNumber *x)
 {
-    MathEquationState *state;   
-    char buf[MAX_DISPLAY];
-
-    state = get_state(equation);
-
-    /* If inside ans variable then modify number */
-    if (state->ans_start >= 0 && cursor_start >= state->ans_start && cursor_start <= state->ans_end) {
-        state->ans_start = -1;
-        state->ans_end = -1;
-    }
-
-    if (cursor_start < 0) {
-        snprintf(buf, MAX_DISPLAY, "%s%s", get_text(equation), text);
-        display_set_string(equation, buf, -1);
-    } else {
-        GString *new_text;
-        const char *c;
-        gint cursor, new_cursor;
-
-        /* Get display text and strip out thousand separators */
-        new_text = g_string_new("");
-        new_cursor = 0;
-        if (cursor_start == 0) {
-            g_string_append(new_text, text);
-            new_cursor += g_utf8_strlen(text, -1);
-        }
-
-        cursor = 0;
-        for (c = equation->priv->localized; *c; c = g_utf8_next_char(c), cursor++) {
-            gboolean use = TRUE;
-
-            /* Ignore selected part */
-            if (cursor_start != cursor_end && cursor >= cursor_start && cursor < cursor_end)
-                use = FALSE;
-
-            /* Ignore thousands separators (if one exists) */
-            if (equation->priv->tsep[0] != '\0' && strncmp(c, equation->priv->tsep, strlen(equation->priv->tsep)) == 0)
-                use = FALSE;
-
-            /* Copy existing text */
-            if (use) {
-                g_string_append_unichar(new_text, g_utf8_get_char(c));
-                if (cursor < cursor_start)
-                    new_cursor++;
-            }
-
-            /* Insert text */
-            if ((cursor + 1) == cursor_start) {
-                g_string_append(new_text, text);
-                new_cursor += g_utf8_strlen(text, -1);
-            }
-        }
-        display_set_string(equation, new_text->str, new_cursor);
-        g_string_free(new_text, TRUE);
-    }
-
-}
+    char text[MAX_DIGITS];
 
+    display_push(equation);
 
-static void
-display_insert_number(MathEquation *equation, int cursor_start, int cursor_end, const MPNumber *value)
-{
-    char text[MAX_DISPLAY];
-    display_make_number(equation, text, MAX_DISPLAY, value);
-    display_insert(equation, cursor_start, cursor_end, text);
+    display_make_number(equation, text, MAX_DIGITS, x);
+    math_equation_set(equation, text);
 }
 
 
-static gboolean
-display_is_empty(MathEquation *equation)
+void
+math_equation_insert(MathEquation *equation, const gchar *text)
 {
-    return strcmp(get_text(equation), "") == 0;
-}
+    display_push(equation);
 
+    /* Replace ** with ^ (not on all keyboards) */
+    if (!gtk_text_buffer_get_has_selection(GTK_TEXT_BUFFER(equation)) &&
+        strcmp(text, "Ã?") == 0 && equation->priv->state.entered_multiply) {
+        GtkTextIter iter;
 
-static void
-display_backspace(MathEquation *equation, int cursor_start, int cursor_end)
-{
-    int cursor;
-
-    /* Can't delete empty display */
-    if (display_is_empty(equation))
+        gtk_text_buffer_get_iter_at_mark(GTK_TEXT_BUFFER(equation), &iter, gtk_text_buffer_get_insert(GTK_TEXT_BUFFER(equation)));
+        gtk_text_buffer_backspace(GTK_TEXT_BUFFER(equation), &iter, TRUE, TRUE);
+        gtk_text_buffer_insert_at_cursor(GTK_TEXT_BUFFER(equation), "^", -1);
         return;
-
-    cursor = display_get_cursor(equation);
-
-    /* If cursor is at end of the line then delete the last character preserving accuracy */
-    if (cursor_start < 0) {
-        int len;
-        len = g_utf8_strlen(equation->priv->localized, -1);
-        display_insert(equation, len - 1, len, "");
-    } else if (cursor_start != cursor_end) {
-        display_insert(equation, cursor_start, cursor_end, "");
-    } else if (cursor_start > 0) {
-        display_insert(equation, cursor_start - 1, cursor_start, "");
-    }
-
-}
-
-static void
-display_delete(MathEquation *equation, int cursor_start, int cursor_end)
-{
-    /* Delete selected block */
-    if (cursor_start != cursor_end)
-        display_insert(equation, cursor_start, cursor_end, "");
-    else if (cursor_start >= 0)
-        display_insert(equation, cursor_start, cursor_start + 1, "");
-}
-
-
-gboolean
-display_is_usable_number(MathEquation *equation, MPNumber *z)
-{
-    if (display_is_empty(equation)) {
-        mp_set_from_integer(0, z);
-        return TRUE;
-    } else if (display_is_result(equation)) {
-        mp_set_from_mp(display_get_answer(equation), z);
-        return TRUE;
-    } else {
-        return mp_set_from_string(get_text(equation), z) == 0;
     }
-}
 
+    /* Start new equation when entering digits after existing result */
+    if(math_equation_is_result(equation) && g_unichar_isdigit(g_utf8_get_char(text)))
+        gtk_text_buffer_set_text(GTK_TEXT_BUFFER(equation), "", -1);
 
-static gboolean
-display_is_number_with_base(MathEquation *equation)
-{
-    MPNumber t;
-    const char *text;
-    const char *sub_digits[] = { "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", NULL };
-    int i;
-
-    if (display_is_empty(equation))
-        return FALSE;
-
-    if (display_is_result(equation))
-        return (equation->priv->format == BIN || equation->priv->format == OCT || equation->priv->format == HEX);
-
-    /* See if it has a subscript suffix */
-    text = get_text(equation);
-    text += strlen (text);
-    for (i = 0; sub_digits[i] != NULL; i++) {
-        if (strcmp (text - strlen (sub_digits[i]), sub_digits[i]) == 0)
-            return mp_set_from_string(get_text(equation), &t) == 0;
-    }
+    /* Can't enter superscript minus after entering digits */
+    if (strstr("�¹²³������", text) != NULL || strcmp("�", text) == 0)
+        equation->priv->can_super_minus = FALSE;
 
-    return FALSE;
-}
+    /* Disable super/subscript mode when finished entering */
+    if (strstr("â?»â?°Â¹Â²Â³â?´â?µâ?¶â?·â?¸â?¹â??â??â??â??â??â??â??â??â??â??", text) == NULL)
+        math_equation_set_number_mode(equation, NORMAL);
 
+    // FIXME: Add thousands separators
 
-void
-math_equation_set_accuracy(MathEquation *equation, int accuracy)
-{
-    equation->priv->accuracy = accuracy;
-    get_state(equation)->cursor = -1;
-    display_refresh(equation);
+    gtk_text_buffer_delete_selection(GTK_TEXT_BUFFER(equation), FALSE, FALSE);
+    gtk_text_buffer_insert_at_cursor(GTK_TEXT_BUFFER(equation), text, -1);
 }
 
 
 void
-math_equation_set_show_thousands_separator(MathEquation *equation, gboolean visible)
+math_equation_insert_digit(MathEquation *equation, unsigned int digit)
 {
-    equation->priv->show_tsep = visible;
-    display_set_cursor(equation, -1);
-    display_refresh(equation);
-}
-
+    static const char *subscript_digits[] = {"â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", "â??", NULL};
+    static const char *superscript_digits[] = {"�", "¹", "²", "³", "�", "�", "�", "�", "�", "�", NULL};
 
-void
-math_equation_set_show_trailing_zeroes(MathEquation *equation, gboolean visible)
-{
-    equation->priv->show_zeroes = visible;
-    get_state(equation)->cursor = -1;
-    display_refresh(equation);
+    if (equation->priv->number_mode == NORMAL || digit >= 10)
+        math_equation_insert(equation, math_equation_get_digit_text(equation, digit));
+    else if (equation->priv->number_mode == SUPERSCRIPT)
+        math_equation_insert(equation, superscript_digits[digit]);
+    else if (equation->priv->number_mode == SUBSCRIPT)
+        math_equation_insert(equation, subscript_digits[digit]);
 }
 
 
 void
-math_equation_set_format(MathEquation *equation, DisplayFormat format)
+math_equation_insert_numeric_point(MathEquation *equation)
 {
-    equation->priv->format = format;
-    get_state(equation)->cursor = -1;
-    display_refresh(equation);
+    math_equation_insert(equation, math_equation_get_numeric_point_text(equation));
 }
 
 
 void
-math_equation_set_word_size(MathEquation *equation, int word_size)
+math_equation_insert_number(MathEquation *equation, const MPNumber *x)
 {
-    equation->priv->word_size = word_size;
+    char text[MAX_DIGITS];
+    display_make_number(equation, text, MAX_DIGITS, x);
+    math_equation_insert(equation, text);
 }
 
 
 void
-math_equation_set_angle_unit(MathEquation *equation, MPAngleUnit angle_unit)
+math_equation_insert_exponent(MathEquation *equation)
 {
-    equation->priv->angle_unit = angle_unit;
+    math_equation_insert(equation, "Ã?10");
+    math_equation_set_number_mode(equation, SUPERSCRIPT);
 }
 
 
 void
-math_equation_set_base(MathEquation *equation, gint base)
+math_equation_insert_subtract(MathEquation *equation)
 {
-    /* If has a number already in a base, then solve and convert it */
-    if (!display_is_result(equation) && display_is_number_with_base(equation))
-        math_equation_solve(equation);
-
-    if (display_is_result(equation)) {
-        if (base == 2)
-            display_convert(equation, BIN);
-        else if (base == 8)
-            display_convert(equation, OCT);
-        else if (base == 16)
-            display_convert(equation, HEX);
-        else
-            display_convert(equation, DEC);
+    if (equation->priv->number_mode == SUPERSCRIPT && equation->priv->can_super_minus) {
+        math_equation_insert(equation, "â?»");
+        equation->priv->can_super_minus = FALSE;
     }
     else {
-        if (base == 2)
-            math_equation_insert(equation, "â??");
-        else if (base == 8)
-            math_equation_insert(equation, "â??");
-        else if (base == 16)
-            math_equation_insert(equation, "â??â??");
-    }
-}
-
-
-/* Convert engineering or scientific number in the given base. */
-static void
-make_eng_sci(MathEquation *equation, char *target, int target_len, const MPNumber *x, int base_)
-{
-    char fixed[MAX_DIGITS], *c;
-    MPNumber t, z, base, base3, base10, base10inv, mantissa;
-    int eng, exponent = 0;
-    GString *string;
-    const char *super_digits[] = {"�", "¹", "²", "³", "�", "�", "�", "�", "�", "�"};
-
-    string = g_string_sized_new(target_len);
-
-    eng = equation->priv->format == ENG;
-
-    mp_abs(x, &z);
-    if (mp_is_negative(x))
-        g_string_append(string, "â??");
-    mp_set_from_mp(&z, &mantissa);
-
-    mp_set_from_integer(base_, &base);
-    mp_xpowy_integer(&base, 3, &base3);
-    mp_xpowy_integer(&base, 10, &base10);
-    mp_set_from_integer(1, &t);
-    mp_divide(&t, &base10, &base10inv);
-
-    if (!mp_is_zero(&mantissa)) {
-        while (!eng && mp_is_greater_equal(&mantissa, &base10)) {
-            exponent += 10;
-            mp_multiply(&mantissa, &base10inv, &mantissa);
-        }
-
-        while ((!eng &&  mp_is_greater_equal(&mantissa, &base)) ||
-                (eng && (mp_is_greater_equal(&mantissa, &base3) || exponent % 3 != 0))) {
-            exponent += 1;
-            mp_divide(&mantissa, &base, &mantissa);
-        }
-
-        while (!eng && mp_is_less_than(&mantissa, &base10inv)) {
-            exponent -= 10;
-            mp_multiply(&mantissa, &base10, &mantissa);
-        }
-
-        mp_set_from_integer(1, &t);
-        while (mp_is_less_than(&mantissa, &t) || (eng && exponent % 3 != 0)) {
-            exponent -= 1;
-            mp_multiply(&mantissa, &base, &mantissa);
-        }
-    }
-
-    mp_cast_to_string(&mantissa, base_, equation->priv->accuracy, !equation->priv->show_zeroes, fixed, MAX_DIGITS);
-    g_string_append(string, fixed);
-    g_string_append_printf(string, "Ã?10");
-    if (exponent < 0) {
-        exponent = -exponent;
-        g_string_append(string, "â?»");
-    }
-    snprintf(fixed, MAX_DIGITS, "%d", exponent);
-    for (c = fixed; *c; c++)
-        g_string_append(string, super_digits[*c - '0']);
-
-    strncpy(target, string->str, target_len);
-    g_string_free(string, TRUE);
-}
-
-
-/* Convert MP number to character string. */
-void
-display_make_number(MathEquation *equation, char *target, int target_len, const MPNumber *x)
-{
-    switch(equation->priv->format) {
-    case DEC:
-        mp_cast_to_string(x, 10, equation->priv->accuracy, !equation->priv->show_zeroes, target, target_len);
-        break;
-    case BIN:
-        mp_cast_to_string(x, 2, equation->priv->accuracy, !equation->priv->show_zeroes, target, target_len);
-        break;
-    case OCT:
-        mp_cast_to_string(x, 8, equation->priv->accuracy, !equation->priv->show_zeroes, target, target_len);
-        break;
-    case HEX:
-        mp_cast_to_string(x, 16, equation->priv->accuracy, !equation->priv->show_zeroes, target, target_len);
-        break;
-    case SCI:
-        make_eng_sci(equation, target, target_len, x, 10);
-        break;
-    case ENG:
-        make_eng_sci(equation, target, target_len, x, 10);
-        break;
+        math_equation_insert(equation, "â??");
+        math_equation_set_number_mode(equation, NORMAL);
     }
 }
 
@@ -1143,7 +650,7 @@ get_variable(const char *name, MPNumber *z, void *data)
     if (strcmp(lower_name, "rand") == 0)
         mp_set_from_random(z);
     else if (strcmp(lower_name, "ans") == 0)
-        mp_set_from_mp(display_get_answer(equation), z);
+        mp_set_from_mp(&equation->priv->state.ans, z);
     else {
         t = register_get_value(name);
         if (t)
@@ -1201,306 +708,319 @@ parse(MathEquation *equation, const char *text, MPNumber *z, char **error_token)
 }
 
 
-static void
-do_paste(MathEquation *equation, int cursor_start, int cursor_end, const char *text)
+void
+math_equation_solve(MathEquation *equation)
 {
-    const char *input;
-    char c, *output, *clean_text;
+    MPNumber z;
+    int result;
+    gchar *text, *error_token = NULL, *message = NULL;
+  
+    if (math_equation_is_empty(equation))
+        return;
 
-    /* Copy input to modify, no operation can make the clean string longer than
-     * the original string */
-    clean_text = strdup(text);
+    /* If showing a result return to the equation that caused it */
+    // FIXME: Result may not be here due to solve (i.e. the user may have entered "ans")
+    if (math_equation_is_result(equation)) {
+        display_pop(equation);
+        return;
+    }
 
-    output = clean_text;
-    for (input = text; *input; input++) {
-        /* If the clipboard buffer contains any occurances of the "thousands
-         * separator", remove them.
-         */
-        if (equation->priv->tsep[0] != '\0' && strncmp(input, equation->priv->tsep, strlen(equation->priv->tsep)) == 0) {
-            input += strlen(equation->priv->tsep) - 1;
-            continue;
-        }
+    display_push(equation);
 
-        /* Replace radix with "." */
-        else if (strncmp(input, equation->priv->radix, strlen(equation->priv->radix)) == 0) {
-            input += strlen(equation->priv->radix) - 1;
-            c = '.';
-        }
+    math_equation_set_number_mode(equation, NORMAL);
 
-        /* Replace tabs with spaces */
-        else if (*input == '\t') {
-            c = ' ';
-        }
+    text = math_equation_get_equation(equation);
+    result = parse(equation, text, &z, &error_token);
+    g_free(text);
 
-        /* Terminate on newlines */
-        else if (*input == '\r' || *input == '\n') {
-            c = '\0';
-        }
+    switch (result) {
+        case PARSER_ERR_NONE:
+            mp_set_from_mp(&z, &equation->priv->state.ans);
+            math_equation_set_answer(equation);
+            break;
 
-        /* If an "A", "B", "C", "D" or "F" character is encountered, it
-         * will be converted to its lowercase equivalent. If an "E" is
-         * found,  and the next character is a "-" or a "+", then it
-         * remains as an upper case "E" (it's assumed to be a possible
-         * exponential number), otherwise its converted to a lower case
-         * "e". See bugs #455889 and #469245 for more details.
-         */
-        else if (*input >= 'A' && *input <= 'F') {
-            c = *input;
-            if (*input == 'E') {
-                if (*(input+1) != '-' && *(input+1) != '+')
-                    c = tolower(*input);
-            }
-            else
-                c = tolower(*input);
-        }
+        case PARSER_ERR_OVERFLOW:
+            message = g_strdup(/* Error displayed to user when they perform a bitwise operation on numbers greater than the current word */
+                               _("Overflow. Try a bigger word size"));
+            break;
 
-        else
-            c = *input;
+        case PARSER_ERR_UNKNOWN_VARIABLE:
+            message = g_strdup_printf(/* Error displayed to user when they an unknown variable is entered */
+                                      _("Unknown variable '%s'"), error_token);
+            break;
 
-        *output++ = c;
-    }
-    *output++ = '\0';
+        case PARSER_ERR_UNKNOWN_FUNCTION:
+            message = g_strdup_printf(/* Error displayed to user when an unknown function is entered */
+                                      _("Function '%s' is not defined"), error_token);
+            break;
 
-    display_insert(equation, cursor_start, cursor_end, clean_text);
-}
+        case PARSER_ERR_UNKNOWN_CONVERSION:
+            message = g_strdup(/* Error displayed to user when an conversion with unknown units is attempted */
+                               _("Unknown conversion"));
+            break;
 
+        case PARSER_ERR_MP:
+            message = g_strdup(mp_get_error());
+            break;
 
-static void
-do_insert_character(MathEquation *equation, const unsigned char *text)
-{
-    MPNumber value;
-    int i = 0;
-    mp_set_from_integer(0, &value);
-    while (TRUE) {
-        mp_add_integer(&value, text[i], &value);
-        if (text[i+1]) {
-            mp_shift(&value, 8, &value);
-            i++;
-        } else {
+        default:
+            message = g_strdup(/* Error displayed to user when they enter an invalid calculation */
+                               _("Malformed expression"));
             break;
-        }
     }
-    display_set_number(equation, &value);
+
+    if (error_token)
+        free(error_token);
+  
+    if (message) {
+        math_equation_set_status(equation, message);
+        g_free(message);
+    }
 }
 
 
-/* Perform bitwise shift on display value. */
-static void
-do_shift(MathEquation *equation, int count)
+void
+math_equation_factorize(MathEquation *equation)
 {
-    MPNumber z;
-
-    if (!display_is_usable_number(equation, &z)) {
-        /* Translators: This message is displayed in the status bar when a bit
-           shift operation is performed and the display does not contain a number */
-        math_equation_set_status(equation, _("No sane value to bitwise shift"));
+    MPNumber x;
+    GList *factors, *factor;
+    GString *text;
+  
+    if (!math_equation_get_number(equation, &x) || !mp_is_integer(&x)) {
+        /* Error displayed when trying to factorize a non-integer value */
+        math_equation_set_status(equation, _("Need an integer to factorize"));
+        return;
     }
-    else {
-        mp_shift(&z, count, display_get_answer(equation));
-        display_set_answer(equation);
+
+    factors = mp_factorize(&x);
+
+    text = g_string_new("");
+
+    for (factor = factors; factor; factor = factor->next) {
+        gchar temp[MAX_DIGITS];
+        MPNumber *n;
+
+        n = factor->data;
+        display_make_number(equation, temp, MAX_DIGITS, n);
+        g_string_append(text, temp);
+        if (factor->next)
+            g_string_append(text, "Ã?");
+        g_slice_free(MPNumber, n);
     }
+    g_list_free(factors);
+
+    math_equation_set(equation, text->str);
+    g_string_free(text, TRUE);
 }
 
 
-static void
-do_factorize(MathEquation *equation)
+void
+math_equation_delete(MathEquation *equation)
 {
-    MPNumber value;
+    gint cursor;
+    GtkTextIter start, end;    
 
-    if (!display_is_usable_number(equation, &value)) {
-        /* Translators: Error displayed when trying to factorize a non-integer value */
-        math_equation_set_status(equation, _("Need an integer to factorize"));
+    g_object_get(G_OBJECT(equation), "cursor-position", &cursor, NULL);
+    if (cursor >= gtk_text_buffer_get_char_count(GTK_TEXT_BUFFER(equation)))
         return;
-    }
-    display_clear(equation);
 
-    GList *factors = mp_factorize(&value);
+    display_push(equation);
+
+    gtk_text_buffer_get_iter_at_offset(GTK_TEXT_BUFFER(equation), &start, cursor);
+    gtk_text_buffer_get_iter_at_offset(GTK_TEXT_BUFFER(equation), &end, cursor+1);
+    gtk_text_buffer_delete(GTK_TEXT_BUFFER(equation), &start, &end);
+}
+
 
-    display_insert_number(equation, -1, -1, factors->data);
-    g_slice_free(MPNumber, factors->data);
+void
+math_equation_backspace(MathEquation *equation)
+{
+    /* Can't delete empty display */
+    if (math_equation_is_empty(equation))
+        return;
 
-    GList *list = factors->next;
-    for (; list != NULL; list = list->next) {
-            display_insert(equation, -1, -1, "Ã?");
-            display_insert_number(equation, -1, -1, list->data);
-            g_slice_free(MPNumber, list->data);
+    display_push(equation);
+
+    if (gtk_text_buffer_get_has_selection(GTK_TEXT_BUFFER(equation)))
+        gtk_text_buffer_delete_selection(GTK_TEXT_BUFFER(equation), FALSE, FALSE);
+    else {
+        GtkTextIter iter;
+        gtk_text_buffer_get_iter_at_mark(GTK_TEXT_BUFFER(equation), &iter, gtk_text_buffer_get_insert(GTK_TEXT_BUFFER(equation)));
+        gtk_text_buffer_backspace(GTK_TEXT_BUFFER(equation), &iter, TRUE, TRUE);
     }
-    g_list_free(factors);
 }
 
 
-static void
-do_sto(MathEquation *equation, const char *name)
+void
+math_equation_clear(MathEquation *equation)
 {
-    MPNumber t;
+    MathEquationState *state;
 
-    if (!display_is_usable_number(equation, &t))
-        math_equation_set_status(equation, _("No sane value to store"));
-    else
-        register_set_value(name, &t);
+    math_equation_set_number_mode(equation, NORMAL);
+    math_equation_set(equation, "");
 }
 
 
-static void
-display_do_function(MathEquation *equation, int function, gpointer arg, int cursor_start, int cursor_end)
+void
+math_equation_shift(MathEquation *equation, gint count)
 {
-    MPNumber *ans;
-    int enabled;
-    guint64 bit_value;
+    MPNumber z;
 
-    switch (function) {
-        case FN_UNDO:
-            display_pop(equation);
-            return;
+    if (!math_equation_get_number(equation, &z)) {
+        math_equation_set_status(equation,
+                                 /* This message is displayed in the status bar when a bit
+                                  shift operation is performed and the display does not contain a number */
+                                 _("No sane value to bitwise shift"));
+        return;
+    }
 
-        case FN_REDO:
-            display_unpop(equation);
-            return;
+    display_push(equation);
+    
+    mp_shift(&z, count, &equation->priv->state.ans);
+    math_equation_set_answer(equation);
+}
 
-        default:
-            break;
+
+void
+math_equation_toggle_bit(MathEquation *equation, guint bit)
+{
+    MPNumber x;
+    guint64 bits;
+    gboolean result;
+
+    result = math_equation_get_number(equation, &x);
+    if (result) {
+        MPNumber max;
+        mp_set_from_unsigned_integer(G_MAXUINT64, &max);
+        if (mp_is_negative(&x) || mp_is_greater_than(&x, &max))
+            result = FALSE;
+        else
+            bits = mp_cast_to_unsigned_int(&x);
     }
 
-    display_push(equation);
+    if (!result) {
+        math_equation_set_status(equation,
+                                 /* Message displayed when cannot toggle bit in display*/
+                                 _("Displayed value not an integer"));
+        return;
+    }
 
-    display_set_cursor(equation, cursor_start);
-    ans = display_get_answer(equation);
+    bits ^= (1LL << (63 - bit));
 
-    math_equation_set_status(equation, "");
+    mp_set_from_unsigned_integer(bits, &x);
+    math_equation_set_number(equation, &x);
+}
 
-    switch (function) {
-        case FN_CLEAR:
-            display_clear(equation);
-            break;
 
-        case FN_SHIFT:
-            do_shift(equation, GPOINTER_TO_INT (arg));
-            break;
+static gboolean
+display_get_integer(MathEquation *equation, gint64 *value)
+{
+    MPNumber t, min, max;
 
-        case FN_FACTORIZE:
-            do_factorize(equation);
-            break;
+    if (!math_equation_get_number(equation, &t))
+        return FALSE;
 
-        case FN_PASTE:
-            do_paste(equation, cursor_start, cursor_end, (const char *)arg);
-            return;
+    mp_set_from_integer(G_MININT64, &min);
+    mp_set_from_integer(G_MAXINT64, &max);
+    if (mp_is_less_than(&t, &min) || mp_is_greater_than(&t, &max))
+        return FALSE;
 
-        case FN_INSERT_CHARACTER:
-            do_insert_character(equation, (const unsigned char *)arg);
-            return;
+    *value = mp_cast_to_int(&t);
+    return TRUE;
+}
 
-        case FN_STORE:
-            do_sto(equation, (const char *)arg);
-            return;
 
-        case FN_RECALL:
-            display_insert(equation, cursor_start, cursor_end, (const char *)arg);
-            break;
+/* Convert engineering or scientific number in the given base. */
+// FIXME: Move into mp-convert.c
+static void
+make_eng_sci(MathEquation *equation, char *target, int target_len, const MPNumber *x, int base_)
+{
+    char fixed[MAX_DIGITS], *c;
+    MPNumber t, z, base, base3, base10, base10inv, mantissa;
+    int eng, exponent = 0;
+    GString *string;
+    const char *super_digits[] = {"�", "¹", "²", "³", "�", "�", "�", "�", "�", "�"};
 
-        case FN_BACKSPACE:
-            display_backspace(equation, cursor_start, cursor_end);
-            break;
+    string = g_string_sized_new(target_len);
 
-        case FN_DELETE:
-            display_delete(equation, cursor_start, cursor_end);
-            break;
+    eng = equation->priv->format == ENG;
 
-        case FN_TOGGLE_BIT:
-            if (display_get_unsigned_integer(equation, &bit_value)) {
-                char buf[MAX_DISPLAY];
-                MPNumber MP;
+    mp_abs(x, &z);
+    if (mp_is_negative(x))
+        g_string_append(string, "â??");
+    mp_set_from_mp(&z, &mantissa);
 
-                bit_value ^= (1LL << (63 - GPOINTER_TO_INT (arg)));
+    mp_set_from_integer(base_, &base);
+    mp_xpowy_integer(&base, 3, &base3);
+    mp_xpowy_integer(&base, 10, &base10);
+    mp_set_from_integer(1, &t);
+    mp_divide(&t, &base10, &base10inv);
 
-                /* FIXME: Convert to string since we don't support setting MP numbers from 64 bit integers */
-                snprintf(buf, MAX_DISPLAY, "%" G_GUINT64_FORMAT, bit_value);
-                mp_set_from_string(buf, &MP);
-                display_set_number(equation, &MP);
-            }
-            break;
+    if (!mp_is_zero(&mantissa)) {
+        while (!eng && mp_is_greater_equal(&mantissa, &base10)) {
+            exponent += 10;
+            mp_multiply(&mantissa, &base10inv, &mantissa);
+        }
 
-        case FN_CALCULATE:
-            /* If showing a result display the calculation that caused
-             * this result */
-            /* TODO: Work out why two undo steps are required and why
-             * the cursor must be taken from the first undo */
-            if (display_is_result(equation)) {
-                display_pop(equation);
-                if (display_is_undo_step(equation)) {
-                    display_pop(equation);
-                }
-
-            /* Do nothing */
-            } else if (display_is_empty(equation)) {
-                ;
-
-            /* Solve the equation */
-            } else {
-                MPNumber z;
-                int result;
-                const char *message = NULL;
-                char *text, *error_token;
-
-                text = get_expression (equation);
-                result = parse(equation,
-                               text,
-                               &z,
-                               &error_token);
-                g_free(text);
-
-                switch (result) {
-                    case PARSER_ERR_NONE:
-                        mp_set_from_mp(&z, ans);
-                        display_set_answer(equation);
-                        break;
-
-                    case PARSER_ERR_OVERFLOW:
-                        /* Translators: Error displayed to user when they perform a bitwise operation on numbers greater than the current word */
-                        message = _("Overflow. Try a bigger word size");
-                        break;
-
-                    case PARSER_ERR_UNKNOWN_VARIABLE:
-                        /* Translators: Error displayed to user when they an unknown variable is entered */
-                        message = g_strdup_printf(_("Unknown variable '%s'"), error_token);
-                        free(error_token);
-                        break;
-
-                    case PARSER_ERR_UNKNOWN_FUNCTION:
-                        /* Translators: Error displayed to user when an unknown function is entered */
-                        message = g_strdup_printf(_("Function '%s' is not defined"), error_token);
-                        free(error_token);
-                        break;
-
-                    case PARSER_ERR_UNKNOWN_CONVERSION:
-                        /* Translators: Error displayed to user when an conversion with unknown units is attempted */
-                        message = g_strdup_printf(_("Unknown conversion"));
-                        break;
-
-                    case PARSER_ERR_MP:
-                        message = mp_get_error();
-                        break;
-
-                    default:
-                        /* Translators: Error displayed to user when they enter an invalid calculation */
-                        message = _("Malformed expression");
-                        break;
-                }
-                if (message)
-                    math_equation_set_status(equation, message);
-            }
-            break;
+        while ((!eng &&  mp_is_greater_equal(&mantissa, &base)) ||
+                (eng && (mp_is_greater_equal(&mantissa, &base3) || exponent % 3 != 0))) {
+            exponent += 1;
+            mp_divide(&mantissa, &base, &mantissa);
+        }
+
+        while (!eng && mp_is_less_than(&mantissa, &base10inv)) {
+            exponent -= 10;
+            mp_multiply(&mantissa, &base10, &mantissa);
+        }
 
-        case FN_TEXT:
-            /* Start new equation when entering digits after existing result */
-            if(display_is_result(equation) && g_unichar_isdigit(g_utf8_get_char((char*)arg)))
-                display_clear(equation);
+        mp_set_from_integer(1, &t);
+        while (mp_is_less_than(&mantissa, &t) || (eng && exponent % 3 != 0)) {
+            exponent -= 1;
+            mp_multiply(&mantissa, &base, &mantissa);
+        }
+    }
 
-            display_insert(equation, cursor_start, cursor_end, (const char *)arg);
-            break;
+    mp_cast_to_string(&mantissa, base_, equation->priv->accuracy, !equation->priv->show_zeroes, fixed, MAX_DIGITS);
+    g_string_append(string, fixed);
+    g_string_append_printf(string, "Ã?10");
+    if (exponent < 0) {
+        exponent = -exponent;
+        g_string_append(string, "â?»");
     }
+    snprintf(fixed, MAX_DIGITS, "%d", exponent);
+    for (c = fixed; *c; c++)
+        g_string_append(string, super_digits[*c - '0']);
 
-    enabled = display_get_unsigned_integer(equation, &bit_value);
-    math_equation_set_bitfield(equation, enabled, bit_value);
+    strncpy(target, string->str, target_len);
+    g_string_free(string, TRUE);
+}
+
+
+/* Convert MP number to character string. */
+//FIXME: What to do with this?
+void
+display_make_number(MathEquation *equation, char *target, int target_len, const MPNumber *x)
+{
+    switch(equation->priv->format) {
+    case DEC:
+        mp_cast_to_string(x, 10, equation->priv->accuracy, !equation->priv->show_zeroes, target, target_len);
+        break;
+    case BIN:
+        mp_cast_to_string(x, 2, equation->priv->accuracy, !equation->priv->show_zeroes, target, target_len);
+        break;
+    case OCT:
+        mp_cast_to_string(x, 8, equation->priv->accuracy, !equation->priv->show_zeroes, target, target_len);
+        break;
+    case HEX:
+        mp_cast_to_string(x, 16, equation->priv->accuracy, !equation->priv->show_zeroes, target, target_len);
+        break;
+    case SCI:
+        make_eng_sci(equation, target, target_len, x, 10);
+        break;
+    case ENG:
+        make_eng_sci(equation, target, target_len, x, 10);
+        break;
+    }
 }
 
 
@@ -1519,11 +1039,11 @@ math_equation_class_init (MathEquationClass *klass)
                       NULL, NULL,
                       g_cclosure_marshal_VOID__VOID,
                       G_TYPE_NONE, 0);
-    signals[BITFIELD_CHANGED] =
-        g_signal_new ("bitfield-changed",
+    signals[DISPLAY_CHANGED] =
+        g_signal_new ("display-changed",
                       G_TYPE_FROM_CLASS (klass),
                       G_SIGNAL_RUN_LAST,
-                      G_STRUCT_OFFSET (MathEquationClass, bitfield_changed),
+                      G_STRUCT_OFFSET (MathEquationClass, display_changed),
                       NULL, NULL,
                       g_cclosure_marshal_VOID__VOID,
                       G_TYPE_NONE, 0);
@@ -1539,9 +1059,42 @@ math_equation_class_init (MathEquationClass *klass)
 
 
 static void
+solve_cb (MathEquation *equation)
+{
+    math_equation_solve(equation);
+}
+
+
+static void
+insert_text_cb (MathEquation  *equation,
+                GtkTextIter   *location,
+                gchar         *text,
+                gint           len,
+                gpointer       user_data)
+{
+    equation->priv->state.entered_multiply = strcmp(text, "Ã?") == 0;
+
+    // FIXME: Check if have split/appended ans
+    g_signal_emit(equation, signals[DISPLAY_CHANGED], 0);
+}
+
+
+static void
+delete_range_cb (MathEquation  *equation,
+                 GtkTextIter   *start,
+                 GtkTextIter   *end,
+                 gpointer       user_data)
+{
+    // FIXME: Check if have joined/deleted ans
+    // FIXME: A replace will emit this both for delete-range and insert-text, can it be avoided?
+    g_signal_emit(equation, signals[DISPLAY_CHANGED], 0);  
+}
+
+
+static void
 math_equation_init(MathEquation *equation)
 {
-    /* Translators: Digits localized for the given language */
+    /* Digits localized for the given language */
     const char *digit_values = _("0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F");
     const char *default_digits[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};
     gchar **digits;
@@ -1550,6 +1103,9 @@ math_equation_init(MathEquation *equation)
 
     equation->priv = G_TYPE_INSTANCE_GET_PRIVATE (equation, math_equation_get_type(), MathEquationPrivate);
 
+    g_signal_connect_after(equation, "insert-text", G_CALLBACK(insert_text_cb), equation);
+    g_signal_connect_after(equation, "delete-range", G_CALLBACK(delete_range_cb), equation);
+
     digits = g_strsplit(digit_values, ",", -1);
     for (i = 0; i < 16; i++) {
         if (use_default_digits || digits[i] == NULL) {
@@ -1561,10 +1117,12 @@ math_equation_init(MathEquation *equation)
     }
     g_strfreev(digits);
 
-    equation->priv->radix = get_radix();   /* Locale specific radix string. */
-    equation->priv->tsep = get_tsep();     /* Locale specific thousands separator. */
+    // FIXME: Take out of get.c
+    equation->priv->radix = get_radix();
+    equation->priv->tsep = get_tsep();
     equation->priv->tsep_count = get_tsep_count();
 
+    // Use GtkClipboad instead
     equation->priv->primary_atom = gdk_atom_intern("PRIMARY", FALSE);
     equation->priv->clipboard_atom = gdk_atom_intern("CLIPBOARD", FALSE);
 
@@ -1576,9 +1134,7 @@ math_equation_init(MathEquation *equation)
     equation->priv->word_size = 32;
     equation->priv->angle_unit = MP_DEGREES;
 
-    for (i = 0; i < UNDO_HISTORY_LENGTH; i++) {
-        equation->priv->h.e[i].expression = strdup("");
-        equation->priv->h.e[i].ans_start = -1;
-        equation->priv->h.e[i].ans_end = -1;
-    }
+    mp_set_from_integer(0, &equation->priv->state.ans);
+    equation->priv->state.ans_start = -1;
+    equation->priv->state.ans_end = -1;
 }
diff --git a/src/math-equation.h b/src/math-equation.h
index ea60df9..ea2c0b2 100644
--- a/src/math-equation.h
+++ b/src/math-equation.h
@@ -40,8 +40,9 @@ typedef struct
 {
     GtkTextBufferClass parent_class;
 
-    void (*status_changed)(MathEquation *display);  
-    void (*bitfield_changed)(MathEquation *display);
+    void (*status_changed)(MathEquation *display);
+    void (*display_changed)(MathEquation *display);
+//FIXME    void (*equation_changed)(MathEquation *display);
     void (*number_mode_changed)(MathEquation *display);
 } MathEquationClass;
 
@@ -63,31 +64,49 @@ const gchar *math_equation_get_numeric_point_text(MathEquation *equation);
 void math_equation_set_status(MathEquation *equation, const gchar *status);
 const gchar *math_equation_get_status(MathEquation *equation);
 
-gboolean math_equation_get_bitfield_enabled(MathEquation *equation);
-guint64 math_equation_get_bitfield(MathEquation *equation);
+gboolean math_equation_is_empty(MathEquation *equation);
+gboolean math_equation_is_result(MathEquation *equation);
+gchar *math_equation_get_display(MathEquation *equation);
+gchar *math_equation_get_equation(MathEquation *equation);
+gboolean math_equation_get_number(MathEquation *equation, MPNumber *z);
 
 void math_equation_set_number_mode(MathEquation *equation, NumberMode mode);
 NumberMode math_equation_get_number_mode(MathEquation *equation);
 
 //FIXME: Make get_
 void math_equation_set_accuracy(MathEquation *equation, int accuracy);
+int math_equation_get_accuracy(MathEquation *equation);
+
 void math_equation_set_show_thousands_separator(MathEquation *equation, gboolean visible);
+gboolean math_equation_get_show_thousands_separator(MathEquation *equation);
+
 void math_equation_set_show_trailing_zeroes(MathEquation *equation, gboolean visible);
+gboolean math_equation_get_show_trailing_zeroes(MathEquation *equation);
+
 void math_equation_set_format(MathEquation *equation, DisplayFormat format);
+DisplayFormat math_equation_get_format(MathEquation *equation);
+
 void math_equation_set_word_size(MathEquation *equation, int word_size);
+int math_equation_get_word_size(MathEquation *equation);
+
 void math_equation_set_angle_unit(MathEquation *equation, MPAngleUnit angle_unit);
+MPAngleUnit math_equation_get_angle_unit(MathEquation *equation);
+
 void math_equation_set_base(MathEquation *equation, gint base);
+gint math_equation_get_base(MathEquation *equation);
 
 void math_equation_copy(MathEquation *equation);
 void math_equation_paste(MathEquation *equation);
 void math_equation_store(MathEquation *equation, const gchar *name);
 void math_equation_recall(MathEquation *equation, const gchar *name);
+void math_equation_set(MathEquation *equation, const gchar *text);
+void math_equation_set_answer(MathEquation *equation);
+void math_equation_set_number(MathEquation *equation, const MPNumber *x);
 void math_equation_insert(MathEquation *equation, const gchar *text);
 void math_equation_insert_digit(MathEquation *equation, guint digit);
 void math_equation_insert_numeric_point(MathEquation *equation);
 void math_equation_insert_subtract(MathEquation *equation);
 void math_equation_insert_exponent(MathEquation *equation);
-void math_equation_insert_character(MathEquation *equation, const gchar *character);
 void math_equation_solve(MathEquation *equation);
 void math_equation_factorize(MathEquation *equation);
 void math_equation_delete(MathEquation *equation);
@@ -97,8 +116,6 @@ void math_equation_shift(MathEquation *equation, gint count);
 void math_equation_toggle_bit(MathEquation *equation, guint bit);
 
 //FIXME: Obsolete
-void display_set_number(MathEquation *equation, const MPNumber *);
-gboolean display_is_usable_number(MathEquation *equation, MPNumber *);
 void display_make_number(MathEquation *equation, char *target, int target_len, const MPNumber *x);
 
 #endif /* MATH_EQUATION_H */
diff --git a/src/mp-convert.c b/src/mp-convert.c
index 7d19b2a..575b1c4 100644
--- a/src/mp-convert.c
+++ b/src/mp-convert.c
@@ -597,12 +597,12 @@ mp_cast_to_string(const MPNumber *x, int base, int accuracy, bool trim_zeroes, c
 {
     MPNumber x_real, x_im;
     GString *string;
-    
+
     string = g_string_sized_new(buffer_length);
-    
+
     mp_real_component(x, &x_real);
     mp_imaginary_component(x, &x_im);
-    
+
     mp_cast_to_string_real(&x_real, base, accuracy, trim_zeroes, FALSE, string);
     if (mp_is_complex(x)) {
         GString *s;
diff --git a/src/mp-equation-lexer.l b/src/mp-equation-lexer.l
index a3fd1ab..91638ea 100644
--- a/src/mp-equation-lexer.l
+++ b/src/mp-equation-lexer.l
@@ -103,7 +103,7 @@ IN   [iI][nN]
         return tVARIABLE;\
     }\
 }
-[ \t\n]
+[ \r\t\n]
 .           {return *yytext;}
 
 %%
diff --git a/src/ui.c b/src/ui.c
index 7828de2..44a2409 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -19,6 +19,7 @@
 
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
 
 #include "ui.h"
 #include "ui-preferences.h"
@@ -178,6 +179,16 @@ mode_changed_cb(GtkWidget *menu, GCalctoolUI *ui)
 
 
 G_MODULE_EXPORT
+gboolean
+main_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, GCalctoolUI *ui)
+{
+    gboolean result;
+    g_signal_emit_by_name(ui->priv->display, "key-press-event", event, &result);
+    return result;
+}
+
+
+G_MODULE_EXPORT
 void
 show_preferences_cb(GtkMenuItem *menu, GCalctoolUI *ui)
 {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]