diff --git a/doc/gnurobots.texi b/doc/gnurobots.texi
index 745e9ef..d9591e2 100644
--- a/doc/gnurobots.texi
+++ b/doc/gnurobots.texi
@@ -25,6 +25,7 @@ own.
 * Robot Actions:: API Commands to Control the Robot.
 * Challenge Maps:: Maps to challenge your robot on.
 * Sample Robots:: Robots others have written for you to use as inspiration.
+* Editing Maps:: How to modify and create maps.
 * Function and Variable Indices:: Functions to control the Robot.
 * Concept Index:: Concept index.
 @end menu
@@ -146,6 +147,16 @@ Sets the robot's initial shields to the provided value @var{SHIELDS}.
 
 Sets the robot's initial energy to the provided value @var{ENERGY}.
 
+@item -m
+@item --map-edit
+@cindex -m option
+@cindex --map-edit option
+@cindex option, -m
+@cindex option, --map-edit
+
+Puts the program into map edit mode allowing GUI and Scheme editing of
+the map.
+
 @item -V
 @item --version
 @cindex -V option
@@ -203,7 +214,7 @@ you, there's nothing more you need to do.
 @cindex load map
 @cindex map, load
 
-You can load a new map using the menus (File/Open Map).
+You can load a new map using the menus (Open Map).
 
 @cindex sample maps
 @cindex map, samples
@@ -607,6 +618,92 @@ This robot turns in place and zaps whatever it finds.
 
 @end table
 
