summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc483
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_gtk.h201
-rwxr-xr-xchrome/browser/autocomplete/autocomplete_popup_view_gtk.cc115
-rwxr-xr-xchrome/browser/autocomplete/autocomplete_popup_view_gtk.h55
-rw-r--r--chrome/browser/browser.scons3
-rw-r--r--chrome/browser/gtk/browser_toolbar_gtk.cc91
-rw-r--r--chrome/browser/gtk/browser_toolbar_gtk.h24
-rw-r--r--chrome/browser/gtk/location_bar_view_gtk.cc143
-rw-r--r--chrome/browser/gtk/location_bar_view_gtk.h88
9 files changed, 1114 insertions, 89 deletions
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc
new file mode 100644
index 0000000..cae7c6e
--- /dev/null
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc
@@ -0,0 +1,483 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/autocomplete/autocomplete_edit_view_gtk.h"
+
+#include <gtk/gtk.h>
+
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "chrome/browser/autocomplete/autocomplete_edit.h"
+#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
+#include "chrome/browser/autocomplete/autocomplete_popup_view_gtk.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/browser/toolbar_model.h"
+#include "chrome/common/notification_service.h"
+#include "googleurl/src/gurl.h"
+
+namespace {
+
+const char kTextBaseColor[] = "#808080";
+const char kSecureSchemeColor[] = "#009614";
+const char kInsecureSchemeColor[] = "#009614";
+const GdkColor kSecureBackgroundColor = {0, 65535, 62965, 50115}; // #fff5c3
+const GdkColor kInsecureBackgroundColor = {0, 65535, 65535, 65535}; // #ffffff
+
+} // namespace
+
+AutocompleteEditViewGtk::AutocompleteEditViewGtk(
+ AutocompleteEditController* controller,
+ ToolbarModel* toolbar_model,
+ Profile* profile,
+ CommandUpdater* command_updater)
+ : text_view_(NULL),
+ tag_table_(NULL),
+ text_buffer_(NULL),
+ base_tag_(NULL),
+ secure_scheme_tag_(NULL),
+ insecure_scheme_tag_(NULL),
+ model_(new AutocompleteEditModel(this, controller, profile)),
+ popup_view_(new AutocompletePopupViewGtk(this, model_.get(), profile)),
+ controller_(controller),
+ toolbar_model_(toolbar_model),
+ command_updater_(command_updater),
+ popup_window_mode_(false), // TODO(deanm)
+ scheme_security_level_(ToolbarModel::NORMAL) {
+ model_->set_popup_model(popup_view_->model());
+}
+
+AutocompleteEditViewGtk::~AutocompleteEditViewGtk() {
+ NotificationService::current()->Notify(
+ NotificationType::AUTOCOMPLETE_EDIT_DESTROYED,
+ Source<AutocompleteEditViewGtk>(this),
+ NotificationService::NoDetails());
+}
+
+void AutocompleteEditViewGtk::Init() {
+ tag_table_ = gtk_text_tag_table_new();
+ text_buffer_ = gtk_text_buffer_new(tag_table_);
+ text_view_ = gtk_text_view_new_with_buffer(text_buffer_);
+
+ gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_view_), 4);
+ gtk_text_view_set_right_margin(GTK_TEXT_VIEW(text_view_), 4);
+
+ // TODO(deanm): This is a super lame attempt to vertically center our single
+ // line of text in a multiline edit control. Mannnn.
+ gtk_text_view_set_pixels_above_lines(GTK_TEXT_VIEW(text_view_), 4);
+
+ // TODO(deanm): This will probably have to be handled differently with the
+ // tab to search business. Maybe we should just eat the tab characters.
+ // We want the tab key to move focus, not insert a tab.
+ gtk_text_view_set_accepts_tab(GTK_TEXT_VIEW(text_view_), false);
+
+ base_tag_ = gtk_text_buffer_create_tag(text_buffer_,
+ NULL, "foreground", kTextBaseColor, NULL);
+ secure_scheme_tag_ = gtk_text_buffer_create_tag(text_buffer_,
+ NULL, "foreground", kSecureSchemeColor, NULL);
+ insecure_scheme_tag_ = gtk_text_buffer_create_tag(text_buffer_,
+ NULL, "foreground", kInsecureSchemeColor, NULL);
+
+ // NOTE: This code used to connect to "changed", however this was fired too
+ // often and during bad times (our own buffer changes?). It works out much
+ // better to listen to end-user-action, which should be fired whenever the
+ // user makes some sort of change to the buffer.
+ g_signal_connect(text_buffer_, "begin-user-action",
+ G_CALLBACK(&HandleBeginUserActionThunk), this);
+ g_signal_connect(text_buffer_, "end-user-action",
+ G_CALLBACK(&HandleEndUserActionThunk), this);
+ g_signal_connect(text_view_, "size-request",
+ G_CALLBACK(&HandleViewSizeRequest), this);
+ g_signal_connect(text_view_, "button-press-event",
+ G_CALLBACK(&HandleViewButtonPressThunk), this);
+ g_signal_connect(text_view_, "focus-in-event",
+ G_CALLBACK(&HandleViewFocusInThunk), this);
+ g_signal_connect(text_view_, "focus-out-event",
+ G_CALLBACK(&HandleViewFocusOutThunk), this);
+ // NOTE: The GtkTextView documentation asks you not to connect to this
+ // signal, but it is very convenient and clean for catching up/down.
+ g_signal_connect(text_view_, "move-cursor",
+ G_CALLBACK(&HandleViewMoveCursorThunk), this);
+}
+
+void AutocompleteEditViewGtk::FocusLocation() {
+ gtk_widget_grab_focus(text_view_);
+ SelectAll(false);
+}
+
+void AutocompleteEditViewGtk::SaveStateToTab(TabContents* tab) {
+ NOTIMPLEMENTED();
+}
+
+void AutocompleteEditViewGtk::Update(const TabContents* contents) {
+ // NOTE: We're getting the URL text here from the ToolbarModel.
+ bool visibly_changed_permanent_text =
+ model_->UpdatePermanentText(toolbar_model_->GetText());
+
+ ToolbarModel::SecurityLevel security_level =
+ toolbar_model_->GetSchemeSecurityLevel();
+ bool changed_security_level = (security_level != scheme_security_level_);
+ scheme_security_level_ = security_level;
+
+ if (contents) {
+ RevertAll();
+ // TODO(deanm): Tab switching. The Windows code puts some state in a
+ // PropertyBag on the tab contents, and restores state from there.
+ } else if (visibly_changed_permanent_text) {
+ RevertAll();
+ // TODO(deanm): There should be code to restore select all here.
+ } else if(changed_security_level) {
+ EmphasizeURLComponents();
+ }
+}
+
+void AutocompleteEditViewGtk::OpenURL(const GURL& url,
+ WindowOpenDisposition disposition,
+ PageTransition::Type transition,
+ const GURL& alternate_nav_url,
+ size_t selected_line,
+ const std::wstring& keyword) {
+ if (!url.is_valid())
+ return;
+
+ model_->SendOpenNotification(selected_line, keyword);
+
+ if (disposition != NEW_BACKGROUND_TAB)
+ RevertAll(); // Revert the box to its unedited state
+ controller_->OnAutocompleteAccept(url, disposition, transition,
+ alternate_nav_url);
+}
+
+std::wstring AutocompleteEditViewGtk::GetText() const {
+ GtkTextIter start, end;
+ gtk_text_buffer_get_bounds(text_buffer_, &start, &end);
+ gchar* utf8 = gtk_text_buffer_get_text(text_buffer_, &start, &end, false);
+ std::wstring out(UTF8ToWide(utf8));
+ g_free(utf8);
+ return out;
+}
+
+void AutocompleteEditViewGtk::SetUserText(const std::wstring& text,
+ const std::wstring& display_text,
+ bool update_popup) {
+ NOTIMPLEMENTED();
+}
+
+void AutocompleteEditViewGtk::SetWindowTextAndCaretPos(const std::wstring& text,
+ size_t caret_pos) {
+ std::string utf8 = WideToUTF8(text);
+ gtk_text_buffer_set_text(text_buffer_, utf8.data(), utf8.length());
+ EmphasizeURLComponents();
+
+ GtkTextIter cur_pos;
+ gtk_text_buffer_get_iter_at_offset(text_buffer_, &cur_pos, caret_pos);
+ gtk_text_buffer_place_cursor(text_buffer_, &cur_pos);
+}
+
+bool AutocompleteEditViewGtk::IsSelectAll() {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void AutocompleteEditViewGtk::SelectAll(bool reversed) {
+ GtkTextIter start, end;
+ if (reversed) {
+ gtk_text_buffer_get_bounds(text_buffer_, &end, &start);
+ } else {
+ gtk_text_buffer_get_bounds(text_buffer_, &start, &end);
+ }
+ gtk_text_buffer_place_cursor(text_buffer_, &start);
+ gtk_text_buffer_select_range(text_buffer_, &start, &end);
+}
+
+void AutocompleteEditViewGtk::RevertAll() {
+ ClosePopup();
+ model_->Revert();
+ TextChanged();
+}
+
+void AutocompleteEditViewGtk::UpdatePopup() {
+ model_->SetInputInProgress(true);
+ if (!model_->has_focus())
+ return;
+
+ // Don't inline autocomplete when the caret/selection isn't at the end of
+ // the text.
+ CharRange sel = GetSelection();
+ model_->StartAutocomplete(sel.cp_max < GetTextLength());
+}
+
+void AutocompleteEditViewGtk::ClosePopup() {
+ popup_view_->model()->StopAutocomplete();
+}
+
+void AutocompleteEditViewGtk::OnTemporaryTextMaybeChanged(
+ const std::wstring& display_text,
+ bool save_original_selection) {
+ // TODO(deanm): Ignoring save_original_selection here, etc.
+ SetWindowTextAndCaretPos(display_text, display_text.length());
+ TextChanged();
+}
+
+bool AutocompleteEditViewGtk::OnInlineAutocompleteTextMaybeChanged(
+ const std::wstring& display_text,
+ size_t user_text_length) {
+ if (display_text == GetText())
+ return false;
+
+ SetWindowTextAndCaretPos(display_text, 0);
+
+ // Select the part of the text that was inline autocompleted.
+ GtkTextIter bound, insert;
+ gtk_text_buffer_get_bounds(text_buffer_, &insert, &bound);
+ gtk_text_buffer_get_iter_at_offset(text_buffer_, &insert, user_text_length);
+ gtk_text_buffer_select_range(text_buffer_, &insert, &bound);
+
+ TextChanged();
+ return true;
+}
+
+void AutocompleteEditViewGtk::OnRevertTemporaryText() {
+ NOTIMPLEMENTED();
+}
+
+void AutocompleteEditViewGtk::OnBeforePossibleChange() {
+ // Record our state.
+ text_before_change_ = GetText();
+ sel_before_change_ = GetSelection();
+}
+
+// TODO(deanm): This is mostly stolen from Windows, and will need some work.
+bool AutocompleteEditViewGtk::OnAfterPossibleChange() {
+ CharRange new_sel = GetSelection();
+ int length = GetTextLength();
+ bool selection_differs = (new_sel.cp_min != sel_before_change_.cp_min) ||
+ (new_sel.cp_max != sel_before_change_.cp_max);
+ bool at_end_of_edit = (new_sel.cp_min == length && new_sel.cp_max == length);
+
+ // See if the text or selection have changed since OnBeforePossibleChange().
+ std::wstring new_text(GetText());
+ bool text_differs = (new_text != text_before_change_);
+
+ // When the user has deleted text, we don't allow inline autocomplete. Make
+ // sure to not flag cases like selecting part of the text and then pasting
+ // (or typing) the prefix of that selection. (We detect these by making
+ // sure the caret, which should be after any insertion, hasn't moved
+ // forward of the old selection start.)
+ bool just_deleted_text =
+ (text_before_change_.length() > new_text.length()) &&
+ (new_sel.cp_min <= std::min(sel_before_change_.cp_min,
+ sel_before_change_.cp_max));
+
+ bool something_changed = model_->OnAfterPossibleChange(new_text,
+ selection_differs, text_differs, just_deleted_text, at_end_of_edit);
+
+ if (something_changed && text_differs)
+ TextChanged();
+
+ return something_changed;
+}
+
+void AutocompleteEditViewGtk::BottomLeftPosWidth(int* x, int* y, int* width) {
+ gdk_window_get_origin(text_view_->window, x, y);
+ *y += text_view_->allocation.height;
+ *width = text_view_->allocation.width;
+}
+
+void AutocompleteEditViewGtk::HandleBeginUserAction() {
+ OnBeforePossibleChange();
+}
+
+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;
+ }
+
+ gtk_text_iter_forward_char(&cur);
+ }
+
+ // We've exhausted the whole input and there is now only 1 line, good.
+ if (gtk_text_iter_equal(&cur, &end))
+ break;
+ }
+
+ OnAfterPossibleChange();
+
+ if (had_newline)
+ model_->AcceptInput(CURRENT_TAB, false);
+}
+
+// static
+void AutocompleteEditViewGtk::HandleViewSizeRequest(GtkWidget* view,
+ GtkRequisition* req,
+ gpointer unused) {
+ // Don't force a minimum size, allow our embedder to size us better.
+ req->height = req->width = 1;
+}
+
+gboolean AutocompleteEditViewGtk::HandleViewButtonPress(GdkEventButton* event) {
+ // When the GtkTextView is clicked, it will call gtk_widget_grab_focus.
+ // I believe this causes the focus-in event to be fired before the main
+ // clicked handling code. If we were to try to set the selection from
+ // the focus-in event, it's just going to be undone by the click handler.
+ // This is a bit ugly. We shim in to get the click before the GtkTextView,
+ // then if we don't have focus, we (hopefully safely) assume that the click
+ // will cause us to become focused. We call GtkTextView's default handler
+ // and then stop propagation. This allows us to run our code after the
+ // default handler, even if that handler stopped propagation.
+ if (GTK_WIDGET_HAS_FOCUS(text_view_))
+ return FALSE; // Continue to propagate into the GtkTextView handler.
+
+ // Call the GtkTextView default handler, ignoring the fact that it will
+ // likely have told us to stop propagating. We want to handle selection.
+ GtkWidgetClass* klass = GTK_WIDGET_GET_CLASS(text_view_);
+ klass->button_press_event(text_view_, event);
+
+ // Select the full input when we get focus.
+ SelectAll(false);
+ // So we told the buffer where the cursor should be, but make sure to tell
+ // the view so it can scroll it to be visible if needed.
+ // NOTE: This function doesn't seem to like a count of 0, looking at the
+ // code it will skip an important loop. Use -1 to achieve the same.
+ GtkTextIter start, end;
+ gtk_text_buffer_get_bounds(text_buffer_, &start, &end);
+ gtk_text_view_move_visually(GTK_TEXT_VIEW(text_view_), &start, -1);
+
+ return TRUE; // Don't continue, we called the default handler already.
+}
+
+gboolean AutocompleteEditViewGtk::HandleViewFocusIn() {
+ model_->OnSetFocus(false);
+ // TODO(deanm): Some keyword hit business, etc here.
+
+ return FALSE; // Continue propagation.
+}
+
+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.
+}
+
+void AutocompleteEditViewGtk::HandleViewMoveCursor(
+ GtkMovementStep step,
+ gint count,
+ gboolean extendion_selection) {
+ // Handle up / down cursor movement on our own.
+ if (step == GTK_MOVEMENT_DISPLAY_LINES) {
+ model_->OnUpOrDownKeyPressed(count);
+ // move-cursor doesn't use a signal accumulator on the return value (it
+ // just ignores them), so we have to stop the propagation.
+ g_signal_stop_emission_by_name(text_view_, "move-cursor");
+ return;
+ }
+ // Propagate into GtkTextView.
+}
+
+AutocompleteEditViewGtk::CharRange AutocompleteEditViewGtk::GetSelection() {
+ // You can not just use get_selection_bounds here, since the order will be
+ // ascending, and you don't know where the user's start and end of the
+ // selection was (if the selection was forwards or backwards). Get the
+ // actual marks so that we can preserve the selection direction.
+ GtkTextIter start, insert;
+ GtkTextMark* mark;
+
+ mark = gtk_text_buffer_get_selection_bound(text_buffer_);
+ gtk_text_buffer_get_iter_at_mark(text_buffer_, &start, mark);
+
+ mark = gtk_text_buffer_get_insert(text_buffer_);
+ gtk_text_buffer_get_iter_at_mark(text_buffer_, &insert, mark);
+
+ return CharRange(gtk_text_iter_get_offset(&start),
+ gtk_text_iter_get_offset(&insert));
+}
+
+void AutocompleteEditViewGtk::ItersFromCharRange(const CharRange& range,
+ GtkTextIter* iter_min,
+ GtkTextIter* iter_max) {
+ gtk_text_buffer_get_iter_at_offset(text_buffer_, iter_min, range.cp_min);
+ gtk_text_buffer_get_iter_at_offset(text_buffer_, iter_max, range.cp_max);
+}
+
+int AutocompleteEditViewGtk::GetTextLength() {
+ GtkTextIter start, end;
+ gtk_text_buffer_get_bounds(text_buffer_, &start, &end);
+ return gtk_text_iter_get_offset(&end);
+}
+
+void AutocompleteEditViewGtk::EmphasizeURLComponents() {
+ // See whether the contents are a URL with a non-empty host portion, which we
+ // should emphasize. To check for a URL, rather than using the type returned
+ // by Parse(), ask the model, which will check the desired page transition for
+ // this input. This can tell us whether an UNKNOWN input string is going to
+ // be treated as a search or a navigation, and is the same method the Paste
+ // And Go system uses.
+ url_parse::Parsed parts;
+ AutocompleteInput::Parse(GetText(), model_->GetDesiredTLD(), &parts, NULL);
+ bool emphasize = model_->CurrentTextIsURL() && (parts.host.len > 0);
+
+ // Set the baseline emphasis.
+ GtkTextIter start, end;
+ gtk_text_buffer_get_bounds(text_buffer_, &start, &end);
+ gtk_text_buffer_remove_all_tags(text_buffer_, &start, &end);
+ if (emphasize) {
+ gtk_text_buffer_apply_tag(text_buffer_, base_tag_, &start, &end);
+
+ // We've found a host name, give it more emphasis.
+ gtk_text_buffer_get_iter_at_line_index(text_buffer_, &start, 0,
+ parts.host.begin);
+ gtk_text_buffer_get_iter_at_line_index(text_buffer_, &end, 0,
+ parts.host.end());
+ gtk_text_buffer_remove_all_tags(text_buffer_, &start, &end);
+ }
+
+ // Emphasize the scheme for security UI display purposes (if necessary).
+ if (!model_->user_input_in_progress() && parts.scheme.is_nonempty() &&
+ (scheme_security_level_ != ToolbarModel::NORMAL)) {
+ gtk_text_buffer_get_iter_at_line_index(text_buffer_, &start, 0,
+ parts.scheme.begin);
+ gtk_text_buffer_get_iter_at_line_index(text_buffer_, &end, 0,
+ parts.scheme.end());
+ const GdkColor* background;
+ if (scheme_security_level_ == ToolbarModel::SECURE) {
+ background = &kSecureBackgroundColor;
+ gtk_text_buffer_apply_tag(text_buffer_, secure_scheme_tag_,
+ &start, &end);
+ } else {
+ background = &kInsecureBackgroundColor;
+ gtk_text_buffer_apply_tag(text_buffer_, insecure_scheme_tag_,
+ &start, &end);
+ }
+ gtk_widget_modify_base(text_view_, GTK_STATE_NORMAL, background);
+ }
+}
+
+void AutocompleteEditViewGtk::TextChanged() {
+ EmphasizeURLComponents();
+ controller_->OnChanged();
+}
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h
new file mode 100644
index 0000000..85d16ae
--- /dev/null
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h
@@ -0,0 +1,201 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_VIEW_GTK_H_
+#define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_VIEW_GTK_H_
+
+#include <gtk/gtk.h>
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/autocomplete/autocomplete.h"
+#include "chrome/browser/autocomplete/autocomplete_edit_view.h"
+#include "chrome/browser/toolbar_model.h"
+#include "chrome/common/page_transition_types.h"
+#include "webkit/glue/window_open_disposition.h"
+
+class AutocompleteEditController;
+class AutocompleteEditModel;
+class AutocompletePopupViewGtk;
+class CommandUpdater;
+class Profile;
+class TabContents;
+class ToolbarModel;
+
+class AutocompleteEditViewGtk : public AutocompleteEditView {
+ public:
+ AutocompleteEditViewGtk(AutocompleteEditController* controller,
+ ToolbarModel* toolbar_model,
+ Profile* profile,
+ CommandUpdater* command_updater);
+ ~AutocompleteEditViewGtk();
+
+ // Initialize, create the underlying widgets, etc.
+ void Init();
+
+ GtkWidget* widget() { return text_view_; }
+
+ // Grab keyboard input focus, putting focus on the location widget.
+ void FocusLocation();
+
+ // Implement the AutocompleteEditView interface.
+ virtual AutocompleteEditModel* model() { return model_.get(); }
+ virtual const AutocompleteEditModel* model() const { return model_.get(); }
+
+ virtual void SaveStateToTab(TabContents* tab);
+
+ virtual void Update(const TabContents* tab_for_state_restoring);
+
+ virtual void OpenURL(const GURL& url,
+ WindowOpenDisposition disposition,
+ PageTransition::Type transition,
+ const GURL& alternate_nav_url,
+ size_t selected_line,
+ const std::wstring& keyword);
+
+ virtual std::wstring GetText() const;
+
+ virtual void SetUserText(const std::wstring& text) {
+ SetUserText(text, text, true);
+ }
+ virtual void SetUserText(const std::wstring& text,
+ const std::wstring& display_text,
+ bool update_popup);
+
+ virtual void SetWindowTextAndCaretPos(const std::wstring& text,
+ size_t caret_pos);
+
+ virtual bool IsSelectAll();
+ virtual void SelectAll(bool reversed);
+ virtual void RevertAll();
+
+ virtual void UpdatePopup();
+ virtual void ClosePopup();
+
+ virtual void OnTemporaryTextMaybeChanged(const std::wstring& display_text,
+ bool save_original_selection);
+ virtual bool OnInlineAutocompleteTextMaybeChanged(
+ const std::wstring& display_text, size_t user_text_length);
+ virtual void OnRevertTemporaryText();
+ virtual void OnBeforePossibleChange();
+ virtual bool OnAfterPossibleChange();
+
+ // Return the position (root coordinates) of the bottom left corner and width
+ // of the location input box. Used by the popup view to position itself.
+ void BottomLeftPosWidth(int* x, int* y, int* width);
+
+ private:
+ // Modeled like the Windows CHARRANGE. Represent a pair of cursor position
+ // offsets. Since GtkTextIters are invalid after the buffer is changed, we
+ // work in character offsets (not bytes).
+ struct CharRange {
+ CharRange() : cp_min(0), cp_max(0) { }
+ CharRange(int n, int x) : cp_min(n), cp_max(x) { }
+
+ // Work in integers to match the gint GTK APIs.
+ int cp_min; // For a selection: Represents the start.
+ int cp_max; // For a selection: Represents the end (insert position).
+ };
+
+ // TODO(deanm): Would be nice to insulate the thunkers better, etc.
+ static void HandleBeginUserActionThunk(GtkTextBuffer* unused, gpointer self) {
+ reinterpret_cast<AutocompleteEditViewGtk*>(self)->HandleBeginUserAction();
+ }
+ void HandleBeginUserAction();
+
+ static void HandleEndUserActionThunk(GtkTextBuffer* unused, gpointer self) {
+ reinterpret_cast<AutocompleteEditViewGtk*>(self)->HandleEndUserAction();
+ }
+ void HandleEndUserAction();
+
+ static void HandleViewSizeRequest(GtkWidget* view, GtkRequisition* req,
+ gpointer unused);
+
+ static gboolean HandleViewButtonPressThunk(GtkWidget* view,
+ GdkEventButton* event,
+ gpointer self) {
+ return reinterpret_cast<AutocompleteEditViewGtk*>(self)->
+ HandleViewButtonPress(event);
+ }
+ gboolean HandleViewButtonPress(GdkEventButton* event);
+
+ static gboolean HandleViewFocusInThunk(GtkWidget* view,
+ GdkEventFocus* event,
+ gpointer self) {
+ return reinterpret_cast<AutocompleteEditViewGtk*>(self)->
+ HandleViewFocusIn();
+ }
+ gboolean HandleViewFocusIn();
+
+ static gboolean HandleViewFocusOutThunk(GtkWidget* view,
+ GdkEventFocus* event,
+ gpointer self) {
+ return reinterpret_cast<AutocompleteEditViewGtk*>(self)->
+ HandleViewFocusOut();
+ }
+ gboolean HandleViewFocusOut();
+
+ static void HandleViewMoveCursorThunk(GtkWidget* view,
+ GtkMovementStep step,
+ gint count,
+ gboolean extend_selection,
+ gpointer self) {
+ reinterpret_cast<AutocompleteEditViewGtk*>(self)->
+ HandleViewMoveCursor(step, count, extend_selection);
+ }
+ void HandleViewMoveCursor(GtkMovementStep step,
+ gint count,
+ gboolean extendion_selection);
+
+ // Get the character indices of the current selection. This honors
+ // direction, cp_max is the insertion point, and cp_min is the bound.
+ CharRange GetSelection();
+
+ // Translate from character positions to iterators for the current buffer.
+ void ItersFromCharRange(const CharRange& range,
+ GtkTextIter* iter_min,
+ GtkTextIter* iter_max);
+
+ // Return the number of characers in the current buffer.
+ int GetTextLength();
+
+ // Try to parse the current text as a URL and colorize the components.
+ void EmphasizeURLComponents();
+
+ // Internally invoked whenever the text changes in some way.
+ void TextChanged();
+
+ GtkWidget* text_view_;
+
+ GtkTextTagTable* tag_table_;
+ GtkTextBuffer* text_buffer_;
+
+ GtkTextTag* base_tag_;
+ GtkTextTag* secure_scheme_tag_;
+ GtkTextTag* insecure_scheme_tag_;
+
+ scoped_ptr<AutocompleteEditModel> model_;
+ scoped_ptr<AutocompletePopupViewGtk> popup_view_;
+ AutocompleteEditController* controller_;
+ ToolbarModel* toolbar_model_;
+
+ // The object that handles additional command functionality exposed on the
+ // edit, such as invoking the keyword editor.
+ CommandUpdater* command_updater_;
+
+ // When true, the location bar view is read only and also is has a slightly
+ // different presentation (font size / color). This is used for popups.
+ // TODO(deanm).
+ bool popup_window_mode_;
+
+ ToolbarModel::SecurityLevel scheme_security_level_;
+
+ // Tracking state before and after a possible change.
+ std::wstring text_before_change_;
+ CharRange sel_before_change_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutocompleteEditViewGtk);
+};
+
+#endif // CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_VIEW_GTK_H_
diff --git a/chrome/browser/autocomplete/autocomplete_popup_view_gtk.cc b/chrome/browser/autocomplete/autocomplete_popup_view_gtk.cc
new file mode 100755
index 0000000..8f1b586
--- /dev/null
+++ b/chrome/browser/autocomplete/autocomplete_popup_view_gtk.cc
@@ -0,0 +1,115 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/autocomplete/autocomplete_popup_view_gtk.h"
+
+#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "chrome/browser/autocomplete/autocomplete.h"
+#include "chrome/browser/autocomplete/autocomplete_edit.h"
+#include "chrome/browser/autocomplete/autocomplete_edit_view_gtk.h"
+#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/search_engines/template_url.h"
+#include "chrome/browser/search_engines/template_url_model.h"
+#include "chrome/common/notification_service.h"
+
+namespace {
+
+const GdkColor kPopupBorderColor = {0, 51143, 51914, 52942}; // #c7cace
+const GdkColor kPopupBackground = {0, 65535, 65535, 65535}; // #ffffff
+const GdkColor kHighlightColor = {0, 49601, 51400, 55769}; // #c1c8d9
+
+} // namespace
+
+AutocompletePopupViewGtk::AutocompletePopupViewGtk(
+ AutocompleteEditViewGtk* edit_view,
+ AutocompleteEditModel* edit_model,
+ Profile* profile)
+ : model_(new AutocompletePopupModel(this, edit_model, profile)),
+ edit_view_(edit_view),
+ window_(gtk_window_new(GTK_WINDOW_POPUP)),
+ vbox_(NULL),
+ opened_(false) {
+ GTK_WIDGET_UNSET_FLAGS(window_, GTK_CAN_FOCUS);
+ // Don't allow the window to be resized. This also forces the window to
+ // shrink down to the size of its child contents.
+ gtk_window_set_resizable(GTK_WINDOW(window_), FALSE);
+ // Set up a 1 pixel border around the popup.
+ gtk_container_set_border_width(GTK_CONTAINER(window_), 1);
+ gtk_widget_modify_bg(window_, GTK_STATE_NORMAL, &kPopupBorderColor);
+ gtk_widget_modify_base(window_, GTK_STATE_NORMAL, &kPopupBorderColor);
+}
+
+AutocompletePopupViewGtk::~AutocompletePopupViewGtk() {
+ if (vbox_)
+ gtk_widget_destroy(vbox_);
+ gtk_widget_destroy(window_);
+}
+
+void AutocompletePopupViewGtk::InvalidateLine(size_t line) {
+ UpdatePopupAppearance();
+}
+
+void AutocompletePopupViewGtk::UpdatePopupAppearance() {
+ const AutocompleteResult& result = model_->result();
+ if (result.empty()) {
+ Hide();
+ return;
+ }
+
+ // TODO(deanm): This could be done better, but the code is temporary
+ // and will need to be replaced with custom drawing and not widgets.
+ if (vbox_)
+ gtk_widget_destroy(vbox_);
+
+ vbox_ = gtk_vbox_new(FALSE, 0);
+
+ for (size_t i = 0; i < result.size(); ++i) {
+ std::string utf8;
+ utf8.append(WideToUTF8(result.match_at(i).contents));
+ utf8.append(" - ");
+ utf8.append(WideToUTF8(result.match_at(i).description));
+ GtkWidget* label = gtk_label_new(utf8.c_str());
+ // We need to put the labels in an event box for background painting.
+ GtkWidget* ebox = gtk_event_box_new();
+ gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+ gtk_container_add(GTK_CONTAINER(ebox), label);
+ gtk_box_pack_start(GTK_BOX(vbox_), ebox, FALSE, FALSE, 0);
+ gtk_widget_show(label);
+ gtk_widget_show(ebox);
+ if (i == model_->selected_line()) {
+ gtk_widget_modify_bg(ebox, GTK_STATE_NORMAL, &kHighlightColor);
+ } else {
+ gtk_widget_modify_bg(ebox, GTK_STATE_NORMAL, &kPopupBackground);
+ }
+ }
+
+ gtk_widget_show(vbox_);
+ gtk_container_add(GTK_CONTAINER(window_), vbox_);
+ Show();
+}
+
+void AutocompletePopupViewGtk::OnHoverEnabledOrDisabled(bool disabled) {
+ NOTIMPLEMENTED();
+}
+
+void AutocompletePopupViewGtk::PaintUpdatesNow() {
+ UpdatePopupAppearance();
+}
+
+void AutocompletePopupViewGtk::Show() {
+ gint x, y, width;
+ edit_view_->BottomLeftPosWidth(&x, &y, &width);
+ gtk_window_move(GTK_WINDOW(window_), x, y);
+ gtk_widget_set_size_request(window_, width, -1);
+ gtk_widget_show(window_);
+ opened_ = true;
+}
+
+void AutocompletePopupViewGtk::Hide() {
+ gtk_widget_hide(window_);
+ opened_ = false;
+}
diff --git a/chrome/browser/autocomplete/autocomplete_popup_view_gtk.h b/chrome/browser/autocomplete/autocomplete_popup_view_gtk.h
new file mode 100755
index 0000000..3c4fcc8
--- /dev/null
+++ b/chrome/browser/autocomplete/autocomplete_popup_view_gtk.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_VIEW_GTK_H_
+#define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_VIEW_GTK_H_
+
+#include <gtk/gtk.h>
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/autocomplete/autocomplete.h"
+#include "chrome/browser/autocomplete/autocomplete_popup_view.h"
+#include "webkit/glue/window_open_disposition.h"
+
+class AutocompletePopupModel;
+class AutocompleteEditModel;
+class AutocompleteEditViewGtk;
+class Profile;
+class SkBitmap;
+
+class AutocompletePopupViewGtk : public AutocompletePopupView {
+ public:
+ AutocompletePopupViewGtk(AutocompleteEditViewGtk* edit_view,
+ AutocompleteEditModel* edit_model,
+ Profile* profile);
+ ~AutocompletePopupViewGtk();
+
+ // Implement the AutocompletePopupView interface.
+ virtual bool IsOpen() const { return opened_; }
+ virtual void InvalidateLine(size_t line);
+ virtual void UpdatePopupAppearance();
+ virtual void OnHoverEnabledOrDisabled(bool disabled);
+ virtual void PaintUpdatesNow();
+
+ AutocompletePopupModel* model() { return model_.get(); }
+
+ private:
+ void Show();
+ void Hide();
+
+ scoped_ptr<AutocompletePopupModel> model_;
+ AutocompleteEditViewGtk* edit_view_;
+
+ GtkWidget* window_;
+ GtkWidget* vbox_;
+
+ bool opened_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutocompletePopupViewGtk);
+};
+
+#endif // CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_VIEW_GTK_H_
diff --git a/chrome/browser/browser.scons b/chrome/browser/browser.scons
index 0e6e74d..7c820b4 100644
--- a/chrome/browser/browser.scons
+++ b/chrome/browser/browser.scons
@@ -736,6 +736,8 @@ if not env.Bit('windows'):
if env.Bit('linux'):
input_files.Extend([
+ 'autocomplete/autocomplete_edit_view_gtk.cc',
+ 'autocomplete/autocomplete_popup_view_gtk.cc',
'browser_main_gtk.cc',
'gtk/back_forward_menu_model_gtk.cc',
'gtk/browser_toolbar_gtk.cc',
@@ -744,6 +746,7 @@ if env.Bit('linux'):
'gtk/custom_button.cc',
'gtk/download_item_gtk.cc',
'gtk/download_shelf_gtk.cc',
+ 'gtk/location_bar_view_gtk.cc',
'gtk/menu_gtk.cc',
'gtk/nine_box.cc',
'gtk/standard_menus.cc',
diff --git a/chrome/browser/gtk/browser_toolbar_gtk.cc b/chrome/browser/gtk/browser_toolbar_gtk.cc
index b218beb..c51d27d 100644
--- a/chrome/browser/gtk/browser_toolbar_gtk.cc
+++ b/chrome/browser/gtk/browser_toolbar_gtk.cc
@@ -11,8 +11,9 @@
#include "base/path_service.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.h"
-#include "chrome/browser/gtk/custom_button.h"
#include "chrome/browser/gtk/back_forward_menu_model_gtk.h"
+#include "chrome/browser/gtk/custom_button.h"
+#include "chrome/browser/gtk/location_bar_view_gtk.h"
#include "chrome/browser/gtk/standard_menus.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/common/l10n_util.h"
@@ -21,17 +22,19 @@
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
-// TODO(deanm): Remove this when the LocationBarView is used.
-class LocationBar;
-
const int BrowserToolbarGtk::kToolbarHeight = 38;
// For the back/forward dropdown menus, the time in milliseconds between
// when the user clicks and the popup menu appears.
static const int kMenuTimerDelay = 500;
+static void OnGrabFocusThunk(GtkWidget* toolbar, gpointer self) {
+ reinterpret_cast<BrowserToolbarGtk*>(self)->FocusLocationBar();
+}
+
BrowserToolbarGtk::BrowserToolbarGtk(Browser* browser)
: toolbar_(NULL),
- entry_(NULL),
+ location_bar_(new LocationBarViewGtk(browser->command_updater(),
+ browser->toolbar_model())),
model_(browser->toolbar_model()),
browser_(browser),
profile_(NULL),
@@ -52,6 +55,9 @@ BrowserToolbarGtk::~BrowserToolbarGtk() {
}
void BrowserToolbarGtk::Init(Profile* profile, GtkAccelGroup* accel_group) {
+ // Make sure to tell the location bar the profile before calling its Init.
+ SetProfile(profile);
+
accel_group_ = accel_group;
show_home_button_.Init(prefs::kShowHomeButton, profile->GetPrefs(), this);
@@ -89,22 +95,17 @@ void BrowserToolbarGtk::Init(Profile* profile, GtkAccelGroup* accel_group) {
star_.reset(BuildToolbarButton(IDR_STAR, IDR_STAR_P, IDR_STAR_H, IDR_STAR_D,
l10n_util::GetString(IDS_TOOLTIP_STAR)));
- entry_ = gtk_entry_new();
- gtk_widget_set_size_request(entry_, 0, 27);
- g_signal_connect(G_OBJECT(entry_), "activate",
- G_CALLBACK(OnEntryActivate), this);
- g_signal_connect(G_OBJECT(entry_), "focus",
- G_CALLBACK(OnEntryFocus), this);
- g_signal_connect(G_OBJECT(entry_), "focus-in-event",
- G_CALLBACK(OnEntryFocusIn), this);
- g_signal_connect(G_OBJECT(entry_), "focus-out-event",
- G_CALLBACK(OnEntryFocusOut), this);
+ location_bar_->Init();
+ gtk_box_pack_start(GTK_BOX(toolbar_), location_bar_->widget(), TRUE, TRUE, 0);
+
+ // We listen for ctrl-l which we have send a grab-focus action to the
+ // toolbar. We want our callback to just call FocusLocationBar().
+ g_signal_connect(toolbar_, "grab-focus",
+ G_CALLBACK(OnGrabFocusThunk), this);
gtk_widget_add_accelerator(
- entry_, "grab-focus", accel_group_, GDK_l,
+ toolbar_, "grab-focus", accel_group_, GDK_l,
GDK_CONTROL_MASK, GtkAccelFlags(0));
- gtk_box_pack_start(GTK_BOX(toolbar_), entry_, TRUE, TRUE, 0);
-
go_.reset(BuildToolbarButton(IDR_GO, IDR_GO_P, IDR_GO_H, 0, L""));
gtk_box_pack_start(GTK_BOX(toolbar_), gtk_label_new(" "), FALSE, FALSE, 0);
@@ -117,8 +118,6 @@ void BrowserToolbarGtk::Init(Profile* profile, GtkAccelGroup* accel_group) {
l10n_util::GetStringF(IDS_APPMENU_TOOLTIP,
l10n_util::GetString(IDS_PRODUCT_NAME))));
app_menu_.reset(new MenuGtk(this, GetStandardAppMenu(), accel_group_));
-
- SetProfile(profile);
}
void BrowserToolbarGtk::AddToolbarToBox(GtkWidget* box) {
@@ -126,12 +125,11 @@ void BrowserToolbarGtk::AddToolbarToBox(GtkWidget* box) {
}
LocationBar* BrowserToolbarGtk::GetLocationBar() const {
- NOTIMPLEMENTED();
- return NULL;
+ return location_bar_.get();
}
void BrowserToolbarGtk::FocusLocationBar() {
- gtk_widget_grab_focus(entry_);
+ location_bar_->FocusLocation();
}
void BrowserToolbarGtk::EnabledStateChangedForCommand(int id, bool enabled) {
@@ -195,16 +193,12 @@ void BrowserToolbarGtk::SetProfile(Profile* profile) {
return;
profile_ = profile;
- // TODO(erg): location_bar_ is a normal gtk text box right now. Change this
- // when we get omnibox support.
- // location_bar_->SetProfile(profile);
+ location_bar_->SetProfile(profile);
}
void BrowserToolbarGtk::UpdateTabContents(TabContents* contents,
bool should_restore_state) {
- // Extract the UTF-8 representation of the URL.
- gtk_entry_set_text(GTK_ENTRY(entry_),
- contents->GetURL().possibly_invalid_spec().c_str());
+ location_bar_->Update(should_restore_state ? contents : NULL);
}
CustomDrawButton* BrowserToolbarGtk::BuildToolbarButton(
@@ -249,45 +243,6 @@ CustomContainerButton* BrowserToolbarGtk::BuildToolbarMenuButton(
}
// static
-void BrowserToolbarGtk::OnEntryActivate(GtkEntry *entry,
- BrowserToolbarGtk* toolbar) {
- GURL dest(URLFixerUpper::FixupURL(std::string(gtk_entry_get_text(entry)),
- std::string()));
- toolbar->browser_->GetSelectedTabContents()->
- OpenURL(dest, GURL(), CURRENT_TAB, PageTransition::TYPED);
-}
-
-// static
-gboolean BrowserToolbarGtk::OnEntryFocus(GtkWidget* widget,
- GtkDirectionType direction,
- BrowserToolbarGtk* host) {
- if (!GTK_WIDGET_HAS_FOCUS(widget)) {
- gtk_widget_grab_focus(widget);
- return TRUE;
- }
-
- return FALSE;
-}
-
-// static
-gboolean BrowserToolbarGtk::OnEntryFocusIn(GtkWidget* widget,
- GdkEventFocus* focus,
- BrowserToolbarGtk* host) {
- // Set the caret at the end of the text.
- gtk_editable_set_position(GTK_EDITABLE(widget), -1);
- return FALSE;
-}
-
-// static
-gboolean BrowserToolbarGtk::OnEntryFocusOut(GtkWidget* widget,
- GdkEventFocus* focus,
- BrowserToolbarGtk* host) {
- // Clear the selected text (if any).
- gtk_editable_set_position(GTK_EDITABLE(widget), 0);
- return FALSE;
-}
-
-// static
void BrowserToolbarGtk::OnButtonClick(GtkWidget* button,
BrowserToolbarGtk* toolbar) {
int tag = -1;
diff --git a/chrome/browser/gtk/browser_toolbar_gtk.h b/chrome/browser/gtk/browser_toolbar_gtk.h
index c943db4..9e854fd 100644
--- a/chrome/browser/gtk/browser_toolbar_gtk.h
+++ b/chrome/browser/gtk/browser_toolbar_gtk.h
@@ -19,6 +19,7 @@ class Browser;
class CustomContainerButton;
class CustomDrawButton;
class LocationBar;
+class LocationBarViewGtk;
class Profile;
class TabContents;
class ToolbarModel;
@@ -83,25 +84,6 @@ class BrowserToolbarGtk : public CommandUpdater::CommandObserver,
unsigned int accelerator,
unsigned int accelerator_mod);
- // Gtk callback for the "activate" signal on the |entry_| widget. Responds to
- // enter.
- static void OnEntryActivate(GtkEntry *entry, BrowserToolbarGtk* toolbar);
-
- // Gtk callback for the "focus" signal on the |entry_| widget.
- static gboolean OnEntryFocus(GtkWidget* widget,
- GtkDirectionType direction,
- BrowserToolbarGtk* host);
-
- // Gtk callback for the "focus-in" signal on the |entry_| widget.
- static gboolean OnEntryFocusIn(GtkWidget* widget,
- GdkEventFocus* focus,
- BrowserToolbarGtk* host);
-
- // Gtk callback for the "focus-out" signal on the |entry_| widget.
- static gboolean OnEntryFocusOut(GtkWidget* widget,
- GdkEventFocus* focus,
- BrowserToolbarGtk* host);
-
// Gtk callback for the "clicked" signal.
static void OnButtonClick(GtkWidget* button, BrowserToolbarGtk* toolbar);
@@ -126,8 +108,8 @@ class BrowserToolbarGtk : public CommandUpdater::CommandObserver,
// Tooltip container for all GTK widgets in this class.
GtkTooltips* toolbar_tooltips_;
- // Our temporary URL bar (until we get the omnibox up).
- GtkWidget* entry_;
+ // The location bar view.
+ scoped_ptr<LocationBarViewGtk> location_bar_;
// A pointer to our window's accelerator list.
GtkAccelGroup* accel_group_;
diff --git a/chrome/browser/gtk/location_bar_view_gtk.cc b/chrome/browser/gtk/location_bar_view_gtk.cc
new file mode 100644
index 0000000..4e97032
--- /dev/null
+++ b/chrome/browser/gtk/location_bar_view_gtk.cc
@@ -0,0 +1,143 @@
+#include "chrome/browser/gtk/location_bar_view_gtk.h"
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "chrome/app/chrome_dll_resource.h"
+#include "chrome/browser/alternate_nav_url_fetcher.h"
+#include "chrome/browser/autocomplete/autocomplete_edit_view_gtk.h"
+#include "chrome/browser/command_updater.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/page_transition_types.h"
+#include "skia/include/SkBitmap.h"
+#include "webkit/glue/window_open_disposition.h"
+
+LocationBarViewGtk::LocationBarViewGtk(CommandUpdater* command_updater,
+ ToolbarModel* toolbar_model)
+ : vbox_(NULL),
+ profile_(NULL),
+ command_updater_(command_updater),
+ toolbar_model_(toolbar_model),
+ disposition_(CURRENT_TAB),
+ transition_(PageTransition::TYPED) {
+}
+
+LocationBarViewGtk::~LocationBarViewGtk(){
+ // TODO(deanm): Should I destroy the widgets here, or leave it up to the
+ // embedder? When the embedder destroys their widget, if we're a child, we
+ // will also get destroyed, so the ownership is kinda unclear.
+}
+
+void LocationBarViewGtk::Init(){
+ edit_view_.reset(new AutocompleteEditViewGtk(this, toolbar_model_, profile_,
+ command_updater_));
+ edit_view_->Init();
+
+ vbox_ = gtk_vbox_new(false, 0);
+
+ // Get the location bar to fit nicely in the toolbar, kinda ugly.
+ static const int kTopPadding = 2;
+ static const int kBottomPadding = 3;
+ GtkWidget* alignment = gtk_alignment_new(0, 0, 1, 1);
+ gtk_alignment_set_padding(GTK_ALIGNMENT(alignment),
+ kTopPadding, kBottomPadding, 0, 0);
+ gtk_container_add(GTK_CONTAINER(alignment), edit_view_->widget());
+
+ gtk_box_pack_start(GTK_BOX(vbox_), alignment, TRUE, TRUE, 0);
+}
+
+void LocationBarViewGtk::SetProfile(Profile* profile) {
+ profile_ = profile;
+}
+
+void LocationBarViewGtk::Update(const TabContents* contents) {
+ edit_view_->Update(contents);
+}
+
+void LocationBarViewGtk::OnAutocompleteAccept(const GURL& url,
+ WindowOpenDisposition disposition,
+ PageTransition::Type transition,
+ const GURL& alternate_nav_url) {
+ if (!url.is_valid())
+ return;
+
+ location_input_ = UTF8ToWide(url.spec());
+ disposition_ = disposition;
+ transition_ = transition;
+
+ if (!command_updater_)
+ return;
+
+ if (!alternate_nav_url.is_valid()) {
+ command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
+ return;
+ }
+
+ scoped_ptr<AlternateNavURLFetcher> fetcher(
+ new AlternateNavURLFetcher(alternate_nav_url));
+ // The AlternateNavURLFetcher will listen for the pending navigation
+ // notification that will be issued as a result of the "open URL." It
+ // will automatically install itself into that navigation controller.
+ command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL);
+ if (fetcher->state() == AlternateNavURLFetcher::NOT_STARTED) {
+ // I'm not sure this should be reachable, but I'm not also sure enough
+ // that it shouldn't to stick in a NOTREACHED(). In any case, this is
+ // harmless; we can simply let the fetcher get deleted here and it will
+ // clean itself up properly.
+ } else {
+ fetcher.release(); // The navigation controller will delete the fetcher.
+ }
+}
+
+void LocationBarViewGtk::OnChanged() {
+ // TODO(deanm): Here is where we would do layout when we have things like
+ // the keyword display, ssl icons, etc.
+}
+
+void LocationBarViewGtk::OnInputInProgress(bool in_progress) {
+ NOTIMPLEMENTED();
+}
+
+SkBitmap LocationBarViewGtk::GetFavIcon() const {
+ NOTIMPLEMENTED();
+ return SkBitmap();
+}
+
+std::wstring LocationBarViewGtk::GetTitle() const {
+ NOTIMPLEMENTED();
+ return std::wstring();
+}
+
+void LocationBarViewGtk::ShowFirstRunBubble(){
+ NOTIMPLEMENTED();
+}
+
+std::wstring LocationBarViewGtk::GetInputString() const{
+ return location_input_;
+}
+
+WindowOpenDisposition LocationBarViewGtk::GetWindowOpenDisposition() const{
+ return disposition_;
+}
+
+PageTransition::Type LocationBarViewGtk::GetPageTransition() const{
+ return transition_;
+}
+
+void LocationBarViewGtk::AcceptInput(){
+ NOTIMPLEMENTED();
+}
+
+void LocationBarViewGtk::FocusLocation(){
+ edit_view_->FocusLocation();
+}
+
+void LocationBarViewGtk::FocusSearch(){
+ NOTIMPLEMENTED();
+}
+
+void LocationBarViewGtk::SaveStateToContents(TabContents* contents){
+ NOTIMPLEMENTED();
+}
diff --git a/chrome/browser/gtk/location_bar_view_gtk.h b/chrome/browser/gtk/location_bar_view_gtk.h
new file mode 100644
index 0000000..50b0775
--- /dev/null
+++ b/chrome/browser/gtk/location_bar_view_gtk.h
@@ -0,0 +1,88 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_GTK_LOCATION_BAR_VIEW_GTK_H_
+#define CHROME_BROWSER_GTK_LOCATION_BAR_VIEW_GTK_H_
+
+#include <gtk/gtk.h>
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "chrome/browser/autocomplete/autocomplete_edit.h"
+#include "chrome/browser/location_bar.h"
+#include "chrome/common/page_transition_types.h"
+#include "webkit/glue/window_open_disposition.h"
+
+class AutocompleteEditViewGtk;
+class CommandUpdater;
+class Profile;
+class SkBitmap;
+class TabContents;
+class ToolbarModel;
+
+class LocationBarViewGtk : public AutocompleteEditController,
+ public LocationBar {
+ public:
+ LocationBarViewGtk(CommandUpdater* command_updater,
+ ToolbarModel* toolbar_model);
+ ~LocationBarViewGtk();
+
+ void Init();
+
+ void SetProfile(Profile* profile);
+
+ // Return the native vbox widget. You must call Init() first, or the result
+ // will be NULL. This is the widget that an embedder should host.
+ GtkWidget* widget() { return vbox_; }
+
+ // Updates the location bar. We also reset the bar's permanent text and
+ // security style, and, if |tab_for_state_restoring| is non-NULL, also
+ // restore saved state that the tab holds.
+ void Update(const TabContents* tab_for_state_restoring);
+
+ // Implement the AutocompleteEditController interface.
+ virtual void OnAutocompleteAccept(const GURL& url,
+ WindowOpenDisposition disposition,
+ PageTransition::Type transition,
+ const GURL& alternate_nav_url);
+ virtual void OnChanged();
+ virtual void OnInputInProgress(bool in_progress);
+ virtual SkBitmap GetFavIcon() const;
+ virtual std::wstring GetTitle() const;
+
+ // Implement the LocationBar interface.
+ virtual void ShowFirstRunBubble();
+ virtual std::wstring GetInputString() const;
+ virtual WindowOpenDisposition GetWindowOpenDisposition() const;
+ virtual PageTransition::Type GetPageTransition() const;
+ virtual void AcceptInput();
+ virtual void FocusLocation();
+ virtual void FocusSearch();
+ virtual void SaveStateToContents(TabContents* contents);
+
+ private:
+ GtkWidget* vbox_;
+
+ scoped_ptr<AutocompleteEditViewGtk> edit_view_;
+
+ Profile* profile_;
+ CommandUpdater* command_updater_;
+ ToolbarModel* toolbar_model_;
+
+ // When we get an OnAutocompleteAccept notification from the autocomplete
+ // edit, we save the input string so we can give it back to the browser on
+ // the LocationBar interface via GetInputString().
+ std::wstring location_input_;
+
+ // The user's desired disposition for how their input should be opened
+ WindowOpenDisposition disposition_;
+
+ // The transition type to use for the navigation
+ PageTransition::Type transition_;
+
+ DISALLOW_COPY_AND_ASSIGN(LocationBarViewGtk);
+};
+
+#endif // CHROME_BROWSER_GTK_LOCATION_BAR_VIEW_GTK_H_