diff --git a/src/GUI/CMakeLists.txt b/src/GUI/CMakeLists.txt
index d3bf72bdb..469117e4f 100644
--- a/src/GUI/CMakeLists.txt
+++ b/src/GUI/CMakeLists.txt
@@ -20,6 +20,7 @@ set(SOURCES
 	FGColor.cxx
     FileDialog.cxx
     PUIFileDialog.cxx
+    MouseCursor.cxx
 	)
 
 set(HEADERS
@@ -39,11 +40,12 @@ set(HEADERS
 	FGColor.hxx
     FileDialog.hxx
     PUIFileDialog.hxx
+    MouseCursor.hxx
 	)
     		
 if (APPLE)
-    list(APPEND HEADERS FGCocoaMenuBar.hxx CocoaFileDialog.hxx)
-    list(APPEND SOURCES FGCocoaMenuBar.mm CocoaFileDialog.mm)
+    list(APPEND HEADERS FGCocoaMenuBar.hxx CocoaFileDialog.hxx CocoaMouseCursor.hxx)
+    list(APPEND SOURCES FGCocoaMenuBar.mm CocoaFileDialog.mm CocoaMouseCursor.mm)
 endif()
     		
 flightgear_component(GUI "${SOURCES}" "${HEADERS}")
diff --git a/src/GUI/CocoaMouseCursor.hxx b/src/GUI/CocoaMouseCursor.hxx
new file mode 100644
index 000000000..6ee3483c9
--- /dev/null
+++ b/src/GUI/CocoaMouseCursor.hxx
@@ -0,0 +1,28 @@
+#ifndef FG_GUI_COCOA_MOUSE_CURSOR_HXX
+#define FG_GUI_COCOA_MOUSE_CURSOR_HXX
+
+#include <memory> // for auto_ptr
+
+#include "MouseCursor.hxx"
+
+class CocoaMouseCursor : public FGMouseCursor
+{
+public:
+    CocoaMouseCursor();
+    virtual ~CocoaMouseCursor();
+    
+    virtual void setCursor(Cursor aCursor);
+    
+    virtual void setCursorVisible(bool aVis);
+    
+    virtual void hideCursorUntilMouseMove();
+    
+    virtual void mouseMoved();
+
+private:
+    class CocoaMouseCursorPrivate;
+    std::auto_ptr<CocoaMouseCursorPrivate> d;
+};
+
+
+#endif
diff --git a/src/GUI/CocoaMouseCursor.mm b/src/GUI/CocoaMouseCursor.mm
new file mode 100644
index 000000000..7cb631c3b
--- /dev/null
+++ b/src/GUI/CocoaMouseCursor.mm
@@ -0,0 +1,93 @@
+#include "CocoaMouseCursor.hxx"
+
+#include <Cocoa/Cocoa.h>
+#include <map>
+
+#include <Main/globals.hxx>
+
+class CocoaMouseCursor::CocoaMouseCursorPrivate
+{
+public:
+    Cursor activeCursorKey;
+    
+    typedef std::map<Cursor, NSCursor*> CursorMap;
+    CursorMap cursors;
+};
+
+NSCursor* cocoaCursorForKey(FGMouseCursor::Cursor aKey)
+{
+    NSImage* img = nil;
+    
+    NSString* path = [NSString stringWithCString:globals->get_fg_root().c_str()
+                                            encoding:NSUTF8StringEncoding];
+    path = [path stringByAppendingPathComponent:@"gui"];
+    
+    switch (aKey) {
+    case FGMouseCursor::CURSOR_HAND: return [NSCursor pointingHandCursor];
+    case FGMouseCursor::CURSOR_CROSSHAIR: return [NSCursor crosshairCursor];
+    case FGMouseCursor::CURSOR_IBEAM: return [NSCursor IBeamCursor];
+    
+    // FIXME - use a proper left-right cursor here.
+    case FGMouseCursor::CURSOR_LEFT_RIGHT: return [NSCursor resizeLeftRightCursor];
+            
+    case FGMouseCursor::CURSOR_SPIN_CW:
+        path = [path stringByAppendingPathComponent:@"cursor-spin-cw.png"];
+        img = [[NSImage alloc] initWithContentsOfFile:path];
+        return [[NSCursor alloc] initWithImage:img hotSpot:NSMakePoint(16,16)];
+            
+    case FGMouseCursor::CURSOR_SPIN_CCW:
+        path = [path stringByAppendingPathComponent:@"cursor-spin-cw.png"];
+        img = [[NSImage alloc] initWithContentsOfFile:path];
+        return [[NSCursor alloc] initWithImage:img hotSpot:NSMakePoint(16,16)];
+            
+    default: return [NSCursor arrowCursor];
+    }
+
+}
+
+CocoaMouseCursor::CocoaMouseCursor() :
+    d(new CocoaMouseCursorPrivate)
+{
+    
+}
+
+CocoaMouseCursor::~CocoaMouseCursor()
+{
+    
+    
+}
+
+
+void CocoaMouseCursor::setCursor(Cursor aCursor)
+{
+    if (aCursor == d->activeCursorKey) {
+        return;
+    }
+    
+    d->activeCursorKey = aCursor;
+    if (d->cursors.find(aCursor) == d->cursors.end()) {
+        d->cursors[aCursor] = cocoaCursorForKey(aCursor);
+        [d->cursors[aCursor] retain];
+    }
+    
+    [d->cursors[aCursor] set];
+}
+
+void CocoaMouseCursor::setCursorVisible(bool aVis)
+{
+    if (aVis) {
+        [NSCursor unhide];
+    } else {
+        [NSCursor hide];
+    }
+}
+
+void CocoaMouseCursor::hideCursorUntilMouseMove()
+{
+    [NSCursor setHiddenUntilMouseMoves:YES];
+}
+
+void CocoaMouseCursor::mouseMoved()
+{
+    // no-op
+}
diff --git a/src/GUI/MouseCursor.cxx b/src/GUI/MouseCursor.cxx
new file mode 100644
index 000000000..c3c720f12
--- /dev/null
+++ b/src/GUI/MouseCursor.cxx
@@ -0,0 +1,203 @@
+#ifdef HAVE_CONFIG_H
+  #include "config.h"
+#endif
+
+#include "MouseCursor.hxx"
+
+#include <cstring>
+#include <boost/foreach.hpp>
+
+#include <osgViewer/GraphicsWindow>
+#include <osgViewer/Viewer>
+
+#include <simgear/debug/logstream.hxx>
+#include <simgear/simgear_config.h>
+#include <simgear/structure/commands.hxx>
+
+#ifdef SG_MAC
+#include "CocoaMouseCursor.hxx"
+#endif
+
+#include <Main/fg_props.hxx>
+#include <Main/globals.hxx>
+#include <Viewer/renderer.hxx>
+#include <Main/fg_os.hxx> // for fgWarpMouse
+
+namespace
+{
+    
+/**
+ * @brief when no native cursor implementation is available, use the osgViewer support. This
+ * has several limitations but is better than nothing
+ */
+class StockOSGCursor : public FGMouseCursor
+{
+public:
+    StockOSGCursor() :
+        mCursorObscured(false),
+        mCursorVisible(true),
+        mCursor(osgViewer::GraphicsWindow::InheritCursor)
+    {
+        mActualCursor = mCursor;
+        
+        globals->get_renderer()->getViewer()->getWindows(mWindows);
+    }
+
+    virtual void setCursor(Cursor aCursor)
+    {
+        mCursor = translateCursor(aCursor);
+        updateCursor();
+    }
+    
+    virtual void setCursorVisible(bool aVis)
+    {
+        if (mCursorObscured == aVis) {
+            return;
+        }
+        
+        mCursorVisible = aVis;
+        updateCursor();
+    }
+    
+    virtual void hideCursorUntilMouseMove()
+    {
+        if (mCursorObscured) {
+            return;
+        }
+        
+        mCursorObscured = true;
+        updateCursor();
+    }
+    
+    virtual void mouseMoved()
+    {
+        if (mCursorObscured) {
+            mCursorObscured = false;
+            updateCursor();
+        }
+    }
+private:
+    osgViewer::GraphicsWindow::MouseCursor translateCursor(Cursor aCursor)
+    {
+        switch (aCursor) {
+        case CURSOR_HAND: return osgViewer::GraphicsWindow::HandCursor;
+        case CURSOR_CROSSHAIR: return osgViewer::GraphicsWindow::CrosshairCursor;
+        case CURSOR_IBEAM: return osgViewer::GraphicsWindow::TextCursor;
+        case CURSOR_LEFT_RIGHT: return osgViewer::GraphicsWindow::LeftRightCursor;
+                    
+        default: return osgViewer::GraphicsWindow::InheritCursor;   
+        }
+    }
+    
+    void updateCursor()
+    {
+        osgViewer::GraphicsWindow::MouseCursor cur = osgViewer::GraphicsWindow::InheritCursor;
+        if (mCursorObscured || !mCursorVisible) {
+            cur = osgViewer::GraphicsWindow::NoCursor;
+        } else {
+            cur = mCursor;
+        }
+        
+        if (cur == mActualCursor) {
+            return;
+        }
+        
+        std::cout << "actually setting cursor" << std::endl;
+        BOOST_FOREACH(osgViewer::GraphicsWindow* gw, mWindows) {
+            gw->setCursor(cur);
+        }
+        
+        mActualCursor = cur;
+    }
+    
+    bool mCursorObscured;
+    bool mCursorVisible;
+    osgViewer::GraphicsWindow::MouseCursor mCursor, mActualCursor;
+    std::vector<osgViewer::GraphicsWindow*> mWindows;
+};
+    
+} // of anonymous namespace
+
+static FGMouseCursor* static_instance = NULL;
+
+FGMouseCursor::FGMouseCursor() :
+    mAutoHideTimeMsec(10000)
+{
+}
+
+FGMouseCursor* FGMouseCursor::instance()
+{
+    if (static_instance == NULL) {
+    #ifdef SG_MAC
+        if (true) {
+            static_instance = new CocoaMouseCursor;
+        }
+    #endif
+        
+        // windows
+        
+        // X11
+                
+        if (static_instance == NULL) {
+            static_instance = new StockOSGCursor;
+        }
+        
+        // initialise mouse-hide delay from global properties
+        
+        globals->get_commands()->addCommand("set-cursor", static_instance, &FGMouseCursor::setCursorCommand);
+    }
+    
+    return static_instance;
+}
+
+void FGMouseCursor::setAutoHideTimeMsec(unsigned int aMsec)
+{
+    mAutoHideTimeMsec = aMsec;
+}
+
+
+bool FGMouseCursor::setCursorCommand(const SGPropertyNode* arg)
+{
+    // JMT 2013 - I would prefer this was a seperate 'warp' command, but
+    // historically set-cursor has done both. 
+    if (arg->hasValue("x") || arg->hasValue("y")) {
+        SGPropertyNode *mx = fgGetNode("/devices/status/mice/mouse/x", true);
+        SGPropertyNode *my = fgGetNode("/devices/status/mice/mouse/y", true);
+        int x = arg->getIntValue("x", mx->getIntValue());
+        int y = arg->getIntValue("y", my->getIntValue());
+        fgWarpMouse(x, y);
+        mx->setIntValue(x);
+        my->setIntValue(y);
+    }
+
+    
+    Cursor c = cursorFromString(arg->getStringValue("cursor"));    
+    setCursor(c);
+    return true;
+}
+
+typedef struct {
+    const char * name;
+    FGMouseCursor::Cursor cursor;
+} MouseCursorMap;
+
+const MouseCursorMap mouse_cursor_map[] = {
+    { "inherit", FGMouseCursor::CURSOR_ARROW },
+    { "crosshair", FGMouseCursor::CURSOR_CROSSHAIR },
+    { "left-right", FGMouseCursor::CURSOR_LEFT_RIGHT },
+    { "hand", FGMouseCursor::CURSOR_HAND },
+    { "text", FGMouseCursor::CURSOR_IBEAM },
+    { 0, FGMouseCursor::CURSOR_ARROW }
+};
+
+FGMouseCursor::Cursor FGMouseCursor::cursorFromString(const char* cursor_name)
+{
+    for (unsigned int k = 0; mouse_cursor_map[k].name != 0; k++) {
+        if (!strcmp(mouse_cursor_map[k].name, cursor_name)) {
+            return mouse_cursor_map[k].cursor;
+        }
+    }
+
+    SG_LOG(SG_GENERAL, SG_WARN, "unknown cursor:" << cursor_name);
+    return CURSOR_ARROW;
+}
diff --git a/src/GUI/MouseCursor.hxx b/src/GUI/MouseCursor.hxx
new file mode 100644
index 000000000..d370c5938
--- /dev/null
+++ b/src/GUI/MouseCursor.hxx
@@ -0,0 +1,47 @@
+
+// MouseCursor.hxx - abstract inteface for  mouse cursor control
+
+#ifndef FG_GUI_MOUSE_CURSOR_HXX
+#define FG_GUI_MOUSE_CURSOR_HXX 1
+
+class SGPropertyNode;
+
+class FGMouseCursor
+{
+public:
+    static FGMouseCursor* instance();
+
+    virtual void setAutoHideTimeMsec(unsigned int aMsec);
+  
+    enum Cursor
+    {
+        CURSOR_ARROW,
+        CURSOR_HAND,
+        CURSOR_CROSSHAIR,
+        CURSOR_IBEAM, ///< for editing text
+        CURSOR_IN_OUT, ///< arrow pointing into / out of the screen
+        CURSOR_LEFT_RIGHT,
+        CURSOR_UP_DOWN,
+        CURSOR_SPIN_CW,
+        CURSOR_SPIN_CCW
+    };
+  
+    virtual void setCursor(Cursor aCursor) = 0;
+    
+    virtual void setCursorVisible(bool aVis) = 0;
+    
+    virtual void hideCursorUntilMouseMove() = 0;
+    
+    virtual void mouseMoved() = 0;
+    
+    static Cursor cursorFromString(const char* str);
+
+protected:
+    FGMouseCursor();
+    
+    bool setCursorCommand(const SGPropertyNode* arg);
+    
+    unsigned int mAutoHideTimeMsec;
+};
+
+#endif // FG_GUI_MOUSE_CURSOR_HXX
diff --git a/src/Input/FGMouseInput.cxx b/src/Input/FGMouseInput.cxx
index f55e7c41c..bb76d10d5 100644
--- a/src/Input/FGMouseInput.cxx
+++ b/src/Input/FGMouseInput.cxx
@@ -28,20 +28,50 @@
 
 #include "FGMouseInput.hxx"
 
+#include <boost/foreach.hpp>
 #include <osgGA/GUIEventAdapter>
+
+#include <simgear/scene/util/SGPickCallback.hxx>
+#include <simgear/timing/timestamp.hxx>
+
+#include "FGButton.hxx"
 #include "Main/globals.hxx"
+#include <Viewer/renderer.hxx>
+#include <plib/pu.h>
+#include <Model/panelnode.hxx>
+#include <Cockpit/panel.hxx>
+#include <Viewer/FGEventHandler.hxx>
+#include <GUI/MouseCursor.hxx>
 
 using std::ios_base;
 
+const int MAX_MICE = 1;
+const int MAX_MOUSE_BUTTONS = 8;
+
+////////////////////////////////////////////////////////////////////////
+
+/**
+ * List of currently pressed mouse button events
+ */
+class ActivePickCallbacks : public std::map<int, std::list<SGSharedPtr<SGPickCallback> > > {
+public:
+    void update( double dt );
+    void init( int button, const osgGA::GUIEventAdapter* ea );
+};
+
+
 void ActivePickCallbacks::init( int button, const osgGA::GUIEventAdapter* ea )
 {
+  osg::Vec2d windowPos;
+  flightgear::eventToWindowCoords(ea, windowPos.x(), windowPos.y());
+    
   // Get the list of hit callbacks. Take the first callback that
   // accepts the mouse button press and ignore the rest of them
   // That is they get sorted by distance and by scenegraph depth.
   // The nearest one is the first one and the deepest
   // (the most specialized one in the scenegraph) is the first.
   std::vector<SGSceneryPick> pickList;
-  if (!globals->get_renderer()->pick(pickList, ea)) {
+  if (!globals->get_renderer()->pick(pickList, windowPos)) {
     return;
   }
 
@@ -65,42 +95,155 @@ void ActivePickCallbacks::update( double dt )
   }
 }
 
+////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * Settings for a mouse mode.
+ */
+struct mouse_mode {
+    mouse_mode ();
+    virtual ~mouse_mode ();
+    FGMouseCursor::Cursor cursor;
+    bool constrained;
+    bool pass_through;
+    FGButton * buttons;
+    SGBindingList x_bindings[KEYMOD_MAX];
+    SGBindingList y_bindings[KEYMOD_MAX];
+};
+
+
+/**
+ * Settings for a mouse.
+ */
+struct mouse {
+    mouse ();
+    virtual ~mouse ();
+    int x, y;
+    SGPropertyNode_ptr mode_node;
+    SGPropertyNode_ptr mouse_button_nodes[MAX_MOUSE_BUTTONS];
+    int nModes;
+    int current_mode;
+    
+    SGTimeStamp timeSinceLastMove;
+    mouse_mode * modes;
+};
+
+////////////////////////////////////////////////////////////////////////
+
+class FGMouseInput::FGMouseInputPrivate
+{
+public:
+    FGMouseInputPrivate() :
+        haveWarped(false),
+        xSizeNode(fgGetNode("/sim/startup/xsize", false ) ),
+        ySizeNode(fgGetNode("/sim/startup/ysize", false ) ),
+        xAccelNode(fgGetNode("/devices/status/mice/mouse/accel-x", true ) ),
+        yAccelNode(fgGetNode("/devices/status/mice/mouse/accel-y", true ) ),
+        hideCursorNode(fgGetNode("/sim/mouse/hide-cursor", true ) ),
+        cursorTimeoutNode(fgGetNode("/sim/mouse/cursor-timeout-sec", true ) ),
+        rightButtonModeCycleNode(fgGetNode("/sim/mouse/right-button-mode-cycle-enabled", true)),
+        tooltipShowDelayNode( fgGetNode("/sim/mouse/tooltip-delay-msec", true) ),
+        clickTriggersTooltipNode( fgGetNode("/sim/mouse/click-shows-tooltip", true) )
+    {
+        tooltipTimeoutDone = false;
+    }
+  
+    void centerMouseCursor(mouse& m)
+    {    
+      // center the cursor
+      m.x = (xSizeNode ? xSizeNode->getIntValue() : 800) / 2;
+      m.y = (ySizeNode ? ySizeNode->getIntValue() : 600) / 2;
+      fgWarpMouse(m.x, m.y);
+      haveWarped = true;
+    }
+    
+    void doHoverPick(const osg::Vec2d& windowPos)
+    {
+        std::vector<SGSceneryPick> pickList;
+        SGPickCallback::Priority priority = SGPickCallback::PriorityScenery;
+        
+        if (globals->get_renderer()->pick(pickList, windowPos)) {
+            
+            std::vector<SGSceneryPick>::const_iterator i;
+            for (i = pickList.begin(); i != pickList.end(); ++i) {
+                if (i->callback->hover(windowPos, i->info)) {
+                    return;
+                }
+                
+            // if the callback is of higher prioirty (lower enum index),
+            // record that.
+                if (i->callback->getPriority() < priority) {
+                    priority = i->callback->getPriority();
+                }
+            }
+        } // of have valid pick
+                
+        if (priority < SGPickCallback::PriorityScenery) {
+            FGMouseCursor::instance()->setCursor(FGMouseCursor::CURSOR_HAND);
+        } else {
+            // restore normal cursor
+            FGMouseCursor::instance()->setCursor(FGMouseCursor::CURSOR_ARROW);
+        }
+        
+        updateHover();
+    }
+    
+    void updateHover()
+    {
+        SGPropertyNode_ptr args(new SGPropertyNode);
+        globals->get_commands()->execute("update-hover", args);
+    }
+
+    
+    ActivePickCallbacks activePickCallbacks;
+
+    mouse mice[MAX_MICE];
+    
+    bool haveWarped;
+    bool tooltipTimeoutDone;
+  
+    SGPropertyNode_ptr xSizeNode;
+    SGPropertyNode_ptr ySizeNode;
+    SGPropertyNode_ptr xAccelNode;
+    SGPropertyNode_ptr yAccelNode;
+    SGPropertyNode_ptr hideCursorNode;
+    SGPropertyNode_ptr cursorTimeoutNode;
+    SGPropertyNode_ptr rightButtonModeCycleNode;
+    SGPropertyNode_ptr tooltipShowDelayNode;
+    SGPropertyNode_ptr clickTriggersTooltipNode;
+};
+
 
-#include <plib/pu.h>
-#include <Model/panelnode.hxx>
-#include <Cockpit/panel.hxx>
 ////////////////////////////////////////////////////////////////////////
 // The Mouse Input Implementation
 ////////////////////////////////////////////////////////////////////////
 
-const FGMouseInput::MouseCursorMap FGMouseInput::mouse_cursor_map[] = {
-    { "none", MOUSE_CURSOR_NONE },
-    { "inherit", MOUSE_CURSOR_POINTER },
-    { "wait", MOUSE_CURSOR_WAIT },
-    { "crosshair", MOUSE_CURSOR_CROSSHAIR },
-    { "left-right", MOUSE_CURSOR_LEFTRIGHT },
-    { 0, 0 }
-};
+static FGMouseInput* global_mouseInput = NULL;
+
+static void mouseClickHandler(int button, int updown, int x, int y, bool mainWindow, const osgGA::GUIEventAdapter* ea)
+{
+    if(global_mouseInput)
+        global_mouseInput->doMouseClick(button, updown, x, y, mainWindow, ea);
+}
+
+static void mouseMotionHandler(int x, int y, const osgGA::GUIEventAdapter* ea)
+{
+    if (global_mouseInput != 0)
+        global_mouseInput->doMouseMotion(x, y, ea);
+}
+
 
-FGMouseInput * FGMouseInput::mouseInput = NULL;
 
 FGMouseInput::FGMouseInput() :
-  haveWarped(false),
-  xSizeNode(fgGetNode("/sim/startup/xsize", false ) ),
-  ySizeNode(fgGetNode("/sim/startup/ysize", false ) ),
-  xAccelNode(fgGetNode("/devices/status/mice/mouse/accel-x", true ) ),
-  yAccelNode(fgGetNode("/devices/status/mice/mouse/accel-y", true ) ),
-  hideCursorNode(fgGetNode("/sim/mouse/hide-cursor", true ) ),
-  cursorTimeoutNode(fgGetNode("/sim/mouse/cursor-timeout-sec", true ) )
+  d(new FGMouseInputPrivate)
 {
-  if( mouseInput == NULL )
-    mouseInput = this;
+    global_mouseInput = this;
 }
 
 FGMouseInput::~FGMouseInput()
 {
-  if( mouseInput == this )
-    mouseInput = NULL;
+    global_mouseInput = NULL;
 }
 
 void FGMouseInput::init()
@@ -117,7 +260,7 @@ void FGMouseInput::init()
   int j;
   for (int i = 0; i < MAX_MICE; i++) {
     SGPropertyNode * mouse_node = mouse_nodes->getChild("mouse", i, true);
-    mouse &m = bindings[i];
+    mouse &m = d->mice[i];
 
                                 // Grab node pointers
     std::ostringstream buf;
@@ -140,19 +283,11 @@ void FGMouseInput::init()
 
     for (int j = 0; j < m.nModes; j++) {
       int k;
-
-                                // Read the mouse cursor for this mode
       SGPropertyNode * mode_node = mouse_node->getChild("mode", j, true);
-      const char * cursor_name =
-        mode_node->getStringValue("cursor", "inherit");
-      m.modes[j].cursor = MOUSE_CURSOR_POINTER;
-      for (k = 0; mouse_cursor_map[k].name != 0; k++) {
-        if (!strcmp(mouse_cursor_map[k].name, cursor_name)) {
-          m.modes[j].cursor = mouse_cursor_map[k].cursor;
-          break;
-        }
-      }
 
+    // Read the mouse cursor for this mode
+      m.modes[j].cursor = FGMouseCursor::cursorFromString(mode_node->getStringValue("cursor", "inherit"));
+        
                                 // Read other properties for this mode
       m.modes[j].constrained = mode_node->getBoolValue("constrained", false);
       m.modes[j].pass_through = mode_node->getBoolValue("pass-through", false);
@@ -163,7 +298,6 @@ void FGMouseInput::init()
       for (k = 0; k < MAX_MOUSE_BUTTONS; k++) {
         buf.seekp(ios_base::beg);
         buf << "mouse button " << k;
-        SG_LOG(SG_INPUT, SG_DEBUG, "Initializing mouse button " << k);
         m.modes[j].buttons[k].init( mode_node->getChild("button", k), buf.str(), module );
       }
 
@@ -179,70 +313,68 @@ void FGMouseInput::init()
 
 void FGMouseInput::update ( double dt )
 {
-  double cursorTimeout = cursorTimeoutNode ? cursorTimeoutNode->getDoubleValue() : 10.0;
-
-  mouse &m = bindings[0];
+  int cursorTimeoutMsec = d->cursorTimeoutNode->getDoubleValue() * 1000;
+  int tooltipDelayMsec = d->tooltipShowDelayNode->getIntValue();
+  
+  mouse &m = d->mice[0];
   int mode =  m.mode_node->getIntValue();
   if (mode != m.current_mode) {
+    // current mode has changed
     m.current_mode = mode;
-    m.timeout = cursorTimeout;
+    m.timeSinceLastMove.stamp();
+      
     if (mode >= 0 && mode < m.nModes) {
-      fgSetMouseCursor(m.modes[mode].cursor);
-      m.x = (xSizeNode ? xSizeNode->getIntValue() : 800) / 2;
-      m.y = (ySizeNode ? ySizeNode->getIntValue() : 600) / 2;
-      fgWarpMouse(m.x, m.y);
-      haveWarped = true;
+      FGMouseCursor::instance()->setCursor(m.modes[mode].cursor);
+      d->centerMouseCursor(m);
     } else {
-      SG_LOG(SG_INPUT, SG_DEBUG, "Mouse mode " << mode << " out of range");
-      fgSetMouseCursor(MOUSE_CURSOR_POINTER);
+      SG_LOG(SG_INPUT, SG_WARN, "Mouse mode " << mode << " out of range");
+      FGMouseCursor::instance()->setCursor(FGMouseCursor::CURSOR_ARROW);
     }
   }
 
-  if ( hideCursorNode ==NULL || hideCursorNode->getBoolValue() ) {
-      if ( m.x != m.save_x || m.y != m.save_y ) {
-          m.timeout = cursorTimeout;
-          if (fgGetMouseCursor() == MOUSE_CURSOR_NONE)
-              fgSetMouseCursor(m.modes[mode].cursor);
-      } else {
-          m.timeout -= dt;
-          if ( m.timeout <= 0.0 ) {
-              fgSetMouseCursor(MOUSE_CURSOR_NONE);
-              m.timeout = 0.0;
-          }
+  if ( d->hideCursorNode == NULL || d->hideCursorNode->getBoolValue() ) {
+      // if delay is <= 0, disable tooltips
+      if ( !d->tooltipTimeoutDone &&
+           (tooltipDelayMsec > 0) &&
+           (m.timeSinceLastMove.elapsedMSec() > tooltipDelayMsec))
+      {
+          d->tooltipTimeoutDone = true;
+          SGPropertyNode_ptr arg(new SGPropertyNode);
+          globals->get_commands()->execute("tooltip-timeout", arg);
+      }
+    
+      if ( m.timeSinceLastMove.elapsedMSec() > cursorTimeoutMsec) {
+          FGMouseCursor::instance()->hideCursorUntilMouseMove();
+          m.timeSinceLastMove.stamp();
       }
-      m.save_x = m.x;
-      m.save_y = m.y;
   }
-
-  activePickCallbacks.update( dt );
+    
+  d->activePickCallbacks.update( dt );
 }
 
-FGMouseInput::mouse::mouse ()
+mouse::mouse ()
   : x(-1),
     y(-1),
-    save_x(-1),
-    save_y(-1),
     nModes(1),
     current_mode(0),
-    timeout(0),
     modes(NULL)
 {
 }
 
-FGMouseInput::mouse::~mouse ()
+mouse::~mouse ()
 {
   delete [] modes;
 }
 
-FGMouseInput::mouse_mode::mouse_mode ()
-  : cursor(MOUSE_CURSOR_POINTER),
+mouse_mode::mouse_mode ()
+  : cursor(FGMouseCursor::CURSOR_ARROW),
     constrained(false),
     pass_through(false),
     buttons(NULL)
 {
 }
 
-FGMouseInput::mouse_mode::~mouse_mode ()
+mouse_mode::~mouse_mode ()
 {
                                 // FIXME: memory leak
 //   for (int i = 0; i < KEYMOD_MAX; i++) {
@@ -252,30 +384,36 @@ FGMouseInput::mouse_mode::~mouse_mode ()
 //     for (j = 0; j < y_bindings[i].size(); j++)
 //       delete bindings[i][j];
 //   }
-  delete [] buttons;
+  if (buttons) {
+    delete [] buttons;
+  }
 }
 
 void FGMouseInput::doMouseClick (int b, int updown, int x, int y, bool mainWindow, const osgGA::GUIEventAdapter* ea)
 {
   int modifiers = fgGetKeyModifiers();
 
-  mouse &m = bindings[0];
+  mouse &m = d->mice[0];
   mouse_mode &mode = m.modes[m.current_mode];
-
                                 // Let the property manager know.
   if (b >= 0 && b < MAX_MOUSE_BUTTONS)
     m.mouse_button_nodes[b]->setBoolValue(updown == MOUSE_BUTTON_DOWN);
 
-                                // Pass on to PUI and the panel if
-                                // requested, and return if one of
-                                // them consumes the event.
+  if (!d->rightButtonModeCycleNode->getBoolValue() && (b == 2)) {
+    // in spring-loaded look mode, ignore right clicks entirely here
+    return;
+  }
+  
+  // Pass on to PUI and the panel if
+  // requested, and return if one of
+  // them consumes the event.
 
   if (updown != MOUSE_BUTTON_DOWN) {
     // Execute the mouse up event in any case, may be we should
     // stop processing here?
-    while (!activePickCallbacks[b].empty()) {
-      activePickCallbacks[b].front()->buttonReleased();
-      activePickCallbacks[b].pop_front();
+    while (!d->activePickCallbacks[b].empty()) {
+      d->activePickCallbacks[b].front()->buttonReleased();
+      d->activePickCallbacks[b].pop_front();
     }
   }
 
@@ -287,7 +425,7 @@ void FGMouseInput::doMouseClick (int b, int updown, int x, int y, bool mainWindo
       // pui didn't want the click event so compute a
       // scenegraph intersection point corresponding to the mouse click
       if (updown == MOUSE_BUTTON_DOWN) {
-        activePickCallbacks.init( b, ea );
+        d->activePickCallbacks.init( b, ea );
       }
     }
   }
@@ -300,54 +438,91 @@ void FGMouseInput::doMouseClick (int b, int updown, int x, int y, bool mainWindo
   }
 
   m.modes[m.current_mode].buttons[b].update( modifiers, 0 != updown, x, y);
+  
+  if (d->clickTriggersTooltipNode->getBoolValue()) {
+    SGPropertyNode_ptr args(new SGPropertyNode);
+    args->setStringValue("reason", "click");
+    globals->get_commands()->execute("tooltip-timeout", args);
+    d->tooltipTimeoutDone = true;
+  }
 }
 
-void FGMouseInput::doMouseMotion (int x, int y)
+void FGMouseInput::doMouseMotion (int x, int y, const osgGA::GUIEventAdapter* ea)
 {
-  // Don't call fgGetKeyModifiers() here, until we are using a
-  // toolkit that supports getting the mods from outside a key
-  // callback.  Glut doesn't.
-  int modifiers = KEYMOD_NONE;
+  int modifiers = fgGetKeyModifiers();
 
-  int xsize = xSizeNode ? xSizeNode->getIntValue() : 800;
-  int ysize = ySizeNode ? ySizeNode->getIntValue() : 600;
+  int xsize = d->xSizeNode ? d->xSizeNode->getIntValue() : 800;
+  int ysize = d->ySizeNode ? d->ySizeNode->getIntValue() : 600;
 
-  mouse &m = bindings[0];
+  mouse &m = d->mice[0];
 
   if (m.current_mode < 0 || m.current_mode >= m.nModes) {
       m.x = x;
       m.y = y;
       return;
   }
-  mouse_mode &mode = m.modes[m.current_mode];
 
-                                // Pass on to PUI if requested, and return
-                                // if PUI consumed the event.
+  if (!d->activePickCallbacks[0].empty()) {
+    SG_LOG(SG_GENERAL, SG_INFO, "mouse-motion, have active pick callback");
+    BOOST_FOREACH(SGPickCallback* cb, d->activePickCallbacks[0]) {
+      cb->mouseMoved(ea);
+    }
+    
+    m.x = x;
+    m.y = y;
+    return;
+  }
+  
+  m.timeSinceLastMove.stamp();
+  FGMouseCursor::instance()->mouseMoved();
+
+  int modeIndex = m.current_mode;
+  // are we in spring-loaded look mode?
+  if (!d->rightButtonModeCycleNode->getBoolValue()) {
+    if (m.mouse_button_nodes[2]->getBoolValue()) {
+      // right mouse is down, force look mode
+      modeIndex = 3;
+    }
+  }
+
+  if (modeIndex == 0) {
+    osg::Vec2d windowPos;
+    flightgear::eventToWindowCoords(ea, windowPos.x(), windowPos.y());
+    d->doHoverPick(windowPos);
+    // mouse has moved, so we may need to issue tooltip-timeout command
+    // again
+    d->tooltipTimeoutDone = false;
+  }
+
+  mouse_mode &mode = m.modes[modeIndex];
+
+    // Pass on to PUI if requested, and return
+    // if PUI consumed the event.
   if (mode.pass_through && puMouse(x, y)) {
       m.x = x;
       m.y = y;
       return;
   }
   
-  if (haveWarped)
+  if (d->haveWarped)
   {
       // don't fire mouse-movement events at the first update after warping the mouse,
       // just remember the new mouse position
-      haveWarped = false;
+      d->haveWarped = false;
   }
   else
   {
-                                // OK, PUI didn't want the event,
-                                // so we can play with it.
+      // OK, PUI didn't want the event,
+      // so we can play with it.
       if (x != m.x) {
         int delta = x - m.x;
-        xAccelNode->setIntValue( delta );
+        d->xAccelNode->setIntValue( delta );
         for (unsigned int i = 0; i < mode.x_bindings[modifiers].size(); i++)
           mode.x_bindings[modifiers][i]->fire(double(delta), double(xsize));
       }
       if (y != m.y) {
         int delta = y - m.y;
-        yAccelNode->setIntValue( -delta );
+        d->yAccelNode->setIntValue( -delta );
         for (unsigned int i = 0; i < mode.y_bindings[modifiers].size(); i++)
           mode.y_bindings[modifiers][i]->fire(double(delta), double(ysize));
       }
@@ -370,8 +545,7 @@ void FGMouseInput::doMouseMotion (int x, int y)
     if (need_warp)
     {
       fgWarpMouse(new_x, new_y);
-      haveWarped = true;
-      SG_LOG(SG_INPUT, SG_DEBUG, "Mouse warp: " << x << ", " << y << " => " << new_x << ", " << new_y);
+      d->haveWarped = true;
     }
   }
 
@@ -382,16 +556,5 @@ void FGMouseInput::doMouseMotion (int x, int y)
       fgSetInt("/devices/status/mice/mouse/y", m.y = y);
 }
 
-void FGMouseInput::mouseClickHandler(int button, int updown, int x, int y, bool mainWindow, const osgGA::GUIEventAdapter* ea)
-{
-    if(mouseInput)
-      mouseInput->doMouseClick(button, updown, x, y, mainWindow, ea);
-}
-
-void FGMouseInput::mouseMotionHandler(int x, int y)
-{
-    if (mouseInput != 0)
-        mouseInput->doMouseMotion(x, y);
-}
 
 
diff --git a/src/Input/FGMouseInput.hxx b/src/Input/FGMouseInput.hxx
index 01c6c2cbd..7e1634413 100644
--- a/src/Input/FGMouseInput.hxx
+++ b/src/Input/FGMouseInput.hxx
@@ -26,33 +26,19 @@
 #ifndef _FGMOUSEINPUT_HXX
 #define _FGMOUSEINPUT_HXX
 
-#ifndef __cplusplus                                                          
-# error This library requires C++
-#endif
-
 #include "FGCommonInput.hxx"
-#include "FGButton.hxx"
 
-#include <map>
-#include <list>
+#include <memory>
+
 #include <simgear/structure/subsystem_mgr.hxx>
-#include <simgear/scene/util/SGPickCallback.hxx>
-#include <Viewer/renderer.hxx>
-
-/**
-  * List of currently pressed mouse button events
-  */
-class ActivePickCallbacks : public std::map<int, std::list<SGSharedPtr<SGPickCallback> > > {
-public:
-  void update( double dt );
-  void init( int button, const osgGA::GUIEventAdapter* ea );
-};
 
+// forward decls
+namespace osgGA { class GUIEventAdapter; }
 
 ////////////////////////////////////////////////////////////////////////
 // The Mouse Input Class
 ////////////////////////////////////////////////////////////////////////
-class FGMouseInput : public SGSubsystem,FGCommonInput {
+class FGMouseInput : public SGSubsystem, FGCommonInput {
 public:
   FGMouseInput();
   virtual ~FGMouseInput();
@@ -60,74 +46,12 @@ public:
   virtual void init();
   virtual void update( double dt );
 
-  static const int MAX_MICE = 1;
-  static const int MAX_MOUSE_BUTTONS = 8;
-
+    void doMouseClick (int b, int updown, int x, int y, bool mainWindow, const osgGA::GUIEventAdapter* ea);
+    void doMouseMotion (int x, int y, const osgGA::GUIEventAdapter*);
 private:
-  void doMouseClick (int b, int updown, int x, int y, bool mainWindow, const osgGA::GUIEventAdapter* ea);
-  void doMouseMotion (int x, int y);
-  static FGMouseInput * mouseInput;
-  static void mouseClickHandler(int button, int updown, int x, int y, bool mainWindow, const osgGA::GUIEventAdapter*);
-  static void mouseMotionHandler(int x, int y);
-
-  ActivePickCallbacks activePickCallbacks;
-  /**
-   * Settings for a mouse mode.
-   */
-  struct mouse_mode {
-    mouse_mode ();
-    virtual ~mouse_mode ();
-    int cursor;
-    bool constrained;
-    bool pass_through;
-    FGButton * buttons;
-    binding_list_t x_bindings[KEYMOD_MAX];
-    binding_list_t y_bindings[KEYMOD_MAX];
-  };
-
-
-  /**
-   * Settings for a mouse.
-   */
-  struct mouse {
-    mouse ();
-    virtual ~mouse ();
-    int x;
-    int y;
-    int save_x;
-    int save_y;
-    SGPropertyNode_ptr mode_node;
-    SGPropertyNode_ptr mouse_button_nodes[MAX_MOUSE_BUTTONS];
-    int nModes;
-    int current_mode;
-    double timeout;
-    mouse_mode * modes;
-  };
-
-  // 
-  // Map of all known cursor names
-  // This used to contain all the Glut cursors, but those are
-  // not defined by other toolkits.  It now supports only the cursor
-  // images we actually use, in the interest of portability.  Someday,
-  // it would be cool to write an OpenGL cursor renderer, with the
-  // cursors defined as textures referenced in the property tree.  This
-  // list could then be eliminated. -Andy
-  //
-  const static struct MouseCursorMap {
-    const char * name;
-    int cursor;
-  } mouse_cursor_map[];
-
-  mouse bindings[MAX_MICE];
+  class FGMouseInputPrivate;
+  std::auto_ptr<FGMouseInputPrivate> d;
   
-  bool haveWarped;
-
-  SGPropertyNode_ptr xSizeNode;
-  SGPropertyNode_ptr ySizeNode;
-  SGPropertyNode_ptr xAccelNode;
-  SGPropertyNode_ptr yAccelNode;
-  SGPropertyNode_ptr hideCursorNode;
-  SGPropertyNode_ptr cursorTimeoutNode;
 };
 
 #endif
diff --git a/src/Main/fg_commands.cxx b/src/Main/fg_commands.cxx
index c0e388719..f1909c1fa 100644
--- a/src/Main/fg_commands.cxx
+++ b/src/Main/fg_commands.cxx
@@ -1108,32 +1108,6 @@ do_add_model (const SGPropertyNode * arg)
     return true;
 }
 
-
-/**
- * Set mouse cursor coordinates and cursor shape.
- */
-static bool
-do_set_cursor (const SGPropertyNode * arg)
-{
-    if (arg->hasValue("x") || arg->hasValue("y")) {
-        SGPropertyNode *mx = fgGetNode("/devices/status/mice/mouse/x", true);
-        SGPropertyNode *my = fgGetNode("/devices/status/mice/mouse/y", true);
-        int x = arg->getIntValue("x", mx->getIntValue());
-        int y = arg->getIntValue("y", my->getIntValue());
-        fgWarpMouse(x, y);
-        mx->setIntValue(x);
-        my->setIntValue(y);
-    }
-
-    SGPropertyNode *cursor = const_cast<SGPropertyNode *>(arg)->getNode("cursor", true);
-    if (cursor->getType() != simgear::props::NONE)
-        fgSetMouseCursor(cursor->getIntValue());
-
-    cursor->setIntValue(fgGetMouseCursor());
-    return true;
-}
-
-
 /**
  * Built-in command: play an audio message (i.e. a wav file) This is
  * fire and forget.  Call this once per message and it will get dumped
@@ -1612,7 +1586,6 @@ static struct {
     { "open-browser", do_open_browser },
     { "gui-redraw", do_gui_redraw },
     { "add-model", do_add_model },
-    { "set-cursor", do_set_cursor },
     { "play-audio-sample", do_play_audio_sample },
     { "presets-commit", do_presets_commit },
     { "log-level", do_log_level },
diff --git a/src/Main/fg_os.hxx b/src/Main/fg_os.hxx
index 74d2e468b..46bc235a7 100644
--- a/src/Main/fg_os.hxx
+++ b/src/Main/fg_os.hxx
@@ -82,7 +82,7 @@ typedef void (*fgWindowResizeHandler)(int w, int h);
 
 typedef void (*fgKeyHandler)(int key, int keymod, int mousex, int mousey);
 typedef void (*fgMouseClickHandler)(int button, int updown, int x, int y, bool mainWindow, const osgGA::GUIEventAdapter*);
-typedef void (*fgMouseMotionHandler)(int x, int y);
+typedef void (*fgMouseMotionHandler)(int x, int y, const osgGA::GUIEventAdapter*);
 
 void fgRegisterIdleHandler(fgIdleHandler func);
 void fgRegisterDrawHandler(fgDrawHandler func);
diff --git a/src/Scenery/scenery.cxx b/src/Scenery/scenery.cxx
index f9878ba05..1f6d4c3c2 100644
--- a/src/Scenery/scenery.cxx
+++ b/src/Scenery/scenery.cxx
@@ -47,9 +47,11 @@
 #include <simgear/scene/model/CheckSceneryVisitor.hxx>
 #include <simgear/bvh/BVHNode.hxx>
 #include <simgear/bvh/BVHLineSegmentVisitor.hxx>
+#include <simgear/structure/commands.hxx>
 
 #include <Viewer/renderer.hxx>
 #include <Main/fg_props.hxx>
+#include <GUI/MouseCursor.hxx>
 
 #include "tilemgr.hxx"
 #include "scenery.hxx"
@@ -59,6 +61,9 @@ using namespace simgear;
 
 class FGGroundPickCallback : public SGPickCallback {
 public:
+  FGGroundPickCallback() : SGPickCallback(PriorityScenery)
+  { }
+    
   virtual bool buttonPressed(int button, const osgGA::GUIEventAdapter*, const Info& info)
   {
     // only on left mouse button
diff --git a/src/Scripting/NasalSys.cxx b/src/Scripting/NasalSys.cxx
index f9e29b9af..bf1a1a21f 100644
--- a/src/Scripting/NasalSys.cxx
+++ b/src/Scripting/NasalSys.cxx
@@ -28,6 +28,7 @@
 #include <simgear/math/sg_geodesy.hxx>
 #include <simgear/structure/event_mgr.hxx>
 #include <simgear/debug/BufferedLogCallback.hxx>
+#include <simgear/nasal/cppbind/NasalHash.hxx>
 
 #include "NasalSys.hxx"
 #include "NasalSys_private.hxx"
@@ -502,7 +503,7 @@ public:
     {
         _sys->setCmdArg(const_cast<SGPropertyNode*>(aNode));
         naRef args[1];
-        args[0] = _sys->cmdArgGhost();
+        args[0] = _sys->wrappedPropsNode(const_cast<SGPropertyNode*>(aNode));
     
         _sys->callMethod(_func, naNil(), 1, args, naNil() /* locals */);
 
@@ -697,6 +698,20 @@ void FGNasalSys::init()
     postinitNasalGUI(_globals, _context);
 }
 
+naRef FGNasalSys::wrappedPropsNode(SGPropertyNode* aProps)
+{
+    static naRef wrapNodeFunc = naNil();
+    if (naIsNil(wrapNodeFunc)) {
+        nasal::Hash g(_globals, _context);
+        nasal::Hash props = g.get<nasal::Hash>("props");
+        wrapNodeFunc = props.get("wrapNode");
+    }
+    
+    naRef args[1];
+    args[0] = propNodeGhost(aProps);
+    return naCall(_context, wrapNodeFunc, 1, args, naNil(), naNil());
+}
+
 void FGNasalSys::update(double)
 {
     if( NasalClipboard::getInstance() )
diff --git a/src/Scripting/NasalSys.hxx b/src/Scripting/NasalSys.hxx
index 7a2048d7e..fc24f9959 100644
--- a/src/Scripting/NasalSys.hxx
+++ b/src/Scripting/NasalSys.hxx
@@ -64,6 +64,12 @@ public:
 
     void setCmdArg(SGPropertyNode* aNode);
     
+    /**
+     * create Nasal props.Node for an SGPropertyNode*
+     * This is the actual ghost, wrapped in a Nasal sugar class.
+     */
+    naRef wrappedPropsNode(SGPropertyNode* aProps);
+    
     // Callbacks for command and timer bindings
     virtual bool handleCommand( const char* moduleName,
                                 const char* fileName,
diff --git a/src/Viewer/CameraGroup.cxx b/src/Viewer/CameraGroup.cxx
index 3d84717e5..255e675f4 100644
--- a/src/Viewer/CameraGroup.cxx
+++ b/src/Viewer/CameraGroup.cxx
@@ -27,6 +27,8 @@
 #include "FGEventHandler.hxx"
 #include "WindowBuilder.hxx"
 #include "WindowSystemAdapter.hxx"
+
+#include <simgear/math/SGRect.hxx>
 #include <simgear/props/props.hxx>
 #include <simgear/structure/OSGUtils.hxx>
 #include <simgear/structure/OSGVersion.hxx>
@@ -1142,34 +1144,34 @@ Camera* getGUICamera(CameraGroup* cgroup)
     return info->getCamera(MAIN_CAMERA);
 }
 
-static bool computeCameraIntersection(const CameraInfo* cinfo,
-                                      const osgGA::GUIEventAdapter* ea,
+
+static bool computeCameraIntersection(const CameraInfo* cinfo, const osg::Vec2d& windowPos,
                                       osgUtil::LineSegmentIntersector::Intersections& intersections)
 {
   using osgUtil::Intersector;
   using osgUtil::LineSegmentIntersector;
-  double x, y;
-  eventToWindowCoords(ea, x, y);
-  
+
   if (!(cinfo->flags & CameraGroup::DO_INTERSECTION_TEST))
     return false;
   
   const Camera* camera = cinfo->getCamera(MAIN_CAMERA);
   if ( !camera )
     camera = cinfo->getCamera( GEOMETRY_CAMERA );
-  if (camera->getGraphicsContext() != ea->getGraphicsContext())
-    return false;
+ 
+  // if (camera->getGraphicsContext() != ea->getGraphicsContext())
+ //   return false;
   
   const Viewport* viewport = camera->getViewport();
+  SGRect<double> viewportRect(viewport->x(), viewport->y(),
+                              viewport->x() + viewport->width() - 1.0,
+                              viewport->y() + viewport->height()- 1.0);
+    
   double epsilon = 0.5;
-  if (!(x >= viewport->x() - epsilon
-        && x < viewport->x() + viewport->width() -1.0 + epsilon
-        && y >= viewport->y() - epsilon
-        && y < viewport->y() + viewport->height() -1.0 + epsilon))
+  if (!viewportRect.contains(windowPos.x(), windowPos.y(), epsilon))
     return false;
   
-  Vec4d start(x, y, 0.0, 1.0);
-  Vec4d end(x, y, 1.0, 1.0);
+  Vec4d start(windowPos.x(), windowPos.y(), 0.0, 1.0);
+  Vec4d end(windowPos.x(), windowPos.y(), 1.0, 1.0);
   Matrix windowMat = viewport->computeWindowMatrix();
   Matrix startPtMat = Matrix::inverse(camera->getProjectionMatrix()
                                       * windowMat);
@@ -1200,12 +1202,12 @@ static bool computeCameraIntersection(const CameraInfo* cinfo,
 }
   
 bool computeIntersections(const CameraGroup* cgroup,
-                          const osgGA::GUIEventAdapter* ea,
+                          const osg::Vec2d& windowPos,
                           osgUtil::LineSegmentIntersector::Intersections& intersections)
 {
     // test the GUI first
     const CameraInfo* guiCamera = cgroup->getGUICamera();
-    if (guiCamera && computeCameraIntersection(guiCamera, ea, intersections))
+    if (guiCamera && computeCameraIntersection(guiCamera, windowPos, intersections))
         return true;
     
     // Find camera that contains event
@@ -1217,7 +1219,7 @@ bool computeIntersections(const CameraGroup* cgroup,
         if (cinfo == guiCamera)
             continue;
         
-        if (computeCameraIntersection(cinfo, ea, intersections))
+        if (computeCameraIntersection(cinfo, windowPos, intersections))
             return true;
     }
   
diff --git a/src/Viewer/CameraGroup.hxx b/src/Viewer/CameraGroup.hxx
index 1bdcd02de..1d5bd0aa0 100644
--- a/src/Viewer/CameraGroup.hxx
+++ b/src/Viewer/CameraGroup.hxx
@@ -292,11 +292,6 @@ protected:
 
 }
 
-namespace osgGA
-{
-class GUIEventAdapter;
-}
-
 namespace flightgear
 {
 /** Get the osg::Camera that draws the GUI, if any, from a camera
@@ -315,7 +310,7 @@ osg::Camera* getGUICamera(CameraGroup* cgroup);
  * @return true if any intersections are found
  */
 bool computeIntersections(const CameraGroup* cgroup,
-                          const osgGA::GUIEventAdapter* ea,
+                          const osg::Vec2d& windowPos,
                           osgUtil::LineSegmentIntersector::Intersections&
                           intersections);
 /** Warp the pointer to coordinates in the GUI camera of a camera group.
diff --git a/src/Viewer/FGEventHandler.cxx b/src/Viewer/FGEventHandler.cxx
index b877cc746..aa3d5ac49 100644
--- a/src/Viewer/FGEventHandler.cxx
+++ b/src/Viewer/FGEventHandler.cxx
@@ -261,7 +261,7 @@ bool FGEventHandler::handle(const osgGA::GUIEventAdapter& ea,
         if (mouseWarped)
             return true;
         if (eventToViewport(ea, us, x, y) && mouseMotionHandler)
-            (*mouseMotionHandler)(x, y);
+            (*mouseMotionHandler)(x, y, &ea);
         return true;
     case osgGA::GUIEventAdapter::RESIZE:
         SG_LOG(SG_VIEW, SG_DEBUG, "FGEventHandler::handle: RESIZE event " << ea.getWindowHeight() << " x " << ea.getWindowWidth() << ", resizable: " << resizable);
@@ -417,6 +417,7 @@ void eventToWindowCoords(const osgGA::GUIEventAdapter* ea,
         y = (double)traits->height - y;
 }
 
+#if 0
 void eventToWindowCoordsYDown(const osgGA::GUIEventAdapter* ea,
                               double& x, double& y)
 {
@@ -431,4 +432,6 @@ void eventToWindowCoordsYDown(const osgGA::GUIEventAdapter* ea,
     if (ea->getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS)
         y = (double)traits->height - y;
 }
+#endif
+    
 }
diff --git a/src/Viewer/renderer.cxx b/src/Viewer/renderer.cxx
index 2e8d8fe87..2584df141 100644
--- a/src/Viewer/renderer.cxx
+++ b/src/Viewer/renderer.cxx
@@ -1724,15 +1724,14 @@ FGRenderer::resize( int width, int height )
 }
 
 bool
-FGRenderer::pick(std::vector<SGSceneryPick>& pickList,
-                 const osgGA::GUIEventAdapter* ea)
+FGRenderer::pick(std::vector<SGSceneryPick>& pickList, const osg::Vec2& windowPos)
 {
     // wipe out the return ...
     pickList.clear();
     typedef osgUtil::LineSegmentIntersector::Intersections Intersections;
     Intersections intersections;
 
-    if (!computeIntersections(CameraGroup::getDefault(), ea, intersections))
+    if (!computeIntersections(CameraGroup::getDefault(), windowPos, intersections))
         return false;
     for (Intersections::iterator hit = intersections.begin(),
              e = intersections.end();
diff --git a/src/Viewer/renderer.hxx b/src/Viewer/renderer.hxx
index a064dcd30..959847408 100644
--- a/src/Viewer/renderer.hxx
+++ b/src/Viewer/renderer.hxx
@@ -61,8 +61,7 @@ public:
   
     /** Just pick into the scene and return the pick callbacks on the way ...
      */
-    bool pick( std::vector<SGSceneryPick>& pickList,
-               const osgGA::GUIEventAdapter* ea );
+    bool pick( std::vector<SGSceneryPick>& pickList, const osg::Vec2& windowPos);
 
     /** Get and set the OSG Viewer object, if any.
      */