Code

Filter effects dialog:
[inkscape.git] / src / desktop.cpp
index 9a2274bea9ca7dae900157fca75a49e07a17515d..859e15bd830280b45628042f99930dc393721f63 100644 (file)
@@ -8,7 +8,12 @@
  *   MenTaLguY <mental@rydia.net>
  *   bulia byak <buliabyak@users.sf.net>
  *   Ralf Stephan <ralf@ark.in-berlin.de>
+ *   John Bintz <jcoswell@coswellproductions.org>
+ *   Johan Engelen <j.b.c.engelen@ewi.utwente.nl>
  *
+ * Copyright (C) 2007 Jon A. Cruz
+ * Copyright (C) 2006-2007 Johan Engelen
+ * Copyright (C) 2006 John Bintz
  * Copyright (C) 2004 MenTaLguY
  * Copyright (C) 1999-2002 Lauris Kaplinski
  * Copyright (C) 2000-2001 Ximian, Inc.
@@ -49,6 +54,8 @@
 #endif
 
 #include <glibmm/i18n.h>
+#include <sigc++/functors/mem_fun.h>
+#include <gtkmm.h>
 
 #include "macros.h"
 #include "inkscape-private.h"
 #include "ui/dialog/dialog-manager.h"
 #include "xml/repr.h"
 #include "message-context.h"
+#include "layer-manager.h"
+#include "event-log.h"
+#include "display/canvas-grid.h"
 
-#ifdef WITH_INKBOARD
-#include "jabber_whiteboard/session-manager.h"
-#endif
+#include "display/sp-canvas.h"
 
 namespace Inkscape { namespace XML { class Node; }}
 
@@ -90,7 +98,7 @@ static void _layer_deactivated(SPObject *layer, SPDesktop *desktop);
 static void _layer_hierarchy_changed(SPObject *top, SPObject *bottom, SPDesktop *desktop);
 static void _reconstruction_start(SPDesktop * desktop);
 static void _reconstruction_finish(SPDesktop * desktop);
-static void _namedview_modified (SPNamedView *nv, guint flags, SPDesktop *desktop);
+static void _namedview_modified (SPObject *obj, guint flags, SPDesktop *desktop);
 static void _update_snap_distances (SPDesktop *desktop);
 
 /**
@@ -98,45 +106,56 @@ static void _update_snap_distances (SPDesktop *desktop);
  * \pre namedview != NULL.
  * \pre canvas != NULL.
  */
-SPDesktop::SPDesktop()
-{
-    _dlg_mgr = NULL;
-    _widget = 0;
-    namedview = NULL;
-    selection = NULL;
-    acetate = NULL;
-    main = NULL;
-    grid = NULL;
-    guides = NULL;
-    drawing = NULL;
-    sketch = NULL;
-    controls = NULL;
-    event_context = 0;
-
+SPDesktop::SPDesktop() :
+    _dlg_mgr( 0 ),
+    namedview( 0 ),
+    canvas( 0 ),
+    selection( 0 ),
+    event_context( 0 ),
+    layer_manager( 0 ),
+    event_log( 0 ),
+    acetate( 0 ),
+    main( 0 ),
+    gridgroup( 0 ),
+    guides( 0 ),
+    drawing( 0 ),
+    sketch( 0 ),
+    controls( 0 ),
+    table( 0 ),
+    page( 0 ),
+    page_border( 0 ),
+    current( 0 ),
+    zooms_past( 0 ),
+    zooms_future( 0 ),
+    dkey( 0 ),
+    number( 0 ),
+    window_state(0),
+    interaction_disabled_counter( 0 ),
+    waiting_cursor( false ),
+    guides_active( false ),
+    gr_item( 0 ),
+    gr_point_type( 0 ),
+    gr_point_i( 0 ),
+    gr_fill_or_stroke( true ),
+    _layer_hierarchy( 0 ),
+    _reconstruction_old_layer_id( 0 ),
+    _widget( 0 ),
+    _inkscape( 0 ),
+    _guides_message_context( 0 ),
+    _active( false ),
+    _w2d(),
+    _d2w(),
+    _doc2dt( NR::Matrix(NR::scale(1, -1)) ),
+    grids_visible( true )
+{
     _d2w.set_identity();
     _w2d.set_identity();
-    _doc2dt = NR::Matrix(NR::scale(1, -1));
-
-    guides_active = false;
-
-    zooms_past = NULL;
-    zooms_future = NULL;
-
-    is_fullscreen = false;
-
-    gr_item = NULL;
-    gr_point_num = 0;
-    gr_fill_or_stroke = true;
-
-    _layer_hierarchy = NULL;
-    _active = false;
 
-    selection = Inkscape::GC::release (new Inkscape::Selection (this));
+    selection = Inkscape::GC::release( new Inkscape::Selection(this) );
 }
 
-void 
+void
 SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas)
