+ wxSize best(80, ret.y);
+ CacheBestSize(best);
+ return best;
+}
+
+// ----------------------------------------------------------------------------
+// freeze/thaw
+// ----------------------------------------------------------------------------
+
+void wxTextCtrl::Freeze()
+{
+ if ( HasFlag(wxTE_MULTILINE) )
+ {
+#ifdef __WXGTK20__
+ if ( !m_frozenness++ )
+ {
+ // freeze textview updates and remove buffer
+ g_signal_connect( G_OBJECT(m_text), "expose_event",
+ GTK_SIGNAL_FUNC(gtk_text_exposed_callback), (gpointer)this);
+ g_signal_connect( G_OBJECT(m_widget), "expose_event",
+ GTK_SIGNAL_FUNC(gtk_text_exposed_callback), (gpointer)this);
+ gtk_widget_set_sensitive(m_widget, false);
+ g_object_ref(m_buffer);
+ gtk_text_view_set_buffer(GTK_TEXT_VIEW(m_text), gtk_text_buffer_new(NULL));
+ }
+#else
+ gtk_text_freeze(GTK_TEXT(m_text));
+#endif
+ }
+}
+
+void wxTextCtrl::Thaw()
+{
+ if ( HasFlag(wxTE_MULTILINE) )
+ {
+#ifdef __WXGTK20__
+ wxASSERT_MSG( m_frozenness > 0, _T("Thaw() without matching Freeze()") );
+
+ if ( !--m_frozenness )
+ {
+ // Reattach buffer and thaw textview updates
+ gtk_text_view_set_buffer(GTK_TEXT_VIEW(m_text), m_buffer);
+ g_object_unref(m_buffer);
+ gtk_widget_set_sensitive(m_widget, true);
+ g_signal_handlers_disconnect_by_func(m_widget, (gpointer)gtk_text_exposed_callback, this);
+ g_signal_handlers_disconnect_by_func(m_text, (gpointer)gtk_text_exposed_callback, this);
+ }
+#else
+ GTK_TEXT(m_text)->vadj->value = 0.0;
+
+ gtk_text_thaw(GTK_TEXT(m_text));
+#endif
+ }
+}
+
+// ----------------------------------------------------------------------------
+// scrolling
+// ----------------------------------------------------------------------------
+
+GtkAdjustment *wxTextCtrl::GetVAdj() const
+{
+ if ( !IsMultiLine() )
+ return NULL;
+
+#ifdef __WXGTK20__
+ return gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(m_widget));
+#else
+ return GTK_TEXT(m_text)->vadj;
+#endif
+}
+
+bool wxTextCtrl::DoScroll(GtkAdjustment *adj, int diff)
+{
+ float value = adj->value + diff;
+
+ if ( value < 0 )
+ value = 0;
+
+ float upper = adj->upper - adj->page_size;
+ if ( value > upper )
+ value = upper;
+
+ // did we noticeably change the scroll position?
+ if ( fabs(adj->value - value) < 0.2 )
+ {
+ // well, this is what Robert does in wxScrollBar, so it must be good...
+ return FALSE;
+ }
+
+ adj->value = value;
+
+#ifdef __WXGTK20__
+ gtk_adjustment_value_changed(GTK_ADJUSTMENT(adj));
+#else
+ gtk_signal_emit_by_name(GTK_OBJECT(adj), "value_changed");
+#endif
+
+ return TRUE;
+}
+
+bool wxTextCtrl::ScrollLines(int lines)
+{
+ GtkAdjustment *adj = GetVAdj();
+ if ( !adj )
+ return FALSE;
+
+#ifdef __WXGTK20__
+ int diff = (int)ceil(lines*adj->step_increment);
+#else
+ // this is hardcoded to 10 in GTK+ 1.2 (great idea)
+ int diff = 10*lines;
+#endif
+
+ return DoScroll(adj, diff);
+}
+
+bool wxTextCtrl::ScrollPages(int pages)
+{
+ GtkAdjustment *adj = GetVAdj();
+ if ( !adj )
+ return FALSE;
+
+ return DoScroll(adj, (int)ceil(pages*adj->page_increment));
+}
+
+
+// static
+wxVisualAttributes
+wxTextCtrl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
+{
+ return GetDefaultAttributesFromGTKWidget(gtk_entry_new, true);