Code

Split SPCanvasItem and SPCanvasGroup to individual .h files. Removed forward header.
[inkscape.git] / src / desktop.cpp
index 9a6b937c559b79fe8feb49752dd0bd778535ca92..bfde0ee9239314b859659f94579c7ab655dae924 100644 (file)
@@ -1,5 +1,3 @@
-#define __SP_DESKTOP_C__
-
 /** \file
  * Editable view implementation
  *
@@ -10,9 +8,11 @@
  *   Ralf Stephan <ralf@ark.in-berlin.de>
  *   John Bintz <jcoswell@coswellproductions.org>
  *   Johan Engelen <j.b.c.engelen@ewi.utwente.nl>
+ *   Jon A. Cruz <jon@joncruz.org>
+ *   Abhishek Sharma
  *
  * Copyright (C) 2007 Jon A. Cruz
- * Copyright (C) 2006-2007 Johan Engelen
+ * Copyright (C) 2006-2008 Johan Engelen
  * Copyright (C) 2006 John Bintz
  * Copyright (C) 2004 MenTaLguY
  * Copyright (C) 1999-2002 Lauris Kaplinski
@@ -57,6 +57,7 @@
 #include <sigc++/functors/mem_fun.h>
 #include <gtkmm.h>
 
+#include <2geom/rect.h>
 #include "macros.h"
 #include "inkscape-private.h"
 #include "desktop.h"
@@ -69,7 +70,7 @@
 #include "sp-namedview.h"
 #include "color.h"
 #include "sp-item-group.h"
-#include "prefs-utils.h"
+#include "preferences.h"
 #include "object-hierarchy.h"
 #include "helper/units.h"
 #include "display/canvas-arena.h"
 #include "display/gnome-canvas-acetate.h"
 #include "display/sodipodi-ctrlrect.h"
 #include "display/sp-canvas-util.h"
-#include "libnr/nr-matrix-div.h"
-#include "libnr/nr-rect-ops.h"
+#include "display/canvas-temporary-item-list.h"
+#include "display/snap-indicator.h"
+#include "display/sp-canvas-group.h"
 #include "ui/dialog/dialog-manager.h"
 #include "xml/repr.h"
 #include "message-context.h"
+#include "device-manager.h"
+#include "layer-fns.h"
 #include "layer-manager.h"
 #include "event-log.h"
 #include "display/canvas-grid.h"
+#include "widgets/desktop-widget.h"
+#include "box3d-context.h"
+#include "desktop-style.h"
+
+// TODO those includes are only for node tool quick zoom. Remove them after fixing it.
+#include "ui/tool/node-tool.h"
+#include "ui/tool/control-point-selection.h"
 
 #include "display/sp-canvas.h"
 
@@ -99,7 +110,6 @@ static void _layer_hierarchy_changed(SPObject *top, SPObject *bottom, SPDesktop
 static void _reconstruction_start(SPDesktop * desktop);
 static void _reconstruction_finish(SPDesktop * desktop);
 static void _namedview_modified (SPObject *obj, guint flags, SPDesktop *desktop);
-static void _update_snap_distances (SPDesktop *desktop);
 
 /**
  * Return new desktop object.
@@ -114,6 +124,8 @@ SPDesktop::SPDesktop() :
     event_context( 0 ),
     layer_manager( 0 ),
     event_log( 0 ),
+    temporary_item_list( 0 ),
+    snapindicator( 0 ),
     acetate( 0 ),
     main( 0 ),
     gridgroup( 0 ),
@@ -121,10 +133,12 @@ SPDesktop::SPDesktop() :
     drawing( 0 ),
     sketch( 0 ),
     controls( 0 ),
+    tempgroup ( 0 ),
     table( 0 ),
     page( 0 ),
     page_border( 0 ),
     current( 0 ),
+    _focusMode(false),
     zooms_past( 0 ),
     zooms_future( 0 ),
     dkey( 0 ),
@@ -139,39 +153,46 @@ SPDesktop::SPDesktop() :
     gr_fill_or_stroke( true ),
     _layer_hierarchy( 0 ),
     _reconstruction_old_layer_id( 0 ),
+    _display_mode(Inkscape::RENDERMODE_NORMAL),
     _widget( 0 ),
     _inkscape( 0 ),
     _guides_message_context( 0 ),
     _active( false ),
     _w2d(),
     _d2w(),
-    _doc2dt( NR::Matrix(NR::scale(1, -1)) ),
+    _doc2dt( Geom::Scale(1, -1) ),
     grids_visible( false )
 {
-    _d2w.set_identity();
-    _w2d.set_identity();
+    _d2w.setIdentity();
+    _w2d.setIdentity();
 
     selection = Inkscape::GC::release( new Inkscape::Selection(this) );
 }
 
 void
-SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas)
+SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas, Inkscape::UI::View::EditWidgetInterface *widget)
 {
+    _widget = widget;
+
+    // Temporary workaround for link order issues:
+    Inkscape::DeviceManager::getManager().getDevices();
+    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+
     _guides_message_context = new Inkscape::MessageContext(const_cast<Inkscape::MessageStack*>(messageStack()));
 
-    current = sp_repr_css_attr_inherited (inkscape_get_repr (INKSCAPE, "desktop"), "style");
+    current = prefs->getStyle("/desktop/style");
 
     namedview = nv;
     canvas = aCanvas;
 
     SPDocument *document = SP_OBJECT_DOCUMENT (namedview);
     /* Kill flicker */
-    sp_document_ensure_up_to_date (document);
+    document->ensureUpToDate();
 
     /* Setup Dialog Manager */
-    _dlg_mgr = new Inkscape::UI::Dialog::DialogManager();
+    _dlg_mgr = &Inkscape::UI::Dialog::DialogManager::getInstance();
 
-    dkey = sp_item_display_key_new (1);
+    dkey = SPItem::display_key_new(1);
 
     /* Connect document */
     setDocument (document);
@@ -191,7 +212,7 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas)
     g_signal_connect (G_OBJECT (main), "event", G_CALLBACK (sp_desktop_root_handler), this);
 
     table = sp_canvas_item_new (main, SP_TYPE_CTRLRECT, NULL);
-    SP_CTRLRECT(table)->setRectangle(NR::Rect(NR::Point(-80000, -80000), NR::Point(80000, 80000)));
+    SP_CTRLRECT(table)->setRectangle(Geom::Rect(Geom::Point(-80000, -80000), Geom::Point(80000, 80000)));
     SP_CTRLRECT(table)->setColor(0x00000000, true, 0x00000000);
     sp_canvas_item_move_to_z (table, 0);
 
@@ -202,9 +223,9 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas)
     drawing = sp_canvas_item_new (main, SP_TYPE_CANVAS_ARENA, NULL);
     g_signal_connect (G_OBJECT (drawing), "arena_event", G_CALLBACK (_arena_handler), this);
 
