1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/html/htmlwin.cpp 
   3 // Purpose:     wxHtmlWindow class for parsing & displaying HTML (implementation) 
   4 // Author:      Vaclav Slavik 
   6 // Copyright:   (c) 1999 Vaclav Slavik 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 #include "wx/wxprec.h" 
  16 #if wxUSE_HTML && wxUSE_STREAMS 
  22     #include "wx/dcclient.h" 
  24     #include "wx/dcmemory.h" 
  26     #include "wx/settings.h" 
  27     #include "wx/dataobj.h" 
  30 #include "wx/html/htmlwin.h" 
  31 #include "wx/html/htmlproc.h" 
  32 #include "wx/clipbrd.h" 
  34 #include "wx/arrimpl.cpp" 
  35 #include "wx/listimpl.cpp" 
  39 // ---------------------------------------------------------------------------- 
  40 // wxHtmlWinAutoScrollTimer: the timer used to generate a stream of scroll 
  41 // events when a captured mouse is held outside the window 
  42 // ---------------------------------------------------------------------------- 
  44 class wxHtmlWinAutoScrollTimer 
: public wxTimer
 
  47     wxHtmlWinAutoScrollTimer(wxScrolledWindow 
*win
, 
  48                       wxEventType eventTypeToSend
, 
  52         m_eventType 
= eventTypeToSend
; 
  57     virtual void Notify(); 
  60     wxScrolledWindow 
*m_win
; 
  61     wxEventType m_eventType
; 
  65     DECLARE_NO_COPY_CLASS(wxHtmlWinAutoScrollTimer
) 
  68 void wxHtmlWinAutoScrollTimer::Notify() 
  70     // only do all this as long as the window is capturing the mouse 
  71     if ( wxWindow::GetCapture() != m_win 
) 
  75     else // we still capture the mouse, continue generating events 
  77         // first scroll the window if we are allowed to do it 
  78         wxScrollWinEvent 
event1(m_eventType
, m_pos
, m_orient
); 
  79         event1
.SetEventObject(m_win
); 
  80         if ( m_win
->GetEventHandler()->ProcessEvent(event1
) ) 
  82             // and then send a pseudo mouse-move event to refresh the selection 
  83             wxMouseEvent 
event2(wxEVT_MOTION
); 
  84             wxGetMousePosition(&event2
.m_x
, &event2
.m_y
); 
  86             // the mouse event coordinates should be client, not screen as 
  87             // returned by wxGetMousePosition 
  88             wxWindow 
*parentTop 
= m_win
; 
  89             while ( parentTop
->GetParent() ) 
  90                 parentTop 
= parentTop
->GetParent(); 
  91             wxPoint ptOrig 
= parentTop
->GetPosition(); 
  92             event2
.m_x 
-= ptOrig
.x
; 
  93             event2
.m_y 
-= ptOrig
.y
; 
  95             event2
.SetEventObject(m_win
); 
  97             // FIXME: we don't fill in the other members - ok? 
  98             m_win
->GetEventHandler()->ProcessEvent(event2
); 
 100         else // can't scroll further, stop 
 107 #endif // wxUSE_CLIPBOARD 
 111 //----------------------------------------------------------------------------- 
 113 //----------------------------------------------------------------------------- 
 115 // item of history list 
 116 class WXDLLIMPEXP_HTML wxHtmlHistoryItem
 
 119     wxHtmlHistoryItem(const wxString
& p
, const wxString
& a
) {m_Page 
= p
, m_Anchor 
= a
, m_Pos 
= 0;} 
 120     int GetPos() const {return m_Pos
;} 
 121     void SetPos(int p
) {m_Pos 
= p
;} 
 122     const wxString
& GetPage() const {return m_Page
;} 
 123     const wxString
& GetAnchor() const {return m_Anchor
;} 
 132 //----------------------------------------------------------------------------- 
 133 // our private arrays: 
 134 //----------------------------------------------------------------------------- 
 136 WX_DECLARE_OBJARRAY(wxHtmlHistoryItem
, wxHtmlHistoryArray
); 
 137 WX_DEFINE_OBJARRAY(wxHtmlHistoryArray
) 
 139 WX_DECLARE_LIST(wxHtmlProcessor
, wxHtmlProcessorList
); 
 140 WX_DEFINE_LIST(wxHtmlProcessorList
) 
 142 //----------------------------------------------------------------------------- 
 143 // wxHtmlWindowMouseHelper 
 144 //----------------------------------------------------------------------------- 
 146 wxHtmlWindowMouseHelper::wxHtmlWindowMouseHelper(wxHtmlWindowInterface 
*iface
) 
 147     : m_tmpMouseMoved(false), 
 154 void wxHtmlWindowMouseHelper::HandleMouseMoved() 
 156     m_tmpMouseMoved 
= true; 
 159 bool wxHtmlWindowMouseHelper::HandleMouseClick(wxHtmlCell 
*rootCell
, 
 161                                                const wxMouseEvent
& event
) 
 166     wxHtmlCell 
*cell 
= rootCell
->FindCellByPos(pos
.x
, pos
.y
); 
 167     // this check is needed because FindCellByPos returns terminal cell and 
 168     // containers may have empty borders -- in this case NULL will be 
 173     // adjust the coordinates to be relative to this cell: 
 174     wxPoint relpos 
= pos 
- cell
->GetAbsPos(rootCell
); 
 176     return OnCellClicked(cell
, relpos
.x
, relpos
.y
, event
); 
 179 void wxHtmlWindowMouseHelper::HandleIdle(wxHtmlCell 
*rootCell
, 
 182     wxHtmlCell 
*cell 
= rootCell 
? rootCell
->FindCellByPos(pos
.x
, pos
.y
) : NULL
; 
 184     if (cell 
!= m_tmpLastCell
) 
 186         wxHtmlLinkInfo 
*lnk 
= NULL
; 
 189             // adjust the coordinates to be relative to this cell: 
 190             wxPoint relpos 
= pos 
- cell
->GetAbsPos(rootCell
); 
 191             lnk 
= cell
->GetLink(relpos
.x
, relpos
.y
); 
 196             cur 
= cell
->GetMouseCursor(m_interface
); 
 198             cur 
= m_interface
->GetHTMLCursor( 
 199                         wxHtmlWindowInterface::HTMLCursor_Default
); 
 201         m_interface
->GetHTMLWindow()->SetCursor(cur
); 
 203         if (lnk 
!= m_tmpLastLink
) 
 206                 m_interface
->SetHTMLStatusText(lnk
->GetHref()); 
 208                 m_interface
->SetHTMLStatusText(wxEmptyString
); 
 213         m_tmpLastCell 
= cell
; 
 215     else // mouse moved but stayed in the same cell 
 219             OnCellMouseHover(cell
, pos
.x
, pos
.y
); 
 223     m_tmpMouseMoved 
= false; 
 226 bool wxHtmlWindowMouseHelper::OnCellClicked(wxHtmlCell 
*cell
, 
 227                                             wxCoord x
, wxCoord y
, 
 228                                             const wxMouseEvent
& event
) 
 230     wxCHECK_MSG( cell
, false, _T("can't be called with NULL cell") ); 
 232     return cell
->ProcessMouseClick(m_interface
, wxPoint(x
, y
), event
); 
 235 void wxHtmlWindowMouseHelper::OnCellMouseHover(wxHtmlCell 
* WXUNUSED(cell
), 
 242 //----------------------------------------------------------------------------- 
 244 //----------------------------------------------------------------------------- 
 246 wxList 
wxHtmlWindow::m_Filters
; 
 247 wxHtmlFilter 
*wxHtmlWindow::m_DefaultFilter 
= NULL
; 
 248 wxHtmlProcessorList 
*wxHtmlWindow::m_GlobalProcessors 
= NULL
; 
 249 wxCursor 
*wxHtmlWindow::ms_cursorLink 
= NULL
; 
 250 wxCursor 
*wxHtmlWindow::ms_cursorText 
= NULL
; 
 252 void wxHtmlWindow::CleanUpStatics() 
 254     wxDELETE(m_DefaultFilter
); 
 255     WX_CLEAR_LIST(wxList
, m_Filters
); 
 256     if (m_GlobalProcessors
) 
 257         WX_CLEAR_LIST(wxHtmlProcessorList
, *m_GlobalProcessors
); 
 258     wxDELETE(m_GlobalProcessors
); 
 259     wxDELETE(ms_cursorLink
); 
 260     wxDELETE(ms_cursorText
); 
 263 void wxHtmlWindow::Init() 
 265     m_tmpCanDrawLocks 
= 0; 
 266     m_FS 
= new wxFileSystem(); 
 268     m_RelatedStatusBar 
= -1; 
 269 #endif // wxUSE_STATUSBAR 
 270     m_RelatedFrame 
= NULL
; 
 271     m_TitleFormat 
= wxT("%s"); 
 272     m_OpenedPage 
= m_OpenedAnchor 
= m_OpenedPageTitle 
= wxEmptyString
; 
 274     m_Parser 
= new wxHtmlWinParser(this); 
 275     m_Parser
->SetFS(m_FS
); 
 278     m_History 
= new wxHtmlHistoryArray
; 
 282     m_makingSelection 
= false; 
 284     m_timerAutoScroll 
= NULL
; 
 285     m_lastDoubleClick 
= 0; 
 286 #endif // wxUSE_CLIPBOARD 
 288     m_eraseBgInOnPaint 
= false; 
 289     m_tmpSelFromCell 
= NULL
; 
 292 bool wxHtmlWindow::Create(wxWindow 
*parent
, wxWindowID id
, 
 293                           const wxPoint
& pos
, const wxSize
& size
, 
 294                           long style
, const wxString
& name
) 
 296     if (!wxScrolledWindow::Create(parent
, id
, pos
, size
, 
 297                                   style 
| wxVSCROLL 
| wxHSCROLL
, 
 301     SetPage(wxT("<html><body></body></html>")); 
 306 wxHtmlWindow::~wxHtmlWindow() 
 310 #endif // wxUSE_CLIPBOARD 
 319         WX_CLEAR_LIST(wxHtmlProcessorList
, *m_Processors
); 
 331 void wxHtmlWindow::SetRelatedFrame(wxFrame
* frame
, const wxString
& format
) 
 333     m_RelatedFrame 
= frame
; 
 334     m_TitleFormat 
= format
; 
 340 void wxHtmlWindow::SetRelatedStatusBar(int bar
) 
 342     m_RelatedStatusBar 
= bar
; 
 344 #endif // wxUSE_STATUSBAR 
 348 void wxHtmlWindow::SetFonts(const wxString
& normal_face
, const wxString
& fixed_face
, const int *sizes
) 
 350     m_Parser
->SetFonts(normal_face
, fixed_face
, sizes
); 
 352     // re-layout the page after changing fonts: 
 353     DoSetPage(*(m_Parser
->GetSource())); 
 356 void wxHtmlWindow::SetStandardFonts(int size
, 
 357                                     const wxString
& normal_face
, 
 358                                     const wxString
& fixed_face
) 
 360     m_Parser
->SetStandardFonts(size
, normal_face
, fixed_face
); 
 362     // re-layout the page after changing fonts: 
 363     DoSetPage(*(m_Parser
->GetSource())); 
 366 bool wxHtmlWindow::SetPage(const wxString
& source
) 
 368     m_OpenedPage 
= m_OpenedAnchor 
= m_OpenedPageTitle 
= wxEmptyString
; 
 369     return DoSetPage(source
); 
 372 bool wxHtmlWindow::DoSetPage(const wxString
& source
) 
 374     wxString 
newsrc(source
); 
 376     wxDELETE(m_selection
); 
 378     // we will soon delete all the cells, so clear pointers to them: 
 379     m_tmpSelFromCell 
= NULL
; 
 381     // pass HTML through registered processors: 
 382     if (m_Processors 
|| m_GlobalProcessors
) 
 384         wxHtmlProcessorList::compatibility_iterator nodeL
, nodeG
; 
 388             nodeL 
= m_Processors
->GetFirst(); 
 389         if ( m_GlobalProcessors 
) 
 390             nodeG 
= m_GlobalProcessors
->GetFirst(); 
 392         // VS: there are two lists, global and local, both of them sorted by 
 393         //     priority. Since we have to go through _both_ lists with 
 394         //     decreasing priority, we "merge-sort" the lists on-line by 
 395         //     processing that one of the two heads that has higher priority 
 396         //     in every iteration 
 397         while (nodeL 
|| nodeG
) 
 399             prL 
= (nodeL
) ? nodeL
->GetData()->GetPriority() : -1; 
 400             prG 
= (nodeG
) ? nodeG
->GetData()->GetPriority() : -1; 
 403                 if (nodeL
->GetData()->IsEnabled()) 
 404                     newsrc 
= nodeL
->GetData()->Process(newsrc
); 
 405                 nodeL 
= nodeL
->GetNext(); 
 409                 if (nodeG
->GetData()->IsEnabled()) 
 410                     newsrc 
= nodeG
->GetData()->Process(newsrc
); 
 411                 nodeG 
= nodeG
->GetNext(); 
 416     // ...and run the parser on it: 
 417     wxClientDC 
*dc 
= new wxClientDC(this); 
 418     dc
->SetMapMode(wxMM_TEXT
); 
 419     SetBackgroundColour(wxColour(0xFF, 0xFF, 0xFF)); 
 420     SetBackgroundImage(wxNullBitmap
); 
 428     m_Cell 
= (wxHtmlContainerCell
*) m_Parser
->Parse(newsrc
); 
 430     m_Cell
->SetIndent(m_Borders
, wxHTML_INDENT_ALL
, wxHTML_UNITS_PIXELS
); 
 431     m_Cell
->SetAlignHor(wxHTML_ALIGN_CENTER
); 
 433     if (m_tmpCanDrawLocks 
== 0) 
 438 bool wxHtmlWindow::AppendToPage(const wxString
& source
) 
 440     return DoSetPage(*(GetParser()->GetSource()) + source
); 
 443 bool wxHtmlWindow::LoadPage(const wxString
& location
) 
 445     wxBusyCursor busyCursor
; 
 449     bool needs_refresh 
= false; 
 452     if (m_HistoryOn 
&& (m_HistoryPos 
!= -1)) 
 454         // store scroll position into history item: 
 456         GetViewStart(&x
, &y
); 
 457         (*m_History
)[m_HistoryPos
].SetPos(y
); 
 460     if (location
[0] == wxT('#')) 
 463         wxString anch 
= location
.Mid(1) /*1 to end*/; 
 465         rt_val 
= ScrollToAnchor(anch
); 
 468     else if (location
.Find(wxT('#')) != wxNOT_FOUND 
&& location
.BeforeFirst(wxT('#')) == m_OpenedPage
) 
 470         wxString anch 
= location
.AfterFirst(wxT('#')); 
 472         rt_val 
= ScrollToAnchor(anch
); 
 475     else if (location
.Find(wxT('#')) != wxNOT_FOUND 
&& 
 476              (m_FS
->GetPath() + location
.BeforeFirst(wxT('#'))) == m_OpenedPage
) 
 478         wxString anch 
= location
.AfterFirst(wxT('#')); 
 480         rt_val 
= ScrollToAnchor(anch
); 
 486         needs_refresh 
= true; 
 489         if (m_RelatedStatusBar 
!= -1) 
 491             m_RelatedFrame
->SetStatusText(_("Connecting..."), m_RelatedStatusBar
); 
 494 #endif // wxUSE_STATUSBAR 
 496         f 
= m_Parser
->OpenURL(wxHTML_URL_PAGE
, location
); 
 498         // try to interpret 'location' as filename instead of URL: 
 501             wxFileName 
fn(location
); 
 502             wxString location2 
= wxFileSystem::FileNameToURL(fn
); 
 503             f 
= m_Parser
->OpenURL(wxHTML_URL_PAGE
, location2
); 
 508             wxLogError(_("Unable to open requested HTML document: %s"), location
.c_str()); 
 515             wxList::compatibility_iterator node
; 
 516             wxString src 
= wxEmptyString
; 
 519             if (m_RelatedStatusBar 
!= -1) 
 521                 wxString msg 
= _("Loading : ") + location
; 
 522                 m_RelatedFrame
->SetStatusText(msg
, m_RelatedStatusBar
); 
 525 #endif // wxUSE_STATUSBAR 
 527             node 
= m_Filters
.GetFirst(); 
 530                 wxHtmlFilter 
*h 
= (wxHtmlFilter
*) node
->GetData(); 
 533                     src 
= h
->ReadFile(*f
); 
 536                 node 
= node
->GetNext(); 
 538             if (src 
== wxEmptyString
) 
 540                 if (m_DefaultFilter 
== NULL
) m_DefaultFilter 
= GetDefaultFilter(); 
 541                 src 
= m_DefaultFilter
->ReadFile(*f
); 
 544             m_FS
->ChangePathTo(f
->GetLocation()); 
 545             rt_val 
= SetPage(src
); 
 546             m_OpenedPage 
= f
->GetLocation(); 
 547             if (f
->GetAnchor() != wxEmptyString
) 
 549                 ScrollToAnchor(f
->GetAnchor()); 
 555             if (m_RelatedStatusBar 
!= -1) 
 556                 m_RelatedFrame
->SetStatusText(_("Done"), m_RelatedStatusBar
); 
 557 #endif // wxUSE_STATUSBAR 
 561     if (m_HistoryOn
) // add this page to history there: 
 563         int c 
= m_History
->GetCount() - (m_HistoryPos 
+ 1); 
 565         if (m_HistoryPos 
< 0 || 
 566             (*m_History
)[m_HistoryPos
].GetPage() != m_OpenedPage 
|| 
 567             (*m_History
)[m_HistoryPos
].GetAnchor() != m_OpenedAnchor
) 
 570             for (int i 
= 0; i 
< c
; i
++) 
 571                 m_History
->RemoveAt(m_HistoryPos
); 
 572             m_History
->Add(new wxHtmlHistoryItem(m_OpenedPage
, m_OpenedAnchor
)); 
 576     if (m_OpenedPageTitle 
== wxEmptyString
) 
 577         OnSetTitle(wxFileNameFromPath(m_OpenedPage
)); 
 591 bool wxHtmlWindow::LoadFile(const wxFileName
& filename
) 
 593     wxString url 
= wxFileSystem::FileNameToURL(filename
); 
 594     return LoadPage(url
); 
 598 bool wxHtmlWindow::ScrollToAnchor(const wxString
& anchor
) 
 600     const wxHtmlCell 
*c 
= m_Cell
->Find(wxHTML_COND_ISANCHOR
, &anchor
); 
 603         wxLogWarning(_("HTML anchor %s does not exist."), anchor
.c_str()); 
 610         for (y 
= 0; c 
!= NULL
; c 
= c
->GetParent()) y 
+= c
->GetPosY(); 
 611         Scroll(-1, y 
/ wxHTML_SCROLL_STEP
); 
 612         m_OpenedAnchor 
= anchor
; 
 618 void wxHtmlWindow::OnSetTitle(const wxString
& title
) 
 623         tit
.Printf(m_TitleFormat
, title
.c_str()); 
 624         m_RelatedFrame
->SetTitle(tit
); 
 626     m_OpenedPageTitle 
= title
; 
 633 void wxHtmlWindow::CreateLayout() 
 635     int ClientWidth
, ClientHeight
; 
 639     if ( HasFlag(wxHW_SCROLLBAR_NEVER
) ) 
 641         SetScrollbars(1, 1, 0, 0); // always off 
 642         GetClientSize(&ClientWidth
, &ClientHeight
); 
 643         m_Cell
->Layout(ClientWidth
); 
 645     else // !wxHW_SCROLLBAR_NEVER 
 647         GetClientSize(&ClientWidth
, &ClientHeight
); 
 648         m_Cell
->Layout(ClientWidth
); 
 649         if (ClientHeight 
< m_Cell
->GetHeight() + GetCharHeight()) 
 652                   wxHTML_SCROLL_STEP
, wxHTML_SCROLL_STEP
, 
 653                   m_Cell
->GetWidth() / wxHTML_SCROLL_STEP
, 
 654                   (m_Cell
->GetHeight() + GetCharHeight()) / wxHTML_SCROLL_STEP
 
 655                   /*cheat: top-level frag is always container*/); 
 657         else /* we fit into window, no need for scrollbars */ 
 659             SetScrollbars(wxHTML_SCROLL_STEP
, 1, m_Cell
->GetWidth() / wxHTML_SCROLL_STEP
, 0); // disable... 
 660             GetClientSize(&ClientWidth
, &ClientHeight
); 
 661             m_Cell
->Layout(ClientWidth
); // ...and relayout 
 668 void wxHtmlWindow::ReadCustomization(wxConfigBase 
*cfg
, wxString path
) 
 673     wxString p_fff
, p_ffn
; 
 675     if (path 
!= wxEmptyString
) 
 677         oldpath 
= cfg
->GetPath(); 
 681     m_Borders 
= cfg
->Read(wxT("wxHtmlWindow/Borders"), m_Borders
); 
 682     p_fff 
= cfg
->Read(wxT("wxHtmlWindow/FontFaceFixed"), m_Parser
->m_FontFaceFixed
); 
 683     p_ffn 
= cfg
->Read(wxT("wxHtmlWindow/FontFaceNormal"), m_Parser
->m_FontFaceNormal
); 
 684     for (int i 
= 0; i 
< 7; i
++) 
 686         tmp
.Printf(wxT("wxHtmlWindow/FontsSize%i"), i
); 
 687         p_fontsizes
[i
] = cfg
->Read(tmp
, m_Parser
->m_FontsSizes
[i
]); 
 689     SetFonts(p_ffn
, p_fff
, p_fontsizes
); 
 691     if (path 
!= wxEmptyString
) 
 692         cfg
->SetPath(oldpath
); 
 697 void wxHtmlWindow::WriteCustomization(wxConfigBase 
*cfg
, wxString path
) 
 702     if (path 
!= wxEmptyString
) 
 704         oldpath 
= cfg
->GetPath(); 
 708     cfg
->Write(wxT("wxHtmlWindow/Borders"), (long) m_Borders
); 
 709     cfg
->Write(wxT("wxHtmlWindow/FontFaceFixed"), m_Parser
->m_FontFaceFixed
); 
 710     cfg
->Write(wxT("wxHtmlWindow/FontFaceNormal"), m_Parser
->m_FontFaceNormal
); 
 711     for (int i 
= 0; i 
< 7; i
++) 
 713         tmp
.Printf(wxT("wxHtmlWindow/FontsSize%i"), i
); 
 714         cfg
->Write(tmp
, (long) m_Parser
->m_FontsSizes
[i
]); 
 717     if (path 
!= wxEmptyString
) 
 718         cfg
->SetPath(oldpath
); 
 723 bool wxHtmlWindow::HistoryBack() 
 727     if (m_HistoryPos 
< 1) return false; 
 729     // store scroll position into history item: 
 731     GetViewStart(&x
, &y
); 
 732     (*m_History
)[m_HistoryPos
].SetPos(y
); 
 734     // go to previous position: 
 737     l 
= (*m_History
)[m_HistoryPos
].GetPage(); 
 738     a 
= (*m_History
)[m_HistoryPos
].GetAnchor(); 
 741     if (a 
== wxEmptyString
) LoadPage(l
); 
 742     else LoadPage(l 
+ wxT("#") + a
); 
 745     Scroll(0, (*m_History
)[m_HistoryPos
].GetPos()); 
 750 bool wxHtmlWindow::HistoryCanBack() 
 752     if (m_HistoryPos 
< 1) return false; 
 757 bool wxHtmlWindow::HistoryForward() 
 761     if (m_HistoryPos 
== -1) return false; 
 762     if (m_HistoryPos 
>= (int)m_History
->GetCount() - 1)return false; 
 764     m_OpenedPage 
= wxEmptyString
; // this will disable adding new entry into history in LoadPage() 
 767     l 
= (*m_History
)[m_HistoryPos
].GetPage(); 
 768     a 
= (*m_History
)[m_HistoryPos
].GetAnchor(); 
 771     if (a 
== wxEmptyString
) LoadPage(l
); 
 772     else LoadPage(l 
+ wxT("#") + a
); 
 775     Scroll(0, (*m_History
)[m_HistoryPos
].GetPos()); 
 780 bool wxHtmlWindow::HistoryCanForward() 
 782     if (m_HistoryPos 
== -1) return false; 
 783     if (m_HistoryPos 
>= (int)m_History
->GetCount() - 1)return false; 
 788 void wxHtmlWindow::HistoryClear() 
 794 void wxHtmlWindow::AddProcessor(wxHtmlProcessor 
*processor
) 
 798         m_Processors 
= new wxHtmlProcessorList
; 
 800     wxHtmlProcessorList::compatibility_iterator node
; 
 802     for (node 
= m_Processors
->GetFirst(); node
; node 
= node
->GetNext()) 
 804         if (processor
->GetPriority() > node
->GetData()->GetPriority()) 
 806             m_Processors
->Insert(node
, processor
); 
 810     m_Processors
->Append(processor
); 
 813 /*static */ void wxHtmlWindow::AddGlobalProcessor(wxHtmlProcessor 
*processor
) 
 815     if (!m_GlobalProcessors
) 
 817         m_GlobalProcessors 
= new wxHtmlProcessorList
; 
 819     wxHtmlProcessorList::compatibility_iterator node
; 
 821     for (node 
= m_GlobalProcessors
->GetFirst(); node
; node 
= node
->GetNext()) 
 823         if (processor
->GetPriority() > node
->GetData()->GetPriority()) 
 825             m_GlobalProcessors
->Insert(node
, processor
); 
 829     m_GlobalProcessors
->Append(processor
); 
 834 void wxHtmlWindow::AddFilter(wxHtmlFilter 
*filter
) 
 836     m_Filters
.Append(filter
); 
 840 bool wxHtmlWindow::IsSelectionEnabled() const 
 843     return !HasFlag(wxHW_NO_SELECTION
); 
 851 wxString 
wxHtmlWindow::DoSelectionToText(wxHtmlSelection 
*sel
) 
 854         return wxEmptyString
; 
 858     const wxHtmlCell 
*end 
= sel
->GetToCell(); 
 860     wxHtmlTerminalCellsInterator 
i(sel
->GetFromCell(), end
); 
 863         text 
<< i
->ConvertToText(sel
); 
 866     const wxHtmlCell 
*prev 
= *i
; 
 869         if ( prev
->GetParent() != i
->GetParent() ) 
 871         text 
<< i
->ConvertToText(*i 
== end 
? sel 
: NULL
); 
 878 wxString 
wxHtmlWindow::ToText() 
 883         sel
.Set(m_Cell
->GetFirstTerminal(), m_Cell
->GetLastTerminal()); 
 884         return DoSelectionToText(&sel
); 
 887         return wxEmptyString
; 
 890 #endif // wxUSE_CLIPBOARD 
 892 bool wxHtmlWindow::CopySelection(ClipboardType t
) 
 897 #if defined(__UNIX__) && !defined(__WXMAC__) 
 898         wxTheClipboard
->UsePrimarySelection(t 
== Primary
); 
 900         // Primary selection exists only under X11, so don't do anything under 
 901         // the other platforms when we try to access it 
 903         // TODO: this should be abstracted at wxClipboard level! 
 906 #endif // __UNIX__/!__UNIX__ 
 908         if ( wxTheClipboard
->Open() ) 
 910             const wxString 
txt(SelectionToText()); 
 911             wxTheClipboard
->SetData(new wxTextDataObject(txt
)); 
 912             wxTheClipboard
->Close(); 
 913             wxLogTrace(_T("wxhtmlselection"), 
 914                        _("Copied to clipboard:\"%s\""), txt
.c_str()); 
 921 #endif // wxUSE_CLIPBOARD 
 927 void wxHtmlWindow::OnLinkClicked(const wxHtmlLinkInfo
& link
) 
 929     const wxMouseEvent 
*e 
= link
.GetEvent(); 
 930     if (e 
== NULL 
|| e
->LeftUp()) 
 931         LoadPage(link
.GetHref()); 
 934 void wxHtmlWindow::OnEraseBackground(wxEraseEvent
& event
) 
 938         // don't even skip the event, if we don't have a bg bitmap we're going 
 939         // to overwrite background in OnPaint() below anyhow, so letting the 
 940         // default handling take place would only result in flicker, just set a 
 941         // flag to erase the background below 
 942         m_eraseBgInOnPaint 
= true; 
 946     wxDC
& dc 
= *event
.GetDC(); 
 948     // if the image is not fully opaque, we have to erase the background before 
 949     // drawing it, however avoid doing it for opaque images as this would just 
 950     // result in extra flicker without any other effect as background is 
 951     // completely covered anyhow 
 952     if ( m_bmpBg
.GetMask() ) 
 954         dc
.SetBackground(wxBrush(GetBackgroundColour(), wxSOLID
)); 
 958     const wxSize 
sizeWin(GetClientSize()); 
 959     const wxSize 
sizeBmp(m_bmpBg
.GetWidth(), m_bmpBg
.GetHeight()); 
 960     for ( wxCoord x 
= 0; x 
< sizeWin
.x
; x 
+= sizeBmp
.x 
) 
 962         for ( wxCoord y 
= 0; y 
< sizeWin
.y
; y 
+= sizeBmp
.y 
) 
 964             dc
.DrawBitmap(m_bmpBg
, x
, y
, true /* use mask */); 
 969 void wxHtmlWindow::OnPaint(wxPaintEvent
& WXUNUSED(event
)) 
 973     if (m_tmpCanDrawLocks 
> 0 || m_Cell 
== NULL
) 
 977     GetViewStart(&x
, &y
); 
 978     wxRect rect 
= GetUpdateRegion().GetBox(); 
 979     wxSize sz 
= GetSize(); 
 983         m_backBuffer 
= new wxBitmap(sz
.x
, sz
.y
); 
 984     dcm
.SelectObject(*m_backBuffer
); 
 986     if ( m_eraseBgInOnPaint 
) 
 988         dcm
.SetBackground(wxBrush(GetBackgroundColour(), wxSOLID
)); 
 991         m_eraseBgInOnPaint 
= false; 
 993     else // someone has already erased the background, keep it 
 995         // preserve the existing background, otherwise we'd erase anything the 
 996         // user code had drawn in its EVT_ERASE_BACKGROUND handler when we do 
 997         // the Blit back below 
 998         dcm
.Blit(0, rect
.GetTop(), 
 999                  sz
.x
, rect
.GetBottom() - rect
.GetTop() + 1, 
1005     dcm
.SetMapMode(wxMM_TEXT
); 
1006     dcm
.SetBackgroundMode(wxTRANSPARENT
); 
1008     wxHtmlRenderingInfo rinfo
; 
1009     wxDefaultHtmlRenderingStyle rstyle
; 
1010     rinfo
.SetSelection(m_selection
); 
1011     rinfo
.SetStyle(&rstyle
); 
1012     m_Cell
->Draw(dcm
, 0, 0, 
1013                  y 
* wxHTML_SCROLL_STEP 
+ rect
.GetTop(), 
1014                  y 
* wxHTML_SCROLL_STEP 
+ rect
.GetBottom(), 
1017 //#define DEBUG_HTML_SELECTION 
1018 #ifdef DEBUG_HTML_SELECTION 
1021     wxGetMousePosition(&xc
, &yc
); 
1022     ScreenToClient(&xc
, &yc
); 
1023     CalcUnscrolledPosition(xc
, yc
, &x
, &y
); 
1024     wxHtmlCell 
*at 
= m_Cell
->FindCellByPos(x
, y
); 
1025     wxHtmlCell 
*before 
= 
1026         m_Cell
->FindCellByPos(x
, y
, wxHTML_FIND_NEAREST_BEFORE
); 
1028         m_Cell
->FindCellByPos(x
, y
, wxHTML_FIND_NEAREST_AFTER
); 
1030     dcm
.SetBrush(*wxTRANSPARENT_BRUSH
); 
1031     dcm
.SetPen(*wxBLACK_PEN
); 
1033         dcm
.DrawRectangle(at
->GetAbsPos(), 
1034                           wxSize(at
->GetWidth(),at
->GetHeight())); 
1035     dcm
.SetPen(*wxGREEN_PEN
); 
1037         dcm
.DrawRectangle(before
->GetAbsPos().x
+1, before
->GetAbsPos().y
+1, 
1038                           before
->GetWidth()-2,before
->GetHeight()-2); 
1039     dcm
.SetPen(*wxRED_PEN
); 
1041         dcm
.DrawRectangle(after
->GetAbsPos().x
+2, after
->GetAbsPos().y
+2, 
1042                           after
->GetWidth()-4,after
->GetHeight()-4); 
1046     dcm
.SetDeviceOrigin(0,0); 
1047     dc
.Blit(0, rect
.GetTop(), 
1048             sz
.x
, rect
.GetBottom() - rect
.GetTop() + 1, 
1056 void wxHtmlWindow::OnSize(wxSizeEvent
& event
) 
1058     wxDELETE(m_backBuffer
); 
1060     wxScrolledWindow::OnSize(event
); 
1063     // Recompute selection if necessary: 
1066         m_selection
->Set(m_selection
->GetFromCell(), 
1067                          m_selection
->GetToCell()); 
1068         m_selection
->ClearPrivPos(); 
1075 void wxHtmlWindow::OnMouseMove(wxMouseEvent
& WXUNUSED(event
)) 
1077     wxHtmlWindowMouseHelper::HandleMouseMoved(); 
1080 void wxHtmlWindow::OnMouseDown(wxMouseEvent
& event
) 
1083     if ( event
.LeftDown() && IsSelectionEnabled() ) 
1085         const long TRIPLECLICK_LEN 
= 200; // 0.2 sec after doubleclick 
1086         if ( wxGetLocalTimeMillis() - m_lastDoubleClick 
<= TRIPLECLICK_LEN 
) 
1088             SelectLine(CalcUnscrolledPosition(event
.GetPosition())); 
1090             (void) CopySelection(); 
1094             m_makingSelection 
= true; 
1098                 wxDELETE(m_selection
); 
1101             m_tmpSelFromPos 
= CalcUnscrolledPosition(event
.GetPosition()); 
1102             m_tmpSelFromCell 
= NULL
; 
1109 #endif // wxUSE_CLIPBOARD 
1112 void wxHtmlWindow::OnMouseUp(wxMouseEvent
& event
) 
1115     if ( m_makingSelection 
) 
1118         m_makingSelection 
= false; 
1120         // did the user move the mouse far enough from starting point? 
1121         if ( CopySelection(Primary
) ) 
1123             // we don't want mouse up event that ended selecting to be 
1124             // handled as mouse click and e.g. follow hyperlink: 
1128 #endif // wxUSE_CLIPBOARD 
1132     wxPoint pos 
= CalcUnscrolledPosition(event
.GetPosition()); 
1133     wxHtmlWindowMouseHelper::HandleMouseClick(m_Cell
, pos
, event
); 
1137 void wxHtmlWindow::OnMouseCaptureLost(wxMouseCaptureLostEvent
& WXUNUSED(event
)) 
1139     if ( !m_makingSelection 
) 
1142     // discard the selecting operation 
1143     m_makingSelection 
= false; 
1144     wxDELETE(m_selection
); 
1145     m_tmpSelFromCell 
= NULL
; 
1148 #endif // wxUSE_CLIPBOARD 
1151 void wxHtmlWindow::OnInternalIdle() 
1153     wxWindow::OnInternalIdle(); 
1155     if (m_Cell 
!= NULL 
&& DidMouseMove()) 
1157 #ifdef DEBUG_HTML_SELECTION 
1161         wxGetMousePosition(&xc
, &yc
); 
1162         ScreenToClient(&xc
, &yc
); 
1163         CalcUnscrolledPosition(xc
, yc
, &x
, &y
); 
1165         wxHtmlCell 
*cell 
= m_Cell
->FindCellByPos(x
, y
); 
1167         // handle selection update: 
1168         if ( m_makingSelection 
) 
1170             if ( !m_tmpSelFromCell 
) 
1171                 m_tmpSelFromCell 
= m_Cell
->FindCellByPos( 
1172                                          m_tmpSelFromPos
.x
,m_tmpSelFromPos
.y
); 
1174             // NB: a trick - we adjust selFromPos to be upper left or bottom 
1175             //     right corner of the first cell of the selection depending 
1176             //     on whether the mouse is moving to the right or to the left. 
1177             //     This gives us more "natural" behaviour when selecting 
1178             //     a line (specifically, first cell of the next line is not 
1179             //     included if you drag selection from left to right over 
1182             if ( !m_tmpSelFromCell 
) 
1184                 dirFromPos 
= m_tmpSelFromPos
; 
1188                 dirFromPos 
= m_tmpSelFromCell
->GetAbsPos(); 
1189                 if ( x 
< m_tmpSelFromPos
.x 
) 
1191                     dirFromPos
.x 
+= m_tmpSelFromCell
->GetWidth(); 
1192                     dirFromPos
.y 
+= m_tmpSelFromCell
->GetHeight(); 
1195             bool goingDown 
= dirFromPos
.y 
< y 
|| 
1196                              (dirFromPos
.y 
== y 
&& dirFromPos
.x 
< x
); 
1198             // determine selection span: 
1199             if ( /*still*/ !m_tmpSelFromCell 
) 
1203                     m_tmpSelFromCell 
= m_Cell
->FindCellByPos( 
1204                                          m_tmpSelFromPos
.x
,m_tmpSelFromPos
.y
, 
1205                                          wxHTML_FIND_NEAREST_AFTER
); 
1206                     if (!m_tmpSelFromCell
) 
1207                         m_tmpSelFromCell 
= m_Cell
->GetFirstTerminal(); 
1211                     m_tmpSelFromCell 
= m_Cell
->FindCellByPos( 
1212                                          m_tmpSelFromPos
.x
,m_tmpSelFromPos
.y
, 
1213                                          wxHTML_FIND_NEAREST_BEFORE
); 
1214                     if (!m_tmpSelFromCell
) 
1215                         m_tmpSelFromCell 
= m_Cell
->GetLastTerminal(); 
1219             wxHtmlCell 
*selcell 
= cell
; 
1224                     selcell 
= m_Cell
->FindCellByPos(x
, y
, 
1225                                                  wxHTML_FIND_NEAREST_BEFORE
); 
1227                         selcell 
= m_Cell
->GetLastTerminal(); 
1231                     selcell 
= m_Cell
->FindCellByPos(x
, y
, 
1232                                                  wxHTML_FIND_NEAREST_AFTER
); 
1234                         selcell 
= m_Cell
->GetFirstTerminal(); 
1238             // NB: it may *rarely* happen that the code above didn't find one 
1239             //     of the cells, e.g. if wxHtmlWindow doesn't contain any 
1241             if ( selcell 
&& m_tmpSelFromCell 
) 
1245                     // start selecting only if mouse movement was big enough 
1246                     // (otherwise it was meant as mouse click, not selection): 
1247                     const int PRECISION 
= 2; 
1248                     wxPoint diff 
= m_tmpSelFromPos 
- wxPoint(x
,y
); 
1249                     if (abs(diff
.x
) > PRECISION 
|| abs(diff
.y
) > PRECISION
) 
1251                         m_selection 
= new wxHtmlSelection(); 
1256                     if ( m_tmpSelFromCell
->IsBefore(selcell
) ) 
1258                         m_selection
->Set(m_tmpSelFromPos
, m_tmpSelFromCell
, 
1259                                          wxPoint(x
,y
), selcell
);                                    } 
1262                         m_selection
->Set(wxPoint(x
,y
), selcell
, 
1263                                          m_tmpSelFromPos
, m_tmpSelFromCell
); 
1265                     m_selection
->ClearPrivPos(); 
1271         // handle cursor and status bar text changes: 
1273         // NB: because we're passing in 'cell' and not 'm_Cell' (so that the 
1274         //     leaf cell lookup isn't done twice), we need to adjust the 
1275         //     position for the new root: 
1276         wxPoint 
posInCell(x
, y
); 
1278             posInCell 
-= cell
->GetAbsPos(); 
1279         wxHtmlWindowMouseHelper::HandleIdle(cell
, posInCell
); 
1284 void wxHtmlWindow::StopAutoScrolling() 
1286     if ( m_timerAutoScroll 
) 
1288         wxDELETE(m_timerAutoScroll
); 
1292 void wxHtmlWindow::OnMouseEnter(wxMouseEvent
& event
) 
1294     StopAutoScrolling(); 
1298 void wxHtmlWindow::OnMouseLeave(wxMouseEvent
& event
) 
1300     // don't prevent the usual processing of the event from taking place 
1303     // when a captured mouse leave a scrolled window we start generate 
1304     // scrolling events to allow, for example, extending selection beyond the 
1305     // visible area in some controls 
1306     if ( wxWindow::GetCapture() == this ) 
1308         // where is the mouse leaving? 
1310         wxPoint pt 
= event
.GetPosition(); 
1313             orient 
= wxHORIZONTAL
; 
1316         else if ( pt
.y 
< 0 ) 
1318             orient 
= wxVERTICAL
; 
1321         else // we're lower or to the right of the window 
1323             wxSize size 
= GetClientSize(); 
1324             if ( pt
.x 
> size
.x 
) 
1326                 orient 
= wxHORIZONTAL
; 
1327                 pos 
= GetVirtualSize().x 
/ wxHTML_SCROLL_STEP
; 
1329             else if ( pt
.y 
> size
.y 
) 
1331                 orient 
= wxVERTICAL
; 
1332                 pos 
= GetVirtualSize().y 
/ wxHTML_SCROLL_STEP
; 
1334             else // this should be impossible 
1336                 // but seems to happen sometimes under wxMSW - maybe it's a bug 
1337                 // there but for now just ignore it 
1339                 //wxFAIL_MSG( _T("can't understand where has mouse gone") ); 
1345         // only start the auto scroll timer if the window can be scrolled in 
1347         if ( !HasScrollbar(orient
) ) 
1350         delete m_timerAutoScroll
; 
1351         m_timerAutoScroll 
= new wxHtmlWinAutoScrollTimer
 
1354                                     pos 
== 0 ? wxEVT_SCROLLWIN_LINEUP
 
1355                                              : wxEVT_SCROLLWIN_LINEDOWN
, 
1359         m_timerAutoScroll
->Start(50); // FIXME: make configurable 
1363 void wxHtmlWindow::OnKeyUp(wxKeyEvent
& event
) 
1365     if ( IsSelectionEnabled() && event
.GetKeyCode() == 'C' && event
.CmdDown() ) 
1367         (void) CopySelection(); 
1371 void wxHtmlWindow::OnCopy(wxCommandEvent
& WXUNUSED(event
)) 
1373     (void) CopySelection(); 
1376 void wxHtmlWindow::OnDoubleClick(wxMouseEvent
& event
) 
1378     // select word under cursor: 
1379     if ( IsSelectionEnabled() ) 
1381         SelectWord(CalcUnscrolledPosition(event
.GetPosition())); 
1383         (void) CopySelection(Primary
); 
1385         m_lastDoubleClick 
= wxGetLocalTimeMillis(); 
1391 void wxHtmlWindow::SelectWord(const wxPoint
& pos
) 
1395         wxHtmlCell 
*cell 
= m_Cell
->FindCellByPos(pos
.x
, pos
.y
); 
1399             m_selection 
= new wxHtmlSelection(); 
1400             m_selection
->Set(cell
, cell
); 
1401             RefreshRect(wxRect(CalcScrolledPosition(cell
->GetAbsPos()), 
1402                                wxSize(cell
->GetWidth(), cell
->GetHeight()))); 
1407 void wxHtmlWindow::SelectLine(const wxPoint
& pos
) 
1411         wxHtmlCell 
*cell 
= m_Cell
->FindCellByPos(pos
.x
, pos
.y
); 
1414             // We use following heuristic to find a "line": let the line be all 
1415             // cells in same container as the cell under mouse cursor that are 
1416             // neither completely above nor completely bellow the clicked cell 
1417             // (i.e. are likely to be words positioned on same line of text). 
1419             int y1 
= cell
->GetAbsPos().y
; 
1420             int y2 
= y1 
+ cell
->GetHeight(); 
1422             const wxHtmlCell 
*c
; 
1423             const wxHtmlCell 
*before 
= NULL
; 
1424             const wxHtmlCell 
*after 
= NULL
; 
1426             // find last cell of line: 
1427             for ( c 
= cell
->GetNext(); c
; c 
= c
->GetNext()) 
1429                 y 
= c
->GetAbsPos().y
; 
1430                 if ( y 
+ c
->GetHeight() > y1 
&& y 
< y2 
) 
1438             // find first cell of line: 
1439             for ( c 
= cell
->GetParent()->GetFirstChild(); 
1440                     c 
&& c 
!= cell
; c 
= c
->GetNext()) 
1442                 y 
= c
->GetAbsPos().y
; 
1443                 if ( y 
+ c
->GetHeight() > y1 
&& y 
< y2 
) 
1455             m_selection 
= new wxHtmlSelection(); 
1456             m_selection
->Set(before
, after
); 
1463 void wxHtmlWindow::SelectAll() 
1468         m_selection 
= new wxHtmlSelection(); 
1469         m_selection
->Set(m_Cell
->GetFirstTerminal(), m_Cell
->GetLastTerminal()); 
1474 #endif // wxUSE_CLIPBOARD 
1478 IMPLEMENT_ABSTRACT_CLASS(wxHtmlProcessor
,wxObject
) 
1480 #if wxUSE_EXTENDED_RTTI 
1481 IMPLEMENT_DYNAMIC_CLASS_XTI(wxHtmlWindow
, wxScrolledWindow
,"wx/html/htmlwin.h") 
1483 wxBEGIN_PROPERTIES_TABLE(wxHtmlWindow
) 
1486         style , wxHW_SCROLLBAR_AUTO 
1487         borders , (dimension) 
1491 wxEND_PROPERTIES_TABLE() 
1493 wxBEGIN_HANDLERS_TABLE(wxHtmlWindow
) 
1494 wxEND_HANDLERS_TABLE() 
1496 wxCONSTRUCTOR_5( wxHtmlWindow 
, wxWindow
* , Parent 
, wxWindowID 
, Id 
, wxPoint 
, Position 
, wxSize 
, Size 
, long , WindowStyle 
) 
1498 IMPLEMENT_DYNAMIC_CLASS(wxHtmlWindow
,wxScrolledWindow
) 
1501 BEGIN_EVENT_TABLE(wxHtmlWindow
, wxScrolledWindow
) 
1502     EVT_SIZE(wxHtmlWindow::OnSize
) 
1503     EVT_LEFT_DOWN(wxHtmlWindow::OnMouseDown
) 
1504     EVT_LEFT_UP(wxHtmlWindow::OnMouseUp
) 
1505     EVT_RIGHT_UP(wxHtmlWindow::OnMouseUp
) 
1506     EVT_MOTION(wxHtmlWindow::OnMouseMove
) 
1507     EVT_ERASE_BACKGROUND(wxHtmlWindow::OnEraseBackground
) 
1508     EVT_PAINT(wxHtmlWindow::OnPaint
) 
1510     EVT_LEFT_DCLICK(wxHtmlWindow::OnDoubleClick
) 
1511     EVT_ENTER_WINDOW(wxHtmlWindow::OnMouseEnter
) 
1512     EVT_LEAVE_WINDOW(wxHtmlWindow::OnMouseLeave
) 
1513     EVT_MOUSE_CAPTURE_LOST(wxHtmlWindow::OnMouseCaptureLost
) 
1514     EVT_KEY_UP(wxHtmlWindow::OnKeyUp
) 
1515     EVT_MENU(wxID_COPY
, wxHtmlWindow::OnCopy
) 
1516 #endif // wxUSE_CLIPBOARD 
1519 //----------------------------------------------------------------------------- 
1520 // wxHtmlWindowInterface implementation in wxHtmlWindow 
1521 //----------------------------------------------------------------------------- 
1523 void wxHtmlWindow::SetHTMLWindowTitle(const wxString
& title
) 
1528 void wxHtmlWindow::OnHTMLLinkClicked(const wxHtmlLinkInfo
& link
) 
1530     OnLinkClicked(link
); 
1533 wxHtmlOpeningStatus 
wxHtmlWindow::OnHTMLOpeningURL(wxHtmlURLType type
, 
1534                                                    const wxString
& url
, 
1535                                                    wxString 
*redirect
) const 
1537     return OnOpeningURL(type
, url
, redirect
); 
1540 wxPoint 
wxHtmlWindow::HTMLCoordsToWindow(wxHtmlCell 
*WXUNUSED(cell
), 
1541                                          const wxPoint
& pos
) const 
1543     return CalcScrolledPosition(pos
); 
1546 wxWindow
* wxHtmlWindow::GetHTMLWindow() 
1551 wxColour 
wxHtmlWindow::GetHTMLBackgroundColour() const 
1553     return GetBackgroundColour(); 
1556 void wxHtmlWindow::SetHTMLBackgroundColour(const wxColour
& clr
) 
1558     SetBackgroundColour(clr
); 
1561 void wxHtmlWindow::SetHTMLBackgroundImage(const wxBitmap
& bmpBg
) 
1563     SetBackgroundImage(bmpBg
); 
1566 void wxHtmlWindow::SetHTMLStatusText(const wxString
& text
) 
1569     if (m_RelatedStatusBar 
!= -1) 
1570         m_RelatedFrame
->SetStatusText(text
, m_RelatedStatusBar
); 
1573 #endif // wxUSE_STATUSBAR 
1577 wxCursor 
wxHtmlWindow::GetDefaultHTMLCursor(HTMLCursor type
) 
1581         case HTMLCursor_Link
: 
1582             if ( !ms_cursorLink 
) 
1583                 ms_cursorLink 
= new wxCursor(wxCURSOR_HAND
); 
1584             return *ms_cursorLink
; 
1586         case HTMLCursor_Text
: 
1587             if ( !ms_cursorText 
) 
1588                 ms_cursorText 
= new wxCursor(wxCURSOR_IBEAM
); 
1589             return *ms_cursorText
; 
1591         case HTMLCursor_Default
: 
1593             return *wxSTANDARD_CURSOR
; 
1597 wxCursor 
wxHtmlWindow::GetHTMLCursor(HTMLCursor type
) const 
1599     return GetDefaultHTMLCursor(type
); 
1603 //----------------------------------------------------------------------------- 
1605 //----------------------------------------------------------------------------- 
1607 // A module to allow initialization/cleanup 
1608 // without calling these functions from app.cpp or from 
1609 // the user's application. 
1611 class wxHtmlWinModule
: public wxModule
 
1613 DECLARE_DYNAMIC_CLASS(wxHtmlWinModule
) 
1615     wxHtmlWinModule() : wxModule() {} 
1616     bool OnInit() { return true; } 
1617     void OnExit() { wxHtmlWindow::CleanUpStatics(); } 
1620 IMPLEMENT_DYNAMIC_CLASS(wxHtmlWinModule
, wxModule
) 
1623 // This hack forces the linker to always link in m_* files 
1624 // (wxHTML doesn't work without handlers from these files) 
1625 #include "wx/html/forcelnk.h" 
1626 FORCE_WXHTML_MODULES() 
1628 #endif // wxUSE_HTML