X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/0ec1179b86dac6c87ad9f2cd126f87e92642c62c..3508c1432884472f0d24f0f98c0dc75ed35df297:/src/gtk/textctrl.cpp diff --git a/src/gtk/textctrl.cpp b/src/gtk/textctrl.cpp index 37c1c1a3f5..11d4eab716 100644 --- a/src/gtk/textctrl.cpp +++ b/src/gtk/textctrl.cpp @@ -38,8 +38,8 @@ extern "C" { static void wxGtkOnRemoveTag(GtkTextBuffer *buffer, GtkTextTag *tag, - GtkTextIter *start, - GtkTextIter *end, + GtkTextIter * WXUNUSED(start), + GtkTextIter * WXUNUSED(end), char *prefix) { gchar *name; @@ -84,7 +84,9 @@ static void wxGtkTextApplyTagsFromAttr(GtkWidget *text, { wxGtkTextRemoveTagsWithPrefix(text_buffer, "WXFONT", start, end); - PangoFontDescription *font_description = attr.GetFont().GetNativeFontInfo()->description; + wxFont font(attr.GetFont()); + + PangoFontDescription *font_description = font.GetNativeFontInfo()->description; wxGtkString font_string(pango_font_description_to_string(font_description)); g_snprintf(buf, sizeof(buf), "WXFONT %s", font_string.c_str()); tag = gtk_text_tag_table_lookup( gtk_text_buffer_get_tag_table( text_buffer ), @@ -95,7 +97,7 @@ static void wxGtkTextApplyTagsFromAttr(GtkWidget *text, NULL ); gtk_text_buffer_apply_tag (text_buffer, tag, start, end); - if (attr.GetFont().GetUnderlined()) + if (font.GetUnderlined()) { g_snprintf(buf, sizeof(buf), "WXFONTUNDERLINE"); tag = gtk_text_tag_table_lookup( gtk_text_buffer_get_tag_table( text_buffer ), @@ -147,7 +149,7 @@ static void wxGtkTextApplyTagsFromAttr(GtkWidget *text, gtk_text_iter_get_line(start) ); gtk_text_iter_forward_line(¶_end); - wxGtkTextRemoveTagsWithPrefix(text_buffer, "WXALIGNMENT", start, end); + wxGtkTextRemoveTagsWithPrefix(text_buffer, "WXALIGNMENT", ¶_start, ¶_end); GtkJustification align; switch (attr.GetAlignment()) @@ -193,17 +195,12 @@ static void wxGtkTextApplyTagsFromAttr(GtkWidget *text, gtk_text_iter_get_line(start) ); gtk_text_iter_forward_line(¶_end); - wxGtkTextRemoveTagsWithPrefix(text_buffer, "WXINDENT", start, end); + wxGtkTextRemoveTagsWithPrefix(text_buffer, "WXINDENT", ¶_start, ¶_end); // Convert indent from 1/10th of a mm into pixels - float factor; -#if GTK_CHECK_VERSION(2,2,0) - if (!gtk_check_version(2,2,0)) - factor = (float)gdk_screen_get_width(gtk_widget_get_screen(text)) / + float factor = + (float)gdk_screen_get_width(gtk_widget_get_screen(text)) / gdk_screen_get_width_mm(gtk_widget_get_screen(text)) / 10; - else -#endif - factor = (float)gdk_screen_width() / gdk_screen_width_mm() / 10; const int indent = (int)(factor * attr.GetLeftIndent()); const int subIndent = (int)(factor * attr.GetLeftSubIndent()); @@ -242,7 +239,7 @@ static void wxGtkTextApplyTagsFromAttr(GtkWidget *text, gtk_text_iter_get_line(start) ); gtk_text_iter_forward_line(¶_end); - wxGtkTextRemoveTagsWithPrefix(text_buffer, "WXTABS", start, end); + wxGtkTextRemoveTagsWithPrefix(text_buffer, "WXTABS", ¶_start, ¶_end); const wxArrayInt& tabs = attr.GetTabs(); @@ -258,14 +255,9 @@ static void wxGtkTextApplyTagsFromAttr(GtkWidget *text, if (!tag) { // Factor to convert from 1/10th of a mm into pixels - float factor; -#if GTK_CHECK_VERSION(2,2,0) - if (!gtk_check_version(2,2,0)) - factor = (float)gdk_screen_get_width(gtk_widget_get_screen(text)) / + float factor = + (float)gdk_screen_get_width(gtk_widget_get_screen(text)) / gdk_screen_get_width_mm(gtk_widget_get_screen(text)) / 10; - else -#endif - factor = (float)gdk_screen_width() / gdk_screen_width_mm() / 10; PangoTabArray* tabArray = pango_tab_array_new(tabs.GetCount(), TRUE); for (size_t i = 0; i < tabs.GetCount(); i++) @@ -303,9 +295,9 @@ extern "C" { static void au_apply_tag_callback(GtkTextBuffer *buffer, GtkTextTag *tag, - GtkTextIter *start, - GtkTextIter *end, - gpointer textctrl) + GtkTextIter * WXUNUSED(start), + GtkTextIter * WXUNUSED(end), + gpointer WXUNUSED(textctrl)) { if(tag == gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(buffer), "wxUrl")) g_signal_stop_emission_by_name (buffer, "apply_tag"); @@ -318,7 +310,7 @@ au_apply_tag_callback(GtkTextBuffer *buffer, extern "C" { static gboolean -pred_whitespace (gunichar ch, gpointer user_data) +pred_whitespace(gunichar ch, gpointer WXUNUSED(user_data)) { return g_unichar_isspace(ch); } @@ -326,7 +318,7 @@ pred_whitespace (gunichar ch, gpointer user_data) extern "C" { static gboolean -pred_non_whitespace (gunichar ch, gpointer user_data) +pred_non_whitespace (gunichar ch, gpointer WXUNUSED(user_data)) { return !g_unichar_isspace(ch); } @@ -334,7 +326,7 @@ pred_non_whitespace (gunichar ch, gpointer user_data) extern "C" { static gboolean -pred_nonpunct (gunichar ch, gpointer user_data) +pred_nonpunct (gunichar ch, gpointer WXUNUSED(user_data)) { return !g_unichar_ispunct(ch); } @@ -342,7 +334,7 @@ pred_nonpunct (gunichar ch, gpointer user_data) extern "C" { static gboolean -pred_nonpunct_or_slash (gunichar ch, gpointer user_data) +pred_nonpunct_or_slash (gunichar ch, gpointer WXUNUSED(user_data)) { return !g_unichar_ispunct(ch) || ch == '/'; } @@ -451,7 +443,7 @@ au_check_range(GtkTextIter *s, extern "C" { static void -au_insert_text_callback(GtkTextBuffer *buffer, +au_insert_text_callback(GtkTextBuffer * WXUNUSED(buffer), GtkTextIter *end, gchar *text, gint len, @@ -483,7 +475,7 @@ au_insert_text_callback(GtkTextBuffer *buffer, extern "C" { static void -au_delete_range_callback(GtkTextBuffer *buffer, +au_delete_range_callback(GtkTextBuffer * WXUNUSED(buffer), GtkTextIter *start, GtkTextIter *end, wxTextCtrl *win) @@ -502,6 +494,27 @@ au_delete_range_callback(GtkTextBuffer *buffer, } } +//----------------------------------------------------------------------------- +// "populate_popup" from text control and "unmap" from its poup menu +//----------------------------------------------------------------------------- + +extern "C" { +static void +gtk_textctrl_popup_unmap( GtkMenu *WXUNUSED(menu), wxTextCtrl* win ) +{ + win->GTKEnableFocusOutEvent(); +} +} + +extern "C" { +static void +gtk_textctrl_populate_popup( GtkEntry *WXUNUSED(entry), GtkMenu *menu, wxTextCtrl *win ) +{ + win->GTKDisableFocusOutEvent(); + + g_signal_connect (menu, "unmap", G_CALLBACK (gtk_textctrl_popup_unmap), win ); +} +} //----------------------------------------------------------------------------- // "changed" @@ -509,7 +522,7 @@ au_delete_range_callback(GtkTextBuffer *buffer, extern "C" { static void -gtk_text_changed_callback( GtkWidget *widget, wxTextCtrl *win ) +gtk_text_changed_callback( GtkWidget *WXUNUSED(widget), wxTextCtrl *win ) { if ( win->IgnoreTextUpdate() ) return; @@ -534,7 +547,7 @@ handle_text_clipboard_callback( GtkWidget *widget, wxTextCtrl *win, { wxClipboardTextEvent event( eventType, win->GetId() ); event.SetEventObject( win ); - if ( win->GetEventHandler()->ProcessEvent( event ) ) + if ( win->HandleWindowEvent( event ) ) { // don't let the default processing to take place if we did something // ourselves in the event handler @@ -565,19 +578,6 @@ gtk_paste_clipboard_callback( GtkWidget *widget, wxTextCtrl *win ) } } -//----------------------------------------------------------------------------- -// "expose_event" from scrolled window and textview -//----------------------------------------------------------------------------- - -extern "C" { -static gboolean -gtk_text_exposed_callback( GtkWidget *widget, GdkEventExpose *event, wxTextCtrl *win ) -{ - return TRUE; -} -} - - //----------------------------------------------------------------------------- // wxTextCtrl //----------------------------------------------------------------------------- @@ -620,7 +620,6 @@ void wxTextCtrl::Init() SetUpdateFont(false); m_text = NULL; - m_freezeCount = 0; m_showPositionOnThaw = NULL; m_gdkHandCursor = NULL; m_gdkXTermCursor = NULL; @@ -707,7 +706,9 @@ bool wxTextCtrl::Create( wxWindow *parent, if (style & wxNO_BORDER) g_object_set (m_text, "has-frame", FALSE, NULL); + } + g_object_ref(m_widget); m_parent->DoAddChild( this ); @@ -732,6 +733,11 @@ bool wxTextCtrl::Create( wxWindow *parent, G_CALLBACK (gtk_text_changed_callback), this); } + // Catch to disable focus out handling + g_signal_connect (m_text, "populate_popup", + G_CALLBACK (gtk_textctrl_populate_popup), + this); + if (!value.empty()) { SetValue( value ); @@ -785,6 +791,13 @@ bool wxTextCtrl::Create( wxWindow *parent, au_check_range(&start, &end); } } + else // single line + { + // do the right thing with Enter presses depending on whether we have + // wxTE_PROCESS_ENTER or not + GTKSetActivatesDefault(); + } + g_signal_connect (m_text, "copy-clipboard", G_CALLBACK (gtk_copy_clipboard_callback), this); @@ -820,9 +833,19 @@ void wxTextCtrl::GTKSetEditable() void wxTextCtrl::GTKSetVisibility() { - // VZ: shouldn't we assert if wxTE_PASSWORD is set for multiline control? - if ( IsSingleLine() ) - gtk_entry_set_visibility(GTK_ENTRY(m_text), !HasFlag(wxTE_PASSWORD)); + wxCHECK_RET( IsSingleLine(), + "wxTE_PASSWORD is for single line text controls only" ); + + gtk_entry_set_visibility(GTK_ENTRY(m_text), !HasFlag(wxTE_PASSWORD)); +} + +void wxTextCtrl::GTKSetActivatesDefault() +{ + wxCHECK_RET( IsSingleLine(), + "wxTE_PROCESS_ENTER is for single line text controls only" ); + + gtk_entry_set_activates_default(GTK_ENTRY(m_text), + !HasFlag(wxTE_PROCESS_ENTER)); } void wxTextCtrl::GTKSetWrapMode() @@ -840,17 +863,7 @@ void wxTextCtrl::GTKSetWrapMode() else if ( HasFlag( wxTE_WORDWRAP ) ) wrap = GTK_WRAP_WORD; else // HasFlag(wxTE_BESTWRAP) always true as wxTE_BESTWRAP == 0 - { - // GTK_WRAP_WORD_CHAR seems to be new in GTK+ 2.4 -#ifdef __WXGTK24__ - if ( !gtk_check_version(2,4,0) ) - { - wrap = GTK_WRAP_WORD_CHAR; - } - else -#endif // __WXGTK24__ - wrap = GTK_WRAP_WORD; - } + wrap = GTK_WRAP_WORD_CHAR; gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( m_text ), wrap ); } @@ -871,23 +884,16 @@ void wxTextCtrl::GTKSetJustification() } else // single line { -#ifdef __WXGTK24__ - // gtk_entry_set_alignment was introduced in gtk+-2.3.5 - if (!gtk_check_version(2,4,0)) - { - gfloat align; - if ( HasFlag(wxTE_RIGHT) ) - align = 1.0; - else if ( HasFlag(wxTE_CENTRE) ) - align = 0.5; - else // single line - align = 0.0; - - gtk_entry_set_alignment(GTK_ENTRY(m_text), align); - } -#endif // __WXGTK24__ - } + gfloat align; + if ( HasFlag(wxTE_RIGHT) ) + align = 1.0; + else if ( HasFlag(wxTE_CENTRE) ) + align = 0.5; + else // single line + align = 0.0; + gtk_entry_set_alignment(GTK_ENTRY(m_text), align); + } } void wxTextCtrl::SetWindowStyleFlag(long style) @@ -902,6 +908,9 @@ void wxTextCtrl::SetWindowStyleFlag(long style) if ( (style & wxTE_PASSWORD) != (styleOld & wxTE_PASSWORD) ) GTKSetVisibility(); + if ( (style & wxTE_PROCESS_ENTER) != (styleOld & wxTE_PROCESS_ENTER) ) + GTKSetActivatesDefault(); + static const long flagsWrap = wxTE_WORDWRAP | wxTE_CHARWRAP | wxTE_DONTWRAP; if ( (style & flagsWrap) != (styleOld & flagsWrap) ) GTKSetWrapMode(); @@ -943,7 +952,7 @@ wxFontEncoding wxTextCtrl::GetTextEncoding() const // first check the default text style (we intentionally don't check the // style for the current position as it doesn't make sense for SetValue()) const wxTextAttr& style = GetDefaultStyle(); - wxFontEncoding enc = style.HasFont() ? style.GetFont().GetEncoding() + wxFontEncoding enc = style.HasFontEncoding() ? style.GetFontEncoding() : wxFONTENCODING_SYSTEM; // fall back to the controls font if no style @@ -973,6 +982,22 @@ void wxTextCtrl::DoSetValue( const wxString &value, int flags ) return; } + if (value.IsEmpty()) + { + if ( !(flags & SetValue_SendEvent) ) + EnableTextChangedEvents(false); + + gtk_text_buffer_set_text( m_buffer, "", 0 ); + + if ( !(flags & SetValue_SendEvent) ) + EnableTextChangedEvents(true); + + return; + } + +#if wxUSE_UNICODE + const wxCharBuffer buffer(value.utf8_str()); +#else wxFontEncoding enc = m_defaultStyle.HasFont() ? m_defaultStyle.GetFont().GetEncoding() : wxFONTENCODING_SYSTEM; @@ -987,6 +1012,7 @@ void wxTextCtrl::DoSetValue( const wxString &value, int flags ) wxLogWarning(_("Failed to set text in the text control.")); return; } +#endif if ( !(flags & SetValue_SendEvent) ) { @@ -1007,9 +1033,6 @@ void wxTextCtrl::DoSetValue( const wxString &value, int flags ) { EnableTextChangedEvents(true); } - - // This was added after discussion on the list - SetInsertionPoint(0); } void wxTextCtrl::WriteText( const wxString &text ) @@ -1025,12 +1048,15 @@ void wxTextCtrl::WriteText( const wxString &text ) return; } +#if wxUSE_UNICODE + const wxCharBuffer buffer(text.utf8_str()); +#else // check if we have a specific style for the current position wxFontEncoding enc = wxFONTENCODING_SYSTEM; wxTextAttr style; - if ( GetStyle(GetInsertionPoint(), style) && style.HasFont() ) + if ( GetStyle(GetInsertionPoint(), style) && style.HasFontEncoding() ) { - enc = style.GetFont().GetEncoding(); + enc = style.GetFontEncoding(); } if ( enc == wxFONTENCODING_SYSTEM ) @@ -1045,6 +1071,7 @@ void wxTextCtrl::WriteText( const wxString &text ) wxLogWarning(_("Failed to insert text in the control.")); return; } +#endif // First remove the selection if there is one // TODO: Is there an easier GTK specific way to do this? @@ -1225,6 +1252,7 @@ bool wxTextCtrl::Enable( bool enable ) } gtk_widget_set_sensitive( m_text, enable ); + SetCursor(enable ? wxCursor(wxCURSOR_IBEAM) : wxCursor()); return true; } @@ -1232,7 +1260,7 @@ bool wxTextCtrl::Enable( bool enable ) // wxGTK-specific: called recursively by Enable, // to give widgets an opportunity to correct their colours after they // have been changed by Enable -void wxTextCtrl::OnEnabled( bool enable ) +void wxTextCtrl::OnEnabled(bool WXUNUSED(enable)) { // If we have a custom background colour, we use this colour in both // disabled and enabled mode, or we end up with a different colour under the @@ -1317,8 +1345,7 @@ void wxTextCtrl::SetSelection( long from, long to ) gtk_text_buffer_get_iter_at_offset( m_buffer, &fromi, from ); gtk_text_buffer_get_iter_at_offset( m_buffer, &toi, to ); - gtk_text_buffer_place_cursor( m_buffer, &toi ); - gtk_text_buffer_move_mark_by_name( m_buffer, "selection_bound", &fromi ); + gtk_text_buffer_select_range( m_buffer, &fromi, &toi ); } else // single line { @@ -1530,32 +1557,9 @@ void wxTextCtrl::OnChar( wxKeyEvent &key_event ) wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId); event.SetEventObject(this); event.SetString(GetValue()); - if ( GetEventHandler()->ProcessEvent(event) ) + if ( HandleWindowEvent(event) ) return; } - - // FIXME: this is not the right place to do it, wxDialog::OnCharHook() - // probably is - if ( IsSingleLine() ) - { - // This will invoke the dialog default action, such - // as the clicking the default button. - - wxWindow *top_frame = m_parent; - while (top_frame->GetParent() && !(top_frame->IsTopLevel())) - top_frame = top_frame->GetParent(); - - if (top_frame && GTK_IS_WINDOW(top_frame->m_widget)) - { - GtkWindow *window = GTK_WINDOW(top_frame->m_widget); - - if (window->default_widget) - { - gtk_widget_activate (window->default_widget); - return; - } - } - } } key_event.Skip(); @@ -1744,60 +1748,52 @@ wxSize wxTextCtrl::DoGetBestSize() const // freeze/thaw // ---------------------------------------------------------------------------- -void wxTextCtrl::Freeze() +void wxTextCtrl::DoFreeze() { wxCHECK_RET(m_text != NULL, wxT("invalid text ctrl")); + wxWindow::DoFreeze(); + if ( HasFlag(wxTE_MULTILINE) ) { - if (m_freezeCount++ == 0) - { - // freeze textview updates and remove buffer - g_signal_connect (m_text, "expose_event", - G_CALLBACK (gtk_text_exposed_callback), this); - g_signal_connect (m_widget, "expose_event", - G_CALLBACK (gtk_text_exposed_callback), this); - gtk_widget_set_sensitive(m_widget, false); - 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). - // 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); - } + GTKFreezeWidget(m_text); + + // 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). + // 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); } } -void wxTextCtrl::Thaw() +void wxTextCtrl::DoThaw() { if ( HasFlag(wxTE_MULTILINE) ) { - wxCHECK_RET(m_freezeCount != 0, _T("Thaw() without matching Freeze()")); + // reattach buffer: + gtk_text_view_set_buffer(GTK_TEXT_VIEW(m_text), m_buffer); + g_object_unref(m_buffer); - if (--m_freezeCount == 0) + if (m_showPositionOnThaw != NULL) { - // 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); - if (m_showPositionOnThaw != NULL) - { - gtk_text_view_scroll_mark_onscreen( - GTK_TEXT_VIEW(m_text), m_showPositionOnThaw); - m_showPositionOnThaw = NULL; - } + gtk_text_view_scroll_mark_onscreen( + GTK_TEXT_VIEW(m_text), m_showPositionOnThaw); + m_showPositionOnThaw = NULL; } + + // and thaw the window + GTKThawWidget(m_text); } + + wxWindow::DoThaw(); } // ---------------------------------------------------------------------------- @@ -1849,8 +1845,8 @@ void wxTextCtrl::OnUrlMouseEvent(wxMouseEvent& event) InitCommandEvent(url_event); // Is that a good idea? Seems not (pleasure with gtk_text_view_start_selection_drag) - //event.Skip(!GetEventHandler()->ProcessEvent(url_event)); - GetEventHandler()->ProcessEvent(url_event); + //event.Skip(!HandleWindowEvent(url_event)); + HandleWindowEvent(url_event); } bool wxTextCtrl::GTKProcessEvent(wxEvent& event) const