diff --git a/src/gtk/textctrl.cpp b/src/gtk/textctrl.cpp index 977954ca35..2fe014a3c8 100644 --- a/src/gtk/textctrl.cpp +++ b/src/gtk/textctrl.cpp @@ -1105,8 +1105,34 @@ bool wxTextCtrl::IsEmpty() const return wxTextEntry::IsEmpty(); } +extern "C" { +static void adjustmentChanged(GtkAdjustment* adj, GtkTextMark** mark) +{ + if (*mark) + { + const double value = gtk_adjustment_get_value(adj); + const double upper = gtk_adjustment_get_upper(adj); + const double page_size = gtk_adjustment_get_page_size(adj); + if (value < upper - page_size) + { + GtkTextIter iter; + GtkTextBuffer* buffer = gtk_text_mark_get_buffer(*mark); + gtk_text_buffer_get_iter_at_mark(buffer, &iter, *mark); + if (gtk_text_iter_is_end(&iter)) + { + // Keep position at bottom as scrollbar is updated during layout + gtk_adjustment_set_value(adj, upper - page_size); + } + } + } +} +} + void wxTextCtrl::GTKAfterLayout() { + g_signal_handlers_disconnect_by_func( + gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(m_widget)), + (void*)adjustmentChanged, &m_showPositionDefer); m_afterLayoutId = 0; if (m_showPositionDefer && !IsFrozen()) { @@ -1118,8 +1144,12 @@ void wxTextCtrl::GTKAfterLayout() extern "C" { static gboolean afterLayout(void* data) { + gdk_threads_enter(); + wxTextCtrl* win = static_cast(data); win->GTKAfterLayout(); + + gdk_threads_leave(); return false; } } @@ -1193,10 +1223,11 @@ void wxTextCtrl::WriteText( const wxString &text ) gtk_text_buffer_insert( m_buffer, &iter, buffer, buffer.length() ); + GtkAdjustment* adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(m_widget)); + // Scroll to cursor, if it is at the end and scrollbar thumb is at the bottom if (insertIsEnd) { - GtkAdjustment* adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(m_widget)); const double value = gtk_adjustment_get_value(adj); const double upper = gtk_adjustment_get_upper(adj); const double page_size = gtk_adjustment_get_page_size(adj); @@ -1212,6 +1243,7 @@ void wxTextCtrl::WriteText( const wxString &text ) } if (m_afterLayoutId == 0) { + g_signal_connect(adj, "changed", G_CALLBACK(adjustmentChanged), &m_showPositionDefer); m_afterLayoutId = g_idle_add_full(GTK_TEXT_VIEW_PRIORITY_VALIDATE + 1, afterLayout, this, NULL); } @@ -1397,7 +1429,11 @@ void wxTextCtrl::SetInsertionPoint( long pos ) // defer until Thaw, text view is not using m_buffer now m_showPositionDefer = mark; else + { gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(m_text), mark); + if (m_afterLayoutId) + m_showPositionDefer = mark; + } } else // single line { @@ -1514,7 +1550,11 @@ void wxTextCtrl::ShowPosition( long pos ) // defer until Thaw, text view is not using m_buffer now m_showPositionDefer = mark; else + { gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(m_text), mark); + if (m_afterLayoutId) + m_showPositionDefer = mark; + } } else // single line { // This function not only shows character at required position