-    SP_CANVAS_ARENA (drawing)->arena->delta = prefs_get_double_attribute ("options.cursortolerance", "value", 1.0); // default is 1 px
+    SP_CANVAS_ARENA (drawing)->arena->delta = prefs->getDouble("/options/cursortolerance/value", 1.0); // default is 1 px
 
-    if (prefs_get_int_attribute("options.startmode", "outline", 0)) {
+    if (prefs->getBool("/options/startmode/outline")) {
         // Start in outline mode
         setDisplayModeOutline();
     } else {
@@ -212,9 +233,17 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas)
         setDisplayModeNormal();
     }
 
+    // The order in which these canvas items are added determines the z-order. It's therefore
+    // important to add the tempgroup (which will contain the snapindicator) before adding the
+    // controls. Only this way one will be able to quickly (before the snap indicator has
+    // disappeared) reselect a node after snapping it. If the z-order is wrong however, this
+    // will not work (the snap indicator is on top of the node handler; is the snapindicator
+    // being selected? or does it intercept some of the events that should have gone to the
+    // node handler? see bug https://bugs.launchpad.net/inkscape/+bug/414142)
     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);
+    tempgroup = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL);
     controls = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL);
 
     /* Push select tool to the bottom of stack */
@@ -223,12 +252,12 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas)
      * call "set" instead of "push".  Can we assume that there is only one
      * context ever?
      */
-    push_event_context (SP_TYPE_SELECT_CONTEXT, "tools.select", SP_EVENT_CONTEXT_STATIC);
+    push_event_context (SP_TYPE_SELECT_CONTEXT, "/tools/select", SP_EVENT_CONTEXT_STATIC);
 
     // display rect and zoom are now handled in sp_desktop_widget_realize()
 
-    NR::Rect const d(NR::Point(0.0, 0.0),
-                     NR::Point(sp_document_width(document), sp_document_height(document)));
+    Geom::Rect const d(Geom::Point(0.0, 0.0),
+                       Geom::Point(document->getWidth(), document->getHeight()));
 
     SP_CTRLRECT(page)->setRectangle(d);
     SP_CTRLRECT(page_border)->setRectangle(d);
@@ -245,18 +274,17 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas)
 
 
     /* Connect event for page resize */
-    _doc2dt[5] = sp_document_height (document);
+    _doc2dt[5] = document->getHeight();
     sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (drawing), _doc2dt);
 
     _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)),
+    NRArenaItem *ai = SP_ITEM(document->getRoot())->invoke_show(
             SP_CANVAS_ARENA (drawing)->arena,
             dkey,
             SP_ITEM_SHOW_DISPLAY);
     if (ai) {
         nr_arena_item_add_child (SP_CANVAS_ARENA (drawing)->root, ai, NULL);
-        nr_arena_item_unref (ai);
     }
 
     namedview->show(this);
@@ -308,12 +336,31 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas)
     //   (Setting up after the connections are all in place, as it may use some of them)
     layer_manager = new Inkscape::LayerManager( this );
 
-    showGrids(namedview->grids_visible);
+    showGrids(namedview->grids_visible, false);
+
+    temporary_item_list = new Inkscape::Display::TemporaryItemList( this );
+    snapindicator = new Inkscape::Display::SnapIndicator ( this );
 }
 
 
 void SPDesktop::destroy()
 {
+    if (snapindicator) {
+        delete snapindicator;
+        snapindicator = NULL;
+    }
+    if (temporary_item_list) {
+        delete temporary_item_list;
+        temporary_item_list = NULL;
+    }
+
+    if (selection) {
+        delete selection;
+        selection = NULL;
+    }
+
+    namedview->hide(this);
+
     _activate_connection.disconnect();
     _deactivate_connection.disconnect();
     _sel_modified_connection.disconnect();
@@ -336,6 +383,12 @@ void SPDesktop::destroy()
 
     if (_layer_hierarchy) {
         delete _layer_hierarchy;
+//        _layer_hierarchy = NULL; //this should be here, but commented to find other bug somewhere else.
+    }
+
+    if (layer_manager) {
+        delete layer_manager;
+        layer_manager = NULL;
     }
 
     if (_inkscape) {
@@ -343,7 +396,7 @@ void SPDesktop::destroy()
     }
 
     if (drawing) {
-        sp_item_invoke_hide (SP_ITEM (sp_document_root (doc())), dkey);
+        SP_ITEM(doc()->getRoot())->invoke_hide(dkey);
         drawing = NULL;
     }
 
@@ -359,30 +412,64 @@ SPDesktop::~SPDesktop() {}
 //--------------------------------------------------------------------
 /* Public methods */
 
-void SPDesktop::setDisplayModeNormal()
+
+/* These methods help for temporarily showing things on-canvas.
+ * The *only* valid use of the TemporaryItem* that you get from add_temporary_canvasitem
+ * is when you want to prematurely remove the item from the canvas, by calling
+ * desktop->remove_temporary_canvasitem(tempitem).
+ */
+/** Note that lifetime is measured in milliseconds
+ * One should *not* keep a reference to the SPCanvasItem, the temporary item code will
+ * delete the object for you and the reference will become invalid without you knowing it.
+ * It is perfectly safe to ignore the returned pointer: the object is deleted by itself, so don't delete it elsewhere!
+ * The *only* valid use of the returned TemporaryItem* is as argument for SPDesktop::remove_temporary_canvasitem,
+ * because the object might be deleted already without you knowing it.
+ * move_to_bottom = true by default so the item does not interfere with handling of other items on the canvas like nodes.
+ */
+Inkscape::Display::TemporaryItem *
+SPDesktop::add_temporary_canvasitem (SPCanvasItem *item, guint lifetime, bool move_to_bottom)
 {
-    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)));
+    if (move_to_bottom) {
+        sp_canvas_item_move_to_z(item, 0);
+    }
+
+    return temporary_item_list->add_item(item, lifetime);
 }
 
-void SPDesktop::setDisplayModeOutline()
+/** It is perfectly safe to call this function while the object has already been deleted due to a timeout.
+*/
+void
+SPDesktop::remove_temporary_canvasitem (Inkscape::Display::TemporaryItem * tempitem)
 {
-    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)));
+    // check for non-null temporary_item_list, because during destruction of desktop, some destructor might try to access this list!
+    if (tempitem && temporary_item_list) {
+        temporary_item_list->delete_item(tempitem);
+    }
 }
 
