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 def8247c61
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...
This commit is contained in:
Vadim Zeitlin 2017-08-24 17:04:04 +02:00
parent 741dd542f2
commit 1a55f4cfa2

View File

@ -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() )
{