summaryrefslogtreecommitdiffstats
path: root/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc')
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc199
1 files changed, 142 insertions, 57 deletions
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc
index 86d886d..006395f 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc
@@ -17,7 +17,6 @@
#include "chrome/app/chrome_dll_resource.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/browser_process.h"
#include "chrome/browser/command_updater.h"
#include "chrome/browser/defaults.h"
@@ -34,9 +33,11 @@
#include "net/base/escape.h"
#if defined(TOOLKIT_VIEWS)
+#include "chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h"
#include "chrome/browser/views/location_bar_view.h"
#include "gfx/skia_utils_gtk.h"
#else
+#include "chrome/browser/autocomplete/autocomplete_popup_view_gtk.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/location_bar_view_gtk.h"
#endif
@@ -45,11 +46,13 @@ using gfx::SkColorToGdkColor;
namespace {
+const gchar* kAutocompleteEditViewGtkKey = "__ACE_VIEW_GTK__";
+
const char kTextBaseColor[] = "#808080";
-const char kSecureSchemeColor[] = "#009614";
-const char kInsecureSchemeColor[] = "#c80000";
+const char kSecureSchemeColor[] = "#079500";
+const char kSecurityErrorSchemeColor[] = "#a20000";
-const double kStrikethroughStrokeRed = 210.0 / 256.0;
+const double kStrikethroughStrokeRed = 162.0 / 256.0;
const double kStrikethroughStrokeWidth = 2.0;
size_t GetUTF8Offset(const std::wstring& wide_text, size_t wide_text_offset) {
@@ -108,6 +111,26 @@ void SetEntryStyle() {
"style \"chrome-location-bar-entry\"");
}
+// Copied from GTK+. Called when we lose the primary selection. This will clear
+// the selection in the text buffer.
+void ClipboardSelectionCleared(GtkClipboard* clipboard,
+ gpointer data) {
+ GtkTextIter insert;
+ GtkTextIter selection_bound;
+ GtkTextBuffer* buffer = GTK_TEXT_BUFFER(data);
+
+ gtk_text_buffer_get_iter_at_mark(buffer, &insert,
+ gtk_text_buffer_get_insert(buffer));
+ gtk_text_buffer_get_iter_at_mark(buffer, &selection_bound,
+ gtk_text_buffer_get_selection_bound(buffer));
+
+ if (!gtk_text_iter_equal(&insert, &selection_bound)) {
+ gtk_text_buffer_move_mark(buffer,
+ gtk_text_buffer_get_selection_bound(buffer),
+ &insert);
+ }
+}
+
} // namespace
AutocompleteEditViewGtk::AutocompleteEditViewGtk(
@@ -116,23 +139,30 @@ AutocompleteEditViewGtk::AutocompleteEditViewGtk(
Profile* profile,
CommandUpdater* command_updater,
bool popup_window_mode,
- const BubblePositioner* bubble_positioner)
+#if defined(TOOLKIT_VIEWS)
+ const views::View* location_bar)
+#else
+ GtkWidget* location_bar)
+#endif
: text_view_(NULL),
tag_table_(NULL),
text_buffer_(NULL),
faded_text_tag_(NULL),
secure_scheme_tag_(NULL),
- insecure_scheme_tag_(NULL),
+ security_error_scheme_tag_(NULL),
model_(new AutocompleteEditModel(this, controller, profile)),
- popup_view_(AutocompletePopupView::CreatePopupView(gfx::Font(), this,
- model_.get(),
- profile,
- bubble_positioner)),
+#if defined(TOOLKIT_VIEWS)
+ popup_view_(new AutocompletePopupContentsView(
+ gfx::Font(), this, model_.get(), profile, location_bar)),
+#else
+ popup_view_(new AutocompletePopupViewGtk(this, model_.get(), profile,
+ location_bar)),
+#endif
controller_(controller),
toolbar_model_(toolbar_model),
command_updater_(command_updater),
popup_window_mode_(popup_window_mode),
- scheme_security_level_(ToolbarModel::NORMAL),
+ security_level_(ToolbarModel::NONE),
mark_set_handler_id_(0),
#if defined(OS_CHROMEOS)
button_1_pressed_(false),
@@ -185,6 +215,7 @@ void AutocompleteEditViewGtk::Init() {
// the other objects adds a reference; it doesn't adopt them.
tag_table_ = gtk_text_tag_table_new();
text_buffer_ = gtk_text_buffer_new(tag_table_);
+ g_object_set_data(G_OBJECT(text_buffer_), kAutocompleteEditViewGtkKey, this);
text_view_ = gtk_text_view_new_with_buffer(text_buffer_);
if (popup_window_mode_)
gtk_text_view_set_editable(GTK_TEXT_VIEW(text_view_), false);
@@ -215,8 +246,8 @@ void AutocompleteEditViewGtk::Init() {
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);
+ security_error_scheme_tag_ = gtk_text_buffer_create_tag(text_buffer_,
+ NULL, "foreground", kSecurityErrorSchemeColor, NULL);
normal_text_tag_ = gtk_text_buffer_create_tag(text_buffer_,
NULL, "foreground", "#000000", NULL);
@@ -258,6 +289,8 @@ void AutocompleteEditViewGtk::Init() {
G_CALLBACK(&HandlePopulatePopupThunk), this);
mark_set_handler_id_ = g_signal_connect(
text_buffer_, "mark-set", G_CALLBACK(&HandleMarkSetThunk), this);
+ mark_set_handler_id2_ = g_signal_connect_after(
+ text_buffer_, "mark-set", G_CALLBACK(&HandleMarkSetAfterThunk), this);
g_signal_connect(text_view_, "drag-data-received",
G_CALLBACK(&HandleDragDataReceivedThunk), this);
g_signal_connect(text_view_, "backspace",
@@ -284,7 +317,7 @@ void AutocompleteEditViewGtk::Init() {
SetBaseColor();
#endif
- ViewIDUtil::SetID(widget(), VIEW_ID_AUTOCOMPLETE);
+ ViewIDUtil::SetID(GetNativeView(), VIEW_ID_AUTOCOMPLETE);
}
void AutocompleteEditViewGtk::SetFocus() {
@@ -318,9 +351,8 @@ void AutocompleteEditViewGtk::SaveStateToTab(TabContents* tab) {
DCHECK(tab);
// If any text has been selected, register it as the PRIMARY selection so it
// can still be pasted via middle-click after the text view is cleared.
- if (!selected_text_.empty()) {
+ if (!selected_text_.empty())
SavePrimarySelection(selected_text_);
- }
// NOTE: GetStateForTabSwitch may affect GetSelection, so order is important.
AutocompleteEditModel::State model_state = model_->GetStateForTabSwitch();
GetStateAccessor()->SetProperty(
@@ -334,15 +366,9 @@ void AutocompleteEditViewGtk::Update(const TabContents* contents) {
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;
-
- // TODO(deanm): This doesn't exactly match Windows. There there is a member
- // background_color_. I think we can get away with just the level though.
- if (changed_security_level) {
- SetBaseColor();
- }
+ toolbar_model_->GetSecurityLevel();
+ bool changed_security_level = (security_level != security_level_);
+ security_level_ = security_level;
if (contents) {
selected_text_.clear();
@@ -392,6 +418,17 @@ std::wstring AutocompleteEditViewGtk::GetText() const {
return out;
}
+bool AutocompleteEditViewGtk::IsEditingOrEmpty() const {
+ return model_->user_input_in_progress() ||
+ (gtk_text_buffer_get_char_count(text_buffer_) == 0);
+}
+
+int AutocompleteEditViewGtk::GetIcon() const {
+ return IsEditingOrEmpty() ?
+ AutocompleteMatch::TypeToIcon(model_->CurrentTextType()) :
+ toolbar_model_->GetIcon();
+}
+
void AutocompleteEditViewGtk::SetUserText(const std::wstring& text,
const std::wstring& display_text,
bool update_popup) {
@@ -582,10 +619,8 @@ void AutocompleteEditViewGtk::SetBaseColor() {
bool use_gtk = theme_provider_->UseGtkTheme();
#endif
- // If we're on a secure connection, ignore what the theme wants us to do
- // and use a yellow background.
- bool is_secure = (scheme_security_level_ == ToolbarModel::SECURE);
- if (use_gtk && !is_secure) {
+ if (use_gtk) {
+ gtk_widget_modify_cursor(text_view_, NULL, NULL);
gtk_widget_modify_base(text_view_, GTK_STATE_NORMAL, NULL);
gtk_widget_modify_base(text_view_, GTK_STATE_SELECTED, NULL);
gtk_widget_modify_text(text_view_, GTK_STATE_SELECTED, NULL);
@@ -600,20 +635,21 @@ void AutocompleteEditViewGtk::SetBaseColor() {
GdkColor average_color = gtk_util::AverageColors(
style->text[GTK_STATE_NORMAL], style->base[GTK_STATE_NORMAL]);
- g_object_set(faded_text_tag_, "foreground-gdk",
- &average_color, NULL);
+ g_object_set(faded_text_tag_, "foreground-gdk", &average_color, NULL);
g_object_set(normal_text_tag_, "foreground-gdk",
&style->text[GTK_STATE_NORMAL], NULL);
} else {
+ const GdkColor* background_color_ptr;
#if defined(TOOLKIT_VIEWS)
const GdkColor background_color = gfx::SkColorToGdkColor(
- LocationBarView::GetColor(is_secure, LocationBarView::BACKGROUND));
- gtk_widget_modify_base(text_view_, GTK_STATE_NORMAL,
- &background_color);
+ LocationBarView::GetColor(ToolbarModel::NONE,
+ LocationBarView::BACKGROUND));
+ background_color_ptr = &background_color;
#else
- gtk_widget_modify_base(text_view_, GTK_STATE_NORMAL,
- &LocationBarViewGtk::kBackgroundColorByLevel[scheme_security_level_]);
+ background_color_ptr = &LocationBarViewGtk::kBackgroundColor;
#endif
+ gtk_widget_modify_cursor(text_view_, &gfx::kGdkBlack, &gfx::kGdkGray);
+ gtk_widget_modify_base(text_view_, GTK_STATE_NORMAL, background_color_ptr);
#if !defined(TOOLKIT_VIEWS)
// Override the selected colors so we don't leak colors from the current
@@ -1037,11 +1073,32 @@ void AutocompleteEditViewGtk::HandleMarkSet(GtkTextBuffer* buffer,
GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
if (gtk_clipboard_get_owner(clipboard) == G_OBJECT(text_buffer_))
SavePrimarySelection(selected_text_);
+ } else if (IsSelectAll() && !model_->user_input_in_progress()) {
+ // Copy the whole URL to the clipboard (including the scheme, which is
+ // hidden in the case of http://).
+ GURL url;
+ if (model_->GetURLForText(GetText(), &url))
+ OwnPrimarySelection(url.spec());
}
selected_text_ = new_selected_text;
}
+// Override the primary selection the text buffer has set. This has to happen
+// after the default handler for the "mark-set" signal.
+void AutocompleteEditViewGtk::HandleMarkSetAfter(GtkTextBuffer* buffer,
+ GtkTextIter* location,
+ GtkTextMark* mark) {
+ std::wstring text = GetText();
+ if (IsSelectAll() && !model_->user_input_in_progress() && !text.empty()) {
+ // Copy the whole URL to the clipboard (including the scheme, which is
+ // hidden in the case of http://).
+ GURL url;
+ if (model_->GetURLForText(GetText(), &url))
+ OwnPrimarySelection(url.spec());
+ }
+}
+
// Just use the default behavior for DnD, except if the drop can be a PasteAndGo
// then override.
void AutocompleteEditViewGtk::HandleDragDataReceived(
@@ -1178,18 +1235,14 @@ void AutocompleteEditViewGtk::HandleCopyOrCutClipboard(GtkWidget* sender) {
// string to avoid encoding and escaping issues when pasting this text
// elsewhere.
scw.WriteText(url_spec16);
+ OwnPrimarySelection(url.spec());
} else {
scw.WriteText(text16);
+ OwnPrimarySelection(UTF16ToUTF8(text16));
}
scw.WriteHyperlink(UTF16ToUTF8(EscapeForHTML(text16)), url.spec());
- // Update PRIMARY selection if it is not owned by the text_buffer.
- if (gtk_clipboard_get_owner(clipboard) != G_OBJECT(text_buffer_)) {
- std::string utf8_text(UTF16ToUTF8(text16));
- gtk_clipboard_set_text(clipboard, utf8_text.c_str(), utf8_text.length());
- }
-
// Stop propagating the signal.
static guint signal_id =
g_signal_lookup("copy-clipboard", GTK_TYPE_TEXT_VIEW);
@@ -1197,16 +1250,27 @@ void AutocompleteEditViewGtk::HandleCopyOrCutClipboard(GtkWidget* sender) {
return;
}
- // Passing gtk_text_buffer_copy_clipboard() a text buffer that already owns
- // the clipboard that's being updated clears the highlighted text, which we
- // don't want to do (and it also appears to at least sometimes trigger a
- // failed G_IS_OBJECT() assertion).
- if (gtk_clipboard_get_owner(clipboard) == G_OBJECT(text_buffer_))
- return;
+ OwnPrimarySelection(selected_text_);
+}
- // We can't just call SavePrimarySelection(); that makes the text view lose
- // the selection and unhighlight its text.
- gtk_text_buffer_copy_clipboard(text_buffer_, clipboard);
+void AutocompleteEditViewGtk::OwnPrimarySelection(const std::string& text) {
+ primary_selection_text_ = text;
+
+ GtkTargetList* list = gtk_target_list_new(NULL, 0);
+ gtk_target_list_add_text_targets(list, 0);
+ gint len;
+ GtkTargetEntry* entries = gtk_target_table_new_from_list(list, &len);
+
+ // When |text_buffer_| is destroyed, it will clear the clipboard, hence
+ // we needn't worry about calling gtk_clipboard_clear().
+ gtk_clipboard_set_with_owner(gtk_clipboard_get(GDK_SELECTION_PRIMARY),
+ entries, len,
+ ClipboardGetSelectionThunk,
+ ClipboardSelectionCleared,
+ G_OBJECT(text_buffer_));
+
+ gtk_target_list_unref(list);
+ gtk_target_table_free(entries, len);
}
void AutocompleteEditViewGtk::HandlePasteClipboard(GtkWidget* sender) {
@@ -1294,6 +1358,7 @@ void AutocompleteEditViewGtk::StartUpdatingHighlightedText() {
gtk_text_buffer_remove_selection_clipboard(text_buffer_, clipboard);
}
g_signal_handler_block(text_buffer_, mark_set_handler_id_);
+ g_signal_handler_block(text_buffer_, mark_set_handler_id2_);
}
void AutocompleteEditViewGtk::FinishUpdatingHighlightedText() {
@@ -1305,6 +1370,7 @@ void AutocompleteEditViewGtk::FinishUpdatingHighlightedText() {
gtk_text_buffer_add_selection_clipboard(text_buffer_, clipboard);
}
g_signal_handler_unblock(text_buffer_, mark_set_handler_id_);
+ g_signal_handler_unblock(text_buffer_, mark_set_handler_id2_);
}
AutocompleteEditViewGtk::CharRange AutocompleteEditViewGtk::GetSelection() {
@@ -1374,22 +1440,21 @@ void AutocompleteEditViewGtk::EmphasizeURLComponents() {
strikethrough_ = CharRange();
// Emphasize the scheme for security UI display purposes (if necessary).
if (!model_->user_input_in_progress() && scheme.is_nonempty() &&
- (scheme_security_level_ != ToolbarModel::NORMAL)) {
+ (security_level_ != ToolbarModel::NONE)) {
CharRange scheme_range = CharRange(GetUTF8Offset(text, scheme.begin),
GetUTF8Offset(text, scheme.end()));
ItersFromCharRange(scheme_range, &start, &end);
- if (scheme_security_level_ == ToolbarModel::SECURE) {
- gtk_text_buffer_apply_tag(text_buffer_, secure_scheme_tag_,
- &start, &end);
- } else {
+ if (security_level_ == ToolbarModel::SECURITY_ERROR) {
strikethrough_ = scheme_range;
// When we draw the strikethrough, we don't want to include the ':' at the
// end of the scheme.
strikethrough_.cp_max--;
- gtk_text_buffer_apply_tag(text_buffer_, insecure_scheme_tag_,
+ gtk_text_buffer_apply_tag(text_buffer_, security_error_scheme_tag_,
&start, &end);
+ } else {
+ gtk_text_buffer_apply_tag(text_buffer_, secure_scheme_tag_, &start, &end);
}
}
}
@@ -1469,3 +1534,23 @@ void AutocompleteEditViewGtk::HandleWidgetDirectionChanged(
void AutocompleteEditViewGtk::HandleKeymapDirectionChanged(GdkKeymap* sender) {
AdjustTextJustification();
}
+
+// static
+void AutocompleteEditViewGtk::ClipboardGetSelectionThunk(
+ GtkClipboard* clipboard,
+ GtkSelectionData* selection_data,
+ guint info,
+ gpointer object) {
+ AutocompleteEditViewGtk* edit_view =
+ reinterpret_cast<AutocompleteEditViewGtk*>(
+ g_object_get_data(G_OBJECT(object), kAutocompleteEditViewGtkKey));
+ edit_view->ClipboardGetSelection(clipboard, selection_data, info);
+}
+
+void AutocompleteEditViewGtk::ClipboardGetSelection(
+ GtkClipboard* clipboard,
+ GtkSelectionData* selection_data,
+ guint info) {
+ gtk_selection_data_set_text(selection_data, primary_selection_text_.c_str(),
+ primary_selection_text_.size());
+}