+// ----------------------------------------------------------------------------
+// "insert_text" for GtkEntry
+// ----------------------------------------------------------------------------
+
+extern "C" {
+static void
+gtk_insert_text_callback(GtkEditable *editable,
+                         const gchar *WXUNUSED(new_text),
+                         gint WXUNUSED(new_text_length),
+                         gint *WXUNUSED(position),
+                         wxTextCtrl *win)
+{
+    if (g_isIdle)
+        wxapp_install_idle_handler();
+
+    // we should only be called if we have a max len limit at all
+    GtkEntry *entry = GTK_ENTRY (editable);
+
+    wxCHECK_RET( entry->text_max_length, wxT("shouldn't be called") );
+
+    // check that we don't overflow the max length limit
+    //
+    // FIXME: this doesn't work when we paste a string which is going to be
+    //        truncated
+    if ( entry->text_length == entry->text_max_length )
+    {
+        // we don't need to run the base class version at all
+        gtk_signal_emit_stop_by_name(GTK_OBJECT(editable), "insert_text");
+
+        // remember that the next changed signal is to be ignored to avoid
+        // generating a dummy wxEVT_COMMAND_TEXT_UPDATED event
+        win->IgnoreNextTextUpdate();
+
+        // and generate the correct one ourselves
+        wxCommandEvent event(wxEVT_COMMAND_TEXT_MAXLEN, win->GetId());
+        event.SetEventObject(win);
+        event.SetString(win->GetValue());
+        win->HandleWindowEvent( event );
+    }
+}
+}
+
+//-----------------------------------------------------------------------------
+//  "changed"
+//-----------------------------------------------------------------------------
+
+extern "C" {
+static void
+gtk_text_changed_callback( GtkWidget *WXUNUSED(widget), wxTextCtrl *win )
+{
+    if ( win->IgnoreTextUpdate() )
+        return;
+
+    if (!win->m_hasVMT) return;
+
+    if (g_isIdle)
+        wxapp_install_idle_handler();
+
+    win->SetModified();
+    win->UpdateFontIfNeeded();
+
+    wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, win->GetId() );
+    event.SetEventObject( win );
+    win->HandleWindowEvent( event );
+}
+}
+
+//-----------------------------------------------------------------------------
+// "changed" from vertical scrollbar
+//-----------------------------------------------------------------------------
+
+extern "C" {
+static void
+gtk_scrollbar_changed_callback( GtkWidget *WXUNUSED(widget), wxTextCtrl *win )
+{
+    if (!win->m_hasVMT) return;
+
+    if (g_isIdle)
+        wxapp_install_idle_handler();
+
+    win->CalculateScrollbar();
+}
+}
+
+// ----------------------------------------------------------------------------
+// redraw callback for multiline text
+// ----------------------------------------------------------------------------
+
+// redrawing a GtkText from inside a wxYield() call results in crashes (the
+// text sample shows it in its "Add lines" command which shows wxProgressDialog
+// which implicitly calls wxYield()) so we override GtkText::draw() and simply
+// don't do anything if we're inside wxYield()
+
+extern "C" {
+    typedef void (*GtkDrawCallback)(GtkWidget *widget, GdkRectangle *rect);
+}