diff --git a/include/wx/gtk/textctrl.h b/include/wx/gtk/textctrl.h index d1e4e5ee716..c3d8a578f2e 100644 --- a/include/wx/gtk/textctrl.h +++ b/include/wx/gtk/textctrl.h @@ -161,10 +161,6 @@ class WXDLLIMPEXP_CORE wxTextCtrl: public wxTextCtrlBase virtual wxString DoGetValue() const wxOVERRIDE; - // Override this to use either GtkEntry or GtkTextView IME depending on the - // kind of control we are. - virtual int GTKIMFilterKeypress(GdkEventKey* event) const wxOVERRIDE; - virtual wxPoint DoPositionToCoords(long pos) const wxOVERRIDE; // wrappers hiding the differences between functions doing the same thing diff --git a/include/wx/gtk/textentry.h b/include/wx/gtk/textentry.h index aaf777a515b..4e2aa0a8ac3 100644 --- a/include/wx/gtk/textentry.h +++ b/include/wx/gtk/textentry.h @@ -57,20 +57,11 @@ class WXDLLIMPEXP_CORE wxTextEntry : public wxTextEntryBase virtual wxString GetHint() const wxOVERRIDE; #endif - // implementation only from now on - void SendMaxLenEvent(); - bool GTKEntryOnInsertText(const char* text); - bool GTKIsUpperCase() const { return m_isUpperCase; } - protected: // This method must be called from the derived class Create() to connect // the handlers for the clipboard (cut/copy/paste) events. void GTKConnectClipboardSignals(GtkWidget* entry); - // And this one to connect "insert-text" signal. - void GTKConnectInsertTextSignal(GtkEntry* entry); - - virtual void DoSetValue(const wxString& value, int flags) wxOVERRIDE; virtual wxString DoGetValue() const wxOVERRIDE; @@ -81,9 +72,6 @@ class WXDLLIMPEXP_CORE wxTextEntry : public wxTextEntryBase virtual bool DoAutoCompleteStrings(const wxArrayString& choices) wxOVERRIDE; virtual bool DoAutoCompleteCustom(wxTextCompleter *completer) wxOVERRIDE; - // Override the base class method to use GtkEntry IM context. - virtual int GTKIMFilterKeypress(GdkEventKey* event) const; - static int GTKGetEntryTextLength(GtkEntry* entry); private: diff --git a/include/wx/gtk/window.h b/include/wx/gtk/window.h index 16c755c4139..eed9e88d8da 100644 --- a/include/wx/gtk/window.h +++ b/include/wx/gtk/window.h @@ -289,40 +289,10 @@ class WXDLLIMPEXP_CORE wxWindowGTK : public wxWindowBase void GTKDisableFocusOutEvent(); void GTKEnableFocusOutEvent(); - - // Input method support - - // The IM context used for generic, i.e. non-native, windows. - // - // It might be a good idea to avoid allocating it unless key events from - // this window are really needed but currently we do it unconditionally. - // - // For native widgets (i.e. those for which IsOfStandardClass() returns - // true) it is NULL. - GtkIMContext* m_imContext; - - // Pointer to the event being currently processed by the IME or NULL if not - // inside key handling. - GdkEventKey* m_imKeyEvent; - - // This method generalizes gtk_im_context_filter_keypress(): for the - // generic windows it does just that but it's overridden by the classes - // wrapping native widgets that use IM themselves and so provide specific - // methods for accessing it such gtk_entry_im_context_filter_keypress(). - virtual int GTKIMFilterKeypress(GdkEventKey* event) const; - - // This method must be called from the derived classes "insert-text" signal - // handlers to check if the text is not being inserted by the IM and, if - // this is the case, generate appropriate wxEVT_CHAR events for it. - // - // Returns true if we did generate and process events corresponding to this - // text or false if we didn't handle it. - bool GTKOnInsertText(const char* text); - - // This is just a helper of GTKOnInsertText() which is also used by GTK+ - // "commit" signal handler. - bool GTKDoInsertTextFromIM(const char* text); - + // Variable to store the result of conversion from GdkEvent to wxKeyEvent + wxKeyEvent m_event; + // Return after IM processing as we cannot do anything with it anyhow. + bool m_return_after_IM; // indices for the arrays below enum ScrollDir { ScrollDir_Horz, ScrollDir_Vert, ScrollDir_Max }; diff --git a/src/gtk/combobox.cpp b/src/gtk/combobox.cpp index 578088c0fd1..189c6af1f2b 100644 --- a/src/gtk/combobox.cpp +++ b/src/gtk/combobox.cpp @@ -188,7 +188,6 @@ bool wxComboBox::Create( wxWindow *parent, wxWindowID id, const wxString& value, g_signal_connect_after (entry, "changed", G_CALLBACK (gtkcombobox_text_changed_callback), this); - GTKConnectInsertTextSignal(entry); GTKConnectClipboardSignals(GTK_WIDGET(entry)); } diff --git a/src/gtk/textctrl.cpp b/src/gtk/textctrl.cpp index 54af9c1deff..6c7e086269f 100644 --- a/src/gtk/textctrl.cpp +++ b/src/gtk/textctrl.cpp @@ -469,23 +469,6 @@ au_check_range(GtkTextIter *s, extern "C" { -// Normal version used for detecting IME input and generating appropriate -// events for it. -static void -wx_insert_text_callback(GtkTextBuffer* buffer, - GtkTextIter* WXUNUSED(end), - gchar *text, - gint WXUNUSED(len), - wxTextCtrl *win) -{ - if ( win->GTKOnInsertText(text) ) - { - // If we already handled the new text insertion, don't do it again. - g_signal_stop_emission_by_name (buffer, "insert_text"); - } -} - - // And an "after" version used for detecting URLs in the text. static void au_insert_text_callback(GtkTextBuffer *buffer, @@ -840,11 +823,6 @@ bool wxTextCtrl::Create( wxWindow *parent, au_check_range(&start, &end); } - // Also connect a normal (not "after") signal handler for checking for - // the IME-generated input. - g_signal_connect(m_buffer, "insert_text", - G_CALLBACK(wx_insert_text_callback), this); - // Needed for wxTE_AUTO_URL and applying custom styles g_signal_connect_after(m_buffer, "insert_text", G_CALLBACK(au_insert_text_callback), this); @@ -854,8 +832,6 @@ bool wxTextCtrl::Create( wxWindow *parent, // do the right thing with Enter presses depending on whether we have // wxTE_PROCESS_ENTER or not GTKSetActivatesDefault(); - - GTKConnectInsertTextSignal(GTK_ENTRY(m_text)); } GTKConnectClipboardSignals(m_text); @@ -882,24 +858,6 @@ GtkEntry *wxTextCtrl::GetEntry() const return NULL; } -int wxTextCtrl::GTKIMFilterKeypress(GdkEventKey* event) const -{ - if (IsSingleLine()) - return wxTextEntry::GTKIMFilterKeypress(event); - - int result = false; -#if GTK_CHECK_VERSION(2, 22, 0) - if (wx_is_at_least_gtk2(22)) - { - result = gtk_text_view_im_context_filter_keypress(GTK_TEXT_VIEW(m_text), event); - } -#else // GTK+ < 2.22 - wxUnusedVar(event); -#endif // GTK+ 2.22+ - - return result; -} - // ---------------------------------------------------------------------------- // flags handling // ---------------------------------------------------------------------------- @@ -1083,15 +1041,6 @@ void wxTextCtrl::WriteText( const wxString &text ) // make sure marking is re-enabled even if events are suppressed wxON_BLOCK_EXIT_SET(m_dontMarkDirty, false); - // Inserting new text into the control below 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), so reset m_imKeyEvent temporarily. - GdkEventKey* const imKeyEvent_save = m_imKeyEvent; - m_imKeyEvent = NULL; - wxON_BLOCK_EXIT_SET(m_imKeyEvent, imKeyEvent_save); - if ( !IsMultiLine() ) { wxTextEntry::WriteText(text); diff --git a/src/gtk/textentry.cpp b/src/gtk/textentry.cpp index 598d7593a07..8461fa8fea0 100644 --- a/src/gtk/textentry.cpp +++ b/src/gtk/textentry.cpp @@ -57,96 +57,7 @@ static int GetEntryTextLength(GtkEntry* entry) // signal handlers implementation // ============================================================================ -// "insert_text" handler for GtkEntry extern "C" { -static void -wx_gtk_insert_text_callback(GtkEditable *editable, - const gchar * new_text, - gint new_text_length, - gint * position, - wxTextEntry *text) -{ - GtkEntry *entry = GTK_ENTRY (editable); - -#if GTK_CHECK_VERSION(3,0,0) || defined(GSEAL_ENABLE) - const int text_max_length = gtk_entry_buffer_get_max_length(gtk_entry_get_buffer(entry)); -#else - const int text_max_length = entry->text_max_length; -#endif - - bool handled = false; - - // check that we don't overflow the max length limit if we have it - if ( text_max_length ) - { - const int text_length = GetEntryTextLength(entry); - - // We can't use new_text_length as it is in bytes while we want to count - // characters (in first approximation, anyhow...). - if ( text_length + g_utf8_strlen(new_text, -1) > text_max_length ) - { - // Prevent the new text from being inserted. - handled = true; - - // Currently we don't insert anything at all, but it would be better to - // insert as many characters as would fit into the text control and - // only discard the rest. - - // Notify the user code about overflow. - text->SendMaxLenEvent(); - } - } - - // Check if we have to convert all input to upper-case - if ( !handled && text->GTKIsUpperCase() ) - { - const wxGtkString upper(g_utf8_strup(new_text, new_text_length)); - - // Use the converted text to generate events - if ( !text->GTKEntryOnInsertText(upper) ) - { - // Event not handled, so do insert the text: we have to do it - // ourselves to use the upper-case version of it - - // Prevent recursive call to this handler again - g_signal_handlers_block_by_func - ( - editable, - (gpointer)wx_gtk_insert_text_callback, - text - ); - - gtk_editable_insert_text(editable, upper, strlen(upper), position); - - g_signal_handlers_unblock_by_func - ( - editable, - (gpointer)wx_gtk_insert_text_callback, - text - ); - } - - // Don't call the default handler in any case, either the event was - // handled in the user code or we've already inserted the text. - handled = true; - } - - if ( !handled && text->GTKEntryOnInsertText(new_text) ) - { - // If we already handled the new text insertion, don't do it again. - handled = true; - } - - if ( handled ) - { - // We must update the position to point after the newly inserted text, - // as expected by GTK+. - *position = text->GetInsertionPoint(); - - g_signal_stop_emission_by_name (editable, "insert_text"); - } -} - // GTK+ does not expose any mechanism that we can really rely on to detect if/when // the completion popup is shown or hidden. And the sole reliable way (for now) to // know its state is to connect to the "grab-notify" signal and be notified then @@ -827,19 +738,6 @@ void wxTextEntry::SetMaxLength(unsigned long len) gtk_entry_set_max_length(entry, len); } -void wxTextEntry::SendMaxLenEvent() -{ - // remember that the next changed signal is to be ignored to avoid - // generating a dummy wxEVT_TEXT event - //IgnoreNextTextUpdate(); - - wxWindow * const win = GetEditableWindow(); - wxCommandEvent event(wxEVT_TEXT_MAXLEN, win->GetId()); - event.SetEventObject(win); - event.SetString(GetValue()); - win->HandleWindowEvent(event); -} - void wxTextEntry::ForceUpper() { if ( !m_isUpperCase ) @@ -850,36 +748,6 @@ void wxTextEntry::ForceUpper() } } -// ---------------------------------------------------------------------------- -// IM handling -// ---------------------------------------------------------------------------- - -int wxTextEntry::GTKIMFilterKeypress(GdkEventKey* event) const -{ - int result = false; -#if GTK_CHECK_VERSION(2, 22, 0) - if (wx_is_at_least_gtk2(22)) - { - result = gtk_entry_im_context_filter_keypress(GetEntry(), event); - } -#else // GTK+ < 2.22 - wxUnusedVar(event); -#endif // GTK+ 2.22+ - - return result; -} - -void wxTextEntry::GTKConnectInsertTextSignal(GtkEntry* entry) -{ - g_signal_connect(entry, "insert_text", - G_CALLBACK(wx_gtk_insert_text_callback), this); -} - -bool wxTextEntry::GTKEntryOnInsertText(const char* text) -{ - return GetEditableWindow()->GTKOnInsertText(text); -} - // ---------------------------------------------------------------------------- // margins support // ---------------------------------------------------------------------------- diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index 2ff5c94b077..fc64bcbf4e1 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -1172,24 +1172,25 @@ void AdjustCharEventKeyCodes(wxKeyEvent& event) static bool gs_isNewEvent; extern "C" { + static gboolean -gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget), - GdkEventKey *gdk_event, - wxWindow *win ) +gtk_window_key_press_before_callback( GtkWidget *WXUNUSED(widget), + GdkEventKey *gdk_event, + wxWindow *win ) { if (g_blockEventsOnDrag) return FALSE; wxPROCESS_EVENT_ONCE(GdkEventKey, gdk_event); - wxKeyEvent event( wxEVT_KEY_DOWN ); + win->m_event = wxKeyEvent( wxEVT_KEY_DOWN ); bool ret = false; - bool return_after_IM = false; + win->m_return_after_IM = false; - if( wxTranslateGTKKeyEventToWx(event, win, gdk_event) ) + if( wxTranslateGTKKeyEventToWx(win->m_event, win, gdk_event) ) { // Send the CHAR_HOOK event first - if ( SendCharHookEvent(event, win) ) + if ( SendCharHookEvent(win->m_event, win) ) { // Don't do anything at all with this event any more. return TRUE; @@ -1200,7 +1201,7 @@ gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget), wxWindowGTK *ancestor = win; while (ancestor) { - int command = ancestor->GetAcceleratorTable()->GetCommand( event ); + int command = ancestor->GetAcceleratorTable()->GetCommand( win->m_event ); if (command != -1) { wxCommandEvent menu_event( wxEVT_MENU, command ); @@ -1225,150 +1226,68 @@ gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget), // If not an accelerator, then emit KEY_DOWN event if ( !ret ) - ret = win->HandleWindowEvent( event ); + ret = win->HandleWindowEvent( win->m_event ); } else { // Return after IM processing as we cannot do // anything with it anyhow. - return_after_IM = true; + win->m_return_after_IM = true; } - if ( !ret ) - { - // Indicate that IM handling is in process by setting this pointer - // (which will remain valid for all the code called during IM key - // handling). - win->m_imKeyEvent = gdk_event; - - // 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. - const int intercepted_by_IM = win->GTKIMFilterKeypress(gdk_event); - - win->m_imKeyEvent = NULL; + return ret; +} - if ( intercepted_by_IM ) - { - wxLogTrace(TRACE_KEYS, wxT("Key event intercepted by IM")); - return TRUE; - } - } +static gboolean +gtk_window_key_press_after_callback( GtkWidget *WXUNUSED(widget), + GdkEventKey *gdk_event, + wxWindow *win ) +{ + if (g_blockEventsOnDrag) + return FALSE; - if (return_after_IM) + if (win->m_return_after_IM) return FALSE; // 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) + KeySym keysym = gdk_event->keyval; + // Find key code for EVT_CHAR and EVT_CHAR_HOOK events + long key_code = wxTranslateKeySymToWXKey(keysym, true /* isChar */); + if ( !key_code ) { - KeySym keysym = gdk_event->keyval; - // Find key code for EVT_CHAR and EVT_CHAR_HOOK events - long key_code = wxTranslateKeySymToWXKey(keysym, true /* isChar */); - if ( !key_code ) + if ( wxIsAsciiKeysym(keysym) ) { - 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]; - } + // ASCII key + key_code = (unsigned char)keysym; } - - if ( key_code ) + // gdk_event->string is actually deprecated + else if ( gdk_event->length == 1 ) { - wxKeyEvent eventChar(wxEVT_CHAR, event); - - wxLogTrace(TRACE_KEYS, wxT("Char event: %ld"), key_code); - - eventChar.m_keyCode = key_code; -#if wxUSE_UNICODE - eventChar.m_uniChar = gdk_keyval_to_unicode(key_code); -#endif // wxUSE_UNICODE - - AdjustCharEventKeyCodes(eventChar); - - ret = win->HandleWindowEvent(eventChar); + key_code = (unsigned char)gdk_event->string[0]; } } - return ret; -} -} - -int wxWindowGTK::GTKIMFilterKeypress(GdkEventKey* event) const -{ - return m_imContext ? gtk_im_context_filter_keypress(m_imContext, event) - : FALSE; -} - -extern "C" { -static void -gtk_wxwindow_commit_cb (GtkIMContext * WXUNUSED(context), - const gchar *str, - wxWindow *window) -{ - // Ignore the return value here, it doesn't matter for the "commit" signal. - window->GTKDoInsertTextFromIM(str); -} -} - -bool wxWindowGTK::GTKDoInsertTextFromIM(const char* str) -{ - wxKeyEvent event( wxEVT_CHAR ); - - // take modifiers, cursor position, timestamp etc. from the last - // key_press_event that was fed into Input Method: - if ( m_imKeyEvent ) - { - wxFillOtherKeyEventFields(event, this, m_imKeyEvent); - } - else + if ( key_code ) { - event.SetEventObject(this); - } + wxKeyEvent eventChar(wxEVT_CHAR, win->m_event); - const wxString data(wxGTK_CONV_BACK_SYS(str)); - if( data.empty() ) - return false; + wxLogTrace(TRACE_KEYS, wxT("Char event: %ld"), key_code); - bool processed = false; - for( wxString::const_iterator pstr = data.begin(); pstr != data.end(); ++pstr ) - { + eventChar.m_keyCode = key_code; #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, wxT("IM sent character '%c'"), event.m_uniChar); -#else - event.m_keyCode = (char)*pstr; -#endif // wxUSE_UNICODE + eventChar.m_uniChar = gdk_keyval_to_unicode(key_code); +#endif // wxUSE_UNICODE - AdjustCharEventKeyCodes(event); + AdjustCharEventKeyCodes(eventChar); - if ( HandleWindowEvent(event) ) - processed = true; + return win->HandleWindowEvent(eventChar); } - return processed; + return FALSE; } - -bool wxWindowGTK::GTKOnInsertText(const char* text) -{ - if ( !m_imKeyEvent ) - { - // We're not inside IM key handling at all. - return false; - } - - return GTKDoInsertTextFromIM(text); } - //----------------------------------------------------------------------------- // "key_release_event" from any window //----------------------------------------------------------------------------- @@ -2340,22 +2259,6 @@ void wxWindowGTK::GTKHandleRealized() { GdkWindow* const window = GTKGetDrawingWindow(); - if (m_wxwindow) - { - if (m_imContext == NULL) - { - // Create input method handler - m_imContext = gtk_im_multicontext_new(); - - // Cannot handle drawing preedited text yet - gtk_im_context_set_use_preedit(m_imContext, false); - - g_signal_connect(m_imContext, - "commit", G_CALLBACK(gtk_wxwindow_commit_cb), this); - } - gtk_im_context_set_client_window(m_imContext, window); - } - // Use composited window if background is transparent, if supported. if (m_backgroundStyle == wxBG_STYLE_TRANSPARENT) { @@ -2406,12 +2309,6 @@ void wxWindowGTK::GTKHandleRealized() void wxWindowGTK::GTKHandleUnrealize() { m_isGtkPositionValid = false; - - if (m_wxwindow) - { - if (m_imContext) - gtk_im_context_set_client_window(m_imContext, NULL); - } } // ---------------------------------------------------------------------------- @@ -2562,9 +2459,6 @@ void wxWindowGTK::Init() m_clipPaintRegion = false; - m_imContext = NULL; - m_imKeyEvent = NULL; - m_dirtyTabOrder = false; } @@ -2748,13 +2642,6 @@ wxWindowGTK::~wxWindowGTK() // destroy children before destroying this window itself DestroyChildren(); - // delete before the widgets to avoid a crash on solaris - if ( m_imContext ) - { - g_object_unref(m_imContext); - m_imContext = NULL; - } - #ifdef __WXGTK3__ if (m_styleProvider) g_object_unref(m_styleProvider); @@ -3669,7 +3556,9 @@ void wxWindowGTK::ConnectWidget( GtkWidget *widget ) } g_signal_connect (widget, "key_press_event", - G_CALLBACK (gtk_window_key_press_callback), this); + G_CALLBACK (gtk_window_key_press_before_callback), this); + g_signal_connect_after (widget, "key_press_event", + G_CALLBACK (gtk_window_key_press_after_callback), this); g_signal_connect (widget, "key_release_event", G_CALLBACK (gtk_window_key_release_callback), this); g_signal_connect (widget, "button_press_event", @@ -4400,9 +4289,6 @@ bool wxWindowGTK::GTKHandleFocusIn() "handling focus_in event for %s", wxDumpWindow(this)); - if (m_imContext) - gtk_im_context_focus_in(m_imContext); - gs_currentFocus = this; if ( gs_pendingFocus ) @@ -4483,9 +4369,6 @@ void wxWindowGTK::GTKHandleFocusOutNoDeferring() gs_lastFocus = this; - if (m_imContext) - gtk_im_context_focus_out(m_imContext); - if ( gs_currentFocus != this ) { // Something is terribly wrong, gs_currentFocus is out of sync with the