Don't reuse the same event object for multiple events in wxGTK.

The old code simply called SetEventType() to change the type of the event and
called HandleWindowEvent() again with it. This was incorrect as the event was
modified after being processed the first time, notably its WasProcessed() flag
was set and so wxApp::FilterEvent() wasn't called when it was being processed
the second time. In practice this meant that FilterEvent() was never called
for wxEVT_CHAR events -- for which it's nevertheless very useful to have as it
allows to implement application-wide keyboard processing.

Also refactor the code to avoid duplication, exactly the same event sending
code was used in gtk_window_key_press_callback() and gtk_wxwindow_commit_cb().
Extract it now in a private SendCharHookAndCharEvents() function.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@65005 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2010-07-18 11:53:04 +00:00
parent 1cf9a80cc1
commit 2933f70a8b

View File

@@ -822,6 +822,37 @@ struct wxGtkIMData
} }
}; };
namespace
{
// Send wxEVT_CHAR_HOOK event to the parent of the window and if it wasn't
// processed, send wxEVT_CHAR to the window itself. Return true if either of
// them was handled.
bool
SendCharHookAndCharEvents(const wxKeyEvent& event, wxWindow *win)
{
// wxEVT_CHAR_HOOK must be sent to the top level parent window to allow it
// to handle key events in all of its children.
wxWindow * const parent = wxGetTopLevelParent(win);
if ( parent )
{
// We need to make a copy of the event object because it is
// modified while it's handled, notably its WasProcessed() flag
// is set after it had been processed once.
wxKeyEvent eventCharHook(event);
eventCharHook.SetEventType(wxEVT_CHAR_HOOK);
if ( parent->HandleWindowEvent(eventCharHook) )
return true;
}
// As above, make a copy of the event first.
wxKeyEvent eventChar(event);
eventChar.SetEventType(wxEVT_CHAR);
return win->HandleWindowEvent(eventChar);
}
} // anonymous namespace
extern "C" { extern "C" {
static gboolean static gboolean
gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget), gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget),
@@ -938,21 +969,7 @@ gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget),
#endif #endif
} }
// Implement OnCharHook by checking ancestor top level windows ret = SendCharHookAndCharEvents(event, win);
wxWindow *parent = win;
while (parent && !parent->IsTopLevel())
parent = parent->GetParent();
if (parent)
{
event.SetEventType( wxEVT_CHAR_HOOK );
ret = parent->HandleWindowEvent( event );
}
if (!ret)
{
event.SetEventType(wxEVT_CHAR);
ret = win->HandleWindowEvent( event );
}
} }
} }
@@ -984,13 +1001,6 @@ gtk_wxwindow_commit_cb (GtkIMContext * WXUNUSED(context),
if( data.empty() ) if( data.empty() )
return; return;
bool ret = false;
// Implement OnCharHook by checking ancestor top level windows
wxWindow *parent = window;
while (parent && !parent->IsTopLevel())
parent = parent->GetParent();
for( wxString::const_iterator pstr = data.begin(); pstr != data.end(); ++pstr ) for( wxString::const_iterator pstr = data.begin(); pstr != data.end(); ++pstr )
{ {
#if wxUSE_UNICODE #if wxUSE_UNICODE
@@ -1018,17 +1028,7 @@ gtk_wxwindow_commit_cb (GtkIMContext * WXUNUSED(context),
#endif #endif
} }
if (parent) SendCharHookAndCharEvents(event, window);
{
event.SetEventType( wxEVT_CHAR_HOOK );
ret = parent->HandleWindowEvent( event );
}
if (!ret)
{
event.SetEventType(wxEVT_CHAR);
ret = window->HandleWindowEvent( event );
}
} }
} }
} }