diff --git a/app/Makefile.am b/app/Makefile.am
index e924a26..1c94efa 100644
--- a/app/Makefile.am
+++ b/app/Makefile.am
@@ -56,7 +56,10 @@ ICON_PNG_PAIRS= \
 	dia_cursor_hand_open $(srcdir)/pixmaps/cursor-hand-open.png \
 	dia_cursor_hand_closed $(srcdir)/pixmaps/cursor-hand-closed.png \
 	dia_cursor_magnify_minus $(srcdir)/pixmaps/cursor-magnify-minus.png \
-	dia_cursor_magnify_plus $(srcdir)/pixmaps/cursor-magnify-plus.png
+	dia_cursor_magnify_plus $(srcdir)/pixmaps/cursor-magnify-plus.png \
+	\
+	dia_guide_snap_on_icon $(srcdir)/pixmaps/guide-snap-on.png \
+	dia_guide_snap_off_icon $(srcdir)/pixmaps/guide-snap-off.png
 	
 
 ICON_PNGS= \
@@ -88,7 +91,9 @@ ICON_PNGS= \
 	pixmaps/objects-layer-below.png \
 	pixmaps/layers.png \
 	pixmaps/layer-add.png \
-	pixmaps/layer-rename.png
+	pixmaps/layer-rename.png \
+	pixmaps/guide-snap-on.png \
+	pixmaps/guide-snap-off.png
 	
 
 dia-app-icons.h: $(ICON_PNGS)
@@ -135,6 +140,8 @@ dia_core_files = \
 	linewidth_area.h \
 	grid.c \
 	grid.h \
+	guide_tool.c \
+	guide_tool.h \
 	handle_ops.c \
 	handle_ops.h \
 	interface.c \
@@ -212,7 +219,10 @@ dia_core_files = \
 	textedit.h \
 	textedit_tool.c \
 	textedit_tool.h \
-	diagrid.h
+	diagrid.h \
+	\
+	new_guide_dialog.c \
+	new_guide_dialog.h
 
 dia_SOURCES = \
 	$(dia_core_files) \
diff --git a/app/commands.c b/app/commands.c
index a5ad14f..4e40aca 100644
--- a/app/commands.c
+++ b/app/commands.c
@@ -89,6 +89,7 @@ ShellExecuteA (long        hwnd,
 #include "dia-props.h"
 #include "authors.h"                /* master contributors data */
 #include "object.h"
+#include "new_guide_dialog.h"
 
 void 
 file_quit_callback (GtkAction *action)
@@ -1192,6 +1193,59 @@ view_snap_to_grid_callback (GtkToggleAction *action)
 }
 
 void
+view_new_guide_callback (GtkAction *action)
+{
+  DDisplay *ddisp;  
+
+  ddisp = ddisplay_active();
+  if (!ddisp) return;
+  
+  dialog_new_guide_show();
+}
+
+void
+view_visible_guides_callback (GtkToggleAction *action)
+{
+  DDisplay *ddisp;
+  gboolean old_val;
+
+  ddisp = ddisplay_active();
+  if (!ddisp) return;
+  
+  old_val = ddisp->guides_visible;
+  ddisp->guides_visible = gtk_toggle_action_get_active (action); 
+
+  if (old_val != ddisp->guides_visible) {
+    ddisplay_add_update_all(ddisp);
+    ddisplay_flush(ddisp);
+  }
+}
+
+void
+view_snap_to_guides_callback (GtkToggleAction *action)
+{
+  DDisplay *ddisp;
+
+  ddisp = ddisplay_active();
+  if (!ddisp) return;
+  
+  ddisplay_set_snap_to_guides(ddisp, gtk_toggle_action_get_active (action));
+}
+
+void
+view_remove_all_guides_callback(GtkAction *action)
+{
+  Diagram *dia;
+  
+  dia = ddisplay_active_diagram();
+  if (!dia) return;
+
+  diagram_remove_all_guides(dia);
+  diagram_add_update_all(dia);
+  diagram_flush(dia);
+}
+
+void
 view_snap_to_objects_callback (GtkToggleAction *action)
 {
   DDisplay *ddisp;
diff --git a/app/commands.h b/app/commands.h
index 077f834..e09be97 100644
--- a/app/commands.h
+++ b/app/commands.h
@@ -45,17 +45,21 @@ void edit_cut_text_callback   (GtkAction *action);
 
 void edit_paste_image_callback (GtkAction *action);
 
-void view_zoom_in_callback         (GtkAction *action);
-void view_zoom_out_callback        (GtkAction *action);
-void view_zoom_set_callback        (GtkAction *action);
-void view_unfullscreen             (void);
-void view_fullscreen_callback      (GtkToggleAction *action);
-void view_aa_callback              (GtkToggleAction *action);
-void view_visible_grid_callback    (GtkToggleAction *action);
-void view_snap_to_grid_callback    (GtkToggleAction *action);
-void view_snap_to_objects_callback (GtkToggleAction *action);
-void view_toggle_rulers_callback   (GtkToggleAction *action);
-void view_toggle_scrollbars_callback (GtkToggleAction *action);
+void view_zoom_in_callback            (GtkAction *action);
+void view_zoom_out_callback           (GtkAction *action);
+void view_zoom_set_callback           (GtkAction *action);
+void view_unfullscreen                (void);
+void view_fullscreen_callback         (GtkToggleAction *action);
+void view_aa_callback                 (GtkToggleAction *action);
+void view_visible_grid_callback       (GtkToggleAction *action);
+void view_snap_to_grid_callback       (GtkToggleAction *action);
+void view_new_guide_callback          (GtkAction *action);
+void view_visible_guides_callback     (GtkToggleAction *action);
+void view_snap_to_guides_callback     (GtkToggleAction *action);
+void view_remove_all_guides_callback  (GtkAction *action);
+void view_snap_to_objects_callback    (GtkToggleAction *action);
+void view_toggle_rulers_callback      (GtkToggleAction *action);
+void view_toggle_scrollbars_callback  (GtkToggleAction *action);
 
 void view_show_cx_pts_callback     (GtkToggleAction *action);
 void view_new_view_callback           (GtkAction *action);
diff --git a/app/dia-props.c b/app/dia-props.c
index 49aa6ff..a10cabd 100644
--- a/app/dia-props.c
+++ b/app/dia-props.c
@@ -37,7 +37,7 @@ static GtkWidget *dialog = NULL;
 static GtkWidget *dynamic_check;
 static GtkWidget *width_x_entry, *width_y_entry;
 static GtkWidget *visible_x_entry, *visible_y_entry;
-static GtkWidget *bg_colour, *grid_colour, *pagebreak_colour;
+static GtkWidget *bg_colour, *grid_colour, *pagebreak_colour, *guide_colour;
 static GtkWidget *hex_check, *hex_size_entry;
 
 static void diagram_properties_respond(GtkWidget *widget,
@@ -202,7 +202,7 @@ create_diagram_properties_dialog(Diagram *dia)
   gtk_widget_show(label);
 
   /* The background page */
-  table = gtk_table_new(1,2, FALSE);
+  table = gtk_table_new(1,3, FALSE);
   gtk_container_set_border_width(GTK_CONTAINER(table), 2);
   gtk_table_set_row_spacings(GTK_TABLE(table), 1);
   gtk_table_set_col_spacings(GTK_TABLE(table), 2);
@@ -240,6 +240,17 @@ create_diagram_properties_dialog(Diagram *dia)
 		   GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
   gtk_widget_show(pagebreak_colour);
 
+  label = gtk_label_new(_("Guides"));
+  gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+  gtk_table_attach(GTK_TABLE(table), label, 0,1, 3,4,
+		   GTK_FILL, GTK_FILL, 0, 0);
+  gtk_widget_show(label);
+
+  guide_colour = dia_color_selector_new();
+  gtk_table_attach(GTK_TABLE(table), guide_colour, 1,2, 3,4,
+		   GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
+  gtk_widget_show(guide_colour);
+
   label = gtk_label_new(_("Colors"));
   gtk_notebook_append_page(GTK_NOTEBOOK(notebook), table, label);
   gtk_widget_show(table);
@@ -286,6 +297,8 @@ diagram_properties_retrieve(Diagram *dia)
 			       &dia->grid.colour);
   dia_color_selector_set_color(pagebreak_colour, 
 			       &dia->pagebreak_color);
+  dia_color_selector_set_color(guide_colour,
+			       &dia->guide_color);
 
   diagram_properties_update_sensitivity(GTK_TOGGLE_BUTTON(dynamic_check), dia);
 
@@ -327,6 +340,8 @@ diagram_properties_respond(GtkWidget *widget,
         &active_diagram->data->bg_color, sizeof(active_diagram->data->bg_color));
       undo_change_memswap (active_diagram, 
         &active_diagram->pagebreak_color, sizeof(active_diagram->pagebreak_color));
+      undo_change_memswap (active_diagram,
+        &active_diagram->guide_color, sizeof(active_diagram->guide_color));
       undo_set_transactionpoint(active_diagram->undo);
 
       active_diagram->grid.dynamic =
@@ -349,6 +364,8 @@ diagram_properties_respond(GtkWidget *widget,
   				 &active_diagram->grid.colour);
       dia_color_selector_get_color(pagebreak_colour,
   				 &active_diagram->pagebreak_color);
+      dia_color_selector_get_color(guide_colour,
+  				 &active_diagram->guide_color);
       diagram_add_update_all(active_diagram);
       diagram_flush(active_diagram);
       diagram_set_modified(active_diagram, TRUE);
diff --git a/app/diagram.c b/app/diagram.c
index bd13876..66821f5 100644
--- a/app/diagram.c
+++ b/app/diagram.c
@@ -201,6 +201,7 @@ diagram_init(Diagram *dia, const char *filename)
   dia->data = &dia->parent_instance; /* compatibility */
 
   dia->pagebreak_color = prefs.new_diagram.pagebreak_color;
+  dia->guide_color = prefs.new_diagram.guide_color;
   
   get_paper_info (&dia->data->paper, -1, &prefs.new_diagram);
 
@@ -215,10 +216,7 @@ diagram_init(Diagram *dia, const char *filename)
   dia->grid.dynamic = prefs.grid.dynamic;
   dia->grid.major_lines = prefs.grid.major_lines;
 
-  dia->guides.nhguides = 0;
-  dia->guides.hguides = NULL;
-  dia->guides.nvguides = 0;
-  dia->guides.vguides = NULL;
+  dia->guides = NULL;
 
   if (dia->filename != NULL)
     g_free(dia->filename);
@@ -1529,3 +1527,162 @@ diagram_object_modified(Diagram *dia, DiaObject *object)
   /* signal about the change */
   dia_diagram_change (dia, DIAGRAM_CHANGE_OBJECT, object);
 }
+
+Guide* diagram_add_guide (Diagram *dia, real position, GtkOrientation orientation, gboolean push_undo)
+{
+  Guide *guide = g_new0(Guide, 1);
+  guide->position = position;
+  guide->orientation = orientation;
+  dia->guides = g_list_append(dia->guides, guide);
+  
+  if(push_undo) {
+    undo_add_guide(dia, guide, TRUE);   /* Update undo stack. */
+    undo_set_transactionpoint(dia->undo);
+  }
+  
+  diagram_add_update_all(dia);
+  diagram_modified(dia);
+  diagram_flush(dia);
+  
+  return guide;
+}
+
+Guide *diagram_pick_guide (Diagram *dia,
+                           gdouble x,
+                           gdouble y,
+                           gdouble epsilon_x,
+                           gdouble epsilon_y)
+{
+  GList *list;
+  Guide *ret = NULL;
+  gdouble mindist = G_MAXDOUBLE;
+
+  g_return_val_if_fail (epsilon_x > 0 && epsilon_y > 0, NULL);
+
+  for (list = dia->guides;
+       list;
+       list = g_list_next (list)) {
+    Guide *guide = list->data;
+    real position = guide->position;
+    gdouble dist;
+
+    switch (guide->orientation) {
+    case GTK_ORIENTATION_HORIZONTAL:
+      dist = ABS (position - y);
+      if (dist < MIN (epsilon_y, mindist)) {
+        mindist = dist;
+        ret = guide;
+      }
+      break;
+
+    case GTK_ORIENTATION_VERTICAL:
+      dist = ABS (position - x);
+      if (dist < MIN (epsilon_x, mindist / epsilon_y * epsilon_x)) {
+        mindist = dist * epsilon_y / epsilon_x;
+        ret = guide;
+      }
+      break;
+
+    default:
+      continue;
+    }
+
+  }
+
+  return ret;
+}
+
+Guide *diagram_pick_guide_h (Diagram *dia,
+                             gdouble x,
+                             gdouble y,
+                             gdouble epsilon_x,
+                             gdouble epsilon_y)
+{
+  GList *list;
+  Guide *ret = NULL;
+  gdouble mindist = G_MAXDOUBLE;
+
+  g_return_val_if_fail (epsilon_x > 0 && epsilon_y > 0, NULL);
+
+  for (list = dia->guides;
+       list;
+       list = g_list_next (list)) {
+    Guide *guide = list->data;
+    real position = guide->position;
+    gdouble dist;
+
+    switch (guide->orientation) {
+    case GTK_ORIENTATION_HORIZONTAL:
+      dist = ABS (position - y);
+      if (dist < MIN (epsilon_y, mindist)) {
+        mindist = dist;
+        ret = guide;
+      }
+      break;
+
+    default:
+      continue;
+    }
+
+  }
+
+  return ret;
+}
+
+Guide *diagram_pick_guide_v (Diagram *dia,
+                             gdouble x,
+                             gdouble y,
+                             gdouble epsilon_x,
+                             gdouble epsilon_y)
+{
+  GList *list;
+  Guide *ret = NULL;
+  gdouble mindist = G_MAXDOUBLE;
+
+  g_return_val_if_fail (epsilon_x > 0 && epsilon_y > 0, NULL);
+
+  for (list = dia->guides;
+       list;
+       list = g_list_next (list)) {
+    Guide *guide = list->data;
+    real position = guide->position;
+    gdouble dist;
+
+    switch (guide->orientation) {
+
+    case GTK_ORIENTATION_VERTICAL:
+      dist = ABS (position - x);
+      if (dist < MIN (epsilon_x, mindist / epsilon_y * epsilon_x)) {
+        mindist = dist * epsilon_y / epsilon_x;
+        ret = guide;
+      }
+      break;
+
+    default:
+      continue;
+    }
+
+  }
+
+  return ret;
+}
+
+void diagram_remove_guide(Diagram *dia, Guide *guide, gboolean push_undo)
+{
+  if(push_undo) {
+    undo_delete_guide(dia, guide, TRUE);   /* Update undo stack. */
+  }
+
+  dia->guides = g_list_remove (dia->guides, guide);
+}
+
+void diagram_remove_all_guides(Diagram *dia)
+{
+  GList *list;
+  
+  for(list = g_list_copy(dia->guides); list; list = g_list_next(list)) {
+    diagram_remove_guide(dia, list->data, TRUE);
+  }
+  
+  undo_set_transactionpoint(dia->undo);
+}
diff --git a/app/diagram.h b/app/diagram.h
index 1c213cf..d44edce 100644
--- a/app/diagram.h
+++ b/app/diagram.h
@@ -26,6 +26,7 @@ typedef struct _Diagram Diagram;
 #include "diagramdata.h"
 #include "undo.h"
 #include "diagrid.h"
+#include "guide.h"
 
 G_BEGIN_DECLS
 
@@ -51,12 +52,9 @@ struct _Diagram {
   Color pagebreak_color; /*!< just to show page breaks */
   DiaGrid     grid;      /*!< the display grid */
 
-  /*! almost completely unused guides (load and save code is there) */  
-  struct {
-    /* sorted arrays of the guides for the diagram */
-    real *hguides, *vguides;
-    guint nhguides, nvguides;
-  } guides;
+
+  GList *guides;        /*!< list of guides */
+  Color guide_color;    /*!< color for guides */
 
   DiagramData *data;     /*! just for compatibility, now that the Diagram _is_ and not _has_ DiagramData */
 
@@ -138,6 +136,42 @@ void diagram_redraw_all(void);
 
 void diagram_object_modified(Diagram *dia, DiaObject *object);
 
+/** Add a guide to the diagram at the given position and orientation.
+ *  Update the undo stack if "push_undo" is true. */
+Guide *diagram_add_guide (Diagram *dia, real position, GtkOrientation orientation, gboolean push_undo);
+
+/** Pick a guide within (epsilon_x, epsilon_y) distance of (x, y).
+ *  Return NULL if no such guide exists. */
+Guide *diagram_pick_guide (Diagram *dia,
+                           gdouble x,
+                           gdouble y,
+                           gdouble epsilon_x,
+                           gdouble epsilon_y);
+
+
+/** Pick a *horizontal* guide within (epsilon_x, epsilon_y) distance of (x, y).
+ *  Return NULL if no such guide exists. */
+Guide *diagram_pick_guide_h (Diagram *dia,
+                             gdouble x,
+                             gdouble y,
+                             gdouble epsilon_x,
+                             gdouble epsilon_y);
+
+/** Pick a *vertical* guide within (epsilon_x, epsilon_y) distance of (x, y).
+ *  Return NULL if no such guide exists. */
+Guide *diagram_pick_guide_v (Diagram *dia,
+                             gdouble x,
+                             gdouble y,
+                             gdouble epsilon_x,
+                             gdouble epsilon_y);
+
+/** Remove the given guide from the diagram.
+ *  Update the undo stack if "push_undo" is true. */
+void diagram_remove_guide(Diagram *dia, Guide *guide, gboolean push_undo);
+
+/** Remove all guides from the diagram. Updates undo stack. */
+void diagram_remove_all_guides(Diagram *dia);
+
 G_END_DECLS
 
 #endif /* DIAGRAM_H */
diff --git a/app/display.c b/app/display.c
index 076d046..59d109b 100644
--- a/app/display.c
+++ b/app/display.c
@@ -241,6 +241,15 @@ new_display(Diagram *dia)
   if (preset != 0) 
     ddisp->grid.snap = (preset > 0 ? TRUE : FALSE);
 
+  ddisp->guides_visible = prefs.guides_visible;
+  preset = GPOINTER_TO_INT (g_object_get_data (G_OBJECT(dia), "show-guides"));
+  if (preset != 0)
+    ddisp->guides_visible = (preset > 0 ? TRUE : FALSE);
+  ddisp->guides_snap = prefs.guides_snap;
+  preset = GPOINTER_TO_INT (g_object_get_data (G_OBJECT(dia), "snap-to-guides"));
+  if (preset != 0)
+    ddisp->guides_snap = (preset > 0 ? TRUE : FALSE);
+
   ddisp->show_cx_pts = prefs.show_cx_pts;
   preset = GPOINTER_TO_INT (g_object_get_data (G_OBJECT(dia), "show-connection-points"));
   if (preset != 0) 
@@ -282,6 +291,10 @@ new_display(Diagram *dia)
 
   ddisp->visible = visible;
 
+  ddisp->is_dragging_new_guideline = FALSE;
+  ddisp->dragged_new_guideline_position = 0;
+  ddisp->dragged_new_guideline_orientation = GTK_ORIENTATION_HORIZONTAL;
+
   initialize_display_widgets(ddisp);
   return ddisp;  /*  set the user data  */
 }
@@ -647,6 +660,7 @@ ddisplay_render_pixmap(DDisplay *ddisp, Rectangle *update)
   /* Draw grid */
   grid_draw(ddisp, update);
   pagebreak_draw(ddisp, update);
+  guidelines_draw(ddisp, update);
 
 #ifdef TRACES
   timer = g_timer_new();
@@ -851,6 +865,24 @@ update_snap_grid_status(DDisplay *ddisp)
   }
 }
 
