[dasher: 135/217] Updated the SettingsStore class so it can handle application parameters.\nUpdated the GTK code so it



commit e543079ef2471e398472d930965e0c9a0738c6f2
Author: lbaudoin <lbaudoin google com>
Date:   Sun Dec 6 09:08:33 2015 -0700

    Updated the SettingsStore class so it can handle application parameters.\nUpdated the GTK code so it 
saves the window posistion on exit.\n

 Src/Common/AppSettingsData.h        |   74 ++----
 Src/DasherCore/Observable.h         |    1 +
 Src/DasherCore/Parameters.cpp       |  234 ++++++++--------
 Src/DasherCore/Parameters.h         |    5 +-
 Src/DasherCore/SettingsStore.cpp    |  222 ++++++++------
 Src/DasherCore/SettingsStore.h      |   28 ++-
 Src/Gtk2/DasherAppSettings.cpp      |  547 ++++-------------------------------
 Src/Gtk2/DasherAppSettings.h        |  120 ++++----
 Src/Gtk2/GenerateSchema.cpp         |   12 +-
 Src/Gtk2/GtkDasherControl.cpp       |   23 +--
 Src/Gtk2/KeyboardHelper.cpp         |    6 +-
 Src/Gtk2/Preferences.cpp            |  110 ++++----
 Src/Gtk2/dasher_editor.cpp          |    9 +-
 Src/Gtk2/dasher_editor.h            |    3 +-
 Src/Gtk2/dasher_editor_private.h    |    3 +-
 Src/Gtk2/dasher_main.cpp            |  131 +++++----
 Src/Gtk2/dasher_main.h              |    1 +
 Src/Gtk2/dasher_main_private.h      |    1 +
 Src/Gtk2/module_settings_window.cpp |   16 +-
 Src/Win32/AppSettings.cpp           |   26 +-
 Src/main.cc                         |    8 +-
 21 files changed, 578 insertions(+), 1002 deletions(-)
---
diff --git a/Src/Common/AppSettingsData.h b/Src/Common/AppSettingsData.h
index acd42d4..45467e4 100644
--- a/Src/Common/AppSettingsData.h
+++ b/Src/Common/AppSettingsData.h
@@ -1,39 +1,11 @@
 #include "AppSettingsHeader.h"
+#include "../DasherCore/Parameters.h"
 
 // This file is an include file purely for the purposes of
 // cross-platform consistency. IT WILL NOT LINK IF INCLUDED IN MORE
 // THAN ONE PLACE! You probably want to obtain values via the
 // application settings object instead.
 
-#define PERS true
-
-struct app_bp_table {
-  int key;
-  const char *regName;
-  bool persistent;
-  bool bDefaultValue;
-  bool value;
-  const char *humanReadable;
-};
-
-struct app_lp_table {
-  int key;
-  const char *regName;
-  bool persistent;
-  long iDefaultValue;
-  long value;
-  const char *humanReadable;
-};
-
-struct app_sp_table {
-  int key;
-  const char *regName;
-  bool persistent;
-  const char *szDefaultValue;
-  char *value;
-  const char *humanReadable;
-};
-
 // The following tables contain details of the application specific
 // settings. Fields are:
 //
