+
+struct wxGtkIMData
+{
+ GtkIMContext *context;
+ GdkEventKey *lastKeyEvent;
+
+ wxGtkIMData()
+ {
+ context = gtk_im_multicontext_new();
+ lastKeyEvent = NULL;
+ }
+ ~wxGtkIMData()
+ {
+ g_object_unref (context);
+ }
+};
+
+extern "C" {
+static gboolean
+gtk_window_key_press_callback( GtkWidget *widget,
+ GdkEventKey *gdk_event,
+ wxWindow *win )
+{
+ if (!win->m_hasVMT)
+ return FALSE;
+ if (g_blockEventsOnDrag)
+ return FALSE;
+
+ // GTK+ sends keypress events to the focus widget and then
+ // to all its parent and grandparent widget. We only want
+ // the key events from the focus widget.
+ if (!GTK_WIDGET_HAS_FOCUS(widget))
+ return FALSE;
+
+ wxKeyEvent event( wxEVT_KEY_DOWN );
+ bool ret = false;
+ bool return_after_IM = false;
+
+ if( wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
+ {
+ // Emit KEY_DOWN event
+ ret = win->HandleWindowEvent( event );
+ }
+ else
+ {
+ // Return after IM processing as we cannot do
+ // anything with it anyhow.
+ return_after_IM = true;
+ }
+
+ if ((!ret) && (win->m_imData != NULL))
+ {
+ // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
+ // docs, if IM filter returns true, no further processing should be done.
+ // we should send the key_down event anyway.
+ bool intercepted_by_IM = gtk_im_context_filter_keypress(win->m_imData->context, gdk_event);
+ win->m_imData->lastKeyEvent = NULL;
+ if (intercepted_by_IM)
+ {
+ wxLogTrace(TRACE_KEYS, _T("Key event intercepted by IM"));
+ return TRUE;
+ }
+ }
+
+ if (return_after_IM)
+ return FALSE;
+
+#if wxUSE_ACCEL
+ if (!ret)
+ {
+ wxWindowGTK *ancestor = win;
+ while (ancestor)
+ {
+ int command = ancestor->GetAcceleratorTable()->GetCommand( event );
+ if (command != -1)
+ {
+ wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
+ ret = ancestor->HandleWindowEvent( command_event );
+ break;
+ }
+ if (ancestor->IsTopLevel())
+ break;
+ ancestor = ancestor->GetParent();
+ }
+ }
+#endif // wxUSE_ACCEL
+
+ // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
+ // will only be sent if it is not in an accelerator table.
+ if (!ret)
+ {
+ long key_code;
+ KeySym keysym = gdk_event->keyval;
+ // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
+ key_code = wxTranslateKeySymToWXKey(keysym, true /* isChar */);
+ if ( !key_code )
+ {
+ if ( wxIsAsciiKeysym(keysym) )
+ {
+ // ASCII key
+ key_code = (unsigned char)keysym;
+ }
+ // gdk_event->string is actually deprecated
+ else if ( gdk_event->length == 1 )
+ {
+ key_code = (unsigned char)gdk_event->string[0];
+ }
+ }
+
+ if ( key_code )
+ {
+ wxLogTrace(TRACE_KEYS, _T("Char event: %ld"), key_code);
+
+ event.m_keyCode = key_code;
+
+ // To conform to the docs we need to translate Ctrl-alpha
+ // characters to values in the range 1-26.
+ if ( event.ControlDown() &&
+ ( wxIsLowerChar(key_code) || wxIsUpperChar(key_code) ))
+ {
+ if ( wxIsLowerChar(key_code) )
+ event.m_keyCode = key_code - 'a' + 1;
+ if ( wxIsUpperChar(key_code) )
+ event.m_keyCode = key_code - 'A' + 1;
+#if wxUSE_UNICODE
+ event.m_uniChar = event.m_keyCode;
+#endif
+ }
+
+ // Implement OnCharHook by checking ancestor top level windows
+ 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 );
+ }
+ }
+ }
+
+ return ret;
+}
+}
+
+extern "C" {
+static void
+gtk_wxwindow_commit_cb (GtkIMContext * WXUNUSED(context),
+ const gchar *str,
+ wxWindow *window)
+{
+ wxKeyEvent event( wxEVT_KEY_DOWN );
+
+ // take modifiers, cursor position, timestamp etc. from the last
+ // key_press_event that was fed into Input Method:
+ if (window->m_imData->lastKeyEvent)
+ {
+ wxFillOtherKeyEventFields(event,
+ window, window->m_imData->lastKeyEvent);
+ }
+ else
+ {
+ event.SetEventObject( window );
+ }
+
+ const wxString data(wxGTK_CONV_BACK_SYS(str));
+ if( data.empty() )
+ 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 )
+ {
+#if wxUSE_UNICODE
+ event.m_uniChar = *pstr;
+ // Backward compatible for ISO-8859-1
+ event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
+ wxLogTrace(TRACE_KEYS, _T("IM sent character '%c'"), event.m_uniChar);
+#else
+ event.m_keyCode = (char)*pstr;
+#endif // wxUSE_UNICODE
+
+ // To conform to the docs we need to translate Ctrl-alpha
+ // characters to values in the range 1-26.
+ if ( event.ControlDown() &&
+ ( wxIsLowerChar(*pstr) || wxIsUpperChar(*pstr) ))
+ {
+ if ( wxIsLowerChar(*pstr) )
+ event.m_keyCode = *pstr - 'a' + 1;
+ if ( wxIsUpperChar(*pstr) )
+ event.m_keyCode = *pstr - 'A' + 1;
+
+ event.m_keyCode = *pstr - 'a' + 1;
+#if wxUSE_UNICODE
+ event.m_uniChar = event.m_keyCode;
+#endif
+ }
+
+ if (parent)
+ {
+ event.SetEventType( wxEVT_CHAR_HOOK );
+ ret = parent->HandleWindowEvent( event );
+ }
+
+ if (!ret)
+ {
+ event.SetEventType(wxEVT_CHAR);
+ ret = window->HandleWindowEvent( event );
+ }
+ }
+}
+}
+
+
+//-----------------------------------------------------------------------------
+// "key_release_event" from any window
+//-----------------------------------------------------------------------------
+
+extern "C" {
+static gboolean
+gtk_window_key_release_callback( GtkWidget * WXUNUSED(widget),
+ GdkEventKey *gdk_event,
+ wxWindowGTK *win )
+{
+ if (!win->m_hasVMT)
+ return FALSE;
+
+ if (g_blockEventsOnDrag)
+ return FALSE;
+
+ wxKeyEvent event( wxEVT_KEY_UP );
+ if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
+ {
+ // unknown key pressed, ignore (the event would be useless anyhow)
+ return FALSE;
+ }
+
+ return win->GTKProcessEvent(event);
+}
+}
+
+// ============================================================================
+// the mouse events
+// ============================================================================
+