+/** Set the display's snap-to-guides setting, updating menu and button
+ * in the process */
+void
+ddisplay_set_snap_to_guides(DDisplay *ddisp, gboolean snap)
+{
+  GtkToggleAction *snap_to_guides;
+  ddisp->guides_snap = snap;
+
+  snap_to_guides = GTK_TOGGLE_ACTION (menus_get_action ("ViewSnaptoguides"));
+
+  if (is_integrated_ui ())
+    integrated_ui_toolbar_guides_snap_synchronize_to_display (ddisp);
+
+  /* Currently, this can cause double emit, but that's a small problem. */
+  gtk_toggle_action_set_active (snap_to_guides, ddisp->guides_snap);
+  ddisplay_update_statusbar(ddisp);
+}
+
 /** Set the display's mainpoint magnetism setting, updating menu and button
  * in the process */
 void
@@ -1323,15 +1355,19 @@ display_update_menu_state(DDisplay *ddisp)
   GtkToggleAction *rulers;
   GtkToggleAction *visible_grid;
   GtkToggleAction *snap_to_grid;
+  GtkToggleAction *visible_guides;
+  GtkToggleAction *snap_to_guides;
   GtkToggleAction *show_cx_pts;
   GtkToggleAction *antialiased;
   gboolean scrollbars_shown;
 
-  rulers       = GTK_TOGGLE_ACTION (menus_get_action ("ViewShowrulers"));
-  visible_grid = GTK_TOGGLE_ACTION (menus_get_action ("ViewShowgrid"));
-  snap_to_grid = GTK_TOGGLE_ACTION (menus_get_action ("ViewSnaptogrid"));
-  show_cx_pts  = GTK_TOGGLE_ACTION (menus_get_action ("ViewShowconnectionpoints"));
-  antialiased  = GTK_TOGGLE_ACTION (menus_get_action ("ViewAntialiased"));
+  rulers          = GTK_TOGGLE_ACTION (menus_get_action ("ViewShowrulers"));
+  visible_grid    = GTK_TOGGLE_ACTION (menus_get_action ("ViewShowgrid"));
+  snap_to_grid    = GTK_TOGGLE_ACTION (menus_get_action ("ViewSnaptogrid"));
+  visible_guides  = GTK_TOGGLE_ACTION (menus_get_action ("ViewShowguides"));
+  snap_to_guides  = GTK_TOGGLE_ACTION (menus_get_action ("ViewSnaptoguides"));  
+  show_cx_pts     = GTK_TOGGLE_ACTION (menus_get_action ("ViewShowconnectionpoints"));
+  antialiased     = GTK_TOGGLE_ACTION (menus_get_action ("ViewAntialiased"));
 
   gtk_action_set_sensitive (menus_get_action ("ViewAntialiased"), 
 		            g_type_from_name ("DiaCairoInteractiveRenderer") != 0 || g_type_from_name ("DiaLibartRenderer") != 0);
@@ -1352,6 +1388,10 @@ display_update_menu_state(DDisplay *ddisp)
 				ddisp->grid.visible);
   gtk_toggle_action_set_active (snap_to_grid,
 				ddisp->grid.snap);