-
 {
     _guides_message_context = new Inkscape::MessageContext(const_cast<Inkscape::MessageStack*>(messageStack()));
 
@@ -144,7 +163,7 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas)
 
     namedview = nv;
     canvas = aCanvas;
-   
+
     SPDocument *document = SP_OBJECT_DOCUMENT (namedview);
     /* Kill flicker */
     sp_document_ensure_up_to_date (document);
@@ -185,11 +204,15 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas)
 
     SP_CANVAS_ARENA (drawing)->arena->delta = prefs_get_double_attribute ("options.cursortolerance", "value", 1.0); // default is 1 px
 
-    // Start always in normal mode
-    SP_CANVAS_ARENA (drawing)->arena->rendermode = RENDERMODE_NORMAL;
-    canvas->rendermode = RENDERMODE_NORMAL; // canvas needs that for choosing the best buffer size
+    if (prefs_get_int_attribute("options.startmode", "outline", 0)) {
+        // Start in outline mode
+        setDisplayModeOutline();
+    } else {
+        // Start in normal mode, default
+        setDisplayModeNormal();
+    }
 
-    grid = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL);
+    gridgroup = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL);
     guides = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL);
     sketch = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL);
     controls = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL);
@@ -206,7 +229,7 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas)
 
     NR::Rect const d(NR::Point(0.0, 0.0),
                      NR::Point(sp_document_width(document), sp_document_height(document)));
-    
+
     SP_CTRLRECT(page)->setRectangle(d);
     SP_CTRLRECT(page_border)->setRectangle(d);
 
@@ -219,18 +242,17 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas)
     if ( namedview->pageshadow != 0 && namedview->showpageshadow ) {
         SP_CTRLRECT(page_border)->setShadow(namedview->pageshadow, 0x3f3f3fff);
     }
-    
+
 
     /* Connect event for page resize */
     _doc2dt[5] = sp_document_height (document);
     sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (drawing), _doc2dt);
 
-    g_signal_connect (G_OBJECT (namedview), "modified", G_CALLBACK (_namedview_modified), this);
-
+    _modified_connection = namedview->connectModified(sigc::bind<2>(sigc::ptr_fun(&_namedview_modified), this));
 
     NRArenaItem *ai = sp_item_invoke_show (SP_ITEM (sp_document_root (document)),
-            SP_CANVAS_ARENA (drawing)->arena, 
-            dkey, 
+            SP_CANVAS_ARENA (drawing)->arena,
+            dkey,
             SP_ITEM_SHOW_DISPLAY);
     if (ai) {
         nr_arena_item_add_child (SP_CANVAS_ARENA (drawing)->root, ai, NULL);
@@ -243,14 +265,6 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas)
     /* Ugly hack */
     _namedview_modified (namedview, SP_OBJECT_MODIFIED_FLAG, this);
 
-       /* Construct SessionManager 
-        * 
-        * SessionManager construction needs to be done after document connection 
-        */
-#ifdef WITH_INKBOARD
-       _whiteboard_session_manager = new Inkscape::Whiteboard::SessionManager(this);
-#endif
-
 /* Set up notification of rebuilding the document, this allows
        for saving object related settings in the document. */
     _reconstruction_start_connection =
@@ -289,6 +303,12 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas)
         )
     );
 
+
+    /* setup LayerManager */
+    //   (Setting up after the connections are all in place, as it may use some of them)
+    layer_manager = new Inkscape::LayerManager( this );
+
+    grids_visible = true;
 }
 
 
@@ -298,6 +318,14 @@ void SPDesktop::destroy()
     _deactivate_connection.disconnect();
     _sel_modified_connection.disconnect();
     _sel_changed_connection.disconnect();