@@ -51,39 +23,39 @@ struct app_sp_table {
 // Human-readable Name: Used for help text etc. Please make sure this
 // is useful
 
-app_bp_table app_boolparamtable[] = {
-  { APP_BP_TIME_STAMP, "TimeStampNewFiles", PERS, true, true, "TimeStampNewFiles" },
-  { APP_BP_CONFIRM_UNSAVED, "ConfirmUnsavedFiles", PERS, true, true, "ConfirmUnsavedFiles" },
-  {APP_BP_SHOW_TOOLBAR, "ViewToolbar", PERS, true, true, "ViewToolbar"},
+Dasher::Settings::bp_table app_boolparamtable[] = {
+  { APP_BP_TIME_STAMP, "TimeStampNewFiles", Persistence::PERSISTENT, true, "TimeStampNewFiles" },
+  { APP_BP_CONFIRM_UNSAVED, "ConfirmUnsavedFiles", Persistence::PERSISTENT, true, "ConfirmUnsavedFiles" },
+  {APP_BP_SHOW_TOOLBAR, "ViewToolbar", Persistence::PERSISTENT, true, "ViewToolbar"},
 #ifdef WITH_MAEMO
-  { APP_BP_SHOW_STATUSBAR, "ViewStatusbar", PERS, false, false, "ViewStatusbar" },
+  { APP_BP_SHOW_STATUSBAR, "ViewStatusbar", Persistence::PERSISTENT, false, "ViewStatusbar" },
 #else
-  { APP_BP_SHOW_STATUSBAR, "ViewStatusbar", PERS, true, true, "ViewStatusbar" },
+  { APP_BP_SHOW_STATUSBAR, "ViewStatusbar", Persistence::PERSISTENT, true, "ViewStatusbar" },
 #endif
 
 };
 
-app_lp_table app_longparamtable[] = {
-  {APP_LP_EDIT_FONT_SIZE, "EditFontSize", PERS, 0, 0, "EditFontSize"},
-  {APP_LP_EDIT_HEIGHT, "EditHeight", PERS, 75, 75, "The height of the edit window"},
-  {APP_LP_EDIT_WIDTH, "EditWidth", PERS, 200, 200, "EditWidth"},
-  {APP_LP_SCREEN_WIDTH, "ScreenWidth", PERS, 400, 400, "ScreenWidth"},
-  {APP_LP_SCREEN_HEIGHT, "ScreenHeight", PERS, 500, 500, "ScreenHeight"},
-  {APP_LP_SCREEN_WIDTH_H, "ScreenWidthH", PERS, 625, 625, "Screen Width for application style compose"},
-  {APP_LP_SCREEN_HEIGHT_H, "ScreenHeightH", PERS, 250, 250, "Screen Height for application style compose"},
-  {APP_LP_STYLE, "AppStyle", PERS, 0, 0, "Application style"},
-  {APP_LP_X, "XPosition", PERS, 100, 100, "X location of window"},
-  {APP_LP_Y, "YPosition", PERS, 100, 100, "Y location of window"},
+Dasher::Settings::lp_table app_longparamtable[] = {
+  {APP_LP_EDIT_FONT_SIZE, "EditFontSize", Persistence::PERSISTENT, 0, "EditFontSize"},
+  {APP_LP_EDIT_HEIGHT, "EditHeight", Persistence::PERSISTENT, 75, "The height of the edit window"},
+  {APP_LP_EDIT_WIDTH, "EditWidth", Persistence::PERSISTENT, 200, "EditWidth"},
+  {APP_LP_SCREEN_WIDTH, "ScreenWidth", Persistence::PERSISTENT, 400, "ScreenWidth"},
+  {APP_LP_SCREEN_HEIGHT, "ScreenHeight", Persistence::PERSISTENT, 500, "ScreenHeight"},
+  {APP_LP_SCREEN_WIDTH_H, "ScreenWidthH", Persistence::PERSISTENT, 625, "Screen Width for application style 
compose"},
+  {APP_LP_SCREEN_HEIGHT_H, "ScreenHeightH", Persistence::PERSISTENT, 250, "Screen Height for application 
style compose"},
+  {APP_LP_STYLE, "AppStyle", Persistence::PERSISTENT, 0, "Application style"},
+  {APP_LP_X, "XPosition", Persistence::PERSISTENT, 100, "X location of window"},
+  {APP_LP_Y, "YPosition", Persistence::PERSISTENT, 100, "Y location of window"},
 #ifdef WITH_MAEMO
-  {APP_LP_MAEMO_SIZE, "MaemoSize", PERS, 0, 0, "Size of Maemo input window"},
+  {APP_LP_MAEMO_SIZE, "MaemoSize", Persistence::PERSISTENT, 0, "Size of Maemo input window"},
 #endif
 };
 
-app_sp_table app_stringparamtable[] = {
+Dasher::Settings::sp_table app_stringparamtable[] = {
 #ifdef WITH_MAEMO
-  {APP_SP_EDIT_FONT, "EditFont", PERS, "Sans 20", NULL, "EditFont"},
+  {APP_SP_EDIT_FONT, "EditFont", Persistence::PERSISTENT, "Sans 20", "EditFont"},
 #else
-  {APP_SP_EDIT_FONT, "EditFont", PERS, "Sans 10", NULL, "EditFont"},
+  {APP_SP_EDIT_FONT, "EditFont", Persistence::PERSISTENT, "Sans 10", "EditFont"},
 #endif
-  {APP_SP_WINDOW_STATE, "WindowState", PERS, "", NULL, "WindowState"},
+  {APP_SP_WINDOW_STATE, "WindowState", Persistence::PERSISTENT, "", "WindowState"},
 };
diff --git a/Src/DasherCore/Observable.h b/Src/DasherCore/Observable.h
index 921256d..e83749c 100644
--- a/Src/DasherCore/Observable.h
+++ b/Src/DasherCore/Observable.h
@@ -9,6 +9,7 @@ template <typename  T> class Observable;
 ///Thing that listens to events - parameterized by the type of event.
 template <typename T> class Observer {
 public:
+  virtual ~Observer() = default;
   ///Called to indicate an event has occurred! Subclasses must implement.
   virtual void HandleEvent(T evt)=0;
 };
diff --git a/Src/DasherCore/Parameters.cpp b/Src/DasherCore/Parameters.cpp
index 9bbc7cd..6f2c3a6 100644
--- a/Src/DasherCore/Parameters.cpp
+++ b/Src/DasherCore/Parameters.cpp
@@ -6,150 +6,150 @@ namespace Dasher{
 // The important thing here is that these are in the same order
 // as the enum declarations (could add check in class that enforces this instead)
 const bp_table boolparamtable[] = {
-  {BP_DRAW_MOUSE_LINE, "DrawMouseLine", true, "Draw Mouse Line"},
-  {BP_DRAW_MOUSE, "DrawMouse", false, "Draw Mouse Position"},
-  {BP_CURVE_MOUSE_LINE, "CurveMouseLine", false, "Curve mouse line according to screen nonlinearity"},
-  {BP_START_MOUSE, "StartOnLeft", true, "StartOnLeft"},
-  {BP_START_SPACE, "StartOnSpace", false, "StartOnSpace"},
-  {BP_CONTROL_MODE, "ControlMode", false, "ControlMode"},
-  {BP_MOUSEPOS_MODE, "StartOnMousePosition", false, "StartOnMousePosition"},
-  {BP_PALETTE_CHANGE, "PaletteChange", true, "PaletteChange"},
-  {BP_TURBO_MODE, "TurboMode", true, "Boost speed when holding key1 or right mouse button"},
-  {BP_EXACT_DYNAMICS, "ExactDynamics", false, "Use exact computation of per-frame movement (slower)"},
-  {BP_AUTOCALIBRATE, "Autocalibrate", false, "Automatically learn TargetOffset e.g. gazetracking"},
-  {BP_REMAP_XTREME, "RemapXtreme", false, "Pointer at extreme Y translates more and zooms less"},
-  {BP_AUTO_SPEEDCONTROL, "AutoSpeedControl", true, "AutoSpeedControl"},
-  {BP_LM_ADAPTIVE, "LMAdaptive", true, "Whether language model should learn as you enter text"},
-  {BP_SOCKET_DEBUG, "SocketInputDebug", false, "Print information about socket input processing to console"},
-  {BP_CIRCLE_START, "CircleStart", false, "Start on circle mode"},
-  {BP_GLOBAL_KEYBOARD, "GlobalKeyboard", false, "Whether to assume global control of the keyboard"},
+  {BP_DRAW_MOUSE_LINE, "DrawMouseLine", Persistence::PERSISTENT, true, "Draw Mouse Line"},
+  {BP_DRAW_MOUSE, "DrawMouse", Persistence::PERSISTENT, false, "Draw Mouse Position"},
+  {BP_CURVE_MOUSE_LINE, "CurveMouseLine", Persistence::PERSISTENT, false, "Curve mouse line according to 
screen nonlinearity"},
+  {BP_START_MOUSE, "StartOnLeft", Persistence::PERSISTENT, true, "StartOnLeft"},
+  {BP_START_SPACE, "StartOnSpace", Persistence::PERSISTENT, false, "StartOnSpace"},
+  {BP_CONTROL_MODE, "ControlMode", Persistence::PERSISTENT, false, "ControlMode"},
+  {BP_MOUSEPOS_MODE, "StartOnMousePosition", Persistence::PERSISTENT, false, "StartOnMousePosition"},
+  {BP_PALETTE_CHANGE, "PaletteChange", Persistence::PERSISTENT, true, "PaletteChange"},
+  {BP_TURBO_MODE, "TurboMode", Persistence::PERSISTENT, true, "Boost speed when holding key1 or right mouse 
button"},
+  {BP_EXACT_DYNAMICS, "ExactDynamics", Persistence::PERSISTENT, false, "Use exact computation of per-frame 
movement (slower)"},
+  {BP_AUTOCALIBRATE, "Autocalibrate", Persistence::PERSISTENT, false, "Automatically learn TargetOffset e.g. 
gazetracking"},
+  {BP_REMAP_XTREME, "RemapXtreme", Persistence::PERSISTENT, false, "Pointer at extreme Y translates more and 
zooms less"},
+  {BP_AUTO_SPEEDCONTROL, "AutoSpeedControl", Persistence::PERSISTENT, true, "AutoSpeedControl"},
+  {BP_LM_ADAPTIVE, "LMAdaptive", Persistence::PERSISTENT, true, "Whether language model should learn as you 
enter text"},
+  {BP_SOCKET_DEBUG, "SocketInputDebug", Persistence::PERSISTENT, false, "Print information about socket 
input processing to console"},
+  {BP_CIRCLE_START, "CircleStart", Persistence::PERSISTENT, false, "Start on circle mode"},
+  {BP_GLOBAL_KEYBOARD, "GlobalKeyboard", Persistence::PERSISTENT, false, "Whether to assume global control 
of the keyboard"},
 #ifdef WITH_MAEMO
-  {BP_NONLINEAR_Y, "NonlinearY", false, "Apply nonlinearities to Y axis (i.e. compress top &amp; bottom)"},
+  {BP_NONLINEAR_Y, "NonlinearY", Persistence::PERSISTENT, false, "Apply nonlinearities to Y axis (i.e. 
compress top &amp; bottom)"},
 #else
-  {BP_NONLINEAR_Y, "NonlinearY", true, "Apply nonlinearities to Y axis (i.e. compress top &amp; bottom)"},
+  {BP_NONLINEAR_Y, "NonlinearY", Persistence::PERSISTENT, true, "Apply nonlinearities to Y axis (i.e. 
compress top &amp; bottom)"},
 #endif
-  {BP_STOP_OUTSIDE, "PauseOutside", false, "Whether to stop when pointer leaves canvas area"},
+  {BP_STOP_OUTSIDE, "PauseOutside", Persistence::PERSISTENT, false, "Whether to stop when pointer leaves 
canvas area"},
 #ifdef TARGET_OS_IPHONE
-  {BP_BACKOFF_BUTTON, "BackoffButton", false, "Whether to enable the extra backoff button in dynamic mode"},
+  {BP_BACKOFF_BUTTON, "BackoffButton", Persistence::PERSISTENT, false, "Whether to enable the extra backoff 
button in dynamic mode"},
 #else
-  {BP_BACKOFF_BUTTON, "BackoffButton", true, "Whether to enable the extra backoff button in dynamic mode"},
+  {BP_BACKOFF_BUTTON, "BackoffButton", Persistence::PERSISTENT, true, "Whether to enable the extra backoff 
button in dynamic mode"},
 #endif
-  {BP_TWOBUTTON_REVERSE, "TwoButtonReverse", false, "Reverse the up/down buttons in two button mode"},
-  {BP_2B_INVERT_DOUBLE, "TwoButtonInvertDouble", false, "Double-press acts as opposite button in two-button 
mode"},
-  {BP_SLOW_START, "SlowStart", false, "Start at low speed and increase"},
-  {BP_COPY_ALL_ON_STOP, "CopyOnStop", false, "Copy all text to clipboard whenever we stop"},
-  {BP_SPEAK_ALL_ON_STOP, "SpeakOnStop", false, "Speak all text whenever we stop"},
-  {BP_SPEAK_WORDS, "SpeakWords", false, "Speak words as they are written"},
-  {BP_GAME_HELP_DRAW_PATH, "GameDrawPath", true, "When we give help, show the shortest path to the target 
sentence"},
-  {BP_TWO_PUSH_RELEASE_TIME, "TwoPushReleaseTime", false, "Use push and release times of single press rather 
than push times of two presses"},
+  {BP_TWOBUTTON_REVERSE, "TwoButtonReverse", Persistence::PERSISTENT, false, "Reverse the up/down buttons in 
two button mode"},
+  {BP_2B_INVERT_DOUBLE, "TwoButtonInvertDouble", Persistence::PERSISTENT, false, "Double-press acts as 
opposite button in two-button mode"},
+  {BP_SLOW_START, "SlowStart", Persistence::PERSISTENT, false, "Start at low speed and increase"},
+  {BP_COPY_ALL_ON_STOP, "CopyOnStop", Persistence::PERSISTENT, false, "Copy all text to clipboard whenever 
we stop"},
+  {BP_SPEAK_ALL_ON_STOP, "SpeakOnStop", Persistence::PERSISTENT, false, "Speak all text whenever we stop"},
+  {BP_SPEAK_WORDS, "SpeakWords", Persistence::PERSISTENT, false, "Speak words as they are written"},
+  {BP_GAME_HELP_DRAW_PATH, "GameDrawPath", Persistence::PERSISTENT, true, "When we give help, show the 
shortest path to the target sentence"},
+  {BP_TWO_PUSH_RELEASE_TIME, "TwoPushReleaseTime", Persistence::PERSISTENT, false, "Use push and release 
times of single press rather than push times of two presses"},
 };
 
 const lp_table longparamtable[] = {
-  {LP_ORIENTATION, "ScreenOrientation", -2, "Screen Orientation"},
-  {LP_MAX_BITRATE, "MaxBitRateTimes100", 80, "Max Bit Rate Times 100"},
-  {LP_FRAMERATE, "FrameRate", 3200, "Decaying average of last known frame rates, *100"},
-  {LP_LANGUAGE_MODEL_ID, "LanguageModelID", 0, "LanguageModelID"},
-  {LP_DASHER_FONTSIZE, "DasherFontSize", 2, "DasherFontSize"},
-  {LP_MESSAGE_FONTSIZE, "MessageFontSize", 14, "Size of font for messages (in points)"},
-  {LP_SHAPE_TYPE, "RenderStyle", 1, "Shapes to render in (0/1=disjoint/overlapping rects, 
2/3=triangles/truncated, 4=quadrics, 5=circles)"},
-  {LP_UNIFORM, "UniformTimes1000", 50, "UniformTimes1000"},
-  {LP_YSCALE, "YScaling", 0, "YScaling"},
-  {LP_MOUSEPOSDIST, "MousePositionBoxDistance", 50, "MousePositionBoxDistance"},
-  {LP_PY_PROB_SORT_THRES, "PYProbabilitySortThreshold", 85, "Sort converted syms in descending probability 
order up to this percentage"},
-  {LP_MESSAGE_TIME, "MessageTime", 2500, "Time for which non-modal messages are displayed, in ms"},
-  {LP_LM_MAX_ORDER, "LMMaxOrder", 5, "LMMaxOrder"},
-  { LP_LM_EXCLUSION, "LMExclusion", 0, "LMExclusion" },
-  {LP_LM_UPDATE_EXCLUSION, "LMUpdateExclusion", 1, "LMUpdateExclusion"},
-  {LP_LM_ALPHA, "LMAlpha", 49, "LMAlpha"},
-  {LP_LM_BETA, "LMBeta", 77, "LMBeta"},
-  {LP_LM_MIXTURE, "LMMixture", 50, "LMMixture"},
-  {LP_LINE_WIDTH, "LineWidth", 1, "Width to draw crosshair and mouse line"},
-  {LP_GEOMETRY, "Geometry", 0, "Screen geometry (mostly for tall thin screens) - 0=old-style, 1=square 
no-xhair, 2=squish, 3=squish+log"},
-  {LP_LM_WORD_ALPHA, "WordAlpha", 50, "Alpha value for word-based model"},
-  {LP_USER_LOG_LEVEL_MASK, "UserLogLevelMask", 0, "Controls level of user logging, 0 = none, 1 = short, 2 = 
detailed, 3 = both"},
-  {LP_ZOOMSTEPS, "Zoomsteps", 32, "Integerised ratio of zoom size for click/button mode, denom 64."},
-  {LP_B, "ButtonMenuBoxes", 4, "Number of boxes for button menu mode"},
-  {LP_S, "ButtonMenuSafety", 25, "Safety parameter for button mode, in percent."},
+  {LP_ORIENTATION, "ScreenOrientation", Persistence::PERSISTENT, -2, "Screen Orientation"},
+  {LP_MAX_BITRATE, "MaxBitRateTimes100", Persistence::PERSISTENT, 80, "Max Bit Rate Times 100"},
+  {LP_FRAMERATE, "FrameRate", Persistence::EPHEMERAL, 3200, "Decaying average of last known frame rates, 
*100"},
+  {LP_LANGUAGE_MODEL_ID, "LanguageModelID", Persistence::PERSISTENT, 0, "LanguageModelID"},
+  {LP_DASHER_FONTSIZE, "DasherFontSize", Persistence::PERSISTENT, 2, "DasherFontSize"},
+  {LP_MESSAGE_FONTSIZE, "MessageFontSize", Persistence::PERSISTENT, 14, "Size of font for messages (in 
points)"},
+  {LP_SHAPE_TYPE, "RenderStyle", Persistence::PERSISTENT, 1, "Shapes to render in (0/1=disjoint/overlapping 
rects, 2/3=triangles/truncated, 4=quadrics, 5=circles)"},
+  {LP_UNIFORM, "UniformTimes1000", Persistence::PERSISTENT, 50, "UniformTimes1000"},
+  {LP_YSCALE, "YScaling", Persistence::PERSISTENT, 0, "YScaling"},
+  {LP_MOUSEPOSDIST, "MousePositionBoxDistance", Persistence::PERSISTENT, 50, "MousePositionBoxDistance"},
+  {LP_PY_PROB_SORT_THRES, "PYProbabilitySortThreshold", Persistence::PERSISTENT, 85, "Sort converted syms in 
descending probability order up to this percentage"},
+  {LP_MESSAGE_TIME, "MessageTime", Persistence::PERSISTENT, 2500, "Time for which non-modal messages are 
displayed, in ms"},
+  {LP_LM_MAX_ORDER, "LMMaxOrder", Persistence::PERSISTENT, 5, "LMMaxOrder"},
+  { LP_LM_EXCLUSION, "LMExclusion", Persistence::PERSISTENT, 0, "LMExclusion" },
+  {LP_LM_UPDATE_EXCLUSION, "LMUpdateExclusion", Persistence::PERSISTENT, 1, "LMUpdateExclusion"},
+  {LP_LM_ALPHA, "LMAlpha", Persistence::PERSISTENT, 49, "LMAlpha"},
+  {LP_LM_BETA, "LMBeta", Persistence::PERSISTENT, 77, "LMBeta"},
+  {LP_LM_MIXTURE, "LMMixture", Persistence::PERSISTENT, 50, "LMMixture"},
+  {LP_LINE_WIDTH, "LineWidth", Persistence::PERSISTENT, 1, "Width to draw crosshair and mouse line"},
+  {LP_GEOMETRY, "Geometry", Persistence::PERSISTENT, 0, "Screen geometry (mostly for tall thin screens) - 
0=old-style, 1=square no-xhair, 2=squish, 3=squish+log"},
+  {LP_LM_WORD_ALPHA, "WordAlpha", Persistence::PERSISTENT, 50, "Alpha value for word-based model"},
+  {LP_USER_LOG_LEVEL_MASK, "UserLogLevelMask", Persistence::PERSISTENT, 0, "Controls level of user logging, 
0 = none, 1 = short, 2 = detailed, 3 = both"},
+  {LP_ZOOMSTEPS, "Zoomsteps", Persistence::PERSISTENT, 32, "Integerised ratio of zoom size for click/button 
mode, denom 64."},
+  {LP_B, "ButtonMenuBoxes", Persistence::PERSISTENT, 4, "Number of boxes for button menu mode"},
+  {LP_S, "ButtonMenuSafety", Persistence::PERSISTENT, 25, "Safety parameter for button mode, in percent."},
 #ifdef TARGET_OS_IPHONE
-  {LP_BUTTON_SCAN_TIME, "ButtonMenuScanTime", 600, "Scanning time in menu mode (0 = don't scan), in ms"},
+  {LP_BUTTON_SCAN_TIME, "ButtonMenuScanTime", Persistence::PERSISTENT, 600, "Scanning time in menu mode (0 = 
don't scan), in ms"},
 #else
-  {LP_BUTTON_SCAN_TIME, "ButtonMenuScanTime", 0, "Scanning time in menu mode (0 = don't scan), in ms"},
+  {LP_BUTTON_SCAN_TIME, "ButtonMenuScanTime", Persistence::PERSISTENT, 0, "Scanning time in menu mode (0 = 
don't scan), in ms"},
 #endif
-  {LP_R, "ButtonModeNonuniformity", 0, "Button mode box non-uniformity"},
-  {LP_RIGHTZOOM, "ButtonCompassModeRightZoom", 5120, "Zoomfactor (*1024) for compass mode"},
+  {LP_R, "ButtonModeNonuniformity", Persistence::PERSISTENT, 0, "Button mode box non-uniformity"},
+  {LP_RIGHTZOOM, "ButtonCompassModeRightZoom", Persistence::PERSISTENT, 5120, "Zoomfactor (*1024) for 
compass mode"},
 #if defined(WITH_MAEMO) || defined (TARGET_OS_IPHONE)
-  {LP_NODE_BUDGET, "NodeBudget", 1000, "Target (min) number of node objects to maintain"},
+  {LP_NODE_BUDGET, "NodeBudget", Persistence::PERSISTENT, 1000, "Target (min) number of node objects to 
maintain"},
 #else
-  {LP_NODE_BUDGET, "NodeBudget", 3000, "Target (min) number of node objects to maintain"},
+  {LP_NODE_BUDGET, "NodeBudget", Persistence::PERSISTENT, 3000, "Target (min) number of node objects to 
maintain"},
 #endif
-  {LP_OUTLINE_WIDTH, "OutlineWidth", 0, "Absolute value is line width to draw boxes (fill iff >=0)" },
-  {LP_MIN_NODE_SIZE, "MinNodeSize", 50, "Minimum size of node (in dasher coords) to draw" }, 
+  {LP_OUTLINE_WIDTH, "OutlineWidth", Persistence::PERSISTENT, 0, "Absolute value is line width to draw boxes 
(fill iff >=0)" },
+  {LP_MIN_NODE_SIZE, "MinNodeSize", Persistence::PERSISTENT, 50, "Minimum size of node (in dasher coords) to 
draw" }, 
 #ifdef WITH_MAEMO
-  {LP_NONLINEAR_X, "NonLinearX", 0, "Nonlinear compression of X-axis (0 = none, higher = more extreme)"},
+  {LP_NONLINEAR_X, "NonLinearX", Persistence::PERSISTENT, 0, "Nonlinear compression of X-axis (0 = none, 
higher = more extreme)"},
 #else
-  {LP_NONLINEAR_X, "NonLinearX", 5, "Nonlinear compression of X-axis (0 = none, higher = more extreme)"},
+  {LP_NONLINEAR_X, "NonLinearX", Persistence::PERSISTENT, 5, "Nonlinear compression of X-axis (0 = none, 
higher = more extreme)"},
 #endif
-  {LP_AUTOSPEED_SENSITIVITY, "AutospeedSensitivity", 100, "Sensitivity of automatic speed control 
(percent)"},
-  {LP_SOCKET_PORT, "SocketPort", 20320, "UDP/TCP socket to use for network socket input"},
-  {LP_SOCKET_INPUT_X_MIN, "SocketInputXMinTimes1000", 0, "Bottom of range of X values expected from network 
input"},
-  {LP_SOCKET_INPUT_X_MAX, "SocketInputXMaxTimes1000", 1000, "Top of range of X values expected from network 
input"},
-  {LP_SOCKET_INPUT_Y_MIN, "SocketInputYMinTimes1000", 0, "Bottom of range of Y values expected from network 
input"},
-  {LP_SOCKET_INPUT_Y_MAX, "SocketInputYMaxTimes1000", 1000, "Top of range of Y values expected from network 
input"},
-  {LP_CIRCLE_PERCENT, "CirclePercent", 10, "Percentage of nominal vertical range to use for radius of start 
circle"},
-  {LP_TWO_BUTTON_OFFSET, "TwoButtonOffset", 1638, "Offset for two button dynamic mode"},
-  {LP_HOLD_TIME, "HoldTime", 1000, "Time for which buttons must be held to count as long presses, in ms"},
-  {LP_MULTIPRESS_TIME, "MultipressTime", 1000, "Time in which multiple presses must occur, in ms"},
-  {LP_SLOW_START_TIME, "SlowStartTime", 1000, "Time over which slow start occurs"},
-  {LP_TWO_PUSH_OUTER, "TwoPushOuter", 1792, "Offset for one button dynamic mode outer marker"},
-  {LP_TWO_PUSH_LONG, "TwoPushLong", 512, "Distance between down markers (long gap)"},
-  {LP_TWO_PUSH_SHORT, "TwoPushShort", 80, "Distance between up markers, as percentage of long gap"},
-  {LP_TWO_PUSH_TOLERANCE, "TwoPushTolerance", 100, "Tolerance of two-push-mode pushes, in ms"},
-  {LP_DYNAMIC_BUTTON_LAG, "DynamicButtonLag", 50, "Lag of pushes in dynamic button mode (ms)"},
-  {LP_STATIC1B_TIME, "Static1BTime", 2000, "Time for static-1B mode to scan from top to bottom (ms)"},
-  {LP_STATIC1B_ZOOM, "Static1BZoom", 8, "Zoom factor for static-1B mode"},
-  {LP_DEMO_SPRING, "DemoSpring", 100, "Springyness in Demo-mode"},
-  {LP_DEMO_NOISE_MEM, "DemoNoiseMem", 100, "Memory parameter for noise in Demo-mode"},
-  {LP_DEMO_NOISE_MAG, "DemoNoiseMag", 325, "Magnitude of noise in Demo-mode"},
-  {LP_MAXZOOM, "ClickMaxZoom", 200, "Maximum zoom possible in click mode (times 10)"},
-  {LP_DYNAMIC_SPEED_INC, "DynamicSpeedInc", 3, "%age by which dynamic mode auto speed control increases 
speed"},
-  {LP_DYNAMIC_SPEED_FREQ, "DynamicSpeedFreq", 10, "Seconds after which dynamic mode auto speed control 
increases speed"},
-  {LP_DYNAMIC_SPEED_DEC, "DynamicSpeedDec", 8, "%age by which dynamic mode auto speed control decreases 
speed on reverse"},
-  {LP_TAP_TIME, "TapTime", 200, "Max length of a stylus 'tap' rather than hold (ms)"},
+  {LP_AUTOSPEED_SENSITIVITY, "AutospeedSensitivity", Persistence::PERSISTENT, 100, "Sensitivity of automatic 
speed control (percent)"},
+  {LP_SOCKET_PORT, "SocketPort", Persistence::PERSISTENT, 20320, "UDP/TCP socket to use for network socket 
input"},
+  {LP_SOCKET_INPUT_X_MIN, "SocketInputXMinTimes1000", Persistence::PERSISTENT, 0, "Bottom of range of X 
values expected from network input"},
+  {LP_SOCKET_INPUT_X_MAX, "SocketInputXMaxTimes1000", Persistence::PERSISTENT, 1000, "Top of range of X 
values expected from network input"},
+  {LP_SOCKET_INPUT_Y_MIN, "SocketInputYMinTimes1000", Persistence::PERSISTENT, 0, "Bottom of range of Y 
values expected from network input"},
+  {LP_SOCKET_INPUT_Y_MAX, "SocketInputYMaxTimes1000", Persistence::PERSISTENT, 1000, "Top of range of Y 
values expected from network input"},
+  {LP_CIRCLE_PERCENT, "CirclePercent", Persistence::PERSISTENT, 10, "Percentage of nominal vertical range to 
use for radius of start circle"},
+  {LP_TWO_BUTTON_OFFSET, "TwoButtonOffset", Persistence::PERSISTENT, 1638, "Offset for two button dynamic 
mode"},
+  {LP_HOLD_TIME, "HoldTime", Persistence::PERSISTENT, 1000, "Time for which buttons must be held to count as 
long presses, in ms"},
+  {LP_MULTIPRESS_TIME, "MultipressTime", Persistence::PERSISTENT, 1000, "Time in which multiple presses must 
occur, in ms"},
+  {LP_SLOW_START_TIME, "SlowStartTime", Persistence::PERSISTENT, 1000, "Time over which slow start occurs"},
+  {LP_TWO_PUSH_OUTER, "TwoPushOuter", Persistence::PERSISTENT, 1792, "Offset for one button dynamic mode 
outer marker"},
+  {LP_TWO_PUSH_LONG, "TwoPushLong", Persistence::PERSISTENT, 512, "Distance between down markers (long 
gap)"},
+  {LP_TWO_PUSH_SHORT, "TwoPushShort", Persistence::PERSISTENT, 80, "Distance between up markers, as 
percentage of long gap"},
+  {LP_TWO_PUSH_TOLERANCE, "TwoPushTolerance", Persistence::PERSISTENT, 100, "Tolerance of two-push-mode 
pushes, in ms"},
+  {LP_DYNAMIC_BUTTON_LAG, "DynamicButtonLag", Persistence::PERSISTENT, 50, "Lag of pushes in dynamic button 
mode (ms)"},
+  {LP_STATIC1B_TIME, "Static1BTime", Persistence::PERSISTENT, 2000, "Time for static-1B mode to scan from 
top to bottom (ms)"},
+  {LP_STATIC1B_ZOOM, "Static1BZoom", Persistence::PERSISTENT, 8, "Zoom factor for static-1B mode"},
+  {LP_DEMO_SPRING, "DemoSpring", Persistence::PERSISTENT, 100, "Springyness in Demo-mode"},
+  {LP_DEMO_NOISE_MEM, "DemoNoiseMem", Persistence::PERSISTENT, 100, "Memory parameter for noise in 
Demo-mode"},
+  {LP_DEMO_NOISE_MAG, "DemoNoiseMag", Persistence::PERSISTENT, 325, "Magnitude of noise in Demo-mode"},
+  {LP_MAXZOOM, "ClickMaxZoom", Persistence::PERSISTENT, 200, "Maximum zoom possible in click mode (times 
10)"},
+  {LP_DYNAMIC_SPEED_INC, "DynamicSpeedInc", Persistence::PERSISTENT, 3, "%age by which dynamic mode auto 
speed control increases speed"},
+  {LP_DYNAMIC_SPEED_FREQ, "DynamicSpeedFreq", Persistence::PERSISTENT, 10, "Seconds after which dynamic mode 
auto speed control increases speed"},
+  {LP_DYNAMIC_SPEED_DEC, "DynamicSpeedDec", Persistence::PERSISTENT, 8, "%age by which dynamic mode auto 
speed control decreases speed on reverse"},
+  {LP_TAP_TIME, "TapTime", Persistence::PERSISTENT, 200, "Max length of a stylus 'tap' rather than hold 
(ms)"},
 #ifdef TARGET_OS_IPHONE
-  {LP_MARGIN_WIDTH, "MarginWidth", 500, "Width of RHS margin (in Dasher co-ords)"},
+  {LP_MARGIN_WIDTH, "MarginWidth", Persistence::PERSISTENT, 500, "Width of RHS margin (in Dasher co-ords)"},
 #else
-  {LP_MARGIN_WIDTH, "MarginWidth", 300, "Width of RHS margin (in Dasher co-ords)"},
+  {LP_MARGIN_WIDTH, "MarginWidth", Persistence::PERSISTENT, 300, "Width of RHS margin (in Dasher co-ords)"},
 #endif
-  {LP_TARGET_OFFSET, "TargetOffset", 0, "Vertical distance between mouse pointer and target (400=screen 
height)"},
-  {LP_X_LIMIT_SPEED, "XLimitSpeed", 800, "X Co-ordinate at which maximum speed is reached (&lt;2048=xhair)"},
-  {LP_GAME_HELP_DIST, "GameHelpDistance", 1920, "Distance of sentence from center to decide user needs 
help"},
-  {LP_GAME_HELP_TIME, "GameHelpTime", 0, "Time for which user must need help before help drawn"},
+  {LP_TARGET_OFFSET, "TargetOffset", Persistence::PERSISTENT, 0, "Vertical distance between mouse pointer 
and target (400=screen height)"},
+  {LP_X_LIMIT_SPEED, "XLimitSpeed", Persistence::PERSISTENT, 800, "X Co-ordinate at which maximum speed is 
reached (&lt;2048=xhair)"},
+  {LP_GAME_HELP_DIST, "GameHelpDistance", Persistence::PERSISTENT, 1920, "Distance of sentence from center 
to decide user needs help"},
+  {LP_GAME_HELP_TIME, "GameHelpTime", Persistence::PERSISTENT, 0, "Time for which user must need help before 
help drawn"},
 };
 
 const sp_table stringparamtable[] = {
-  {SP_ALPHABET_ID, "AlphabetID", "", "AlphabetID"},
-  {SP_ALPHABET_1, "Alphabet1", "", "Alphabet History 1"},
-  {SP_ALPHABET_2, "Alphabet2", "", "Alphabet History 2"},
-  {SP_ALPHABET_3, "Alphabet3", "", "Alphabet History 3"},
-  {SP_ALPHABET_4, "Alphabet4", "", "Alphabet History 4"},
-  {SP_COLOUR_ID, "ColourID", "", "ColourID"}, 
-  {SP_DASHER_FONT, "DasherFont", "", "DasherFont"},
-  {SP_GAME_TEXT_FILE, "GameTextFile", "", "User-specified file with strings to practice writing"},
-  {SP_SOCKET_INPUT_X_LABEL, "SocketInputXLabel", "x", "Label preceding X values for network input"},
-  {SP_SOCKET_INPUT_Y_LABEL, "SocketInputYLabel", "y", "Label preceding Y values for network input"},
+  {SP_ALPHABET_ID, "AlphabetID", Persistence::PERSISTENT, "", "AlphabetID"},
+  {SP_ALPHABET_1, "Alphabet1", Persistence::PERSISTENT, "", "Alphabet History 1"},
+  {SP_ALPHABET_2, "Alphabet2", Persistence::PERSISTENT, "", "Alphabet History 2"},
+  {SP_ALPHABET_3, "Alphabet3", Persistence::PERSISTENT, "", "Alphabet History 3"},
+  {SP_ALPHABET_4, "Alphabet4", Persistence::PERSISTENT, "", "Alphabet History 4"},
+  {SP_COLOUR_ID, "ColourID", Persistence::PERSISTENT, "", "ColourID"}, 
+  {SP_DASHER_FONT, "DasherFont", Persistence::PERSISTENT, "", "DasherFont"},
+  {SP_GAME_TEXT_FILE, "GameTextFile", Persistence::PERSISTENT, "", "User-specified file with strings to 
practice writing"},
+  {SP_SOCKET_INPUT_X_LABEL, "SocketInputXLabel", Persistence::PERSISTENT, "x", "Label preceding X values for 
network input"},
+  {SP_SOCKET_INPUT_Y_LABEL, "SocketInputYLabel", Persistence::PERSISTENT, "y", "Label preceding Y values for 
network input"},
 #if defined(WITH_MAEMO) || defined(TARGET_OS_IPHONE)
-  {SP_INPUT_FILTER, "InputFilter", "Stylus Control", "Input filter used to provide the current control 
mode"},
+  {SP_INPUT_FILTER, "InputFilter", Persistence::PERSISTENT, "Stylus Control", "Input filter used to provide 
the current control mode"},
 #else
-  {SP_INPUT_FILTER, "InputFilter", "Normal Control", "Input filter used to provide the current control 
mode"},
+  {SP_INPUT_FILTER, "InputFilter", Persistence::PERSISTENT, "Normal Control", "Input filter used to provide 
the current control mode"},
 #endif
-  {SP_INPUT_DEVICE, "InputDevice", "Mouse Input", "Driver for the input device"},
-  {SP_BUTTON_0, "Button0", "", "Assignment to button 0"},
-  {SP_BUTTON_1, "Button1", "", "Assignment to button 1"},
-  {SP_BUTTON_2, "Button2", "", "Assignment to button 2"},
-  {SP_BUTTON_3, "Button3", "", "Assignment to button 3"},
-  {SP_BUTTON_4, "Button4", "", "Assignment to button 4"},
-  {SP_BUTTON_10, "Button10", "", "Assignment to button 10"},
-  {SP_JOYSTICK_DEVICE, "JoystickDevice", "/dev/input/js0", "Joystick device"},
+  {SP_INPUT_DEVICE, "InputDevice", Persistence::PERSISTENT, "Mouse Input", "Driver for the input device"},
+  {SP_BUTTON_0, "Button0", Persistence::PERSISTENT, "", "Assignment to button 0"},
+  {SP_BUTTON_1, "Button1", Persistence::PERSISTENT, "", "Assignment to button 1"},
+  {SP_BUTTON_2, "Button2", Persistence::PERSISTENT, "", "Assignment to button 2"},
+  {SP_BUTTON_3, "Button3", Persistence::PERSISTENT, "", "Assignment to button 3"},
+  {SP_BUTTON_4, "Button4", Persistence::PERSISTENT, "", "Assignment to button 4"},
+  {SP_BUTTON_10, "Button10", Persistence::PERSISTENT, "", "Assignment to button 10"},
+  {SP_JOYSTICK_DEVICE, "JoystickDevice", Persistence::PERSISTENT, "/dev/input/js0", "Joystick device"},
 };
 
 ParameterType GetParameterType(int iParameter) {
diff --git a/Src/DasherCore/Parameters.h b/Src/DasherCore/Parameters.h
index 3cfd36e..762556f 100644
--- a/Src/DasherCore/Parameters.h
+++ b/Src/DasherCore/Parameters.h
@@ -87,7 +87,7 @@ enum {
 #define NUM_OF_LPS (END_OF_LPS - END_OF_BPS)
 #define NUM_OF_SPS (END_OF_SPS - END_OF_LPS)
 
-#define PERS true
+enum class Persistence { PERSISTENT, EPHEMERAL };
 
 namespace Dasher {
   ///Namespace containing all static (i.e. fixed/constant) data about
@@ -100,6 +100,7 @@ namespace Dasher {
     struct bp_table {
       int key;
       const char *regName;
+      Persistence persistent;
       bool defaultValue;
       const char *humanReadable;
     };
@@ -111,6 +112,7 @@ namespace Dasher {
     struct lp_table {
       int key;
       const char *regName;
+      Persistence persistent;
       long defaultValue;
       const char *humanReadable;
     };
@@ -122,6 +124,7 @@ namespace Dasher {
     struct sp_table {
       int key;
       const char *regName;
+      Persistence persistent;
       const char *defaultValue;
       const char *humanReadable;
     };
diff --git a/Src/DasherCore/SettingsStore.cpp b/Src/DasherCore/SettingsStore.cpp
index de225ac..9a283c4 100644
--- a/Src/DasherCore/SettingsStore.cpp
+++ b/Src/DasherCore/SettingsStore.cpp
@@ -36,66 +36,93 @@ CSettingsStore::CSettingsStore() {
 }
 
 void CSettingsStore::LoadPersistent() {
-
   // Load each of the persistent parameters.  If we fail loading for the store, then 
   // we'll save the settings with the default value that comes from Parameters.h
+  AddParameters(boolparamtable, NUM_OF_BPS);
+  AddParameters(longparamtable, NUM_OF_LPS);
+  AddParameters(stringparamtable, NUM_OF_SPS);
+}
 
-  for(int i(0); i < NUM_OF_BPS; ++i) {
-    bool bValue;
-    if(LoadSetting(boolparamtable[i].regName, &bValue))
-      boolParamValues[i] = bValue;
-    else
-      SaveSetting(boolparamtable[i].regName,
-                  boolParamValues[i] = boolparamtable[i].defaultValue);
-  }
-
-  for(int j(0); j < NUM_OF_LPS; ++j) {
-    long lValue;
-    if(LoadSetting(longparamtable[j].regName, &lValue))
-      longParamValues[j] = lValue;
-    else
-      SaveSetting(longparamtable[j].regName,
-                  longParamValues[j] = longparamtable[j].defaultValue);
-  }
-
-  for(int k(0); k < NUM_OF_SPS; ++k) {
-    std::string strValue;
-    if(LoadSetting(stringparamtable[k].regName, &strValue))
-      stringParamValues[k] = strValue;
-    else
-      SaveSetting(stringparamtable[k].regName,     stringParamValues[k] = stringparamtable[k].defaultValue);
+void CSettingsStore::AddParameters(const Settings::bp_table* table, size_t count) {
+  for (size_t i = 0; i < count; ++i) {
+    const auto& e = table[i];
+    auto &parameter = parameters_[e.key];
+    DASHER_ASSERT(parameter.type == Settings::ParamInvalid);
+    parameter.type = ParamBool;
+    parameter.name = e.regName;
+    parameter.bool_default = e.defaultValue;
+    parameter.persistence = e.persistent;
+    if (!LoadSetting(e.regName, &parameter.bool_value)) {
+      parameter.bool_value = e.defaultValue;
+      SaveSetting(e.regName, e.defaultValue);
+    }
   }
 }
 
-
-// Return 0 on success, an error string on failure.
-const char * CSettingsStore::ClSet(const std::string &strKey, const std::string &strValue) {
-  for(int i(0); i < NUM_OF_BPS; ++i) {
-    if(strKey == boolparamtable[i].regName) {
-      if ((strValue == "0") || (strValue == _("true")))
-       SetBoolParameter(boolparamtable[i].key, false);
-      else if((strValue == "1") || (strValue == _("false")))
-       SetBoolParameter(boolparamtable[i].key, true);
-      else
-        // Note to translators: This message will be output for a command line
-        // with "--options foo=VAL" and foo is a boolean valued parameter, but
-        // "VAL" is not true or false.
-        return _("boolean value must be specified as 'true' or 'false'.");
-      return 0;
+void CSettingsStore::AddParameters(const Settings::lp_table* table, size_t count) {
+  for (size_t i = 0; i < count; ++i) {
+    const lp_table& e = table[i];
+    auto &parameter = parameters_[e.key];
+    DASHER_ASSERT(parameter.type == Settings::ParamInvalid);
+    parameter.type = ParamLong;
+    parameter.name = e.regName;
+    parameter.long_default = e.defaultValue;
+    parameter.persistence = e.persistent;
+    if (!LoadSetting(e.regName, &parameter.long_value)) {
+      parameter.long_value = e.defaultValue;
+      SaveSetting(e.regName, e.defaultValue);
     }
   }
+}
 
-  for(int i(0); i < NUM_OF_LPS; ++i) {
-    if(strKey == longparamtable[i].regName) {
-      SetLongParameter(longparamtable[i].key, atoi(strValue.c_str()));
-      return 0;
+void CSettingsStore::AddParameters(const Settings::sp_table* table, size_t count) {
+  for (size_t i = 0; i < count; ++i) {
+    const auto& e = table[i];
+    auto &parameter = parameters_[e.key];
+    DASHER_ASSERT(parameter.type == Settings::ParamInvalid);
+    parameter.type = ParamString;
+    parameter.name = e.regName;
+    parameter.string_default = e.defaultValue;
+    parameter.persistence = e.persistent;
+    if (!LoadSetting(e.regName, &parameter.string_value)) {
+      parameter.string_value = e.defaultValue;
+      SaveSetting(e.regName, std::string(e.defaultValue));
     }
   }
+}
 
-  for(int i(0); i < NUM_OF_SPS; ++i) {
-    if(strKey == stringparamtable[i].regName) {
-      SetStringParameter(stringparamtable[i].key, strValue);
-      return 0;
+// Return 0 on success, an error string on failure.
+const char * CSettingsStore::ClSet(const std::string &strKey, const std::string &strValue) {
+  for (auto& p : parameters_) {
+    if(strKey == p.second.name) {
+      switch (p.second.type) {
+        case ParamBool: {
+          if ((strValue == "0") || (strValue == _("true")))
+            SetBoolParameter(p.first, false);
+          else if((strValue == "1") || (strValue == _("false")))
+            SetBoolParameter(p.first, true);
+          else
+            // Note to translators: This message will be output for a command line
+            // with "--options foo=VAL" and foo is a boolean valued parameter, but
+            // "VAL" is not true or false.
+            return _("boolean value must be specified as 'true' or 'false'.");
+          return nullptr;
+        } break;
+
+        case ParamLong: {
+          // TODO: check the string to int conversion result.
+          SetLongParameter(p.first, atoi(strValue.c_str()));
+          return nullptr;
+        }
+
+        case ParamString: {
+          SetStringParameter(p.first, strValue);
+          return nullptr;
+        }
+        default:
+          // Show unknown options.
+          break;
+      }
     }
   }
   // Note to translators: This is output when command line "--options" doesn't
@@ -107,97 +134,98 @@ const char * CSettingsStore::ClSet(const std::string &strKey, const std::string
 /* TODO: Consider using Template functions to make this neater. */
 
 void CSettingsStore::SetBoolParameter(int iParameter, bool bValue) {
-
+  auto p = parameters_.find(iParameter);
   // Check that the parameter is in fact in the right spot in the table
-  DASHER_ASSERT(iParameter == boolparamtable[iParameter - FIRST_BP].key);
+  DASHER_ASSERT(p != parameters_.end() && p->second.type == ParamBool);
 
   if(bValue == GetBoolParameter(iParameter))
     return;
 
   // Set the value
-  boolParamValues[iParameter - FIRST_BP] = bValue;
+  p->second.bool_value = bValue;
 
   // Initiate events for changed parameter
   DispatchEvent(iParameter);
-
-  // Write out to permanent storage
-  SaveSetting(boolparamtable[iParameter - FIRST_BP].regName, bValue);
+  if (p->second.persistence == Persistence::PERSISTENT) {
+    // Write out to permanent storage
+    SaveSetting(p->second.name, bValue);
+  }
 }
 
 void CSettingsStore::SetLongParameter(int iParameter, long lValue) {
-
+  auto p = parameters_.find(iParameter);
   // Check that the parameter is in fact in the right spot in the table
-  DASHER_ASSERT(iParameter == longparamtable[iParameter - FIRST_LP].key);
+  DASHER_ASSERT(p != parameters_.end() && p->second.type == ParamLong);
 
   if(lValue == GetLongParameter(iParameter))
     return;
 
   // Set the value
-  longParamValues[iParameter - FIRST_LP] = lValue;
+  p->second.long_value = lValue;
 
   // Initiate events for changed parameter
   DispatchEvent(iParameter);
-
-  // Write out to permanent storage
-  SaveSetting(longparamtable[iParameter - FIRST_LP].regName, lValue);
+  if (p->second.persistence == Persistence::PERSISTENT) {
+    // Write out to permanent storage
+    SaveSetting(p->second.name, lValue);
+  }
 }
 
 void CSettingsStore::SetStringParameter(int iParameter, const std::string sValue) {
-
+  auto p = parameters_.find(iParameter);
   // Check that the parameter is in fact in the right spot in the table
-  DASHER_ASSERT(iParameter == stringparamtable[iParameter - FIRST_SP].key);
+  DASHER_ASSERT(p != parameters_.end() && p->second.type == ParamString);
 
   if(sValue == GetStringParameter(iParameter))
     return;
 
   // Set the value
-  stringParamValues[iParameter - FIRST_SP] = sValue;
+  p->second.string_value = sValue;
 
   // Initiate events for changed parameter
   DispatchEvent(iParameter);
-
-  // Write out to permanent storage
-  SaveSetting(stringparamtable[iParameter - FIRST_SP].regName, sValue);
+  if (p->second.persistence != Persistence::PERSISTENT) {
+    // Write out to permanent storage
+    SaveSetting(p->second.name, sValue);
+  }
 }
 
 bool CSettingsStore::GetBoolParameter(int iParameter) const {
+  auto p = parameters_.find(iParameter);
   // Check that the parameter is in fact in the right spot in the table
-  DASHER_ASSERT(iParameter == boolparamtable[iParameter - FIRST_BP].key);
-
-  // Return the value
-  return boolParamValues[iParameter - FIRST_BP];
+  DASHER_ASSERT(p != parameters_.end() && p->second.type == ParamBool);
+  return p->second.bool_value;
 }
 
 long CSettingsStore::GetLongParameter(int iParameter) const {
+  auto p = parameters_.find(iParameter);
   // Check that the parameter is in fact in the right spot in the table
-  DASHER_ASSERT(iParameter == longparamtable[iParameter - FIRST_LP].key);
-
-  // Return the value
-  return longParamValues[iParameter - FIRST_LP];
+  DASHER_ASSERT(p != parameters_.end() && p->second.type == ParamLong);
+  return p->second.long_value;
 }
 
 const std::string &CSettingsStore::GetStringParameter(int iParameter) const {
+  auto p = parameters_.find(iParameter);
   // Check that the parameter is in fact in the right spot in the table
-  DASHER_ASSERT(iParameter == stringparamtable[iParameter - FIRST_SP].key);
-
-  // Return the value
-  return stringParamValues[iParameter - FIRST_SP];
+  DASHER_ASSERT(p != parameters_.end() && p->second.type == ParamString);
+  return p->second.string_value;
 }
 
 void CSettingsStore::ResetParameter(int iParameter) {
-  switch(GetParameterType(iParameter)) {
-  case ParamBool:
-    SetBoolParameter(iParameter, boolparamtable[iParameter-FIRST_BP].defaultValue);
-    break;
-  case ParamLong:
-    SetLongParameter(iParameter, longparamtable[iParameter-FIRST_LP].defaultValue);
-    break;
-  case ParamString:
-    SetStringParameter(iParameter, stringparamtable[iParameter-FIRST_SP].defaultValue);
-    break;
-  case ParamInvalid:
-    // TODO: Error handling?
-    break;
+  auto p = parameters_.find(iParameter);
+  switch(p->second.type) {
+    case ParamBool:
+      SetBoolParameter(iParameter, p->second.bool_default);
+      break;
+    case ParamLong:
+      SetLongParameter(iParameter, p->second.long_default);
+      break;
+    case ParamString:
+      SetStringParameter(iParameter, std::string(p->second.string_default));
+      break;
+    case ParamInvalid:
+      // TODO: Error handling?
+      break;
   }
 }
 
@@ -205,25 +233,25 @@ void CSettingsStore::ResetParameter(int iParameter) {
 functions are over-ridden.
 --------------------------------------------------------------------------*/
 
-bool CSettingsStore::LoadSetting(const std::string &Key, bool *Value) {
+bool CSettingsStore::LoadSetting(const std::string &, bool *) {
   return false;
 }
 
-bool CSettingsStore::LoadSetting(const std::string &Key, long *Value) {
+bool CSettingsStore::LoadSetting(const std::string &, long *) {
   return false;
 }
 
-bool CSettingsStore::LoadSetting(const std::string &Key, std::string *Value) {
+bool CSettingsStore::LoadSetting(const std::string &, std::string *) {
   return false;
 }
 
-void CSettingsStore::SaveSetting(const std::string &Key, bool Value) {
+void CSettingsStore::SaveSetting(const std::string &, bool ) {
 }
 
-void CSettingsStore::SaveSetting(const std::string &Key, long Value) {
+void CSettingsStore::SaveSetting(const std::string &, long ) {
 }
 
-void CSettingsStore::SaveSetting(const std::string &Key, const std::string &Value) {
+void CSettingsStore::SaveSetting(const std::string &, const std::string &) {
 }
 
 /* SettingsUser and SettingsObserver definitions... */
diff --git a/Src/DasherCore/SettingsStore.h b/Src/DasherCore/SettingsStore.h
index 69b0cd0..1c56795 100644
--- a/Src/DasherCore/SettingsStore.h
+++ b/Src/DasherCore/SettingsStore.h
@@ -10,6 +10,8 @@
 #define __SettingsStore_h__
 
 #include <string>
+#include <unordered_map>
+
 #include "Observable.h"
 #include "Parameters.h"
 
@@ -54,7 +56,12 @@ public:
   void ResetParameter(int iParameter);
 
   const char *ClSet(const std::string &strKey, const std::string &strValue);
-    
+
+  // TODO: just load the application parameters by default?
+  void AddParameters(const Settings::bp_table* table, size_t count);
+  void AddParameters(const Settings::lp_table* table, size_t count);
+  void AddParameters(const Settings::sp_table* table, size_t count);
+
 protected:
     ///Loads all (persistent) prefs from disk, using+storing default values when no
     /// existing value stored; non-persistent prefs are reinitialized from defaults.
@@ -104,10 +111,19 @@ private:
   //! \param Value Value of the setting, UTF8 encoded
   virtual void SaveSetting(const std::string & Key, const std::string & Value);
 
-  //actually store the settings data...
-  bool boolParamValues[NUM_OF_BPS];
-  long longParamValues[NUM_OF_LPS];
-  std::string stringParamValues[NUM_OF_SPS];
+  struct Parameter {
+    const char* name;  // Doesn't own the string.
+    Settings::ParameterType type = Settings::ParamInvalid;
+    Persistence persistence = Persistence::PERSISTENT;
+    bool bool_value;
+    bool bool_default;
+    long long_value;
+    long long_default;
+    std::string string_value;
+    const char* string_default;  // Doesn't own the string.
+  };
+
+  std::unordered_map<int, Parameter> parameters_;
 };
   /// Superclass for anything that wants to use/access/store persistent settings.
   /// (The nearest thing remaining to the old CDasherComponent,
@@ -149,7 +165,7 @@ private:
     ///Create a CSettingsObserver listening to changes to the settings values
     /// used by a particular CSettingsUser.
     CSettingsObserver(CSettingsUser *pCreateFrom);
-    ~CSettingsObserver();
+    ~CSettingsObserver() override;
   };
   ///Utility class, for (majority of) cases where a class wants to be both
   /// a CSettingsUser and CSettingsObserver.
diff --git a/Src/Gtk2/DasherAppSettings.cpp b/Src/Gtk2/DasherAppSettings.cpp
index 7dac789..e5ad0fb 100644
--- a/Src/Gtk2/DasherAppSettings.cpp
+++ b/Src/Gtk2/DasherAppSettings.cpp
@@ -2,16 +2,6 @@
 #include <config.h>
 #endif
 
-#ifdef WITH_GCONF
-#include <gconf/gconf.h>
-#include <gconf/gconf-client.h>
-#include <gconf/gconf-enum-types.h>
-#endif
-
-#ifdef WITH_GSETTINGS
-#include <gio/gio.h>
-#endif
-
 #include <cstring>
 #include "DasherAppSettings.h"
 #include "../Common/AppSettingsData.h"
@@ -23,481 +13,71 @@
 #include "dasher.h"
 #include "GtkDasherControl.h"
 
-// XXX PRLW parameter_notification() should be squashed with prejudice
-typedef struct _DasherMain DasherMain;
-struct _DasherMain;
-
-// FIXME - should really do something to make this a singleton class
-
 // TODO: Rename this file to fit in with naming conventions
 
 using namespace Dasher::Settings;
 
-struct _DasherAppSettingsPrivate {
-#ifdef WITH_GCONF
-  GConfClient *pGConfClient;
-#endif
-#ifdef WITH_GSETTINGS
-  GSettings *psettings;
-#endif
-  GtkDasherControl *pDasherWidget;
-  // XXX PRLW nasty hack due to egregious
-  // parameter_notification (0 , iParameter, 0) calls
-  DasherMain *pDasherMain;
-};
-
-typedef struct _DasherAppSettingsPrivate DasherAppSettingsPrivate;
-
-// Private member functions
-
-static void dasher_app_settings_class_init(DasherAppSettingsClass *pClass);
-static void dasher_app_settings_init(DasherAppSettings *pAppSettings);
-static void dasher_app_settings_destroy(GObject*);
-
-#ifdef WITH_GCONF
-static void dasher_app_settings_init_gconf(DasherAppSettings *pSelf, int argc, char **argv);
-#endif
-static void dasher_app_settings_load(DasherAppSettings *pSelf);
-
-// Function declarations
-
-GType dasher_app_settings_get_type() {
-
-  static GType dasher_app_settings_type = 0;
-
-  if(!dasher_app_settings_type) {
-    static const GTypeInfo dasher_app_settings_info = {
-      sizeof(DasherAppSettingsClass),
-      NULL,
-      NULL,
-      (GClassInitFunc) dasher_app_settings_class_init,
-      NULL,
-      NULL,
-      sizeof(DasherAppSettings),
-      0,
-      (GInstanceInitFunc) dasher_app_settings_init,
-      NULL
-    };
-
-    dasher_app_settings_type = g_type_register_static(G_TYPE_OBJECT, "DasherAppSettings", 
&dasher_app_settings_info, static_cast < GTypeFlags > (0));
-  }
-
-  return dasher_app_settings_type;
-}
-
-static void dasher_app_settings_class_init(DasherAppSettingsClass *pClass) {
-  GObjectClass *pObjectClass = (GObjectClass *) pClass;
-  pObjectClass->finalize = dasher_app_settings_destroy;
-}
-
-static void dasher_app_settings_init(DasherAppSettings *pDasherControl) {
-  DasherAppSettingsPrivate *pPrivate = new DasherAppSettingsPrivate;
-  pDasherControl->private_data = pPrivate;
+std::unique_ptr<DasherAppSettings> DasherAppSettings::instance_;
 
-#ifdef WITH_GCONF
-  pPrivate->pGConfClient = NULL;
-#endif
-#ifdef WITH_GSETTINGS
-  pPrivate->psettings = NULL;
-#endif
-  pPrivate->pDasherWidget = NULL;
-  pPrivate->pDasherMain = NULL;
+DasherAppSettings::DasherAppSettings(Dasher::CSettingsStore* settings_store) {
+  settings_store_.reset(settings_store);
+  Load();
 }
 
-static void dasher_app_settings_destroy(GObject *pObject) {
-  DasherAppSettings *pSelf = DASHER_APP_SETTINGS(pObject);
-  DasherAppSettingsPrivate *pPrivate = (DasherAppSettingsPrivate*)(pSelf->private_data);
-#ifdef WITH_GCONF
-  g_object_unref(pPrivate->pGConfClient);
-#endif
-#ifdef WITH_GSETTINGS
-  g_object_unref(pPrivate->psettings);
-#endif
-
-  for(int i(0); i < NUM_OF_APP_SPS; ++i)
-    delete[] app_stringparamtable[i].value;
-
-  // FIXME - glib routines?
-  delete pPrivate;
-  
-  // FIXME - I think we need to chain up through the finalize methods
-  // of the parent classes here...
+DasherAppSettings::~DasherAppSettings() {
+  settings_store_->Unregister(this);
 }
 
-#ifdef WITH_GCONF
-static void dasher_app_settings_init_gconf(DasherAppSettings *pSelf, int argc, char **argv) {
-  DasherAppSettingsPrivate *pPrivate = (DasherAppSettingsPrivate*)(pSelf->private_data);
-
-  GError *pGConfError;
-
-  if(!gconf_init(argc, argv, &pGConfError))
-    g_error("Failed to initialise gconf: %s", pGConfError->message);
-  
-    pPrivate->pGConfClient = gconf_client_get_default();
-}
-#endif
-
-static void dasher_app_settings_load(DasherAppSettings *pSelf) { 
-  DasherAppSettingsPrivate *pPrivate = (DasherAppSettingsPrivate *)(pSelf->private_data);
-
-#ifdef WITH_GCONF
-  GError *pGConfError = NULL;
-  GConfValue *pGConfValue;
- 
-  for(int i(0); i < NUM_OF_APP_BPS; ++i ) {
-    if(app_boolparamtable[i].persistent) {
-      gchar szName[256];
-    
-      strncpy(szName, "/apps/dasher4/", 256);
-      strncat(szName,  app_boolparamtable[i].regName, 255 - strlen( szName ));
-
-      pGConfValue = gconf_client_get_without_default(pPrivate->pGConfClient, szName, &pGConfError);
-      
-      if(pGConfValue) {
-       app_boolparamtable[i].value = gconf_value_get_bool(pGConfValue);
-
-       gconf_value_free(pGConfValue);
-      }
-    }
-  }
-
-  for(int i(0); i < NUM_OF_APP_LPS; ++i ) {
-    if(app_longparamtable[i].persistent) {
-      gchar szName[256];
-    
-      strncpy(szName, "/apps/dasher4/", 256);
-      strncat(szName,  app_longparamtable[i].regName, 255 - strlen( szName ));
-
-      pGConfValue = gconf_client_get_without_default(pPrivate->pGConfClient, szName, &pGConfError);
-      
-      if(pGConfValue) {
-       app_longparamtable[i].value = gconf_value_get_int(pGConfValue);
-
-       gconf_value_free(pGConfValue);
-      }
-    }
-  }
-
-  for(int i(0); i < NUM_OF_APP_SPS; ++i ) {
-    if(app_stringparamtable[i].persistent) {
-      gchar szName[256];
-    
-      strncpy(szName, "/apps/dasher4/", 256);
-      strncat(szName,  app_stringparamtable[i].regName, 255 - strlen( szName ));
-
-      pGConfValue = gconf_client_get_without_default(pPrivate->pGConfClient, szName, &pGConfError);
-      
-      if(pGConfValue) {
-       delete[] app_stringparamtable[i].value;
-
-       const gchar *szValue(gconf_value_get_string(pGConfValue));
-
-       gchar *szNew;
-       szNew = new gchar[strlen(szValue) + 1];
-       strcpy(szNew, szValue);
-       
-       app_stringparamtable[i].value = szNew;
-       gconf_value_free(pGConfValue);
-      }
-    }
-  }
-#endif
-#ifdef WITH_GSETTINGS
-  gchar *tmpstr;
-  for(int i(0); i < NUM_OF_APP_BPS; ++i ) {
-    if(app_boolparamtable[i].persistent) {
-         app_boolparamtable[i].value = g_settings_get_boolean(pPrivate->psettings,
-                                               app_boolparamtable[i].regName);
-    }
-  }
-
-  for(int i(0); i < NUM_OF_APP_LPS; ++i ) {
-    if(app_longparamtable[i].persistent) {
-         app_longparamtable[i].value = g_settings_get_int(pPrivate->psettings,
-                                               app_longparamtable[i].regName);
-    }
-  }
-
-  for(int i(0); i < NUM_OF_APP_SPS; ++i ) {
-    if(app_stringparamtable[i].persistent) {
-         tmpstr = g_settings_get_string(pPrivate->psettings,
-                                               app_stringparamtable[i].regName);
-
-      if(tmpstr) {
-        delete[] app_stringparamtable[i].value;
-        app_stringparamtable[i].value = new char[strlen(tmpstr) + 1];
-        strcpy(app_stringparamtable[i].value, tmpstr);
-        g_free(tmpstr);
-      }
-    }
-  }
-#endif
+int DasherAppSettings::RegisterParameterChangeCallback(std::function<void(int)> fn) {
+  int id = ++callback_id_;
+  change_callbacks_[id] = fn;
+  return id;
 }
 
-// Public methods
-
-DasherAppSettings *dasher_app_settings_new(DasherMain *pDasherMain, int argc, char **argv) {
-  DasherAppSettings *pNewAppSettings;
-  pNewAppSettings = (DasherAppSettings *)(g_object_new(dasher_app_settings_get_type(), NULL));
-  DasherAppSettingsPrivate *pPrivate = (DasherAppSettingsPrivate*)(pNewAppSettings->private_data);
-
-  for(int i(0); i < NUM_OF_APP_SPS; ++i) {
-    gchar *szNew;
-    szNew = new gchar[strlen(app_stringparamtable[i].szDefaultValue) + 1];
-    strcpy(szNew, app_stringparamtable[i].szDefaultValue);
-    app_stringparamtable[i].value = szNew;
-  }
-#ifdef WITH_GCONF
-  dasher_app_settings_init_gconf(pNewAppSettings, argc, argv);  
-#endif
-#ifdef WITH_GSETTINGS
-  pPrivate->psettings = g_settings_new("org.gnome.Dasher");
-#endif
-  pPrivate->pDasherMain = pDasherMain;
-  dasher_app_settings_load(pNewAppSettings);
-
-  return pNewAppSettings;
+void DasherAppSettings::UnregisterParameterChangeCallback(int callback_id) {
+  change_callbacks_.erase(callback_id);
 }
 
-void dasher_app_settings_reset(DasherAppSettings *pSelf, int iParameter) {
-  DasherAppSettingsPrivate *pPrivate = (DasherAppSettingsPrivate*)(pSelf->private_data);
-
-  if(iParameter < END_OF_SPS) {
-    if(pPrivate->pDasherWidget)
-      gtk_dasher_control_reset_parameter(pPrivate->pDasherWidget, iParameter);
-    return;
-  }
-  else {
-    //    pre_parameter_notification(0, iParameter, 0);
-    
-    if(iParameter < END_OF_APP_BPS)
-      app_boolparamtable[ iParameter - FIRST_APP_BP ].value = app_boolparamtable[ iParameter - FIRST_APP_BP 
].bDefaultValue;
-    else if(iParameter < END_OF_APP_LPS)
-      app_longparamtable[ iParameter - FIRST_APP_LP ].value = app_longparamtable[ iParameter - FIRST_APP_LP 
].iDefaultValue; 
-    else {
-      delete[] app_stringparamtable[iParameter - FIRST_APP_SP].value;
-      
-      gchar *szNew;
-      szNew = new gchar[strlen(app_stringparamtable[iParameter - FIRST_APP_SP].szDefaultValue) + 1];
-      strcpy(szNew, app_stringparamtable[iParameter - FIRST_APP_SP].szDefaultValue);
-      app_stringparamtable[iParameter - FIRST_APP_SP].value = szNew;
-    }
-  }
-  // TODO: Use real signals to achieve this
-  parameter_notification(pPrivate->pDasherWidget, iParameter, pPrivate->pDasherMain);
+void DasherAppSettings::Load() {
+  settings_store_->AddParameters(app_boolparamtable, NUM_OF_APP_BPS);
+  settings_store_->AddParameters(app_longparamtable, NUM_OF_APP_LPS);
+  settings_store_->AddParameters(app_stringparamtable, NUM_OF_APP_SPS);
+  settings_store_->Register(this);
 }
 
-bool dasher_app_settings_get_bool(DasherAppSettings *pSelf, int iParameter) { 
-  DasherAppSettingsPrivate *pPrivate = (DasherAppSettingsPrivate*)(pSelf->private_data);
-  if( iParameter < END_OF_BPS ) {
-    if(pPrivate->pDasherWidget)
-      return gtk_dasher_control_get_parameter_bool(pPrivate->pDasherWidget, iParameter);
-    else
-      return false;
-  }
-  else
-    return app_boolparamtable[ iParameter - FIRST_APP_BP ].value;
+bool DasherAppSettings::GetBool(int iParameter) {
+  return settings_store_->GetBoolParameter(iParameter);
 }
 
-void dasher_app_settings_set_bool(DasherAppSettings *pSelf, int iParameter, bool bValue) {
-  DasherAppSettingsPrivate *pPrivate = (DasherAppSettingsPrivate *)(pSelf->private_data);
-  if( iParameter < END_OF_BPS ) {
-    gtk_dasher_control_set_parameter_bool(pPrivate->pDasherWidget, iParameter, bValue);
-  }
-  else {
-    if(dasher_app_settings_get_bool(pSelf, iParameter) == bValue)
-      return; // Don't attempt to change to the existing value
-
-    app_boolparamtable[ iParameter - FIRST_APP_BP ].value = bValue;
-#ifdef WITH_GCONF    
-    if(app_boolparamtable[ iParameter - FIRST_APP_BP ].persistent) {
-      gchar szName[256];
-      
-      strncpy(szName, "/apps/dasher4/", 256);
-      strncat(szName,  app_boolparamtable[ iParameter - FIRST_APP_BP ].regName, 255 - strlen( szName ));
-      
-      GError *pGConfError = NULL;
-      gconf_client_set_bool(pPrivate->pGConfClient, szName, bValue, &pGConfError);
-
-      if(pGConfError)
-       g_message("Error");
-    }
-#endif
-#ifdef WITH_GSETTINGS
-    if(app_boolparamtable[ iParameter - FIRST_APP_BP ].persistent) {
-      g_settings_set_boolean(pPrivate->psettings,
-                            app_boolparamtable[iParameter-FIRST_APP_BP].regName,
-                            bValue);
-    }
-#endif
-
-    // TODO: Use real signals to achieve this
-    parameter_notification(pPrivate->pDasherWidget, iParameter, pPrivate->pDasherMain);
-  }
+void DasherAppSettings::SetBool(int iParameter, bool bValue) {
+  settings_store_->SetBoolParameter(iParameter, bValue);
 }
 
-gint dasher_app_settings_get_long(DasherAppSettings *pSelf, int iParameter) {
-  DasherAppSettingsPrivate *pPrivate = (DasherAppSettingsPrivate *)(pSelf->private_data);
- 
-  if( iParameter < END_OF_LPS) {
-    DASHER_ASSERT_VALIDPTR_R(pPrivate->pDasherWidget);
-    return gtk_dasher_control_get_parameter_long(pPrivate->pDasherWidget, iParameter);
-  }
-  else
-    return app_longparamtable[ iParameter - FIRST_APP_LP ].value;
+gint DasherAppSettings::GetLong(int iParameter) {
+  return settings_store_->GetLongParameter(iParameter);
 }
 
-void dasher_app_settings_set_long(DasherAppSettings *pSelf, int iParameter, gint iValue) {
-  DasherAppSettingsPrivate *pPrivate = (DasherAppSettingsPrivate *)(pSelf->private_data);
-
-  if( iParameter < END_OF_LPS) {
-    DASHER_ASSERT_VALIDPTR_RW(pPrivate->pDasherWidget);
-    gtk_dasher_control_set_parameter_long(pPrivate->pDasherWidget, iParameter, iValue);
-  }
-  else {
-    if(dasher_app_settings_get_long(pSelf, iParameter) == iValue)
-      return; // Don't attempt to change to the existing value
-    
-    //    pre_parameter_notification(0, iParameter, 0);
-
-    app_longparamtable[ iParameter - FIRST_APP_LP ].value = iValue;
-
-#ifdef WITH_GCONF    
-    if(app_longparamtable[ iParameter - FIRST_APP_LP ].persistent) {
-      gchar szName[256];
-      
-      strncpy(szName, "/apps/dasher4/", 256);
-      strncat(szName,  app_longparamtable[ iParameter - FIRST_APP_LP ].regName, 255 - strlen( szName ));
-      
-      GError *pGConfError = NULL;
-      gconf_client_set_int(pPrivate->pGConfClient, szName, iValue, &pGConfError);
-    }
-#endif
-#ifdef WITH_GSETTINGS    
-    if(app_longparamtable[ iParameter - FIRST_APP_LP ].persistent) {
-      g_settings_set_int(pPrivate->psettings,
-                         app_longparamtable[iParameter-FIRST_APP_LP].regName,
-                         iValue);
-    }
-#endif
-    
-    // TODO: Use real signals to achieve this
-    parameter_notification(pPrivate->pDasherWidget, iParameter, pPrivate->pDasherMain);
-  }
+void DasherAppSettings::SetLong(int iParameter, gint iValue) {
+  return settings_store_->SetLongParameter(iParameter, iValue);
 }
 
-const gchar *dasher_app_settings_get_string(DasherAppSettings *pSelf, int iParameter) {
-  DasherAppSettingsPrivate *pPrivate = (DasherAppSettingsPrivate *)(pSelf->private_data);
- 
-  if( iParameter < END_OF_SPS ) {
-    if(pPrivate->pDasherWidget)
-      return gtk_dasher_control_get_parameter_string(pPrivate->pDasherWidget, iParameter);
-    else
-      return nullptr;
-  }
-  else
-    return app_stringparamtable[ iParameter - FIRST_APP_SP ].value;
+const std::string& DasherAppSettings::GetString(int iParameter) {
+  return settings_store_->GetStringParameter(iParameter);
 }
 
-void dasher_app_settings_set_string(DasherAppSettings *pSelf, int iParameter, const gchar *szValue) {
-  DasherAppSettingsPrivate *pPrivate = (DasherAppSettingsPrivate *)(pSelf->private_data);
-
-  if( iParameter < END_OF_SPS ) {
-    if(pPrivate->pDasherWidget)
-      gtk_dasher_control_set_parameter_string(pPrivate->pDasherWidget, iParameter, szValue);
-  }
-  else {
-    if(!strcmp(dasher_app_settings_get_string(pSelf, iParameter), szValue))
-      return; // Don't attempt to change to the existing value
-
-    //    pre_parameter_notification(0, iParameter, 0);
-    
-    delete[] app_stringparamtable[ iParameter - FIRST_APP_SP ].value;
-    
-    gchar *szNew;
-    szNew = new gchar[strlen(szValue) + 1];
-    strcpy(szNew, szValue);
-    
-    app_stringparamtable[ iParameter - FIRST_APP_SP ].value = szNew;
-    
-#ifdef WITH_GCONF
-    if(app_stringparamtable[ iParameter - FIRST_APP_SP ].persistent) {
-      gchar szName[256];
-      
-      strncpy(szName, "/apps/dasher4/", 256);
-      strncat(szName,  app_stringparamtable[ iParameter - FIRST_APP_SP ].regName, 255 - strlen( szName ));
-      
-      GError *pGConfError = NULL;
-      gconf_client_set_string(pPrivate->pGConfClient, szName, szValue, &pGConfError);
-    }
-#endif    
-#ifdef WITH_GSETTINGS
-    if(app_stringparamtable[ iParameter - FIRST_APP_SP ].persistent) {
-      g_settings_set_string(pPrivate->psettings,
-                          app_stringparamtable[iParameter-FIRST_APP_SP].regName,
-                            szValue);
-    }
-#endif    
-
-    // TODO: Use real signals to achieve this
-    parameter_notification(pPrivate->pDasherWidget, iParameter, pPrivate->pDasherMain);
-  }
+void DasherAppSettings::SetString(int iParameter, const gchar *szValue) {
+  return settings_store_->SetStringParameter(iParameter, szValue);
 }
 
-int dasher_app_settings_get_count(DasherAppSettings *pSelf) {
+int DasherAppSettings::GetCount() {
   return END_OF_APP_SPS;
 }
 
-int dasher_app_settings_get_parameter_type(DasherAppSettings *pSelf, int iParameter) {
-  if(iParameter < END_OF_BPS)
-    return DASHER_TYPE_BOOL;
-  else if(iParameter < END_OF_LPS)
-    return DASHER_TYPE_LONG;
-  else if(iParameter < END_OF_SPS)
-    return DASHER_TYPE_STRING;
-  else if(iParameter < END_OF_APP_BPS)
-    return DASHER_TYPE_BOOL;
-  else if(iParameter < END_OF_APP_LPS)
-    return DASHER_TYPE_LONG;
-  else 
-    return DASHER_TYPE_STRING;
-}
-
-const gchar *dasher_app_settings_get_reg_name(DasherAppSettings *pSelf, int iParameter) {
-  if(iParameter < END_OF_BPS)
-    return boolparamtable[iParameter - FIRST_BP].regName;
-  else if(iParameter < END_OF_LPS)
-    return longparamtable[iParameter - FIRST_LP].regName;
-  else if(iParameter < END_OF_SPS)
-    return stringparamtable[iParameter - FIRST_SP].regName;
-  else if(iParameter < END_OF_APP_BPS)
-    return app_boolparamtable[iParameter - FIRST_APP_BP].regName;
-  else if(iParameter < END_OF_APP_LPS)
-    return app_longparamtable[iParameter - FIRST_APP_LP].regName;
-  else 
-    return app_stringparamtable[iParameter - FIRST_APP_SP].regName;
+bool DasherAppSettings::HaveAdvanced() {
+  return (g_find_program_in_path("gconf-editor") != NULL);
 }
 
-const gchar *dasher_app_settings_get_human_name(DasherAppSettings *pSelf, int iParameter) {
-  if(iParameter < END_OF_BPS)
-    return boolparamtable[iParameter - FIRST_BP].humanReadable;
-  else if(iParameter < END_OF_LPS)
-    return longparamtable[iParameter - FIRST_LP].humanReadable;
-  else if(iParameter < END_OF_SPS)
-    return stringparamtable[iParameter - FIRST_SP].humanReadable;
-  else if(iParameter < END_OF_APP_BPS)
-    return app_boolparamtable[iParameter - FIRST_APP_BP].humanReadable;
-  else if(iParameter < END_OF_APP_LPS)
-    return app_longparamtable[iParameter - FIRST_APP_LP].humanReadable;
-  else 
-    return app_stringparamtable[iParameter - FIRST_APP_SP].humanReadable;
-}
-
-bool dasher_app_settings_have_advanced(DasherAppSettings *pSelf) {
-  return(g_find_program_in_path("gconf-editor") != NULL);
-}
-
-void dasher_app_settings_launch_advanced(DasherAppSettings *pSelf) {
+void DasherAppSettings::LaunchAdvanced() {
   gchar *szArgs[3];
 
   szArgs[0] = g_strdup("gconf-editor");
@@ -512,65 +92,39 @@ void dasher_app_settings_launch_advanced(DasherAppSettings *pSelf) {
   g_strfreev(szArgs);
 }
 
-void dasher_app_settings_set_widget(DasherAppSettings *pSelf, GtkDasherControl *pWidget) {
-  DasherAppSettingsPrivate *pPrivate = (DasherAppSettingsPrivate*)(pSelf->private_data);
-
-  pPrivate->pDasherWidget = pWidget;
+void DasherAppSettings::SetWidget(GtkDasherControl *pWidget) {
+  pDasherWidget = pWidget;
 }
 
-GArray *dasher_app_settings_get_allowed_values(DasherAppSettings *pSelf, int iParameter) {
-  DasherAppSettingsPrivate *pPrivate = (DasherAppSettingsPrivate*)(pSelf->private_data);
-  return gtk_dasher_control_get_allowed_values(pPrivate->pDasherWidget, iParameter);
+GArray *DasherAppSettings::GetAllowedValues(int iParameter) {
+  return gtk_dasher_control_get_allowed_values(pDasherWidget, iParameter);
 }
 
-gboolean dasher_app_settings_get_module_settings(DasherAppSettings *pSelf, const gchar *szValue, 
SModuleSettings **pSettings, gint *iCount) {
-  DasherAppSettingsPrivate *pPrivate = (DasherAppSettingsPrivate*)(pSelf->private_data);
-  return gtk_dasher_control_get_module_settings(pPrivate->pDasherWidget, szValue, pSettings, iCount);
+gboolean DasherAppSettings::GetModuleSettings(const gchar *szValue,
+                                              SModuleSettings **pSettings,
+                                              gint *iCount) {
+  return gtk_dasher_control_get_module_settings(pDasherWidget, szValue, pSettings, iCount);
 }
 
 // Set the option szKey to szValue.  Return NULL if everything worked, a
 // (literal) error string for unrecognized or illegal values.
-const gchar *
-dasher_app_settings_cl_set(DasherAppSettings *pSelf, const gchar *szKey, const gchar *szValue) {
-
-  for(int i(0); i < NUM_OF_APP_BPS; ++i ) {
-    if(!strcmp(app_boolparamtable[i].regName, szKey)) {
-      
-      if(!strcmp(szValue, "1") || !strcmp(szValue, _("true")))
-        dasher_app_settings_set_bool(pSelf, app_boolparamtable[i].key, true);
-      else if(!strcmp(szValue, "0") || !strcmp(szValue, _("false")))
-        dasher_app_settings_set_bool(pSelf, app_boolparamtable[i].key, false);
-      else
-        return _("boolean value must be specified as 'true' or 'false'.");
-      return 0;
-    }
-  }
+const gchar * DasherAppSettings::ClSet(const gchar *szKey, const gchar *szValue) {
+  return settings_store_->ClSet(szKey, szValue);
+}
 
-  for(int i(0); i < NUM_OF_APP_LPS; ++i ) {
-    if(!strcmp(app_longparamtable[i].regName, szKey)) {
-      dasher_app_settings_set_long(pSelf, app_longparamtable[i].key, atoi(szValue));
-      return 0;
-    }
+void DasherAppSettings::HandleEvent(int iParameter) {
+  for (const auto& f : change_callbacks_) {
+    f.second(iParameter);
   }
-
-  for(int i(0); i < NUM_OF_APP_SPS; ++i ) {
-    if(!strcmp(app_stringparamtable[i].regName, szKey)) {
-      dasher_app_settings_set_string(pSelf, app_stringparamtable[i].key, szValue);
-      return 0;
-    }
-  }  
-  DasherAppSettingsPrivate *pPrivate = (DasherAppSettingsPrivate*)(pSelf->private_data);
-  return gtk_dasher_control_cl_set(pPrivate->pDasherWidget, szKey, szValue);
 }
 
-
 void option_help()
 {
   g_print("\n");
   g_print("%-30s %-12s  %s\n", _("Boolean parameters"), _("Default"), _("Description"));
   g_print("%-30s %-12s  %s\n", "------------------------------", "------------", 
"------------------------------");
   for(unsigned int i=0; i < sizeof(app_boolparamtable)/sizeof(app_boolparamtable[0]); ++i) {
-    g_print("%-30s %-12s  %s\n", app_boolparamtable[i].regName, (app_boolparamtable[i].bDefaultValue ? 
_("true") : _("false")), app_boolparamtable[i].humanReadable);
+    g_print("%-30s %-12s  %s\n", app_boolparamtable[i].regName, (app_boolparamtable[i].defaultValue ? 
_("true") : _("false")), app_boolparamtable[i].humanReadable);
   }
 
   for(unsigned int i = 0; i < sizeof(boolparamtable)/sizeof(boolparamtable[0]); i++) {
@@ -581,7 +135,7 @@ void option_help()
   g_print("%-30s %-12s  %s\n", _("Integer parameters"), _("Default"), _("Description"));
   g_print("%-30s %-12s  %s\n", "------------------------------", "------------", 
"------------------------------");
   for(unsigned int i=0; i < sizeof(app_longparamtable)/sizeof(app_longparamtable[0]); ++i) {
-    g_print("%-30s %12li  %s\n", app_longparamtable[i].regName, app_longparamtable[i].iDefaultValue, 
app_longparamtable[i].humanReadable);
+    g_print("%-30s %12li  %s\n", app_longparamtable[i].regName, app_longparamtable[i].defaultValue, 
app_longparamtable[i].humanReadable);
   }
 
   for(unsigned int i = 0; i < sizeof(longparamtable)/sizeof(longparamtable[0]); i++) {
@@ -592,11 +146,10 @@ void option_help()
   g_print("%-30s %-12s  %s\n", _("String parameters"), _("Default"), _("Description"));
   g_print("%-30s %-12s  %s\n", "------------------------------", "------------", 
"------------------------------");
   for(unsigned int i=0; i < sizeof(app_stringparamtable)/sizeof(app_stringparamtable[0]); ++i) {
-    g_print("%-30s %-12s  %s\n", app_stringparamtable[i].regName, app_stringparamtable[i].szDefaultValue, 
app_stringparamtable[i].humanReadable);
+    g_print("%-30s %-12s  %s\n", app_stringparamtable[i].regName, app_stringparamtable[i].defaultValue, 
app_stringparamtable[i].humanReadable);
   }
 
   for(unsigned int i = 0; i < sizeof(stringparamtable)/sizeof(stringparamtable[0]); i++) {
     g_print("%-30s %-12s  %s\n", stringparamtable[i].regName, stringparamtable[i].defaultValue, 
stringparamtable[i].humanReadable);
   }
-
 }
diff --git a/Src/Gtk2/DasherAppSettings.h b/Src/Gtk2/DasherAppSettings.h
index c1afaca..ff78c8f 100644
--- a/Src/Gtk2/DasherAppSettings.h
+++ b/Src/Gtk2/DasherAppSettings.h
@@ -1,83 +1,85 @@
 #ifndef __dasher_app_settings_h__
 #define __dasher_app_settings_h__
 
+#include <functional>
+#include <map>
+#include <memory>
+
 #include <glib.h>
 #include <glib-object.h>
 
 #include "../DasherCore/Parameters.h"
 #include "../Common/AppSettingsHeader.h"
 #include "../Common/ModuleSettings.h"
+#include "../DasherCore/SettingsStore.h"
+#include "../DasherCore/Observable.h"
 
 // Forward declarations
 typedef struct _GtkDasherControl GtkDasherControl;
 struct _GtkDasherControl;
-typedef struct _DasherMain DasherMain;
-struct _DasherMain;
-
-// Define first int value of the first element of each type.
-// Useful for offsetting into specific arrays,
-// since each setting is a unique int, but all 3 arrays start at 0
-#define FIRST_APP_BP END_OF_SPS
-#define FIRST_APP_LP END_OF_APP_BPS
-#define FIRST_APP_SP END_OF_APP_LPS
 
 // Define the number of each type of setting
 #define NUM_OF_APP_BPS (END_OF_APP_BPS - END_OF_SPS)
 #define NUM_OF_APP_LPS (END_OF_APP_LPS - END_OF_APP_BPS)
 #define NUM_OF_APP_SPS (END_OF_APP_SPS - END_OF_APP_LPS)
 
-enum {
-  DASHER_TYPE_BOOL,
-  DASHER_TYPE_LONG,
-  DASHER_TYPE_STRING
-};
-
-G_BEGIN_DECLS
-#define TYPE_DASHER_APP_SETTINGS            (dasher_app_settings_get_type())
-#define DASHER_APP_SETTINGS(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_DASHER_APP_SETTINGS, 
DasherAppSettings ))
-#define DASHER_APP_SETTINGS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_DASHER_APP_SETTINGS, 
DasherAppSettingsClass ))
-#define IS_DASHER_APP_SETTINGS(obj)        (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_DASHER_APP_SETTINGS))
-#define IS_DASHER_APP_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_DASHER_APP_SETTINGS))
-#define DASHER_APP_SETTINGS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_DASHER_APP_SETTINGS, 
DasherAppSettingsClass))
-
-typedef struct _DasherAppSettings DasherAppSettings;
-typedef struct _DasherAppSettingsClass DasherAppSettingsClass;
-
-struct _DasherAppSettings {
-  GObject parent;
-  gpointer private_data;
-};
-
-struct _DasherAppSettingsClass {
-  GObjectClass parent_class;
+// Singleton holding the settings.
+class DasherAppSettings : public Observer<int> {
+public:
+  // Returns the AppSettings singleton, 'Create' must have been called once beforehand.
+  static DasherAppSettings* Get() {
+    return instance_.get();
+  }
+  virtual ~DasherAppSettings();
+
+  // Initializes the AppSettings singleton and takes ownership of 'store'.
+  static void Create(Dasher::CSettingsStore* store) {
+    if (instance_ == nullptr) {
+      instance_.reset(new DasherAppSettings(store));
+    }
+  }
+
+  // 'fn' will be called each time a parameter is changed and its argument will be
+  // the setting id.
+  // The return value is used to unregister the callback.
+  int RegisterParameterChangeCallback(std::function<void(int)> fn);
+  // Use the value returned by 'RegisterParameterChangeCallback' to unregister it.
+  void UnregisterParameterChangeCallback(int);
+
+  void Load();
+  void SetWidget(GtkDasherControl *pWidget);
+  bool GetBool(int iParameter);
+  void SetBool(int iParameter, bool bValue);
+  gint GetLong(int iParameter);
+  void SetLong(int iParameter, gint iValue);
+  const std::string& GetString(int iParameter);
+  void SetString(int iParameter, const gchar *szValue);
+  int GetCount();
+  GArray *GetAllowedValues(int iParameter);
+  bool HaveAdvanced();
+  void LaunchAdvanced();
+  gboolean GetModuleSettings(const gchar *szValue, SModuleSettings **pSettings, gint *iCount);
+  const gchar * ClSet(const gchar *szKey, const gchar *szValue);
+  Dasher::CSettingsStore* GetStore() { return settings_store_.get(); }
+
+private:
+  DasherAppSettings(Dasher::CSettingsStore* store);
+  // The callback for the SettingsStore notifications.
+  void HandleEvent(int iParameter) override;
+
+  // The object is non copyable.
+  DasherAppSettings(const DasherAppSettings&) = delete;
+  void operator=(const DasherAppSettings&) = delete;
+
+  // Holds the singleton instance.
+  static std::unique_ptr<DasherAppSettings> instance_;
+
+  GtkDasherControl *pDasherWidget = nullptr;
+  std::unique_ptr<Dasher::CSettingsStore> settings_store_ = nullptr;
+  std::map<int, std::function<void(int)>> change_callbacks_;
+  int callback_id_ = 0;
 };
 
-DasherAppSettings *dasher_app_settings_new(DasherMain *, int argc, char **argv);
-GType dasher_app_settings_get_type();
-
-void dasher_app_settings_reset(DasherAppSettings *pSelf, int iParameter);
-void dasher_app_settings_set_widget(DasherAppSettings *pSelf, GtkDasherControl *pWidget);
-
-bool dasher_app_settings_get_bool(DasherAppSettings *pSelf, int iParameter);
-void dasher_app_settings_set_bool(DasherAppSettings *pSelf, int iParameter, bool bValue);
-gint dasher_app_settings_get_long(DasherAppSettings *pSelf, int iParameter);
-void dasher_app_settings_set_long(DasherAppSettings *pSelf, int iParameter, gint iValue);
-const gchar *dasher_app_settings_get_string(DasherAppSettings *pSelf, int iParameter);
-void dasher_app_settings_set_string(DasherAppSettings *pSelf, int iParameter, const gchar *szValue);
-
-int dasher_app_settings_get_count(DasherAppSettings *pSelf);
-GArray *dasher_app_settings_get_allowed_values(DasherAppSettings *pSelf, int iParameter);
-int dasher_app_settings_get_parameter_type(DasherAppSettings *pSelf, int iParameter);
-const gchar *dasher_app_settings_get_reg_name(DasherAppSettings *pSelf, int iParameter);
-const gchar *dasher_app_settings_get_human_name(DasherAppSettings *pSelf, int iParameter);
-bool dasher_app_settings_have_advanced(DasherAppSettings *pSelf);
-void dasher_app_settings_launch_advanced(DasherAppSettings *pSelf);
-
-gboolean dasher_app_settings_get_module_settings(DasherAppSettings *pSelf, const gchar *szValue, 
SModuleSettings **pSettings, gint *iCount);
-
-const gchar * dasher_app_settings_cl_set(DasherAppSettings *pSelf, const gchar *szKey, const gchar *szValue);
-
 void option_help();
-G_END_DECLS
 
 #endif
diff --git a/Src/Gtk2/GenerateSchema.cpp b/Src/Gtk2/GenerateSchema.cpp
index 093ab5a..d979617 100644
--- a/Src/Gtk2/GenerateSchema.cpp
+++ b/Src/Gtk2/GenerateSchema.cpp
@@ -187,10 +187,10 @@ int main(int argc, char **argv) {
 
   for(int i(0); i < END_OF_APP_BPS - END_OF_SPS; ++i) {
 
-    if(app_boolparamtable[i].persistent) {
+    if(app_boolparamtable[i].persistent == Persistence::PERSISTENT) {
       std::string strDefault;
       
-      if(app_boolparamtable[i].bDefaultValue)
+      if(app_boolparamtable[i].defaultValue)
        strDefault = "TRUE";
       else
        strDefault = "FALSE";
@@ -221,11 +221,11 @@ int main(int argc, char **argv) {
   }  
  
   for(int i(0); i < END_OF_APP_LPS - END_OF_APP_BPS; ++i) {
-    if(app_longparamtable[i].persistent) {
+    if(app_longparamtable[i].persistent == Persistence::PERSISTENT) {
 
       std::stringstream ssDefault;
       
-      ssDefault << app_longparamtable[i].iDefaultValue;
+      ssDefault << app_longparamtable[i].defaultValue;
 
       
       CSchema oSchema( app_longparamtable[i].regName,
@@ -249,10 +249,10 @@ int main(int argc, char **argv) {
   } 
   
   for(int i(0); i < END_OF_APP_SPS - END_OF_APP_LPS; ++i) {
-    if(app_stringparamtable[i].persistent) {
+    if(app_stringparamtable[i].persistent == Persistence::PERSISTENT) {
       CSchema oSchema( app_stringparamtable[i].regName,
                       TYPE_STRING,
-                      app_stringparamtable[i].szDefaultValue,
+                      app_stringparamtable[i].defaultValue,
                       "",
                       app_stringparamtable[i].humanReadable );
       
diff --git a/Src/Gtk2/GtkDasherControl.cpp b/Src/Gtk2/GtkDasherControl.cpp
index 5dca279..6d6ca2b 100644
--- a/Src/Gtk2/GtkDasherControl.cpp
+++ b/Src/Gtk2/GtkDasherControl.cpp
@@ -25,6 +25,7 @@
 #include "GtkDasherControl.h"
 #include "custom_marshal.h"
 #include "dasher_editor.h"
+#include "DasherAppSettings.h"
 
 // TODO: find a better way to get access to the command line arguments.
 extern gchar* g_xml_file_location;
@@ -111,30 +112,10 @@ gtk_dasher_control_class_init(GtkDasherControlClass *pClass) {
   // pClass->key_release_event = gtk_dasher_control_default_key_release_handler;
 }
 
-class XmlErrorDisplay : public CMessageDisplay {
- public:
-  void Message(const std::string &strText, bool bInterrupt) override {
-    // TODO: decide if a pop-up dialog should be shown instead.
-    fputs(strText.c_str(), stderr);
-    fputs("\n", stderr);
-  }
-};
-
 static void 
 gtk_dasher_control_init(GtkDasherControl *pDasherControl) {
   GtkDasherControlPrivate *pPrivate = GTK_DASHER_CONTROL_GET_PRIVATE(pDasherControl);
-  static XmlErrorDisplay display;
-  Dasher::CSettingsStore* settings;
-  if (g_xml_file_location == nullptr) {
-    settings = new CGnomeSettingsStore();
-  } else {
-    auto xml_settings = new XmlSettingsStore(g_xml_file_location, &display);
-    xml_settings->Load();
-    // Save the defaults if needed.
-    xml_settings->Save();
-    settings = xml_settings;
-  }
-  pPrivate->pControl = new CDasherControl(&(pDasherControl->box), pDasherControl, settings);
+  pPrivate->pControl = new CDasherControl(&(pDasherControl->box), pDasherControl, 
DasherAppSettings::Get()->GetStore());
 
 //   g_signal_connect(G_OBJECT(pDasherControl), "key-press-event", 
G_CALLBACK(gtk_dasher_control_default_key_press_handler), pPrivate->pControl);
 //   g_signal_connect(G_OBJECT(pDasherControl), "key-release-event", 
G_CALLBACK(gtk_dasher_control_default_key_release_handler), pPrivate->pControl);
diff --git a/Src/Gtk2/KeyboardHelper.cpp b/Src/Gtk2/KeyboardHelper.cpp
index 9b46ad1..7727a75 100644
--- a/Src/Gtk2/KeyboardHelper.cpp
+++ b/Src/Gtk2/KeyboardHelper.cpp
@@ -19,7 +19,7 @@ CKeyboardHelper::CKeyboardHelper(DasherAppSettings *pAppSettings) {
   m_pAppSettings = pAppSettings;
 
   // For now assume we either have all or nothing
-  if(!m_pAppSettings || (!strcmp(dasher_app_settings_get_string(m_pAppSettings, SP_BUTTON_0), "")))
+  if(!m_pAppSettings || (!m_pAppSettings->GetString(SP_BUTTON_0).empty()))
     SetupDefaults();
   else
     LoadSettings();
@@ -95,7 +95,7 @@ void CKeyboardHelper::LoadSettings() {
   int iCount(sizeof(iButtons) / sizeof(int));
   
   for(int i(0); i < iCount; ++i) {
-    std::string strEntry(dasher_app_settings_get_string(m_pAppSettings, iIDs[i]));
+    std::string strEntry(m_pAppSettings->GetString(iIDs[i]));
     std::string strCurrent;
 
     for(std::string::iterator it(strEntry.begin()); it != strEntry.end(); ++it) {
@@ -149,7 +149,7 @@ void CKeyboardHelper::SaveSettings() {
       return;
     }
 
-    dasher_app_settings_set_string(m_pAppSettings, iID, it->second.c_str());
+    m_pAppSettings->SetString(iID, it->second.c_str());
   }
 }
 
diff --git a/Src/Gtk2/Preferences.cpp b/Src/Gtk2/Preferences.cpp
index 62d4351..0f0c9d2 100644
--- a/Src/Gtk2/Preferences.cpp
+++ b/Src/Gtk2/Preferences.cpp
@@ -347,7 +347,7 @@ void dasher_preferences_dialogue_refresh_widget(DasherPreferencesDialogue *pSelf
   int iNumBoolEntries = sizeof(sBoolTranslationTable) / sizeof(BoolTranslation);
   for(int i(0); i < iNumBoolEntries; ++i) {
     if((iParameter == -1) || (sBoolTranslationTable[i].iParameter == iParameter)) {
-      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sBoolTranslationTable[i].pWidget), 
dasher_app_settings_get_bool(pPrivate->pAppSettings, sBoolTranslationTable[i].iParameter));
+      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sBoolTranslationTable[i].pWidget), 
pPrivate->pAppSettings->GetBool(sBoolTranslationTable[i].iParameter));
     }
   }
 #endif
@@ -362,7 +362,7 @@ void dasher_preferences_dialogue_refresh_widget(DasherPreferencesDialogue *pSelf
 
       // TODO: tidy up in a struct
       const void *pUserData[3];
-      pUserData[0] = dasher_app_settings_get_string(pPrivate->pAppSettings, 
sStringTranslationTable[i].iParameter);
+      pUserData[0] = pPrivate->pAppSettings->GetString(sStringTranslationTable[i].iParameter).c_str();
       pUserData[1] = GTK_TREE_VIEW(sStringTranslationTable[i].pWidget);
       pUserData[2] = pSelf;
 
@@ -385,9 +385,9 @@ static void dasher_preferences_dialogue_refresh_parameter(DasherPreferencesDialo
   for(int i(0); i < iNumBoolEntries; ++i) {
     if((pWidget == NULL) || (sBoolTranslationTable[i].pWidget == pWidget)) {
 
-      if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sBoolTranslationTable[i].pWidget)) != 
dasher_app_settings_get_bool(pPrivate->pAppSettings, sBoolTranslationTable[i].iParameter)) {
+      if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sBoolTranslationTable[i].pWidget)) != 
pPrivate->pAppSettings->GetBool(sBoolTranslationTable[i].iParameter)) {
         
-        dasher_app_settings_set_bool(pPrivate->pAppSettings, sBoolTranslationTable[i].iParameter, 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sBoolTranslationTable[i].pWidget)));
+        pPrivate->pAppSettings->SetBool(sBoolTranslationTable[i].iParameter, 
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sBoolTranslationTable[i].pWidget)));
       }
     }
   }
@@ -409,9 +409,9 @@ extern "C" void generic_bool_changed(GtkWidget *widget, gpointer user_data) {
 extern "C" void outline_button_toggled(GtkWidget *widget, gpointer user_data) {
        DasherPreferencesDialoguePrivate *pPrivate = 
DASHER_PREFERENCES_DIALOGUE_PRIVATE(g_pPreferencesDialogue);
        if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
-               dasher_app_settings_set_long(pPrivate->pAppSettings, LP_OUTLINE_WIDTH, 1);
+               pPrivate->pAppSettings->SetLong(LP_OUTLINE_WIDTH, 1);
        } else {
-               dasher_app_settings_set_long(pPrivate->pAppSettings, LP_OUTLINE_WIDTH, 0);
+               pPrivate->pAppSettings->SetLong(LP_OUTLINE_WIDTH, 0);
        }
 }
 
@@ -421,9 +421,9 @@ extern "C" void outline_button_toggled(GtkWidget *widget, gpointer user_data) {
 void dasher_preferences_dialogue_populate_list(DasherPreferencesDialogue *pSelf, GtkTreeView *pView, int 
iParameter, GtkWidget *pHelper) {
   DasherPreferencesDialoguePrivate *pPrivate = DASHER_PREFERENCES_DIALOGUE_PRIVATE(pSelf);
   
-  const gchar *szCurrentValue(dasher_app_settings_get_string(pPrivate->pAppSettings, iParameter));
+  const gchar *szCurrentValue(pPrivate->pAppSettings->GetString(iParameter).c_str());
 
-  GArray *pFilterArray = dasher_app_settings_get_allowed_values(pPrivate->pAppSettings, iParameter);
+  GArray *pFilterArray = pPrivate->pAppSettings->GetAllowedValues(iParameter);
 
   //for each item in the list: the dasher Parameters.h number (i.e. same for all items); the "helper" button 
(as above, also the same for all items);
   // the text to display (and perhaps pass to SetStringParameter).
@@ -478,13 +478,13 @@ extern "C" void on_list_selection(GtkTreeSelection *pSelection, gpointer pUserDa
     gchar *szValue;
     gtk_tree_model_get(pModel, &oIter, 0, &iParameter, 1, &pHelper, 2, &szValue, -1);
     
-    dasher_app_settings_set_string(pPrivate->pAppSettings, iParameter, szValue);
+    pPrivate->pAppSettings->SetString(iParameter, szValue);
 
     if(pHelper) {
       //check if input filter/device has any settings...
       SModuleSettings *pSettings;
       int iCount;
-      bool bHasSettings = dasher_app_settings_get_module_settings(pPrivate->pAppSettings, szValue, 
&pSettings, &iCount);
+      bool bHasSettings = pPrivate->pAppSettings->GetModuleSettings(szValue, &pSettings, &iCount);
       gtk_widget_set_sensitive(GTK_WIDGET(pHelper), bHasSettings);
     }
 
@@ -497,7 +497,7 @@ extern "C" void on_list_selection(GtkTreeSelection *pSelection, gpointer pUserDa
 static void dasher_preferences_dialogue_populate_special_speed(DasherPreferencesDialogue *pSelf) {
   DasherPreferencesDialoguePrivate *pPrivate = DASHER_PREFERENCES_DIALOGUE_PRIVATE(pSelf);
 
-  double dNewValue = dasher_app_settings_get_long(pPrivate->pAppSettings, LP_MAX_BITRATE) / 100.0;
+  double dNewValue = pPrivate->pAppSettings->GetLong(LP_MAX_BITRATE) / 100.0;
   gtk_range_set_value(pPrivate->pSpeedSlider, dNewValue);
 }
 
@@ -508,11 +508,11 @@ static void dasher_preferences_dialogue_populate_special_mouse_start(DasherPrefe
   pPrivate->pMousePosButton = GTK_TOGGLE_BUTTON(gtk_builder_get_object(pPrivate->pXML, "mouseposbutton"));
   pPrivate->pMousePosStyle = GTK_COMBO_BOX(gtk_builder_get_object(pPrivate->pXML, "MousePosStyle"));
 
-  if(dasher_app_settings_get_bool(pPrivate->pAppSettings, BP_MOUSEPOS_MODE)) {
+  if(pPrivate->pAppSettings->GetBool(BP_MOUSEPOS_MODE)) {
     gtk_combo_box_set_active(pPrivate->pMousePosStyle, 1);
     gtk_toggle_button_set_active(pPrivate->pMousePosButton, true);
   }
-  else if(dasher_app_settings_get_bool(pPrivate->pAppSettings, BP_CIRCLE_START)) {
+  else if(pPrivate->pAppSettings->GetBool(BP_CIRCLE_START)) {
     gtk_combo_box_set_active(pPrivate->pMousePosStyle, 0);
     gtk_toggle_button_set_active(pPrivate->pMousePosButton, true);
   }
@@ -531,7 +531,7 @@ static void dasher_preferences_dialogue_populate_special_orientation(DasherPrefe
   pPrivate->pTBButton = GTK_TOGGLE_BUTTON(gtk_builder_get_object(pPrivate->pXML, "radiobutton4"));
   pPrivate->pBTButton = GTK_TOGGLE_BUTTON(gtk_builder_get_object(pPrivate->pXML, "radiobutton5"));
   GtkToggleButton *pButton;
-  switch (dasher_app_settings_get_long(pPrivate->pAppSettings, LP_ORIENTATION)) {
+  switch (pPrivate->pAppSettings->GetLong(LP_ORIENTATION)) {
   case Dasher::Opts::AlphabetDefault:
     pButton = pPrivate->pAlphOrient; break;
 
@@ -559,7 +559,7 @@ static void dasher_preferences_dialogue_populate_special_appstyle(DasherPreferen
 #ifndef WITH_MAEMO  
   DasherPreferencesDialoguePrivate *pPrivate = DASHER_PREFERENCES_DIALOGUE_PRIVATE(pSelf);
 
-  switch(dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_STYLE)) {
+  switch(pPrivate->pAppSettings->GetLong(APP_LP_STYLE)) {
   case 0:
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(pPrivate->pXML, 
"appstyle_classic")), TRUE);
     break;
@@ -580,7 +580,7 @@ static void dasher_preferences_dialogue_populate_special_linewidth(DasherPrefere
 #ifndef WITH_MAEMO
   DasherPreferencesDialoguePrivate *pPrivate = DASHER_PREFERENCES_DIALOGUE_PRIVATE(pSelf);
 
-  if(dasher_app_settings_get_long(pPrivate->pAppSettings, LP_LINE_WIDTH) > 1)
+  if(pPrivate->pAppSettings->GetLong(LP_LINE_WIDTH) > 1)
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(pPrivate->pXML, 
"thicklinebutton")), true);
   else
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(pPrivate->pXML, 
"thicklinebutton")), false);
@@ -591,7 +591,7 @@ static void dasher_preferences_dialogue_populate_special_linewidth(DasherPrefere
 static void dasher_preferences_dialogue_populate_special_lm(DasherPreferencesDialogue *pSelf) {
   DasherPreferencesDialoguePrivate *pPrivate = DASHER_PREFERENCES_DIALOGUE_PRIVATE(pSelf);
 
-  switch( dasher_app_settings_get_long(pPrivate->pAppSettings, LP_LANGUAGE_MODEL_ID )) {
+  switch( pPrivate->pAppSettings->GetLong(LP_LANGUAGE_MODEL_ID )) {
   case 0:
     if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(pPrivate->pXML, 
"radiobutton6"))) != TRUE)
       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(pPrivate->pXML, 
"radiobutton6")), TRUE);
@@ -616,14 +616,14 @@ static void dasher_preferences_dialogue_populate_special_lm(DasherPreferencesDia
 static void dasher_preferences_dialogue_populate_special_uniform(DasherPreferencesDialogue *pSelf) {
   DasherPreferencesDialoguePrivate *pPrivate = DASHER_PREFERENCES_DIALOGUE_PRIVATE(pSelf);
 
-  gtk_range_set_value( GTK_RANGE(gtk_builder_get_object(pPrivate->pXML, "uniformhscale")), 
dasher_app_settings_get_long(pPrivate->pAppSettings, LP_UNIFORM)/10.0);
+  gtk_range_set_value( GTK_RANGE(gtk_builder_get_object(pPrivate->pXML, "uniformhscale")), 
pPrivate->pAppSettings->GetLong(LP_UNIFORM)/10.0);
 }
 
 static void dasher_preferences_dialogue_populate_special_colour(DasherPreferencesDialogue *pSelf) {
   DasherPreferencesDialoguePrivate *pPrivate = DASHER_PREFERENCES_DIALOGUE_PRIVATE(pSelf);
 
-  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(pPrivate->pXML, "manual_colour")), 
!dasher_app_settings_get_bool(pPrivate->pAppSettings, BP_PALETTE_CHANGE));
-  gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(pPrivate->pXML, "ColorTree")), 
!dasher_app_settings_get_bool(pPrivate->pAppSettings, BP_PALETTE_CHANGE));
+  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(pPrivate->pXML, "manual_colour")), 
!pPrivate->pAppSettings->GetBool(BP_PALETTE_CHANGE));
+  gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(pPrivate->pXML, "ColorTree")), 
!pPrivate->pAppSettings->GetBool(BP_PALETTE_CHANGE));
 }
 
 static void dasher_preferences_dialogue_populate_special_dasher_font(DasherPreferencesDialogue *pSelf) {
@@ -632,7 +632,7 @@ static void dasher_preferences_dialogue_populate_special_dasher_font(DasherPrefe
   GObject *pDasherFontButton = gtk_builder_get_object(pPrivate->pXML, "dasher_fontbutton");
 
   gtk_font_button_set_font_name(GTK_FONT_BUTTON(pDasherFontButton), 
-                                dasher_app_settings_get_string(pPrivate->pAppSettings, SP_DASHER_FONT));
+                                pPrivate->pAppSettings->GetString(SP_DASHER_FONT).c_str());
 }
 
 static void dasher_preferences_dialogue_populate_special_edit_font(DasherPreferencesDialogue *pSelf) {
@@ -641,13 +641,13 @@ static void dasher_preferences_dialogue_populate_special_edit_font(DasherPrefere
   GObject *pEditFontButton = gtk_builder_get_object(pPrivate->pXML, "edit_fontbutton");
 
   gtk_font_button_set_font_name(GTK_FONT_BUTTON(pEditFontButton), 
-                                dasher_app_settings_get_string(pPrivate->pAppSettings, APP_SP_EDIT_FONT));
+                                pPrivate->pAppSettings->GetString(APP_SP_EDIT_FONT).c_str());
 }
  
 static void dasher_preferences_dialogue_populate_special_fontsize(DasherPreferencesDialogue *pSelf) {
   DasherPreferencesDialoguePrivate *pPrivate = DASHER_PREFERENCES_DIALOGUE_PRIVATE(pSelf);
 
-  int iValue = dasher_app_settings_get_long(pPrivate->pAppSettings, LP_DASHER_FONTSIZE);
+  int iValue = pPrivate->pAppSettings->GetLong(LP_DASHER_FONTSIZE);
   gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(gtk_builder_get_object(pPrivate->pXML, "fontsizenormal")), 
iValue == Opts::Normal);
   gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(gtk_builder_get_object(pPrivate->pXML, "fontsizelarge")), 
iValue == Opts::Big);
   gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(gtk_builder_get_object(pPrivate->pXML, "fontsizevlarge")), 
iValue == Opts::VBig);
@@ -683,8 +683,8 @@ extern "C" void OnMousePosChanged(GtkWidget *widget, gpointer user_data) {
        }
   } else iIndex=-1;
   
-  dasher_app_settings_set_bool(pPrivate->pAppSettings, BP_MOUSEPOS_MODE, iIndex==1);
-  dasher_app_settings_set_bool(pPrivate->pAppSettings, BP_CIRCLE_START, iIndex==0);
+  pPrivate->pAppSettings->SetBool(BP_MOUSEPOS_MODE, iIndex==1);
+  pPrivate->pAppSettings->SetBool(BP_CIRCLE_START, iIndex==0);
   
 }
 
@@ -693,7 +693,7 @@ extern "C" void PrefsSpeedSliderChanged(GtkHScale *hscale, gpointer user_data) {
   DasherPreferencesDialoguePrivate *pPrivate = DASHER_PREFERENCES_DIALOGUE_PRIVATE(g_pPreferencesDialogue); 
// TODO: Fix NULL
   
   long iNewValue = long(round(gtk_range_get_value(GTK_RANGE(hscale)) * 100));
-  dasher_app_settings_set_long(pPrivate->pAppSettings, LP_MAX_BITRATE, iNewValue);
+  pPrivate->pAppSettings->SetLong(LP_MAX_BITRATE, iNewValue);
 }
 
 extern "C" void orientation(GtkRadioButton *widget, gpointer user_data) {
@@ -716,7 +716,7 @@ extern "C" void orientation(GtkRadioButton *widget, gpointer user_data) {
   } else if (pButton == pPrivate->pBTButton) {
     orient = Dasher::Opts::BottomToTop;
   }
-  dasher_app_settings_set_long(pPrivate->pAppSettings, LP_ORIENTATION, orient);
+  pPrivate->pAppSettings->SetLong(LP_ORIENTATION, orient);
 
 }
 
@@ -725,16 +725,16 @@ extern "C" void ThickLineClicked(GtkWidget *widget, gpointer user_data) {
   DasherPreferencesDialoguePrivate *pPrivate = DASHER_PREFERENCES_DIALOGUE_PRIVATE(g_pPreferencesDialogue); 
// TODO: Fix NULL
 
   if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
-    dasher_app_settings_set_long(pPrivate->pAppSettings, LP_LINE_WIDTH, 3);
+    pPrivate->pAppSettings->SetLong(LP_LINE_WIDTH, 3);
   else
-    dasher_app_settings_set_long(pPrivate->pAppSettings, LP_LINE_WIDTH, 1);
+    pPrivate->pAppSettings->SetLong(LP_LINE_WIDTH, 1);
 }
 
 extern "C" void autocolour_clicked(GtkWidget *widget, gpointer user_data) {
   //  DasherPreferencesDialoguePrivate *pPrivate = DASHER_PREFERENCES_DIALOGUE_PRIVATE(pSelf);
   DasherPreferencesDialoguePrivate *pPrivate = DASHER_PREFERENCES_DIALOGUE_PRIVATE(g_pPreferencesDialogue); 
// TODO: Fix NULL
 
-  dasher_app_settings_set_bool(pPrivate->pAppSettings, BP_PALETTE_CHANGE, 
!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
+  pPrivate->pAppSettings->SetLong(BP_PALETTE_CHANGE, 
!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
 }
 
 extern "C" void mouseposstart_y_changed(GtkRange *widget, gpointer user_data) {
@@ -742,7 +742,7 @@ extern "C" void mouseposstart_y_changed(GtkRange *widget, gpointer user_data) {
   DasherPreferencesDialoguePrivate *pPrivate = DASHER_PREFERENCES_DIALOGUE_PRIVATE(g_pPreferencesDialogue); 
// TODO: Fix NULL
 
   int mouseposstartdist=int(gtk_adjustment_get_value(gtk_range_get_adjustment(widget)));
-  dasher_app_settings_set_long(pPrivate->pAppSettings, LP_MOUSEPOSDIST, mouseposstartdist);
+  pPrivate->pAppSettings->SetLong(LP_MOUSEPOSDIST, mouseposstartdist);
 }
 
 extern "C" void languagemodel(GtkRadioButton *widget, gpointer user_data) {
@@ -752,25 +752,25 @@ extern "C" void languagemodel(GtkRadioButton *widget, gpointer user_data) {
 #if GTK_CHECK_VERSION (2,20,0)
   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))==TRUE) {
     if( !strcmp( gtk_buildable_get_name( GTK_BUILDABLE(widget) ), "radiobutton6" ) ) {
-      dasher_app_settings_set_long(pPrivate->pAppSettings, LP_LANGUAGE_MODEL_ID, 0 );
+      pPrivate->pAppSettings->SetLong(LP_LANGUAGE_MODEL_ID, 0 );
     } else if (!strcmp( gtk_buildable_get_name( GTK_BUILDABLE(widget) ), "radiobutton7" )) {
-      dasher_app_settings_set_long(pPrivate->pAppSettings, LP_LANGUAGE_MODEL_ID, 2 );
+      pPrivate->pAppSettings->SetLong(LP_LANGUAGE_MODEL_ID, 2 );
     } else if (!strcmp( gtk_buildable_get_name( GTK_BUILDABLE(widget) ), "radiobutton8" )) {
-      dasher_app_settings_set_long(pPrivate->pAppSettings, LP_LANGUAGE_MODEL_ID, 3 );
+      pPrivate->pAppSettings->SetLong(LP_LANGUAGE_MODEL_ID, 3 );
     } else if (!strcmp( gtk_buildable_get_name( GTK_BUILDABLE(widget) ), "radiobutton9" )) {
-      dasher_app_settings_set_long(pPrivate->pAppSettings, LP_LANGUAGE_MODEL_ID, 4 );
+      pPrivate->pAppSettings->SetLong(LP_LANGUAGE_MODEL_ID, 4 );
     }
   }
 #else
   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))==TRUE) {
     if( !strcmp( gtk_widget_get_name( GTK_WIDGET(widget) ), "radiobutton6" ) ) {
-      dasher_app_settings_set_long(pPrivate->pAppSettings, LP_LANGUAGE_MODEL_ID, 0 );
+      pPrivate->pAppSettings->SetLong(LP_LANGUAGE_MODEL_ID, 0 );
     } else if (!strcmp( gtk_widget_get_name( GTK_WIDGET(widget) ), "radiobutton7" )) {
-      dasher_app_settings_set_long(pPrivate->pAppSettings, LP_LANGUAGE_MODEL_ID, 2 );
+      pPrivate->pAppSettings->SetLong(LP_LANGUAGE_MODEL_ID, 2 );
     } else if (!strcmp( gtk_widget_get_name( GTK_WIDGET(widget) ), "radiobutton8" )) {
-      dasher_app_settings_set_long(pPrivate->pAppSettings, LP_LANGUAGE_MODEL_ID, 3 );
+      pPrivate->pAppSettings->SetLong(LP_LANGUAGE_MODEL_ID, 3 );
     } else if (!strcmp( gtk_widget_get_name( GTK_WIDGET(widget) ), "radiobutton9" )) {
-      dasher_app_settings_set_long(pPrivate->pAppSettings, LP_LANGUAGE_MODEL_ID, 4 );
+      pPrivate->pAppSettings->SetLong(LP_LANGUAGE_MODEL_ID, 4 );
     }
   }
 #endif
@@ -788,7 +788,7 @@ extern "C" void uniform_changed(GtkHScale *hscale) {
     gtk_range_set_value(GTK_RANGE(gtk_builder_get_object(pPrivate->pXML, "uniformhscale")), 5.0);
   }
   
-  dasher_app_settings_set_long(pPrivate->pAppSettings, LP_UNIFORM, iValue);
+  pPrivate->pAppSettings->SetLong(LP_UNIFORM, iValue);
 }
 
 extern "C" gboolean show_helper_window(GtkWidget *pWidget, gpointer *pUserData) {
@@ -808,7 +808,7 @@ extern "C" gboolean show_helper_window(GtkWidget *pWidget, gpointer *pUserData)
   
   SModuleSettings *pSettings;
   int iCount;
-  if (!dasher_app_settings_get_module_settings(pPrivate->pAppSettings, szValue, &pSettings, &iCount))
+  if (!pPrivate->pAppSettings->GetModuleSettings(szValue, &pSettings, &iCount))
     DASHER_ASSERT(false); //button should only be sensitive if item has settings
   
   GtkWidget *pWindow = module_settings_window_new(pPrivate->pAppSettings, szValue, pSettings, iCount);
@@ -826,38 +826,38 @@ extern "C" void on_appstyle_changed(GtkWidget *widget, gpointer user_data) {
 #if GTK_CHECK_VERSION (2,20,0)
   if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
     if(!strcmp(gtk_buildable_get_name(GTK_BUILDABLE(widget)), "appstyle_classic"))
-      dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, 0);
+      pPrivate->pAppSettings->SetLong(APP_LP_STYLE, 0);
     else if(!strcmp(gtk_buildable_get_name(GTK_BUILDABLE(widget)), "appstyle_compose"))
-      dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, 1);
+      pPrivate->pAppSettings->SetLong(APP_LP_STYLE, 1);
     else if(!strcmp(gtk_buildable_get_name(GTK_BUILDABLE(widget)), "appstyle_direct"))
-      dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, 2);
+      pPrivate->pAppSettings->SetLong(APP_LP_STYLE, 2);
     else if(!strcmp(gtk_buildable_get_name(GTK_BUILDABLE(widget)), "appstyle_fullscreen"))
-      dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, 3);
+      pPrivate->pAppSettings->SetLong(APP_LP_STYLE, 3);
   }
 #else
   if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
     if(!strcmp(gtk_widget_get_name(GTK_WIDGET(widget)), "appstyle_classic"))
-      dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, 0);
+      pPrivate->pAppSettings->SetLong(APP_LP_STYLE, 0);
     else if(!strcmp(gtk_widget_get_name(GTK_WIDGET(widget)), "appstyle_compose"))
-      dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, 1);
+      pPrivate->pAppSettings->SetLong(APP_LP_STYLE, 1);
     else if(!strcmp(gtk_widget_get_name(GTK_WIDGET(widget)), "appstyle_direct"))
-      dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, 2);
+      pPrivate->pAppSettings->SetLong(APP_LP_STYLE, 2);
     else if(!strcmp(gtk_widget_get_name(GTK_WIDGET(widget)), "appstyle_fullscreen"))
-      dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, 3);
+      pPrivate->pAppSettings->SetLong(APP_LP_STYLE, 3);
   }
 #endif
 }
 
 extern "C" void on_dasher_font_changed(GtkFontButton *pButton, gpointer pUserData) {
   DasherMainPrivate *pMainPrivate = DASHER_MAIN_GET_PRIVATE(pUserData);
-  dasher_app_settings_set_string(pMainPrivate->pAppSettings,
+  pMainPrivate->pAppSettings->SetString(
                                  SP_DASHER_FONT, 
                                  gtk_font_button_get_font_name(pButton));
 }
 
 extern "C" void on_edit_font_changed(GtkFontButton *pButton, gpointer pUserData) {
   DasherMainPrivate *pMainPrivate = DASHER_MAIN_GET_PRIVATE(pUserData);
-  dasher_app_settings_set_string(pMainPrivate->pAppSettings,
+  pMainPrivate->pAppSettings->SetString(
                                  APP_SP_EDIT_FONT, 
                                  gtk_font_button_get_font_name(pButton));
 }
@@ -865,14 +865,14 @@ extern "C" void on_edit_font_changed(GtkFontButton *pButton, gpointer pUserData)
 extern "C" void set_dasher_fontsize(GtkWidget *pWidget, gboolean pUserData) {
   DasherPreferencesDialoguePrivate *pPrivate = DASHER_PREFERENCES_DIALOGUE_PRIVATE(g_pPreferencesDialogue);
 
-  int iValue = dasher_app_settings_get_long(pPrivate->pAppSettings, LP_DASHER_FONTSIZE);
+  int iValue = pPrivate->pAppSettings->GetLong(LP_DASHER_FONTSIZE);
 
   if((iValue != Opts::Normal) && gtk_toggle_button_get_active( 
GTK_TOGGLE_BUTTON(gtk_builder_get_object(pPrivate->pXML, "fontsizenormal"))))
-    dasher_app_settings_set_long(pPrivate->pAppSettings, LP_DASHER_FONTSIZE, Opts::Normal);
+    pPrivate->pAppSettings->SetLong(LP_DASHER_FONTSIZE, Opts::Normal);
   else if((iValue != Opts::Big) && gtk_toggle_button_get_active( 
GTK_TOGGLE_BUTTON(gtk_builder_get_object(pPrivate->pXML, "fontsizelarge"))))
-    dasher_app_settings_set_long(pPrivate->pAppSettings, LP_DASHER_FONTSIZE, Opts::Big);
+    pPrivate->pAppSettings->SetLong(LP_DASHER_FONTSIZE, Opts::Big);
   else if((iValue != Opts::VBig) && gtk_toggle_button_get_active( 
GTK_TOGGLE_BUTTON(gtk_builder_get_object(pPrivate->pXML, "fontsizevlarge"))))
-    dasher_app_settings_set_long(pPrivate->pAppSettings, LP_DASHER_FONTSIZE, Opts::VBig);
+    pPrivate->pAppSettings->SetLong(LP_DASHER_FONTSIZE, Opts::VBig);
 }
 
 
diff --git a/Src/Gtk2/dasher_editor.cpp b/Src/Gtk2/dasher_editor.cpp
index 99ec3b2..8b99384 100644
--- a/Src/Gtk2/dasher_editor.cpp
+++ b/Src/Gtk2/dasher_editor.cpp
@@ -86,7 +86,7 @@ extern "C" void gtk2_edit_output_callback(GtkDasherControl *pDasherControl, cons
 
 static gboolean
 isdirect(DasherAppSettings *pAppSettings) {
-  return (dasher_app_settings_get_long(pAppSettings, APP_LP_STYLE) == APP_STYLE_DIRECT);
+  return pAppSettings->GetLong(APP_LP_STYLE) == APP_STYLE_DIRECT;
 }
 
 static void
@@ -216,8 +216,7 @@ dasher_editor_initialise(DasherEditor *pSelf, DasherAppSettings *pAppSettings, G
   pPrivate->pDasherCtrl = pDasherCtrl;
 
   dasher_editor_internal_handle_font(pSelf,
-                                    dasher_app_settings_get_string(pPrivate->pAppSettings,
-                                                                   APP_SP_EDIT_FONT));
+                                    pPrivate->pAppSettings->GetString(APP_SP_EDIT_FONT).c_str());
 
   dasher_editor_external_create_buffer(pSelf);
   // TODO: is this still needed?
@@ -497,7 +496,7 @@ dasher_editor_internal_generate_filename(DasherEditor *pSelf) {
 
   gchar *szNewFilename = NULL;
 
-  if( dasher_app_settings_get_bool(pPrivate->pAppSettings,  APP_BP_TIME_STAMP )) {
+  if( pPrivate->pAppSettings->GetBool(APP_BP_TIME_STAMP )) {
     // Build a filename based on the current time and date
     tm *t_struct;
     time_t ctime;
@@ -1279,7 +1278,7 @@ dasher_editor_handle_parameter_change(DasherEditor *pSelf, gint iParameter) {
   switch(iParameter) {
   case APP_SP_EDIT_FONT:
     dasher_editor_internal_handle_font(pSelf,
-                                      dasher_app_settings_get_string(pPrivate->pAppSettings, 
APP_SP_EDIT_FONT));
+                                      pPrivate->pAppSettings->GetString(APP_SP_EDIT_FONT).c_str());
     break;
   }
 }
diff --git a/Src/Gtk2/dasher_editor.h b/Src/Gtk2/dasher_editor.h
index a9768b9..827ccc4 100644
--- a/Src/Gtk2/dasher_editor.h
+++ b/Src/Gtk2/dasher_editor.h
@@ -10,8 +10,7 @@
 G_BEGIN_DECLS
 
 /* Forward declaration */
-typedef struct _DasherAppSettings DasherAppSettings;
-struct _DasherAppSettings;
+class DasherAppSettings;
 typedef struct _GtkDasherControl GtkDasherControl;
 struct _GtkDasherControl;
 
diff --git a/Src/Gtk2/dasher_editor_private.h b/Src/Gtk2/dasher_editor_private.h
index 9125940..47339e1 100644
--- a/Src/Gtk2/dasher_editor_private.h
+++ b/Src/Gtk2/dasher_editor_private.h
@@ -4,8 +4,7 @@
 #include <gtk/gtk.h>
 
 // Forward declarations
-typedef struct _DasherAppSettings DasherAppSettings;
-struct _DasherAppSettings;
+class DasherAppSettings;
 typedef struct _GtkDasherControl GtkDasherControl;
 struct _GtkDasherControl;
 typedef struct _DasherEditorExternalPrivate DasherEditorExternalPrivate;
diff --git a/Src/Gtk2/dasher_main.cpp b/Src/Gtk2/dasher_main.cpp
index e48a97e..20882ee 100644
--- a/Src/Gtk2/dasher_main.cpp
+++ b/Src/Gtk2/dasher_main.cpp
@@ -3,7 +3,9 @@
 #endif
 
 #include <cstring>
+#include <functional>
 #include <utility>
+
 #include <gdk/gdk.h>
 #include <gdk/gdkx.h>
 #include <glib/gi18n.h>
@@ -24,6 +26,8 @@
 #include "math.h"
 
 #include "dasher_main_private.h"
+#include "GnomeSettingsStore.h"
+#include "XmlSettingsStore.h"
 
 enum {
   REALIZED,
@@ -138,7 +142,7 @@ dasher_main_finalize(GObject *pObject) {
   DasherMain *pDasherMain = DASHER_MAIN(pObject);
   DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pDasherMain);
 
-  dasher_main_save_state(pDasherMain);
+  pPrivate->pAppSettings->UnregisterParameterChangeCallback(pPrivate->parameter_callback_id_);
 
   /* TODO: Does unref really do the right thing - check the whole ref counting situation */
   //  if(pPrivate->pEditor)
@@ -155,28 +159,51 @@ dasher_main_finalize(GObject *pObject) {
   /* TODO: Do we need to take down anything else? */
 }
 
+class XmlErrorDisplay : public CMessageDisplay {
+public:
+    void Message(const std::string &strText, bool bInterrupt) override {
+      // TODO: decide if a pop-up dialog should be shown instead.
+      fputs(strText.c_str(), stderr);
+      fputs("\n", stderr);
+    }
+};
+
 /* Public methods */
 DasherMain *
 dasher_main_new(int *argc, char ***argv, SCommandLine *pCommandLine) {
     DasherMain *pDasherMain = (DasherMain *)(g_object_new(dasher_main_get_type(), NULL));
     DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pDasherMain);
 
-    /* Create the app settings object */
-    pPrivate->pAppSettings = dasher_app_settings_new(pDasherMain, *argc, *argv);
+  static XmlErrorDisplay display;
+  Dasher::CSettingsStore* settings;
+  if (pCommandLine->szConfigFile == nullptr) {
+    settings = new CGnomeSettingsStore();
+  } else {
+    auto xml_settings = new Dasher::XmlSettingsStore(pCommandLine->szConfigFile, &display);
+    xml_settings->Load();
+    // Save the defaults if needed.
+    xml_settings->Save();
+    settings = xml_settings;
+  }
+  DasherAppSettings::Create(settings);
+  pPrivate->pAppSettings = DasherAppSettings::Get();
+  pPrivate->parameter_callback_id_ =
+    pPrivate->pAppSettings->RegisterParameterChangeCallback(
+      std::bind(dasher_main_handle_parameter_change, pDasherMain, std::placeholders::_1));
     
     /* Load the user interface from the GUI file */
     if(pCommandLine && pCommandLine->szAppStyle) {
       if(!strcmp(pCommandLine->szAppStyle, "traditional")) {
-        dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, APP_STYLE_TRAD);
+        pPrivate->pAppSettings->SetLong(APP_LP_STYLE, APP_STYLE_TRAD);
       }
       else if(!strcmp(pCommandLine->szAppStyle, "compose")) {
-        dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, APP_STYLE_COMPOSE);
+        pPrivate->pAppSettings->SetLong(APP_LP_STYLE, APP_STYLE_COMPOSE);
       }
       else if(!strcmp(pCommandLine->szAppStyle, "direct")) {
-        dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, APP_STYLE_DIRECT);
+        pPrivate->pAppSettings->SetLong(APP_LP_STYLE, APP_STYLE_DIRECT);
       }
       else if(!strcmp(pCommandLine->szAppStyle, "fullscreen")) {
-        dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, APP_STYLE_FULLSCREEN);
+        pPrivate->pAppSettings->SetLong(APP_LP_STYLE, APP_STYLE_FULLSCREEN);
       }
       else {
         g_critical("Application style %s is not supported", pCommandLine->szAppStyle);
@@ -185,12 +212,12 @@ dasher_main_new(int *argc, char ***argv, SCommandLine *pCommandLine) {
     }
     else { 
       // By default use traditional mode
-      dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, APP_STYLE_TRAD);
+      pPrivate->pAppSettings->SetLong(APP_LP_STYLE, APP_STYLE_TRAD);
     }
 
     dasher_main_load_interface(pDasherMain);
 
-    dasher_app_settings_set_widget(pPrivate->pAppSettings, GTK_DASHER_CONTROL(pPrivate->pDasherWidget));
+    pPrivate->pAppSettings->SetWidget(GTK_DASHER_CONTROL(pPrivate->pDasherWidget));
 
 
     /* TODO: This parsing code should really be tidied up */
@@ -212,7 +239,7 @@ dasher_main_new(int *argc, char ***argv, SCommandLine *pCommandLine) {
           memcpy(szKey, *pszCurrent, iLength);
           szKey[iLength] = '\0';
           
-          errorMessage = dasher_app_settings_cl_set(pPrivate->pAppSettings, szKey, szJoin + 1);
+          errorMessage = pPrivate->pAppSettings->ClSet(szKey, szJoin + 1);
           
           g_free(szKey);
         }
@@ -485,7 +512,7 @@ dasher_main_load_interface(DasherMain *pSelf) {
 #endif
   
   // Hide any widgets which aren't appropriate for this mode
-  if(dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_STYLE) == APP_STYLE_DIRECT) {
+  if(pPrivate->pAppSettings->GetLong(APP_LP_STYLE) == APP_STYLE_DIRECT) {
     gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pPrivate->pXML, "DasherEditor")));
   }
     
@@ -531,9 +558,7 @@ void show_game_file_dialog(GtkWidget *pButton, GtkWidget *pWidget, gpointer pDat
        
                char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(pFileDialog));
 
-               dasher_app_settings_set_string(pPrivate->pAppSettings,
-                                                       SP_GAME_TEXT_FILE,
-                                                       filename);
+               pPrivate->pAppSettings->SetString(SP_GAME_TEXT_FILE, filename);
                gtk_dasher_control_set_game_mode(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), true);
        }
        gtk_widget_destroy(GTK_WIDGET(objRefs->first));
@@ -544,13 +569,13 @@ void dasher_main_command_toggle_direct_mode(DasherMain *pSelf) {
 
        // Question of style: we could hide/show in
        // dasher_main_handle_parameter_change()
-       if (dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_STYLE) == APP_STYLE_DIRECT) {
+       if (pPrivate->pAppSettings->GetLong(APP_LP_STYLE) == APP_STYLE_DIRECT) {
                // Opposite of direct mode
                gtk_widget_show(GTK_WIDGET(gtk_builder_get_object(pPrivate->pXML, "DasherEditor")));
                gtk_window_set_keep_above(GTK_WINDOW(pPrivate->pMainWindow), false);
                gtk_window_set_accept_focus(GTK_WINDOW(pPrivate->pMainWindow), true);
                gtk_window_unstick(GTK_WINDOW(pPrivate->pMainWindow));
-               dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, APP_STYLE_TRAD);
+               pPrivate->pAppSettings->SetLong(APP_LP_STYLE, APP_STYLE_TRAD);
        } else {
                // Hide text window
                gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(pPrivate->pXML, "DasherEditor")));
@@ -560,7 +585,7 @@ void dasher_main_command_toggle_direct_mode(DasherMain *pSelf) {
                gtk_window_set_accept_focus(GTK_WINDOW(pPrivate->pMainWindow), false);
                // Stick on all desktops
                gtk_window_stick(GTK_WINDOW(pPrivate->pMainWindow));
-               dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_STYLE, APP_STYLE_DIRECT);
+               pPrivate->pAppSettings->SetLong(APP_LP_STYLE, APP_STYLE_DIRECT);
        }
 
        dasher_editor_toggle_direct_mode(pPrivate->pEditor);
@@ -628,20 +653,20 @@ dasher_main_handle_parameter_change(DasherMain *pSelf, int iParameter) {
 
   switch( iParameter ) {
   case APP_BP_SHOW_TOOLBAR:
-    if( dasher_app_settings_get_bool(pPrivate->pAppSettings, APP_BP_SHOW_TOOLBAR))
+    if( pPrivate->pAppSettings->GetBool(APP_BP_SHOW_TOOLBAR))
       gtk_widget_show(pPrivate->pToolbar);
     else
       gtk_widget_hide(pPrivate->pToolbar);
     break;
   case APP_BP_SHOW_STATUSBAR:
-    if (dasher_app_settings_get_bool(pPrivate->pAppSettings, APP_BP_SHOW_STATUSBAR))
+    if (pPrivate->pAppSettings->GetBool(APP_BP_SHOW_STATUSBAR))
       gtk_widget_show(pPrivate->pStatusControl);
     else
       gtk_widget_hide(pPrivate->pStatusControl);
     break;
 #ifndef WITH_MAEMO
   case LP_MAX_BITRATE:
-    gtk_spin_button_set_value(pPrivate->pSpeedBox, dasher_app_settings_get_long(pPrivate->pAppSettings, 
LP_MAX_BITRATE) / 100.0);
+    gtk_spin_button_set_value(pPrivate->pSpeedBox, pPrivate->pAppSettings->GetLong(LP_MAX_BITRATE) / 100.0);
     break;
 #endif
   case SP_ALPHABET_ID:
@@ -656,7 +681,7 @@ dasher_main_handle_parameter_change(DasherMain *pSelf, int iParameter) {
 
     bool bVisible = GTK_WIDGET_VISIBLE(pPrivate->pMainWindow);
     gtk_widget_hide(pPrivate->pMainWindow);
-    if(dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_MAEMO_SIZE) == 0) {
+    if(pPrivate->pAppSettings->GetLong(APP_LP_MAEMO_SIZE) == 0) {
       int iWidth;
       gtk_window_get_size(GTK_WINDOW(pPrivate->pMainWindow), &iWidth, NULL);
       gtk_widget_set_size_request(pPrivate->pMainWindow, -1, 150);
@@ -692,15 +717,15 @@ dasher_main_load_state(DasherMain *pSelf) {
   int iWindowHeight;
   int iEditHeight;
   
-  if(dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_STYLE) != APP_STYLE_COMPOSE) {
-    iEditHeight = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_EDIT_HEIGHT);
-    iWindowWidth = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_SCREEN_WIDTH);
-    iWindowHeight = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_SCREEN_HEIGHT);
+  if(pPrivate->pAppSettings->GetLong(APP_LP_STYLE) != APP_STYLE_COMPOSE) {
+    iEditHeight = pPrivate->pAppSettings->GetLong(APP_LP_EDIT_HEIGHT);
+    iWindowWidth = pPrivate->pAppSettings->GetLong(APP_LP_SCREEN_WIDTH);
+    iWindowHeight = pPrivate->pAppSettings->GetLong(APP_LP_SCREEN_HEIGHT);
   }
   else {
-    iEditHeight = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_EDIT_WIDTH);
-    iWindowWidth = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_SCREEN_WIDTH_H);
-    iWindowHeight = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_SCREEN_HEIGHT_H);
+    iEditHeight = pPrivate->pAppSettings->GetLong(APP_LP_EDIT_WIDTH);
+    iWindowWidth = pPrivate->pAppSettings->GetLong(APP_LP_SCREEN_WIDTH_H);
+    iWindowHeight = pPrivate->pAppSettings->GetLong(APP_LP_SCREEN_HEIGHT_H);
   }
 
 #ifndef WITH_MAEMO
@@ -716,8 +741,8 @@ dasher_main_load_state(DasherMain *pSelf) {
   int iWindowX;
   int iWindowY;
  
-  iWindowX = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_X);
-  iWindowY = dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_Y);
+  iWindowX = pPrivate->pAppSettings->GetLong(APP_LP_X);
+  iWindowY = pPrivate->pAppSettings->GetLong(APP_LP_Y);
 
   gtk_window_move(GTK_WINDOW(pPrivate->pMainWindow), iWindowX, iWindowY);
 }
@@ -736,25 +761,25 @@ dasher_main_save_state(DasherMain *pSelf) {
    gtk_window_get_size(GTK_WINDOW(pPrivate->pMainWindow), &iWindowWidth, &iWindowHeight);
    iEditHeight = gtk_paned_get_position(pPrivate->pDivider);
 
-   if(dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_STYLE) != APP_STYLE_COMPOSE) {
+   if(pPrivate->pAppSettings->GetLong(APP_LP_STYLE) != APP_STYLE_COMPOSE) {
      // APP_STYLE_DIRECT doesn't have an edit window.
-     if (dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_STYLE) != APP_STYLE_DIRECT)
-       dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_EDIT_HEIGHT, iEditHeight);
-     dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_SCREEN_WIDTH, iWindowWidth);
-     dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_SCREEN_HEIGHT, iWindowHeight);
+     if (pPrivate->pAppSettings->GetLong(APP_LP_STYLE) != APP_STYLE_DIRECT)
+       pPrivate->pAppSettings->SetLong(APP_LP_EDIT_HEIGHT, iEditHeight);
+     pPrivate->pAppSettings->SetLong(APP_LP_SCREEN_WIDTH, iWindowWidth);
+     pPrivate->pAppSettings->SetLong(APP_LP_SCREEN_HEIGHT, iWindowHeight);
    }
    else {
-     dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_EDIT_WIDTH, iEditHeight);
-     dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_SCREEN_WIDTH_H, iWindowWidth);
-     dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_SCREEN_HEIGHT_H, iWindowHeight);
+     pPrivate->pAppSettings->SetLong(APP_LP_EDIT_WIDTH, iEditHeight);
+     pPrivate->pAppSettings->SetLong(APP_LP_SCREEN_WIDTH_H, iWindowWidth);
+     pPrivate->pAppSettings->SetLong(APP_LP_SCREEN_HEIGHT_H, iWindowHeight);
    } 
 
    int iWindowX;
    int iWindowY;
    gtk_window_get_position(GTK_WINDOW(pPrivate->pMainWindow), &iWindowX, &iWindowY);
 
-   dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_X, iWindowX);
-   dasher_app_settings_set_long(pPrivate->pAppSettings, APP_LP_Y, iWindowY);
+   pPrivate->pAppSettings->SetLong(APP_LP_X, iWindowX);
+   pPrivate->pAppSettings->SetLong(APP_LP_Y, iWindowY);
 }
 
 void 
@@ -786,7 +811,7 @@ dasher_main_populate_controls(DasherMain *pSelf) {
   
   // Set the value of the speed spinner
   gtk_spin_button_set_value(pPrivate->pSpeedBox, 
-                            dasher_app_settings_get_long(pPrivate->pAppSettings, LP_MAX_BITRATE) / 100.0);
+                            pPrivate->pAppSettings->GetLong(LP_MAX_BITRATE) / 100.0);
 }
 
 /* Private methods */
@@ -805,7 +830,7 @@ static void
 dasher_main_setup_window_style(DasherMain *pSelf) {
   DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
 
-  switch(dasher_app_settings_get_long(pPrivate->pAppSettings, APP_LP_STYLE)) {
+  switch(pPrivate->pAppSettings->GetLong(APP_LP_STYLE)) {
   case APP_STYLE_TRAD:
     // Nothing to do
     break;
@@ -837,14 +862,14 @@ dasher_main_setup_internal_layout(DasherMain *pSelf) {
   DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
  
   if(pPrivate->pToolbar) {
-    if( dasher_app_settings_get_bool(pPrivate->pAppSettings, APP_BP_SHOW_TOOLBAR))
+    if(pPrivate->pAppSettings->GetBool(APP_BP_SHOW_TOOLBAR))
       gtk_widget_show(pPrivate->pToolbar);
     else
       gtk_widget_hide(pPrivate->pToolbar);
   }    
 
   if(pPrivate->pStatusControl) {
-    if (dasher_app_settings_get_bool(pPrivate->pAppSettings, APP_BP_SHOW_STATUSBAR))
+    if (pPrivate->pAppSettings->GetBool(APP_BP_SHOW_STATUSBAR))
       gtk_widget_show(pPrivate->pStatusControl);
     else
       gtk_widget_hide(pPrivate->pStatusControl);
@@ -906,7 +931,7 @@ static void dasher_main_command_quit(DasherMain *pSelf) {
   DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
 
   GtkWidget *pDialogue = NULL;
-
+  dasher_main_save_state(pSelf);
   if(dasher_editor_file_changed(pPrivate->pEditor)) {
 // XXX PRLW: Just open the save dialogue box.
 #if 0
@@ -1061,8 +1086,8 @@ dasher_main_speed_changed(DasherMain *pSelf) {
   
   int iNewValue( static_cast<int>(round(gtk_spin_button_get_value(pPrivate->pSpeedBox) * 100)));
   
-  if(dasher_app_settings_get_long(pPrivate->pAppSettings, LP_MAX_BITRATE) != iNewValue)
-    dasher_app_settings_set_long(pPrivate->pAppSettings, LP_MAX_BITRATE, iNewValue);
+  if(pPrivate->pAppSettings->GetLong(LP_MAX_BITRATE) != iNewValue)
+    pPrivate->pAppSettings->SetLong(LP_MAX_BITRATE, iNewValue);
 
   return true;
 }
@@ -1083,7 +1108,7 @@ dasher_main_alphabet_combo_changed(DasherMain *pSelf) {
       dasher_main_command_preferences_alphabet(pSelf);
     }
     else 
-      dasher_app_settings_set_string(pPrivate->pAppSettings, SP_ALPHABET_ID, szSelected);
+      pPrivate->pAppSettings->SetString(SP_ALPHABET_ID, szSelected);
 
     g_free(szSelected);
   }
@@ -1105,7 +1130,7 @@ dasher_main_populate_alphabet_combo(DasherMain *pSelf) {
   GtkTreeIter sIter;
   const char *szValue;
   
-  szValue = dasher_app_settings_get_string(pPrivate->pAppSettings, SP_ALPHABET_ID);
+  szValue = pPrivate->pAppSettings->GetString(SP_ALPHABET_ID).c_str();
 
   if(strlen(szValue) > 0) {
     gtk_list_store_append(pPrivate->pAlphabetList, &sIter);
@@ -1113,25 +1138,25 @@ dasher_main_populate_alphabet_combo(DasherMain *pSelf) {
     gtk_combo_box_set_active_iter(GTK_COMBO_BOX(pPrivate->pAlphabetCombo), &sIter);
   }
   
-  szValue = dasher_app_settings_get_string(pPrivate->pAppSettings, SP_ALPHABET_1);
+  szValue = pPrivate->pAppSettings->GetString(SP_ALPHABET_1).c_str();
   if(strlen(szValue) > 0) {
     gtk_list_store_append(pPrivate->pAlphabetList, &sIter);
     gtk_list_store_set(pPrivate->pAlphabetList, &sIter, 0, szValue, -1);
   }
   
-  szValue = dasher_app_settings_get_string(pPrivate->pAppSettings, SP_ALPHABET_2);
+  szValue = pPrivate->pAppSettings->GetString(SP_ALPHABET_2).c_str();
   if(strlen(szValue) > 0) {
     gtk_list_store_append(pPrivate->pAlphabetList, &sIter);
     gtk_list_store_set(pPrivate->pAlphabetList, &sIter, 0, szValue, -1);
   }
   
-  szValue = dasher_app_settings_get_string(pPrivate->pAppSettings, SP_ALPHABET_3);
+  szValue = pPrivate->pAppSettings->GetString(SP_ALPHABET_3).c_str();
   if(strlen(szValue) > 0) {
     gtk_list_store_append(pPrivate->pAlphabetList, &sIter);
     gtk_list_store_set(pPrivate->pAlphabetList, &sIter, 0, szValue, -1);
   }
   
-  szValue = dasher_app_settings_get_string(pPrivate->pAppSettings, SP_ALPHABET_4);
+  szValue = pPrivate->pAppSettings->GetString(SP_ALPHABET_4).c_str();
   if(strlen(szValue) > 0) {
     gtk_list_store_append(pPrivate->pAlphabetList, &sIter);
     gtk_list_store_set(pPrivate->pAlphabetList, &sIter, 0, szValue, -1);
diff --git a/Src/Gtk2/dasher_main.h b/Src/Gtk2/dasher_main.h
index 46099ef..6de7fae 100644
--- a/Src/Gtk2/dasher_main.h
+++ b/Src/Gtk2/dasher_main.h
@@ -34,6 +34,7 @@ struct SCommandLine {
   gchar *szFilename = nullptr;
   gchar *szAppStyle = nullptr;
   gchar *szOptions = nullptr;
+  gchar *szConfigFile = nullptr;
 };
 
 DasherMain *dasher_main_new(int *argc, char ***argv, SCommandLine *pCommandLine);
diff --git a/Src/Gtk2/dasher_main_private.h b/Src/Gtk2/dasher_main_private.h
index aca4fa5..1190ade 100644
--- a/Src/Gtk2/dasher_main_private.h
+++ b/Src/Gtk2/dasher_main_private.h
@@ -40,6 +40,7 @@ struct _DasherMainPrivate {
   int iWidth;
   int iHeight;
   bool bWidgetsInitialised;
+  int parameter_callback_id_ = 0;
 };
 
 typedef struct _DasherMainPrivate DasherMainPrivate;
diff --git a/Src/Gtk2/module_settings_window.cpp b/Src/Gtk2/module_settings_window.cpp
index e20e3d2..48abfe2 100644
--- a/Src/Gtk2/module_settings_window.cpp
+++ b/Src/Gtk2/module_settings_window.cpp
@@ -112,7 +112,7 @@ module_settings_window_new(DasherAppSettings *pAppSettings, const gchar *szName,
       pControl = gtk_check_button_new_with_label(_(pSettings[i].szDescription)); 
       
       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pControl), 
-                                  dasher_app_settings_get_bool(pPrivate->pAppSettings, 
pSettings[i].iParameter)); 
+                                  pPrivate->pAppSettings->GetBool(pSettings[i].iParameter));
       
       gtk_table_attach_defaults(GTK_TABLE(pTable), pControl, 0, 2, i, i+1);
       g_signal_connect(G_OBJECT(pControl), "toggled", G_CALLBACK(handle_bool_changed), pDasherControl);
@@ -133,7 +133,7 @@ module_settings_window_new(DasherAppSettings *pAppSettings, const gchar *szName,
                                 pSettings[i].iStep / static_cast<double>(pSettings[i].iDivisor));
 
        gtk_range_set_value(GTK_RANGE(pControl), 
-                           dasher_app_settings_get_long(pPrivate->pAppSettings, pSettings[i].iParameter) 
+                           pPrivate->pAppSettings->GetLong(pSettings[i].iParameter)
                            / static_cast<double>(pSettings[i].iDivisor));
        
        gtk_widget_set_size_request(pControl, 256, -1);
@@ -145,7 +145,7 @@ module_settings_window_new(DasherAppSettings *pAppSettings, const gchar *szName,
                                                  pSettings[i].iMax / 
static_cast<double>(pSettings[i].iDivisor), 
                                                  pSettings[i].iStep / 
static_cast<double>(pSettings[i].iDivisor));
        gtk_spin_button_set_value(GTK_SPIN_BUTTON(pControl), 
-                                 dasher_app_settings_get_long(pPrivate->pAppSettings, 
pSettings[i].iParameter) 
+                                 pPrivate->pAppSettings->GetLong(pSettings[i].iParameter)
                                  / static_cast<double>(pSettings[i].iDivisor));
 
        gtk_widget_set_size_request(pControl, 256, -1); 
@@ -155,7 +155,7 @@ module_settings_window_new(DasherAppSettings *pAppSettings, const gchar *szName,
       case T_STRING:
        pControl = gtk_entry_new();
        gtk_entry_set_text(GTK_ENTRY(pControl),
-                          dasher_app_settings_get_string(pPrivate->pAppSettings, pSettings[i].iParameter));
+                          pPrivate->pAppSettings->GetString(pSettings[i].iParameter).c_str());
        gtk_widget_set_size_request(pControl, 256, -1);
 
        g_signal_connect(G_OBJECT(pControl), "changed", G_CALLBACK(handle_string_changed), pDasherControl);
@@ -215,7 +215,7 @@ module_settings_window_handle_bool_changed(ModuleSettingsWindow *pSelf, GtkToggl
   ModuleSettingsWindowPrivate *pPrivate = MODULE_SETTINGS_WINDOW_GET_PRIVATE(pSelf);
   
   gboolean bNewValue = gtk_toggle_button_get_active(pToggleButton);
-  dasher_app_settings_set_bool(pPrivate->pAppSettings, pData->iParameter, bNewValue);
+  pPrivate->pAppSettings->SetBool(pData->iParameter, bNewValue);
 }
 
 static void 
@@ -228,7 +228,7 @@ module_settings_window_handle_long_changed(ModuleSettingsWindow *pSelf, GtkRange
   ModuleSettingsWindowPrivate *pPrivate = MODULE_SETTINGS_WINDOW_GET_PRIVATE(pSelf);
 
   gint iNewValue = (gint)(gtk_range_get_value(pRange) * pData->iDivisor);
-  dasher_app_settings_set_long(pPrivate->pAppSettings, pData->iParameter, iNewValue);
+  pPrivate->pAppSettings->SetLong(pData->iParameter, iNewValue);
 }
 
 static void 
@@ -241,7 +241,7 @@ module_settings_window_handle_longspin_changed(ModuleSettingsWindow *pSelf, GtkS
   ModuleSettingsWindowPrivate *pPrivate = MODULE_SETTINGS_WINDOW_GET_PRIVATE(pSelf);
 
   gint iNewValue = (gint)(gtk_spin_button_get_value(pSpinButton) * pData->iDivisor);
-  dasher_app_settings_set_long(pPrivate->pAppSettings, pData->iParameter, iNewValue);
+  pPrivate->pAppSettings->SetLong(pData->iParameter, iNewValue);
 }
 
 static void 
@@ -254,7 +254,7 @@ module_settings_window_handle_string_changed(ModuleSettingsWindow *pSelf, GtkEdi
   ModuleSettingsWindowPrivate *pPrivate = MODULE_SETTINGS_WINDOW_GET_PRIVATE(pSelf);
 
   const gchar *szNewValue = gtk_editable_get_chars(pEditable, 0, -1);
-  dasher_app_settings_set_string(pPrivate->pAppSettings, pData->iParameter, szNewValue);
+  pPrivate->pAppSettings->SetString(pData->iParameter, szNewValue);
 }
 
 static gboolean 
diff --git a/Src/Win32/AppSettings.cpp b/Src/Win32/AppSettings.cpp
index 40d88fc..420ae24 100644
--- a/Src/Win32/AppSettings.cpp
+++ b/Src/Win32/AppSettings.cpp
@@ -51,30 +51,30 @@ CAppSettings::CAppSettings(Dasher::CDasher *pDasher, HWND hWnd)
   for(int ii = 0; ii < NUM_OF_APP_BPS; ii++) {
     m_pBoolTable[ii].key = app_boolparamtable[ii].key;
     if(!LoadSetting(app_boolparamtable[ii].regName, &m_pBoolTable[ii].value))
-      m_pBoolTable[ii].value = app_boolparamtable[ii].bDefaultValue;
-    m_pBoolTable[ii].defaultVal = app_boolparamtable[ii].bDefaultValue;
+      m_pBoolTable[ii].value = app_boolparamtable[ii].defaultValue;
+    m_pBoolTable[ii].defaultVal = app_boolparamtable[ii].defaultValue;
     m_pBoolTable[ii].humanReadable = app_boolparamtable[ii].humanReadable;
-    m_pBoolTable[ii].persistent = app_boolparamtable[ii].persistent;
+    m_pBoolTable[ii].persistent = app_boolparamtable[ii].persistent == Persistence::PERSISTENT;
     m_pBoolTable[ii].regName = app_boolparamtable[ii].regName;
   } 
     
   for(int ii = 0; ii < NUM_OF_APP_LPS; ii++) {
     m_pLongTable[ii].key = app_longparamtable[ii].key;
     if(!LoadSetting(app_longparamtable[ii].regName, &m_pLongTable[ii].value))
-      m_pLongTable[ii].value = app_longparamtable[ii].iDefaultValue;
-    m_pLongTable[ii].defaultVal = app_longparamtable[ii].iDefaultValue;
+      m_pLongTable[ii].value = app_longparamtable[ii].defaultValue;
+    m_pLongTable[ii].defaultVal = app_longparamtable[ii].defaultValue;
     m_pLongTable[ii].humanReadable = app_longparamtable[ii].humanReadable;
-    m_pLongTable[ii].persistent = app_longparamtable[ii].persistent;
+    m_pLongTable[ii].persistent = app_longparamtable[ii].persistent == Persistence::PERSISTENT;
     m_pLongTable[ii].regName = app_longparamtable[ii].regName;
   }
 
   for(int ii = 0; ii < NUM_OF_APP_SPS; ii++) {
     m_pStringTable[ii].key = app_stringparamtable[ii].key;
-    if(!LoadSetting(app_stringparamtable[ii].regName, &m_pStringTable[ii].value)) 
-      m_pStringTable[ii].value = app_stringparamtable[ii].szDefaultValue; 
-    m_pStringTable[ii].defaultVal = app_stringparamtable[ii].szDefaultValue;
+    if(!LoadSetting(app_stringparamtable[ii].regName, &m_pStringTable[ii].value))
+      m_pStringTable[ii].value = app_stringparamtable[ii].defaultValue;
+    m_pStringTable[ii].defaultVal = app_stringparamtable[ii].defaultValue;
     m_pStringTable[ii].humanReadable = app_stringparamtable[ii].humanReadable;
-    m_pStringTable[ii].persistent = app_stringparamtable[ii].persistent;
+    m_pStringTable[ii].persistent = app_stringparamtable[ii].persistent == Persistence::PERSISTENT;
     m_pStringTable[ii].regName = app_stringparamtable[ii].regName;
   }
 }
@@ -144,11 +144,11 @@ void CAppSettings::ResetParamater(int iParameter) {
   if(iParameter < END_OF_SPS)
     m_pDasher->ResetParameter(iParameter);
   else if(iParameter < END_OF_APP_BPS)
-    SetBoolParameter(iParameter, app_boolparamtable[iParameter - FIRST_APP_BP].bDefaultValue);
+    SetBoolParameter(iParameter, app_boolparamtable[iParameter - FIRST_APP_BP].defaultValue);
   else if(iParameter < END_OF_APP_LPS)
-    SetLongParameter(iParameter, app_longparamtable[iParameter - FIRST_APP_LP].iDefaultValue);
+    SetLongParameter(iParameter, app_longparamtable[iParameter - FIRST_APP_LP].defaultValue);
   else
-    SetStringParameter(iParameter, app_stringparamtable[iParameter - FIRST_APP_SP].szDefaultValue);
+    SetStringParameter(iParameter, app_stringparamtable[iParameter - FIRST_APP_SP].defaultValue);
 }
 
 void CAppSettings::GetPermittedValues(int iParameter, vector<string> &vList) {
diff --git a/Src/main.cc b/Src/main.cc
index 4c0fbe2..8fed2bc 100644
--- a/Src/main.cc
+++ b/Src/main.cc
@@ -133,8 +133,6 @@ void clean_up();
 //   }
 // }
 
-gchar* g_xml_file_location = nullptr;
-
 extern "C" gint main_key_snooper(GtkWidget *pWidget, GdkEventKey *pEvent, gpointer pUserData);
 
 
@@ -163,7 +161,7 @@ int main(int argc, char *argv[]) {
     {"appstyle", 'a', 0, G_OPTION_ARG_STRING, &(sCommandLine.szAppStyle), N_("Application style 
(traditional, direct, compose or fullscreen)"), "traditional"},
     // Note to translators: This is the help string for "--options"
     {"options", 'o', 0, G_OPTION_ARG_STRING, &(sCommandLine.szOptions), N_("Override stored options"), NULL},
-    {"config", 'c', 0, G_OPTION_ARG_STRING, &g_xml_file_location, N_("XML configuration file name"), NULL},
+    {"config", 'c', 0, G_OPTION_ARG_STRING, &(sCommandLine.szConfigFile), N_("XML configuration file name"), 
NULL},
         // Note to translators: This is the help string for "--help-options"
     {"help-options", 0, 0, G_OPTION_ARG_NONE, &do_option_help, N_("Describe \"--options\"."), NULL},
     {NULL}
@@ -222,6 +220,7 @@ int main(int argc, char *argv[]) {
   g_free(sCommandLine.szFilename);
   g_free(sCommandLine.szAppStyle);
   g_free(sCommandLine.szOptions);
+  g_free(sCommandLine.szConfigFile);
 
   if (g_pDasherMain == 0)
     return 1;
@@ -237,9 +236,6 @@ int main(int argc, char *argv[]) {
   // 11.
   clean_up();
 
-  if (g_xml_file_location != nullptr)
-    g_free(g_xml_file_location);
-
   return 0;
 }
 


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