summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsamarth@chromium.org <samarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-12 04:18:16 +0000
committersamarth@chromium.org <samarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-12 04:18:16 +0000
commit6a6811ae25d84530cfdcb5b73cffddb8f4497a04 (patch)
tree59baed7c1d2ef0066872b5ec109991d220f97ba6
parentb358c951e427a6c5a6e14a8c84440f8631cae40a (diff)
downloadchromium_src-6a6811ae25d84530cfdcb5b73cffddb8f4497a04.zip
chromium_src-6a6811ae25d84530cfdcb5b73cffddb8f4497a04.tar.gz
chromium_src-6a6811ae25d84530cfdcb5b73cffddb8f4497a04.tar.bz2
Instant API: tell page whether the browser is capturing key strokes.
TESTED=manual, per bug BUG=164782 Review URL: https://chromiumcodereview.appspot.com/11413217 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@172524 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/instant/instant_browsertest.cc18
-rw-r--r--chrome/browser/instant/instant_client.cc5
-rw-r--r--chrome/browser/instant/instant_client.h3
-rw-r--r--chrome/browser/instant/instant_controller.cc103
-rw-r--r--chrome/browser/instant/instant_controller.h20
-rw-r--r--chrome/browser/instant/instant_loader.cc4
-rw-r--r--chrome/browser/instant/instant_loader.h1
-rw-r--r--chrome/browser/ui/omnibox/omnibox_edit_model.cc72
-rw-r--r--chrome/browser/ui/omnibox/omnibox_edit_model.h63
-rw-r--r--chrome/browser/ui/views/omnibox/omnibox_view_views.cc26
-rw-r--r--chrome/browser/ui/views/omnibox/omnibox_view_win.cc19
-rw-r--r--chrome/common/render_messages.h3
-rw-r--r--chrome/renderer/resources/extensions/searchbox_api.js3
-rw-r--r--chrome/renderer/searchbox/searchbox.cc14
-rw-r--r--chrome/renderer/searchbox/searchbox.h3
-rw-r--r--chrome/renderer/searchbox/searchbox_extension.cc29
-rw-r--r--chrome/renderer/searchbox/searchbox_extension.h1
17 files changed, 275 insertions, 112 deletions
diff --git a/chrome/browser/instant/instant_browsertest.cc b/chrome/browser/instant/instant_browsertest.cc
index e97b25f..797688c 100644
--- a/chrome/browser/instant/instant_browsertest.cc
+++ b/chrome/browser/instant/instant_browsertest.cc
@@ -102,10 +102,13 @@ class InstantTest : public InProcessBrowserTest {
void FocusOmnibox() {
// If the omnibox already has focus, just notify Instant.
- if (omnibox()->model()->has_focus())
- instant()->OmniboxGotFocus();
- else
+ if (omnibox()->model()->has_focus()) {
+ instant()->OmniboxFocusChanged(OMNIBOX_FOCUS_VISIBLE,
+ OMNIBOX_FOCUS_CHANGE_EXPLICIT, NULL);
+ }
+ else {
browser()->window()->GetLocationBar()->FocusLocation(false);
+ }
}
void FocusOmniboxAndWaitForInstantSupport() {
@@ -678,7 +681,8 @@ IN_PROC_BROWSER_TEST_F(InstantTest, DoesNotCommitURLsTwo) {
// Pretend the omnibox got focus. It already had focus, so we are just trying
// to tickle a different code path.
- instant()->OmniboxGotFocus();
+ instant()->OmniboxFocusChanged(OMNIBOX_FOCUS_VISIBLE,
+ OMNIBOX_FOCUS_CHANGE_EXPLICIT, NULL);
// Commit the URL. As before, check that Instant wasn't committed.
browser()->window()->GetLocationBar()->AcceptInput();
@@ -897,7 +901,8 @@ IN_PROC_BROWSER_TEST_F(InstantTest, InstantLoaderRefresh) {
EXPECT_TRUE(instant()->loader_->supports_instant());
instant()->HideLoader();
EXPECT_TRUE(instant()->loader_->supports_instant());
- instant()->OmniboxLostFocus(NULL);
+ instant()->OmniboxFocusChanged(OMNIBOX_FOCUS_NONE,
+ OMNIBOX_FOCUS_CHANGE_EXPLICIT, NULL);
EXPECT_FALSE(instant()->loader_->supports_instant());
// Try with a different ordering.
@@ -905,7 +910,8 @@ IN_PROC_BROWSER_TEST_F(InstantTest, InstantLoaderRefresh) {
instant()->stale_loader_timer_.Stop();
instant()->OnStaleLoader();
EXPECT_TRUE(instant()->loader_->supports_instant());
- instant()->OmniboxLostFocus(NULL);
+ instant()->OmniboxFocusChanged(OMNIBOX_FOCUS_NONE,
+ OMNIBOX_FOCUS_CHANGE_EXPLICIT, NULL);
// TODO(sreeram): Currently, OmniboxLostFocus() calls HideLoader(). When it
// stops hiding the preview eventually, uncomment these two lines:
// EXPECT_TRUE(instant()->loader_->supports_instant());
diff --git a/chrome/browser/instant/instant_client.cc b/chrome/browser/instant/instant_client.cc
index 50d7852..6f23d9a 100644
--- a/chrome/browser/instant/instant_client.cc
+++ b/chrome/browser/instant/instant_client.cc
@@ -71,6 +71,11 @@ void InstantClient::SetDisplayInstantResults(bool display_instant_results) {
display_instant_results));
}
+void InstantClient::KeyCaptureChanged(bool is_key_capture_enabled) {
+ Send(new ChromeViewMsg_SearchBoxKeyCaptureChanged(routing_id(),
+ is_key_capture_enabled));
+}
+
void InstantClient::DidFinishLoad(
int64 /* frame_id */,
const GURL& /* validated_url */,
diff --git a/chrome/browser/instant/instant_client.h b/chrome/browser/instant/instant_client.h
index 821c36c..486ae8d 100644
--- a/chrome/browser/instant/instant_client.h
+++ b/chrome/browser/instant/instant_client.h
@@ -121,6 +121,9 @@ class InstantClient : public content::WebContentsObserver {
// Tells the page whether it is allowed to display Instant results.
void SetDisplayInstantResults(bool display_instant_results);
+ // Tells the page whether the browser is capturing user key strokes.
+ void KeyCaptureChanged(bool is_key_capture_enabled);
+
private:
// Overridden from content::WebContentsObserver:
virtual void DidFinishLoad(
diff --git a/chrome/browser/instant/instant_controller.cc b/chrome/browser/instant/instant_controller.cc
index d3e6545..9f40c85 100644
--- a/chrome/browser/instant/instant_controller.cc
+++ b/chrome/browser/instant/instant_controller.cc
@@ -156,7 +156,7 @@ InstantController::InstantController(chrome::BrowserInstantController* browser,
last_verbatim_(false),
last_transition_type_(content::PAGE_TRANSITION_LINK),
last_match_was_search_(false),
- is_omnibox_focused_(false),
+ omnibox_focus_state_(OMNIBOX_FOCUS_NONE),
allow_preview_to_show_search_suggestions_(false) {
}
@@ -547,50 +547,37 @@ bool InstantController::CommitIfPossible(InstantCommitType type) {
return true;
}
-void InstantController::OmniboxLostFocus(gfx::NativeView view_gaining_focus) {
- DVLOG(1) << "OmniboxLostFocus";
- is_omnibox_focused_ = false;
-
- if (!extended_enabled_ && !instant_enabled_)
- return;
-
- // If the preview is showing custom NTP content, don't hide it, commit it
- // (no matter where the user clicked) or try to recreate it.
- if (model_.mode().is_ntp())
- return;
-
- // If the preview is not showing at all, recreate it if it's stale.
- if (model_.mode().is_default()) {
- OnStaleLoader();
- return;
- }
-
- // The preview is showing search suggestions. If GetPreviewContents() is NULL,
- // we are in the commit path. Don't do anything.
- if (!GetPreviewContents())
- return;
-
-#if defined(OS_MACOSX)
- // TODO(sreeram): See if Mac really needs this special treatment.
- if (!loader_->is_pointer_down_from_activate())
- HideLoader();
-#else
- if (IsViewInContents(GetViewGainingFocus(view_gaining_focus),
- loader_->contents()))
- CommitIfPossible(INSTANT_COMMIT_FOCUS_LOST);
- else
- HideLoader();
-#endif
-}
-
-void InstantController::OmniboxGotFocus() {
- DVLOG(1) << "OmniboxGotFocus";
- is_omnibox_focused_ = true;
+void InstantController::OmniboxFocusChanged(
+ OmniboxFocusState state,
+ OmniboxFocusChangeReason reason,
+ gfx::NativeView view_gaining_focus) {
+ DVLOG(1) << "OmniboxFocusChanged: " << omnibox_focus_state_ << " to "
+ << state << " for reason " << reason;
+ OmniboxFocusState old_focus_state = omnibox_focus_state_;
+ omnibox_focus_state_ = state;
if (!extended_enabled_ && !instant_enabled_)
return;
- CreateDefaultLoader();
+ // Tell the page if the key capture mode changed unless the focus state
+ // changed because of TYPING. This is because in that case, the browser hasn't
+ // really stopped capturing key strokes.
+ //
+ // (More practically, if we don't do this check, the page would receive
+ // onkeycapturechange before the corresponding onchange, and the page would
+ // have no way of telling whether the keycapturechange happened because of
+ // some actual user action or just because they started typing.)
+ if (extended_enabled_ && GetPreviewContents() &&
+ reason != OMNIBOX_FOCUS_CHANGE_TYPING)
+ loader_->KeyCaptureChanged(omnibox_focus_state_ == OMNIBOX_FOCUS_INVISIBLE);
+
+ // If focus went from outside the omnibox to the omnibox, preload the default
+ // search engine, in anticipation of the user typing a query. If the reverse
+ // happened, commit or discard the preview.
+ if (state != OMNIBOX_FOCUS_NONE && old_focus_state == OMNIBOX_FOCUS_NONE)
+ CreateDefaultLoader();
+ else if (state == OMNIBOX_FOCUS_NONE && old_focus_state != OMNIBOX_FOCUS_NONE)
+ OmniboxLostFocus(view_gaining_focus);
}
void InstantController::SearchModeChanged(
@@ -810,6 +797,36 @@ void InstantController::InstantLoaderAboutToNavigateMainFrame(const GURL& url) {
CommitIfPossible(INSTANT_COMMIT_NAVIGATED);
}
+void InstantController::OmniboxLostFocus(gfx::NativeView view_gaining_focus) {
+ // If the preview is showing custom NTP content, don't hide it, commit it
+ // (no matter where the user clicked) or try to recreate it.
+ if (model_.mode().is_ntp())
+ return;
+
+ // If the preview is not showing at all, recreate it if it's stale.
+ if (model_.mode().is_default()) {
+ OnStaleLoader();
+ return;
+ }
+
+ // The preview is showing search suggestions. If GetPreviewContents() is NULL,
+ // we are in the commit path. Don't do anything.
+ if (!GetPreviewContents())
+ return;
+
+#if defined(OS_MACOSX)
+ // TODO(sreeram): See if Mac really needs this special treatment.
+ if (!loader_->is_pointer_down_from_activate())
+ HideLoader();
+#else
+ if (IsViewInContents(GetViewGainingFocus(view_gaining_focus),
+ loader_->contents()))
+ CommitIfPossible(INSTANT_COMMIT_FOCUS_LOST);
+ else
+ HideLoader();
+#endif
+}
+
bool InstantController::ResetLoader(const TemplateURL* template_url,
const content::WebContents* active_tab) {
std::string instant_url;
@@ -828,6 +845,7 @@ bool InstantController::ResetLoader(const TemplateURL* template_url,
browser_->UpdateThemeInfoForPreview();
loader_->SetDisplayInstantResults(instant_enabled_);
loader_->SearchModeChanged(search_mode_);
+ loader_->KeyCaptureChanged(omnibox_focus_state_ == OMNIBOX_FOCUS_INVISIBLE);
}
// Restart the stale loader timer.
@@ -855,7 +873,8 @@ void InstantController::OnStaleLoader() {
// If the preview is showing or the omnibox has focus, don't delete the
// loader. It will get refreshed the next time the preview is hidden or the
// omnibox loses focus.
- if (!stale_loader_timer_.IsRunning() && !is_omnibox_focused_ &&
+ if (!stale_loader_timer_.IsRunning() &&
+ omnibox_focus_state_ == OMNIBOX_FOCUS_NONE &&
model_.mode().is_default()) {
loader_.reset();
CreateDefaultLoader();
diff --git a/chrome/browser/instant/instant_controller.h b/chrome/browser/instant/instant_controller.h
index 0f37e86..452e434 100644
--- a/chrome/browser/instant/instant_controller.h
+++ b/chrome/browser/instant/instant_controller.h
@@ -17,6 +17,7 @@
#include "base/timer.h"
#include "chrome/browser/instant/instant_commit_type.h"
#include "chrome/browser/instant/instant_model.h"
+#include "chrome/browser/ui/omnibox/omnibox_edit_model.h"
#include "chrome/common/instant_types.h"
#include "chrome/common/search_types.h"
#include "content/public/common/page_transition_types.h"
@@ -84,12 +85,12 @@ class InstantController {
// CommitInstant() on the browser, and returns true. Else, returns false.
bool CommitIfPossible(InstantCommitType type);
- // The omnibox has lost focus. Commit or discard the preview accordingly.
- void OmniboxLostFocus(gfx::NativeView view_gaining_focus);
-
- // The omnibox has gained focus. Preload the default search engine, in
- // anticipation of the user typing a query.
- void OmniboxGotFocus();
+ // Called to indicate that the omnibox focus state changed with the given
+ // |reason|. If |focus_state| is FOCUS_NONE, |view_gaining_focus| is set to
+ // the view gaining focus.
+ void OmniboxFocusChanged(OmniboxFocusState focus_state,
+ OmniboxFocusChangeReason reason,
+ gfx::NativeView view_gaining_focus);
// The search mode in the active tab has changed. Pass the message down to
// the loader which will notify the renderer. Create |instant_tab_| if the
@@ -153,6 +154,9 @@ class InstantController {
FRIEND_TEST_ALL_PREFIXES(InstantTest, NonInstantSearchProvider);
FRIEND_TEST_ALL_PREFIXES(InstantTest, InstantLoaderRefresh);
+ // Helper for OmniboxFocusChanged. Commit or discard the preview.
+ void OmniboxLostFocus(gfx::NativeView view_gaining_focus);
+
// Creates a new loader if necessary, using the instant_url property of the
// |template_url| (for example, if the Instant URL has changed since the last
// time the loader was created). Returns false if the |template_url| doesn't
@@ -243,8 +247,8 @@ class InstantController {
// Used to ensure that the preview page is committable.
bool last_match_was_search_;
- // True if the omnibox is focused, false otherwise.
- bool is_omnibox_focused_;
+ // Omnibox focus state.
+ OmniboxFocusState omnibox_focus_state_;
// The search model mode for the active tab.
chrome::search::Mode search_mode_;
diff --git a/chrome/browser/instant/instant_loader.cc b/chrome/browser/instant/instant_loader.cc
index 7561ffd..06e61d0 100644
--- a/chrome/browser/instant/instant_loader.cc
+++ b/chrome/browser/instant/instant_loader.cc
@@ -274,6 +274,10 @@ void InstantLoader::SetDisplayInstantResults(bool display_instant_results) {
client_.SetDisplayInstantResults(display_instant_results);
}
+void InstantLoader::KeyCaptureChanged(bool is_key_capture_enabled) {
+ client_.KeyCaptureChanged(is_key_capture_enabled);
+}
+
void InstantLoader::SetSuggestions(
const std::vector<InstantSuggestion>& suggestions) {
InstantSupportDetermined(true);
diff --git a/chrome/browser/instant/instant_loader.h b/chrome/browser/instant/instant_loader.h
index 25257c7..23b6f06 100644
--- a/chrome/browser/instant/instant_loader.h
+++ b/chrome/browser/instant/instant_loader.h
@@ -101,6 +101,7 @@ class InstantLoader : public InstantClient::Delegate,
void SendThemeBackgroundInfo(const ThemeBackgroundInfo& theme_info);
void SendThemeAreaHeight(int height);
void SetDisplayInstantResults(bool display_instant_results);
+ void KeyCaptureChanged(bool is_key_capture_enabled);
private:
class WebContentsDelegateImpl;
diff --git a/chrome/browser/ui/omnibox/omnibox_edit_model.cc b/chrome/browser/ui/omnibox/omnibox_edit_model.cc
index d27e9b1..698fba6 100644
--- a/chrome/browser/ui/omnibox/omnibox_edit_model.cc
+++ b/chrome/browser/ui/omnibox/omnibox_edit_model.cc
@@ -71,12 +71,12 @@ OmniboxEditModel::State::State(bool user_input_in_progress,
const string16& user_text,
const string16& keyword,
bool is_keyword_hint,
- bool is_caret_visible)
+ OmniboxFocusState focus_state)
: user_input_in_progress(user_input_in_progress),
user_text(user_text),
keyword(keyword),
is_keyword_hint(is_keyword_hint),
- is_caret_visible(is_caret_visible) {
+ focus_state(focus_state) {
}
OmniboxEditModel::State::~State() {
@@ -91,8 +91,7 @@ OmniboxEditModel::OmniboxEditModel(OmniboxView* view,
: view_(view),
popup_(NULL),
controller_(controller),
- has_focus_(false),
- is_caret_visible_(true),
+ focus_state_(OMNIBOX_FOCUS_NONE),
user_input_in_progress_(false),
just_deleted_text_(false),
has_temporary_text_(false),
@@ -132,11 +131,11 @@ const OmniboxEditModel::State OmniboxEditModel::GetStateForTabSwitch() {
}
return State(user_input_in_progress_, user_text_, keyword_, is_keyword_hint_,
- is_caret_visible_);
+ focus_state_);
}
void OmniboxEditModel::RestoreState(const State& state) {
- SetCaretVisibility(state.is_caret_visible);
+ SetFocusState(state.focus_state, OMNIBOX_FOCUS_CHANGE_TAB_SWITCH);
// Restore any user editing.
if (state.user_input_in_progress) {
// NOTE: Be sure and set keyword-related state BEFORE invoking
@@ -161,7 +160,7 @@ bool OmniboxEditModel::UpdatePermanentText(const string16& new_permanent_text) {
// an edit and then abandoned it and clicked a link on the page.)
const bool visibly_changed_permanent_text =
(permanent_text_ != new_permanent_text) &&
- (!user_input_in_progress_ || !has_focus_);
+ (!user_input_in_progress_ || !has_focus());
permanent_text_ = new_permanent_text;
return visibly_changed_permanent_text;
@@ -440,7 +439,7 @@ void OmniboxEditModel::Revert() {
has_temporary_text_ = false;
is_temporary_text_set_by_instant_ = false;
view_->SetWindowTextAndCaretPos(permanent_text_,
- has_focus_ ? permanent_text_.length() : 0,
+ has_focus() ? permanent_text_.length() : 0,
false, true);
AutocompleteActionPredictor* action_predictor =
AutocompleteActionPredictorFactory::GetForProfile(profile_);
@@ -716,13 +715,12 @@ const AutocompleteResult& OmniboxEditModel::result() const {
}
void OmniboxEditModel::OnSetFocus(bool control_down) {
- has_focus_ = true;
+ // If the omnibox lost focus while the caret was hidden and then regained
+ // focus, OnSetFocus() is called and should restore visibility. Note that
+ // focus can be regained without an accompanying call to
+ // OmniboxView::SetFocus(), e.g. by tabbing in.
+ SetFocusState(OMNIBOX_FOCUS_VISIBLE, OMNIBOX_FOCUS_CHANGE_EXPLICIT);
control_key_state_ = control_down ? DOWN_WITHOUT_CHANGE : UP;
- // Restore caret visibility whenever the user focuses back into the omnibox.
- SetCaretVisibility(true);
-
- if (InstantController* instant = controller_->GetInstant())
- instant->OmniboxGotFocus();
content::WebContents* web_contents = controller_->GetWebContents();
if (web_contents) {
@@ -739,17 +737,22 @@ void OmniboxEditModel::OnSetFocus(bool control_down) {
}
void OmniboxEditModel::SetCaretVisibility(bool visible) {
- if (has_focus_ && visible != is_caret_visible_) {
- is_caret_visible_ = visible;
- view_->ApplyCaretVisibility();
+ // Caret visibility only matters if the omnibox has focus.
+ if (focus_state_ != OMNIBOX_FOCUS_NONE) {
+ SetFocusState(visible ? OMNIBOX_FOCUS_VISIBLE : OMNIBOX_FOCUS_INVISIBLE,
+ OMNIBOX_FOCUS_CHANGE_EXPLICIT);
}
}
void OmniboxEditModel::OnWillKillFocus(gfx::NativeView view_gaining_focus) {
SetInstantSuggestion(InstantSuggestion());
- if (InstantController* instant = controller_->GetInstant())
- instant->OmniboxLostFocus(view_gaining_focus);
+ InstantController* instant = controller_->GetInstant();
+ if (instant) {
+ instant->OmniboxFocusChanged(OMNIBOX_FOCUS_NONE,
+ OMNIBOX_FOCUS_CHANGE_EXPLICIT,
+ view_gaining_focus);
+ }
// TODO(jered): Rip this out along with StartZeroSuggest.
autocomplete_controller_->StopZeroSuggest();
@@ -757,7 +760,10 @@ void OmniboxEditModel::OnWillKillFocus(gfx::NativeView view_gaining_focus) {
}
void OmniboxEditModel::OnKillFocus() {
- has_focus_ = false;
+ // TODO(samarth): determine if it is safe to move the call to
+ // OmniboxFocusChanged() from OnWillKillFocus() to here, which would let us
+ // just call SetFocusState() to handle the state change.
+ focus_state_ = OMNIBOX_FOCUS_NONE;
control_key_state_ = UP;
paste_state_ = NONE;
}
@@ -955,7 +961,7 @@ bool OmniboxEditModel::OnAfterPossibleChange(const string16& old_text,
// Restore caret visibility whenever the user changes text or selection in the
// omnibox.
if (text_differs || selection_differs)
- SetCaretVisibility(true);
+ SetFocusState(OMNIBOX_FOCUS_VISIBLE, OMNIBOX_FOCUS_CHANGE_TYPING);
// Modifying the selection counts as accepting the autocompleted text.
const bool user_text_changed =
@@ -1017,7 +1023,8 @@ bool OmniboxEditModel::OnAfterPossibleChange(const string16& old_text,
}
void OmniboxEditModel::PopupBoundsChangedTo(const gfx::Rect& bounds) {
- if (InstantController* instant = controller_->GetInstant())
+ InstantController* instant = controller_->GetInstant();
+ if (instant)
instant->SetOmniboxBounds(bounds);
}
@@ -1066,7 +1073,8 @@ void OmniboxEditModel::OnResultChanged(bool default_match_changed) {
NotifySearchTabHelper();
}
- if (InstantController* instant = controller_->GetInstant())
+ InstantController* instant = controller_->GetInstant();
+ if (instant)
instant->HandleAutocompleteResults(*autocomplete_controller_->providers());
}
@@ -1291,3 +1299,21 @@ void OmniboxEditModel::ClassifyStringForPasteAndGo(
AutocompleteClassifierFactory::GetForProfile(profile_)->Classify(text,
string16(), false, false, match, alternate_nav_url);
}
+
+void OmniboxEditModel::SetFocusState(OmniboxFocusState state,
+ OmniboxFocusChangeReason reason) {
+ if (state == focus_state_)
+ return;
+
+ InstantController* instant = controller_->GetInstant();
+ if (instant)
+ instant->OmniboxFocusChanged(state, reason, NULL);
+
+ // Update state and notify view if the omnibox has focus and the caret
+ // visibility changed.
+ const bool was_caret_visible = is_caret_visible();
+ focus_state_ = state;
+ if (focus_state_ != OMNIBOX_FOCUS_NONE &&
+ is_caret_visible() != was_caret_visible)
+ view_->ApplyCaretVisibility();
+}
diff --git a/chrome/browser/ui/omnibox/omnibox_edit_model.h b/chrome/browser/ui/omnibox/omnibox_edit_model.h
index f8444f6..06f47a2 100644
--- a/chrome/browser/ui/omnibox/omnibox_edit_model.h
+++ b/chrome/browser/ui/omnibox/omnibox_edit_model.h
@@ -31,6 +31,33 @@ class Image;
class Rect;
}
+// Omnibox focus state.
+enum OmniboxFocusState {
+ // Not focused.
+ OMNIBOX_FOCUS_NONE,
+
+ // Visibly focused.
+ OMNIBOX_FOCUS_VISIBLE,
+
+ // Invisibly focused, i.e. focused with a hidden caret.
+ OMNIBOX_FOCUS_INVISIBLE,
+};
+
+// Reasons why the Omnibox focus state could change.
+enum OmniboxFocusChangeReason {
+ // Includes any explicit changes to focus. (e.g. user clicking to change
+ // focus, user tabbing to change focus, any explicit calls to SetFocus,
+ // etc.)
+ OMNIBOX_FOCUS_CHANGE_EXPLICIT,
+
+ // Focus changed to restore state from a tab the user switched to.
+ OMNIBOX_FOCUS_CHANGE_TAB_SWITCH,
+
+ // Focus changed because user started typing. This only happens when focus
+ // state is INVISIBLE (and this results in a change to VISIBLE).
+ OMNIBOX_FOCUS_CHANGE_TYPING,
+};
+
class OmniboxEditModel : public AutocompleteControllerDelegate {
public:
struct State {
@@ -38,14 +65,14 @@ class OmniboxEditModel : public AutocompleteControllerDelegate {
const string16& user_text,
const string16& keyword,
bool is_keyword_hint,
- bool is_caret_visible);
+ OmniboxFocusState focus_state);
~State();
bool user_input_in_progress;
const string16 user_text;
const string16 keyword;
const bool is_keyword_hint;
- const bool is_caret_visible;
+ OmniboxFocusState focus_state;
};
OmniboxEditModel(OmniboxView* view,
@@ -191,8 +218,11 @@ class OmniboxEditModel : public AutocompleteControllerDelegate {
const GURL& alternate_nav_url,
size_t index);
- bool has_focus() const { return has_focus_; }
- bool is_caret_visible() const { return is_caret_visible_; }
+ OmniboxFocusState focus_state() const { return focus_state_; }
+ bool has_focus() const { return focus_state_ != OMNIBOX_FOCUS_NONE; }
+ bool is_caret_visible() const {
+ return focus_state_ == OMNIBOX_FOCUS_VISIBLE;
+ }
// Accessors for keyword-related state (see comments on keyword_ and
// is_keyword_hint_).
@@ -217,12 +247,13 @@ class OmniboxEditModel : public AutocompleteControllerDelegate {
void OnSetFocus(bool control_down);
// Sets the visibility of the caret in the omnibox, if it has focus. The
- // visibility of the caret is reset to visible if any of the following
- // happens:
- // - User starts typing in the omnibox
- // - User clicks in the omnibox
- // - Omnibox loses and then regains focus
- // - SetFocus() is explicitly called again
+ // visibility of the caret is reset to visible if either
+ // - The user starts typing, or
+ // - We explicitly focus the omnibox again.
+ // The latter case must be handled in three separate places--OnSetFocus(),
+ // OmniboxView::SetFocus(), and the mouse handlers in OmniboxView. See
+ // accompanying comments for why each of these is necessary.
+ //
// Caret visibility is tracked per-tab and updates automatically upon
// switching tabs.
void SetCaretVisibility(bool visible);
@@ -407,6 +438,12 @@ class OmniboxEditModel : public AutocompleteControllerDelegate {
AutocompleteMatch* match,
GURL* alternate_nav_url) const;
+ // If focus_state_ does not match |state|, we update it and notify the
+ // InstantController about the change (passing along the |reason| for the
+ // change). If the caret visibility changes, we call ApplyCaretVisibility() on
+ // the view.
+ void SetFocusState(OmniboxFocusState state, OmniboxFocusChangeReason reason);
+
scoped_ptr<AutocompleteController> autocomplete_controller_;
OmniboxView* view_;
@@ -415,11 +452,7 @@ class OmniboxEditModel : public AutocompleteControllerDelegate {
OmniboxEditController* controller_;
- // Whether the edit has focus.
- bool has_focus_;
-
- // Is the caret visible? Only meaningful if has_focus_ is true.
- bool is_caret_visible_;
+ OmniboxFocusState focus_state_;
// The URL of the currently displayed page.
string16 permanent_text_;
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index fce7818..07b7c56 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -14,6 +14,7 @@
#include "chrome/browser/chromeos/input_method/input_method_configuration.h"
#include "chrome/browser/command_updater.h"
#include "chrome/browser/ui/omnibox/omnibox_edit_controller.h"
+#include "chrome/browser/ui/omnibox/omnibox_edit_model.h"
#include "chrome/browser/ui/omnibox/omnibox_popup_model.h"
#include "chrome/browser/ui/search/search.h"
#include "chrome/browser/ui/view_ids.h"
@@ -361,11 +362,14 @@ bool OmniboxViewViews::HandleKeyReleaseEvent(const ui::KeyEvent& event) {
void OmniboxViewViews::HandleMousePressEvent(const ui::MouseEvent& event) {
select_all_on_mouse_release_ =
(event.IsOnlyLeftMouseButton() || event.IsOnlyRightMouseButton()) &&
- !textfield_->HasFocus();
- // Restore caret visibility whenever the user clicks in the the omnibox. This
- // is not always covered by OnSetFocus() because when clicking while the
- // omnibox has invisible focus does not trigger a new OnSetFocus() call.
- model()->SetCaretVisibility(true);
+ (!textfield_->HasFocus() ||
+ (model()->focus_state() == OMNIBOX_FOCUS_INVISIBLE));
+ // Restore caret visibility whenever the user clicks in the omnibox in a way
+ // that would give it focus. We must handle this case separately here because
+ // if the omnibox currently has invisible focus, the mouse event won't trigger
+ // either SetFocus() or OmniboxEditModel::OnSetFocus().
+ if (select_all_on_mouse_release_)
+ model()->SetCaretVisibility(true);
}
void OmniboxViewViews::HandleMouseDragEvent(const ui::MouseEvent& event) {
@@ -572,14 +576,14 @@ void OmniboxViewViews::UpdatePopup() {
}
void OmniboxViewViews::SetFocus() {
- // Restore caret visibility if focused explicitly. We need to do this here
- // because if we already have invisible focus, the RequestFocus() call below
- // will short-circuit, preventing us from reaching
- // OmniboxEditModel::OnSetFocus(), which handles restoring visibility when we
- // didn't previously have focus.
- model()->SetCaretVisibility(true);
// In views-implementation, the focus is on textfield rather than OmniboxView.
textfield_->RequestFocus();
+ // Restore caret visibility if focus is explicitly requested. This is
+ // necessary because if we already have invisible focus, the RequestFocus()
+ // call above will short-circuit, preventing us from reaching
+ // OmniboxEditModel::OnSetFocus(), which handles restoring visibility when the
+ // omnibox regains focus after losing focus.
+ model()->SetCaretVisibility(true);
}
void OmniboxViewViews::ApplyCaretVisibility() {
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_win.cc b/chrome/browser/ui/views/omnibox/omnibox_view_win.cc
index 32dda4b..5059591 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_win.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_win.cc
@@ -33,6 +33,7 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/omnibox/omnibox_edit_controller.h"
+#include "chrome/browser/ui/omnibox/omnibox_edit_model.h"
#include "chrome/browser/ui/omnibox/omnibox_popup_model.h"
#include "chrome/browser/ui/search/search.h"
#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
@@ -761,10 +762,11 @@ void OmniboxViewWin::UpdatePopup() {
void OmniboxViewWin::SetFocus() {
::SetFocus(m_hWnd);
- // Restore caret visibility if focused explicitly. We need to do this here
- // because if we already have invisible focus, the ::SetFocus call above will
- // short-circuit, preventing us from reaching OmniboxEditModel::OnSetFocus(),
- // which handles restoring visibility when we didn't previously have focus.
+ // Restore caret visibility if focus is explicitly requested. This is
+ // necessary because if we already have invisible focus, the ::SetFocus()
+ // call above will short-circuit, preventing us from reaching
+ // OmniboxEditModel::OnSetFocus(), which handles restoring visibility when the
+ // omnibox regains focus after losing focus.
model()->SetCaretVisibility(true);
}
@@ -1772,7 +1774,8 @@ LRESULT OmniboxViewWin::OnMouseActivate(HWND window,
// reached before OnXButtonDown(), preventing us from detecting this properly
// there. Also in those cases, we need to already know in OnSetFocus() that
// we should not restore the saved selection.
- if ((!model()->has_focus() || !model()->is_caret_visible()) &&
+ if ((!model()->has_focus() ||
+ (model()->focus_state() == OMNIBOX_FOCUS_INVISIBLE)) &&
((mouse_message == WM_LBUTTONDOWN || mouse_message == WM_RBUTTONDOWN)) &&
(result == MA_ACTIVATE)) {
if (gaining_focus_) {
@@ -1783,8 +1786,10 @@ LRESULT OmniboxViewWin::OnMouseActivate(HWND window,
}
gaining_focus_.reset(new ScopedFreeze(this, GetTextObjectModel()));
- // Explicitely set focus visibility in the case of clicking on the omnibox,
- // which will remove invisible focus if present.
+ // Restore caret visibility whenever the user clicks in the omnibox in a
+ // way that would give it focus. We must handle this case separately here
+ // because if the omnibox currently has invisible focus, the mouse event
+ // won't trigger either SetFocus() or OmniboxEditModel::OnSetFocus().
model()->SetCaretVisibility(true);
// NOTE: Despite |mouse_message| being WM_XBUTTONDOWN here, we're not
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index f91f2bd..a27f376 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -329,6 +329,9 @@ IPC_MESSAGE_ROUTED1(ChromeViewMsg_SearchBoxThemeChanged,
IPC_MESSAGE_ROUTED1(ChromeViewMsg_SearchBoxThemeAreaHeightChanged,
int /* height */)
+IPC_MESSAGE_ROUTED1(ChromeViewMsg_SearchBoxKeyCaptureChanged,
+ bool /* is_key_capture_enabled */)
+
// Toggles visual muting of the render view area. This is on when a constrained
// window is showing.
IPC_MESSAGE_ROUTED1(ChromeViewMsg_SetVisuallyDeemphasized,
diff --git a/chrome/renderer/resources/extensions/searchbox_api.js b/chrome/renderer/resources/extensions/searchbox_api.js
index f4e6d2d8..1b32046 100644
--- a/chrome/renderer/resources/extensions/searchbox_api.js
+++ b/chrome/renderer/resources/extensions/searchbox_api.js
@@ -42,6 +42,7 @@ if (!chrome.searchBox) {
native function GetDisplayInstantResults();
native function GetThemeBackgroundInfo();
native function GetThemeAreaHeight();
+ native function IsKeyCaptureEnabled();
native function NavigateContentWindow();
native function SetSuggestions();
native function SetQuerySuggestion();
@@ -197,6 +198,7 @@ if (!chrome.searchBox) {
this.__defineGetter__('width', GetWidth);
this.__defineGetter__('height', GetHeight);
this.__defineGetter__('nativeSuggestions', GetAutocompleteResultsWrapper);
+ this.__defineGetter__('isKeyCaptureEnabled', IsKeyCaptureEnabled);
this.__defineGetter__('context', GetContext);
this.__defineGetter__('displayInstantResults', GetDisplayInstantResults);
this.__defineGetter__('themeBackgroundInfo', GetThemeBackgroundInfo);
@@ -237,6 +239,7 @@ if (!chrome.searchBox) {
this.onresize = null;
this.onautocompleteresults = null;
this.onkeypress = null;
+ this.onkeycapturechange = null;
this.oncontextchange = null;
};
}
diff --git a/chrome/renderer/searchbox/searchbox.cc b/chrome/renderer/searchbox/searchbox.cc
index e974186..cd52856 100644
--- a/chrome/renderer/searchbox/searchbox.cc
+++ b/chrome/renderer/searchbox/searchbox.cc
@@ -17,6 +17,7 @@ SearchBox::SearchBox(content::RenderView* render_view)
selection_end_(0),
results_base_(0),
last_results_base_(0),
+ is_key_capture_enabled_(false),
theme_area_height_(0),
display_instant_results_(false) {
}
@@ -114,6 +115,8 @@ bool SearchBox::OnMessageReceived(const IPC::Message& message) {
OnModeChanged)
IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxSetDisplayInstantResults,
OnSetDisplayInstantResults)
+ IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxKeyCaptureChanged,
+ OnKeyCaptureChange)
IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxThemeChanged,
OnThemeChanged)
IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxThemeAreaHeightChanged,
@@ -204,6 +207,16 @@ void SearchBox::OnUpOrDownKeyPressed(int count) {
}
}
+void SearchBox::OnKeyCaptureChange(bool is_key_capture_enabled) {
+ if (is_key_capture_enabled != is_key_capture_enabled_ &&
+ render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
+ is_key_capture_enabled_ = is_key_capture_enabled;
+ DVLOG(1) << render_view() << " OnKeyCaptureChange";
+ extensions_v8::SearchBoxExtension::DispatchKeyCaptureChange(
+ render_view()->GetWebView()->mainFrame());
+ }
+}
+
void SearchBox::OnModeChanged(const chrome::search::Mode& mode) {
mode_ = mode;
if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
@@ -241,6 +254,7 @@ void SearchBox::Reset() {
results_base_ = 0;
rect_ = gfx::Rect();
autocomplete_results_.clear();
+ is_key_capture_enabled_ = false;
mode_ = chrome::search::Mode();
theme_info_ = ThemeBackgroundInfo();
theme_area_height_ = 0;
diff --git a/chrome/renderer/searchbox/searchbox.h b/chrome/renderer/searchbox/searchbox.h
index cf3d01d..351316c 100644
--- a/chrome/renderer/searchbox/searchbox.h
+++ b/chrome/renderer/searchbox/searchbox.h
@@ -45,6 +45,7 @@ class SearchBox : public content::RenderViewObserver,
size_t selection_end() const { return selection_end_; }
int results_base() const { return results_base_; }
const chrome::search::Mode& mode() const { return mode_; }
+ bool is_key_capture_enabled() const { return is_key_capture_enabled_; }
bool display_instant_results() const { return display_instant_results_; }
gfx::Rect GetRect();
@@ -71,6 +72,7 @@ class SearchBox : public content::RenderViewObserver,
void OnAutocompleteResults(
const std::vector<InstantAutocompleteResult>& results);
void OnUpOrDownKeyPressed(int count);
+ void OnKeyCaptureChange(bool is_key_capture_enabled);
void OnModeChanged(const chrome::search::Mode& mode);
void OnSetDisplayInstantResults(bool display_instant_results);
void OnThemeChanged(const ThemeBackgroundInfo& theme_info);
@@ -88,6 +90,7 @@ class SearchBox : public content::RenderViewObserver,
std::vector<InstantAutocompleteResult> autocomplete_results_;
size_t last_results_base_;
std::vector<InstantAutocompleteResult> last_autocomplete_results_;
+ bool is_key_capture_enabled_;
chrome::search::Mode mode_;
ThemeBackgroundInfo theme_info_;
int theme_area_height_;
diff --git a/chrome/renderer/searchbox/searchbox_extension.cc b/chrome/renderer/searchbox/searchbox_extension.cc
index ba6fad7..7a6e1ad 100644
--- a/chrome/renderer/searchbox/searchbox_extension.cc
+++ b/chrome/renderer/searchbox/searchbox_extension.cc
@@ -141,6 +141,15 @@ static const char kDispatchUpOrDownKeyPressEventScript[] =
" true;"
"}";
+static const char kDispatchKeyCaptureChangeScript[] =
+ "if (window.chrome &&"
+ " window.chrome.searchBox &&"
+ " window.chrome.searchBox.onkeycapturechange &&"
+ " typeof window.chrome.searchBox.onkeycapturechange == 'function') {"
+ " window.chrome.searchBox.onkeycapturechange();"
+ " true;"
+ "}";
+
static const char kDispatchContextChangeEventScript[] =
"if (window.chrome &&"
" window.chrome.searchBox &&"
@@ -234,6 +243,9 @@ class SearchBoxExtensionWrapper : public v8::Extension {
// "top".
static v8::Handle<v8::Value> GetThemeAreaHeight(const v8::Arguments& args);
+ // Gets whether the browser is capturing key strokes.
+ static v8::Handle<v8::Value> IsKeyCaptureEnabled(const v8::Arguments& args);
+
// Navigates the window to a URL represented by either a URL string or a
// restricted ID.
static v8::Handle<v8::Value> NavigateContentWindow(const v8::Arguments& args);
@@ -303,6 +315,8 @@ v8::Handle<v8::FunctionTemplate> SearchBoxExtensionWrapper::GetNativeFunction(
return v8::FunctionTemplate::New(GetThemeBackgroundInfo);
if (name->Equals(v8::String::New("GetThemeAreaHeight")))
return v8::FunctionTemplate::New(GetThemeAreaHeight);
+ if (name->Equals(v8::String::New("IsKeyCaptureEnabled")))
+ return v8::FunctionTemplate::New(IsKeyCaptureEnabled);
if (name->Equals(v8::String::New("NavigateContentWindow")))
return v8::FunctionTemplate::New(NavigateContentWindow);
if (name->Equals(v8::String::New("SetSuggestions")))
@@ -445,6 +459,16 @@ v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetAutocompleteResults(
}
// static
+v8::Handle<v8::Value> SearchBoxExtensionWrapper::IsKeyCaptureEnabled(
+ const v8::Arguments& args) {
+ content::RenderView* render_view = GetRenderView();
+ if (!render_view) return v8::Undefined();
+
+ return v8::Boolean::New(SearchBox::Get(render_view)->
+ is_key_capture_enabled());
+}
+
+// static
v8::Handle<v8::Value> SearchBoxExtensionWrapper::GetContext(
const v8::Arguments& args) {
content::RenderView* render_view = GetRenderView();
@@ -830,6 +854,11 @@ void SearchBoxExtension::DispatchUpOrDownKeyPress(WebKit::WebFrame* frame,
}
// static
+void SearchBoxExtension::DispatchKeyCaptureChange(WebKit::WebFrame* frame) {
+ Dispatch(frame, kDispatchKeyCaptureChangeScript);
+}
+
+// static
void SearchBoxExtension::DispatchContextChange(WebKit::WebFrame* frame) {
Dispatch(frame, kDispatchContextChangeEventScript);
}
diff --git a/chrome/renderer/searchbox/searchbox_extension.h b/chrome/renderer/searchbox/searchbox_extension.h
index 04eadfc..51fb15b 100644
--- a/chrome/renderer/searchbox/searchbox_extension.h
+++ b/chrome/renderer/searchbox/searchbox_extension.h
@@ -36,6 +36,7 @@ class SearchBoxExtension {
static void DispatchOnWindowReady(WebKit::WebFrame* frame);
static void DispatchAutocompleteResults(WebKit::WebFrame* frame);
static void DispatchUpOrDownKeyPress(WebKit::WebFrame* frame, int count);
+ static void DispatchKeyCaptureChange(WebKit::WebFrame* frame);
static void DispatchFocus(WebKit::WebFrame* frame);
static void DispatchBlur(WebKit::WebFrame* frame);
static void DispatchContextChange(WebKit::WebFrame* frame);