+    _modified_connection.disconnect();
+    _commit_connection.disconnect();
+    _reconstruction_start_connection.disconnect();
+    _reconstruction_finish_connection.disconnect();
+
+    g_signal_handlers_disconnect_by_func(G_OBJECT (acetate), (gpointer) G_CALLBACK(sp_desktop_root_handler), this);
+    g_signal_handlers_disconnect_by_func(G_OBJECT (main), (gpointer) G_CALLBACK(sp_desktop_root_handler), this);
+    g_signal_handlers_disconnect_by_func(G_OBJECT (drawing), (gpointer) G_CALLBACK(_arena_handler), this);
 
     while (event_context) {
         SPEventContext *ec = event_context;
@@ -319,17 +347,9 @@ void SPDesktop::destroy()
         drawing = NULL;
     }
 
-#ifdef WITH_INKBOARD
-       if (_whiteboard_session_manager) {
-               delete _whiteboard_session_manager;
-       }
-#endif
-
     delete _guides_message_context;
     _guides_message_context = NULL;
 
-    sp_signal_disconnect_by_data (G_OBJECT (namedview), this);
-
     g_list_free (zooms_past);
     g_list_free (zooms_future);
 }
@@ -343,20 +363,32 @@ void SPDesktop::setDisplayModeNormal()
 {
     SP_CANVAS_ARENA (drawing)->arena->rendermode = RENDERMODE_NORMAL;
     canvas->rendermode = RENDERMODE_NORMAL; // canvas needs that for choosing the best buffer size
+    displayMode = RENDERMODE_NORMAL;
     sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (main), _d2w); // redraw
+    _widget->setTitle(SP_DOCUMENT_NAME(sp_desktop_document(this)));
 }
 
 void SPDesktop::setDisplayModeOutline()
 {
     SP_CANVAS_ARENA (drawing)->arena->rendermode = RENDERMODE_OUTLINE;
     canvas->rendermode = RENDERMODE_OUTLINE; // canvas needs that for choosing the best buffer size
+    displayMode = RENDERMODE_OUTLINE;
     sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (main), _d2w); // redraw
+    _widget->setTitle(SP_DOCUMENT_NAME(sp_desktop_document(this)));
+}
+
+void SPDesktop::displayModeToggle()
+{
+    if (displayMode == RENDERMODE_OUTLINE)
+        setDisplayModeNormal();
+    else 
+        setDisplayModeOutline();
 }
 
 /**
  * Returns current root (=bottom) layer.
  */
-SPObject *SPDesktop::currentRoot() const 
+SPObject *SPDesktop::currentRoot() const
 {
     return _layer_hierarchy ? _layer_hierarchy->top() : NULL;
 }
@@ -370,11 +402,13 @@ SPObject *SPDesktop::currentLayer() const
 }
 
 /**
+ * Sets the current layer of the desktop.
+ * 
  * Make \a object the top layer.
  */
 void SPDesktop::setCurrentLayer(SPObject *object) {
     g_return_if_fail(SP_IS_GROUP(object));
-    g_return_if_fail( currentRoot() == object || currentRoot()->isAncestorOf(object));
+    g_return_if_fail( currentRoot() == object || (currentRoot() && currentRoot()->isAncestorOf(object)) );
     // printf("Set Layer to ID: %s\n", SP_OBJECT_ID(object));
     _layer_hierarchy->setBottom(object);
 }
