Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(233)

Side by Side Diff: chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc

Issue 151006: Make Linux restore Omnibox contents on tab switch. (Closed)
Patch Set: free string returned by gtk Created 11 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/autocomplete/autocomplete_edit_view_gtk.h" 5 #include "chrome/browser/autocomplete/autocomplete_edit_view_gtk.h"
6 6
7 #include <gtk/gtk.h> 7 #include <gtk/gtk.h>
8 #include <gdk/gdkkeysyms.h> 8 #include <gdk/gdkkeysyms.h>
9 9
10 #include "app/l10n_util.h" 10 #include "app/l10n_util.h"
(...skipping 16 matching lines...) Expand all
27 namespace { 27 namespace {
28 28
29 const char kTextBaseColor[] = "#808080"; 29 const char kTextBaseColor[] = "#808080";
30 const char kSecureSchemeColor[] = "#009614"; 30 const char kSecureSchemeColor[] = "#009614";
31 const char kInsecureSchemeColor[] = "#c80000"; 31 const char kInsecureSchemeColor[] = "#c80000";
32 32
33 size_t GetUTF8Offset(const std::wstring& wide_text, size_t wide_text_offset) { 33 size_t GetUTF8Offset(const std::wstring& wide_text, size_t wide_text_offset) {
34 return WideToUTF8(wide_text.substr(0, wide_text_offset)).size(); 34 return WideToUTF8(wide_text.substr(0, wide_text_offset)).size();
35 } 35 }
36 36
37 // Stores GTK+-specific state so it can be restored after switching tabs.
38 struct ViewState {
39 explicit ViewState(const AutocompleteEditViewGtk::CharRange& selection_range)
40 : selection_range(selection_range) {
41 }
42
43 // Range of selected text.
44 AutocompleteEditViewGtk::CharRange selection_range;
45 };
46
47 struct AutocompleteEditState {
48 AutocompleteEditState(const AutocompleteEditModel::State& model_state,
49 const ViewState& view_state)
50 : model_state(model_state),
51 view_state(view_state) {
52 }
53
54 const AutocompleteEditModel::State model_state;
55 const ViewState view_state;
56 };
57
58 // Returns a lazily initialized property bag accessor for saving our state in a
59 // TabContents.
60 PropertyAccessor<AutocompleteEditState>* GetStateAccessor() {
61 static PropertyAccessor<AutocompleteEditState> state;
62 return &state;
63 }
64
37 } // namespace 65 } // namespace
38 66
39 AutocompleteEditViewGtk::AutocompleteEditViewGtk( 67 AutocompleteEditViewGtk::AutocompleteEditViewGtk(
40 AutocompleteEditController* controller, 68 AutocompleteEditController* controller,
41 ToolbarModel* toolbar_model, 69 ToolbarModel* toolbar_model,
42 Profile* profile, 70 Profile* profile,
43 CommandUpdater* command_updater, 71 CommandUpdater* command_updater,
44 AutocompletePopupPositioner* popup_positioner) 72 AutocompletePopupPositioner* popup_positioner)
45 : text_view_(NULL), 73 : text_view_(NULL),
46 tag_table_(NULL), 74 tag_table_(NULL),
47 text_buffer_(NULL), 75 text_buffer_(NULL),
48 base_tag_(NULL), 76 base_tag_(NULL),
49 secure_scheme_tag_(NULL), 77 secure_scheme_tag_(NULL),
50 insecure_scheme_tag_(NULL), 78 insecure_scheme_tag_(NULL),
51 primary_clipboard_(NULL),
52 model_(new AutocompleteEditModel(this, controller, profile)), 79 model_(new AutocompleteEditModel(this, controller, profile)),
53 popup_view_(new AutocompletePopupViewGtk(this, model_.get(), profile, 80 popup_view_(new AutocompletePopupViewGtk(this, model_.get(), profile,
54 popup_positioner)), 81 popup_positioner)),
55 controller_(controller), 82 controller_(controller),
56 toolbar_model_(toolbar_model), 83 toolbar_model_(toolbar_model),
57 command_updater_(command_updater), 84 command_updater_(command_updater),
58 popup_window_mode_(false), // TODO(deanm) 85 popup_window_mode_(false), // TODO(deanm)
59 scheme_security_level_(ToolbarModel::NORMAL) { 86 scheme_security_level_(ToolbarModel::NORMAL),
87 selection_saved_(false) {
60 model_->set_popup_model(popup_view_->GetModel()); 88 model_->set_popup_model(popup_view_->GetModel());
61 } 89 }
62 90
63 AutocompleteEditViewGtk::~AutocompleteEditViewGtk() { 91 AutocompleteEditViewGtk::~AutocompleteEditViewGtk() {
64 NotificationService::current()->Notify( 92 NotificationService::current()->Notify(
65 NotificationType::AUTOCOMPLETE_EDIT_DESTROYED, 93 NotificationType::AUTOCOMPLETE_EDIT_DESTROYED,
66 Source<AutocompleteEditViewGtk>(this), 94 Source<AutocompleteEditViewGtk>(this),
67 NotificationService::NoDetails()); 95 NotificationService::NoDetails());
68 96
69 // Explicitly teardown members which have a reference to us. Just to be safe 97 // Explicitly teardown members which have a reference to us. Just to be safe
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
138 // signal, but it is very convenient and clean for catching up/down. 166 // signal, but it is very convenient and clean for catching up/down.
139 g_signal_connect(text_view_, "move-cursor", 167 g_signal_connect(text_view_, "move-cursor",
140 G_CALLBACK(&HandleViewMoveCursorThunk), this); 168 G_CALLBACK(&HandleViewMoveCursorThunk), this);
141 // Override the size request. We want to keep the original height request 169 // Override the size request. We want to keep the original height request
142 // from the widget, since that's font dependent. We want to ignore the width 170 // from the widget, since that's font dependent. We want to ignore the width
143 // so we don't force a minimum width based on the text length. 171 // so we don't force a minimum width based on the text length.
144 g_signal_connect(text_view_, "size-request", 172 g_signal_connect(text_view_, "size-request",
145 G_CALLBACK(&HandleViewSizeRequestThunk), this); 173 G_CALLBACK(&HandleViewSizeRequestThunk), this);
146 g_signal_connect(text_view_, "populate-popup", 174 g_signal_connect(text_view_, "populate-popup",
147 G_CALLBACK(&HandlePopulatePopupThunk), this); 175 G_CALLBACK(&HandlePopulatePopupThunk), this);
176 g_signal_connect(text_buffer_, "mark-set",
177 G_CALLBACK(&HandleMarkSetThunk), this);
148 } 178 }
149 179
150 void AutocompleteEditViewGtk::SetFocus() { 180 void AutocompleteEditViewGtk::SetFocus() {
151 gtk_widget_grab_focus(text_view_); 181 gtk_widget_grab_focus(text_view_);
152 } 182 }
153 183
154 void AutocompleteEditViewGtk::SaveStateToTab(TabContents* tab) { 184 void AutocompleteEditViewGtk::SaveStateToTab(TabContents* tab) {
155 NOTIMPLEMENTED(); 185 DCHECK(tab);
186 GetStateAccessor()->SetProperty(
187 tab->property_bag(),
188 AutocompleteEditState(model_->GetStateForTabSwitch(),
189 ViewState(GetSelection())));
190
191 // If any text has been selected, register it as the PRIMARY selection so it
192 // can still be pasted via middle-click after the text view is cleared.
193 if (!selected_text_.empty() && !selection_saved_) {
194 SavePrimarySelection(selected_text_);
195 selection_saved_ = true;
196 }
156 } 197 }
157 198
158 void AutocompleteEditViewGtk::Update(const TabContents* contents) { 199 void AutocompleteEditViewGtk::Update(const TabContents* contents) {
159 // NOTE: We're getting the URL text here from the ToolbarModel. 200 // NOTE: We're getting the URL text here from the ToolbarModel.
160 bool visibly_changed_permanent_text = 201 bool visibly_changed_permanent_text =
161 model_->UpdatePermanentText(toolbar_model_->GetText()); 202 model_->UpdatePermanentText(toolbar_model_->GetText());
162 203
163 ToolbarModel::SecurityLevel security_level = 204 ToolbarModel::SecurityLevel security_level =
164 toolbar_model_->GetSchemeSecurityLevel(); 205 toolbar_model_->GetSchemeSecurityLevel();
165 bool changed_security_level = (security_level != scheme_security_level_); 206 bool changed_security_level = (security_level != scheme_security_level_);
166 scheme_security_level_ = security_level; 207 scheme_security_level_ = security_level;
167 208
168 // TODO(deanm): This doesn't exactly match Windows. There there is a member 209 // TODO(deanm): This doesn't exactly match Windows. There there is a member
169 // background_color_. I think we can get away with just the level though. 210 // background_color_. I think we can get away with just the level though.
170 if (changed_security_level) { 211 if (changed_security_level) {
171 gtk_widget_modify_base(text_view_, GTK_STATE_NORMAL, 212 gtk_widget_modify_base(text_view_, GTK_STATE_NORMAL,
172 &LocationBarViewGtk::kBackgroundColorByLevel[security_level]); 213 &LocationBarViewGtk::kBackgroundColorByLevel[security_level]);
173 } 214 }
174 215
175 if (contents) { 216 if (contents) {
217 selected_text_.clear();
218 selection_saved_ = false;
176 RevertAll(); 219 RevertAll();
177 // TODO(deanm): Tab switching. The Windows code puts some state in a 220 const AutocompleteEditState* state =
178 // PropertyBag on the tab contents, and restores state from there. 221 GetStateAccessor()->GetProperty(contents->property_bag());
222 if (state) {
223 model_->RestoreState(state->model_state);
224
225 // Move the marks for the cursor and the other end of the selection to
226 // the previously-saved offsets.
227 GtkTextIter selection_iter, insert_iter;
228 ItersFromCharRange(
229 state->view_state.selection_range, &selection_iter, &insert_iter);
230 // TODO(derat): Restore the selection range instead of just the cursor
231 // ("insert") position. This in itself is trivial to do using
232 // gtk_text_buffer_select_range(), but then it also becomes necessary to
233 // invalidate hidden tabs' saved ranges when another tab or another app
234 // takes the selection, lest we incorrectly regrab a stale selection when
235 // a hidden tab is later shown.
236 gtk_text_buffer_place_cursor(text_buffer_, &insert_iter);
237 }
179 } else if (visibly_changed_permanent_text) { 238 } else if (visibly_changed_permanent_text) {
180 RevertAll(); 239 RevertAll();
181 // TODO(deanm): There should be code to restore select all here. 240 // TODO(deanm): There should be code to restore select all here.
182 } else if (changed_security_level) { 241 } else if (changed_security_level) {
183 EmphasizeURLComponents(); 242 EmphasizeURLComponents();
184 } 243 }
185 } 244 }
186 245
187 void AutocompleteEditViewGtk::OpenURL(const GURL& url, 246 void AutocompleteEditViewGtk::OpenURL(const GURL& url,
188 WindowOpenDisposition disposition, 247 WindowOpenDisposition disposition,
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 // TODO(deanm): Ignoring save_original_selection here, etc. 347 // TODO(deanm): Ignoring save_original_selection here, etc.
289 SetWindowTextAndCaretPos(display_text, display_text.length()); 348 SetWindowTextAndCaretPos(display_text, display_text.length());
290 TextChanged(); 349 TextChanged();
291 } 350 }
292 351
293 bool AutocompleteEditViewGtk::OnInlineAutocompleteTextMaybeChanged( 352 bool AutocompleteEditViewGtk::OnInlineAutocompleteTextMaybeChanged(
294 const std::wstring& display_text, 353 const std::wstring& display_text,
295 size_t user_text_length) { 354 size_t user_text_length) {
296 if (display_text == GetText()) 355 if (display_text == GetText())
297 return false; 356 return false;
298 357
299 // We need to get the clipboard while it's attached to the toplevel. The 358 // We need to get the clipboard while it's attached to the toplevel. The
300 // easiest thing to do is just to lazily pull the clipboard here. 359 // easiest thing to do is just to lazily pull the clipboard here.
301 if (primary_clipboard_ == NULL) { 360 GtkClipboard* clipboard =
302 primary_clipboard_ = gtk_widget_get_clipboard(text_view_, 361 gtk_widget_get_clipboard(text_view_, GDK_SELECTION_PRIMARY);
303 GDK_SELECTION_PRIMARY); 362 DCHECK(clipboard);
304 } 363 if (!clipboard)
364 return true;
305 365
306 // Remove the PRIMARY clipboard to avoid having "clipboard helpers" like 366 // Remove the PRIMARY clipboard to avoid having "clipboard helpers" like
307 // klipper and glipper race with / remove our inline autocomplete selection. 367 // klipper and glipper race with / remove our inline autocomplete selection.
308 gtk_text_buffer_remove_selection_clipboard(text_buffer_, primary_clipboard_); 368 gtk_text_buffer_remove_selection_clipboard(text_buffer_, clipboard);
309 SetWindowTextAndCaretPos(display_text, 0); 369 SetWindowTextAndCaretPos(display_text, 0);
310 370
311 // Select the part of the text that was inline autocompleted. 371 // Select the part of the text that was inline autocompleted.
312 GtkTextIter bound, insert; 372 GtkTextIter bound, insert;
313 gtk_text_buffer_get_bounds(text_buffer_, &insert, &bound); 373 gtk_text_buffer_get_bounds(text_buffer_, &insert, &bound);
314 gtk_text_buffer_get_iter_at_offset(text_buffer_, &insert, user_text_length); 374 gtk_text_buffer_get_iter_at_offset(text_buffer_, &insert, user_text_length);
315 gtk_text_buffer_select_range(text_buffer_, &insert, &bound); 375 gtk_text_buffer_select_range(text_buffer_, &insert, &bound);
316 376
317 TextChanged(); 377 TextChanged();
318 // Put the PRIMARY clipboard back, so that selection still somewhat works. 378 // Put the PRIMARY clipboard back, so that selection still somewhat works.
319 gtk_text_buffer_add_selection_clipboard(text_buffer_, primary_clipboard_); 379 gtk_text_buffer_add_selection_clipboard(text_buffer_, clipboard);
320 380
321 return true; 381 return true;
322 } 382 }
323 383
324 void AutocompleteEditViewGtk::OnRevertTemporaryText() { 384 void AutocompleteEditViewGtk::OnRevertTemporaryText() {
325 NOTIMPLEMENTED(); 385 NOTIMPLEMENTED();
326 } 386 }
327 387
328 void AutocompleteEditViewGtk::OnBeforePossibleChange() { 388 void AutocompleteEditViewGtk::OnBeforePossibleChange() {
329 // Record our state. 389 // Record our state.
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
442 // clicked handling code. If we were to try to set the selection from 502 // clicked handling code. If we were to try to set the selection from
443 // the focus-in event, it's just going to be undone by the click handler. 503 // the focus-in event, it's just going to be undone by the click handler.
444 // This is a bit ugly. We shim in to get the click before the GtkTextView, 504 // This is a bit ugly. We shim in to get the click before the GtkTextView,
445 // then if we don't have focus, we (hopefully safely) assume that the click 505 // then if we don't have focus, we (hopefully safely) assume that the click
446 // will cause us to become focused. We call GtkTextView's default handler 506 // will cause us to become focused. We call GtkTextView's default handler
447 // and then stop propagation. This allows us to run our code after the 507 // and then stop propagation. This allows us to run our code after the
448 // default handler, even if that handler stopped propagation. 508 // default handler, even if that handler stopped propagation.
449 if (GTK_WIDGET_HAS_FOCUS(text_view_)) 509 if (GTK_WIDGET_HAS_FOCUS(text_view_))
450 return FALSE; // Continue to propagate into the GtkTextView handler. 510 return FALSE; // Continue to propagate into the GtkTextView handler.
451 511
512 // We only want to select everything on left-click; otherwise we'll end up
513 // stealing the PRIMARY selection when the user middle-clicks to paste it
514 // here.
515 if (event->button != 1)
516 return FALSE;
517
452 // Call the GtkTextView default handler, ignoring the fact that it will 518 // Call the GtkTextView default handler, ignoring the fact that it will
453 // likely have told us to stop propagating. We want to handle selection. 519 // likely have told us to stop propagating. We want to handle selection.
454 GtkWidgetClass* klass = GTK_WIDGET_GET_CLASS(text_view_); 520 GtkWidgetClass* klass = GTK_WIDGET_GET_CLASS(text_view_);
455 klass->button_press_event(text_view_, event); 521 klass->button_press_event(text_view_, event);
456 522
457 // Select the full input when we get focus. 523 // Select the full input when we get focus.
458 SelectAll(false); 524 SelectAll(false);
459 // So we told the buffer where the cursor should be, but make sure to tell 525 // So we told the buffer where the cursor should be, but make sure to tell
460 // the view so it can scroll it to be visible if needed. 526 // the view so it can scroll it to be visible if needed.
461 // NOTE: This function doesn't seem to like a count of 0, looking at the 527 // NOTE: This function doesn't seem to like a count of 0, looking at the
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
538 gtk_clipboard_request_text(x_clipboard, HandlePasteAndGoReceivedTextThunk, 604 gtk_clipboard_request_text(x_clipboard, HandlePasteAndGoReceivedTextThunk,
539 this); 605 this);
540 } 606 }
541 607
542 void AutocompleteEditViewGtk::HandlePasteAndGoReceivedText( 608 void AutocompleteEditViewGtk::HandlePasteAndGoReceivedText(
543 const std::wstring& text) { 609 const std::wstring& text) {
544 if (model_->CanPasteAndGo(text)) 610 if (model_->CanPasteAndGo(text))
545 model_->PasteAndGo(); 611 model_->PasteAndGo();
546 } 612 }
547 613
614 void AutocompleteEditViewGtk::HandleMarkSet(GtkTextBuffer* buffer,
615 GtkTextIter* location,
616 GtkTextMark* mark) {
617 if (!text_buffer_ || buffer != text_buffer_)
618 return;
619
620 if (mark != gtk_text_buffer_get_insert(text_buffer_) &&
621 mark != gtk_text_buffer_get_selection_bound(text_buffer_)) {
622 return;
623 }
624
625 // Is no text selected in the GtkTextView?
626 bool no_text_selected = false;
627
628 // Get the currently-selected text, if there is any.
629 GtkTextIter start, end;
630 if (!gtk_text_buffer_get_selection_bounds(text_buffer_, &start, &end)) {
631 no_text_selected = true;
632 } else {
633 gchar* text = gtk_text_iter_get_text(&start, &end);
634 size_t text_len = strlen(text);
635 if (!text_len) {
636 no_text_selected = true;
637 } else {
638 selected_text_ = std::string(text, text_len);
639 selection_saved_ = false;
640 }
641 g_free(text);
642 }
643
644 // If we have some previously-selected text but it's no longer highlighted
645 // and we haven't saved it as the selection yet, we save it now.
646 if (!selected_text_.empty() && no_text_selected && !selection_saved_) {
647 SavePrimarySelection(selected_text_);
648 selection_saved_ = true;
649 }
650 }
651
548 AutocompleteEditViewGtk::CharRange AutocompleteEditViewGtk::GetSelection() { 652 AutocompleteEditViewGtk::CharRange AutocompleteEditViewGtk::GetSelection() {
549 // You can not just use get_selection_bounds here, since the order will be 653 // You can not just use get_selection_bounds here, since the order will be
550 // ascending, and you don't know where the user's start and end of the 654 // ascending, and you don't know where the user's start and end of the
551 // selection was (if the selection was forwards or backwards). Get the 655 // selection was (if the selection was forwards or backwards). Get the
552 // actual marks so that we can preserve the selection direction. 656 // actual marks so that we can preserve the selection direction.
553 GtkTextIter start, insert; 657 GtkTextIter start, insert;
554 GtkTextMark* mark; 658 GtkTextMark* mark;
555 659
556 mark = gtk_text_buffer_get_selection_bound(text_buffer_); 660 mark = gtk_text_buffer_get_selection_bound(text_buffer_);
557 gtk_text_buffer_get_iter_at_mark(text_buffer_, &start, mark); 661 gtk_text_buffer_get_iter_at_mark(text_buffer_, &start, mark);
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
628 gtk_text_buffer_apply_tag(text_buffer_, insecure_scheme_tag_, 732 gtk_text_buffer_apply_tag(text_buffer_, insecure_scheme_tag_,
629 &start, &end); 733 &start, &end);
630 } 734 }
631 } 735 }
632 } 736 }
633 737
634 void AutocompleteEditViewGtk::TextChanged() { 738 void AutocompleteEditViewGtk::TextChanged() {
635 EmphasizeURLComponents(); 739 EmphasizeURLComponents();
636 controller_->OnChanged(); 740 controller_->OnChanged();
637 } 741 }
742
743 void AutocompleteEditViewGtk::SavePrimarySelection(
744 const std::string& selected_text) {
745 GtkClipboard* clipboard =
746 gtk_widget_get_clipboard(text_view_, GDK_SELECTION_PRIMARY);
747 DCHECK(clipboard);
748 if (!clipboard)
749 return;
750
751 gtk_clipboard_set_text(
752 clipboard, selected_text.data(), selected_text.size());
753 }
OLDNEW
« no previous file with comments | « chrome/browser/autocomplete/autocomplete_edit_view_gtk.h ('k') | chrome/browser/gtk/location_bar_view_gtk.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698