+            // NB: it may *rarely* happen that the code above didn't find one
+            //     of the cells, e.g. if wxHtmlWindow doesn't contain any
+            //     visible cells.
+            if ( selcell && m_tmpSelFromCell )
+            {
+                if ( !m_selection )
+                {
+                    // start selecting only if mouse movement was big enough
+                    // (otherwise it was meant as mouse click, not selection):
+                    const int PRECISION = 2;
+                    wxPoint diff = m_tmpSelFromPos - wxPoint(x,y);
+                    if (abs(diff.x) > PRECISION || abs(diff.y) > PRECISION)
+                    {
+                        m_selection = new wxHtmlSelection();
+                    }
+                }
+                if ( m_selection )
+                {
+                    if ( m_tmpSelFromCell->IsBefore(selcell) )
+                    {
+                        m_selection->Set(m_tmpSelFromPos, m_tmpSelFromCell,
+                                         wxPoint(x,y), selcell);
+                    }
+                    else
+                    {
+                        m_selection->Set(wxPoint(x,y), selcell,
+                                         m_tmpSelFromPos, m_tmpSelFromCell);
+                    }
+                    m_selection->ClearPrivPos();
+                    Refresh();
+                }
+            }
+        }
+
+        // handle cursor and status bar text changes:
+
+        // NB: because we're passing in 'cell' and not 'm_Cell' (so that the
+        //     leaf cell lookup isn't done twice), we need to adjust the
+        //     position for the new root:
+        wxPoint posInCell(x, y);
+        if (cell)
+            posInCell -= cell->GetAbsPos();
+        wxHtmlWindowMouseHelper::HandleIdle(cell, posInCell);
+    }
+}
+
+#if wxUSE_CLIPBOARD
+void wxHtmlWindow::StopAutoScrolling()
+{
+    if ( m_timerAutoScroll )
+    {
+        wxDELETE(m_timerAutoScroll);
+    }
+}
+
+void wxHtmlWindow::OnMouseEnter(wxMouseEvent& event)
+{
+    StopAutoScrolling();
+    event.Skip();
+}
+
+void wxHtmlWindow::OnMouseLeave(wxMouseEvent& event)
+{
+    // don't prevent the usual processing of the event from taking place
+    event.Skip();
+
+    // when a captured mouse leave a scrolled window we start generate
+    // scrolling events to allow, for example, extending selection beyond the
+    // visible area in some controls
+    if ( wxWindow::GetCapture() == this )
+    {
+        // where is the mouse leaving?
+        int pos, orient;
+        wxPoint pt = event.GetPosition();
+        if ( pt.x < 0 )
+        {
+            orient = wxHORIZONTAL;
+            pos = 0;
+        }
+        else if ( pt.y < 0 )
+        {
+            orient = wxVERTICAL;
+            pos = 0;
+        }
+        else // we're lower or to the right of the window
+        {
+            wxSize size = GetClientSize();
+            if ( pt.x > size.x )
+            {
+                orient = wxHORIZONTAL;
+                pos = GetVirtualSize().x / wxHTML_SCROLL_STEP;
+            }
+            else if ( pt.y > size.y )
+            {
+                orient = wxVERTICAL;
+                pos = GetVirtualSize().y / wxHTML_SCROLL_STEP;
+            }
+            else // this should be impossible
+            {
+                // but seems to happen sometimes under wxMSW - maybe it's a bug
+                // there but for now just ignore it
+
+                //wxFAIL_MSG( _T("can't understand where has mouse gone") );
+
+                return;
+            }
+        }
+
+        // only start the auto scroll timer if the window can be scrolled in
+        // this direction
+        if ( !HasScrollbar(orient) )
+            return;
+
+        delete m_timerAutoScroll;
+        m_timerAutoScroll = new wxHtmlWinAutoScrollTimer
+                                (
+                                    this,
+                                    pos == 0 ? wxEVT_SCROLLWIN_LINEUP
+                                             : wxEVT_SCROLLWIN_LINEDOWN,
+                                    pos,
+                                    orient
+                                );
+        m_timerAutoScroll->Start(50); // FIXME: make configurable
+    }
+}
+
+void wxHtmlWindow::OnKeyUp(wxKeyEvent& event)
+{
+    if ( IsSelectionEnabled() &&
+            (event.GetKeyCode() == 'C' && event.CmdDown()) )
+    {
+        wxClipboardTextEvent evt(wxEVT_COMMAND_TEXT_COPY, GetId());
+
+        evt.SetEventObject(this);
+
+        GetEventHandler()->ProcessEvent(evt);
+    }
+}
+
+void wxHtmlWindow::OnCopy(wxCommandEvent& WXUNUSED(event))
+{
+    (void) CopySelection();
+}
+
+void wxHtmlWindow::OnClipboardEvent(wxClipboardTextEvent& WXUNUSED(event))
+{
+    (void) CopySelection();
+}
+
+void wxHtmlWindow::OnDoubleClick(wxMouseEvent& event)
+{
+    // select word under cursor:
+    if ( IsSelectionEnabled() )
+    {
+        SelectWord(CalcUnscrolledPosition(event.GetPosition()));
+
+        (void) CopySelection(Primary);
+
+        m_lastDoubleClick = wxGetLocalTimeMillis();
+    }
+    else
+        event.Skip();
+}
+
+void wxHtmlWindow::SelectWord(const wxPoint& pos)
+{
+    if ( m_Cell )
+    {
+        wxHtmlCell *cell = m_Cell->FindCellByPos(pos.x, pos.y);
+        if ( cell )
+        {
+            delete m_selection;
+            m_selection = new wxHtmlSelection();
+            m_selection->Set(cell, cell);
+            RefreshRect(wxRect(CalcScrolledPosition(cell->GetAbsPos()),
+                               wxSize(cell->GetWidth(), cell->GetHeight())));