+
+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 )
+{
+ DEBUG_MAIN_THREAD
+
+ if (!win->m_hasVMT)
+ return FALSE;
+ if (g_blockEventsOnDrag)
+ 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->GetEventHandler()->ProcessEvent( event );
+ }
+ else
+ {
+ // Return after IM processing as we cannot do
+ // anything with it anyhow.
+ return_after_IM = true;
+ }
+
+ // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
+ // When we get a key_press event here, it could be originate
+ // from the current widget or its child widgets. However, only the widget
+ // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
+ // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
+ // originated from its child widgets and shouldn't be passed to IM context.
+ // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
+ // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
+ // widgets has both IM context and input focus, the event should be filtered
+ // by gtk_im_context_filter_keypress().
+ // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
+ if ((!ret) && (win->m_imData != NULL) && ( wxWindow::FindFocus() == win ))
+ {
+ // 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->GetEventHandler()->ProcessEvent( 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->GetEventHandler()->ProcessEvent( event );
+ }
+
+ if (!ret)
+ {
+ event.SetEventType(wxEVT_CHAR);
+ ret = win->GetEventHandler()->ProcessEvent( event );
+ }
+ }
+ }
+
+ return ret;
+}
+}
+
+extern "C" {
+static void
+gtk_wxwindow_commit_cb (GtkIMContext *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);
+ }
+
+ const wxWxCharBuffer data(wxGTK_CONV_BACK_SYS(str));
+ if( !data )
+ return;
+
+ bool ret = false;
+
+ // Implement OnCharHook by checking ancestor top level windows
+ wxWindow *parent = window;
+ while (parent && !parent->IsTopLevel())
+ parent = parent->GetParent();
+
+ for( const wxChar* pstr = data; *pstr; 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 = *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->GetEventHandler()->ProcessEvent( event );
+ }
+
+ if (!ret)
+ {
+ event.SetEventType(wxEVT_CHAR);
+ ret = window->GetEventHandler()->ProcessEvent( event );
+ }
+ }
+}
+}
+
+
+//-----------------------------------------------------------------------------
+// "key_release_event" from any window
+//-----------------------------------------------------------------------------
+
+extern "C" {
+static gboolean
+gtk_window_key_release_callback( GtkWidget *widget,
+ GdkEventKey *gdk_event,
+ wxWindowGTK *win )
+{
+ DEBUG_MAIN_THREAD
+
+ 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
+// ============================================================================
+