X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c2246a3881e5c3293b70560dde099ee772c86d73..8a31648287be0ef976f133de2786b137f1e98340:/src/gtk/textctrl.cpp?ds=inline diff --git a/src/gtk/textctrl.cpp b/src/gtk/textctrl.cpp index f5a78bdf8d..6920e299b6 100644 --- a/src/gtk/textctrl.cpp +++ b/src/gtk/textctrl.cpp @@ -580,10 +580,20 @@ gtk_paste_clipboard_callback( GtkWidget *widget, wxTextCtrl *win ) } //----------------------------------------------------------------------------- -// wxTextCtrl +// "mark_set" //----------------------------------------------------------------------------- -IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxTextCtrlBase) +extern "C" { +static void mark_set(GtkTextBuffer*, GtkTextIter*, GtkTextMark* mark, GSList** markList) +{ + if (gtk_text_mark_get_name(mark) == NULL) + *markList = g_slist_prepend(*markList, mark); +} +} + +//----------------------------------------------------------------------------- +// wxTextCtrl +//----------------------------------------------------------------------------- BEGIN_EVENT_TABLE(wxTextCtrl, wxTextCtrlBase) EVT_CHAR(wxTextCtrl::OnChar) @@ -622,10 +632,13 @@ void wxTextCtrl::Init() m_text = NULL; m_showPositionOnThaw = NULL; + m_anonymousMarkList = NULL; } wxTextCtrl::~wxTextCtrl() { + if (m_anonymousMarkList) + g_slist_free(m_anonymousMarkList); } wxTextCtrl::wxTextCtrl( wxWindow *parent, @@ -662,10 +675,13 @@ bool wxTextCtrl::Create( wxWindow *parent, if (multi_line) { + m_buffer = gtk_text_buffer_new(NULL); + gulong sig_id = g_signal_connect(m_buffer, "mark_set", G_CALLBACK(mark_set), &m_anonymousMarkList); // Create view - m_text = gtk_text_view_new(); - - m_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_text) ); + m_text = gtk_text_view_new_with_buffer(m_buffer); + // gtk_text_view_set_buffer adds its own reference + g_object_unref(m_buffer); + g_signal_handler_disconnect(m_buffer, sig_id); // create "ShowPosition" marker GtkTextIter iter; @@ -680,7 +696,7 @@ bool wxTextCtrl::Create( wxWindow *parent, ? GTK_POLICY_NEVER : GTK_POLICY_AUTOMATIC ); // for ScrollLines/Pages - m_scrollBar[1] = (GtkRange*)((GtkScrolledWindow*)m_widget)->vscrollbar; + m_scrollBar[1] = GTK_RANGE(gtk_scrolled_window_get_vscrollbar(GTK_SCROLLED_WINDOW(m_widget))); // Insert view into scrolled window gtk_container_add( GTK_CONTAINER(m_widget), m_text ); @@ -691,7 +707,7 @@ bool wxTextCtrl::Create( wxWindow *parent, gtk_widget_add_events( GTK_WIDGET(m_text), GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK ); - GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS ); + gtk_widget_set_can_focus(m_widget, FALSE); } else { @@ -1084,13 +1100,19 @@ void wxTextCtrl::WriteText( const wxString &text ) // Insert the text wxGtkTextInsert( m_text, m_buffer, m_defaultStyle, buffer ); - GtkAdjustment *adj = gtk_scrolled_window_get_vadjustment( GTK_SCROLLED_WINDOW(m_widget) ); // Scroll to cursor, but only if scrollbar thumb is at the very bottom // won't work when frozen, text view is not using m_buffer then - if (!IsFrozen() && wxIsSameDouble(adj->value, adj->upper - adj->page_size)) + if (!IsFrozen()) { - gtk_text_view_scroll_to_mark( GTK_TEXT_VIEW(m_text), - gtk_text_buffer_get_insert( m_buffer ), 0.0, FALSE, 0.0, 1.0 ); + 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); + if (wxIsSameDouble(value, upper - page_size)) + { + gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(m_text), + gtk_text_buffer_get_insert(m_buffer), 0, false, 0, 1); + } } } @@ -1143,7 +1165,7 @@ bool wxTextCtrl::PositionToXY(long pos, long *x, long *y ) const } else // single line control { - if ( pos <= GTK_ENTRY(m_text)->text_length ) + if (pos <= gtk_entry_get_text_length(GTK_ENTRY(m_text))) { if ( y ) *y = 0; @@ -1196,6 +1218,37 @@ int wxTextCtrl::GetLineLength(long lineNo) const } } +wxPoint wxTextCtrl::DoPositionToCoords(long pos) const +{ + if ( !IsMultiLine() ) + { + // Single line text entry (GtkTextEntry) doesn't have support for + // getting the coordinates for the given offset. Perhaps we could + // find them ourselves by using GetTextExtent() but for now just leave + // it unimplemented, this function is more useful for multiline + // controls anyhow. + return wxDefaultPosition; + } + + // Window coordinates for the given position is calculated by getting + // the buffer coordinates and converting them to window coordinates. + GtkTextView *textview = GTK_TEXT_VIEW(m_text); + + GtkTextIter iter; + gtk_text_buffer_get_iter_at_offset(m_buffer, &iter, pos); + + GdkRectangle bufferCoords; + gtk_text_view_get_iter_location(textview, &iter, &bufferCoords); + + gint winCoordX = 0, + winCoordY = 0; + gtk_text_view_buffer_to_window_coords(textview, GTK_TEXT_WINDOW_WIDGET, + bufferCoords.x, bufferCoords.y, + &winCoordX, &winCoordY); + + return wxPoint(winCoordX, winCoordY); +} + int wxTextCtrl::GetNumberOfLines() const { if ( IsMultiLine() ) @@ -1267,7 +1320,7 @@ void wxTextCtrl::OnEnabled(bool WXUNUSED(enable)) // disabled and enabled mode, or we end up with a different colour under the // text. wxColour oldColour = GetBackgroundColour(); - if (oldColour.Ok()) + if (oldColour.IsOk()) { // Need to set twice or it'll optimize the useful stuff out if (oldColour == * wxWHITE) @@ -1334,14 +1387,14 @@ void wxTextCtrl::SetSelection( long from, long to ) { wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") ); - if (from == -1 && to == -1) - { - from = 0; - to = GetValue().length(); - } - if ( IsMultiLine() ) { + if (from == -1 && to == -1) + { + from = 0; + to = GetValue().length(); + } + GtkTextIter fromi, toi; gtk_text_buffer_get_iter_at_offset( m_buffer, &fromi, from ); gtk_text_buffer_get_iter_at_offset( m_buffer, &toi, to ); @@ -1580,7 +1633,7 @@ GdkWindow *wxTextCtrl::GTKGetWindow(wxArrayGdkWindows& WXUNUSED(windows)) const } else { - return GTK_ENTRY(m_text)->text_area; + return gtk_entry_get_text_window(GTK_ENTRY(m_text)); } } @@ -1644,7 +1697,7 @@ bool wxTextCtrl::SetBackgroundColour( const wxColour &colour ) if ( !wxControl::SetBackgroundColour( colour ) ) return false; - if (!m_backgroundColour.Ok()) + if (!m_backgroundColour.IsOk()) return false; // change active background color too @@ -1692,7 +1745,7 @@ bool wxTextCtrl::GetStyle(long position, wxTextAttr& style) gint l = gtk_text_buffer_get_char_count( m_buffer ); wxCHECK_MSG( position >= 0 && position <= l, false, - _T("invalid range in wxTextCtrl::GetStyle") ); + wxT("invalid range in wxTextCtrl::GetStyle") ); GtkTextIter positioni; gtk_text_buffer_get_iter_at_offset(m_buffer, &positioni, position); @@ -1700,7 +1753,7 @@ bool wxTextCtrl::GetStyle(long position, wxTextAttr& style) // Obtain a copy of the default attributes GtkTextAttributes * const pattr = gtk_text_view_get_default_attributes(GTK_TEXT_VIEW(m_text)); - wxON_BLOCK_EXIT1( g_free, pattr ); + wxON_BLOCK_EXIT1(gtk_text_attributes_unref, pattr); // And query GTK for the attributes at the given position using it as base if ( !gtk_text_iter_get_attributes(&positioni, pattr) ) @@ -1806,16 +1859,24 @@ void wxTextCtrl::DoFreeze() // removing buffer dramatically speeds up insertion: g_object_ref(m_buffer); GtkTextBuffer* buf_new = gtk_text_buffer_new(NULL); - GtkTextMark* mark = GTK_TEXT_VIEW(m_text)->first_para_mark; gtk_text_view_set_buffer(GTK_TEXT_VIEW(m_text), buf_new); // gtk_text_view_set_buffer adds its own reference g_object_unref(buf_new); - // This mark should be deleted when the buffer is changed, - // but it's not (in GTK+ up to at least 2.10.6). + // These marks should be deleted when the buffer is changed, + // but they are not (in GTK+ up to at least 3.0.1). // Otherwise these anonymous marks start to build up in the buffer, // and Freeze takes longer and longer each time it is called. - if (GTK_IS_TEXT_MARK(mark) && !gtk_text_mark_get_deleted(mark)) - gtk_text_buffer_delete_mark(m_buffer, mark); + if (m_anonymousMarkList) + { + for (GSList* item = m_anonymousMarkList; item; item = item->next) + { + GtkTextMark* mark = static_cast(item->data); + if (GTK_IS_TEXT_MARK(mark) && !gtk_text_mark_get_deleted(mark)) + gtk_text_buffer_delete_mark(m_buffer, mark); + } + g_slist_free(m_anonymousMarkList); + m_anonymousMarkList = NULL; + } } } @@ -1824,8 +1885,10 @@ void wxTextCtrl::DoThaw() if ( HasFlag(wxTE_MULTILINE) ) { // reattach buffer: + gulong sig_id = g_signal_connect(m_buffer, "mark_set", G_CALLBACK(mark_set), &m_anonymousMarkList); gtk_text_view_set_buffer(GTK_TEXT_VIEW(m_text), m_buffer); g_object_unref(m_buffer); + g_signal_handler_disconnect(m_buffer, sig_id); if (m_showPositionOnThaw != NULL) {