+@node Editing Maps
+@chapter Editing Maps
+@cindex editing maps
+@cindex maps, edit
+@cindex maps
+
+Maps can be edited in a text editor.  Each location type is
+represented by a character:
+
+@itemize @bullet
+@item
+@samp{ } for spaces
+@item
+@samp{#} for walls
+@item
+@samp{+} for food
+@item
+@samp{$} for prizes
+@item
+@samp{@@} for baddies
+@item
+@samp{R} for robot starting locations
+@end itemize
+
+An easy way to create a map is to take an existing map, save it under
+a different name using @samp{Save Map As} and edit it in a text editor.
+
+@section Map Editing Mode
+@cindex map editing mode
+
+GNU Robots comes with a command line option to enable map editing in
+the GUI and via Scheme functions.
+
+If gnurobots is initiated using the @option{--map-edit} option, it
+will add a toolbar to select location types and let the user use the
+mouse to edit the map.
+
+Once the map has been edited to your liking, you can save it using
+@samp{Save Map As} or @samp{Save Map} in the menu.
+
+Map editing mode also enables several scheme functions which can be
+used to modify the map programmatically.  @footnote{These functions
+are not normally available when not in map editing mode, though the
+user can enable them using @code{(use-modules (gnurobots map))}.}
+
+@deffn Function map-set-loc x y is-wall
+@var{x}, @var{y} are map coordinates (map origin is in the top left
+with positive numbers right and down from there).
+
+@var{is-wall} is @code{#t} for walls; @code{#f} otherwise.
+@end deffn
+
+@deffn Function map-get-loc x y
+@var{x}, @var{y} are map coordinates (map origin is in the top left
+with positive numbers right and down from there).
+
+Returns @code{#t} if the location is a wall; #f otherwise.
+@end deffn
+
+@deffn Function map-remove-thing x y
+@var{x}, @var{y} are map coordinates (map origin is in the top left
+with positive numbers right and down from there).
+
+Things are @samp{baddie}, @samp{robot}, @samp{prize}, @samp{food}.
+
+Returns @code{#t} if the thing in location @var{x}, @var{y} was removed.
+@end deffn
+
+@deffn Function map-place-thing x y TH
+
+@var{x}, @var{y} are map coordinates (map origin is in the top left
+with positive numbers right and down from there).
+
+@var{TH} is a string describing the locations @xref{Things in the Map}
+
+Returns @code{#t} if the thing in location @var{x}, @var{y} was removed.
+@end deffn
+
+@deffn Function map-get-loc-string x y
+
+@var{x}, @var{y} are map coordinates (map origin is in the top left
+with positive numbers right and down from there).
+
+Returns @var{TH}, a string describing the location @xref{Things in the Map}
+@end deffn
+
 @node Function and Variable Indices
 @unnumbered Function and Variable Indices
 
diff --git a/include/api.h b/include/api.h
index ae10e7d..e650eb6 100644
--- a/include/api.h
+++ b/include/api.h
@@ -25,7 +25,7 @@
  *
  * This is accomplished by generating the SIGUSR1 signal.
  */
-void            api_interrupt   (void);
+void            api_interrupt (void);
 
 /** Initialize the Guile environment in a newly created thread.
  *
@@ -41,6 +41,7 @@ void            api_interrupt   (void);
  *
  * \returns a pointer to the GThread created.
  */
-GThread*        api_init        (gint argc, gchar **argv, gpointer in_robot);
+GThread*        api_init (gint argc, gchar **argv, gpointer in_robot,
+			  gpointer in_map, gboolean map_edit);
 
 #endif /* _API_H */
diff --git a/include/configs.h b/include/configs.h
index b850700..1db107f 100644
--- a/include/configs.h
+++ b/include/configs.h
@@ -79,3 +79,9 @@
 #define COPYRIGHT "Copyright (C) 1998,1999,2000 Jim Hall <jhall@freedos.org>\nCopyright (C) 2008 Bradley Smith <brad@brad-smith.co.uk>"
 
 #endif /* CONFIGS_H */
+
+enum errors
+  {
+   ERROR_MAP_FILENAME_NULL,
+   ERROR_LAST
+  };
diff --git a/include/map.h b/include/map.h
index 8dc4bd9..0a7ea8f 100644
--- a/include/map.h
+++ b/include/map.h
@@ -130,7 +130,7 @@ gboolean map_init_map(Map *self);
  * This will emit a map-update signal.
  *
  * \param[in, out] self the map to update
- * \param[in] filename the path and name of the file to load.  It is
+ * \param[in] filename the path and name of the file to save to.  It is
  *            safe to free this after the function completes.
  * \param[out] error a GError object representing details about errors
  *             encountered. error is set to NULL if the function is
@@ -139,6 +139,39 @@ gboolean map_init_map(Map *self);
  * \returns TRUE if successful; FALSE otherwise.
  */
 gboolean map_load_filename(Map *self, const gchar *filename, GError **error);
+/** Saves the map to filename.
+ *
+ * Saves the map to the given filename.
+ *
+ * Initially all locations are set to be walls, so the load will add
+ * itself into a map the size of map_get_max_x and map_get_max_y.
+ *
+ * This will emit a map-update signal.
+ *
+ * \param[in, out] self the map to update
+ * \param[in] filename the path and name of the file to load.  It is
+ *            safe to free this after the function completes.
+ * \param[out] error a GError object representing details about errors
+ *             encountered. error is set to NULL if the function is
+ *             successful.
+ *
+ * \returns TRUE if successful; FALSE otherwise.
+ */
+gboolean map_save_filename(Map *self, const gchar *filename, GError **error);
+/** Saves the map.
+ *
+ * Saves the map to the previously set filename.
+ *
+ * This will emit a map-update signal.
+ *
+ * \param[in, out] self the map to update
+ * \param[out] error a GError object representing details about errors
+ *             encountered. error is set to NULL if the function is
+ *             successful.
+ *
+ * \returns TRUE if successful; FALSE otherwise.
+ */
+gboolean map_save(Map *self, GError **error);
 
 /** @} */
 
diff --git a/include/ui-arena.h b/include/ui-arena.h
index 25c9dd5..a9613ba 100644
--- a/include/ui-arena.h
+++ b/include/ui-arena.h
@@ -57,7 +57,7 @@ GType ui_arena_get_type(void) G_GNUC_CONST;
 
 /* Constructor */
 
-GtkWidget *ui_arena_new(Map *map);
+GtkWidget *ui_arena_new(Map *map, gboolean map_edit);
 
 /* Methods */
 
diff --git a/include/ui-window.h b/include/ui-window.h
index f2e32e1..35a2b4c 100644
--- a/include/ui-window.h
+++ b/include/ui-window.h
@@ -57,7 +57,8 @@ struct _UIWindowClass
  *
  * \returns the status from running the GtkApplication
  */
-gint          ui_window_main(Map *map, GRobot *robot, gint argc, gchar **argv);
+gint          ui_window_main(Map *map, GRobot *robot, gint argc, gchar **argv,
+			     gboolean map_edit);
 /** Returns the GOptionGroup to be used in commandline processing.
  *
  * The GOptionGroup is found by calling gtk_get_option_group.
diff --git a/src/api.c b/src/api.c
index 96efb9b..4c553ce 100644
--- a/src/api.c
+++ b/src/api.c
@@ -25,6 +25,7 @@
 #include "config.h"
 #include "configs.h"
 #include "grobot.h"
+#include "map.h"
 #include "api.h"                /* GNU Robots API */
 
 /** Robot object to be used in all the calls to the grobot.h
@@ -294,7 +295,7 @@ api_load_robot_program(const gchar *robot_program)
  * \param[in] robot_program a file name to load into Guile.
  */
 static void
-api_repl_init(const gchar *robot_program)
+api_repl_init(const gchar *robot_program, gboolean map_edit)
 {
   scm_internal_catch(SCM_BOOL_T,
 		     (scm_t_catch_body) scm_c_eval_string,
@@ -308,6 +309,11 @@ api_repl_init(const gchar *robot_program)
 		     (scm_t_catch_body) scm_c_use_module,
 		     "gnurobots robot",
 		     catch_handler, NULL);
+  if(map_edit)
+      scm_internal_catch(SCM_BOOL_T,
+		     (scm_t_catch_body) scm_c_use_module,
+		     "gnurobots map",
+		     catch_handler, NULL);
   scm_internal_catch(SCM_BOOL_T,
 		     (scm_t_catch_body) scm_c_eval_string,
 		     "(activate-readline)",
@@ -398,6 +404,11 @@ api_define_procedures (gpointer data)
   scm_c_export("quit");
 }
 
+static void api_define_map_procedures (gpointer data);
+/** Map object to be used in all the map calls.
+ */
+Map *map;
+
 /** The main program code that is executed after Guile starts up. 
  *
  * Pass the Scheme program as argv[1]. The program name is still
@@ -413,20 +424,23 @@ static void
 api_main_prog(void *closure, gint argc, gchar *argv[])
 {
   scm_c_define_module("gnurobots robot", api_define_procedures, NULL);
+  scm_c_define_module("gnurobots map", api_define_map_procedures, NULL);
 
   gchar *robot_program = NULL;
   if(argc > 1)
     robot_program = argv[1];
 
-  api_repl_init(robot_program);
+  gboolean map_edit = GPOINTER_TO_INT(closure);
+  api_repl_init(robot_program, map_edit);
 }
 
 /** Structure to hold argc and argv to be passed to api_callback_scm.
  */
 struct _ProgramArguments
 {
-  gint    argc; /*!< Number of arguments being passed in argv. */
-  gchar **argv; /*!< Arguments being passed as strings. */
+  gint     argc; /*!< Number of arguments being passed in argv. */
+  gchar  **argv; /*!< Arguments being passed as strings. */
+  gboolean map_edit; /*!< TRUE if the map edit module should be interned. */
 };
 
 /** Typedef to hold argc and argv to be passed to api_callback_scm.
@@ -444,7 +458,7 @@ typedef struct _ProgramArguments ProgramArguments;
 static gpointer
 api_callback_scm(ProgramArguments *args)
 {
-  scm_boot_guile(args->argc, args->argv, api_main_prog, NULL);
+  scm_boot_guile(args->argc, args->argv, api_main_prog, GINT_TO_POINTER(args->map_edit));
 
   return NULL; /* never gets here, but keeps compiler happy */
 }
@@ -456,17 +470,220 @@ api_interrupt(void)
 }
 
 GThread*
-api_init(gint argc, gchar **argv, gpointer in_robot)
+api_init(gint argc, gchar **argv, gpointer in_robot, gpointer in_map, gboolean map_edit)
 {
   g_return_val_if_fail(G_IS_ROBOT(in_robot), NULL);
 
   robot = g_object_ref(G_ROBOT(in_robot));
-
+  map = g_object_ref(MAP(in_map));
   ProgramArguments *args = g_malloc(sizeof(ProgramArguments));
   args->argc = argc;
   args->argv = argv;
+  args->map_edit = map_edit;
 
   GThread *guile_thread = g_thread_new("Guile Thread", (GThreadFunc) api_callback_scm, args);
 
   return guile_thread;
 }
+
+/***************** Map API *****************/
+
+/** Utility data for going from string to char for things.
+ */
+static gchar *things[] = {"space", "wall", "food", "prize", "baddie", "robot"};
+/** Utility data for going from string to char for things.
+ */
+static gint cthings[] = {SPACE, WALL, FOOD, PRIZE, BADDIE, ROBOT};
+
+/** Scans the list of possible things (strings) and returns a cthing
+ *   (location character).
+ *
+ * My idea here is that by return -1 on error, this won't match
+ * anything in the list of cthings.  That way, the function that uses
+ * what_thing to determine the cthing doesn't have to care if the call
+ * failed or not.
+ *
+ * \param[in] th string representing the location type.
+ * \sa what_cthing
+ *
+ * \returns -1 if not found in the list.
+ */
+static gint
+what_thing(const gchar *th)
+{
+  gint i;
+
+  for (i = 0; i < 6; i++)
+    {
+      if (strcmp(th, things[i]) == 0)
+	{
+	  return cthings[i];
+	}
+    } /* for */
+
+  /* not found */
+
+  return -1;
+}
+
+/** Scans the list of possible cthings (characters) and returns a thing
+ *   (string).
+ *
+ * My idea here is that by return NULL on error, this won't match
+ * anything in the list of things.  That way, the function that uses
+ * what_cthing to determine the cthing doesn't have to care if the call
+ * failed or not.
+ *
+ * \param[in] cth character representing the location type.
+ * \sa what_thing
+ *
+ * \returns -1 if not found in the list.
+ */
+static gchar*
+what_cthing(const gchar cth)
+{
+  gint i;
+
+  for (i = 0; i < 6; i++)
+    {
+      if (cthings[i] == cth)
+	{
+	  return things[i];
+	}
+    } /* for */
+
+  /* not found */
+
+  return NULL;
+}
+
+static gboolean
+map_coords_validate(SCM s_x, SCM s_y)
+{
+  gint x = scm_to_int(s_x);
+  gint y = scm_to_int(s_y);
+
+  gboolean retval = x >= 0 && y >= 0 &&
+    x < map_get_max_x(map) &&
+    y < map_get_max_y(map);
+
+  SCM b = scm_from_utf8_symbol("map-coords-out-of-range-exception");
+  
+  if(!retval)
+    scm_throw(b, scm_list_2(s_x, s_y));
+  
+  return retval;
+}
+
+static SCM
+api_map_set_loc(SCM s_x, SCM s_y, SCM s_b)
+{
+  gboolean retval = map_coords_validate(s_x, s_y);
+
+  if(retval)
+    retval = map_set_loc(map, scm_to_int(s_x), scm_to_int(s_y), scm_is_true(s_b));
+
+  return SCM_BOOL(retval);
+}
+
+static SCM
+api_map_get_loc(SCM s_x, SCM s_y)
+{
+  gboolean retval = map_coords_validate(s_x, s_y);
+
+  if(retval)
+    retval = map_get_loc(map, scm_to_int(s_x), scm_to_int(s_y));
+
+  return SCM_BOOL(retval);
+}
+
+static SCM
+api_map_remove_thing(SCM s_x, SCM s_y)
+{
+  gboolean retval = map_coords_validate(s_x, s_y);
+
+  if(retval)
+    retval = map_remove_thing(map, scm_to_int(s_x), scm_to_int(s_y));
+
+  return SCM_BOOL(retval);
+}
+
+static SCM
+api_map_place_thing(SCM s_x, SCM s_y, SCM s_th)
+{
+  gchar *str;
+
+  if (scm_symbol_p (s_th) == SCM_BOOL_T) {
+    s_th = scm_symbol_to_string (s_th);
+  }
+  str = scm_to_locale_string (s_th);
+
+  gboolean retval = map_coords_validate(s_x, s_y);
+
+  gint x = scm_to_int(s_x);
+  gint y = scm_to_int(s_y);
+  if(g_strcmp0(str, "wall") != 0 && map_get_loc(map, x, y))
+    map_set_loc(map, x, y, FALSE);
+  else if(g_strcmp0(str, "wall") == 0 && !map_get_loc(map, x, y))
+    map_set_loc(map, x, y, TRUE);
+
+  if(retval && g_strcmp0(str, "space") != 0 && g_strcmp0(str, "wall") != 0)
+    retval = map_place_thing(map, x, y, what_thing(str), EAST, NULL);
+  else if(g_strcmp0(str, "space") == 0 || g_strcmp0(str, "wall") == 0)
+    retval = map_remove_thing(map, x, y);
+
+  return SCM_BOOL(retval);
+}
+
+static SCM
+api_map_get_max_x()
+{
+  return scm_from_int(map_get_max_x(map));
+}
+
+static SCM
+api_map_get_max_y()
+{
+  return scm_from_int(map_get_max_y(map));
+}
+
+static SCM
+api_map_get_loc_thing_string(SCM s_x, SCM s_y)
+{
+  gboolean coords = map_coords_validate(s_x, s_y);
+
+  if(coords)
+    {
+      gchar cth = map_get_loc_thing_char(map, scm_to_int(s_x), scm_to_int(s_y));
+      return scm_from_utf8_string(what_cthing(cth));
+    }
+  else
+    return SCM_BOOL_F;
+}
+
+static void
+api_define_map_procedures (gpointer data)
+{
+  /* Guile has this function set to expect that function-pointers are
+     passed as (void *), which generates warnings because it's actually
+     illegal in C99 (supposedly because there are architectures where
+     `function pointers' and `object pointers' actually are incompatible);
+     So... jump through hoops to out-guile the system....
+  */
+  typedef SCM (*c99_fakeout_guile)(const char *, int, int, int, SCM(*)());
+  c99_fakeout_guile define_gsubr = (c99_fakeout_guile) scm_c_define_gsubr;
+  define_gsubr("map-set-loc", 3, 0, 0, api_map_set_loc);
+  scm_c_export("map-set-loc");
+  define_gsubr("map-get-loc", 2, 0, 0, api_map_get_loc);
+  scm_c_export("map-get-loc");
+  define_gsubr("map-remove-thing", 2, 0, 0, api_map_remove_thing);
+  scm_c_export("map-remove-thing");
+  define_gsubr("map-place-thing", 3, 0, 0, api_map_place_thing);
+  scm_c_export("map-place-thing");
+  define_gsubr("map-get-max-x", 0, 0, 0, api_map_get_max_x);
+  scm_c_export("map-get-max-x");
+  define_gsubr("map-get-max-y", 0, 0, 0, api_map_get_max_y);
+  scm_c_export("map-get-max-y");
+  define_gsubr("map-get-loc-string", 2, 0, 0, api_map_get_loc_thing_string);
+  scm_c_export("map-get-loc-string");
+}
diff --git a/src/main.c b/src/main.c
index bad4e0b..0a63bee 100644
--- a/src/main.c
+++ b/src/main.c
@@ -123,6 +123,9 @@ static gchar *map_filename = NULL;
 /** Flag determining whether the user is requesting version information.
  */
 static gboolean version = FALSE;
+/** Flag determining whether to enter map editing mode.
+ */
+static gboolean map_edit = FALSE;
 
 /** Program options.
  */
@@ -131,6 +134,7 @@ static GOptionEntry entries[] =
  { "energy", 'e', 0, G_OPTION_ARG_INT, &robot_energy, "Starting energy for the robot.", "N" },
  { "shields", 's', 0, G_OPTION_ARG_INT, &robot_shields, "Starting shields for the robot", "N" },
  { "map-file", 'f', 0, G_OPTION_ARG_FILENAME, &map_filename, "Map file to load on startup.", "M" },
+ { "map-edit", 'm', 0, G_OPTION_ARG_NONE, &map_edit, "Enable map editing mode.", NULL },
  { "version", 'V', 0, G_OPTION_ARG_NONE, &version, "Print version information and exit.", NULL },
  { NULL }
 };
@@ -296,11 +300,11 @@ main(int argc, char **argv)
 		   G_CALLBACK(print_robot_summary), NULL);
 
   /* Initialize Guile/Scheme */
-  GThread *guile_thread = api_init(argc, argv, robot);
+  GThread *guile_thread = api_init(argc, argv, robot, map, map_edit);
 
   /* Initialize the GUI */
   g_printf("Loading GTK Interface ... Please wait\n\n");
-  ui_window_main(map, robot, argc, argv);
+  ui_window_main(map, robot, argc, argv, map_edit);
 
   print_robot_summary(robot);
   g_thread_unref(guile_thread);
diff --git a/src/map.c b/src/map.c
index 6ddef8b..a455bf1 100644
--- a/src/map.c
+++ b/src/map.c
@@ -690,6 +690,111 @@ map_get_filename(Map *self)
   return(g_strdup(self->priv->map_filename));
 }
 
+static gboolean
+map_save_stream(Map *self, GFileOutputStream *stream, GError **error)
+{
+  g_return_val_if_fail(G_IS_MAP (self), FALSE);
+
+  GError *inner_error = NULL;
+
+  gchar buffer[1] = "\0";
+  for(gint y = 0; y < map_get_max_y(self); y++)
+    {
+      for(gint x = 0; x < map_get_max_x(self); x++)
+	{
+	  gchar loc_char = map_get_loc_thing_char(self, x, y);
+	  buffer[0] = loc_char;
+	  g_output_stream_write(G_OUTPUT_STREAM(stream), buffer, 1, NULL, &inner_error);
+	  if(NULL != inner_error)
+	    {
+	      g_propagate_error(error, inner_error);
+	      return FALSE;
+	    }
+	  buffer[0] = '\0';
+	}
+      buffer[0] = '\n';
+      g_output_stream_write(G_OUTPUT_STREAM(stream), buffer, 1, NULL, &inner_error);
+      buffer[0] = '\0';
+    }
+
+  return TRUE;
+}
+
+gboolean
+map_save_filename (Map *self, const gchar *filename, GError **error)
+{
+  g_return_val_if_fail(G_IS_MAP (self), FALSE);
+
+  if(map_get_max_x(self) == 0 || map_get_max_y(self) == 0) {
+    g_error("map_load_filename: attempt to save file before initializing max_x and max_y.");
+    return(FALSE);
+  }
+  if(NULL == filename)
+    {
+      g_set_error (error,
+                   0, // error domain
+                   ERROR_MAP_FILENAME_NULL, // error code
+                   "Filename not set (is NULL).");
+      return FALSE;
+    }
+
+  GFile *file = g_file_new_for_path(filename);
+
+  gboolean retval = FALSE;
+  GError *inner_error = NULL;
+  GFileOutputStream *stream =
+    g_file_replace(file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &inner_error);
+  if (NULL == inner_error)
+  {
+    map_save_stream(self, stream, &inner_error);
+    if(NULL == inner_error)
+      {
+	if(filename != self->priv->map_filename)
+	  self->priv->map_filename = g_strdup(filename);
+	retval = TRUE;
+      }
+    else
+      {
+	g_propagate_error(error, inner_error);
+	retval = FALSE;
+      }
+    g_output_stream_close (G_OUTPUT_STREAM(stream), NULL, NULL);
+    g_object_unref(stream);
+  }
+  else /* else, no file to open */
+  {
+    g_propagate_error(error, inner_error);
+    retval = FALSE;
+  }
+  g_object_unref(file);
+
+  g_signal_emit(self, map_signals[MAP_UPDATE], 0 /* details */);
+  return retval;
+}
+
+gboolean
+map_save (Map *self, GError **error)
+{
+  g_return_val_if_fail(G_IS_MAP (self), FALSE);
+
+  if(map_get_max_x(self) == 0 || map_get_max_y(self) == 0) {
+    g_error("map_load_filename: attempt to save file before initializing max_x and max_y.");
+    return FALSE;
+  }
+
+  GError *inner_error = NULL;
+  map_save_filename(self, self->priv->map_filename, &inner_error);
+  if (NULL != inner_error)
+    {
+      g_propagate_error(error, inner_error);
+      return FALSE;
+    }
+  else
+    {
+      return TRUE;
+    }
+}
+
 /* Sequence of positive coords closest to origin given. */
 static MapCoords*
 map_iterate_pyramid(Map *self, gint x, gint y, gint max_x, gint max_y, gchar on_loc_thing_char)
diff --git a/src/ui-arena.c b/src/ui-arena.c
index a6329b0..7344d27 100644
--- a/src/ui-arena.c
+++ b/src/ui-arena.c
@@ -39,9 +39,12 @@
 
 enum conn_signals
 {
-	MAP_UPDATE,
-	MAP_MOVE,
-	LAST_CONN_SIGNAL
+ MAP_UPDATE,
+ MAP_MOVE,
+ DRAW,
+ BUTTON_PRESSED,
+ MOTION_NOTIFY,
+ LAST_CONN_SIGNAL
 };
 
 enum tile_index
@@ -88,8 +91,10 @@ typedef struct _UIArenaAnimate UIArenaAnimate;
 struct _UIArenaPrivate
 {
   cairo_surface_t *surface;
-  GtkDrawingArea *arena;
-  GtkLabel *filelabel;
+  GtkDrawingArea  *arena;
+  GtkLabel        *filelabel;
+  GtkWidget       *toolbar;
+  GSList          *toolbar_tiles;
 
   Map *map;
 
@@ -99,10 +104,22 @@ struct _UIArenaPrivate
   GAsyncQueue *animation_queue;
 
   gulong connected_signals[LAST_CONN_SIGNAL];
+
+  gboolean map_edit;
 };
 
+enum ui_arena_properties
+  {
+   UI_ARENA_PROP_0,
+   UI_ARENA_PROP_MAP,
+   UI_ARENA_PROP_MAP_EDIT,
+   UI_ARENA_PROP_LAST
+  };
+
 G_DEFINE_TYPE_WITH_CODE(UIArena, ui_arena, GTK_TYPE_BOX, G_ADD_PRIVATE(UIArena))
 
+static void ui_arena_map_edit_init(UIArena *self);
+
 static gboolean
 ui_arena_draw_handler(GtkWidget *widget, cairo_t *cr, UIArena *uiarena)
 {
@@ -136,7 +153,7 @@ ui_arena_init(UIArena *self)
      self->priv->width,
      self->priv->height);
 
-  g_signal_connect(G_OBJECT(self->priv->arena), "draw",
+  self->priv->connected_signals[DRAW] = g_signal_connect(G_OBJECT(self->priv->arena), "draw",
 		   G_CALLBACK(ui_arena_draw_handler), self);
 
   gtk_widget_set_events(GTK_WIDGET(self->priv->arena),
@@ -153,7 +170,7 @@ ui_arena_init(UIArena *self)
   gtk_grid_attach(GTK_GRID(head), lab, 0, 0, 1, 1);
   gtk_grid_attach(GTK_GRID(head), GTK_WIDGET(self->priv->filelabel), 1, 0, 1, 1);
 
-  /* Add the Graphical Map and File Label to UIArean */
+  /* Add the Graphical Map and File Label to UIArena */
   gtk_box_set_homogeneous(GTK_BOX(self), FALSE);
   gtk_box_pack_start(GTK_BOX(self), head, FALSE, TRUE, 0);
   gtk_box_pack_start(GTK_BOX(self), GTK_WIDGET(self->priv->arena), TRUE, TRUE, 0);
@@ -163,9 +180,69 @@ ui_arena_init(UIArena *self)
   gtk_widget_show(head);
 }
 
+static void
+ui_arena_set_property(GObject *self, guint prop_id, const GValue *value,
+		      GParamSpec *pspec)
+{
+  /* it's not null if we got it, but it might not be ours */
+  g_return_if_fail(IS_UI_ARENA(self));
+
+  UIArena *arena = UI_ARENA(self);
+  GObject *obj;
+
+  switch (prop_id)
+    {
+    case UI_ARENA_PROP_MAP:
+      obj = g_value_get_object(value);
+      if(NULL != arena->priv->map)
+	g_object_unref(arena->priv->map);
+      arena->priv->map = NULL;
+      if(NULL != obj)
+	{
+	  g_assert(G_IS_MAP(obj));
+	  arena->priv->map = g_object_ref(MAP(obj));
+	  ui_arena_set_map(arena, arena->priv->map);
+	}
+      break;
+    case UI_ARENA_PROP_MAP_EDIT:
+      arena->priv->map_edit = g_value_get_boolean(value);
+      /* Setup for Map editing */
+      if(arena->priv->map_edit)
+	ui_arena_map_edit_init(arena);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID(self, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+ui_arena_get_property(GObject *self, guint prop_id, GValue *value,
+		      GParamSpec *pspec)
+{
+  /* it's not null if we got it, but it might not be ours */
+  g_return_if_fail(IS_UI_ARENA(self));
+
+  UIArena *arena = UI_ARENA(self);
+
+  switch (prop_id)
+    {
+    case UI_ARENA_PROP_MAP:
+      g_value_set_object(value, g_object_ref(G_OBJECT(arena->priv->map)));
+      break;
+    case UI_ARENA_PROP_MAP_EDIT:
+      g_value_set_boolean(value, arena->priv->map_edit);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID(self, prop_id, pspec);
+      break;
+    }
+}
+
 static void
 ui_arena_class_init(UIArenaClass *klass)
 {
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
   for(gint i = 0; i < TILE_LAST; i++)
     {
       tile_buf[i] = gdk_pixbuf_new_from_xpm_data((const gchar **)xpm[i]);
@@ -177,6 +254,24 @@ ui_arena_class_init(UIArenaClass *klass)
 		  gdk_pixbuf_get_height(tile_buf[i]),
 		  TILE_SIZE);
     }
+
+  object_class->set_property = ui_arena_set_property;
+  object_class->get_property = ui_arena_get_property;
+
+  g_object_class_install_property
+    (G_OBJECT_CLASS(klass), UI_ARENA_PROP_MAP,
+     g_param_spec_object("map",
+			 "GNU Robots Map",
+			 "Map to use for the robot's exploration.",
+			 G_TYPE_OBJECT,
+			 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+  g_object_class_install_property
+    (G_OBJECT_CLASS(klass), UI_ARENA_PROP_MAP_EDIT,
+     g_param_spec_boolean("map-edit",
+			  "Map Edit Mode",
+			  "Use map editing mode instead of robot exploration mode.",
+			  FALSE,
+			  G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 }
 
 static void
@@ -486,15 +581,195 @@ ui_arena_set_map(UIArena *arena, Map *map)
 }
 
 GtkWidget *
-ui_arena_new(Map *map)
+ui_arena_new(Map *map, gboolean map_edit)
+{
+  UIArena* arena = NULL;
+
+  if(NULL == map)
+    arena = UI_ARENA(g_object_new(UI_TYPE_ARENA,
+				  "map-edit", map_edit,
+				  NULL));
+  else
+    arena = UI_ARENA(g_object_new(UI_TYPE_ARENA,
+				  "map", map,
+				  "map-edit", map_edit,
+				  NULL));
+
+  return GTK_WIDGET(arena);
+}
+
+/***************** Map Update Functions *****************/
+
+/** Number of tile types the user can edit on the map
+ */
+#define NUM_TILES 6
+/** Characters used for each tile type (see configs.h), in the same
+ *  order as the toolbar.
+ */
+static const gint tile_char[NUM_TILES] =
+  {SPACE,      WALL,      PRIZE,      FOOD,      BADDIE,      ROBOT};
+/** Descriptions for each tile type (see configs.h), in the same
+ *  order as the toolbar.
+ */
+static const gchar* tile_text[NUM_TILES] =
+  {"Space",    "Wall",    "Prize",    "Food",    "Baddie",    "Robot"};
+/** tile_index for each tile type (see configs.h), in the same
+ *  order as the toolbar.
+ */
+static const gint tile_index[NUM_TILES] =
+  {TILE_SPACE, TILE_WALL, TILE_PRIZE, TILE_FOOD, TILE_BADDIE, TILE_ROBOT};
+
+/** Check the toolbar to determine which tile type is currently selected.
+ *
+ * \param[in] self the UIArena being checked.
+ *
+ * \returns a character representing the location type (as defined in
+ * configs.h).
+ */
+static gchar
+toolbar_selected_char(UIArena *self)
 {
-  UIArena* arena = UI_ARENA(g_object_new(UI_TYPE_ARENA, NULL));
+  gchar retval = '\0';
+  gint item = NUM_TILES + 1;
+  for(gint i = 0; i < g_slist_length(self->priv->toolbar_tiles); i++)
+    {
+      GtkToolItem *button = GTK_TOOL_ITEM(g_slist_nth_data(self->priv->toolbar_tiles, i));
+      if(gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(button)))
+	{
+	  for(gint j = 0; j < NUM_TILES; j++)
+	    {
+	      if(g_strcmp0(gtk_tool_button_get_label(GTK_TOOL_BUTTON(button)), tile_text[j]) == 0)
+		{
+		  item = j;
+		  break;
+		}
+	    }
+	  break;
+	}
+    }
+  g_return_val_if_fail(item < NUM_TILES, retval); /* No toolbar tile is selected */
+  retval = tile_char[item];
+  return retval;
+}
 
-  if(NULL != map)
+/** Change the map at location x, y (GUI coordinates) to match the
+ * currently selected tile type.
+ *
+ * \param[in] self the UIArena being modified.
+ * \param[in] x    the x GUI coordinate (will be converted to a map
+ *                 coordinate).
+ * \param[in] y    the y GUI coordinate (will be converted to a map
+ *                 coordinate).
+ */
+static void
+map_edit(UIArena *self, gint x, gint y)
+{
+  x = (x - (x % TILE_SIZE)) / TILE_SIZE;
+  y = (y - (y % TILE_SIZE)) / TILE_SIZE;
+
+  g_debug("ui-arena:button_press_handler: Primary button (x, y): (%d, %d)\n", x, y);
+  gchar loc_char = toolbar_selected_char(self);
+  g_debug("ui-arena: button_press_handler: '%c' is selected for (%d, %d)\n", loc_char, x, y);
+  gchar old_loc_char = map_get_loc_thing_char(self->priv->map, x, y);
+  if(old_loc_char != loc_char)
     {
-      g_return_val_if_fail(G_IS_MAP(map), NULL);
-      ui_arena_set_map(arena, map);
+      if(old_loc_char == WALL)
+	map_set_loc(self->priv->map, x, y, FALSE);
+      else if(loc_char == WALL)
+	map_set_loc(self->priv->map, x, y, TRUE);
+
+      switch(loc_char)
+	{
+	case WALL:
+	case SPACE:
+	  map_remove_thing(self->priv->map, x, y);
+	  break;
+	case FOOD:
+	case PRIZE:
+	case BADDIE:
+	case ROBOT:
+	  map_place_thing(self->priv->map, x, y, loc_char, EAST, NULL);
+	  break;
+	default:
+	  g_error("ui-arena: button_press_handler: Unknown loc_char: %c", loc_char);
+	}
     }
+}
 
-  return GTK_WIDGET(arena);
+/* Handle button click events, modifying the map if the primary button
+ * is clicked.
+ */
+static gboolean
+button_press_handler(GtkWidget      *widget,
+		     GdkEventButton *event,
+		     gpointer        data)
+{
+  if (event->button == GDK_BUTTON_PRIMARY)
+    {
+      map_edit(UI_ARENA(data), event->x, event->y);
+    }
+  else if (event->button == GDK_BUTTON_SECONDARY)
+    {
+      g_debug("Secondary button\n");
+    }
+
+  /* We've handled the event, stop processing */
+  return TRUE;
+}
+
+/* Handle motion events by continuing to draw if button 1 is
+ * still held down. 
+ */
+static gboolean
+motion_notify_handler (GtkWidget      *widget,
+		       GdkEventMotion *event,
+		       gpointer        data)
+{
+  if (event->state & GDK_BUTTON1_MASK)
+      map_edit(UI_ARENA(data), event->x, event->y);
+
+  /* We've handled it, stop processing */
+  return TRUE;
+}
+
+/** Set up a toolbar and event handlers for map editing.
+ *
+ * The toolbar will be added to UIArena at the start (will fall after
+ * any other items already packed at the start).
+ *
+ * \param[in, out] self the UIArena object to be modified.
+ */
+static void
+ui_arena_map_edit_init(UIArena *self)
+{
+  GtkIconTheme *theme = gtk_icon_theme_get_default();
+  gtk_icon_theme_append_search_path(theme, "/home/mhenry/programs/gnurobots/icons");
+
+  self->priv->connected_signals[BUTTON_PRESSED] =
+    g_signal_connect(G_OBJECT(self->priv->arena), "button-press-event",
+		     G_CALLBACK(button_press_handler), self);
+  self->priv->connected_signals[MOTION_NOTIFY] =
+    g_signal_connect(G_OBJECT(self->priv->arena), "motion-notify-event",
+		     G_CALLBACK(motion_notify_handler), self);
+  gtk_widget_add_events (GTK_WIDGET(self->priv->arena),
+			 GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK);
+
+  self->priv->toolbar = gtk_toolbar_new();
+  self->priv->toolbar_tiles = NULL;
+  GSList *group = NULL;
+  for(gint i = 0; i < NUM_TILES; i++)
+    {
+      GtkToolItem *item = gtk_radio_tool_button_new(group);
+      gtk_tool_button_set_label(GTK_TOOL_BUTTON(item), tile_text[i]);
+      gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(item), tile_text[i]);
+      GtkWidget *image = gtk_image_new_from_pixbuf(tile_buf[tile_index[i]]);
+      gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(item), image);
+      gtk_toolbar_insert(GTK_TOOLBAR(self->priv->toolbar), item, i);
+      group = gtk_radio_tool_button_get_group(GTK_RADIO_TOOL_BUTTON(item));
+      self->priv->toolbar_tiles =
+	g_slist_append(self->priv->toolbar_tiles, item);
+    }
+
+  gtk_box_pack_start(GTK_BOX(self), self->priv->toolbar, FALSE, TRUE, 0);
+  gtk_widget_show_all(self->priv->toolbar);
 }
diff --git a/src/ui-window.c b/src/ui-window.c
index dd976c9..da9be49 100644
--- a/src/ui-window.c
+++ b/src/ui-window.c
@@ -40,6 +40,7 @@ struct _UIWindowPrivate {
 
   Map *map;
   GRobot *robot;
+  gboolean map_edit;
 };
 
 enum ui_window_properties
@@ -47,6 +48,7 @@ enum ui_window_properties
    UI_WINDOW_PROP_0,
    UI_WINDOW_PROP_MAP,
    UI_WINDOW_PROP_ROBOT,
+   UI_WINDOW_PROP_MAP_EDIT,
    UI_WINDOW_PROP_LAST
   };
 
@@ -58,6 +60,9 @@ ui_window_dispose (GObject *self)
   g_action_map_remove_action(G_ACTION_MAP(self), "map-open");
   g_action_map_remove_action(G_ACTION_MAP(self), "scheme-interrupt");
 
+  g_object_unref(UI_WINDOW(self)->priv->map);
+  g_object_unref(UI_WINDOW(self)->priv->robot);
+
   /* These should all get disposed when the window disposes, but we'll
      clear the priv object anyway */
 
@@ -72,12 +77,6 @@ ui_window_dispose (GObject *self)
 static void
 ui_window_finalize (GObject *self)
 {
-  GValue *value = NULL;
-
-  g_value_init_from_instance(value, G_OBJECT(NULL));
-  g_object_set_property(self, "map", value);
-  g_object_set_property(self, "robot", value);
-
   G_OBJECT_CLASS (ui_window_parent_class)->finalize (self);
 }
 
@@ -95,22 +94,32 @@ ui_window_set_property(GObject *self, guint prop_id, const GValue *value,
     {
     case UI_WINDOW_PROP_MAP:
       obj = g_value_get_object(value);
-      if(NULL != obj)
-	  g_assert(G_IS_MAP(obj));
       if(NULL != win->priv->map)
 	g_object_unref(win->priv->map);
-      win->priv->map = g_object_ref(MAP(obj));
-      ui_arena_set_map(UI_ARENA(win->priv->arena), win->priv->map);
+      win->priv->map = NULL;
+      if(NULL != obj)
+	{
+	  g_assert(G_IS_MAP(obj));
+	  win->priv->map = g_object_ref(MAP(obj));
+	}
+      g_object_set(win->priv->arena, "map", win->priv->map, NULL);
       break;
     case UI_WINDOW_PROP_ROBOT:
       obj = g_value_get_object(value);
-      if(NULL != obj)
-	g_assert(G_IS_ROBOT(obj));
       if(NULL != win->priv->robot)
 	g_object_unref(win->priv->robot);
-      win->priv->robot = g_object_ref(G_ROBOT(obj));
+      win->priv->robot = NULL;
+      if(NULL != obj)
+	{
+	  g_assert(G_IS_ROBOT(obj));
+	  win->priv->robot = g_object_ref(G_ROBOT(obj));
+	}
       ui_status_set_robot(UI_STATUS(win->priv->statustab), win->priv->robot);
       break;
+    case UI_WINDOW_PROP_MAP_EDIT:
+      win->priv->map_edit = g_value_get_boolean(value);
+      g_object_set(win->priv->arena, "map-edit", win->priv->map_edit, NULL);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID(self, prop_id, pspec);
       break;
@@ -134,6 +143,9 @@ ui_window_get_property(GObject *self, guint prop_id, GValue *value,
     case UI_WINDOW_PROP_ROBOT:
       g_value_set_object(value, g_object_ref(G_OBJECT(win->priv->robot)));
       break;
+    case UI_WINDOW_PROP_MAP_EDIT:
+      g_value_set_boolean(value, win->priv->map_edit);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID(self, prop_id, pspec);
       break;
@@ -164,6 +176,13 @@ ui_window_class_init (UIWindowClass *klass)
 			 "Robot that will explore the map.",
 			 G_TYPE_OBJECT,
 			 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+  g_object_class_install_property
+    (G_OBJECT_CLASS(klass), UI_WINDOW_PROP_MAP_EDIT,
+     g_param_spec_boolean("map-edit",
+			  "Map Edit Mode",
+			  "Use map editing mode instead of robot exploration mode.",
+			  FALSE,
+			  G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
   /*    GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 	widget_class->window_state_event = gedit_window_window_state_event;
 	widget_class->configure_event = gedit_window_configure_event;
@@ -197,16 +216,16 @@ on_ui_window_destroy(GtkWidget *widget, gpointer data)
 	gtk_main_quit();
 }
 
-
 static gchar*
-ui_window_choose_file(GtkWidget *parent, gchar *title, gint num_shortcuts, gchar **shortcuts)
+ui_window_choose_file(GtkWidget *parent, gchar *title, gint num_shortcuts, gchar **shortcuts, GtkFileChooserAction action)
 {
   GtkWidget* file_chooser =
     gtk_file_chooser_dialog_new(title,
 				GTK_WINDOW(parent),
-				GTK_FILE_CHOOSER_ACTION_OPEN,
+				action,
 				"Cancel", GTK_RESPONSE_CANCEL,
-				"Open", GTK_RESPONSE_ACCEPT,
+				action == GTK_FILE_CHOOSER_ACTION_OPEN? "Open" : "Save",
+				GTK_RESPONSE_ACCEPT,
 				NULL);
 
   for(gint i = 0; i < num_shortcuts; i++)
@@ -221,7 +240,7 @@ ui_window_choose_file(GtkWidget *parent, gchar *title, gint num_shortcuts, gchar
       filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (file_chooser));
     }
   gtk_widget_destroy(file_chooser);
- 
+
   return(filename);
 }
 
@@ -236,7 +255,7 @@ map_open_activated (GSimpleAction  *action,
   shortcuts[0] = getenv(MAPS_PATH_ENV);
   shortcuts[1] = MAPS_PATH;
 
-  gchar *map_filename = ui_window_choose_file(GTK_WIDGET(win), "Load Map File", num_shortcuts, shortcuts);
+  gchar *map_filename = ui_window_choose_file(GTK_WIDGET(win), "Load Map File", num_shortcuts, shortcuts, GTK_FILE_CHOOSER_ACTION_OPEN);
 
   g_free(shortcuts);
 
@@ -266,6 +285,69 @@ map_open_activated (GSimpleAction  *action,
     }
 }
 
+static void
+map_save_as_activated (GSimpleAction  *action,
+		    GVariant       *parameter,
+		    gpointer        user_data)
+{
+  UIWindow *win = UI_WINDOW(user_data);
+  const gint num_shortcuts = 2;
+  gchar **shortcuts = g_malloc(num_shortcuts * sizeof(gchar**));
+  shortcuts[0] = getenv(MAPS_PATH_ENV);
+  shortcuts[1] = MAPS_PATH;
+
+  gchar *map_filename = ui_window_choose_file(GTK_WIDGET(win), "Save Map File", num_shortcuts, shortcuts, GTK_FILE_CHOOSER_ACTION_SAVE);
+
+  g_free(shortcuts);
+
+  if(NULL != map_filename)
+    {
+      Map *map = win->priv->map;
+      GError *error = NULL;
+      map_save_filename(map, map_filename, &error);
+      if(NULL != error)
+	{
+	  GtkWidget *dialog =
+	    gtk_message_dialog_new (GTK_WINDOW(win),
+				    GTK_DIALOG_DESTROY_WITH_PARENT,
+				    GTK_MESSAGE_ERROR,
+				    GTK_BUTTONS_CLOSE,
+				    "Error loading file '%s': %s",
+				    map_filename, error->message);
+	  gtk_dialog_run (GTK_DIALOG (dialog));
+	  gtk_widget_destroy (dialog);
+	  //	  g_error("Unable to load map: %s", error->message);
+	  g_error_free(error);
+	}
+    }
+}
+
+static void
+map_save_activated (GSimpleAction  *action,
+		    GVariant       *parameter,
+		    gpointer        user_data)
+{
+  UIWindow *win = UI_WINDOW(user_data);
+
+  Map *map = win->priv->map;
+  GError *error = NULL;
+  map_save(map, &error);
+  if(NULL != error)
+    {
+      GtkWidget *dialog =
+	gtk_message_dialog_new (GTK_WINDOW(win),
+				GTK_DIALOG_DESTROY_WITH_PARENT,
+				GTK_MESSAGE_ERROR,
+				GTK_BUTTONS_CLOSE,
+				"Error saving file: %s",
+				error->message);
+      gtk_dialog_run (GTK_DIALOG (dialog));
+      gtk_widget_destroy (dialog);
+      //	  g_error("Unable to load map: %s", error->message);
+      g_error_free(error);
+    }
+}
+
 static void
 about_activated (GSimpleAction  *action,
 		 GVariant       *parameter,
@@ -324,6 +406,8 @@ ui_window_menu(UIWindow *self)
 {
   GActionEntry actions[] =
     {{"map-open", map_open_activated, NULL, NULL, NULL},
+     {"map-save", map_save_activated, NULL, NULL, NULL},
+     {"map-save-as", map_save_as_activated, NULL, NULL, NULL},
      {"scheme-interrupt", scheme_interrupt_activated, NULL, NULL, NULL}};
 
   g_action_map_add_action_entries (G_ACTION_MAP (self),
@@ -334,6 +418,8 @@ ui_window_menu(UIWindow *self)
   GMenu *gmenu = g_menu_new();
 
   g_menu_append(gmenu, "_Open Map", "win.map-open");
+  g_menu_append(gmenu, "_Save Map", "win.map-save");
+  g_menu_append(gmenu, "_Save Map As", "win.map-save-as");
   g_menu_append(gmenu, "_Interrupt Scheme", "win.scheme-interrupt");
 
   GtkWidget *mbar = gtk_header_bar_new();
@@ -365,7 +451,7 @@ ui_window_init(UIWindow *self)
   self->priv->cmdwin = ui_cmdwin_new();
   /* ^so that's needed before guile can start... */
 
-  self->priv->arena = ui_arena_new(NULL);
+  self->priv->arena = ui_arena_new(self->priv->map, self->priv->map_edit);
   self->priv->statustab = ui_status_new();
 
   gtk_window_set_titlebar(GTK_WINDOW(self), self->priv->menubar);
@@ -384,13 +470,14 @@ ui_window_init(UIWindow *self)
 }
 
 GtkWidget *
-ui_window_new(Map *map, GRobot *robot)
+ui_window_new(Map *map, GRobot *robot, gboolean map_edit)
 {
   g_return_val_if_fail(G_IS_MAP(map), NULL);
   g_return_val_if_fail(G_IS_ROBOT(robot), NULL);
 
   return g_object_new(UI_WINDOW_TYPE,
 		      "map", map, "robot", robot,
+		      "map-edit", map_edit,
 		      NULL);
 }
 
@@ -428,19 +515,20 @@ activate(GtkApplication* app,
 {
   GtkWidget *window;
 
-  window = ui_window_new(MAP(user_data[0]), G_ROBOT(user_data[1]));
+  window = ui_window_new(MAP(user_data[0]), G_ROBOT(user_data[1]),
+			 GPOINTER_TO_INT(user_data[2]));
   gtk_application_add_window(app, GTK_WINDOW(window));
 
   gtk_widget_show_all (window);
 }
 
 gint
-ui_window_main(Map *map, GRobot *robot, gint argc, gchar **argv)
+ui_window_main(Map *map, GRobot *robot, gint argc, gchar **argv, gboolean map_edit)
 {
   g_return_val_if_fail(G_IS_MAP(map), EXIT_FAILURE);
   g_return_val_if_fail(G_IS_ROBOT(robot), EXIT_FAILURE);
 
-  gpointer user_data[2] = {map, robot};
+  gpointer user_data[3] = {map, robot, GINT_TO_POINTER(map_edit)};
 
   GtkApplication *app = gtk_application_new("org.gnu.gnurobots",
 					    G_APPLICATION_FLAGS_NONE);
