1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling, Vadim Zeitlin 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  11 #pragma implementation "textctrl.h" 
  14 // For compilers that support precompilation, includes "wx.h". 
  15 #include "wx/wxprec.h" 
  17 #include "wx/textctrl.h" 
  21 #include "wx/settings.h" 
  23 #include "wx/strconv.h" 
  24 #include "wx/fontutil.h"        // for wxNativeFontInfo (GetNativeFontInfo()) 
  26 #include <sys/types.h> 
  31 #include "wx/gtk/private.h" 
  32 #include <gdk/gdkkeysyms.h> 
  34 //----------------------------------------------------------------------------- 
  36 //----------------------------------------------------------------------------- 
  38 extern void wxapp_install_idle_handler(); 
  41 //----------------------------------------------------------------------------- 
  43 //----------------------------------------------------------------------------- 
  45 extern bool       g_blockEventsOnDrag
; 
  46 extern wxCursor   g_globalCursor
; 
  47 extern wxWindowGTK 
*g_delayedFocus
; 
  49 // ---------------------------------------------------------------------------- 
  51 // ---------------------------------------------------------------------------- 
  54 static void wxGtkTextApplyTagsFromAttr(GtkTextBuffer 
*text_buffer
, 
  55                                        const wxTextAttr
& attr
, 
  59     static gchar buf
[1024]; 
  65         PangoFontDescription 
*font_description 
= attr
.GetFont().GetNativeFontInfo()->description
; 
  66         font_string 
= pango_font_description_to_string(font_description
); 
  67         g_snprintf(buf
, sizeof(buf
), "WXFONT %s", font_string
); 
  68         tag 
= gtk_text_tag_table_lookup( gtk_text_buffer_get_tag_table( text_buffer 
), 
  71             tag 
= gtk_text_buffer_create_tag( text_buffer
, buf
, 
  72                                               "font-desc", font_description
, 
  74         gtk_text_buffer_apply_tag (text_buffer
, tag
, start
, end
); 
  78     if (attr
.HasTextColour()) 
  80         GdkColor 
*colFg 
= attr
.GetTextColour().GetColor(); 
  81         g_snprintf(buf
, sizeof(buf
), "WXFORECOLOR %d %d %d", 
  82                    colFg
->red
, colFg
->green
, colFg
->blue
); 
  83         tag 
= gtk_text_tag_table_lookup( gtk_text_buffer_get_tag_table( text_buffer 
), 
  86             tag 
= gtk_text_buffer_create_tag( text_buffer
, buf
, 
  87                                               "foreground-gdk", colFg
, NULL 
); 
  88         gtk_text_buffer_apply_tag (text_buffer
, tag
, start
, end
); 
  91     if (attr
.HasBackgroundColour()) 
  93         GdkColor 
*colBg 
= attr
.GetBackgroundColour().GetColor(); 
  94         g_snprintf(buf
, sizeof(buf
), "WXBACKCOLOR %d %d %d", 
  95                    colBg
->red
, colBg
->green
, colBg
->blue
); 
  96         tag 
= gtk_text_tag_table_lookup( gtk_text_buffer_get_tag_table( text_buffer 
), 
  99             tag 
= gtk_text_buffer_create_tag( text_buffer
, buf
, 
 100                                               "background-gdk", colBg
, NULL 
); 
 101         gtk_text_buffer_apply_tag (text_buffer
, tag
, start
, end
); 
 105 static void wxGtkTextInsert(GtkWidget 
*text
, 
 106                             GtkTextBuffer 
*text_buffer
, 
 107                             const wxTextAttr
& attr
, 
 112     GtkTextIter iter
, start
; 
 114     gtk_text_buffer_get_iter_at_mark( text_buffer
, &iter
, 
 115                                      gtk_text_buffer_get_insert (text_buffer
) ); 
 116     start_offset 
= gtk_text_iter_get_offset (&iter
); 
 117     gtk_text_buffer_insert( text_buffer
, &iter
, buffer
, strlen(buffer
) ); 
 119     gtk_text_buffer_get_iter_at_offset (text_buffer
, &start
, start_offset
); 
 121     wxGtkTextApplyTagsFromAttr(text_buffer
, attr
, &start
, &iter
); 
 124 static void wxGtkTextInsert(GtkWidget 
*text
, 
 125                             const wxTextAttr
& attr
, 
 129     GdkFont 
*font 
= attr
.HasFont() ? attr
.GetFont().GetInternalFont() 
 132     GdkColor 
*colFg 
= attr
.HasTextColour() ? attr
.GetTextColour().GetColor() 
 135     GdkColor 
*colBg 
= attr
.HasBackgroundColour() 
 136                         ? attr
.GetBackgroundColour().GetColor() 
 139     gtk_text_insert( GTK_TEXT(text
), font
, colFg
, colBg
, txt
, len 
); 
 143 // ---------------------------------------------------------------------------- 
 144 // "insert_text" for GtkEntry 
 145 // ---------------------------------------------------------------------------- 
 148 gtk_insert_text_callback(GtkEditable 
*editable
, 
 149                          const gchar 
*new_text
, 
 150                          gint new_text_length
, 
 155         wxapp_install_idle_handler(); 
 157     // we should only be called if we have a max len limit at all 
 158     GtkEntry 
*entry 
= GTK_ENTRY (editable
); 
 160     wxCHECK_RET( entry
->text_max_length
, _T("shouldn't be called") ); 
 162     // check that we don't overflow the max length limit 
 164     // FIXME: this doesn't work when we paste a string which is going to be 
 166     if ( entry
->text_length 
== entry
->text_max_length 
) 
 168         // we don't need to run the base class version at all 
 169         gtk_signal_emit_stop_by_name(GTK_OBJECT(editable
), "insert_text"); 
 171         // remember that the next changed signal is to be ignored to avoid 
 172         // generating a dummy wxEVT_COMMAND_TEXT_UPDATED event 
 173         win
->IgnoreNextTextUpdate(); 
 175         // and generate the correct one ourselves 
 176         wxCommandEvent 
event(wxEVT_COMMAND_TEXT_MAXLEN
, win
->GetId()); 
 177         event
.SetEventObject(win
); 
 178         event
.SetString(win
->GetValue()); 
 179         win
->GetEventHandler()->ProcessEvent( event 
); 
 183 //----------------------------------------------------------------------------- 
 185 //----------------------------------------------------------------------------- 
 188 gtk_text_changed_callback( GtkWidget 
*widget
, wxTextCtrl 
*win 
) 
 190     if ( win
->IgnoreTextUpdate() ) 
 193     if (!win
->m_hasVMT
) return; 
 196         wxapp_install_idle_handler(); 
 200     win
->UpdateFontIfNeeded(); 
 201 #endif // !__WXGTK20__ 
 203     wxCommandEvent 
event( wxEVT_COMMAND_TEXT_UPDATED
, win
->GetId() ); 
 204     event
.SetEventObject( win 
); 
 205     win
->GetEventHandler()->ProcessEvent( event 
); 
 208 //----------------------------------------------------------------------------- 
 209 // "expose_event" from scrolled window and textview 
 210 //----------------------------------------------------------------------------- 
 214 gtk_text_exposed_callback( GtkWidget 
*widget
, GdkEventExpose 
*event
, wxTextCtrl 
*win 
) 
 220 //----------------------------------------------------------------------------- 
 221 // "changed" from vertical scrollbar 
 222 //----------------------------------------------------------------------------- 
 226 gtk_scrollbar_changed_callback( GtkWidget 
*WXUNUSED(widget
), wxTextCtrl 
*win 
) 
 228     if (!win
->m_hasVMT
) return; 
 231         wxapp_install_idle_handler(); 
 233     win
->CalculateScrollbar(); 
 237 // ---------------------------------------------------------------------------- 
 238 // redraw callback for multiline text 
 239 // ---------------------------------------------------------------------------- 
 243 // redrawing a GtkText from inside a wxYield() call results in crashes (the 
 244 // text sample shows it in its "Add lines" command which shows wxProgressDialog 
 245 // which implicitly calls wxYield()) so we override GtkText::draw() and simply 
 246 // don't do anything if we're inside wxYield() 
 248 extern bool wxIsInsideYield
; 
 251     typedef void (*GtkDrawCallback
)(GtkWidget 
*widget
, GdkRectangle 
*rect
); 
 254 static GtkDrawCallback gs_gtk_text_draw 
= NULL
; 
 257 void wxgtk_text_draw( GtkWidget 
*widget
, GdkRectangle 
*rect
) 
 259     if ( !wxIsInsideYield 
) 
 261         wxCHECK_RET( gs_gtk_text_draw 
!= wxgtk_text_draw
, 
 262                      _T("infinite recursion in wxgtk_text_draw aborted") ); 
 264         gs_gtk_text_draw(widget
, rect
); 
 268 #endif // __WXGTK20__ 
 270 //----------------------------------------------------------------------------- 
 272 //----------------------------------------------------------------------------- 
 274 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl
,wxControl
) 
 276 BEGIN_EVENT_TABLE(wxTextCtrl
, wxControl
) 
 277     EVT_CHAR(wxTextCtrl::OnChar
) 
 279     EVT_MENU(wxID_CUT
, wxTextCtrl::OnCut
) 
 280     EVT_MENU(wxID_COPY
, wxTextCtrl::OnCopy
) 
 281     EVT_MENU(wxID_PASTE
, wxTextCtrl::OnPaste
) 
 282     EVT_MENU(wxID_UNDO
, wxTextCtrl::OnUndo
) 
 283     EVT_MENU(wxID_REDO
, wxTextCtrl::OnRedo
) 
 285     EVT_UPDATE_UI(wxID_CUT
, wxTextCtrl::OnUpdateCut
) 
 286     EVT_UPDATE_UI(wxID_COPY
, wxTextCtrl::OnUpdateCopy
) 
 287     EVT_UPDATE_UI(wxID_PASTE
, wxTextCtrl::OnUpdatePaste
) 
 288     EVT_UPDATE_UI(wxID_UNDO
, wxTextCtrl::OnUpdateUndo
) 
 289     EVT_UPDATE_UI(wxID_REDO
, wxTextCtrl::OnUpdateRedo
) 
 292 void wxTextCtrl::Init() 
 296     SetUpdateFont(false); 
 298     m_vScrollbar 
= (GtkWidget 
*)NULL
; 
 304 wxTextCtrl::wxTextCtrl( wxWindow 
*parent
, 
 306                         const wxString 
&value
, 
 310                         const wxValidator
& validator
, 
 311                         const wxString 
&name 
) 
 315     Create( parent
, id
, value
, pos
, size
, style
, validator
, name 
); 
 318 bool wxTextCtrl::Create( wxWindow 
*parent
, 
 320                          const wxString 
&value
, 
 324                          const wxValidator
& validator
, 
 325                          const wxString 
&name 
) 
 328     m_acceptsFocus 
= true; 
 330     if (!PreCreation( parent
, pos
, size 
) || 
 331         !CreateBase( parent
, id
, pos
, size
, style
, validator
, name 
)) 
 333         wxFAIL_MSG( wxT("wxTextCtrl creation failed") ); 
 338     m_vScrollbarVisible 
= false; 
 340     bool multi_line 
= (style 
& wxTE_MULTILINE
) != 0; 
 346         m_text 
= gtk_text_view_new(); 
 348         m_buffer 
= gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_text
) ); 
 350         // create scrolled window 
 351         m_widget 
= gtk_scrolled_window_new( NULL
, NULL 
); 
 352         gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( m_widget 
), 
 353                                         GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC 
); 
 355         // Insert view into scrolled window 
 356         gtk_container_add( GTK_CONTAINER(m_widget
), m_text 
); 
 358         // Global settings which can be overridden by tags, I guess. 
 359         if (HasFlag( wxHSCROLL 
) || HasFlag( wxTE_DONTWRAP 
)) 
 360             gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( m_text 
), GTK_WRAP_NONE 
); 
 362             gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( m_text 
), GTK_WRAP_WORD 
); 
 364         if (!HasFlag(wxNO_BORDER
)) 
 365             gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(m_widget
), GTK_SHADOW_IN 
); 
 367         GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS 
); 
 369         // create our control ... 
 370         m_text 