+  gtk_toggle_action_set_active (visible_guides,
+				ddisp->guides_visible);
+  gtk_toggle_action_set_active (snap_to_guides,
+				ddisp->guides_snap);
   gtk_toggle_action_set_active (show_cx_pts,
 				ddisp->show_cx_pts); 
 
@@ -1599,6 +1639,9 @@ display_set_active(DDisplay *ddisp)
         /* Object snapping */
         ddisplay_set_snap_to_objects (ddisp, ddisp->mainpoint_magnetism);
 
+        /* Snap to guides */
+        ddisplay_set_snap_to_guides( ddisp, ddisp->guides_snap );
+
         display_update_menu_state (ddisp);
 
         gtk_window_present (GTK_WINDOW(ddisp->shell));
diff --git a/app/display.h b/app/display.h
index 2fef0f0..296b32f 100644
--- a/app/display.h
+++ b/app/display.h
@@ -62,6 +62,7 @@ struct _DDisplay {
   GtkWidget *zoom_status;         
   GtkWidget *grid_status;
   GtkWidget *mainpoint_status;
+  GtkWidget *guide_snap_status;
   GtkWidget *modified_status;
 
   GtkAccelGroup *accel_group;
@@ -75,6 +76,9 @@ struct _DDisplay {
 
   Grid grid;                      /* the grid in this display          */
 
+  gboolean guides_visible;        /* Whether guides are visible. */
+  gboolean guides_snap;           /* Whether to snap to guides. */
+
   gboolean show_cx_pts;		  /* Connection points toggle boolean  */
   gboolean autoscroll;
   gboolean mainpoint_magnetism;   /* Mainpoints snapped from entire obj*/
@@ -110,6 +114,11 @@ struct _DDisplay {
   
   /* Rember the last clicked point per display, but in diagram coordinates */
   Point clicked_position;
+
+  /* For dragging a new guideline. */
+  gboolean is_dragging_new_guideline;
+  gdouble dragged_new_guideline_position;
+  GtkOrientation dragged_new_guideline_orientation;
 };
 
 extern GdkCursor *default_cursor;
@@ -148,6 +157,7 @@ void ddisplay_zoom_middle(DDisplay *ddisp, real magnify);
 
 void ddisplay_zoom_centered(DDisplay *ddisp, Point *point, real magnify);
 void ddisplay_set_snap_to_grid(DDisplay *ddisp, gboolean snap);
+void ddisplay_set_snap_to_guides(DDisplay *ddisp, gboolean snap);
 void ddisplay_set_snap_to_objects(DDisplay *ddisp, gboolean magnetic);
 void ddisplay_set_renderer(DDisplay *ddisp, int aa_renderer);
 void ddisplay_resize_canvas(DDisplay *ddisp,
diff --git a/app/grid.c b/app/grid.c
index 7ac60c0..f2708b6 100644
--- a/app/grid.c
+++ b/app/grid.c
@@ -349,8 +349,118 @@ pagebreak_draw(DDisplay *ddisp, Rectangle *update)
 }
 
 void
+guidelines_draw(DDisplay *ddisp, Rectangle *update)
+{
+
+  Diagram *dia = ddisp->diagram;
+  DiaRenderer *renderer = ddisp->renderer;
+  DiaInteractiveRendererInterface *irenderer;
+  GList *list;
+  real line_width;
+
+  int width = dia_renderer_get_width_pixels(ddisp->renderer);
+  int height = dia_renderer_get_height_pixels(ddisp->renderer);
+
+  Color guideline_color = dia->guide_color;
+
+  if(!dia) {
+    return;
+  }
+
+  /* Make the line width a little bigger than hairline. */
+  line_width = ddisplay_untransform_length(ddisp, 2);
+
+  irenderer = DIA_GET_INTERACTIVE_RENDERER_INTERFACE (renderer);
+
+  DIA_RENDERER_GET_CLASS(renderer)->set_linewidth(renderer, line_width);
+  DIA_RENDERER_GET_CLASS(renderer)->set_linestyle(renderer, LINESTYLE_SOLID, 0.0);
+
+  if(ddisp->guides_visible) {
+    list = dia->guides;
+    while(list) {
+      int x;
+      int y;
+      Guide *guide = list->data;
+
+      switch(guide->orientation) {
+      case GTK_ORIENTATION_HORIZONTAL:
+        ddisplay_transform_coords(ddisp, 0, guide->position, &x, &y);
+        irenderer->draw_pixel_line(renderer, 0, y, width, y, &guideline_color);
+        break;
+
+      case GTK_ORIENTATION_VERTICAL:
+        ddisplay_transform_coords(ddisp, guide->position, 0, &x, &y);
+        irenderer->draw_pixel_line(renderer, x, 0, x, height, &guideline_color);
+        break;
+
+      default:
+        g_print("Should not have reached this.\n");
+        break;
+      }
+
+      list = g_list_next(list);
+    }
+  }
+
+  /* NOTE: We can still drag new guides even if guide visibility
+   * is set to off (like in GIMP). */
+  if( ddisp->is_dragging_new_guideline ) {
+    int x;
+    int y;
+
+    switch(ddisp->dragged_new_guideline_orientation) {
+    case GTK_ORIENTATION_HORIZONTAL:
+      ddisplay_transform_coords(ddisp, 0, ddisp->dragged_new_guideline_position, &x, &y);
+      irenderer->draw_pixel_line(renderer, 0, y, width, y, &guideline_color);
+      break;
+
+    case GTK_ORIENTATION_VERTICAL:
+      ddisplay_transform_coords(ddisp, ddisp->dragged_new_guideline_position, 0, &x, &y);
+      irenderer->draw_pixel_line(renderer, x, 0, x, height, &guideline_color);
+      break;
+
+    default:
+      g_print("Should not have reached this.\n");
+      break;
+    }
+  }
+}
+
+/* For guides. */
+#define  FUNSCALEX(s,x)   ((x) / (s)->zoom_factor)
+#define  FUNSCALEY(s,y)   ((y) / (s)->zoom_factor)
+
+void
 snap_to_grid(DDisplay *ddisp, coord *x, coord *y)
 {
+  /* First snap to guides - only if they are visible and the setting is
+   * turned on. */
+  if(ddisp->guides_snap  &&  ddisp->guides_visible)
+  {
+    Guide *guide_h;
+    Guide *guide_v;
+    const gint snap_distance = prefs.snap_distance;
+
+    guide_h = diagram_pick_guide_h (ddisp->diagram, *x, *y,
+    FUNSCALEX (ddisp, snap_distance),
+    FUNSCALEY (ddisp, snap_distance));
+
+    guide_v = diagram_pick_guide_v (ddisp->diagram, *x, *y,
+    FUNSCALEX (ddisp, snap_distance),
+    FUNSCALEY (ddisp, snap_distance));    
+
+    if(guide_h)
+      *y = guide_h->position;
+      
+    if(guide_v)
+      *x = guide_v->position;
+    
+    /* Assume this takes priority over grid. */
+    if(guide_h  ||  guide_v)
+      return;
+  }
+
+  /* Snap to grid. */
   if (ddisp->grid.snap) {
     if (ddisp->diagram->grid.hex) {
       real width_x = ddisp->diagram->grid.width_w;
diff --git a/app/grid.h b/app/grid.h
index 13a6c71..66ff6d7 100644
--- a/app/grid.h
+++ b/app/grid.h
@@ -32,6 +32,7 @@ struct _Grid {
 
 void grid_draw(DDisplay *ddisp, Rectangle *update);
 void pagebreak_draw(DDisplay *ddisp, Rectangle *update);
+void guidelines_draw(DDisplay *ddisp, Rectangle *update);
 void snap_to_grid(DDisplay *ddisp, coord *x, coord *y);
 
 gboolean grid_step (DDisplay *ddisp, GtkOrientation orientation,
diff --git a/app/guide_tool.c b/app/guide_tool.c
new file mode 100644
index 0000000..2892293
--- /dev/null
+++ b/app/guide_tool.c
@@ -0,0 +1,219 @@
+/* Dia -- an diagram creation/manipulation program
+ * Copyright (C) 1998 Alexander Larsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <config.h>
+
+#include <gdk/gdk.h>
+
+#include "cursor.h"
+#include "guide_tool.h"
+
+#define GUIDE_POSITION_UNDEFINED G_MINDOUBLE
+
+/* The original position of the current guide
+ * before we started dragging it. Need to keep track of it for
+ * undo moving/deleting guides. */
+static real guide_original_pos = 0;
+
+struct _GuideTool {
+  Tool tool;
+
+  Guide *guide;
+  real position;
+  GtkOrientation orientation;
+  int ruler_height;
+};
+
+
+
+static void
+guide_button_release(GuideTool *tool, GdkEventButton *event, DDisplay *ddisp);
+
+static void
+guide_motion(GuideTool *tool, GdkEventMotion *event, DDisplay *ddisp);
+
+
+
+void _guide_tool_start_new (DDisplay *display,
+                            GtkOrientation orientation)
+{
+  _guide_tool_start (display, orientation, NULL);
+}
+
+void _guide_tool_start (DDisplay *display,
+                        GtkOrientation orientation,
+                        Guide *guide)
+{
+  tool_select(GUIDE_TOOL, guide, GINT_TO_POINTER(orientation), NULL, 0);
+  display->dragged_new_guideline_orientation = orientation;
+}
+
+Tool *create_guide_tool(void)
+{
+  GuideTool *tool;
+
+  tool = g_new0(GuideTool, 1);
+  tool->tool.type = GUIDE_TOOL;
+
+  tool->tool.button_release_func = (ButtonReleaseFunc) &guide_button_release;
+  tool->tool.motion_func = (MotionFunc) &guide_motion;
+
+  tool->guide        = NULL;
+  tool->position     = GUIDE_POSITION_UNDEFINED;
+  tool->orientation  = GTK_ORIENTATION_HORIZONTAL;  /* Default. */
+
+  return (Tool *)tool;
+}
+
+void free_guide_tool(Tool *tool)
+{
+  GuideTool *gtool = (GuideTool *)tool;
+  g_free(gtool);
+}
+
+static void
+guide_button_release(GuideTool *tool, GdkEventButton *event,
+                     DDisplay *ddisp)
+{
+  /* Reset. */
+  ddisp->is_dragging_new_guideline = FALSE;
+
+  if (tool->position == GUIDE_POSITION_UNDEFINED)    
+  {
+    /* Dragged out of bounds, so remove the guide. */
+    if (tool->guide) {
+      tool->guide->position = guide_original_pos; /* So that when we undo, it goes back to original position. */
+      diagram_remove_guide (ddisp->diagram, tool->guide, TRUE);
+      tool->guide = NULL;
+    }
+  }
+  else
+  {
+    if (!tool->guide) {
+      /* Add a new guide. */
+      diagram_add_guide (ddisp->diagram, tool->position, tool->orientation, TRUE);
+    }
+    else
+    {
+      /* Moved an existing guide, so update the undo stack. */
+      undo_move_guide(ddisp->diagram, tool->guide, guide_original_pos, tool->position);
+      undo_set_transactionpoint(ddisp->diagram->undo);
+    }
+  }
+
+  diagram_add_update_all(ddisp->diagram);
+  diagram_modified(ddisp->diagram);  
+  diagram_flush(ddisp->diagram);
+
+  tool_reset();
+}
+
+static void
+guide_motion(GuideTool *tool, GdkEventMotion *event, DDisplay *ddisp)
+{
+  gint tx, ty;
+  Point to;
+  gint disp_width;
+  gint disp_height;
+
+  disp_width = dia_renderer_get_width_pixels(ddisp->renderer);
+  disp_height = dia_renderer_get_height_pixels(ddisp->renderer);
+
+  /* Event coordinates. */
+  tx = event->x;
+  ty = event->y;
+  
+  /* Minus ruler height. */
+  if (tool->orientation == GTK_ORIENTATION_HORIZONTAL)  
+    ty -= tool->ruler_height;
+  else
+    tx -= tool->ruler_height;
+
+  /* Diagram coordinates. */
+  ddisplay_untransform_coords(ddisp, tx, ty, &to.x, &to.y);
+
+  if (tx < 0 || tx >= disp_width ||
+      ty < 0 || ty >= disp_height)
+  {
+    /* Out of bounds. */
+    tool->position = GUIDE_POSITION_UNDEFINED;
+
+    /* Cancel dragging a new guide. */
+    ddisp->is_dragging_new_guideline = FALSE;
+    ddisp->dragged_new_guideline_position = 0;
+
+    if(tool->guide)
+    {
+      /* Deleting an existing guide. Hide it for now. */
+      tool->guide->position = G_MAXDOUBLE;
+    }
+  }
+  else
+  {
+    /* In bounds - add or move a guide. */
+    if (tool->orientation == GTK_ORIENTATION_HORIZONTAL)
+      tool->position = to.y;
+    else
+      tool->position = to.x;
+
+    if(tool->guide)
+    {
+      /* Move existing guide. */
+      tool->guide->position = tool->position;
+    }
+    else
+    {
+      /* Add new guide. */
+      ddisp->is_dragging_new_guideline = TRUE;
+      ddisp->dragged_new_guideline_position = tool->position;
+    }
+  }
+
+  diagram_add_update_all(ddisp->diagram);
+  diagram_modified(ddisp->diagram);
+  ddisplay_flush(ddisp);
+}
+
+void guide_tool_set_ruler_height(Tool *tool, int height)
+{
+  GuideTool *gtool = (GuideTool *)tool;
+  gtool->ruler_height = height;
+}
+
+void guide_tool_start_edit (DDisplay *display,
+                            Guide *guide)
+{
+  _guide_tool_start (display, guide->orientation, guide);
+
+  if(guide)
+  {
+    /* Store original position for undo stack. */
+    guide_original_pos = guide->position;
+  }
+}
+
+void guide_tool_set_guide(Tool *tool, Guide *guide)
+{
+  GuideTool *gtool = (GuideTool *)tool;
+  gtool->guide = guide;
+}
+
+void guide_tool_set_orientation(Tool *tool, GtkOrientation orientation)
+{
+  GuideTool *gtool = (GuideTool *)tool;
+  gtool->orientation = orientation;
+}
diff --git a/app/guide_tool.h b/app/guide_tool.h
new file mode 100644
index 0000000..1e00351
--- /dev/null
+++ b/app/guide_tool.h
@@ -0,0 +1,54 @@
+/* Dia -- an diagram creation/manipulation program
+ * Copyright (C) 1998 Alexander Larsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#ifndef GUIDE_TOOL_H
+#define GUIDE_TOOL_H
+
+#include "guide.h"
+#include "tool.h"
+
+typedef struct _GuideTool GuideTool;
+
+Tool *create_guide_tool(void);
+void free_guide_tool(Tool *tool);
+
+/** Start dragging a new guide. */
+void _guide_tool_start_new (DDisplay *display,
+                            GtkOrientation orientation);
+
+/** Start editing (i.e. moving) an existing guide. */
+void guide_tool_start_edit (DDisplay *display,
+                            Guide *guide);
+
+/** Start using the guide tool.
+ *  If guide is not NULL, then start editing that guide.
+ *  If guide is NULL, then start adding a new guide. */
+void _guide_tool_start (DDisplay *display,
+                        GtkOrientation orientation,
+                        Guide *guide);
+
+/** Inform the tool of the ruler height. Required to calculate
+ *  the position of the guide on the page. */
+void guide_tool_set_ruler_height(Tool *tool, int height);
+
+/** Set the guide to edit. */
+void guide_tool_set_guide(Tool *tool, Guide *guide);
+
+/** Set the orientation of the tool. */
+void guide_tool_set_orientation(Tool *tool, GtkOrientation orientation);
+
+#endif /* GUIDE_TOOL_H */
diff --git a/app/interface.c b/app/interface.c
index 4f97d43..5a9e48b 100644
--- a/app/interface.c
+++ b/app/interface.c
@@ -52,6 +52,35 @@
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include "dia-app-icons.h"
 
+#include "guide_tool.h"
+
+#include <glib/gprintf.h>
+
+static gboolean _ddisplay_hruler_button_press (GtkWidget *widget,
+        GdkEventButton *bevent,
+        DDisplay *ddisp);
+
+static gboolean _ddisplay_vruler_button_press (GtkWidget *widget,
+        GdkEventButton *bevent,
+        DDisplay *ddisp);
+
+static gboolean _ddisplay_ruler_button_press (GtkWidget *widget,
+        GdkEventButton *event,
+        DDisplay *ddisp,
+        GtkOrientation orientation);
+
+static gboolean _ddisplay_ruler_button_release (GtkWidget *widget,
+        GdkEventButton *bevent,
+        DDisplay *ddisp);
+        
+static gboolean _ddisplay_hruler_motion_notify (GtkWidget *widget,
+        GdkEventMotion *event,
+        DDisplay *ddisp);
+
+static gboolean _ddisplay_vruler_motion_notify (GtkWidget *widget,
+        GdkEventMotion *event,
+        DDisplay *ddisp);
+
 static void
 dia_dnd_file_drag_data_received (GtkWidget        *widget,
                                  GdkDragContext   *context,
@@ -160,6 +189,16 @@ interface_toggle_mainpoint_magnetism(GtkWidget *widget, gpointer data)
   ddisplay_flush(ddisp);
 }
 
+static void
+interface_toggle_snap_to_guides(GtkWidget *widget, gpointer data)
+{
+  DDisplay *ddisp = (DDisplay *)data;
+  ddisplay_set_snap_to_guides(ddisp,
+				   gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
+  ddisplay_add_update_all(ddisp);
+  ddisplay_flush(ddisp);
+}
+
 static gint
 origin_button_press(GtkWidget *widget, GdkEventButton *event, gpointer data)
 {
@@ -452,6 +491,32 @@ _ddisplay_setup_rulers (DDisplay *ddisp, GtkWidget *shell, GtkWidget *table)
   ddisp->hrule = dia_ruler_new (GTK_ORIENTATION_HORIZONTAL, shell, ddisp);
   ddisp->vrule = dia_ruler_new (GTK_ORIENTATION_VERTICAL, shell, ddisp);
 
+  /* Callbacks for adding guides - horizontal ruler. */
+  g_signal_connect (ddisp->hrule, "button-press-event",
+                    G_CALLBACK (_ddisplay_hruler_button_press),
+                    ddisp);
+
+  g_signal_connect (ddisp->hrule, "button_release_event",
+                    G_CALLBACK (_ddisplay_ruler_button_release),
+                    ddisp);
+
+  g_signal_connect (ddisp->hrule, "motion_notify_event",
+                    G_CALLBACK (_ddisplay_hruler_motion_notify),
+                    ddisp);
+
+  /* Callbacks for adding guides - vertical ruler. */
+  g_signal_connect (ddisp->vrule, "button-press-event",
+                    G_CALLBACK (_ddisplay_vruler_button_press),
+                    ddisp);
+
+  g_signal_connect (ddisp->vrule, "button_release_event",
+                    G_CALLBACK (_ddisplay_ruler_button_release),
+                    ddisp);
+
+  g_signal_connect (ddisp->vrule, "motion_notify_event",
+                    G_CALLBACK (_ddisplay_vruler_motion_notify),
+                    ddisp);
+
   /* harder to change position in the table, but we did not do it for years ;) */
   gtk_table_attach (GTK_TABLE (table), ddisp->hrule, 1, 2, 0, 1,
                     GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_FILL, 0, 0);
@@ -642,6 +707,7 @@ use_integrated_ui_for_display_shell(DDisplay *ddisp, char *title)
 
   integrated_ui_toolbar_grid_snap_synchronize_to_display (ddisp);
   integrated_ui_toolbar_object_snap_synchronize_to_display (ddisp);
+  integrated_ui_toolbar_guides_snap_synchronize_to_display (ddisp);
 
   /*  set the focus to the canvas area  */
   gtk_widget_grab_focus (ddisp->canvas);
@@ -804,6 +870,16 @@ create_display_shell(DDisplay *ddisp,
   gtk_box_pack_start (GTK_BOX (status_hbox), ddisp->mainpoint_status,
 		      FALSE, FALSE, 0);
 
+  ddisp->guide_snap_status = dia_toggle_button_new_with_icons(dia_guide_snap_on_icon,
+                            dia_guide_snap_off_icon);
+
+  g_signal_connect(G_OBJECT(ddisp->guide_snap_status), "toggled",
+           G_CALLBACK (interface_toggle_snap_to_guides), ddisp);
+  gtk_widget_set_tooltip_text(ddisp->guide_snap_status,
+               _("Toggles snap-to-guides for this window."));
+  gtk_box_pack_start (GTK_BOX (status_hbox), ddisp->guide_snap_status,
+              FALSE, FALSE, 0);
+
 
   /* Statusbar */
   ddisp->modified_status = gtk_statusbar_new ();
@@ -1255,3 +1331,94 @@ integrated_ui_statusbar_show (gboolean show)
       gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), show);
   }
 }
+
+static gboolean
+_ddisplay_hruler_button_press (GtkWidget *widget,
+                               GdkEventButton *event,
+                               DDisplay *ddisp)
+{
+  return _ddisplay_ruler_button_press (widget, event, ddisp,
+                                       GTK_ORIENTATION_HORIZONTAL);
+}
+
+static gboolean
+_ddisplay_vruler_button_press (GtkWidget *widget,
+                               GdkEventButton *event,
+                               DDisplay *ddisp)
+{
+  return _ddisplay_ruler_button_press (widget, event, ddisp,
+                                       GTK_ORIENTATION_VERTICAL);
+}
+
+static gboolean
+_ddisplay_ruler_button_press (GtkWidget *widget,
+                              GdkEventButton *event,
+                              DDisplay *ddisp,
+                              GtkOrientation orientation)
+{
+  /* Start adding a new guide if the left button was pressed. */
+  if (event->type == GDK_BUTTON_PRESS && event->button == 1) {
+      _guide_tool_start_new (ddisp, orientation);
+  }
+
+  return FALSE;
+}
+
+static gboolean
+_ddisplay_ruler_button_release (GtkWidget *widget,
+                                 GdkEventButton *event,
+                                 DDisplay *ddisp)
+{
+  /* Hack to get this triggered. */  
+  if(active_tool->type == GUIDE_TOOL)
+  {
+    if (active_tool->button_release_func)
+    {
+      (*active_tool->button_release_func) (active_tool, event, ddisp);
+    }
+  }
+  
+  return FALSE;
+}
+
+static gboolean _ddisplay_hruler_motion_notify (GtkWidget *widget,
+    GdkEventMotion *event,
+    DDisplay *ddisp)
+{
+  /* Hack to get this triggered. */
+  if(active_tool->type == GUIDE_TOOL) {
+    if (active_tool->motion_func) {
+
+      /* Minus ruler height. */
+      GtkRequisition ruler_requisition;
+      gtk_widget_size_request (widget, &ruler_requisition);
+      guide_tool_set_ruler_height(active_tool, ruler_requisition.height);
+
+      /* Do the move. */
+      (*active_tool->motion_func) (active_tool, event, ddisp);
+    }
+  }
+
+  return FALSE;
+}
+
+static gboolean _ddisplay_vruler_motion_notify (GtkWidget *widget,
+    GdkEventMotion *event,
+    DDisplay *ddisp)
+{
+  /* Hack to get this triggered. */
+  if(active_tool->type == GUIDE_TOOL) {
+    if (active_tool->motion_func) {
+
+      /* Minus ruler width. */
+      GtkRequisition ruler_requisition;
+      gtk_widget_size_request (widget, &ruler_requisition);
+      guide_tool_set_ruler_height(active_tool, ruler_requisition.width);
+
+      /* Do the move. */
+      (*active_tool->motion_func) (active_tool, event, ddisp);
+    }
+  }
+
+  return FALSE;
+}
diff --git a/app/load_save.c b/app/load_save.c
index a41e028..d54db37 100644
--- a/app/load_save.c
+++ b/app/load_save.c
@@ -376,7 +376,7 @@ diagram_data_load(const gchar *filename, DiagramData *data, DiaContext *ctx, voi
   xmlDocPtr doc;
   xmlNodePtr root;
   xmlNodePtr diagramdata;
-  xmlNodePtr paperinfo, gridinfo, guideinfo;
+  xmlNodePtr paperinfo, gridinfo;
   xmlNodePtr layer_node;
   AttributeNode attr;
   Layer *layer;
@@ -566,32 +566,40 @@ diagram_data_load(const gchar *filename, DiagramData *data, DiaContext *ctx, voi
   if (diagram) {
     attr = composite_find_attribute(diagramdata, "guides");
     if (attr != NULL) {
-      guint i;
-      DataNode guide;
+      DataNode guides_data;
 
-      guideinfo = attribute_first_data(attr);
+      /* Clear old guides. */
+      g_list_free(diagram->guides);
+      diagram->guides = NULL;
 
-      attr = composite_find_attribute(guideinfo, "hguides");
-      if (attr != NULL) {
-        diagram->guides.nhguides = attribute_num_data(attr);
-        g_free(diagram->guides.hguides);
-        diagram->guides.hguides = g_new(real, diagram->guides.nhguides);
-    
-        guide = attribute_first_data(attr);
-        for (i = 0; i < diagram->guides.nhguides; i++, guide = data_next(guide))
-	  diagram->guides.hguides[i] = data_real(guide, ctx);
-      }
-      attr = composite_find_attribute(guideinfo, "vguides");
-      if (attr != NULL) {
-        diagram->guides.nvguides = attribute_num_data(attr);
-        g_free(diagram->guides.vguides);
-        diagram->guides.vguides = g_new(real, diagram->guides.nvguides);
-    
-        guide = attribute_first_data(attr);
-        for (i = 0; i < diagram->guides.nvguides; i++, guide = data_next(guide))
-	  diagram->guides.vguides[i] = data_real(guide, ctx);
+      /* Load new guides. */
+      guides_data = attribute_first_data(attr);
+      while (guides_data) {
+
+        real position = 0;
+        GtkOrientation orientation = GTK_ORIENTATION_HORIZONTAL;
+
+        attr = composite_find_attribute(guides_data, "position");
+        if(attr != NULL) {
+          position = data_real(attribute_first_data(attr), ctx);
+        }
+
+        attr = composite_find_attribute(guides_data, "orientation");
+        if(attr != NULL) {
+          orientation = data_int(attribute_first_data(attr), ctx);
+        }
+
+        diagram_add_guide (diagram, position, orientation, FALSE);
+
+        guides_data = data_next(guides_data);
       }
     }
+
+    /* Guide color. */
+    diagram->guide_color = prefs.new_diagram.guide_color;
+    attr = composite_find_attribute(diagramdata, "guide_color");
+    if (attr != NULL)
+      data_color(attribute_first_data(attr), &diagram->guide_color, ctx);
   }
   /* parse some display settings */
   if (diagram) {
@@ -613,6 +621,11 @@ diagram_data_load(const gchar *filename, DiagramData *data, DiaContext *ctx, voi
 	g_object_set_data(G_OBJECT(diagram), 
 	  "snap-to-grid", GINT_TO_POINTER (data_boolean(attribute_first_data(attr), ctx) ? 1 : -1));
 
+      attr = composite_find_attribute(dispinfo, "snap-to-guides");
+      if (attr != NULL)
+	g_object_set_data(G_OBJECT(diagram),
+	  "snap-to-guides", GINT_TO_POINTER (data_boolean(attribute_first_data(attr), ctx) ? 1 : -1));
+
       attr = composite_find_attribute(dispinfo, "snap-to-object");
       if (attr != NULL)
         g_object_set_data(G_OBJECT(diagram), 
@@ -623,6 +636,11 @@ diagram_data_load(const gchar *filename, DiagramData *data, DiaContext *ctx, voi
         g_object_set_data(G_OBJECT(diagram), 
 	  "show-grid", GINT_TO_POINTER (data_boolean(attribute_first_data(attr), ctx) ? 1 : -1));
 
+      attr = composite_find_attribute(dispinfo, "show-guides");
+      if (attr != NULL)
+        g_object_set_data(G_OBJECT(diagram),
+	  "show-guides", GINT_TO_POINTER (data_boolean(attribute_first_data(attr), ctx) ? 1 : -1));
+
       attr = composite_find_attribute(dispinfo, "show-connection-points");
       if (attr != NULL)
         g_object_set_data(G_OBJECT(diagram), 
@@ -922,6 +940,7 @@ diagram_data_write_doc(DiagramData *data, const char *filename, DiaContext *ctx)
   }
 
   if (diagram) {
+    GList *list;
     attr = new_attribute((ObjectNode)tree, "grid");
     gridinfo = data_add_composite(attr, "grid", ctx);
     data_add_boolean(composite_add_attribute(gridinfo, "dynamic"),
@@ -937,15 +956,26 @@ diagram_data_write_doc(DiagramData *data, const char *filename, DiaContext *ctx)
     attr = new_attribute((ObjectNode)tree, "color");
     data_add_composite(gridinfo, "color", ctx);
     data_add_color(attr, &diagram->grid.colour, ctx);
-  
+
+    /* Guides. */
     attr = new_attribute((ObjectNode)tree, "guides");
-    guideinfo = data_add_composite(attr, "guides", ctx);
-    attr = composite_add_attribute(guideinfo, "hguides");
-    for (i = 0; i < diagram->guides.nhguides; i++)
-      data_add_real(attr, diagram->guides.hguides[i], ctx);
-    attr = composite_add_attribute(guideinfo, "vguides");
-    for (i = 0; i < diagram->guides.nvguides; i++)
-      data_add_real(attr, diagram->guides.vguides[i], ctx);
+
+    list = diagram->guides;
+    while(list) {
+      Guide *guide = list->data;
+      
+      guideinfo = data_add_composite(attr, "guide", ctx);
+      
+      data_add_real(composite_add_attribute(guideinfo, "position"), guide->position, ctx);
+      data_add_int(composite_add_attribute(guideinfo, "orientation"), guide->orientation, ctx);
+
+      list = g_list_next(list);
+    }
+    
+    if (diagram) {
+      attr = new_attribute((ObjectNode)tree, "guide_color");
+      data_add_color(attr, &diagram->guide_color, ctx);
+    }
 
     if (g_slist_length(diagram->displays) == 1) {
       xmlNodePtr dispinfo;
@@ -958,10 +988,14 @@ diagram_data_write_doc(DiagramData *data, const char *filename, DiaContext *ctx)
                        ddisp->aa_renderer, ctx);
       data_add_boolean(composite_add_attribute(dispinfo, "snap-to-grid"),
 		       ddisp->grid.snap, ctx);
+      data_add_boolean(composite_add_attribute(dispinfo, "snap-to-guides"),
+		       ddisp->guides_snap, ctx);
       data_add_boolean(composite_add_attribute(dispinfo, "snap-to-object"),
 		       ddisp->mainpoint_magnetism, ctx);
       data_add_boolean(composite_add_attribute(dispinfo, "show-grid"),
 		       ddisp->grid.visible, ctx);
+      data_add_boolean(composite_add_attribute(dispinfo, "show-guides"),
+		       ddisp->guides_visible, ctx);
       data_add_boolean(composite_add_attribute(dispinfo, "show-connection-points"),
 		       ddisp->show_cx_pts, ctx);
     }
diff --git a/app/menus.c b/app/menus.c
index b39bb73..c8e94b6 100644
--- a/app/menus.c
+++ b/app/menus.c
@@ -60,6 +60,7 @@
 #define DIA_INTEGRATED_TOOLBAR_ZOOM_COMBO  "dia-integrated-toolbar-zoom-combo_entry"
 #define DIA_INTEGRATED_TOOLBAR_SNAP_GRID   "dia-integrated-toolbar-snap-grid"
 #define DIA_INTEGRATED_TOOLBAR_OBJECT_SNAP "dia-integrated-toolbar-object-snap"
+#define DIA_INTEGRATED_TOOLBAR_GUIDES_SNAP "dia-integrated-toolbar-guides-snap"
 
 #define ZOOM_FIT        _("Fit")
 
@@ -176,6 +177,8 @@ static const GtkActionEntry display_entries[] =
     { "ViewCloneview", NULL, N_("C_lone View"), NULL, NULL, G_CALLBACK (view_clone_view_callback) },
     { "ViewRedraw", GTK_STOCK_REFRESH, NULL, NULL, NULL, G_CALLBACK (view_redraw_callback) },
 
+    { "ViewNewguide", NULL, N_("New Guide..."), NULL, NULL, G_CALLBACK (view_new_guide_callback) },
+
   { "Objects", NULL, N_("_Objects"), NULL, NULL },
     { "ObjectsSendtoback", GTK_STOCK_GOTO_BOTTOM, N_("Send to _Back"), FIRST_MODIFIER "<shift>B", N_("Move selection to the bottom"), G_CALLBACK (objects_place_under_callback) },
     { "ObjectsBringtofront", GTK_STOCK_GOTO_TOP, N_("Bring to _Front"), FIRST_MODIFIER "<shift>F", N_("Move selection to the top"), G_CALLBACK (objects_place_over_callback) },
@@ -259,6 +262,10 @@ static const GtkToggleActionEntry display_toggle_entries[] =
     { "ViewAntialiased", NULL, N_("_Antialiased"), NULL, NULL, G_CALLBACK (view_aa_callback) },
     { "ViewShowgrid", NULL, N_("Show _Grid"), NULL, NULL, G_CALLBACK (view_visible_grid_callback) },
     { "ViewSnaptogrid", NULL, N_("_Snap to Grid"), NULL, NULL, G_CALLBACK (view_snap_to_grid_callback) },
+    { "ViewGuides", NULL, N_("Guides"), NULL, NULL, NULL },
+      { "ViewShowguides", NULL, N_("Show Guides"), NULL, NULL, G_CALLBACK (view_visible_guides_callback) },
+      { "ViewSnaptoguides", NULL, N_("Snap to Guides"), NULL, NULL, G_CALLBACK (view_snap_to_guides_callback) },
+      { "ViewRemoveallguides", NULL, N_("Remove all Guides"), NULL, NULL, G_CALLBACK (view_remove_all_guides_callback) },
     { "ViewSnaptoobjects", NULL, N_("Snap to _Objects"), NULL, NULL, G_CALLBACK (view_snap_to_objects_callback) },
     { "ViewShowrulers", NULL, N_("Show _Rulers"), NULL, NULL, G_CALLBACK (view_toggle_rulers_callback)  },
     { "ViewShowscrollbars", NULL, N_("Show Scrollbars"), NULL, N_("Show or hide the toolbar"), G_CALLBACK (view_toggle_scrollbars_callback) },
@@ -385,6 +392,23 @@ integrated_ui_toolbar_object_snap_synchronize_to_display(gpointer param)
 }
 
 /**
+ * Synchronized the snap-to-guide property button with the display.
+ * @param param Display to synchronize to.
+ */
+void
+integrated_ui_toolbar_guides_snap_synchronize_to_display(gpointer param)
+{
+  DDisplay *ddisp = param;
+  if (ddisp && ddisp->common_toolbar)
+  {
+    GtkToggleButton *b = g_object_get_data (G_OBJECT (ddisp->common_toolbar), 
+                                            DIA_INTEGRATED_TOOLBAR_GUIDES_SNAP);
+    gboolean active = ddisp->guides_snap? TRUE : FALSE;
+    gtk_toggle_button_set_active (b, active);
+  }
+}
+
+/**
  * Sets the Object-snap property for the active display.
  * @param b Object snap toggle button.
  * @param not_used
@@ -400,6 +424,21 @@ integrated_ui_toolbar_object_snap_toggle(GtkToggleButton *b, gpointer *not_used)
 }
 
 /**
+ * Sets the Guide-snap property for the active display.
+ * @param b Guide snap toggle button.
+ * @param not_used
+ */
+static void
+integrated_ui_toolbar_guide_snap_toggle(GtkToggleButton *b, gpointer *not_used)
+{
+  DDisplay *ddisp = ddisplay_active ();
+  if (ddisp)
+  {
+    ddisplay_set_snap_to_guides (ddisp, gtk_toggle_button_get_active (b));
+  }
+}
+
+/**
  * Synchronizes the Snap-to-grid property button with the display.
  * @param param Display to synchronize to.
  */
@@ -658,6 +697,17 @@ create_integrated_ui_toolbar (void)
                      w);
   integrated_ui_toolbar_add_custom_item (toolbar, w);
 
+  /* Guide Snapping */
+  w = dia_toggle_button_new_with_icons (dia_guide_snap_on_icon,
+                                        dia_guide_snap_off_icon);
+  g_signal_connect (G_OBJECT (w), "toggled",
+		   G_CALLBACK (integrated_ui_toolbar_guide_snap_toggle), toolbar);
+  gtk_widget_set_tooltip_text (w, _("Toggles guide snapping."));
+  g_object_set_data (G_OBJECT (toolbar), 
+                     DIA_INTEGRATED_TOOLBAR_GUIDES_SNAP,
+                     w);
+  integrated_ui_toolbar_add_custom_item (toolbar, w);
+
   sep = gtk_separator_tool_item_new ();
   gtk_toolbar_insert (toolbar, sep, -1);
   gtk_widget_show (GTK_WIDGET (sep));
diff --git a/app/menus.h b/app/menus.h
index d300bc6..68f0b9f 100644
--- a/app/menus.h
+++ b/app/menus.h
@@ -38,6 +38,9 @@ integrated_ui_toolbar_grid_snap_synchronize_to_display (gpointer ddisp);
 void
 integrated_ui_toolbar_object_snap_synchronize_to_display (gpointer ddisp);
 
+void
+integrated_ui_toolbar_guides_snap_synchronize_to_display (gpointer ddisp);
+
 /* TODO: rename: menus_get_integrated_ui_menubar() */
 void            menus_get_integrated_ui_menubar  (GtkWidget **menubar, GtkWidget **toolbar, 
                                                   GtkAccelGroup **accel);
diff --git a/app/modify_tool.c b/app/modify_tool.c
index a7f9678..f709fc8 100644
--- a/app/modify_tool.c
+++ b/app/modify_tool.c
@@ -40,6 +40,8 @@
 #include "prop_text.h"
 #include "object.h"
 
+#include "guide_tool.h"
+
 
 static DiaObject *click_select_object(DDisplay *ddisp, Point *clickedpoint,
 				   GdkEventButton *event);
@@ -77,6 +79,9 @@ struct _ModifyTool {
                              modify_motion was called */
   /* Undo info: */
   Point *orig_pos;
+
+  /* Guide info: */  
+  Guide *guide;
 };
 
 
@@ -255,6 +260,9 @@ static int do_if_clicked_handle(DDisplay *ddisp, ModifyTool *tool,
   return FALSE;
 }
 
+#define  FUNSCALEX(s,x)   ((x) / (s)->zoom_factor)
+#define  FUNSCALEY(s,y)   ((y) / (s)->zoom_factor)
+
 static void
 modify_button_press(ModifyTool *tool, GdkEventButton *event,
 		     DDisplay *ddisp)
@@ -262,11 +270,15 @@ modify_button_press(ModifyTool *tool, GdkEventButton *event,
   Point clickedpoint;
   DiaObject *clicked_obj;
   gboolean some_selected;
+  Guide *guide;
+  const gint pick_guide_snap_distance = 20;	/* Margin of error for selecting a guide. */
 
   ddisplay_untransform_coords(ddisp,
 			      (int)event->x, (int)event->y,
 			      &clickedpoint.x, &clickedpoint.y);
 
+  tool->guide = NULL;
+
   /* don't got to single handle movement if there is more than one object selected */
   some_selected = g_list_length (ddisp->diagram->data->selected) > 1;
   if (!some_selected && do_if_clicked_handle(ddisp, tool, &clickedpoint, event))
@@ -290,6 +302,23 @@ modify_button_press(ModifyTool *tool, GdkEventButton *event,
     tool->start_time = time_micro();
     ddisplay_set_all_cursor(get_cursor(CURSOR_SCROLL));
   } else {
+
+    /* If there is a guide nearby, then drag it.
+     * Note: We can only drag guides if they are visible (like in GIMP). */
+    if(ddisp->guides_visible)
+    {
+      guide = diagram_pick_guide (ddisp->diagram, clickedpoint.x, clickedpoint.y,
+      FUNSCALEX (ddisp, pick_guide_snap_distance ),
+      FUNSCALEY (ddisp, pick_guide_snap_distance ));
+
+      if(guide) {
+        tool->guide = guide;
+        guide_tool_start_edit (ddisp, guide);
+        return;
+      }
+    }
+    
+    /* Box select. */
     tool->state = STATE_BOX_SELECT;
     tool->start_box = clickedpoint;
     tool->end_box = clickedpoint;
diff --git a/app/new_guide_dialog.c b/app/new_guide_dialog.c
new file mode 100644
index 0000000..3f15dc0
--- /dev/null
+++ b/app/new_guide_dialog.c
@@ -0,0 +1,149 @@
+/* Dia -- an diagram creation/manipulation program
+ * Copyright (C) 1998 Alexander Larsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "intl.h"
+#include "new_guide_dialog.h"
+#include "object_ops.h"
+#include "object.h"
+#include "connectionpoint_ops.h"
+#include "undo.h"
+#include "message.h"
+#include "properties.h"
+#include "diaoptionmenu.h"
+
+static GtkWidget *dialog = NULL;
+static GtkWidget *position_entry, *orientation_menu;
+static Diagram *current_diagram = NULL;
+
+static void
+diagram_new_guide_respond(GtkWidget *widget,
+                         gint       response_id,
+                         gpointer   user_data)
+{
+  if (response_id == GTK_RESPONSE_OK) {
+    real position = gtk_spin_button_get_value( GTK_SPIN_BUTTON(position_entry) );
+    int orientation = dia_option_menu_get_active(orientation_menu);
+    diagram_add_guide(current_diagram, position, orientation, TRUE);
+  }
+
+  /* Hide the dialog if "OK" or "Cancel" were clicked. */
+  if (response_id != GTK_RESPONSE_APPLY)
+    gtk_widget_hide(dialog);
+}
+
+static void
+create_new_guide_dialog(Diagram *dia)
+{
+  GtkWidget *dialog_vbox;
+  GtkWidget *label;
+  GtkAdjustment *adj;
+  GtkWidget *table;
+  const gdouble UPPER_LIMIT = G_MAXDOUBLE;
+  
+  current_diagram = dia;
+
+  dialog = gtk_dialog_new_with_buttons(
+             _("Add New Guide"),
+             GTK_WINDOW(ddisplay_active()->shell),
+             GTK_DIALOG_DESTROY_WITH_PARENT,
+             GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL,
+             GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
+             GTK_STOCK_OK, GTK_RESPONSE_OK,
+             NULL);
+
+  gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_OK);
+
+  dialog_vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+
+  gtk_window_set_role(GTK_WINDOW(dialog), "new_guide");
+
+  g_signal_connect(G_OBJECT(dialog), "response",
+		   G_CALLBACK(diagram_new_guide_respond), NULL);
+
+  g_signal_connect(G_OBJECT(dialog), "delete_event",
+		   G_CALLBACK(gtk_widget_hide), NULL);
+  g_signal_connect(G_OBJECT(dialog), "destroy",
+		   G_CALLBACK(gtk_widget_destroyed), &dialog);
+
+  table = gtk_table_new(3,3,FALSE);
+  gtk_container_set_border_width(GTK_CONTAINER(table), 2);
+  gtk_table_set_row_spacings(GTK_TABLE(table), 1);
+  gtk_table_set_col_spacings(GTK_TABLE(table), 2);
+
+  label = gtk_label_new(_("Orientation: "));
+  gtk_table_attach(GTK_TABLE(table), label, 0,1, 0,1,
+		   GTK_FILL, GTK_FILL, 0, 0);
+  gtk_widget_show(label);
+
+  orientation_menu = dia_option_menu_new();
+  gtk_table_attach(GTK_TABLE(table), orientation_menu, 1,2, 0,1,
+		   GTK_FILL, GTK_FILL, 0, 0);
+  dia_option_menu_add_item (orientation_menu, "Horizontal", GTK_ORIENTATION_HORIZONTAL);
+  dia_option_menu_add_item (orientation_menu, "Vertical", GTK_ORIENTATION_VERTICAL);
+  dia_option_menu_set_active (orientation_menu, GTK_ORIENTATION_HORIZONTAL);
+  gtk_widget_show(orientation_menu);
+
+  label = gtk_label_new(_("Position: "));
+  gtk_table_attach(GTK_TABLE(table), label, 0,1, 1,2,
+		   GTK_FILL, GTK_FILL, 0, 0);
+  gtk_widget_show(label);
+
+  adj = GTK_ADJUSTMENT(gtk_adjustment_new(1.0, 0.0, UPPER_LIMIT, 0.1, 10.0, 0));
+  position_entry = gtk_spin_button_new(adj, 1.0, 3);
+  gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(position_entry), TRUE);
+  gtk_table_attach(GTK_TABLE(table), position_entry, 1,2, 1,2,
+		   GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0);
+  gtk_widget_show(position_entry);
+
+  gtk_widget_show(table);
+
+  gtk_box_pack_start(GTK_BOX(dialog_vbox), table, TRUE, TRUE, 0);
+  gtk_widget_show(dialog_vbox);
+}
+
+void
+dialog_new_guide_show(void)
+{
+  Diagram *dia;
+  dia = ddisplay_active_diagram();
+  
+  if(!dia)
+    return;
+
+  if (dialog) {
+    /* This makes the dialog a child of the newer diagram */
+    gtk_widget_destroy(dialog);
+    dialog = NULL;
+  }
+
+  create_new_guide_dialog(dia);
+
+  gtk_window_set_transient_for(GTK_WINDOW(dialog),
+			       GTK_WINDOW (ddisplay_active()->shell));
+  gtk_widget_show(dialog);
+}
diff --git a/app/new_guide_dialog.h b/app/new_guide_dialog.h
new file mode 100644
index 0000000..e8799b7
--- /dev/null
+++ b/app/new_guide_dialog.h
@@ -0,0 +1,26 @@
+/* Dia -- an diagram creation/manipulation program
+ * Copyright (C) 1998 Alexander Larsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#ifndef NEW_GUIDE_DIALOG_H
+#define NEW_GUIDE_DIALOG_H
+
+#include "diatypes.h"
+#include "diagram.h"
+
+void dialog_new_guide_show (void);
+
+#endif /* NEW_GUIDE_DIALOG_H */
diff --git a/app/pixmaps/Makefile.am b/app/pixmaps/Makefile.am
index 179367d..0fd6c05 100644
--- a/app/pixmaps/Makefile.am
+++ b/app/pixmaps/Makefile.am
@@ -8,6 +8,8 @@ IMAGES = \
 	on-grid.png \
 	off-grid.png \
 	visible.png \
-	visible-empty.png
+	visible-empty.png \
+	guide-snap-on.png \
+	guide-snap-off.png
 
 EXTRA_DIST = $(IMAGES)
diff --git a/app/pixmaps/guide-snap-off.png b/app/pixmaps/guide-snap-off.png
new file mode 100644
index 0000000..fd4147f
Binary files /dev/null and b/app/pixmaps/guide-snap-off.png differ
diff --git a/app/pixmaps/guide-snap-on.png b/app/pixmaps/guide-snap-on.png
new file mode 100644
index 0000000..969c83a
Binary files /dev/null and b/app/pixmaps/guide-snap-on.png differ
diff --git a/app/preferences.c b/app/preferences.c
index c45cd38..9b207b4 100644
--- a/app/preferences.c
+++ b/app/preferences.c
@@ -93,9 +93,11 @@ static int default_undo_depth = 15;
 static guint default_recent_documents = 5;
 static Color default_colour = DEFAULT_GRID_COLOR;
 static Color pbreak_colour = DEFAULT_PAGEBREAK_COLOR;
+static Color guide_colour = DEFAULT_GUIDE_COLOR;
 static const gchar *default_paper_name = NULL;
 static const gchar *default_length_unit = "Centimeter";
 static const gchar *default_fontsize_unit = "Point";
+static guint default_snap_distance = 10;
 
 static const char *default_favored_filter = N_("any");
 
@@ -184,6 +186,8 @@ DiaPrefData prefs_data[] =
   { "fontsize_unit", PREF_CHOICE, PREF_OFFSET(fontsize_unit),
     &default_fontsize_unit, UI_TAB, N_("Font size unit:"), NULL, FALSE,
     _get_units_name_list, update_internal_prefs },
+  { "snap_distance", PREF_UINT, PREF_OFFSET(snap_distance),
+    &default_snap_distance, 0, N_("Guide snapping distance:") },
   
   { NULL, PREF_NONE, 0, NULL, DIA_TAB, N_("New diagram:") },
   { "is_portrait", PREF_BOOLEAN, PREF_OFFSET(new_diagram.is_portrait), &default_true, DIA_TAB, N_("Portrait") },
@@ -216,6 +220,12 @@ DiaPrefData prefs_data[] =
   { "view_antialiased", PREF_BOOLEAN, PREF_OFFSET(view_antialiased), &default_false, VIEW_TAB, N_("view antialiased") },
   { NULL, PREF_END_GROUP, 0, NULL, VIEW_TAB, NULL },
 
+  { NULL, PREF_NONE, 0, NULL, VIEW_TAB, N_("Guides:") },
+  { "show_guides", PREF_BOOLEAN, PREF_OFFSET(guides_visible), &default_true, VIEW_TAB, N_("Visible") },
+  { "snap_to_guides", PREF_BOOLEAN, PREF_OFFSET(guides_snap), &default_true, VIEW_TAB, N_("Snap to guides") },
+  { "guide_colour", PREF_COLOUR, PREF_OFFSET(new_diagram.guide_color), &guide_colour, VIEW_TAB, N_("Color:") },
+  { NULL, PREF_END_GROUP, 0, NULL, VIEW_TAB, NULL },
+
   /* Favored Filter */
   { NULL, PREF_NONE, 0, NULL, FAVOR_TAB, N_("Export") },
   { "favored_png_export", PREF_CHOICE, PREF_OFFSET(favored_filter.png), &default_favored_filter, 
diff --git a/app/preferences.h b/app/preferences.h
index 8665f08..53cd1c8 100644
--- a/app/preferences.h
+++ b/app/preferences.h
@@ -23,6 +23,7 @@
 
 #define DEFAULT_GRID_COLOR { 0.85, .90, .90, 1.0 }
 #define DEFAULT_PAGEBREAK_COLOR { 0.0, 0.0, 0.6, 1.0 }
+#define DEFAULT_GUIDE_COLOR { 0.0, 1.0, 0.0, 1.0 }
 
 struct DiaPreferences {
   struct {
@@ -79,6 +80,10 @@ struct DiaPreferences {
     char *emf;
     char *print;
   } favored_filter;
+
+  int guides_visible;   /** Whether guides are visible. */
+  int guides_snap;      /** Whether to snap to guides. */
+  guint snap_distance;  /** The snapping distance for guides. */
 };
 
 extern struct DiaPreferences prefs;
diff --git a/app/ruler.c b/app/ruler.c
index c26b055..f36d59a 100644
--- a/app/ruler.c
+++ b/app/ruler.c
@@ -272,7 +272,7 @@ dia_ruler_new (GtkOrientation orientation, GtkWidget *shell, DDisplay *ddisp)
   DIA_RULER(rule)->orientation = orientation;
   DIA_RULER(rule)->ddisp = ddisp;
 
-  gtk_widget_set_events (rule, GDK_EXPOSURE_MASK);
+  gtk_widget_set_events (rule, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK);
 
   g_signal_connect_swapped (G_OBJECT (shell), "motion_notify_event",
                             G_CALLBACK (dia_ruler_motion_notify),
diff --git a/app/tool.c b/app/tool.c
index 492af30..8646ccd 100644
--- a/app/tool.c
+++ b/app/tool.c
@@ -26,6 +26,7 @@
 #include "interface.h"
 #include "defaults.h"
 #include "object.h"
+#include "guide_tool.h"
 
 Tool *active_tool = NULL;
 Tool *transient_tool = NULL;
@@ -92,6 +93,9 @@ tool_free(Tool *tool)
   case TEXTEDIT_TOOL :
     free_textedit_tool(tool);
     break;
+  case GUIDE_TOOL:
+    free_guide_tool(tool);
+    break;
   default:
     g_assert(0);    
   }
@@ -124,6 +128,11 @@ tool_select(ToolType type, gpointer extra_data,
   case TEXTEDIT_TOOL :
     active_tool = create_textedit_tool();
     break;
+  case GUIDE_TOOL :
+    active_tool = create_guide_tool();
+    guide_tool_set_guide(active_tool, extra_data);
+    guide_tool_set_orientation(active_tool, GPOINTER_TO_INT(user_data));
+    break;
   default:
     g_assert(0);    
   }
@@ -154,5 +163,7 @@ tool_options_dialog_show(ToolType type, gpointer extra_data,
     break;
   case TEXTEDIT_TOOL :
     break;
+  case GUIDE_TOOL :
+    break;
   }
 }
diff --git a/app/tool.h b/app/tool.h
index 174eda1..61912f2 100644
--- a/app/tool.h
+++ b/app/tool.h
@@ -38,7 +38,8 @@ enum _ToolType {
   MAGNIFY_TOOL,
   MODIFY_TOOL,
   SCROLL_TOOL,
-  TEXTEDIT_TOOL
+  TEXTEDIT_TOOL,
+  GUIDE_TOOL
 };
 
 struct _Tool {
diff --git a/app/undo.c b/app/undo.c
index 55201f2..9cc7623 100644
--- a/app/undo.c
+++ b/app/undo.c
@@ -341,6 +341,14 @@ struct MoveObjectsChange {
   GList *obj_list;
 };
 
+struct MoveGuideChange {
+  Change change;
+
+  real orig_pos;
+  real dest_pos;
+  Guide *guide;
+};
+
 static void
 move_objects_apply(struct MoveObjectsChange *change, Diagram *dia)
 {
@@ -373,6 +381,17 @@ move_objects_apply(struct MoveObjectsChange *change, Diagram *dia)
 }
 
 static void
+move_guide_apply(struct MoveGuideChange *change, Diagram *dia)
+{
+  change->guide->position = change->dest_pos;
+    
+  /* Force redraw. */
+  diagram_add_update_all(dia);
+  diagram_modified(dia);
+  diagram_flush(dia);
+}
+
+static void
 move_objects_revert(struct MoveObjectsChange *change, Diagram *dia)
 {
   GList *list;
@@ -404,6 +423,17 @@ move_objects_revert(struct MoveObjectsChange *change, Diagram *dia)
 }
 
 static void
+move_guide_revert(struct MoveGuideChange *change, Diagram *dia)
+{
+  change->guide->position = change->orig_pos;
+
+  /* Force redraw. */
+  diagram_add_update_all(dia);
+  diagram_modified(dia);
+  diagram_flush(dia);
+}
+
+static void
 move_objects_free(struct MoveObjectsChange *change)
 {
   g_free(change->orig_pos);
@@ -411,6 +441,12 @@ move_objects_free(struct MoveObjectsChange *change)
   g_list_free(change->obj_list);
 }
 
+static void
+move_guide_free(struct MoveGuideChange *change)
+{
+  /* Nothing to free. */
+}
+
 extern Change *
 undo_move_objects(Diagram *dia, Point *orig_pos, Point *dest_pos,
 		  GList *obj_list)
@@ -432,6 +468,26 @@ undo_move_objects(Diagram *dia, Point *orig_pos, Point *dest_pos,
   return (Change *)change;
 }
 
+Change *
+undo_move_guide(Diagram *dia, Guide *guide, real orig_pos, real dest_pos)
+{
+  struct MoveGuideChange *change;
+
+  change = g_new0(struct MoveGuideChange, 1);
+
+  change->change.apply = (UndoApplyFunc) move_guide_apply;
+  change->change.revert = (UndoRevertFunc) move_guide_revert;
+  change->change.free = (UndoFreeFunc) move_guide_free;
+
+  change->orig_pos = orig_pos;
+  change->dest_pos = dest_pos;
+  change->guide = guide;
+
+  DEBUG_PRINTF(("UNDO: Move guide at %d\n", dia->undo->depth));
+  undo_push_change(dia->undo, (Change *) change);
+  return (Change *)change;
+}
+
 /********** Move handle: */
 
 struct MoveHandleChange {
@@ -727,6 +783,20 @@ struct InsertObjectsChange {
   int applied;
 };
 
+struct AddGuideChange {
+  Change change;
+
+  Guide *guide;
+  int applied;
+};
+
+struct DeleteGuideChange {
+  Change change;
+
+  Guide *guide;
+  int applied;
+};
+
 static void
 insert_objects_apply(struct InsertObjectsChange *change, Diagram *dia)
 {
@@ -737,6 +807,41 @@ insert_objects_apply(struct InsertObjectsChange *change, Diagram *dia)
 }
 
 static void
+add_guide_apply(struct AddGuideChange *change, Diagram *dia)
+{
+  Guide *new_guide;
+
+  DEBUG_PRINTF(("add_guide_apply()\n"));
+
+  new_guide = diagram_add_guide(dia, change->guide->position, change->guide->orientation, FALSE);
+  g_free(change->guide);
+  change->guide = new_guide;
+  
+  /* Force redraw. */
+  diagram_add_update_all(dia);
+  diagram_modified(dia);
+  diagram_flush(dia);
+
+  /* Set flag. */
+  change->applied = 1;
+}
+
+static void
+delete_guide_apply(struct DeleteGuideChange *change, Diagram *dia)
+{
+  DEBUG_PRINTF(("delete_guide_apply()\n"));
+  diagram_remove_guide(dia, change->guide, FALSE);
+  
+  /* Force redraw. */
+  diagram_add_update_all(dia);
+  diagram_modified(dia);
+  diagram_flush(dia);
+
+  /* Set flag. */
+  change->applied = 1;  
+}
+
+static void
 insert_objects_revert(struct InsertObjectsChange *change, Diagram *dia)
 {
   GList *list;
@@ -760,6 +865,46 @@ insert_objects_revert(struct InsertObjectsChange *change, Diagram *dia)
 }
 
 static void
+add_guide_revert(struct AddGuideChange *change, Diagram *dia)
+{
+  DEBUG_PRINTF(("add_guide_revert()\n"));
+  diagram_remove_guide(dia, change->guide, FALSE);
+
+  /* Force redraw. */
+  diagram_add_update_all(dia);
+  diagram_modified(dia);
+  diagram_flush(dia);
+
+  /* Set flag. */
+  change->applied = 0;
+}
+
+static void
+delete_guide_revert(struct DeleteGuideChange *change, Diagram *dia)
+{  
+  /* Declare variable. */
+  Guide *new_guide;
+  
+  /* Log message. */
+  DEBUG_PRINTF(("delete_guide_revert()\n"));
+  
+  /* Add it again. */
+  new_guide = diagram_add_guide(dia, change->guide->position, change->guide->orientation, FALSE);
+  
+  /* Reassign. */
+  g_free(change->guide);
+  change->guide = new_guide;
+  
+  /* Force redraw. */
+  diagram_add_update_all(dia);
+  diagram_modified(dia);
+  diagram_flush(dia);
+
+  /* Set flag. */
+  change->applied = 0;  
+}
+
+static void
 insert_objects_free(struct InsertObjectsChange *change)
 {
   DEBUG_PRINTF(("insert_objects_free()\n"));
@@ -769,6 +914,22 @@ insert_objects_free(struct InsertObjectsChange *change)
     g_list_free(change->obj_list);
 }
 
+static void
+add_guide_free(struct AddGuideChange *change, Diagram *dia)
+{
+  DEBUG_PRINTF(("add_guide_free()\n"));
+  if (!change->applied)
+    g_free(change->guide);
+}
+
+static void
+delete_guide_free(struct DeleteGuideChange *change, Diagram *dia)
+{
+  DEBUG_PRINTF(("delete_guide_free()\n"));
+  if (change->applied)
+    g_free(change->guide);
+}
+
 Change *
 undo_insert_objects(Diagram *dia, GList *obj_list, int applied)
 {
@@ -789,6 +950,42 @@ undo_insert_objects(Diagram *dia, GList *obj_list, int applied)
   return (Change *)change;
 }
 
+Change *undo_add_guide(Diagram *dia, Guide *guide, int applied)
+{
+  struct AddGuideChange *change;
+
+  change = g_new0(struct AddGuideChange, 1);
+
+  change->change.apply = (UndoApplyFunc) add_guide_apply;
+  change->change.revert = (UndoRevertFunc) add_guide_revert;
+  change->change.free = (UndoFreeFunc) add_guide_free;
+
+  change->guide = guide;
+  change->applied = applied;
+
+  DEBUG_PRINTF(("UNDO: Push add guide at %d\n", dia->undo->depth));
+  undo_push_change(dia->undo, (Change *) change);
+  return (Change *)change;
+}
+
+Change *undo_delete_guide(Diagram *dia, Guide *guide, int applied)
+{
+  struct DeleteGuideChange *change;
+
+  change = g_new0(struct DeleteGuideChange, 1);
+  
+  change->change.apply = (UndoApplyFunc) delete_guide_apply;
+  change->change.revert = (UndoRevertFunc) delete_guide_revert;
+  change->change.free = (UndoFreeFunc) delete_guide_free;
+
+  change->guide = guide;
+  change->applied = applied;
+
+  DEBUG_PRINTF(("UNDO: Push delete guide at %d\n", dia->undo->depth));
+  undo_push_change(dia->undo, (Change *) change);
+  return (Change *)change;
+}
+
 /******** Reorder object list: */
 
 struct ReorderObjectsChange {
diff --git a/app/undo.h b/app/undo.h
index 438a441..caa759b 100644
--- a/app/undo.h
+++ b/app/undo.h
@@ -23,6 +23,7 @@ typedef struct _UndoStack UndoStack;
 typedef struct _Change Change;
 
 #include "diagram.h"
+#include "guide.h"
 
 typedef void (*UndoApplyFunc)(Change *change, Diagram *dia);
 typedef void (*UndoRevertFunc)(Change *change, Diagram *dia);
@@ -84,6 +85,9 @@ Change *undo_parenting(Diagram *dia, DiaObject *parentobj, DiaObject *childobj,
 		       gboolean parent);
 Change *undo_move_object_other_layer(Diagram *diagram, GList *selected_list,
 				     gboolean moving_up);
+Change *undo_add_guide(Diagram *dia, Guide *guide, int applied);
+Change *undo_delete_guide(Diagram *dia, Guide *guide, int applied);
+Change *undo_move_guide(Diagram *dia, Guide *guide, real orig_pos, real dest_pos);
 
 /* Create an import change object listening on diagram additions/removals */
 Change *undo_import_change_setup (Diagram *diagram);
diff --git a/data/display-ui.xml b/data/display-ui.xml
index 049de3b..37e251d 100644
--- a/data/display-ui.xml
+++ b/data/display-ui.xml
@@ -69,6 +69,13 @@
 			<menuitem name="ViewCloneview" action="ViewCloneview" />
 			<menuitem name="ViewRedraw" action="ViewRedraw" />
 			<separator name="ViewSep3" />
+			<menu name="ViewGuides" action="ViewGuides">
+				<menuitem name="ViewNewguide" action="ViewNewguide" />
+				<menuitem name="ViewShowguides" action="ViewShowguides" />
+				<menuitem name="ViewSnaptoguides" action="ViewSnaptoguides" />
+				<menuitem name="ViewRemoveallguides" action="ViewRemoveallguides" />
+			</menu>
+			<separator name="ViewSep4" />
 			<separator name="ViewExtensionStart" />
 		</menu>
 		<menu name="Layers" action="Layers">
diff --git a/data/integrated-ui.xml b/data/integrated-ui.xml
index 25919ff..0d0a177 100644
--- a/data/integrated-ui.xml
+++ b/data/integrated-ui.xml
@@ -83,6 +83,13 @@
 			<menuitem name="ViewShowscrollbars" action="ViewShowscrollbars" />
 			<menuitem name="ViewShowconnectionpoints" action="ViewShowconnectionpoints" />
 			<separator name="ViewSep3" />
+			<menu name="ViewGuides" action="ViewGuides">
+				<menuitem name="ViewNewguide" action="ViewNewguide" />
+				<menuitem name="ViewShowguides" action="ViewShowguides" />
+				<menuitem name="ViewSnaptoguides" action="ViewSnaptoguides" />
+				<menuitem name="ViewRemoveallguides" action="ViewRemoveallguides" />
+			</menu>
+			<separator name="ViewSep4" />
 			<menuitem name="ViewNewview" action="ViewNewview" />
 			<menuitem name="ViewCloneview" action="ViewCloneview" />
 			<menuitem name="ViewRedraw" action="ViewRedraw" />
diff --git a/data/popup-ui.xml b/data/popup-ui.xml
index 4a4b297..71a15f3 100644
--- a/data/popup-ui.xml
+++ b/data/popup-ui.xml
@@ -64,11 +64,18 @@
 			<menuitem name="ViewShowrulers" action="ViewShowrulers" />
 			<menuitem name="ViewShowconnectionpoints" action="ViewShowconnectionpoints" />
 			<separator name="ViewSep2" />
+			<menu name="ViewGuides" action="ViewGuides">
+				<menuitem name="ViewNewguide" action="ViewNewguide" />
+				<menuitem name="ViewShowguides" action="ViewShowguides" />
+				<menuitem name="ViewSnaptoguides" action="ViewSnaptoguides" />
+				<menuitem name="ViewRemoveallguides" action="ViewRemoveallguides" />
+			</menu>
+			<separator name="ViewSep3" />
 			<menuitem name="ViewNewview" action="ViewNewview" />
 			<menuitem name="ViewCloneview" action="ViewCloneview" />
 			<menuitem name="ViewShowall" action="ViewShowall" />
 			<menuitem name="ViewRedraw" action="ViewRedraw" />
-			<separator name="ViewSep3" />
+			<separator name="ViewSep4" />
 			<separator name="ViewExtensionStart" />
 		</menu>
 		<menu name="Layers" action="Layers">
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 17ee987..881ac76 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -219,7 +219,9 @@ libdia_la_SOURCES =  \
 		diacellrendererproperty.c \
 		diacellrendererproperty.h \
 		\
-		dia-lib-icons.h
+		dia-lib-icons.h \
+		guide.c \
+		guide.h
 
 #		charconv.c \
 #		charconv.h 
diff --git a/lib/diagramdata.h b/lib/diagramdata.h
index 9ca9cc5..6754e95 100644
--- a/lib/diagramdata.h
+++ b/lib/diagramdata.h
@@ -39,7 +39,7 @@ struct _NewDiagramData {
   gfloat scaling;
   gboolean fitto;
   gint fitwidth, fitheight;
-  Color bg_color, pagebreak_color, grid_color;
+  Color bg_color, pagebreak_color, grid_color, guide_color;
   int compress_save;
   gchar *unit, *font_unit;
 };
diff --git a/lib/guide.c b/lib/guide.c
new file mode 100644
index 0000000..3860953
--- /dev/null
+++ b/lib/guide.c
@@ -0,0 +1 @@
+#include "guide.h"
diff --git a/lib/guide.h b/lib/guide.h
new file mode 100644
index 0000000..1be5669
--- /dev/null
+++ b/lib/guide.h
@@ -0,0 +1,31 @@
+/* Dia -- an diagram creation/manipulation program
+ * Copyright (C) 1998 Alexander Larsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#ifndef GUIDE_H
+#define GUIDE_H
+
+#include "diatypes.h"
+#include <gtk/gtk.h>
+
+typedef struct _Guide Guide;
+
+struct _Guide {
+  real position;
+  GtkOrientation orientation;
+};
+
+#endif /* GUIDE_H */