-void SPDesktop::displayModeToggle()
-{
-    if (displayMode == RENDERMODE_OUTLINE)
-        setDisplayModeNormal();
-    else 
-        setDisplayModeOutline();
+void SPDesktop::_setDisplayMode(Inkscape::RenderMode mode) {
+    SP_CANVAS_ARENA (drawing)->arena->rendermode = mode;
+    canvas->rendermode = mode;
+    _display_mode = mode;
+    sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (main), _d2w); // redraw
+    _widget->setTitle( sp_desktop_document(this)->getName() );
+}
+
+void SPDesktop::displayModeToggle() {
+    switch (_display_mode) {
+    case Inkscape::RENDERMODE_NORMAL:
+        _setDisplayMode(Inkscape::RENDERMODE_NO_FILTERS);
+        break;
+    case Inkscape::RENDERMODE_NO_FILTERS:
+        _setDisplayMode(Inkscape::RENDERMODE_OUTLINE);
+        break;
+    case Inkscape::RENDERMODE_OUTLINE:
+        _setDisplayMode(Inkscape::RENDERMODE_NORMAL);
+        break;
+//    case Inkscape::RENDERMODE_PRINT_COLORS_PREVIEW:
+    default:
+        _setDisplayMode(Inkscape::RENDERMODE_NORMAL);
+    }
 }
 
 /**
@@ -403,16 +490,41 @@ 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() && currentRoot()->isAncestorOf(object)) );
-    // printf("Set Layer to ID: %s\n", SP_OBJECT_ID(object));
+    // printf("Set Layer to ID: %s\n", object->getId());
     _layer_hierarchy->setBottom(object);
 }
 
+void SPDesktop::toggleLayerSolo(SPObject *object) {
+    g_return_if_fail(SP_IS_GROUP(object));
+    g_return_if_fail( currentRoot() == object || (currentRoot() && currentRoot()->isAncestorOf(object)) );
+
+    bool othersShowing = false;
+    std::vector<SPObject*> layers;
+    for ( SPObject* obj = Inkscape::next_layer(currentRoot(), object); obj; obj = Inkscape::next_layer(currentRoot(), obj) ) {
+        layers.push_back(obj);
+        othersShowing |= !SP_ITEM(obj)->isHidden();
+    }
+    for ( SPObject* obj = Inkscape::previous_layer(currentRoot(), object); obj; obj = Inkscape::previous_layer(currentRoot(), obj) ) {
+        layers.push_back(obj);
+        othersShowing |= !SP_ITEM(obj)->isHidden();
+    }
+
+
+    if ( SP_ITEM(object)->isHidden() ) {
+        SP_ITEM(object)->setHidden(false);
+    }
+
+    for ( std::vector<SPObject*>::iterator it = layers.begin(); it != layers.end(); ++it ) {
+        SP_ITEM(*it)->setHidden(othersShowing);
+    }
+}
+
 /**
  * Return layer that contains \a object.
  */
