diff options
author | deanm@chromium.org <deanm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-12 11:15:14 +0000 |
---|---|---|
committer | deanm@chromium.org <deanm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-12 11:15:14 +0000 |
commit | 4d79d76ed8e6a450fe5fdb5d7e2c539dbe5c6462 (patch) | |
tree | df05674ae732d585d50ecada394e9e9c2bf0d0a3 /chrome | |
parent | 739c52198933941ad2602533d7dc271a2854b600 (diff) | |
download | chromium_src-4d79d76ed8e6a450fe5fdb5d7e2c539dbe5c6462.zip chromium_src-4d79d76ed8e6a450fe5fdb5d7e2c539dbe5c6462.tar.gz chromium_src-4d79d76ed8e6a450fe5fdb5d7e2c539dbe5c6462.tar.bz2 |
Better keyboard and mouse handling in Omnibox:
- Grab enter key events before they get to GtkTextView.
We need to do this, otherwise enter when text is selected
will replace the text, and we won't get a chance to catch
that happening. This might have problems with IME, but it
should be straightforward to fix anything IME related.
- Don't deselect when we lose focus. This sometimes looks a
bit strange, but it's the GTK thing to do. This also unbreaks
copy and paste via the context menu, since popping up the
context menu makes the GtkTextView lose focus.
- Rewrite the inefficent newline eater. This should now only be
needed for newlines that didn't come from the keyboard (like when
you paste text). Use the builtin iter support for finding line
boundaries, hopefully more efficient than checking the characters
one by one. Still might have some bad behavior when pasting a ton
of newline characters, but that can be improved later.
This fixes inline autocomplete, you can now hit the enter key on an
inline autocompleted suggestion, and you will get the intented navigation,
instead of the navigation with the selected completion removed.
This also adds support for alt-enter in Omnibox to navigate in a new tab.
BUG=8236
Review URL: http://codereview.chromium.org/43072
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@11527 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc | 81 | ||||
-rw-r--r-- | chrome/browser/autocomplete/autocomplete_edit_view_gtk.h | 16 |
2 files changed, 64 insertions, 33 deletions
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc index acbeb26..b7d2552 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc +++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc @@ -5,6 +5,7 @@ #include "chrome/browser/autocomplete/autocomplete_edit_view_gtk.h" #include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> #include "base/gfx/gtk_util.h" #include "base/logging.h" @@ -87,6 +88,11 @@ void AutocompleteEditViewGtk::Init() { G_CALLBACK(&HandleBeginUserActionThunk), this); g_signal_connect(text_buffer_, "end-user-action", G_CALLBACK(&HandleEndUserActionThunk), this); + // We connect to key press and release for special handling of the enter key. + g_signal_connect(text_view_, "key-press-event", + G_CALLBACK(&HandleKeyPressThunk), this); + g_signal_connect(text_view_, "key-release-event", + G_CALLBACK(&HandleKeyReleaseThunk), this); g_signal_connect(text_view_, "size-request", G_CALLBACK(&HandleViewSizeRequest), this); g_signal_connect(text_view_, "button-press-event", @@ -294,36 +300,54 @@ void AutocompleteEditViewGtk::HandleBeginUserAction() { } void AutocompleteEditViewGtk::HandleEndUserAction() { - bool had_newline = false; - - // TODO(deanm): obviously super inefficient. - for(;;) { - GtkTextIter cur, end; - gtk_text_buffer_get_bounds(text_buffer_, &cur, &end); - - while (!gtk_text_iter_equal(&cur, &end)) { - if (gtk_text_iter_ends_line(&cur)) { - had_newline = true; - GtkTextIter next = cur; - gtk_text_iter_forward_char(&next); - gtk_text_buffer_delete(text_buffer_, &cur, &next); - - // We've invalidated our iterators, gotta start again. - break; - } + // Eat any newline / paragraphs that might have come in, for example in a + // copy and paste. We want to make sure our widget stays single line. + for (;;) { + GtkTextIter cur; + gtk_text_buffer_get_start_iter(text_buffer_, &cur); + + // If there is a line ending, this should put us right before the newline + // or carriage return / newline (or Unicode) sequence. If not, we're done. + if (gtk_text_iter_forward_to_line_end(&cur) == FALSE) + break; - gtk_text_iter_forward_char(&cur); - } + // Stepping to the next cursor position should put us on the other side of + // the newline / paragraph / etc sequence, and then delete this range. + GtkTextIter next_line = cur; + gtk_text_iter_forward_cursor_position(&next_line); + gtk_text_buffer_delete(text_buffer_, &cur, &next_line); - // We've exhausted the whole input and there is now only 1 line, good. - if (gtk_text_iter_equal(&cur, &end)) - break; + // We've invalidated our iterators, gotta start again. } OnAfterPossibleChange(); +} + +gboolean AutocompleteEditViewGtk::HandleKeyPress(GtkWidget* widget, + GdkEventKey* event) { + // This is very similar to the special casing of the return key in the + // GtkTextView key_press default handler. TODO(deanm): We do however omit + // some IME related code, this might become a problem if an IME wants to + // handle enter. We can get at the im_context and do it ourselves if needed. + if (event->keyval == GDK_Return || + event->keyval == GDK_ISO_Enter || + event->keyval == GDK_KP_Enter) { + bool alt_held = (event->state & GDK_MOD1_MASK); + model_->AcceptInput(alt_held ? NEW_FOREGROUND_TAB : CURRENT_TAB, false); + return TRUE; // Don't propagate into GtkTextView. + } + return FALSE; // Propagate into GtkTextView. +} - if (had_newline) - model_->AcceptInput(CURRENT_TAB, false); +gboolean AutocompleteEditViewGtk::HandleKeyRelease(GtkWidget* widget, + GdkEventKey* event) { + // We ate the press, might as well eat the release. + if (event->keyval == GDK_Return || + event->keyval == GDK_ISO_Enter || + event->keyval == GDK_KP_Enter) { + return TRUE; // Don't propagate into GtkTextView. + } + return FALSE; // Propagate into GtkTextView. } // static @@ -375,17 +399,8 @@ gboolean AutocompleteEditViewGtk::HandleViewFocusIn() { gboolean AutocompleteEditViewGtk::HandleViewFocusOut() { // Close the popup. ClosePopup(); - // Tell the model to reset itself. model_->OnKillFocus(); - - // TODO(deanm): This probably isn't right, and doesn't match Windows. We - // don't really want to match Windows though, because it probably feels - // wrong on Linux. Firefox doesn't have great behavior here also, imo. - // Deselect any selection and make sure the input is at the beginning. - GtkTextIter start, end; - gtk_text_buffer_get_bounds(text_buffer_, &start, &end); - gtk_text_buffer_place_cursor(text_buffer_, &start); return FALSE; // Pass the event on to the GtkTextView. } diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h index f3f1d9f..6f14da9 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h @@ -109,6 +109,22 @@ class AutocompleteEditViewGtk : public AutocompleteEditView { } void HandleEndUserAction(); + static gboolean HandleKeyPressThunk(GtkWidget* widget, + GdkEventKey* event, + gpointer self) { + return reinterpret_cast<AutocompleteEditViewGtk*>(self)->HandleKeyPress( + widget, event); + } + gboolean HandleKeyPress(GtkWidget* widget, GdkEventKey* event); + + static gboolean HandleKeyReleaseThunk(GtkWidget* widget, + GdkEventKey* event, + gpointer self) { + return reinterpret_cast<AutocompleteEditViewGtk*>(self)->HandleKeyRelease( + widget, event); + } + gboolean HandleKeyRelease(GtkWidget* widget, GdkEventKey* event); + static void HandleViewSizeRequest(GtkWidget* view, GtkRequisition* req, gpointer unused); |