summaryrefslogtreecommitdiffstats
path: root/chrome/browser/autocomplete
diff options
context:
space:
mode:
authorestade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-14 19:53:13 +0000
committerestade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-14 19:53:13 +0000
commit6de627262d774f26056ea431a9ce4eacdbc05be0 (patch)
treee431cee7793176d4122ab41e36451194d348cc19 /chrome/browser/autocomplete
parent981268b70dab10093c3ca08fabe1d2ecb56744cc (diff)
downloadchromium_src-6de627262d774f26056ea431a9ce4eacdbc05be0.zip
chromium_src-6de627262d774f26056ea431a9ce4eacdbc05be0.tar.gz
chromium_src-6de627262d774f26056ea431a9ce4eacdbc05be0.tar.bz2
GTK: make the primary selection include the url's scheme when an entire URL is selected.
sometimes the scheme will be hidden, which is the reason we need this workaround. BUG=41173 TEST=manual Review URL: http://codereview.chromium.org/1638007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@44519 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/autocomplete')
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc108
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_gtk.h26
2 files changed, 115 insertions, 19 deletions
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc
index e193736..ea49b8e 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc
@@ -46,6 +46,8 @@ using gfx::SkColorToGdkColor;
namespace {
+const gchar* kAutocompleteEditViewGtkKey = "__ACE_VIEW_GTK__";
+
const char kTextBaseColor[] = "#808080";
const char kEVSecureSchemeColor[] = "#079500";
const char kSecureSchemeColor[] = "#000e95";
@@ -110,6 +112,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(
@@ -195,6 +217,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);
@@ -270,6 +293,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",
@@ -330,9 +355,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(
@@ -1050,11 +1074,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(
@@ -1191,18 +1236,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);
@@ -1210,16 +1251,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_);
+}
+
+void AutocompleteEditViewGtk::OwnPrimarySelection(const std::string& text) {
+ primary_selection_text_ = 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);
+ 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) {
@@ -1307,6 +1359,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() {
@@ -1318,6 +1371,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() {
@@ -1483,3 +1537,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());
+}
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h
index 6dc5bea..22ea93e 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h
@@ -141,6 +141,9 @@ class AutocompleteEditViewGtk : public AutocompleteEditView,
GtkTextBuffer*);
CHROMEG_CALLBACK_2(AutocompleteEditViewGtk, void, HandleMarkSet,
GtkTextBuffer*, GtkTextIter*, GtkTextMark*);
+ // As above, but called after the default handler.
+ CHROMEG_CALLBACK_2(AutocompleteEditViewGtk, void, HandleMarkSetAfter,
+ GtkTextBuffer*, GtkTextIter*, GtkTextMark*);
CHROMEG_CALLBACK_3(AutocompleteEditViewGtk, void, HandleInsertText,
GtkTextBuffer*, GtkTextIter*, const gchar*, gint);
CHROMEG_CALLBACK_0(AutocompleteEditViewGtk, void,
@@ -179,6 +182,20 @@ class AutocompleteEditViewGtk : public AutocompleteEditView,
CHROMEGTK_CALLBACK_1(AutocompleteEditViewGtk, void,
HandleWidgetDirectionChanged, GtkTextDirection);
+ // Callback for the PRIMARY selection clipboard.
+ static void ClipboardGetSelectionThunk(GtkClipboard* clipboard,
+ GtkSelectionData* selection_data,
+ guint info,
+ gpointer object);
+ void ClipboardGetSelection(GtkClipboard* clipboard,
+ GtkSelectionData* selection_data,
+ guint info);
+
+ // Take control of the PRIMARY selection clipboard with |text|. Use
+ // |text_buffer_| as the owner, so that this doesn't remove the selection on
+ // it. This makes use of the above callbacks.
+ void OwnPrimarySelection(const std::string& text);
+
// Gets the GTK_TEXT_WINDOW_WIDGET coordinates for |text_view_| that bound the
// given iters.
gfx::Rect WindowBoundsFromIters(GtkTextIter* iter1, GtkTextIter* iter2);
@@ -216,7 +233,8 @@ class AutocompleteEditViewGtk : public AutocompleteEditView,
// Internally invoked whenever the text changes in some way.
void TextChanged();
- // Save |selected_text| as the PRIMARY X selection.
+ // Save |selected_text| as the PRIMARY X selection. Unlike
+ // OwnPrimarySelection(), this won't set an owner or use callbacks.
void SavePrimarySelection(const std::string& selected_text);
// Update the field with |text| and set the selection.
@@ -280,8 +298,12 @@ class AutocompleteEditViewGtk : public AutocompleteEditView,
// it, we pass this string to SavePrimarySelection()).
std::string selected_text_;
- // ID of the signal handler for "mark-set" on |text_buffer_|.
+ // When we own the X clipboard, this is the text for it.
+ std::string primary_selection_text_;
+
+ // IDs of the signal handlers for "mark-set" on |text_buffer_|.
gulong mark_set_handler_id_;
+ gulong mark_set_handler_id2_;
#if defined(OS_CHROMEOS)
// The following variables are used to implement select-all-on-mouse-up, which