= gtk_text_new( (GtkAdjustment 
*) NULL
, (GtkAdjustment 
*) NULL 
); 
 372         // ... and put into the upper left hand corner of the table 
 373         bool bHasHScrollbar 
= false; 
 374         m_widget 
= gtk_table_new(bHasHScrollbar 
? 2 : 1, 2, FALSE
); 
 375         GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS 
); 
 376         gtk_table_attach( GTK_TABLE(m_widget
), m_text
, 0, 1, 0, 1, 
 377                       (GtkAttachOptions
)(GTK_FILL 
| GTK_EXPAND 
| GTK_SHRINK
), 
 378                       (GtkAttachOptions
)(GTK_FILL 
| GTK_EXPAND 
| GTK_SHRINK
), 
 382         gtk_text_set_word_wrap( GTK_TEXT(m_text
), TRUE 
); 
 384         // finally, put the vertical scrollbar in the upper right corner 
 385         m_vScrollbar 
= gtk_vscrollbar_new( GTK_TEXT(m_text
)->vadj 
); 
 386         GTK_WIDGET_UNSET_FLAGS( m_vScrollbar
, GTK_CAN_FOCUS 
); 
 387         gtk_table_attach(GTK_TABLE(m_widget
), m_vScrollbar
, 1, 2, 0, 1, 
 389                      (GtkAttachOptions
)(GTK_EXPAND 
| GTK_FILL 
| GTK_SHRINK
), 
 395         // a single-line text control: no need for scrollbars 
 397         m_text 
= gtk_entry_new(); 
 400         if (style 
& wxNO_BORDER
) 
 401             g_object_set( GTK_ENTRY(m_text
), "has-frame", FALSE
, NULL 
); 
 405     m_parent
->DoAddChild( this ); 
 407     m_focusWidget 
= m_text
; 
 412         gtk_widget_show(m_text
); 
 417         gtk_signal_connect(GTK_OBJECT(GTK_TEXT(m_text
)->vadj
), "changed", 
 418           (GtkSignalFunc
) gtk_scrollbar_changed_callback
, (gpointer
) this ); 
 420         // only initialize gs_gtk_text_draw once, starting from the next the 
 421         // klass::draw will already be wxgtk_text_draw 
 422         if ( !gs_gtk_text_draw 
) 
 425                 draw 
= GTK_WIDGET_CLASS(GTK_OBJECT(m_text
)->klass
)->draw
; 
 427             gs_gtk_text_draw 
= draw
; 
 429             draw 
= wxgtk_text_draw
; 
 440 #if !GTK_CHECK_VERSION(1, 2, 0) 
 441         // if we don't realize it, GTK 1.0.6 dies with a SIGSEGV in 
 442         // gtk_editable_insert_text() 
 443         gtk_widget_realize(m_text
); 
 448         wxWX2MBbuf val 
= value
.mbc_str(); 
 449         gtk_editable_insert_text( GTK_EDITABLE(m_text
), val
, strlen(val
), &tmp 
); 
 451         gtk_editable_insert_text( GTK_EDITABLE(m_text
), value
, value
.Length(), &tmp 
); 
 456             // Bring editable's cursor uptodate. Bug in GTK. 
 457             SET_EDITABLE_POS(m_text
, gtk_text_get_point( GTK_TEXT(m_text
) )); 
 463     if (style 
& wxTE_PASSWORD
) 
 466             gtk_entry_set_visibility( GTK_ENTRY(m_text
), FALSE 
); 
 469     if (style 
& wxTE_READONLY
) 
 472             gtk_entry_set_editable( GTK_ENTRY(m_text
), FALSE 
); 
 475             gtk_text_view_set_editable( GTK_TEXT_VIEW( m_text
), FALSE
); 
 481             gtk_text_set_editable( GTK_TEXT(m_text
), 1 ); 
 488         if (style 
& wxTE_RIGHT
) 
 489             gtk_text_view_set_justification( GTK_TEXT_VIEW(m_text
), GTK_JUSTIFY_RIGHT 
); 
 490         else if (style 
& wxTE_CENTRE
) 
 491             gtk_text_view_set_justification( GTK_TEXT_VIEW(m_text
), GTK_JUSTIFY_CENTER 
); 
 492         // Left justify (alignment) is the default and we don't need to apply GTK_JUSTIFY_LEFT 
 497         // gtk_entry_set_alignment was introduced in gtk+-2.3.5 
 498         if (!gtk_check_version(2,4,0)) 
 500             if (style 
& wxTE_RIGHT
) 
 501                 gtk_entry_set_alignment( GTK_ENTRY(m_text
), 1.0 ); 
 502             else if (style 
& wxTE_CENTRE
) 
 503                 gtk_entry_set_alignment( GTK_ENTRY(m_text
), 0.5 ); 
 507 #endif // __WXGTK20__ 
 509     // We want to be notified about text changes. 
 513         g_signal_connect( G_OBJECT(m_buffer
), "changed", 
 514             GTK_SIGNAL_FUNC(gtk_text_changed_callback
), (gpointer
)this); 
 520         gtk_signal_connect( GTK_OBJECT(m_text
), "changed", 
 521             GTK_SIGNAL_FUNC(gtk_text_changed_callback
), (gpointer
)this); 
 524     m_cursor 
= wxCursor( wxCURSOR_IBEAM 
); 
 526     wxTextAttr 
attrDef(GetForegroundColour(), GetBackgroundColour(), GetFont()); 
 527     SetDefaultStyle( attrDef 
); 
 533 void wxTextCtrl::CalculateScrollbar() 
 536     if ((m_windowStyle 
& wxTE_MULTILINE
) == 0) return; 
 538     GtkAdjustment 
*adj 
= GTK_TEXT(m_text
)->vadj
; 
 540     if (adj
->upper 
- adj
->page_size 
< 0.8) 
 542         if (m_vScrollbarVisible
) 
 544             gtk_widget_hide( m_vScrollbar 
); 
 545             m_vScrollbarVisible 
= false; 
 550         if (!m_vScrollbarVisible
) 
 552             gtk_widget_show( m_vScrollbar 
); 
 553             m_vScrollbarVisible 
= true; 
 559 wxString 
wxTextCtrl::GetValue() const 
 561     wxCHECK_MSG( m_text 
!= NULL
, wxT(""), wxT("invalid text ctrl") ); 
 564     if (m_windowStyle 
& wxTE_MULTILINE
) 
 568         gtk_text_buffer_get_start_iter( m_buffer
, &start 
); 
 570         gtk_text_buffer_get_end_iter( m_buffer
, &end 
); 
 571         gchar 
*text 
= gtk_text_buffer_get_text( m_buffer
, &start
, &end
, TRUE 
); 
 574         wxWCharBuffer 
buffer( wxConvUTF8
.cMB2WX( text 
) ); 
 576         wxCharBuffer 
buffer( wxConvLocal
.cWC2WX( wxConvUTF8
.cMB2WC( text 
) ) ); 
 583         gint len 
= gtk_text_get_length( GTK_TEXT(m_text
) ); 
 584         char *text 
= gtk_editable_get_chars( GTK_EDITABLE(m_text
), 0, len 
); 
 591         tmp 
= wxGTK_CONV_BACK( gtk_entry_get_text( GTK_ENTRY(m_text
) ) ); 
 597 void wxTextCtrl::SetValue( const wxString 
&value 
) 
 599     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
 601     if (m_windowStyle 
& wxTE_MULTILINE
) 
 606         wxCharBuffer 
buffer( wxConvUTF8
.cWX2MB( value
) ); 
 608         wxCharBuffer 
buffer( wxConvUTF8
.cWC2MB( wxConvLocal
.cWX2WC( value 
) ) ); 
 610         if (gtk_text_buffer_get_char_count(m_buffer
) != 0) 
 611             IgnoreNextTextUpdate(); 
 613         gtk_text_buffer_set_text( m_buffer
, buffer
, strlen(buffer
) ); 
 616         gint len 
= gtk_text_get_length( GTK_TEXT(m_text
) ); 
 617         gtk_editable_delete_text( GTK_EDITABLE(m_text
), 0, len 
); 
 619         gtk_editable_insert_text( GTK_EDITABLE(m_text
), value
.mbc_str(), value
.Length(), &len 
); 
 624         gtk_entry_set_text( GTK_ENTRY(m_text
), wxGTK_CONV( value 
) ); 
 627     // GRG, Jun/2000: Changed this after a lot of discussion in 
 628     //   the lists. wxWidgets 2.2 will have a set of flags to 
 629     //   customize this behaviour. 
 630     SetInsertionPoint(0); 
 635 void wxTextCtrl::WriteText( const wxString 
&text 
) 
 637     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
 642     // gtk_text_changed_callback() will set m_modified to true but m_modified 
 643     // shouldn't be changed by the program writing to the text control itself, 
 644     // so save the old value and restore when we're done 
 645     bool oldModified 
= m_modified
; 
 647     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
 652         wxCharBuffer 
buffer( wxConvUTF8
.cWX2MB( text 
) ); 
 654         wxCharBuffer 
buffer( wxConvUTF8
.cWC2MB( wxConvLocal
.cWX2WC( text 
) ) ); 
 658             // what else can we do? at least don't crash... 
 662         // TODO: Call whatever is needed to delete the selection. 
 663         wxGtkTextInsert( m_text
, m_buffer
, m_defaultStyle
, buffer 
); 
 665         GtkAdjustment 
*adj 
= gtk_scrolled_window_get_vadjustment( GTK_SCROLLED_WINDOW(m_widget
) ); 
 666         // Scroll to cursor, but only if scrollbar thumb is at the very bottom 
 667         if ( adj
->value 
== adj
->upper 
- adj
->page_size 
) 
 669             gtk_text_view_scroll_to_mark( GTK_TEXT_VIEW(m_text
), 
 670                     gtk_text_buffer_get_insert( m_buffer 
), 0.0, FALSE
, 0.0, 1.0 ); 
 673         // After cursor movements, gtk_text_get_point() is wrong by one. 
 674         gtk_text_set_point( GTK_TEXT(m_text
), GET_EDITABLE_POS(m_text
) ); 
 676         // always use m_defaultStyle, even if it is empty as otherwise 
 677         // resetting the style and appending some more text wouldn't work: if 
 678         // we don't specify the style explicitly, the old style would be used 
 679         gtk_editable_delete_selection( GTK_EDITABLE(m_text
) ); 
 680         wxGtkTextInsert(m_text
, m_defaultStyle
, text
.c_str(), text
.Len()); 
 682         // we called wxGtkTextInsert with correct font, no need to do anything 
 683         // in UpdateFontIfNeeded() any longer 
 686             SetUpdateFont(false); 
 689         // Bring editable's cursor back uptodate. 
 690         SET_EDITABLE_POS(m_text
, gtk_text_get_point( GTK_TEXT(m_text
) )); 
 691 #endif // GTK 1.x/2.0 
 695         // First remove the selection if there is one 
 696         gtk_editable_delete_selection( GTK_EDITABLE(m_text
) ); 
 698         // This moves the cursor pos to behind the inserted text. 
 699         gint len 
= GET_EDITABLE_POS(m_text
); 
 704         wxCharBuffer 
buffer( wxConvUTF8
.cWX2MB( text 
) ); 
 706         wxCharBuffer 
buffer( wxConvUTF8
.cWC2MB( wxConvLocal
.cWX2WC( text 
) ) ); 
 708         gtk_editable_insert_text( GTK_EDITABLE(m_text
), buffer
, strlen(buffer
), &len 
); 
 711         gtk_editable_insert_text( GTK_EDITABLE(m_text
), text
.c_str(), text
.Len(), &len 
); 
 714         // Bring entry's cursor uptodate. 
 715         gtk_entry_set_position( GTK_ENTRY(m_text
), len 
); 
 718     m_modified 
= oldModified
; 
 721 void wxTextCtrl::AppendText( const wxString 
&text 
) 
 723     SetInsertionPointEnd(); 
 727 wxString 
wxTextCtrl::GetLineText( long lineNo 
) const 
 729     if (m_windowStyle 
& wxTE_MULTILINE
) 
 732         gint len 
= gtk_text_get_length( GTK_TEXT(m_text
) ); 
 733         char *text 
= gtk_editable_get_chars( GTK_EDITABLE(m_text
), 0, len 
); 
 737             wxString 
buf(wxT("")); 
 740             for (i 
= 0; currentLine 
!= lineNo 
&& text
[i
]; i
++ ) 
 745             for (j 
= 0; text
[i
] && text
[i
] != '\n'; i
++, j
++ ) 
 753             return wxEmptyString
; 
 757         gtk_text_buffer_get_iter_at_line(m_buffer
,&line
,lineNo
); 
 759         gtk_text_buffer_get_end_iter(m_buffer
,&end 
); 
 760         gchar 
*text 
= gtk_text_buffer_get_text(m_buffer
,&line
,&end
,TRUE
); 
 761         wxString 
result(wxGTK_CONV_BACK(text
)); 
 763         return result
.BeforeFirst(wxT('\n')); 
 768         if (lineNo 
== 0) return GetValue(); 
 769         return wxEmptyString
; 
 773 void wxTextCtrl::OnDropFiles( wxDropFilesEvent 
&WXUNUSED(event
) ) 
 775   /* If you implement this, don't forget to update the documentation! 
 776    * (file docs/latex/wx/text.tex) */ 
 777     wxFAIL_MSG( wxT("wxTextCtrl::OnDropFiles not implemented") ); 
 780 bool wxTextCtrl::PositionToXY(long pos
, long *x
, long *y 
) const 
 782     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
 784         wxString text 
= GetValue(); 
 786         // cast to prevent warning. But pos really should've been unsigned. 
 787         if( (unsigned long)pos 
> text
.Len()  ) 
 793         const wxChar
* stop 
= text
.c_str() + pos
; 
 794         for ( const wxChar 
*p 
= text
.c_str(); p 
< stop
; p
++ ) 
 805     else // single line control 
 807         if ( pos 
<= GTK_ENTRY(m_text
)->text_length 
) 
 814             // index out of bounds 
 822 long wxTextCtrl::XYToPosition(long x
, long y 
) const 
 824     if (!(m_windowStyle 
& wxTE_MULTILINE
)) return 0; 
 827     for( int i
=0; i
<y
; i
++ ) pos 
+= GetLineLength(i
) + 1; // one for '\n' 
 833 int wxTextCtrl::GetLineLength(long lineNo
) const 
 835     wxString str 
= GetLineText (lineNo
); 
 836     return (int) str
.Length(); 
 839 int wxTextCtrl::GetNumberOfLines() const 
 841     if (m_windowStyle 
& wxTE_MULTILINE
) 
 844         return gtk_text_buffer_get_line_count( m_buffer 
); 
 846         gint len 
= gtk_text_get_length( GTK_TEXT(m_text
) ); 
 847         char *text 
= gtk_editable_get_chars( GTK_EDITABLE(m_text
), 0, len 
); 
 852             for (int i 
= 0; i 
< len
; i
++ ) 
 859             // currentLine is 0 based, add 1 to get number of lines 
 860             return currentLine 
+ 1; 
 874 void wxTextCtrl::SetInsertionPoint( long pos 
) 
 876     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
 882         gtk_text_buffer_get_iter_at_offset( m_buffer
, &iter
, pos 
); 
 883         gtk_text_buffer_place_cursor( m_buffer
, &iter 
); 
 884         gtk_text_view_scroll_mark_onscreen
 
 886             GTK_TEXT_VIEW(m_text
), 
 887             gtk_text_buffer_get_insert( m_buffer 
) 
 890         gtk_signal_disconnect_by_func( GTK_OBJECT(m_text
), 
 891           GTK_SIGNAL_FUNC(gtk_text_changed_callback
), (gpointer
)this); 
 893         /* we fake a set_point by inserting and deleting. as the user 
 894            isn't supposed to get to know about this non-sense, we 
 895            disconnect so that no events are sent to the user program. */ 
 897         gint tmp 
= (gint
)pos
; 
 898         gtk_editable_insert_text( GTK_EDITABLE(m_text
), " ", 1, &tmp 
); 
 899         gtk_editable_delete_text( GTK_EDITABLE(m_text
), tmp
-1, tmp 
); 
 901         gtk_signal_connect( GTK_OBJECT(m_text
), "changed", 
 902           GTK_SIGNAL_FUNC(gtk_text_changed_callback
), (gpointer
)this); 
 904         // bring editable's cursor uptodate. Bug in GTK. 
 905         SET_EDITABLE_POS(m_text
, gtk_text_get_point( GTK_TEXT(m_text
) )); 
 910         gtk_entry_set_position( GTK_ENTRY(m_text
), (int)pos 
); 
 912         // Bring editable's cursor uptodate. Bug in GTK. 
 913         SET_EDITABLE_POS(m_text
, (guint32
)pos
); 
 917 void wxTextCtrl::SetInsertionPointEnd() 
 919     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
 921     if (m_windowStyle 
& wxTE_MULTILINE
) 
 925         gtk_text_buffer_get_end_iter( m_buffer
, &end 
); 
 926         gtk_text_buffer_place_cursor( m_buffer
, &end 
); 
 928         SetInsertionPoint(gtk_text_get_length(GTK_TEXT(m_text
))); 
 933         gtk_entry_set_position( GTK_ENTRY(m_text
), -1 ); 
 937 void wxTextCtrl::SetEditable( bool editable 
) 
 939     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
 941     if (m_windowStyle 
& wxTE_MULTILINE
) 
 944         gtk_text_view_set_editable( GTK_TEXT_VIEW(m_text
), editable 
); 
 946         gtk_text_set_editable( GTK_TEXT(m_text
), editable 
); 
 951         gtk_entry_set_editable( GTK_ENTRY(m_text
), editable 
); 
 955 bool wxTextCtrl::Enable( bool enable 
) 
 957     if (!wxWindowBase::Enable(enable
)) 
 963     if (m_windowStyle 
& wxTE_MULTILINE
) 
 966         SetEditable( enable 
); 
 968         gtk_text_set_editable( GTK_TEXT(m_text
), enable 
); 
 969         OnParentEnable(enable
); 
 974         gtk_widget_set_sensitive( m_text
, enable 
); 
 980 // wxGTK-specific: called recursively by Enable, 
 981 // to give widgets an oppprtunity to correct their colours after they 
 982 // have been changed by Enable 
 983 void wxTextCtrl::OnParentEnable( bool enable 
) 
 985     // If we have a custom background colour, we use this colour in both 
 986     // disabled and enabled mode, or we end up with a different colour under the 
 988     wxColour oldColour 
= GetBackgroundColour(); 
 991         // Need to set twice or it'll optimize the useful stuff out 
 992         if (oldColour 
== * wxWHITE
) 
 993             SetBackgroundColour(*wxBLACK
); 
 995             SetBackgroundColour(*wxWHITE
); 
 996         SetBackgroundColour(oldColour
); 
1000 void wxTextCtrl::MarkDirty() 
1005 void wxTextCtrl::DiscardEdits() 
1010 // ---------------------------------------------------------------------------- 
1011 // max text length support 
1012 // ---------------------------------------------------------------------------- 
1014 void wxTextCtrl::IgnoreNextTextUpdate() 
1016     m_ignoreNextUpdate 
= true; 
1019 bool wxTextCtrl::IgnoreTextUpdate() 
1021     if ( m_ignoreNextUpdate 
) 
1023         m_ignoreNextUpdate 
= false; 
1031 void wxTextCtrl::SetMaxLength(unsigned long len
) 
1033     if ( !HasFlag(wxTE_MULTILINE
) ) 
1035         gtk_entry_set_max_length(GTK_ENTRY(m_text
), len
); 
1037         // there is a bug in GTK+ 1.2.x: "changed" signal is emitted even if 
1038         // we had tried to enter more text than allowed by max text length and 
1039         // the text wasn't really changed 
1041         // to detect this and generate TEXT_MAXLEN event instead of 
1042         // TEXT_CHANGED one in this case we also catch "insert_text" signal 
1044         // when max len is set to 0 we disconnect our handler as it means that 
1045         // we shouldn't check anything any more 
1048             gtk_signal_connect( GTK_OBJECT(m_text
), 
1050                                 GTK_SIGNAL_FUNC(gtk_insert_text_callback
), 
1055             gtk_signal_disconnect_by_func
 
1058                 GTK_SIGNAL_FUNC(gtk_insert_text_callback
), 
1065 void wxTextCtrl::SetSelection( long from
, long to 
) 
1067     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
1069     if (from 
== -1 && to 
== -1) 
1072         to 
= GetValue().Length(); 
1076     if ( (m_windowStyle 
& wxTE_MULTILINE
) && 
1077          !GTK_TEXT(m_text
)->line_start_cache 
) 
1079         // tell the programmer that it didn't work 
1080         wxLogDebug(_T("Can't call SetSelection() before realizing the control")); 
1085     if (m_windowStyle 
& wxTE_MULTILINE
) 
1088         GtkTextIter fromi
, toi
; 
1089         gtk_text_buffer_get_iter_at_offset( m_buffer
, &fromi
, from 
); 
1090         gtk_text_buffer_get_iter_at_offset( m_buffer
, &toi
, to 
); 
1092         gtk_text_buffer_place_cursor( m_buffer
, &toi 
); 
1093         gtk_text_buffer_move_mark_by_name( m_buffer
, "selection_bound", &fromi 
); 
1095         gtk_editable_select_region( GTK_EDITABLE(m_text
), (gint
)from
, (gint
)to 
); 
1100         gtk_editable_select_region( GTK_EDITABLE(m_text
), (gint
)from
, (gint
)to 
); 
1104 void wxTextCtrl::ShowPosition( long pos 
) 
1106     if (m_windowStyle 
& wxTE_MULTILINE
) 
1110         gtk_text_buffer_get_start_iter( m_buffer
, &iter 
); 
1111         gtk_text_iter_set_offset( &iter
, pos 
); 
1112         GtkTextMark 
*mark 
= gtk_text_buffer_create_mark( m_buffer
, NULL
, &iter
, TRUE 
); 
1113         gtk_text_view_scroll_to_mark( GTK_TEXT_VIEW(m_text
), mark
, 0.0, FALSE
, 0.0, 0.0 ); 
1115         GtkAdjustment 
*vp 
= GTK_TEXT(m_text
)->vadj
; 
1116         float totalLines 
=  (float) GetNumberOfLines(); 
1119         PositionToXY(pos
, &posX
, &posY
); 
1120         float posLine 
= (float) posY
; 
1121         float p 
= (posLine
/totalLines
)*(vp
->upper 
- vp
->lower
) + vp
->lower
; 
1122         gtk_adjustment_set_value(GTK_TEXT(m_text
)->vadj
, p
); 
1123 #endif // GTK 1.x/2.x 
1129 wxTextCtrlHitTestResult
 
1130 wxTextCtrl::HitTest(const wxPoint
& pt
, long *pos
) const 
1132     if ( !IsMultiLine() ) 
1135         return wxTE_HT_UNKNOWN
; 
1139     gtk_text_view_window_to_buffer_coords
 
1141         GTK_TEXT_VIEW(m_text
), 
1142         GTK_TEXT_WINDOW_TEXT
, 
1148     gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(m_text
), &iter
, x
, y
); 
1150         *pos 
= gtk_text_iter_get_offset(&iter
); 
1152     return wxTE_HT_ON_TEXT
; 
1155 #endif // __WXGTK20__ 
1157 long wxTextCtrl::GetInsertionPoint() const 
1159     wxCHECK_MSG( m_text 
!= NULL
, 0, wxT("invalid text ctrl") ); 
1162     if (m_windowStyle 
& wxTE_MULTILINE
) 
1164         // There is no direct accessor for the cursor, but 
1165         // internally, the cursor is the "mark" called 
1166         // "insert" in the text view's btree structure. 
1168         GtkTextMark 
*mark 
= gtk_text_buffer_get_insert( m_buffer 
); 
1170         gtk_text_buffer_get_iter_at_mark( m_buffer
, &cursor
, mark 
); 
1172         return gtk_text_iter_get_offset( &cursor 
); 
1177     return (long) GET_EDITABLE_POS(m_text
); 
1181 wxTextPos 
wxTextCtrl::GetLastPosition() const 
1183     wxCHECK_MSG( m_text 
!= NULL
, 0, wxT("invalid text ctrl") ); 
1187     if (m_windowStyle 
& wxTE_MULTILINE
) 
1191         gtk_text_buffer_get_end_iter( m_buffer
, &end 
); 
1193         pos 
= gtk_text_iter_get_offset( &end 
); 
1195         pos 
= gtk_text_get_length( GTK_TEXT(m_text
) ); 
1200         pos 
= GTK_ENTRY(m_text
)->text_length
; 
1206 void wxTextCtrl::Remove( long from
, long to 
) 
1208     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
1211     if (m_windowStyle 
& wxTE_MULTILINE
) 
1213         GtkTextIter fromi
, toi
; 
1214         gtk_text_buffer_get_iter_at_offset( m_buffer
, &fromi
, from 
); 
1215         gtk_text_buffer_get_iter_at_offset( m_buffer
, &toi
, to 
); 
1217         gtk_text_buffer_delete( m_buffer
, &fromi
, &toi 
); 
1221     gtk_editable_delete_text( GTK_EDITABLE(m_text
), (gint
)from
, (gint
)to 
); 
1224 void wxTextCtrl::Replace( long from
, long to
, const wxString 
&value 
) 
1226     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
1233         SetInsertionPoint( from 
); 
1236         gint pos 
= (gint
)from
; 
1238         wxWX2MBbuf buf 
= value
.mbc_str(); 
1239         gtk_editable_insert_text( GTK_EDITABLE(m_text
), buf
, strlen(buf
), &pos 
); 
1241         gtk_editable_insert_text( GTK_EDITABLE(m_text
), value
, value
.Length(), &pos 
); 
1242 #endif // wxUSE_UNICODE 
1243 #endif // GTK 1.x/2.x 
1247 void wxTextCtrl::Cut() 
1249     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
1252     if (m_windowStyle 
& wxTE_MULTILINE
) 
1253         g_signal_emit_by_name(m_text
, "cut-clipboard"); 
1256         gtk_editable_cut_clipboard(GTK_EDITABLE(m_text
) DUMMY_CLIPBOARD_ARG
); 
1259 void wxTextCtrl::Copy() 
1261     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
1264     if (m_windowStyle 
& wxTE_MULTILINE
) 
1265         g_signal_emit_by_name(m_text
, "copy-clipboard"); 
1268         gtk_editable_copy_clipboard(GTK_EDITABLE(m_text
) DUMMY_CLIPBOARD_ARG
); 
1271 void wxTextCtrl::Paste() 
1273     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
1276     if (m_windowStyle 
& wxTE_MULTILINE
) 
1277         g_signal_emit_by_name(m_text
, "paste-clipboard"); 
1280         gtk_editable_paste_clipboard(GTK_EDITABLE(m_text
) DUMMY_CLIPBOARD_ARG
); 
1284 void wxTextCtrl::Undo() 
1287     wxFAIL_MSG( wxT("wxTextCtrl::Undo not implemented") ); 
1290 void wxTextCtrl::Redo() 
1293     wxFAIL_MSG( wxT("wxTextCtrl::Redo not implemented") ); 
1296 bool wxTextCtrl::CanUndo() const 
1299     //wxFAIL_MSG( wxT("wxTextCtrl::CanUndo not implemented") ); 
1303 bool wxTextCtrl::CanRedo() const 
1306     //wxFAIL_MSG( wxT("wxTextCtrl::CanRedo not implemented") ); 
1310 // If the return values from and to are the same, there is no 
1312 void wxTextCtrl::GetSelection(long* fromOut
, long* toOut
) const 
1314     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
1318     bool haveSelection 
= false; 
1321      if (m_windowStyle 
& wxTE_MULTILINE
) 
1323          GtkTextIter ifrom
, ito
; 
1324          if ( gtk_text_buffer_get_selection_bounds(m_buffer
, &ifrom
, &ito
) ) 
1326              haveSelection 
= true; 
1327              from 
= gtk_text_iter_get_offset(&ifrom
); 
1328              to 
= gtk_text_iter_get_offset(&ito
); 
1331      else  // not multi-line 
1333          if ( gtk_editable_get_selection_bounds( GTK_EDITABLE(m_text
), 
1336              haveSelection 
= true; 
1340      if ( (GTK_EDITABLE(m_text
)->has_selection
) ) 
1342          haveSelection 
= true; 
1343          from 
= (long) GTK_EDITABLE(m_text
)->selection_start_pos
; 
1344          to 
= (long) GTK_EDITABLE(m_text
)->selection_end_pos
; 
1348      if (! haveSelection 
) 
1349           from 
= to 
= GetInsertionPoint(); 
1353          // exchange them to be compatible with wxMSW 
1366 bool wxTextCtrl::IsEditable() const 
1368     wxCHECK_MSG( m_text 
!= NULL
, false, wxT("invalid text ctrl") ); 
1371     if (m_windowStyle 
& wxTE_MULTILINE
) 
1373         return gtk_text_view_get_editable(GTK_TEXT_VIEW(m_text
)); 
1377         return gtk_editable_get_editable(GTK_EDITABLE(m_text
)); 
1380     return GTK_EDITABLE(m_text
)->editable
; 
1384 bool wxTextCtrl::IsModified() const 
1389 void wxTextCtrl::Clear() 
1391     SetValue( wxT("") ); 
1394 void wxTextCtrl::OnChar( wxKeyEvent 
&key_event 
) 
1396     wxCHECK_RET( m_text 
!= NULL
, wxT("invalid text ctrl") ); 
1398     if ((key_event
.GetKeyCode() == WXK_RETURN
) && (m_windowStyle 
& wxPROCESS_ENTER
)) 
1400         wxCommandEvent 
event(wxEVT_COMMAND_TEXT_ENTER
, m_windowId
); 
1401         event
.SetEventObject(this); 
1402         event
.SetString(GetValue()); 
1403         if (GetEventHandler()->ProcessEvent(event
)) return; 
1406     if ((key_event
.GetKeyCode() == WXK_RETURN
) && !(m_windowStyle 
& wxTE_MULTILINE
)) 
1408         // This will invoke the dialog default action, such 
1409         // as the clicking the default button. 
1411         wxWindow 
*top_frame 
= m_parent
; 
1412         while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
1413             top_frame 
= top_frame
->GetParent(); 
1415         if (top_frame 
&& GTK_IS_WINDOW(top_frame
->m_widget
)) 
1417             GtkWindow 
*window 
= GTK_WINDOW(top_frame
->m_widget
); 
1419             if (window
->default_widget
) 
1421                 gtk_widget_activate (window
->default_widget
); 
1430 GtkWidget
* wxTextCtrl::GetConnectWidget() 
1432     return GTK_WIDGET(m_text
); 
1435 bool wxTextCtrl::IsOwnGtkWindow( GdkWindow 
*window 
) 
1437     if (m_windowStyle 
& wxTE_MULTILINE
) 
1440         return window 
== gtk_text_view_get_window( GTK_TEXT_VIEW( m_text 
), GTK_TEXT_WINDOW_TEXT 
);  // pure guesswork 
1442         return (window 
== GTK_TEXT(m_text
)->text_area
); 
1447         return (window 
== GTK_ENTRY(m_text
)->text_area
); 
1451 // the font will change for subsequent text insertiongs 
1452 bool wxTextCtrl::SetFont( const wxFont 
&font 
) 
1454     wxCHECK_MSG( m_text 
!= NULL
, false, wxT("invalid text ctrl") ); 
1456     if ( !wxTextCtrlBase::SetFont(font
) ) 
1458         // font didn't change, nothing to do 
1462     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
1464         SetUpdateFont(true); 
1466         m_defaultStyle
.SetFont(font
); 
1468         ChangeFontGlobally(); 
1474 void wxTextCtrl::ChangeFontGlobally() 
1476     // this method is very inefficient and hence should be called as rarely as 
1479     // TODO: it can be implemented much more efficiently for GTK2 
1481     wxASSERT_MSG( (m_windowStyle 
& wxTE_MULTILINE
) && m_updateFont
, 
1483                   _T("shouldn't be called for single line controls") ); 
1485     wxASSERT_MSG( (m_windowStyle 
& wxTE_MULTILINE
), 
1486                   _T("shouldn't be called for single line controls") ); 
1489     wxString value 
= GetValue(); 
1490     if ( !value
.empty() ) 
1492         SetUpdateFont(false); 
1501 void wxTextCtrl::UpdateFontIfNeeded() 
1504         ChangeFontGlobally(); 
1509 bool wxTextCtrl::SetForegroundColour(const wxColour
& colour
) 
1511     if ( !wxControl::SetForegroundColour(colour
) ) 
1514     // update default fg colour too 
1515     m_defaultStyle
.SetTextColour(colour
); 
1520 bool wxTextCtrl::SetBackgroundColour( const wxColour 
&colour 
) 
1522     wxCHECK_MSG( m_text 
!= NULL
, false, wxT("invalid text ctrl") ); 
1524     if ( !wxControl::SetBackgroundColour( colour 
) ) 
1528     if (!m_widget
->window
) 
1532     if (!m_backgroundColour
.Ok()) 
1535     if (m_windowStyle 
& wxTE_MULTILINE
) 
1538         GdkWindow 
*window 
= GTK_TEXT(m_text
)->text_area
; 
1541         m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window 
) ); 
1542         gdk_window_set_background( window
, m_backgroundColour
.GetColor() ); 
1543         gdk_window_clear( window 
); 
1547     // change active background color too 
1548     m_defaultStyle
.SetBackgroundColour( colour 
); 
1553 bool wxTextCtrl::SetStyle( long start
, long end
, const wxTextAttr
& style 
) 
1555     if ( m_windowStyle 
& wxTE_MULTILINE 
) 
1557         if ( style
.IsDefault() ) 
1563         gint l 
= gtk_text_buffer_get_char_count( m_buffer 
); 
1565         wxCHECK_MSG( start 
>= 0 && end 
<= l
, false, 
1566                      _T("invalid range in wxTextCtrl::SetStyle") ); 
1568         GtkTextIter starti
, endi
; 
1569         gtk_text_buffer_get_iter_at_offset( m_buffer
, &starti
, start 
); 
1570         gtk_text_buffer_get_iter_at_offset( m_buffer
, &endi
, end 
); 
1572         // use the attributes from style which are set in it and fall back 
1573         // first to the default style and then to the text control default 
1574         // colours for the others 
1575         wxTextAttr attr 
= wxTextAttr::Combine(style
, m_defaultStyle
, this); 
1577         wxGtkTextApplyTagsFromAttr( m_buffer
, attr
, &starti
, &endi 
); 
1581         // VERY dirty way to do that - removes the required text and re-adds it 
1582         // with styling (FIXME) 
1584         gint l 
= gtk_text_get_length( GTK_TEXT(m_text
) ); 
1586         wxCHECK_MSG( start 
>= 0 && end 
<= l
, false, 
1587                      _T("invalid range in wxTextCtrl::SetStyle") ); 
1589         gint old_pos 
= gtk_editable_get_position( GTK_EDITABLE(m_text
) ); 
1590         char *text 
= gtk_editable_get_chars( GTK_EDITABLE(m_text
), start
, end 
); 
1591         wxString 
tmp(text
,*wxConvCurrent
); 
1594         gtk_editable_delete_text( GTK_EDITABLE(m_text
), start
, end 
); 
1595         gtk_editable_set_position( GTK_EDITABLE(m_text
), start 
); 
1598         wxWX2MBbuf buf 
= tmp
.mbc_str(); 
1599         const char *txt 
= buf
; 
1600         size_t txtlen 
= strlen(buf
); 
1602         const char *txt 
= tmp
; 
1603         size_t txtlen 
= tmp
.length(); 
1606         // use the attributes from style which are set in it and fall back 
1607         // first to the default style and then to the text control default 
1608         // colours for the others 
1609         wxGtkTextInsert(m_text
, 
1610                         wxTextAttr::Combine(style
, m_defaultStyle
, this), 
1614         /* does not seem to help under GTK+ 1.2 !!! 
1615         gtk_editable_set_position( GTK_EDITABLE(m_text), old_pos ); */ 
1616         SetInsertionPoint( old_pos 
); 
1622         // cannot do this for GTK+'s Entry widget 
1627 void wxTextCtrl::DoApplyWidgetStyle(GtkRcStyle 
*style
) 
1629     gtk_widget_modify_style(m_text
, style
); 
1632 void wxTextCtrl::OnCut(wxCommandEvent
& WXUNUSED(event
)) 
1637 void wxTextCtrl::OnCopy(wxCommandEvent
& WXUNUSED(event
)) 
1642 void wxTextCtrl::OnPaste(wxCommandEvent
& WXUNUSED(event
)) 
1647 void wxTextCtrl::OnUndo(wxCommandEvent
& WXUNUSED(event
)) 
1652 void wxTextCtrl::OnRedo(wxCommandEvent
& WXUNUSED(event
)) 
1657 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent
& event
) 
1659     event
.Enable( CanCut() ); 
1662 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent
& event
) 
1664     event
.Enable( CanCopy() ); 
1667 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent
& event
) 
1669     event
.Enable( CanPaste() ); 
1672 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent
& event
) 
1674     event
.Enable( CanUndo() ); 
1677 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent
& event
) 
1679     event
.Enable( CanRedo() ); 
1682 void wxTextCtrl::OnInternalIdle() 
1684     wxCursor cursor 
= m_cursor
; 
1685     if (g_globalCursor
.Ok()) cursor 
= g_globalCursor
; 
1690         GdkWindow 
*window 
= (GdkWindow
*) NULL
; 
1691         if (HasFlag(wxTE_MULTILINE
)) 
1692             window 
= GTK_TEXT(m_text
)->text_area
; 
1694             window 
= GTK_ENTRY(m_text
)->text_area
; 
1697             gdk_window_set_cursor( window
, cursor
.GetCursor() ); 
1699         if (!g_globalCursor
.Ok()) 
1700             cursor 
= *wxSTANDARD_CURSOR
; 
1702         window 
= m_widget
->window
; 
1703         if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
))) 
1704             gdk_window_set_cursor( window
, cursor
.GetCursor() ); 
1708     if (g_delayedFocus 
== this) 
1710         if (GTK_WIDGET_REALIZED(m_widget
)) 
1712             gtk_widget_grab_focus( m_widget 
); 
1713             g_delayedFocus 
= NULL
; 
1717     if (wxUpdateUIEvent::CanUpdate(this)) 
1718         UpdateWindowUI(wxUPDATE_UI_FROMIDLE
); 
1721 wxSize 
wxTextCtrl::DoGetBestSize() const 
1723     // FIXME should be different for multi-line controls... 
1724     wxSize 
ret( wxControl::DoGetBestSize() ); 
1725     wxSize 
best(80, ret
.y
); 
1726     CacheBestSize(best
); 
1730 // ---------------------------------------------------------------------------- 
1732 // ---------------------------------------------------------------------------- 
1734 void wxTextCtrl::Freeze() 
1736     if ( HasFlag(wxTE_MULTILINE
) ) 
1739         if ( !m_frozenness
++ ) 
1741             // freeze textview updates and remove buffer 
1742             g_signal_connect( G_OBJECT(m_text
), "expose_event", 
1743                 GTK_SIGNAL_FUNC(gtk_text_exposed_callback
), (gpointer
)this); 
1744             g_signal_connect( G_OBJECT(m_widget
), "expose_event", 
1745                 GTK_SIGNAL_FUNC(gtk_text_exposed_callback
), (gpointer
)this); 
1746             gtk_widget_set_sensitive(m_widget
, false); 
1747             g_object_ref(m_buffer
); 
1748             gtk_text_view_set_buffer(GTK_TEXT_VIEW(m_text
), gtk_text_buffer_new(NULL
)); 
1751         gtk_text_freeze(GTK_TEXT(m_text
)); 
1756 void wxTextCtrl::Thaw() 
1758     if ( HasFlag(wxTE_MULTILINE
) ) 
1761         wxASSERT_MSG( m_frozenness 
> 0, _T("Thaw() without matching Freeze()") ); 
1763         if ( !--m_frozenness 
) 
1765             // Reattach buffer and thaw textview updates 
1766             gtk_text_view_set_buffer(GTK_TEXT_VIEW(m_text
), m_buffer
); 
1767             g_object_unref(m_buffer
); 
1768             gtk_widget_set_sensitive(m_widget
, true); 
1769             g_signal_handlers_disconnect_by_func(m_widget
, (gpointer
)gtk_text_exposed_callback
, this); 
1770             g_signal_handlers_disconnect_by_func(m_text
, (gpointer
)gtk_text_exposed_callback
, this); 
1773         GTK_TEXT(m_text
)->vadj
->value 
= 0.0; 
1775         gtk_text_thaw(GTK_TEXT(m_text
)); 
1780 // ---------------------------------------------------------------------------- 
1782 // ---------------------------------------------------------------------------- 
1784 GtkAdjustment 
*wxTextCtrl::GetVAdj() const 
1786     if ( !IsMultiLine() ) 
1790     return gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(m_widget
)); 
1792     return GTK_TEXT(m_text
)->vadj
; 
1796 bool wxTextCtrl::DoScroll(GtkAdjustment 
*adj
, int diff
) 
1798     float value 
= adj
->value 
+ diff
; 
1803     float upper 
= adj
->upper 
- adj
->page_size
; 
1804     if ( value 
> upper 
) 
1807     // did we noticeably change the scroll position? 
1808     if ( fabs(adj
->value 
- value
) < 0.2 ) 
1810         // well, this is what Robert does in wxScrollBar, so it must be good... 
1817     gtk_adjustment_value_changed(GTK_ADJUSTMENT(adj
)); 
1819     gtk_signal_emit_by_name(GTK_OBJECT(adj
), "value_changed"); 
1825 bool wxTextCtrl::ScrollLines(int lines
) 
1827     GtkAdjustment 
*adj 
= GetVAdj(); 
1832     int diff 
= (int)ceil(lines
*adj
->step_increment
); 
1834     // this is hardcoded to 10 in GTK+ 1.2 (great idea) 
1835     int diff 
= 10*lines
; 
1838     return DoScroll(adj
, diff
); 
1841 bool wxTextCtrl::ScrollPages(int pages
) 
1843     GtkAdjustment 
*adj 
= GetVAdj(); 
1847     return DoScroll(adj
, (int)ceil(pages
*adj
->page_increment
)); 
1853 wxTextCtrl::GetClassDefaultAttributes(wxWindowVariant 
WXUNUSED(variant
)) 
1855     return GetDefaultAttributesFromGTKWidget(gtk_entry_new
, true);