@@ -441,8 +553,8 @@ bool SPDesktop::isLayer(SPObject *object) const {
  */
 bool SPDesktop::isWithinViewport (SPItem *item) const
 {
-    NR::Rect const viewport = get_display_area();
-    NR::Maybe<NR::Rect> const bbox = sp_item_bbox_desktop(item);
+    Geom::Rect const viewport = get_display_area();
+    Geom::OptRect const bbox = item->getBboxDesktop();
     if (bbox) {
         return viewport.contains(*bbox);
     } else {
@@ -493,6 +605,17 @@ SPDesktop::change_document (SPDocument *theDocument)
     selection->clear();
 
     setDocument (theDocument);
+
+    /* update the rulers, connect the desktop widget's signal to the new namedview etc.
+       (this can probably be done in a better way) */
+    Gtk::Window *parent = this->getToplevel();
+    g_assert(parent != NULL);
+    SPDesktopWidget *dtw = (SPDesktopWidget *) parent->get_data("desktopwidget");
+    if (dtw) {
+        dtw->desktop = this;
+    }
+    dtw->updateNamedview();
+
     _namedview_modified (namedview, SP_OBJECT_MODIFIED_FLAG, this);
     _document_replaced_signal.emit (this, theDocument);
 }
@@ -507,15 +630,23 @@ SPDesktop::set_event_context (GtkType type, const gchar *config)
     while (event_context) {
         ec = event_context;
         sp_event_context_deactivate (ec);
-        event_context = ec->next;
+        // we have to keep event_context valid during destruction - otherwise writing
+        // destructors is next to impossible
+        SPEventContext *next = ec->next;
         sp_event_context_finish (ec);
         g_object_unref (G_OBJECT (ec));
+        event_context = next;
     }
 
-    Inkscape::XML::Node *repr = (config) ? inkscape_get_repr (_inkscape, config) : NULL;
-    ec = sp_event_context_new (type, this, repr, SP_EVENT_CONTEXT_STATIC);
+    // The event_context will be null. This means that it will be impossible
+    // to process any event invoked by the lines below. See for example bug
+    // LP #622350. Cutting and undoing again in the node tool resets the event
+    // context to the node tool. In this bug the line bellow invokes GDK_LEAVE_NOTIFY
+    // events which cannot be handled and must be discarded.
+    ec = sp_event_context_new (type, this, config, SP_EVENT_CONTEXT_STATIC);
     ec->next = event_context;
     event_context = ec;
+    // Now the event_context has been set again and we can process all events again
     sp_event_context_activate (ec);
     _event_context_changed_signal.emit (this, ec);
 }
@@ -527,7 +658,6 @@ void
 SPDesktop::push_event_context (GtkType type, const gchar *config, unsigned int key)
 {
     SPEventContext *ref, *ec;
-    Inkscape::XML::Node *repr;
 
     if (event_context && event_context->key == key) return;
     ref = event_context;
@@ -540,8 +670,7 @@ SPDesktop::push_event_context (GtkType type, const gchar *config, unsigned int k
     }
 
     if (event_context) sp_event_context_deactivate (event_context);
-    repr = (config) ? inkscape_get_repr (INKSCAPE, config) : NULL;
-    ec = sp_event_context_new (type, this, repr, key);
+    ec = sp_event_context_new (type, this, config, key);
     ec->next = event_context;
     event_context = ec;
     sp_event_context_activate (ec);
@@ -552,60 +681,57 @@ SPDesktop::push_event_context (GtkType type, const gchar *config, unsigned int k
  * Sets the coordinate status to a given point
  */
 void
-SPDesktop::set_coordinate_status (NR::Point p) {
+SPDesktop::set_coordinate_status (Geom::Point p) {
     _widget->setCoordinateStatus(p);
 }
 
 /**
- * \see sp_document_item_from_list_at_point_bottom()
+ * \see SPDocument::getItemFromListAtPointBottom()
  */
-SPItem *
-SPDesktop::item_from_list_at_point_bottom (const GSList *list, NR::Point const p) const
+SPItem *SPDesktop::getItemFromListAtPointBottom(const GSList *list, Geom::Point const p) const
 {
     g_return_val_if_fail (doc() != NULL, NULL);
-    return sp_document_item_from_list_at_point_bottom (dkey, SP_GROUP (doc()->root), list, p);
+    return SPDocument::getItemFromListAtPointBottom(dkey, SP_GROUP (doc()->root), list, p);
 }
 
 /**
- * \see sp_document_item_at_point()
+ * \see SPDocument::getItemAtPoint()
  */
-SPItem *
-SPDesktop::item_at_point (NR::Point const p, bool into_groups, SPItem *upto) const
+SPItem *SPDesktop::getItemAtPoint(Geom::Point const p, bool into_groups, SPItem *upto) const
 {
     g_return_val_if_fail (doc() != NULL, NULL);
-    return sp_document_item_at_point (doc(), dkey, p, into_groups, upto);
+    return doc()->getItemAtPoint( dkey, p, into_groups, upto);
 }
 
 /**
- * \see sp_document_group_at_point()
+ * \see SPDocument::getGroupAtPoint()
  */
-SPItem *
-SPDesktop::group_at_point (NR::Point const p) const
+SPItem *SPDesktop::getGroupAtPoint(Geom::Point const p) const
 {
     g_return_val_if_fail (doc() != NULL, NULL);
-    return sp_document_group_at_point (doc(), dkey, p);
+    return doc()->getGroupAtPoint(dkey, p);
 }
 
 /**
  * \brief  Returns the mouse point in document coordinates; if mouse is
  * outside the canvas, returns the center of canvas viewpoint
  */
-NR::Point
+Geom::Point
 SPDesktop::point() const
 {
-    NR::Point p = _widget->getPointer();
-    NR::Point pw = sp_canvas_window_to_world (canvas, p);
+    Geom::Point p = _widget->getPointer();
+    Geom::Point pw = sp_canvas_window_to_world (canvas, p);
     p = w2d(pw);
 
-    NR::Rect const r = canvas->getViewbox();
+    Geom::Rect const r = canvas->getViewbox();
 
-    NR::Point r0 = w2d(r.min());
-    NR::Point r1 = w2d(r.max());
+    Geom::Point r0 = w2d(r.min());
+    Geom::Point r1 = w2d(r.max());
 
-    if (p[NR::X] >= r0[NR::X] &&
-        p[NR::X] <= r1[NR::X] &&
-        p[NR::Y] >= r1[NR::Y] &&
-        p[NR::Y] <= r0[NR::Y])
+    if (p[Geom::X] >= r0[Geom::X] &&
+        p[Geom::X] <= r1[Geom::X] &&
+        p[Geom::Y] >= r1[Geom::Y] &&
+        p[Geom::Y] <= r0[Geom::Y])
     {
         return p;
     } else {
@@ -619,13 +745,13 @@ SPDesktop::point() const
 void
 SPDesktop::push_current_zoom (GList **history)
 {
-    NR::Rect const area = get_display_area();
+    Geom::Rect const area = get_display_area();
 
     NRRect *old_zoom = g_new(NRRect, 1);
-    old_zoom->x0 = area.min()[NR::X];
-    old_zoom->x1 = area.max()[NR::X];
-    old_zoom->y0 = area.min()[NR::Y];
-    old_zoom->y1 = area.max()[NR::Y];
+    old_zoom->x0 = area.min()[Geom::X];
+    old_zoom->x1 = area.max()[Geom::X];
+    old_zoom->y0 = area.min()[Geom::Y];
+    old_zoom->y1 = area.max()[Geom::Y];
     if ( *history == NULL
          || !( ( ((NRRect *) ((*history)->data))->x0 == old_zoom->x0 ) &&
                ( ((NRRect *) ((*history)->data))->x1 == old_zoom->x1 ) &&
@@ -637,7 +763,7 @@ SPDesktop::push_current_zoom (GList **history)
 }
 
 /**
- * Set viewbox.
+ * Set viewbox (x0, x1, y0 and y1 are in document pixels. Border is in screen pixels).
  */
 void
 SPDesktop::set_display_area (double x0, double y0, double x1, double y1, double border, bool log)
@@ -655,55 +781,61 @@ SPDesktop::set_display_area (double x0, double y0, double x1, double y1, double
     double const cx = 0.5 * (x0 + x1);
     double const cy = 0.5 * (y0 + y1);
 
-    NR::Rect const viewbox = NR::expand(canvas->getViewbox(), border);
+    // FIXME: This 2geom idiom doesn't allow us to declare dbox const
+    Geom::Rect viewbox = canvas->getViewbox();
+    viewbox.expandBy(-border);
 
-    double scale = expansion(_d2w);
+    double scale = _d2w.descrim();
     double newscale;
-    if (((x1 - x0) * viewbox.dimensions()[NR::Y]) > ((y1 - y0) * viewbox.dimensions()[NR::X])) {
-        newscale = viewbox.dimensions()[NR::X] / (x1 - x0);
+    if (((x1 - x0) * viewbox.dimensions()[Geom::Y]) > ((y1 - y0) * viewbox.dimensions()[Geom::X])) {
+        newscale = viewbox.dimensions()[Geom::X] / (x1 - x0);
     } else {
-        newscale = viewbox.dimensions()[NR::Y] / (y1 - y0);
+        newscale = viewbox.dimensions()[Geom::Y] / (y1 - y0);
     }
 
-    newscale = CLAMP(newscale, SP_DESKTOP_ZOOM_MIN, SP_DESKTOP_ZOOM_MAX);
+    newscale = CLAMP(newscale, SP_DESKTOP_ZOOM_MIN, SP_DESKTOP_ZOOM_MAX); // unit: 'screen pixels' per 'document pixels'
 
     int clear = FALSE;
     if (!NR_DF_TEST_CLOSE (newscale, scale, 1e-4 * scale)) {
-        /* Set zoom factors */
-        _d2w = NR::Matrix(NR::scale(newscale, -newscale));
-        _w2d = NR::Matrix(NR::scale(1/newscale, 1/-newscale));
+        // zoom changed - set new zoom factors
+        _d2w = Geom::Scale(newscale, -newscale);
+        _w2d = Geom::Scale(1/newscale, 1/-newscale);
         sp_canvas_item_affine_absolute(SP_CANVAS_ITEM(main), _d2w);
         clear = TRUE;
+        signal_zoom_changed.emit(_d2w.descrim());
     }
 
-    /* Calculate top left corner */
-    x0 = cx - 0.5 * viewbox.dimensions()[NR::X] / newscale;
-    y1 = cy + 0.5 * viewbox.dimensions()[NR::Y] / newscale;
+    /* Calculate top left corner (in document pixels) */
+    x0 = cx - 0.5 * viewbox.dimensions()[Geom::X] / newscale;
+    y1 = cy + 0.5 * viewbox.dimensions()[Geom::Y] / newscale;
 
     /* Scroll */
     sp_canvas_scroll_to (canvas, x0 * newscale - border, y1 * -newscale - border, clear);
 
+    /*  update perspective lines if we are in the 3D box tool (so that infinite ones are shown correctly) */
+    sp_box3d_context_update_lines(event_context);
+
     _widget->updateRulers();
-    _widget->updateScrollbars(expansion(_d2w));
+    _widget->updateScrollbars(_d2w.descrim());
     _widget->updateZoom();
 }
 
-void SPDesktop::set_display_area(NR::Rect const &a, NR::Coord b, bool log)
+void SPDesktop::set_display_area(Geom::Rect const &a, Geom::Coord b, bool log)
 {
-    set_display_area(a.min()[NR::X], a.min()[NR::Y], a.max()[NR::X], a.max()[NR::Y], b, log);
+    set_display_area(a.min()[Geom::X], a.min()[Geom::Y], a.max()[Geom::X], a.max()[Geom::Y], b, log);
 }
 
 /**
  * Return viewbox dimensions.
  */
-NR::Rect SPDesktop::get_display_area() const
+Geom::Rect SPDesktop::get_display_area() const
 {
-    NR::Rect const viewbox = canvas->getViewbox();
+    Geom::Rect const viewbox = canvas->getViewbox();
 
     double const scale = _d2w[0];
 
-    return NR::Rect(NR::Point(viewbox.min()[NR::X] / scale, viewbox.max()[NR::Y] / -scale),
-                    NR::Point(viewbox.max()[NR::X] / scale, viewbox.min()[NR::Y] / -scale));
+    return Geom::Rect(Geom::Point(viewbox.min()[Geom::X] / scale, viewbox.max()[Geom::Y] / -scale),
+                      Geom::Point(viewbox.max()[Geom::X] / scale, viewbox.min()[Geom::Y] / -scale));
 }
 
 /**
@@ -756,6 +888,57 @@ SPDesktop::next_zoom()
     zooms_future = g_list_remove (zooms_future, ((NRRect *) zooms_future->data));
 }
 
+/** \brief  Performs a quick zoom into what the user is working on
+    \param  enable  Whether we're going in or out of quick zoom
+
+*/
+void
+SPDesktop::zoom_quick (bool enable)
+{
+    if (enable == _quick_zoom_enabled) {
+        return;
+    }
+
+    if (enable == true) {
+        _quick_zoom_stored_area = get_display_area();
+        bool zoomed = false;
+
+        // TODO This needs to migrate into the node tool, but currently the design
+        // of this method is sufficiently wrong to prevent this.
+        if (!zoomed && INK_IS_NODE_TOOL(event_context)) {
+            InkNodeTool *nt = static_cast<InkNodeTool*>(event_context);
+            if (!nt->_selected_nodes->empty()) {
+                Geom::Rect nodes = *nt->_selected_nodes->bounds();
+                double area = nodes.area();
+                // do not zoom if a single cusp node is selected aand the bounds
+                // have zero area.
+                if (!Geom::are_near(area, 0) && area * 2.0 < _quick_zoom_stored_area.area()) {
+                    set_display_area(nodes, true);
+                    zoomed = true;
+                }
+            }
+        }
+
+        if (!zoomed) {
+            Geom::OptRect const d = selection->bounds();
+            if (d && d->area() * 2.0 < _quick_zoom_stored_area.area()) {
+                set_display_area(*d, true);
+                zoomed = true;
+            }
+        }
+
+        if (!zoomed) {
+            zoom_relative(_quick_zoom_stored_area.midpoint()[Geom::X], _quick_zoom_stored_area.midpoint()[Geom::Y], 2.0);
+            zoomed = true;
+        }
+    } else {
+        set_display_area(_quick_zoom_stored_area, false);
+    }
+
+    _quick_zoom_enabled = enable;
+    return;
+}
+
 /**
  * Zoom to point with absolute zoom factor.
  */
@@ -767,13 +950,13 @@ SPDesktop::zoom_absolute_keep_point (double cx, double cy, double px, double py,
     // maximum or minimum zoom reached, but there's no exact equality because of rounding errors;
     // this check prevents "sliding" when trying to zoom in at maximum zoom;
     /// \todo someone please fix calculations properly and remove this hack
-    if (fabs(expansion(_d2w) - zoom) < 0.0001*zoom && (fabs(SP_DESKTOP_ZOOM_MAX - zoom) < 0.01 || fabs(SP_DESKTOP_ZOOM_MIN - zoom) < 0.000001))
+    if (fabs(_d2w.descrim() - zoom) < 0.0001*zoom && (fabs(SP_DESKTOP_ZOOM_MAX - zoom) < 0.01 || fabs(SP_DESKTOP_ZOOM_MIN - zoom) < 0.000001))
         return;
 
-    NR::Rect const viewbox = canvas->getViewbox();
+    Geom::Rect const viewbox = canvas->getViewbox();
 
-    double const width2 = viewbox.dimensions()[NR::X] / zoom;
-    double const height2 = viewbox.dimensions()[NR::Y] / zoom;
+    double const width2 = viewbox.dimensions()[Geom::X] / zoom;
+    double const height2 = viewbox.dimensions()[Geom::Y] / zoom;
 
     set_display_area(cx - px * width2,
                      cy - py * height2,
@@ -782,6 +965,26 @@ SPDesktop::zoom_absolute_keep_point (double cx, double cy, double px, double py,
                      0.0);
 }
 
+/**
+  * Apply the desktop's current style or the tool style to the object.
+  */
+void SPDesktop::applyCurrentOrToolStyle(SPObject *obj, Glib::ustring const &tool_path, bool with_text)
+{
+    SPCSSAttr *css_current = sp_desktop_get_style(this, with_text);
+    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+
+    if (prefs->getBool(tool_path + "/usecurrent") && css_current) {
+        obj->setCSS(css_current,"style");
+    } else {
+        SPCSSAttr *css = prefs->getInheritedStyle(tool_path + "/style");
+        obj->setCSS(css,"style");
+        sp_repr_css_attr_unref(css);
+    }
+    if (css_current) {
+        sp_repr_css_attr_unref(css_current);
+    }
+}
+
 /**
  * Zoom to center with absolute zoom factor.
  */
@@ -797,24 +1000,24 @@ SPDesktop::zoom_absolute (double cx, double cy, double zoom)
 void
 SPDesktop::zoom_relative_keep_point (double cx, double cy, double zoom)
 {
-    NR::Rect const area = get_display_area();
+    Geom::Rect const area = get_display_area();
 
-    if (cx < area.min()[NR::X]) {
-        cx = area.min()[NR::X];
+    if (cx < area.min()[Geom::X]) {
+        cx = area.min()[Geom::X];
     }
-    if (cx > area.max()[NR::X]) {
-        cx = area.max()[NR::X];
+    if (cx > area.max()[Geom::X]) {
+        cx = area.max()[Geom::X];
     }
-    if (cy < area.min()[NR::Y]) {
-        cy = area.min()[NR::Y];
+    if (cy < area.min()[Geom::Y]) {
+        cy = area.min()[Geom::Y];
     }
-    if (cy > area.max()[NR::Y]) {
-        cy = area.max()[NR::Y];
+    if (cy > area.max()[Geom::Y]) {
+        cy = area.max()[Geom::Y];
     }
 
-    gdouble const scale = expansion(_d2w) * zoom;
-    double const px = (cx - area.min()[NR::X]) / area.dimensions()[NR::X];
-    double const py = (cy - area.min()[NR::Y]) / area.dimensions()[NR::Y];
+    gdouble const scale = _d2w.descrim() * zoom;
+    double const px = (cx - area.min()[Geom::X]) / area.dimensions()[Geom::X];
+    double const py = (cy - area.min()[Geom::Y]) / area.dimensions()[Geom::Y];
 
     zoom_absolute_keep_point(cx, cy, px, py, scale);
 }
@@ -825,7 +1028,7 @@ SPDesktop::zoom_relative_keep_point (double cx, double cy, double zoom)
 void
 SPDesktop::zoom_relative (double cx, double cy, double zoom)
 {
-    gdouble scale = expansion(_d2w) * zoom;
+    gdouble scale = _d2w.descrim() * zoom;
     zoom_absolute (cx, cy, scale);
 }
 
@@ -835,10 +1038,10 @@ SPDesktop::zoom_relative (double cx, double cy, double zoom)
 void
 SPDesktop::zoom_page()
 {
-    NR::Rect d(NR::Point(0, 0),
-               NR::Point(sp_document_width(doc()), sp_document_height(doc())));
+    Geom::Rect d(Geom::Point(0, 0),
+                 Geom::Point(doc()->getWidth(), doc()->getHeight()));
 
-    if (d.isEmpty(1.0)) {
+    if (d.minExtent() < 1.0) {
         return;
     }
 
@@ -851,14 +1054,14 @@ SPDesktop::zoom_page()
 void
 SPDesktop::zoom_page_width()
 {
-    NR::Rect const a = get_display_area();
+    Geom::Rect const a = get_display_area();
 
-    if (sp_document_width(doc()) < 1.0) {
+    if (doc()->getWidth() < 1.0) {
         return;
     }
 
-    NR::Rect d(NR::Point(0, a.midpoint()[NR::Y]),
-               NR::Point(sp_document_width(doc()), a.midpoint()[NR::Y]));
+    Geom::Rect d(Geom::Point(0, a.midpoint()[Geom::Y]),
+                 Geom::Point(doc()->getWidth(), a.midpoint()[Geom::Y]));
 
     set_display_area(d, 10);
 }
@@ -869,9 +1072,9 @@ SPDesktop::zoom_page_width()
 void
 SPDesktop::zoom_selection()
 {
-    NR::Maybe<NR::Rect> const d = selection->bounds();
+    Geom::OptRect const d = selection->bounds();
 
-    if ( !d || d->isEmpty(0.1) ) {
+    if ( !d || d->minExtent() < 0.1 ) {
         return;
     }
 
@@ -894,21 +1097,31 @@ void
 SPDesktop::zoom_drawing()
 {
     g_return_if_fail (doc() != NULL);
-    SPItem *docitem = SP_ITEM (sp_document_root (doc()));
+    SPItem *docitem = SP_ITEM(doc()->getRoot());
     g_return_if_fail (docitem != NULL);
 
-    NR::Maybe<NR::Rect> d = sp_item_bbox_desktop(docitem);
+    Geom::OptRect d = docitem->getBboxDesktop();
 
     /* Note that the second condition here indicates that
     ** there are no items in the drawing.
     */
-    if ( !d || d->isEmpty(1.0) ) {
+    if ( !d || d->minExtent() < 0.1 ) {
         return;
     }
 
     set_display_area(*d, 10);
 }
 
+/**
+ * Scroll canvas by specific coordinate amount in svg coordinates.
+ */
+void
+SPDesktop::scroll_world_in_svg_coords (double dx, double dy, bool is_scrolling)
+{
+    double scale = _d2w.descrim();
+    scroll_world(dx*scale, dy*scale, is_scrolling);
+}
+
 /**
  * Scroll canvas by specific coordinate amount.
  */
@@ -917,50 +1130,59 @@ SPDesktop::scroll_world (double dx, double dy, bool is_scrolling)
 {
     g_assert(_widget);
 
-    NR::Rect const viewbox = canvas->getViewbox();
+    Geom::Rect const viewbox = canvas->getViewbox();
+
+    sp_canvas_scroll_to(canvas, viewbox.min()[Geom::X] - dx, viewbox.min()[Geom::Y] - dy, FALSE, is_scrolling);
 
-    sp_canvas_scroll_to(canvas, viewbox.min()[NR::X] - dx, viewbox.min()[NR::Y] - dy, FALSE, is_scrolling);
+    /*  update perspective lines if we are in the 3D box tool (so that infinite ones are shown correctly) */
+    sp_box3d_context_update_lines(event_context);
 
     _widget->updateRulers();
-    _widget->updateScrollbars(expansion(_d2w));
+    _widget->updateScrollbars(_d2w.descrim());
 }
 
 bool
-SPDesktop::scroll_to_point (NR::Point const *p, gdouble autoscrollspeed)
+SPDesktop::scroll_to_point (Geom::Point const &p, gdouble autoscrollspeed)
 {
-    gdouble autoscrolldistance = (gdouble) prefs_get_int_attribute_limited ("options.autoscrolldistance", "value", 0, -1000, 10000);
+    using Geom::X;
+    using Geom::Y;
+
+    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+    gdouble autoscrolldistance = (gdouble) prefs->getIntLimited("/options/autoscrolldistance/value", 0, -1000, 10000);
 
     // autoscrolldistance is in screen pixels, but the display area is in document units
-    autoscrolldistance /= expansion(_d2w);
-    NR::Rect const dbox = NR::expand(get_display_area(), -autoscrolldistance);
+    autoscrolldistance /= _d2w.descrim();
+    // FIXME: This 2geom idiom doesn't allow us to declare dbox const
+    Geom::Rect dbox = get_display_area();
+    dbox.expandBy(-autoscrolldistance);
 
-    if (!((*p)[NR::X] > dbox.min()[NR::X] && (*p)[NR::X] < dbox.max()[NR::X]) ||
-        !((*p)[NR::Y] > dbox.min()[NR::Y] && (*p)[NR::Y] < dbox.max()[NR::Y])   ) {
+    if (!(p[X] > dbox.min()[X] && p[X] < dbox.max()[X]) ||
+        !(p[Y] > dbox.min()[Y] && p[Y] < dbox.max()[Y])   ) {
 
-        NR::Point const s_w( (*p) * _d2w );
+        Geom::Point const s_w( p * (Geom::Matrix)_d2w );
 
         gdouble x_to;
-        if ((*p)[NR::X] < dbox.min()[NR::X])
-            x_to = dbox.min()[NR::X];
-        else if ((*p)[NR::X] > dbox.max()[NR::X])
-            x_to = dbox.max()[NR::X];
+        if (p[X] < dbox.min()[X])
+            x_to = dbox.min()[X];
+        else if (p[X] > dbox.max()[X])
+            x_to = dbox.max()[X];
         else
-            x_to = (*p)[NR::X];
+            x_to = p[X];
 
         gdouble y_to;
-        if ((*p)[NR::Y] < dbox.min()[NR::Y])
-            y_to = dbox.min()[NR::Y];
-        else if ((*p)[NR::Y] > dbox.max()[NR::Y])
-            y_to = dbox.max()[NR::Y];
+        if (p[Y] < dbox.min()[Y])
+            y_to = dbox.min()[Y];
+        else if (p[Y] > dbox.max()[Y])
+            y_to = dbox.max()[Y];
         else
-            y_to = (*p)[NR::Y];
+            y_to = p[Y];
 
-        NR::Point const d_dt(x_to, y_to);
-        NR::Point const d_w( d_dt * _d2w );
-        NR::Point const moved_w( d_w - s_w );
+        Geom::Point const d_dt(x_to, y_to);
+        Geom::Point const d_w( d_dt * _d2w );
+        Geom::Point const moved_w( d_w - s_w );
 
         if (autoscrollspeed == 0)
-            autoscrollspeed = prefs_get_double_attribute_limited ("options.autoscrollspeed", "value", 1, 0, 10);
+            autoscrollspeed = prefs->getDoubleLimited("/options/autoscrollspeed/value", 1, 0, 10);
 
         if (autoscrollspeed != 0)
             scroll_world (autoscrollspeed * moved_w);
@@ -1006,6 +1228,33 @@ SPDesktop::fullscreen()
     _widget->setFullscreen();
 }
 
+/** \brief  Checks to see if the user is working in focused mode
+
+    Returns the value of \c _focusMode
+*/
+bool
+SPDesktop::is_focusMode()
+{
+    return _focusMode;
+}
+
+/** \brief  Changes whether the user is in focus mode or not
+    \param  mode  Which mode the view should be in
+
+*/
+void
+SPDesktop::focusMode (bool mode)
+{
+    if (mode == _focusMode) { return; }
+
+    _focusMode = mode;
+
+    layoutWidget();
+    //sp_desktop_widget_layout(SPDesktopWidget);
+
+    return;
+}
+
 void
 SPDesktop::getWindowGeometry (gint &x, gint &y, gint &w, gint &h)
 {
@@ -1013,7 +1262,7 @@ SPDesktop::getWindowGeometry (gint &x, gint &y, gint &w, gint &h)
 }
 
 void
-SPDesktop::setWindowPosition (NR::Point p)
+SPDesktop::setWindowPosition (Geom::Point p)
 {
     _widget->setPosition (p);
 }
@@ -1080,9 +1329,11 @@ SPDesktop::shutdown()
 
 bool SPDesktop::onDeleteUI (GdkEventAny*)
 {
-       if(shutdown()) return true;
-       destroyWidget();
-       return false;
+    if(shutdown())
+        return true;
+
+    destroyWidget();
+    return false;
 }
 
 /**
@@ -1095,7 +1346,7 @@ bool SPDesktop::onDeleteUI (GdkEventAny*)
 bool
 SPDesktop::onWindowStateEvent (GdkEventWindowState* event)
 {
-       // Record the desktop window's state
+    // Record the desktop window's state
     window_state = event->new_window_state;
 
     // Layout may differ depending on full-screen mode or not
@@ -1103,8 +1354,8 @@ SPDesktop::onWindowStateEvent (GdkEventWindowState* event)
     if (changed & (GDK_WINDOW_STATE_FULLSCREEN|GDK_WINDOW_STATE_MAXIMIZED)) {
         layoutWidget();
     }
-       
-       return false;
+
+    return false;
 }
 
 void
@@ -1134,14 +1385,14 @@ SPDesktop::isToolboxButtonActive (gchar const *id)
 void
 SPDesktop::emitToolSubselectionChanged(gpointer data)
 {
-       _tool_subselection_changed.emit(data);
-       inkscape_subselection_changed (this);
+    _tool_subselection_changed.emit(data);
+    inkscape_subselection_changed (this);
 }
 
 void
 SPDesktop::updateNow()
 {
-  sp_canvas_update_now(canvas);
+    sp_canvas_update_now(canvas);
 }
 
 void
@@ -1160,14 +1411,9 @@ 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);
+    // GDK needs the flush for the cursor change to take effect
+    gdk_flush();
     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()
@@ -1176,6 +1422,11 @@ void SPDesktop::clearWaitingCursor()
       sp_event_context_update_cursor(sp_desktop_event_context(this));
 }
 
+void SPDesktop::toggleColorProfAdjust()
+{
+    _widget->toggleColorProfAdjust();
+}
+
 void SPDesktop::toggleGrids()
 {
     if (namedview->grids) {
@@ -1184,16 +1435,15 @@ void SPDesktop::toggleGrids()
         }
     } 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);
+        namedview->writeNewGrid(sp_desktop_document(this), Inkscape::GRID_RECTANGULAR);
         showGrids(true);
     }
 }
 
-void SPDesktop::showGrids(bool show)
+void SPDesktop::showGrids(bool show, bool dirty_document)
 {
     grids_visible = show;
-    sp_namedview_show_grids(namedview, grids_visible);
+    sp_namedview_show_grids(namedview, grids_visible, dirty_document);
     if (show) {
         sp_canvas_item_show(SP_CANVAS_ITEM(gridgroup));
     } else {
@@ -1201,6 +1451,11 @@ void SPDesktop::showGrids(bool show)
     }
 }
 
+void SPDesktop::toggleSnapGlobal()
+{
+    bool v = namedview->getSnapGlobal();
+    namedview->setSnapGlobal(!v);
+}
 
 //----------------------------------------------------------------------
 // Callback implementations. The virtual ones are connected by the view.
@@ -1208,11 +1463,11 @@ void SPDesktop::showGrids(bool show)
 void
 SPDesktop::onPositionSet (double x, double y)
 {
-    _widget->viewSetPosition (NR::Point(x,y));
+    _widget->viewSetPosition (Geom::Point(x,y));
 }
 
 void
-SPDesktop::onResized (double x, double y)
+SPDesktop::onResized (double /*x*/, double /*y*/)
 {
    // Nothing called here
 }
@@ -1242,7 +1497,7 @@ SPDesktop::setDocument (SPDocument *doc)
 {
     if (this->doc() && doc) {
         namedview->hide(this);
-        sp_item_invoke_hide (SP_ITEM (sp_document_root (this->doc())), dkey);
+        SP_ITEM(this->doc()->getRoot())->invoke_hide(dkey);
     }
 
     if (_layer_hierarchy) {
@@ -1253,7 +1508,7 @@ SPDesktop::setDocument (SPDocument *doc)
     _layer_hierarchy->connectAdded(sigc::bind(sigc::ptr_fun(_layer_activated), this));
     _layer_hierarchy->connectRemoved(sigc::bind(sigc::ptr_fun(_layer_deactivated), this));
     _layer_hierarchy->connectChanged(sigc::bind(sigc::ptr_fun(_layer_hierarchy_changed), this));
-    _layer_hierarchy->setTop(SP_DOCUMENT_ROOT(doc));
+    _layer_hierarchy->setTop(doc->getRoot());
 
     /* setup EventLog */
     event_log = new Inkscape::EventLog(doc);
@@ -1273,13 +1528,12 @@ SPDesktop::setDocument (SPDocument *doc)
         _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(doc->getRoot())->invoke_show(
                 SP_CANVAS_ARENA (drawing)->arena,
                 dkey,
                 SP_ITEM_SHOW_DISPLAY);
         if (ai) {
             nr_arena_item_add_child (SP_CANVAS_ARENA (drawing)->root, ai, NULL);
-            nr_arena_item_unref (ai);
         }
         namedview->show(this);
         /* Ugly hack */
@@ -1316,7 +1570,7 @@ SPDesktop::onDocumentResized (gdouble width, gdouble height)
 {
     _doc2dt[5] = height;
     sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (drawing), _doc2dt);
-    NR::Rect const a(NR::Point(0, 0), NR::Point(width, height));
+    Geom::Rect const a(Geom::Point(0, 0), Geom::Point(width, height));
     SP_CTRLRECT(page)->setRectangle(a);
     SP_CTRLRECT(page_border)->setRectangle(a);
 }
@@ -1338,10 +1592,10 @@ SPDesktop::_onDeactivate (SPDesktop* dt)
 
 void
 SPDesktop::_onSelectionModified
-(Inkscape::Selection *selection, guint flags, SPDesktop *dt)
+(Inkscape::Selection */*selection*/, guint /*flags*/, SPDesktop *dt)
 {
     if (!dt->_widget) return;
-    dt->_widget->updateScrollbars (expansion(dt->_d2w));
+    dt->_widget->updateScrollbars (dt->_d2w.descrim());
 }
 
 static void
@@ -1368,7 +1622,7 @@ _onSelectionChanged
  * \todo fixme
  */
 static gint
-_arena_handler (SPCanvasArena *arena, NRArenaItem *ai, GdkEvent *event, SPDesktop *desktop)
+_arena_handler (SPCanvasArena */*arena*/, NRArenaItem *ai, GdkEvent *event, SPDesktop *desktop)
 {
     if (ai) {
         SPItem *spi = (SPItem*)NR_ARENA_ITEM_GET_DATA (ai);
@@ -1393,7 +1647,7 @@ _layer_deactivated(SPObject *layer, SPDesktop *desktop) {
 
 /// Callback
 static void
-_layer_hierarchy_changed(SPObject *top, SPObject *bottom,
+_layer_hierarchy_changed(SPObject */*top*/, SPObject *bottom,
                                          SPDesktop *desktop)
 {
     desktop->_layer_changed_signal.emit (bottom);
@@ -1404,7 +1658,7 @@ static void
 _reconstruction_start (SPDesktop * desktop)
 {
     // printf("Desktop, starting reconstruction\n");
-    desktop->_reconstruction_old_layer_id = g_strdup(SP_OBJECT_ID(desktop->currentLayer()));
+    desktop->_reconstruction_old_layer_id = g_strdup(desktop->currentLayer()->getId());
     desktop->_layer_hierarchy->setBottom(desktop->currentRoot());
 
     /*
@@ -1446,12 +1700,6 @@ _namedview_modified (SPObject *obj, guint flags, SPDesktop *desktop)
 
     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 */
         if (nv->pagecolor & 0xff) {
             sp_canvas_item_show (desktop->table);
@@ -1477,7 +1725,7 @@ _namedview_modified (SPObject *obj, guint flags, SPDesktop *desktop)
                 int order = sp_canvas_item_order (desktop->page_border);
                 int morder = sp_canvas_item_order (desktop->drawing);
                 if (morder > order) sp_canvas_item_raise (desktop->page_border,
-                                   morder - order);
+                    morder - order);
             }
         } else {
                 sp_canvas_item_hide (desktop->page_border);
@@ -1485,7 +1733,7 @@ _namedview_modified (SPObject *obj, guint flags, SPDesktop *desktop)
                     ((CtrlRect *) desktop->page)->setShadow(0, 0x00000000);
                 }
         }
-       
+
         /* Show/hide page shadow */
         if (nv->showpageshadow && nv->pageshadow) {
             ((CtrlRect *) desktop->page_border)->setShadow(nv->pageshadow, nv->bordercolor);
@@ -1493,77 +1741,57 @@ _namedview_modified (SPObject *obj, guint flags, SPDesktop *desktop)
             ((CtrlRect *) desktop->page_border)->setShadow(0, 0x00000000);
         }
 
+        Inkscape::Preferences *prefs = Inkscape::Preferences::get();
         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) {
             // the background color is light or transparent, use black outline
-            SP_CANVAS_ARENA (desktop->drawing)->arena->outlinecolor = prefs_get_int_attribute("options.wireframecolors", "onlight", 0xff);
+            SP_CANVAS_ARENA (desktop->drawing)->arena->outlinecolor = prefs->getInt("/options/wireframecolors/onlight", 0xff);
         } else { // use white outline
-            SP_CANVAS_ARENA (desktop->drawing)->arena->outlinecolor = prefs_get_int_attribute("options.wireframecolors", "ondark", 0xffffffff);
+            SP_CANVAS_ARENA (desktop->drawing)->arena->outlinecolor = prefs->getInt("/options/wireframecolors/ondark", 0xffffffff);
         }
     }
 }
 
-/**
- * Callback to reset snapper's distances.
- */
-static void
-_update_snap_distances (SPDesktop *desktop)
-{
-    SPUnit const &px = sp_unit_get_by_id(SP_UNIT_PX);
-
-    SPNamedView &nv = *desktop->namedview;
-
-    //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));
-}
-
-
-NR::Matrix SPDesktop::w2d() const
+Geom::Matrix SPDesktop::w2d() const
 {
     return _w2d;
 }
 
-NR::Point SPDesktop::w2d(NR::Point const &p) const
+Geom::Point SPDesktop::w2d(Geom::Point const &p) const
 {
     return p * _w2d;
 }
 
-NR::Point SPDesktop::d2w(NR::Point const &p) const
+Geom::Point SPDesktop::d2w(Geom::Point const &p) const
 {
     return p * _d2w;
 }
 
-NR::Matrix SPDesktop::doc2dt() const
+Geom::Matrix SPDesktop::doc2dt() const
+{
+    return _doc2dt;
+}
+
+Geom::Matrix SPDesktop::dt2doc() const
 {
+    // doc2dt is its own inverse
     return _doc2dt;
 }
 
-NR::Point SPDesktop::doc2dt(NR::Point const &p) const
+Geom::Point SPDesktop::doc2dt(Geom::Point const &p) const
 {
     return p * _doc2dt;
 }
 
-NR::Point SPDesktop::dt2doc(NR::Point const &p) const
+Geom::Point SPDesktop::dt2doc(Geom::Point const &p) const
 {
-    return p / _doc2dt;
+    return p * dt2doc();
 }
 
 
-/**
+/*
  * Pop event context from desktop's context stack. Never used.
  */
 // void
@@ -1605,4 +1833,4 @@ NR::Point SPDesktop::dt2doc(NR::Point const &p) const
   fill-column:99
   End:
 */
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :