From 1a55f4cfa21f0be2d4d34124449d3f29fa7f0f24 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 24 Aug 2017 17:04:04 +0200 Subject: [PATCH] Don't send wxEVT_CHAR events from wxTextCtrl::SetValue() in wxGTK This could happen if the code calling SetValue() was in a handler invoked in response to a keyboard action as our insert-text signal handler believed that it was called in response to this key in this case, even when it wasn't the case. This extends the changes of def8247c617238bc69fbd8d7b55325e9051c9e3f to WriteText() to DoSetValue(), thus fixing the same problem in SetValue() and ChangeValue() too. But the question of why do we have two so similar, yet different, functions, resulting in having to fix the same bugs twice still remains unanswered... --- src/gtk/textctrl.cpp | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/gtk/textctrl.cpp b/src/gtk/textctrl.cpp index b394203e98..60de6ac116 100644 --- a/src/gtk/textctrl.cpp +++ b/src/gtk/textctrl.cpp @@ -1030,6 +1030,30 @@ bool wxTextCtrl::IsEmpty() const return wxTextEntry::IsEmpty(); } +// Helper class used by DoSetValue() and WriteText() to temporarily reset +// m_imKeyEvent to NULL and restore its original value in the dtor. +class TemporarilyUnsetIMKeyEvent +{ +public: + explicit TemporarilyUnsetIMKeyEvent(GdkEventKey*& event) + : m_event(event), + m_eventOrig(event) + { + m_event = NULL; + } + + ~TemporarilyUnsetIMKeyEvent() + { + m_event = m_eventOrig; + } + +private: + GdkEventKey*& m_event; + GdkEventKey* const m_eventOrig; + + wxDECLARE_NO_COPY_CLASS(TemporarilyUnsetIMKeyEvent); +}; + void wxTextCtrl::DoSetValue( const wxString &value, int flags ) { wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") ); @@ -1079,6 +1103,12 @@ void wxTextCtrl::DoSetValue( const wxString &value, int flags ) EnableTextChangedEvents(false); } + // This will emit insert-text signal which assumes that if m_imKeyEvent is + // set, it is called in response to this key press -- which is not the case + // here (but m_imKeyEvent might still be set e.g. because we're called from + // a menu event handler triggered by a keyboard accelerator). + TemporarilyUnsetIMKeyEvent unset(m_imKeyEvent); + gtk_text_buffer_set_text( m_buffer, buffer, strlen(buffer) ); if ( !(flags & SetValue_SendEvent) ) @@ -1095,9 +1125,7 @@ void wxTextCtrl::WriteText( const wxString &text ) DontMarkDirtyOnNextChange(); // avoid generating wxEVT_CHAR when called from wxEVT_CHAR handler - GdkEventKey* const imKeyEvent_save = m_imKeyEvent; - m_imKeyEvent = NULL; - wxON_BLOCK_EXIT_SET(m_imKeyEvent, imKeyEvent_save); + TemporarilyUnsetIMKeyEvent unset(m_imKeyEvent); if ( !IsMultiLine() ) {