@@ -405,11 +439,15 @@ bool SPDesktop::isLayer(SPObject *object) const {
 /**
  * True if desktop viewport fully contains \a item's bbox.
  */
-bool SPDesktop::isWithinViewport (SPItem *item) const 
+bool SPDesktop::isWithinViewport (SPItem *item) const
 {
     NR::Rect const viewport = get_display_area();
-    NR::Rect const bbox = sp_item_bbox_desktop(item);
-    return viewport.contains(bbox);
+    NR::Maybe<NR::Rect> const bbox = sp_item_bbox_desktop(item);
+    if (bbox) {
+        return viewport.contains(*bbox);
+    } else {
+        return true;
+    }
 }
 
 ///
@@ -510,12 +548,17 @@ SPDesktop::push_event_context (GtkType type, const gchar *config, unsigned int k
     _event_context_changed_signal.emit (this, ec);
 }
 
+/**
+ * Sets the coordinate status to a given point
+ */
 void
 SPDesktop::set_coordinate_status (NR::Point p) {
     _widget->setCoordinateStatus(p);
 }
 
-
+/**
+ * \see sp_document_item_from_list_at_point_bottom()
+ */
 SPItem *
 SPDesktop::item_from_list_at_point_bottom (const GSList *list, NR::Point const p) const
 {
@@ -523,6 +566,9 @@ SPDesktop::item_from_list_at_point_bottom (const GSList *list, NR::Point const p
     return sp_document_item_from_list_at_point_bottom (dkey, SP_GROUP (doc()->root), list, p);
 }
 
+/**
+ * \see sp_document_item_at_point()
+ */
 SPItem *
 SPDesktop::item_at_point (NR::Point const p, bool into_groups, SPItem *upto) const
 {
@@ -530,6 +576,9 @@ SPDesktop::item_at_point (NR::Point const p, bool into_groups, SPItem *upto) con
     return sp_document_item_at_point (doc(), dkey, p, into_groups, upto);
 }
 
+/**
+ * \see sp_document_group_at_point()
+ */
 SPItem *
 SPDesktop::group_at_point (NR::Point const p) const
 {
@@ -538,7 +587,7 @@ SPDesktop::group_at_point (NR::Point const p) const
 }
 
 /**
- * \brief  Returns the mouse point in document coordinates; if mouse is 
+ * \brief  Returns the mouse point in document coordinates; if mouse is
  * outside the canvas, returns the center of canvas viewpoint
  */
 NR::Point
@@ -726,10 +775,10 @@ SPDesktop::zoom_absolute_keep_point (double cx, double cy, double px, double py,
     double const width2 = viewbox.dimensions()[NR::X] / zoom;
     double const height2 = viewbox.dimensions()[NR::Y] / zoom;
 
-    set_display_area(cx - px * width2, 
-                     cy - py * height2, 
-                     cx + (1 - px) * width2, 
-                     cy + (1 - py) * height2, 
+    set_display_area(cx - px * width2,
+                     cy - py * height2,
+                     cx + (1 - px) * width2,
+                     cy + (1 - py) * height2,
                      0.0);
 }
 
@@ -788,8 +837,8 @@ SPDesktop::zoom_page()
 {
     NR::Rect d(NR::Point(0, 0),
                NR::Point(sp_document_width(doc()), sp_document_height(doc())));
-                         
-    if (d.dimensions()[NR::X] < 1.0 || d.dimensions()[NR::Y] < 1.0) {
+
+    if (d.isEmpty(1.0)) {
         return;
     }
 
@@ -810,7 +859,7 @@ SPDesktop::zoom_page_width()
 
     NR::Rect d(NR::Point(0, a.midpoint()[NR::Y]),
                NR::Point(sp_document_width(doc()), a.midpoint()[NR::Y]));
-               
+
     set_display_area(d, 10);
 }
 
@@ -820,13 +869,13 @@ SPDesktop::zoom_page_width()
 void
 SPDesktop::zoom_selection()
 {
-    NR::Rect const d = selection->bounds();
+    NR::Maybe<NR::Rect> const d = selection->bounds();
 
-    if (d.dimensions()[NR::X] < 0.1 || d.dimensions()[NR::Y] < 0.1) {
+    if ( !d || d->isEmpty(0.1) ) {
         return;
     }
-    
-    set_display_area(d, 10);
+
+    set_display_area(*d, 10);
 }
 
 /**
@@ -848,29 +897,29 @@ SPDesktop::zoom_drawing()
     SPItem *docitem = SP_ITEM (sp_document_root (doc()));
     g_return_if_fail (docitem != NULL);
 
-    NR::Rect d = sp_item_bbox_desktop(docitem);
+    NR::Maybe<NR::Rect> d = sp_item_bbox_desktop(docitem);
 
     /* Note that the second condition here indicates that
     ** there are no items in the drawing.
     */
-    if ( d.dimensions()[NR::X] < 1.0 || d.dimensions()[NR::Y] < 1.0 ) {
+    if ( !d || d->isEmpty(1.0) ) {
         return;
     }
 
-    set_display_area(d, 10);
+    set_display_area(*d, 10);
 }
 
 /**
  * Scroll canvas by specific coordinate amount.
  */
-void 
-SPDesktop::scroll_world (double dx, double dy)
+void
+SPDesktop::scroll_world (double dx, double dy, bool is_scrolling)
 {
-    g_assert(_widget); 
+    g_assert(_widget);
 
     NR::Rect const viewbox = canvas->getViewbox();
 
-    sp_canvas_scroll_to(canvas, viewbox.min()[NR::X] - dx, viewbox.min()[NR::Y] - dy, FALSE);
+    sp_canvas_scroll_to(canvas, viewbox.min()[NR::X] - dx, viewbox.min()[NR::Y] - dy, FALSE, is_scrolling);
 
     _widget->updateRulers();
     _widget->updateScrollbars(expansion(_d2w));
@@ -921,19 +970,49 @@ SPDesktop::scroll_to_point (NR::Point const *p, gdouble autoscrollspeed)
     return false;
 }
 
+bool
+SPDesktop::is_iconified()
+{
+    return 0!=(window_state & GDK_WINDOW_STATE_ICONIFIED);
+}
+
+void
+SPDesktop::iconify()
+{
+    _widget->setIconified();
+}
+
+bool
+SPDesktop::is_maximized()
+{
+    return 0!=(window_state & GDK_WINDOW_STATE_MAXIMIZED);
+}
+
+void
+SPDesktop::maximize()
+{
+    _widget->setMaximized();
+}
+
+bool
+SPDesktop::is_fullscreen()
+{
+    return 0!=(window_state & GDK_WINDOW_STATE_FULLSCREEN);
+}
+
 void
 SPDesktop::fullscreen()
 {
     _widget->setFullscreen();
 }
-    
-void 
+
+void
 SPDesktop::getWindowGeometry (gint &x, gint &y, gint &w, gint &h)
 {
     _widget->getGeometry (x, y, w, h);
 }
 
-void 
+void
 SPDesktop::setWindowPosition (NR::Point p)
 {
     _widget->setPosition (p);
@@ -951,6 +1030,11 @@ SPDesktop::setWindowTransient (void *p, int transient_policy)
     _widget->setTransient (p, transient_policy);
 }
 
+void SPDesktop::getToplevel( GtkWidget*& toplevel )
+{
+    toplevel = GTK_WIDGET( _widget->getWindow() );
+}
+
 void
 SPDesktop::presentWindow()
 {
@@ -999,7 +1083,7 @@ SPDesktop::setToolboxFocusTo (gchar const *label)
     _widget->setToolboxFocusTo (label);
 }
 
-void 
+void
 SPDesktop::setToolboxAdjustmentValue (gchar const* id, double val)
 {
     _widget->setToolboxAdjustmentValue (id, val);
@@ -1011,17 +1095,76 @@ SPDesktop::isToolboxButtonActive (gchar const *id)
     return _widget->isToolboxButtonActive (id);
 }
 
-void 
-SPDesktop::emitToolSubselectionChanged(gpointer data) 
+void
+SPDesktop::emitToolSubselectionChanged(gpointer data)
 {
        _tool_subselection_changed.emit(data);
        inkscape_subselection_changed (this);
 }
 
+void
+SPDesktop::updateNow()
+{
+  sp_canvas_update_now(canvas);
+}
+
+void
+SPDesktop::enableInteraction()
+{
+  _widget->enableInteraction();
+}
+
+void SPDesktop::disableInteraction()
+{
+  _widget->disableInteraction();
+}
+
+void SPDesktop::setWaitingCursor()
+{
+    GdkCursor *waiting = gdk_cursor_new(GDK_WATCH);
+    gdk_window_set_cursor(GTK_WIDGET(sp_desktop_canvas(this))->window, waiting);
+    gdk_cursor_unref(waiting);
+    waiting_cursor = true;
+
+    // Stupidly broken GDK cannot just set the new cursor right now - it needs some main loop iterations for that
+    // Since setting waiting_cursor is usually immediately followed by some Real Work, we must run the iterations here
+    // CAUTION: iterations may redraw, and redraw may be interrupted, so you cannot assume that anything is the same
+    // after the call to setWaitingCursor as it was before
+    while( Gtk::Main::events_pending() )
+       Gtk::Main::iteration();
+}
+
+void SPDesktop::clearWaitingCursor()
+{
+  if (waiting_cursor)
+      sp_event_context_update_cursor(sp_desktop_event_context(this));
+}
+
+void SPDesktop::toggleGrid()
+{
+    if (namedview->grids) {
+        if(gridgroup) {
+            grids_visible = !grids_visible;
+            if (grids_visible) {
+                sp_canvas_item_show(SP_CANVAS_ITEM(gridgroup));
+            } else {
+                sp_canvas_item_hide(SP_CANVAS_ITEM(gridgroup));
+            }
+        }
+    } else {
+        //there is no grid present at the moment. add a rectangular grid and make it visible
+        Inkscape::XML::Node *repr = SP_OBJECT_REPR(namedview);
+        Inkscape::CanvasGrid::writeNewGridToRepr(repr, sp_desktop_document(this), Inkscape::GRID_RECTANGULAR);
+        grids_visible = true;
+        sp_canvas_item_show(SP_CANVAS_ITEM(gridgroup));
+    }
+}
+
+
 //----------------------------------------------------------------------
 // Callback implementations. The virtual ones are connected by the view.
 
-void 
+void
 SPDesktop::onPositionSet (double x, double y)
 {
     _widget->viewSetPosition (NR::Point(x,y));
@@ -1030,7 +1173,7 @@ SPDesktop::onPositionSet (double x, double y)
 void
 SPDesktop::onResized (double x, double y)
 {
-   // Nothing called here 
+   // Nothing called here
 }
 
 /**
@@ -1044,6 +1187,12 @@ SPDesktop::onRedrawRequested ()
     }
 }
 
+void
+SPDesktop::updateCanvasNow()
+{
+  _widget->requestCanvasUpdateAndWait();
+}
+
 /**
  * Associate document with desktop.
  */
@@ -1065,19 +1214,27 @@ SPDesktop::setDocument (SPDocument *doc)
     _layer_hierarchy->connectChanged(sigc::bind(sigc::ptr_fun(_layer_hierarchy_changed), this));
     _layer_hierarchy->setTop(SP_DOCUMENT_ROOT(doc));
 
+    /* setup EventLog */
+    event_log = new Inkscape::EventLog(doc);
+    doc->addUndoObserver(*event_log);
+
+    _commit_connection.disconnect();
+    _commit_connection = doc->connectCommit(sigc::mem_fun(*this, &SPDesktop::updateNow));
+
     /// \todo fixme: This condition exists to make sure the code
-    /// inside is called only once on initialization. But there
+    /// inside is NOT called on initialization, only on replacement. But there
     /// are surely more safe methods to accomplish this.
+    // TODO since the comment had reversed logic, check the intent of this block of code:
     if (drawing) {
-        NRArenaItem *ai;
+        NRArenaItem *ai = 0;
 
         namedview = sp_document_namedview (doc, NULL);
-        g_signal_connect (G_OBJECT (namedview), "modified", G_CALLBACK (_namedview_modified), this);
+        _modified_connection = namedview->connectModified(sigc::bind<2>(sigc::ptr_fun(&_namedview_modified), this));
         number = namedview->getViewCount();
 
-        ai = sp_item_invoke_show (SP_ITEM (sp_document_root (doc)), 
+        ai = sp_item_invoke_show (SP_ITEM (sp_document_root (doc)),
                 SP_CANVAS_ARENA (drawing)->arena,
-                dkey, 
+                dkey,
                 SP_ITEM_SHOW_DISPLAY);
         if (ai) {
             nr_arena_item_add_child (SP_CANVAS_ARENA (drawing)->root, ai, NULL);
@@ -1139,18 +1296,18 @@ SPDesktop::_onDeactivate (SPDesktop* dt)
 }
 
 void
-SPDesktop::_onSelectionModified 
+SPDesktop::_onSelectionModified
 (Inkscape::Selection *selection, guint flags, SPDesktop *dt)
 {
     if (!dt->_widget) return;
     dt->_widget->updateScrollbars (expansion(dt->_d2w));
 }
 
-static void 
+static void
 _onSelectionChanged
 (Inkscape::Selection *selection, SPDesktop *desktop)
 {
-    /** \todo 
+    /** \todo
      * only change the layer for single selections, or what?
      * This seems reasonable -- for multiple selections there can be many
      * different layers involved.
@@ -1180,21 +1337,21 @@ _arena_handler (SPCanvasArena *arena, NRArenaItem *ai, GdkEvent *event, SPDeskto
     }
 }
 
-static void 
+static void
 _layer_activated(SPObject *layer, SPDesktop *desktop) {
     g_return_if_fail(SP_IS_GROUP(layer));
     SP_GROUP(layer)->setLayerDisplayMode(desktop->dkey, SPGroup::LAYER);
 }
 
 /// Callback
-static void 
+static void
 _layer_deactivated(SPObject *layer, SPDesktop *desktop) {
     g_return_if_fail(SP_IS_GROUP(layer));
     SP_GROUP(layer)->setLayerDisplayMode(desktop->dkey, SPGroup::GROUP);
 }
 
 /// Callback
-static void 
+static void
 _layer_hierarchy_changed(SPObject *top, SPObject *bottom,
                                          SPDesktop *desktop)
 {
@@ -1242,11 +1399,16 @@ _reconstruction_finish (SPDesktop * desktop)
  * Namedview_modified callback.
  */
 static void
-_namedview_modified (SPNamedView *nv, guint flags, SPDesktop *desktop)
+_namedview_modified (SPObject *obj, guint flags, SPDesktop *desktop)
 {
+    SPNamedView *nv=SP_NAMEDVIEW(obj);
+
     if (flags & SP_OBJECT_MODIFIED_FLAG) {
 
         /* Recalculate snap distances */
+        /* FIXME: why is the desktop getting involved in setting up something
+        ** that is entirely to do with the namedview?
+        */
         _update_snap_distances (desktop);
 
         /* Show/hide page background */
@@ -1291,14 +1453,14 @@ _namedview_modified (SPNamedView *nv, guint flags, SPDesktop *desktop)
         }
 
         if (SP_RGBA32_A_U(nv->pagecolor) < 128 ||
-            (SP_RGBA32_R_U(nv->pagecolor) + 
-             SP_RGBA32_G_U(nv->pagecolor) + 
-             SP_RGBA32_B_U(nv->pagecolor)) >= 384) { 
+            (SP_RGBA32_R_U(nv->pagecolor) +
+             SP_RGBA32_G_U(nv->pagecolor) +
+             SP_RGBA32_B_U(nv->pagecolor)) >= 384) {
             // the background color is light or transparent, use black outline
-            SP_CANVAS_ARENA (desktop->drawing)->arena->outlinecolor = 0xff;
+            SP_CANVAS_ARENA (desktop->drawing)->arena->outlinecolor = prefs_get_int_attribute("options.wireframecolors", "onlight", 0xff);
         } else { // use white outline
-            SP_CANVAS_ARENA (desktop->drawing)->arena->outlinecolor = 0xffffffff;
-        }        
+            SP_CANVAS_ARENA (desktop->drawing)->arena->outlinecolor = prefs_get_int_attribute("options.wireframecolors", "ondark", 0xffffffff);
+        }
     }
 }
 
@@ -1312,15 +1474,20 @@ _update_snap_distances (SPDesktop *desktop)
 
     SPNamedView &nv = *desktop->namedview;
 
-    nv.grid_snapper.setDistance(sp_convert_distance_full(nv.gridtolerance,
-                                                         *nv.gridtoleranceunit,
-                                                         px));
-    nv.guide_snapper.setDistance(sp_convert_distance_full(nv.guidetolerance,
-                                                          *nv.guidetoleranceunit,
-                                                          px));
-    nv.object_snapper.setDistance(sp_convert_distance_full(nv.objecttolerance,
-                                                           *nv.objecttoleranceunit,
-                                                           px));
+    //tell all grid snappers
+    for ( GSList const *l = nv.grids; l != NULL; l = l->next) {
+        Inkscape::CanvasGrid *grid = (Inkscape::CanvasGrid*) l->data;
+        grid->snapper->setDistance(sp_convert_distance_full(nv.gridtolerance,
+                                                                      *nv.gridtoleranceunit,
+                                                                      px));
+    }
+    
+    nv.snap_manager.guide.setDistance(sp_convert_distance_full(nv.guidetolerance,
+                                                                       *nv.guidetoleranceunit,
+                                                                       px));
+    nv.snap_manager.object.setDistance(sp_convert_distance_full(nv.objecttolerance,
+                                                                        *nv.objecttoleranceunit,
+                                                                        px));
 }