OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 <algorithm> | 10 #include <algorithm> |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 const views::View* location_bar) | 143 const views::View* location_bar) |
144 #else | 144 #else |
145 GtkWidget* location_bar) | 145 GtkWidget* location_bar) |
146 #endif | 146 #endif |
147 : text_view_(NULL), | 147 : text_view_(NULL), |
148 tag_table_(NULL), | 148 tag_table_(NULL), |
149 text_buffer_(NULL), | 149 text_buffer_(NULL), |
150 faded_text_tag_(NULL), | 150 faded_text_tag_(NULL), |
151 secure_scheme_tag_(NULL), | 151 secure_scheme_tag_(NULL), |
152 security_error_scheme_tag_(NULL), | 152 security_error_scheme_tag_(NULL), |
| 153 normal_text_tag_(NULL), |
| 154 instant_anchor_tag_(NULL), |
| 155 instant_view_(NULL), |
| 156 instant_mark_(NULL), |
153 model_(new AutocompleteEditModel(this, controller, profile)), | 157 model_(new AutocompleteEditModel(this, controller, profile)), |
154 #if defined(TOOLKIT_VIEWS) | 158 #if defined(TOOLKIT_VIEWS) |
155 popup_view_(new AutocompletePopupContentsView( | 159 popup_view_(new AutocompletePopupContentsView( |
156 gfx::Font(), this, model_.get(), profile, location_bar)), | 160 gfx::Font(), this, model_.get(), profile, location_bar)), |
157 #else | 161 #else |
158 popup_view_(new AutocompletePopupViewGtk(this, model_.get(), profile, | 162 popup_view_(new AutocompletePopupViewGtk(this, model_.get(), profile, |
159 location_bar)), | 163 location_bar)), |
160 #endif | 164 #endif |
161 controller_(controller), | 165 controller_(controller), |
162 toolbar_model_(toolbar_model), | 166 toolbar_model_(toolbar_model), |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
211 alignment_.Own(gtk_alignment_new(0., 0.5, 1.0, 0.0)); | 215 alignment_.Own(gtk_alignment_new(0., 0.5, 1.0, 0.0)); |
212 gtk_widget_set_name(alignment_.get(), | 216 gtk_widget_set_name(alignment_.get(), |
213 "chrome-autocomplete-edit-view"); | 217 "chrome-autocomplete-edit-view"); |
214 | 218 |
215 // The GtkTagTable and GtkTextBuffer are not initially unowned, so we have | 219 // The GtkTagTable and GtkTextBuffer are not initially unowned, so we have |
216 // our own reference when we create them, and we own them. Adding them to | 220 // our own reference when we create them, and we own them. Adding them to |
217 // the other objects adds a reference; it doesn't adopt them. | 221 // the other objects adds a reference; it doesn't adopt them. |
218 tag_table_ = gtk_text_tag_table_new(); | 222 tag_table_ = gtk_text_tag_table_new(); |
219 text_buffer_ = gtk_text_buffer_new(tag_table_); | 223 text_buffer_ = gtk_text_buffer_new(tag_table_); |
220 g_object_set_data(G_OBJECT(text_buffer_), kAutocompleteEditViewGtkKey, this); | 224 g_object_set_data(G_OBJECT(text_buffer_), kAutocompleteEditViewGtkKey, this); |
| 225 |
| 226 // We need to run this two handlers before undo manager's handlers, so that |
| 227 // text iterators modified by these handlers can be passed down to undo |
| 228 // manager's handlers. |
| 229 g_signal_connect(text_buffer_, "delete-range", |
| 230 G_CALLBACK(&HandleDeleteRangeThunk), this); |
| 231 g_signal_connect(text_buffer_, "mark-set", |
| 232 G_CALLBACK(&HandleMarkSetAlwaysThunk), this); |
| 233 |
221 text_view_ = gtk_undo_view_new(text_buffer_); | 234 text_view_ = gtk_undo_view_new(text_buffer_); |
222 if (popup_window_mode_) | 235 if (popup_window_mode_) |
223 gtk_text_view_set_editable(GTK_TEXT_VIEW(text_view_), false); | 236 gtk_text_view_set_editable(GTK_TEXT_VIEW(text_view_), false); |
224 | 237 |
225 // One pixel left margin is necessary to make the cursor visible when UI | 238 // One pixel left margin is necessary to make the cursor visible when UI |
226 // language direction is LTR but |text_buffer_|'s content direction is RTL. | 239 // language direction is LTR but |text_buffer_|'s content direction is RTL. |
227 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_view_), 1); | 240 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_view_), 1); |
228 | 241 |
229 // See SetEntryStyle() comments. | 242 // See SetEntryStyle() comments. |
230 gtk_widget_set_name(text_view_, "chrome-location-bar-entry"); | 243 gtk_widget_set_name(text_view_, "chrome-location-bar-entry"); |
(...skipping 17 matching lines...) Expand all Loading... |
248 NULL, "foreground", "#000000", NULL); | 261 NULL, "foreground", "#000000", NULL); |
249 | 262 |
250 // NOTE: This code used to connect to "changed", however this was fired too | 263 // NOTE: This code used to connect to "changed", however this was fired too |
251 // often and during bad times (our own buffer changes?). It works out much | 264 // often and during bad times (our own buffer changes?). It works out much |
252 // better to listen to end-user-action, which should be fired whenever the | 265 // better to listen to end-user-action, which should be fired whenever the |
253 // user makes some sort of change to the buffer. | 266 // user makes some sort of change to the buffer. |
254 g_signal_connect(text_buffer_, "begin-user-action", | 267 g_signal_connect(text_buffer_, "begin-user-action", |
255 G_CALLBACK(&HandleBeginUserActionThunk), this); | 268 G_CALLBACK(&HandleBeginUserActionThunk), this); |
256 g_signal_connect(text_buffer_, "end-user-action", | 269 g_signal_connect(text_buffer_, "end-user-action", |
257 G_CALLBACK(&HandleEndUserActionThunk), this); | 270 G_CALLBACK(&HandleEndUserActionThunk), this); |
258 g_signal_connect(text_buffer_, "insert-text", | |
259 G_CALLBACK(&HandleInsertTextThunk), this); | |
260 // We connect to key press and release for special handling of a few keys. | 271 // We connect to key press and release for special handling of a few keys. |
261 g_signal_connect(text_view_, "key-press-event", | 272 g_signal_connect(text_view_, "key-press-event", |
262 G_CALLBACK(&HandleKeyPressThunk), this); | 273 G_CALLBACK(&HandleKeyPressThunk), this); |
263 g_signal_connect(text_view_, "key-release-event", | 274 g_signal_connect(text_view_, "key-release-event", |
264 G_CALLBACK(&HandleKeyReleaseThunk), this); | 275 G_CALLBACK(&HandleKeyReleaseThunk), this); |
265 g_signal_connect(text_view_, "button-press-event", | 276 g_signal_connect(text_view_, "button-press-event", |
266 G_CALLBACK(&HandleViewButtonPressThunk), this); | 277 G_CALLBACK(&HandleViewButtonPressThunk), this); |
267 g_signal_connect(text_view_, "button-release-event", | 278 g_signal_connect(text_view_, "button-release-event", |
268 G_CALLBACK(&HandleViewButtonReleaseThunk), this); | 279 G_CALLBACK(&HandleViewButtonReleaseThunk), this); |
269 g_signal_connect(text_view_, "focus-in-event", | 280 g_signal_connect(text_view_, "focus-in-event", |
(...skipping 28 matching lines...) Expand all Loading... |
298 g_signal_connect(text_view_, "paste-clipboard", | 309 g_signal_connect(text_view_, "paste-clipboard", |
299 G_CALLBACK(&HandlePasteClipboardThunk), this); | 310 G_CALLBACK(&HandlePasteClipboardThunk), this); |
300 g_signal_connect_after(text_view_, "expose-event", | 311 g_signal_connect_after(text_view_, "expose-event", |
301 G_CALLBACK(&HandleExposeEventThunk), this); | 312 G_CALLBACK(&HandleExposeEventThunk), this); |
302 g_signal_connect(text_view_, "direction-changed", | 313 g_signal_connect(text_view_, "direction-changed", |
303 G_CALLBACK(&HandleWidgetDirectionChangedThunk), this); | 314 G_CALLBACK(&HandleWidgetDirectionChangedThunk), this); |
304 g_signal_connect(text_view_, "delete-from-cursor", | 315 g_signal_connect(text_view_, "delete-from-cursor", |
305 G_CALLBACK(&HandleDeleteFromCursorThunk), this); | 316 G_CALLBACK(&HandleDeleteFromCursorThunk), this); |
306 g_signal_connect(text_view_, "hierarchy-changed", | 317 g_signal_connect(text_view_, "hierarchy-changed", |
307 G_CALLBACK(&HandleHierarchyChangedThunk), this); | 318 G_CALLBACK(&HandleHierarchyChangedThunk), this); |
308 #if GTK_CHECK_VERSION(2,20,0) | 319 #if GTK_CHECK_VERSION(2, 20, 0) |
309 g_signal_connect(text_view_, "preedit-changed", | 320 g_signal_connect(text_view_, "preedit-changed", |
310 G_CALLBACK(&HandlePreeditChangedThunk), this); | 321 G_CALLBACK(&HandlePreeditChangedThunk), this); |
311 #endif | 322 #endif |
| 323 g_signal_connect(text_view_, "undo", G_CALLBACK(&HandleUndoRedoThunk), this); |
| 324 g_signal_connect(text_view_, "redo", G_CALLBACK(&HandleUndoRedoThunk), this); |
| 325 g_signal_connect_after(text_view_, "undo", |
| 326 G_CALLBACK(&HandleUndoRedoAfterThunk), this); |
| 327 g_signal_connect_after(text_view_, "redo", |
| 328 G_CALLBACK(&HandleUndoRedoAfterThunk), this); |
312 | 329 |
313 // Setup for the Instant suggestion text view. | 330 // Setup for the Instant suggestion text view. |
314 instant_view_ = gtk_text_view_new(); | 331 // GtkLabel is used instead of GtkTextView to get transparent background. |
315 instant_buffer_ = gtk_text_view_get_buffer(GTK_TEXT_VIEW(instant_view_)); | 332 instant_view_ = gtk_label_new(NULL); |
316 gtk_text_view_add_child_in_window(GTK_TEXT_VIEW(text_view_), | 333 |
| 334 GtkTextIter end_iter; |
| 335 gtk_text_buffer_get_end_iter(text_buffer_, &end_iter); |
| 336 |
| 337 // Insert a Zero Width Space character just before the instant anchor. |
| 338 // It's a hack to workaround a bug of GtkTextView which can not align the |
| 339 // preedit string and a child anchor correctly when there is no other content |
| 340 // around the preedit string. |
| 341 gtk_text_buffer_insert(text_buffer_, &end_iter, "\342\200\213", -1); |
| 342 GtkTextChildAnchor* instant_anchor = |
| 343 gtk_text_buffer_create_child_anchor(text_buffer_, &end_iter); |
| 344 |
| 345 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(text_view_), |
317 instant_view_, | 346 instant_view_, |
318 GTK_TEXT_WINDOW_WIDGET, | 347 instant_anchor); |
319 0, 0); | 348 |
320 instant_text_tag_ = gtk_text_buffer_create_tag( | 349 instant_anchor_tag_ = gtk_text_buffer_create_tag(text_buffer_, NULL, NULL); |
321 instant_buffer_, NULL, "foreground", kTextBaseColor, NULL); | 350 |
322 GTK_WIDGET_UNSET_FLAGS(instant_view_, GTK_CAN_FOCUS); | 351 GtkTextIter anchor_iter; |
323 g_signal_connect(instant_view_, "button-press-event", | 352 gtk_text_buffer_get_iter_at_child_anchor(text_buffer_, &anchor_iter, |
324 G_CALLBACK(&HandleInstantViewButtonPressThunk), this); | 353 instant_anchor); |
| 354 gtk_text_buffer_apply_tag(text_buffer_, instant_anchor_tag_, |
| 355 &anchor_iter, &end_iter); |
| 356 |
| 357 GtkTextIter start_iter; |
| 358 gtk_text_buffer_get_start_iter(text_buffer_, &start_iter); |
| 359 instant_mark_ = |
| 360 gtk_text_buffer_create_mark(text_buffer_, NULL, &start_iter, FALSE); |
| 361 |
| 362 // Hooking up this handler after setting up above hacks for Instant view, so |
| 363 // that we won't filter out the special ZWP mark itself. |
| 364 g_signal_connect(text_buffer_, "insert-text", |
| 365 G_CALLBACK(&HandleInsertTextThunk), this); |
| 366 |
| 367 AdjustVerticalAlignmentOfInstantView(); |
325 | 368 |
326 #if !defined(TOOLKIT_VIEWS) | 369 #if !defined(TOOLKIT_VIEWS) |
327 registrar_.Add(this, | 370 registrar_.Add(this, |
328 NotificationType::BROWSER_THEME_CHANGED, | 371 NotificationType::BROWSER_THEME_CHANGED, |
329 NotificationService::AllSources()); | 372 NotificationService::AllSources()); |
330 theme_provider_->InitThemesFor(this); | 373 theme_provider_->InitThemesFor(this); |
331 #else | 374 #else |
332 // Manually invoke SetBaseColor() because TOOLKIT_VIEWS doesn't observe | 375 // Manually invoke SetBaseColor() because TOOLKIT_VIEWS doesn't observe |
333 // themes. | 376 // themes. |
334 SetBaseColor(); | 377 SetBaseColor(); |
(...skipping 22 matching lines...) Expand all Loading... |
357 gtk_text_view_get_border_window_size(GTK_TEXT_VIEW(text_view_), | 400 gtk_text_view_get_border_window_size(GTK_TEXT_VIEW(text_view_), |
358 GTK_TEXT_WINDOW_LEFT) + | 401 GTK_TEXT_WINDOW_LEFT) + |
359 gtk_text_view_get_border_window_size(GTK_TEXT_VIEW(text_view_), | 402 gtk_text_view_get_border_window_size(GTK_TEXT_VIEW(text_view_), |
360 GTK_TEXT_WINDOW_RIGHT) + | 403 GTK_TEXT_WINDOW_RIGHT) + |
361 gtk_text_view_get_left_margin(GTK_TEXT_VIEW(text_view_)) + | 404 gtk_text_view_get_left_margin(GTK_TEXT_VIEW(text_view_)) + |
362 gtk_text_view_get_right_margin(GTK_TEXT_VIEW(text_view_)); | 405 gtk_text_view_get_right_margin(GTK_TEXT_VIEW(text_view_)); |
363 | 406 |
364 GtkTextIter start, end; | 407 GtkTextIter start, end; |
365 GdkRectangle first_char_bounds, last_char_bounds; | 408 GdkRectangle first_char_bounds, last_char_bounds; |
366 gtk_text_buffer_get_start_iter(text_buffer_, &start); | 409 gtk_text_buffer_get_start_iter(text_buffer_, &start); |
| 410 |
| 411 // Use the real end iterator here to take the width of instant suggestion |
| 412 // text into account, so that location bar can layout its children correctly. |
367 gtk_text_buffer_get_end_iter(text_buffer_, &end); | 413 gtk_text_buffer_get_end_iter(text_buffer_, &end); |
368 gtk_text_view_get_iter_location(GTK_TEXT_VIEW(text_view_), | 414 gtk_text_view_get_iter_location(GTK_TEXT_VIEW(text_view_), |
369 &start, &first_char_bounds); | 415 &start, &first_char_bounds); |
370 gtk_text_view_get_iter_location(GTK_TEXT_VIEW(text_view_), | 416 gtk_text_view_get_iter_location(GTK_TEXT_VIEW(text_view_), |
371 &end, &last_char_bounds); | 417 &end, &last_char_bounds); |
372 return ((last_char_bounds.x > first_char_bounds.x) ? | 418 return ((last_char_bounds.x > first_char_bounds.x) ? |
373 (last_char_bounds.x + last_char_bounds.width - first_char_bounds.x) : | 419 (last_char_bounds.x + last_char_bounds.width - first_char_bounds.x) : |
374 (first_char_bounds.x - last_char_bounds.x + last_char_bounds.width)) + | 420 (first_char_bounds.x - last_char_bounds.x + last_char_bounds.width)) + |
375 horizontal_border_size; | 421 horizontal_border_size; |
376 } | 422 } |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
438 size_t selected_line, | 484 size_t selected_line, |
439 const std::wstring& keyword) { | 485 const std::wstring& keyword) { |
440 if (!url.is_valid()) | 486 if (!url.is_valid()) |
441 return; | 487 return; |
442 | 488 |
443 model_->OpenURL(url, disposition, transition, alternate_nav_url, | 489 model_->OpenURL(url, disposition, transition, alternate_nav_url, |
444 selected_line, keyword); | 490 selected_line, keyword); |
445 } | 491 } |
446 | 492 |
447 std::wstring AutocompleteEditViewGtk::GetText() const { | 493 std::wstring AutocompleteEditViewGtk::GetText() const { |
448 return GetTextFromBuffer(text_buffer_); | 494 GtkTextIter start, end; |
| 495 GetTextBufferBounds(&start, &end); |
| 496 gchar* utf8 = gtk_text_buffer_get_text(text_buffer_, &start, &end, false); |
| 497 std::wstring out(UTF8ToWide(utf8)); |
| 498 g_free(utf8); |
| 499 |
| 500 #if GTK_CHECK_VERSION(2, 20, 0) |
| 501 // We need to treat the text currently being composed by the input method as |
| 502 // part of the text content, so that omnibox can work correctly in the middle |
| 503 // of composition. |
| 504 if (preedit_.size()) { |
| 505 GtkTextMark* mark = gtk_text_buffer_get_insert(text_buffer_); |
| 506 gtk_text_buffer_get_iter_at_mark(text_buffer_, &start, mark); |
| 507 out.insert(gtk_text_iter_get_offset(&start), preedit_); |
| 508 } |
| 509 #endif |
| 510 return out; |
449 } | 511 } |
450 | 512 |
451 bool AutocompleteEditViewGtk::IsEditingOrEmpty() const { | 513 bool AutocompleteEditViewGtk::IsEditingOrEmpty() const { |
452 return model_->user_input_in_progress() || | 514 return model_->user_input_in_progress() || (GetTextLength() == 0); |
453 (gtk_text_buffer_get_char_count(text_buffer_) == 0); | |
454 } | 515 } |
455 | 516 |
456 int AutocompleteEditViewGtk::GetIcon() const { | 517 int AutocompleteEditViewGtk::GetIcon() const { |
457 return IsEditingOrEmpty() ? | 518 return IsEditingOrEmpty() ? |
458 AutocompleteMatch::TypeToIcon(model_->CurrentTextType()) : | 519 AutocompleteMatch::TypeToIcon(model_->CurrentTextType()) : |
459 toolbar_model_->GetIcon(); | 520 toolbar_model_->GetIcon(); |
460 } | 521 } |
461 | 522 |
462 void AutocompleteEditViewGtk::SetUserText(const std::wstring& text) { | 523 void AutocompleteEditViewGtk::SetUserText(const std::wstring& text) { |
463 SetUserText(text, text, true); | 524 SetUserText(text, text, true); |
(...skipping 26 matching lines...) Expand all Loading... |
490 SetSelectedRange(CharRange(current_text.size(), start + 1)); | 551 SetSelectedRange(CharRange(current_text.size(), start + 1)); |
491 FinishUpdatingHighlightedText(); | 552 FinishUpdatingHighlightedText(); |
492 } | 553 } |
493 } | 554 } |
494 | 555 |
495 bool AutocompleteEditViewGtk::IsSelectAll() { | 556 bool AutocompleteEditViewGtk::IsSelectAll() { |
496 GtkTextIter sel_start, sel_end; | 557 GtkTextIter sel_start, sel_end; |
497 gtk_text_buffer_get_selection_bounds(text_buffer_, &sel_start, &sel_end); | 558 gtk_text_buffer_get_selection_bounds(text_buffer_, &sel_start, &sel_end); |
498 | 559 |
499 GtkTextIter start, end; | 560 GtkTextIter start, end; |
500 gtk_text_buffer_get_bounds(text_buffer_, &start, &end); | 561 GetTextBufferBounds(&start, &end); |
501 | 562 |
502 // Returns true if the |text_buffer_| is empty. | 563 // Returns true if the |text_buffer_| is empty. |
503 return gtk_text_iter_equal(&start, &sel_start) && | 564 return gtk_text_iter_equal(&start, &sel_start) && |
504 gtk_text_iter_equal(&end, &sel_end); | 565 gtk_text_iter_equal(&end, &sel_end); |
505 } | 566 } |
506 | 567 |
507 void AutocompleteEditViewGtk::GetSelectionBounds(std::wstring::size_type* start, | 568 void AutocompleteEditViewGtk::GetSelectionBounds(std::wstring::size_type* start, |
508 std::wstring::size_type* end) { | 569 std::wstring::size_type* end) { |
509 CharRange selection = GetSelection(); | 570 CharRange selection = GetSelection(); |
510 *start = static_cast<size_t>(selection.cp_min); | 571 *start = static_cast<size_t>(selection.cp_min); |
(...skipping 12 matching lines...) Expand all Loading... |
523 model_->Revert(); | 584 model_->Revert(); |
524 TextChanged(); | 585 TextChanged(); |
525 } | 586 } |
526 | 587 |
527 void AutocompleteEditViewGtk::UpdatePopup() { | 588 void AutocompleteEditViewGtk::UpdatePopup() { |
528 model_->SetInputInProgress(true); | 589 model_->SetInputInProgress(true); |
529 if (!model_->has_focus()) | 590 if (!model_->has_focus()) |
530 return; | 591 return; |
531 | 592 |
532 // Don't inline autocomplete when the caret/selection isn't at the end of | 593 // Don't inline autocomplete when the caret/selection isn't at the end of |
533 // the text. | 594 // the text, or in the middle of composition. |
534 CharRange sel = GetSelection(); | 595 CharRange sel = GetSelection(); |
535 model_->StartAutocomplete(sel.cp_min != sel.cp_max, | 596 bool no_inline_autocomplete = |
536 std::max(sel.cp_max, sel.cp_min) < GetTextLength()); | 597 std::max(sel.cp_max, sel.cp_min) < GetTextLength(); |
| 598 #if GTK_CHECK_VERSION(2, 20, 0) |
| 599 no_inline_autocomplete = no_inline_autocomplete || preedit_.size(); |
| 600 #endif |
| 601 model_->StartAutocomplete(sel.cp_min != sel.cp_max, no_inline_autocomplete); |
537 } | 602 } |
538 | 603 |
539 void AutocompleteEditViewGtk::ClosePopup() { | 604 void AutocompleteEditViewGtk::ClosePopup() { |
540 if (popup_view_->GetModel()->IsOpen()) | 605 if (popup_view_->GetModel()->IsOpen()) |
541 controller_->OnAutocompleteWillClosePopup(); | 606 controller_->OnAutocompleteWillClosePopup(); |
542 | 607 |
543 popup_view_->GetModel()->StopAutocomplete(); | 608 popup_view_->GetModel()->StopAutocomplete(); |
544 } | 609 } |
545 | 610 |
546 void AutocompleteEditViewGtk::OnTemporaryTextMaybeChanged( | 611 void AutocompleteEditViewGtk::OnTemporaryTextMaybeChanged( |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
667 | 732 |
668 if (use_gtk) { | 733 if (use_gtk) { |
669 gtk_widget_modify_cursor(text_view_, NULL, NULL); | 734 gtk_widget_modify_cursor(text_view_, NULL, NULL); |
670 gtk_widget_modify_base(text_view_, GTK_STATE_NORMAL, NULL); | 735 gtk_widget_modify_base(text_view_, GTK_STATE_NORMAL, NULL); |
671 gtk_widget_modify_base(text_view_, GTK_STATE_SELECTED, NULL); | 736 gtk_widget_modify_base(text_view_, GTK_STATE_SELECTED, NULL); |
672 gtk_widget_modify_text(text_view_, GTK_STATE_SELECTED, NULL); | 737 gtk_widget_modify_text(text_view_, GTK_STATE_SELECTED, NULL); |
673 gtk_widget_modify_base(text_view_, GTK_STATE_ACTIVE, NULL); | 738 gtk_widget_modify_base(text_view_, GTK_STATE_ACTIVE, NULL); |
674 gtk_widget_modify_text(text_view_, GTK_STATE_ACTIVE, NULL); | 739 gtk_widget_modify_text(text_view_, GTK_STATE_ACTIVE, NULL); |
675 | 740 |
676 gtk_util::UndoForceFontSize(text_view_); | 741 gtk_util::UndoForceFontSize(text_view_); |
| 742 gtk_util::UndoForceFontSize(instant_view_); |
677 | 743 |
678 // Grab the text colors out of the style and set our tags to use them. | 744 // Grab the text colors out of the style and set our tags to use them. |
679 GtkStyle* style = gtk_rc_get_style(text_view_); | 745 GtkStyle* style = gtk_rc_get_style(text_view_); |
680 | 746 |
681 // style may be unrealized at this point, so calculate the halfway point | 747 // style may be unrealized at this point, so calculate the halfway point |
682 // between text[] and base[] manually instead of just using text_aa[]. | 748 // between text[] and base[] manually instead of just using text_aa[]. |
683 GdkColor average_color = gtk_util::AverageColors( | 749 GdkColor average_color = gtk_util::AverageColors( |
684 style->text[GTK_STATE_NORMAL], style->base[GTK_STATE_NORMAL]); | 750 style->text[GTK_STATE_NORMAL], style->base[GTK_STATE_NORMAL]); |
685 | 751 |
686 g_object_set(faded_text_tag_, "foreground-gdk", &average_color, NULL); | 752 g_object_set(faded_text_tag_, "foreground-gdk", &average_color, NULL); |
687 g_object_set(instant_text_tag_, "foreground-gdk", &average_color, NULL); | |
688 g_object_set(normal_text_tag_, "foreground-gdk", | 753 g_object_set(normal_text_tag_, "foreground-gdk", |
689 &style->text[GTK_STATE_NORMAL], NULL); | 754 &style->text[GTK_STATE_NORMAL], NULL); |
| 755 |
| 756 // GtkLabel uses fg color instead of text color. |
| 757 gtk_widget_modify_fg(instant_view_, GTK_STATE_NORMAL, &average_color); |
690 } else { | 758 } else { |
691 const GdkColor* background_color_ptr; | 759 const GdkColor* background_color_ptr; |
692 #if defined(TOOLKIT_VIEWS) | 760 #if defined(TOOLKIT_VIEWS) |
693 const GdkColor background_color = gfx::SkColorToGdkColor( | 761 const GdkColor background_color = gfx::SkColorToGdkColor( |
694 LocationBarView::GetColor(ToolbarModel::NONE, | 762 LocationBarView::GetColor(ToolbarModel::NONE, |
695 LocationBarView::BACKGROUND)); | 763 LocationBarView::BACKGROUND)); |
696 background_color_ptr = &background_color; | 764 background_color_ptr = &background_color; |
697 #else | 765 #else |
698 background_color_ptr = &LocationBarViewGtk::kBackgroundColor; | 766 background_color_ptr = &LocationBarViewGtk::kBackgroundColor; |
699 #endif | 767 #endif |
700 gtk_widget_modify_cursor( | 768 gtk_widget_modify_cursor( |
701 text_view_, >k_util::kGdkBlack, >k_util::kGdkGray); | 769 text_view_, >k_util::kGdkBlack, >k_util::kGdkGray); |
702 gtk_widget_modify_base(text_view_, GTK_STATE_NORMAL, background_color_ptr); | 770 gtk_widget_modify_base(text_view_, GTK_STATE_NORMAL, background_color_ptr); |
703 | 771 |
| 772 GdkColor c; |
704 #if !defined(TOOLKIT_VIEWS) | 773 #if !defined(TOOLKIT_VIEWS) |
705 // Override the selected colors so we don't leak colors from the current | 774 // Override the selected colors so we don't leak colors from the current |
706 // gtk theme into the chrome-theme. | 775 // gtk theme into the chrome-theme. |
707 GdkColor c; | |
708 c = gfx::SkColorToGdkColor( | 776 c = gfx::SkColorToGdkColor( |
709 theme_provider_->get_active_selection_bg_color()); | 777 theme_provider_->get_active_selection_bg_color()); |
710 gtk_widget_modify_base(text_view_, GTK_STATE_SELECTED, &c); | 778 gtk_widget_modify_base(text_view_, GTK_STATE_SELECTED, &c); |
711 | 779 |
712 c = gfx::SkColorToGdkColor( | 780 c = gfx::SkColorToGdkColor( |
713 theme_provider_->get_active_selection_fg_color()); | 781 theme_provider_->get_active_selection_fg_color()); |
714 gtk_widget_modify_text(text_view_, GTK_STATE_SELECTED, &c); | 782 gtk_widget_modify_text(text_view_, GTK_STATE_SELECTED, &c); |
715 | 783 |
716 c = gfx::SkColorToGdkColor( | 784 c = gfx::SkColorToGdkColor( |
717 theme_provider_->get_inactive_selection_bg_color()); | 785 theme_provider_->get_inactive_selection_bg_color()); |
718 gtk_widget_modify_base(text_view_, GTK_STATE_ACTIVE, &c); | 786 gtk_widget_modify_base(text_view_, GTK_STATE_ACTIVE, &c); |
719 | 787 |
720 c = gfx::SkColorToGdkColor( | 788 c = gfx::SkColorToGdkColor( |
721 theme_provider_->get_inactive_selection_fg_color()); | 789 theme_provider_->get_inactive_selection_fg_color()); |
722 gtk_widget_modify_text(text_view_, GTK_STATE_ACTIVE, &c); | 790 gtk_widget_modify_text(text_view_, GTK_STATE_ACTIVE, &c); |
723 #endif | 791 #endif |
724 | 792 |
| 793 gdk_color_parse(kTextBaseColor, &c); |
| 794 gtk_widget_modify_fg(instant_view_, GTK_STATE_NORMAL, &c); |
| 795 |
725 // Until we switch to vector graphics, force the font size. | 796 // Until we switch to vector graphics, force the font size. |
726 gtk_util::ForceFontSizePixels(text_view_, | 797 gtk_util::ForceFontSizePixels(text_view_, |
727 popup_window_mode_ ? | 798 popup_window_mode_ ? |
728 browser_defaults::kAutocompleteEditFontPixelSizeInPopup : | 799 browser_defaults::kAutocompleteEditFontPixelSizeInPopup : |
729 browser_defaults::kAutocompleteEditFontPixelSize); | 800 browser_defaults::kAutocompleteEditFontPixelSize); |
730 | 801 |
| 802 gtk_util::ForceFontSizePixels(instant_view_, |
| 803 popup_window_mode_ ? |
| 804 browser_defaults::kAutocompleteEditFontPixelSizeInPopup : |
| 805 browser_defaults::kAutocompleteEditFontPixelSize); |
| 806 |
731 g_object_set(faded_text_tag_, "foreground", kTextBaseColor, NULL); | 807 g_object_set(faded_text_tag_, "foreground", kTextBaseColor, NULL); |
732 g_object_set(instant_text_tag_, "foreground", kTextBaseColor, NULL); | |
733 g_object_set(normal_text_tag_, "foreground", "#000000", NULL); | 808 g_object_set(normal_text_tag_, "foreground", "#000000", NULL); |
734 } | 809 } |
| 810 |
| 811 AdjustVerticalAlignmentOfInstantView(); |
735 } | 812 } |
736 | 813 |
737 void AutocompleteEditViewGtk::HandleBeginUserAction(GtkTextBuffer* sender) { | 814 void AutocompleteEditViewGtk::HandleBeginUserAction(GtkTextBuffer* sender) { |
738 OnBeforePossibleChange(); | 815 OnBeforePossibleChange(); |
739 } | 816 } |
740 | 817 |
741 void AutocompleteEditViewGtk::HandleEndUserAction(GtkTextBuffer* sender) { | 818 void AutocompleteEditViewGtk::HandleEndUserAction(GtkTextBuffer* sender) { |
742 OnAfterPossibleChange(); | 819 OnAfterPossibleChange(); |
743 } | 820 } |
744 | 821 |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
939 if (!text_view_focused_before_button_press_ && !text_selected_during_click_) { | 1016 if (!text_view_focused_before_button_press_ && !text_selected_during_click_) { |
940 // If this was a focusing click and the user didn't drag to highlight any | 1017 // If this was a focusing click and the user didn't drag to highlight any |
941 // text, select the full input and update the PRIMARY selection. | 1018 // text, select the full input and update the PRIMARY selection. |
942 SelectAllInternal(false, true); | 1019 SelectAllInternal(false, true); |
943 | 1020 |
944 // So we told the buffer where the cursor should be, but make sure to tell | 1021 // So we told the buffer where the cursor should be, but make sure to tell |
945 // the view so it can scroll it to be visible if needed. | 1022 // the view so it can scroll it to be visible if needed. |
946 // NOTE: This function doesn't seem to like a count of 0, looking at the | 1023 // NOTE: This function doesn't seem to like a count of 0, looking at the |
947 // code it will skip an important loop. Use -1 to achieve the same. | 1024 // code it will skip an important loop. Use -1 to achieve the same. |
948 GtkTextIter start, end; | 1025 GtkTextIter start, end; |
949 gtk_text_buffer_get_bounds(text_buffer_, &start, &end); | 1026 GetTextBufferBounds(&start, &end); |
950 gtk_text_view_move_visually(GTK_TEXT_VIEW(text_view_), &start, -1); | 1027 gtk_text_view_move_visually(GTK_TEXT_VIEW(text_view_), &start, -1); |
951 } | 1028 } |
952 #endif | 1029 #endif |
953 | 1030 |
954 // Inform |model_| about possible text selection change. | 1031 // Inform |model_| about possible text selection change. |
955 OnAfterPossibleChange(); | 1032 OnAfterPossibleChange(); |
956 | 1033 |
957 return TRUE; // Don't continue, we called the default handler already. | 1034 return TRUE; // Don't continue, we called the default handler already. |
958 } | 1035 } |
959 | 1036 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1018 // Cursor placement will remove the selection, so we need inform |model_| | 1095 // Cursor placement will remove the selection, so we need inform |model_| |
1019 // about this change by calling On{Before|After}PossibleChange() methods. | 1096 // about this change by calling On{Before|After}PossibleChange() methods. |
1020 OnBeforePossibleChange(); | 1097 OnBeforePossibleChange(); |
1021 gtk_text_buffer_place_cursor(text_buffer_, | 1098 gtk_text_buffer_place_cursor(text_buffer_, |
1022 count == 1 ? &sel_end : &sel_start); | 1099 count == 1 ? &sel_end : &sel_start); |
1023 OnAfterPossibleChange(); | 1100 OnAfterPossibleChange(); |
1024 } else if (count == 1 && !has_selection) { | 1101 } else if (count == 1 && !has_selection) { |
1025 gint cursor_pos; | 1102 gint cursor_pos; |
1026 g_object_get(G_OBJECT(text_buffer_), "cursor-position", &cursor_pos, | 1103 g_object_get(G_OBJECT(text_buffer_), "cursor-position", &cursor_pos, |
1027 NULL); | 1104 NULL); |
1028 if (cursor_pos == gtk_text_buffer_get_char_count(text_buffer_)) | 1105 if (cursor_pos == GetTextLength()) |
1029 controller_->OnCommitSuggestedText(GetText()); | 1106 controller_->OnCommitSuggestedText(GetText()); |
1030 else | 1107 else |
1031 handled = false; | 1108 handled = false; |
1032 } else { | 1109 } else { |
1033 handled = false; | 1110 handled = false; |
1034 } | 1111 } |
1035 } else if (step == GTK_MOVEMENT_PAGES) { // Page up and down. | 1112 } else if (step == GTK_MOVEMENT_PAGES) { // Page up and down. |
1036 // Multiply by count for the direction (if we move too much that's ok). | 1113 // Multiply by count for the direction (if we move too much that's ok). |
1037 model_->OnUpOrDownKeyPressed(model_->result().size() * count); | 1114 model_->OnUpOrDownKeyPressed(model_->result().size() * count); |
1038 } else if (step == GTK_MOVEMENT_DISPLAY_LINES) { // Arrow up and down. | 1115 } else if (step == GTK_MOVEMENT_DISPLAY_LINES) { // Arrow up and down. |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1196 g_signal_stop_emission(text_view_, signal_id, 0); | 1273 g_signal_stop_emission(text_view_, signal_id, 0); |
1197 } | 1274 } |
1198 } | 1275 } |
1199 | 1276 |
1200 void AutocompleteEditViewGtk::HandleInsertText( | 1277 void AutocompleteEditViewGtk::HandleInsertText( |
1201 GtkTextBuffer* buffer, GtkTextIter* location, const gchar* text, gint len) { | 1278 GtkTextBuffer* buffer, GtkTextIter* location, const gchar* text, gint len) { |
1202 std::string filtered_text; | 1279 std::string filtered_text; |
1203 filtered_text.reserve(len); | 1280 filtered_text.reserve(len); |
1204 | 1281 |
1205 // Filter out new line and tab characters. | 1282 // Filter out new line and tab characters. |
1206 // |text| is guaranteed to be a valid UTF-8 string, so it's safe here to | 1283 // |text| is guaranteed to be a valid UTF-8 string, so we don't need to |
1207 // filter byte by byte. | 1284 // validate it here. |
1208 // | 1285 // |
1209 // If there was only a single character, then it might be generated by a key | 1286 // If there was only a single character, then it might be generated by a key |
1210 // event. In this case, we save the single character to help our | 1287 // event. In this case, we save the single character to help our |
1211 // "key-press-event" signal handler distinguish if an Enter key event is | 1288 // "key-press-event" signal handler distinguish if an Enter key event is |
1212 // handled by IME or not. | 1289 // handled by IME or not. |
1213 if (len == 1 && (text[0] == '\n' || text[0] == '\r')) | 1290 if (len == 1 && (text[0] == '\n' || text[0] == '\r')) |
1214 enter_was_inserted_ = true; | 1291 enter_was_inserted_ = true; |
1215 | 1292 |
1216 for (gint i = 0; i < len; ++i) { | 1293 const gchar* p = text; |
1217 gchar c = text[i]; | 1294 while(*p) { |
1218 if (c == '\n' || c == '\r' || c == '\t') | 1295 gunichar c = g_utf8_get_char(p); |
1219 continue; | 1296 const gchar* next = g_utf8_next_char(p); |
1220 | 1297 |
1221 filtered_text.push_back(c); | 1298 // 0x200B is Zero Width Space, which is inserted just before the instant |
| 1299 // anchor for working around the GtkTextView's misalignment bug. |
| 1300 // This character might be captured and inserted into the content by undo |
| 1301 // manager, so we need to filter it out here. |
| 1302 if (c != L'\n' && c != L'\r' && c != L'\t' && c != 0x200B) |
| 1303 filtered_text.append(p, next); |
| 1304 |
| 1305 p = next; |
1222 } | 1306 } |
1223 | 1307 |
1224 if (filtered_text.length()) { | 1308 if (filtered_text.length()) { |
| 1309 // Avoid inserting the text after the instant anchor. |
| 1310 ValidateTextBufferIter(location); |
| 1311 |
1225 // Call the default handler to insert filtered text. | 1312 // Call the default handler to insert filtered text. |
1226 GtkTextBufferClass* klass = GTK_TEXT_BUFFER_GET_CLASS(buffer); | 1313 GtkTextBufferClass* klass = GTK_TEXT_BUFFER_GET_CLASS(buffer); |
1227 klass->insert_text(buffer, location, filtered_text.data(), | 1314 klass->insert_text(buffer, location, filtered_text.data(), |
1228 static_cast<gint>(filtered_text.length())); | 1315 static_cast<gint>(filtered_text.length())); |
1229 } | 1316 } |
1230 | 1317 |
1231 // Stop propagating the signal emission to prevent the default handler from | 1318 // Stop propagating the signal emission to prevent the default handler from |
1232 // being called again. | 1319 // being called again. |
1233 static guint signal_id = g_signal_lookup("insert-text", GTK_TYPE_TEXT_BUFFER); | 1320 static guint signal_id = g_signal_lookup("insert-text", GTK_TYPE_TEXT_BUFFER); |
1234 g_signal_stop_emission(buffer, signal_id, 0); | 1321 g_signal_stop_emission(buffer, signal_id, 0); |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1403 cairo_stroke(cr); | 1490 cairo_stroke(cr); |
1404 cairo_destroy(cr); | 1491 cairo_destroy(cr); |
1405 | 1492 |
1406 return FALSE; | 1493 return FALSE; |
1407 } | 1494 } |
1408 | 1495 |
1409 void AutocompleteEditViewGtk::SelectAllInternal(bool reversed, | 1496 void AutocompleteEditViewGtk::SelectAllInternal(bool reversed, |
1410 bool update_primary_selection) { | 1497 bool update_primary_selection) { |
1411 GtkTextIter start, end; | 1498 GtkTextIter start, end; |
1412 if (reversed) { | 1499 if (reversed) { |
1413 gtk_text_buffer_get_bounds(text_buffer_, &end, &start); | 1500 GetTextBufferBounds(&end, &start); |
1414 } else { | 1501 } else { |
1415 gtk_text_buffer_get_bounds(text_buffer_, &start, &end); | 1502 GetTextBufferBounds(&start, &end); |
1416 } | 1503 } |
1417 if (!update_primary_selection) | 1504 if (!update_primary_selection) |
1418 StartUpdatingHighlightedText(); | 1505 StartUpdatingHighlightedText(); |
1419 gtk_text_buffer_select_range(text_buffer_, &start, &end); | 1506 gtk_text_buffer_select_range(text_buffer_, &start, &end); |
1420 if (!update_primary_selection) | 1507 if (!update_primary_selection) |
1421 FinishUpdatingHighlightedText(); | 1508 FinishUpdatingHighlightedText(); |
1422 } | 1509 } |
1423 | 1510 |
1424 void AutocompleteEditViewGtk::StartUpdatingHighlightedText() { | 1511 void AutocompleteEditViewGtk::StartUpdatingHighlightedText() { |
1425 if (GTK_WIDGET_REALIZED(text_view_)) { | 1512 if (GTK_WIDGET_REALIZED(text_view_)) { |
(...skipping 26 matching lines...) Expand all Loading... |
1452 // actual marks so that we can preserve the selection direction. | 1539 // actual marks so that we can preserve the selection direction. |
1453 GtkTextIter start, insert; | 1540 GtkTextIter start, insert; |
1454 GtkTextMark* mark; | 1541 GtkTextMark* mark; |
1455 | 1542 |
1456 mark = gtk_text_buffer_get_selection_bound(text_buffer_); | 1543 mark = gtk_text_buffer_get_selection_bound(text_buffer_); |
1457 gtk_text_buffer_get_iter_at_mark(text_buffer_, &start, mark); | 1544 gtk_text_buffer_get_iter_at_mark(text_buffer_, &start, mark); |
1458 | 1545 |
1459 mark = gtk_text_buffer_get_insert(text_buffer_); | 1546 mark = gtk_text_buffer_get_insert(text_buffer_); |
1460 gtk_text_buffer_get_iter_at_mark(text_buffer_, &insert, mark); | 1547 gtk_text_buffer_get_iter_at_mark(text_buffer_, &insert, mark); |
1461 | 1548 |
| 1549 #if GTK_CHECK_VERSION(2, 20, 0) |
| 1550 // Nothing should be selected when we are in the middle of composition. |
| 1551 DCHECK(preedit_.empty() || gtk_text_iter_equal(&start, &insert)); |
| 1552 #endif |
| 1553 |
1462 return CharRange(gtk_text_iter_get_offset(&start), | 1554 return CharRange(gtk_text_iter_get_offset(&start), |
1463 gtk_text_iter_get_offset(&insert)); | 1555 gtk_text_iter_get_offset(&insert)); |
1464 } | 1556 } |
1465 | 1557 |
1466 void AutocompleteEditViewGtk::ItersFromCharRange(const CharRange& range, | 1558 void AutocompleteEditViewGtk::ItersFromCharRange(const CharRange& range, |
1467 GtkTextIter* iter_min, | 1559 GtkTextIter* iter_min, |
1468 GtkTextIter* iter_max) { | 1560 GtkTextIter* iter_max) { |
1469 gtk_text_buffer_get_iter_at_offset(text_buffer_, iter_min, range.cp_min); | 1561 gtk_text_buffer_get_iter_at_offset(text_buffer_, iter_min, range.cp_min); |
1470 gtk_text_buffer_get_iter_at_offset(text_buffer_, iter_max, range.cp_max); | 1562 gtk_text_buffer_get_iter_at_offset(text_buffer_, iter_max, range.cp_max); |
1471 } | 1563 } |
1472 | 1564 |
1473 int AutocompleteEditViewGtk::GetTextLength() { | 1565 int AutocompleteEditViewGtk::GetTextLength() const { |
1474 GtkTextIter start, end; | 1566 GtkTextIter end; |
1475 gtk_text_buffer_get_bounds(text_buffer_, &start, &end); | 1567 gtk_text_buffer_get_iter_at_mark(text_buffer_, &end, instant_mark_); |
| 1568 #if GTK_CHECK_VERSION(2, 20, 0) |
| 1569 // We need to count the length of the text being composed, because we treat |
| 1570 // it as part of the content in GetText(). |
| 1571 return gtk_text_iter_get_offset(&end) + preedit_.size(); |
| 1572 #else |
1476 return gtk_text_iter_get_offset(&end); | 1573 return gtk_text_iter_get_offset(&end); |
1477 } | 1574 #endif |
1478 | |
1479 std::wstring AutocompleteEditViewGtk::GetTextFromBuffer( | |
1480 GtkTextBuffer* buffer) const { | |
1481 GtkTextIter start, end; | |
1482 gtk_text_buffer_get_bounds(buffer, &start, &end); | |
1483 gchar* utf8 = gtk_text_buffer_get_text(buffer, &start, &end, false); | |
1484 std::wstring out(UTF8ToWide(utf8)); | |
1485 g_free(utf8); | |
1486 return out; | |
1487 } | 1575 } |
1488 | 1576 |
1489 void AutocompleteEditViewGtk::EmphasizeURLComponents() { | 1577 void AutocompleteEditViewGtk::EmphasizeURLComponents() { |
| 1578 #if GTK_CHECK_VERSION(2, 20, 0) |
| 1579 // We can't change the text style easily, if the preedit string (the text |
| 1580 // being composed by the input method) is not empty, which is not treated as |
| 1581 // a part of the text content inside GtkTextView. And it's ok to simply return |
| 1582 // in this case, as this method will be called again when the preedit string |
| 1583 // gets committed. |
| 1584 if (preedit_.size()) |
| 1585 return; |
| 1586 #endif |
1490 // See whether the contents are a URL with a non-empty host portion, which we | 1587 // See whether the contents are a URL with a non-empty host portion, which we |
1491 // should emphasize. To check for a URL, rather than using the type returned | 1588 // should emphasize. To check for a URL, rather than using the type returned |
1492 // by Parse(), ask the model, which will check the desired page transition for | 1589 // by Parse(), ask the model, which will check the desired page transition for |
1493 // this input. This can tell us whether an UNKNOWN input string is going to | 1590 // this input. This can tell us whether an UNKNOWN input string is going to |
1494 // be treated as a search or a navigation, and is the same method the Paste | 1591 // be treated as a search or a navigation, and is the same method the Paste |
1495 // And Go system uses. | 1592 // And Go system uses. |
1496 url_parse::Component scheme, host; | 1593 url_parse::Component scheme, host; |
1497 std::wstring text(GetText()); | 1594 std::wstring text(GetText()); |
1498 AutocompleteInput::ParseForEmphasizeComponents( | 1595 AutocompleteInput::ParseForEmphasizeComponents( |
1499 text, model_->GetDesiredTLD(), &scheme, &host); | 1596 text, model_->GetDesiredTLD(), &scheme, &host); |
1500 const bool emphasize = model_->CurrentTextIsURL() && (host.len > 0); | 1597 const bool emphasize = model_->CurrentTextIsURL() && (host.len > 0); |
1501 | 1598 |
1502 // Set the baseline emphasis. | 1599 // Set the baseline emphasis. |
1503 GtkTextIter start, end; | 1600 GtkTextIter start, end; |
1504 gtk_text_buffer_get_bounds(text_buffer_, &start, &end); | 1601 GetTextBufferBounds(&start, &end); |
1505 gtk_text_buffer_remove_all_tags(text_buffer_, &start, &end); | 1602 gtk_text_buffer_remove_all_tags(text_buffer_, &start, &end); |
1506 if (emphasize) { | 1603 if (emphasize) { |
1507 gtk_text_buffer_apply_tag(text_buffer_, faded_text_tag_, &start, &end); | 1604 gtk_text_buffer_apply_tag(text_buffer_, faded_text_tag_, &start, &end); |
1508 | 1605 |
1509 // We've found a host name, give it more emphasis. | 1606 // We've found a host name, give it more emphasis. |
1510 gtk_text_buffer_get_iter_at_line_index(text_buffer_, &start, 0, | 1607 gtk_text_buffer_get_iter_at_line_index(text_buffer_, &start, 0, |
1511 GetUTF8Offset(text, | 1608 GetUTF8Offset(text, |
1512 host.begin)); | 1609 host.begin)); |
1513 gtk_text_buffer_get_iter_at_line_index(text_buffer_, &end, 0, | 1610 gtk_text_buffer_get_iter_at_line_index(text_buffer_, &end, 0, |
1514 GetUTF8Offset(text, | 1611 GetUTF8Offset(text, |
(...skipping 23 matching lines...) Expand all Loading... |
1538 } else if (security_level_ == ToolbarModel::SECURITY_WARNING) { | 1635 } else if (security_level_ == ToolbarModel::SECURITY_WARNING) { |
1539 gtk_text_buffer_apply_tag(text_buffer_, faded_text_tag_, &start, &end); | 1636 gtk_text_buffer_apply_tag(text_buffer_, faded_text_tag_, &start, &end); |
1540 } else { | 1637 } else { |
1541 gtk_text_buffer_apply_tag(text_buffer_, secure_scheme_tag_, &start, &end); | 1638 gtk_text_buffer_apply_tag(text_buffer_, secure_scheme_tag_, &start, &end); |
1542 } | 1639 } |
1543 } | 1640 } |
1544 } | 1641 } |
1545 | 1642 |
1546 void AutocompleteEditViewGtk::SetInstantSuggestion( | 1643 void AutocompleteEditViewGtk::SetInstantSuggestion( |
1547 const std::string& suggestion) { | 1644 const std::string& suggestion) { |
| 1645 gtk_label_set_text(GTK_LABEL(instant_view_), suggestion.c_str()); |
1548 if (suggestion.empty()) { | 1646 if (suggestion.empty()) { |
1549 gtk_widget_hide(instant_view_); | 1647 gtk_widget_hide(instant_view_); |
1550 } else { | 1648 } else { |
1551 gtk_text_buffer_set_text(instant_buffer_, suggestion.data(), | |
1552 suggestion.size()); | |
1553 GtkTextIter start, end; | |
1554 gtk_text_buffer_get_bounds(instant_buffer_, &start, &end); | |
1555 gtk_text_buffer_apply_tag(instant_buffer_, instant_text_tag_, &start, &end); | |
1556 gtk_widget_show(instant_view_); | 1649 gtk_widget_show(instant_view_); |
| 1650 AdjustVerticalAlignmentOfInstantView(); |
1557 } | 1651 } |
1558 } | 1652 } |
1559 | 1653 |
1560 bool AutocompleteEditViewGtk::CommitInstantSuggestion() { | 1654 bool AutocompleteEditViewGtk::CommitInstantSuggestion() { |
1561 if (!GTK_WIDGET_VISIBLE(instant_view_)) | 1655 const gchar* suggestion = gtk_label_get_text(GTK_LABEL(instant_view_)); |
1562 return false; | 1656 if (!suggestion || !*suggestion) |
1563 | |
1564 std::wstring suggest_text = GetTextFromBuffer(instant_buffer_); | |
1565 if (suggest_text.empty()) | |
1566 return false; | 1657 return false; |
1567 | 1658 |
1568 OnBeforePossibleChange(); | 1659 OnBeforePossibleChange(); |
1569 SetUserText(GetText() + suggest_text); | 1660 SetUserText(GetText() + UTF8ToWide(suggestion)); |
1570 OnAfterPossibleChange(); | 1661 OnAfterPossibleChange(); |
1571 return true; | 1662 return true; |
1572 } | 1663 } |
1573 | 1664 |
1574 void AutocompleteEditViewGtk::TextChanged() { | 1665 void AutocompleteEditViewGtk::TextChanged() { |
1575 EmphasizeURLComponents(); | 1666 EmphasizeURLComponents(); |
1576 controller_->OnChanged(); | 1667 controller_->OnChanged(); |
1577 | |
1578 // Move the instant suggestion to the end of the text. | |
1579 GtkTextIter start, end; | |
1580 gtk_text_buffer_get_bounds(text_buffer_, &start, &end); | |
1581 GdkRectangle rect; | |
1582 gtk_text_view_get_iter_location(GTK_TEXT_VIEW(text_view_), &end, &rect); | |
1583 | |
1584 // +1 so the cursor will show. | |
1585 gtk_text_view_move_child(GTK_TEXT_VIEW(text_view_), instant_view_, | |
1586 rect.x + rect.width + 1, 0); | |
1587 } | 1668 } |
1588 | 1669 |
1589 void AutocompleteEditViewGtk::SavePrimarySelection( | 1670 void AutocompleteEditViewGtk::SavePrimarySelection( |
1590 const std::string& selected_text) { | 1671 const std::string& selected_text) { |
1591 GtkClipboard* clipboard = | 1672 GtkClipboard* clipboard = |
1592 gtk_widget_get_clipboard(text_view_, GDK_SELECTION_PRIMARY); | 1673 gtk_widget_get_clipboard(text_view_, GDK_SELECTION_PRIMARY); |
1593 DCHECK(clipboard); | 1674 DCHECK(clipboard); |
1594 if (!clipboard) | 1675 if (!clipboard) |
1595 return; | 1676 return; |
1596 | 1677 |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1665 if (selection_suggested_) { | 1746 if (selection_suggested_) { |
1666 gtk_text_buffer_delete_selection(text_buffer_, true, true); | 1747 gtk_text_buffer_delete_selection(text_buffer_, true, true); |
1667 selection_suggested_ = false; | 1748 selection_suggested_ = false; |
1668 } | 1749 } |
1669 } | 1750 } |
1670 | 1751 |
1671 void AutocompleteEditViewGtk::HandleKeymapDirectionChanged(GdkKeymap* sender) { | 1752 void AutocompleteEditViewGtk::HandleKeymapDirectionChanged(GdkKeymap* sender) { |
1672 AdjustTextJustification(); | 1753 AdjustTextJustification(); |
1673 } | 1754 } |
1674 | 1755 |
1675 gboolean AutocompleteEditViewGtk::HandleInstantViewButtonPress( | 1756 void AutocompleteEditViewGtk::HandleDeleteRange(GtkTextBuffer* buffer, |
1676 GtkWidget* sender, | 1757 GtkTextIter* start, |
1677 GdkEventButton* event) { | 1758 GtkTextIter* end) { |
1678 // Clicking on the view should have no effect; just stop propagation of the | 1759 // Prevent the user from deleting the instant anchor. We can't simply set the |
1679 // event. | 1760 // instant anchor readonly by applying a tag with "editable" = FALSE, because |
1680 return TRUE; | 1761 // it'll prevent the insert caret from blinking. |
| 1762 ValidateTextBufferIter(start); |
| 1763 ValidateTextBufferIter(end); |
| 1764 if (!gtk_text_iter_compare(start, end)) { |
| 1765 static guint signal_id = |
| 1766 g_signal_lookup("delete-range", GTK_TYPE_TEXT_BUFFER); |
| 1767 g_signal_stop_emission(buffer, signal_id, 0); |
| 1768 } |
| 1769 } |
| 1770 |
| 1771 void AutocompleteEditViewGtk::HandleMarkSetAlways(GtkTextBuffer* buffer, |
| 1772 GtkTextIter* location, |
| 1773 GtkTextMark* mark) { |
| 1774 if (mark == instant_mark_) |
| 1775 return; |
| 1776 |
| 1777 GtkTextIter new_iter = *location; |
| 1778 ValidateTextBufferIter(&new_iter); |
| 1779 |
| 1780 // "mark-set" signal is actually emitted after the mark's location is already |
| 1781 // set, so if the location is beyond the instant anchor, we need to move the |
| 1782 // mark again, which will emit the signal again. In order to prevent other |
| 1783 // signal handlers from being called twice, we need to stop signal emission |
| 1784 // before moving the mark again. |
| 1785 if (gtk_text_iter_compare(&new_iter, location)) { |
| 1786 static guint signal_id = g_signal_lookup("mark-set", GTK_TYPE_TEXT_BUFFER); |
| 1787 g_signal_stop_emission(buffer, signal_id, 0); |
| 1788 gtk_text_buffer_move_mark(buffer, mark, &new_iter); |
| 1789 } |
1681 } | 1790 } |
1682 | 1791 |
1683 // static | 1792 // static |
1684 void AutocompleteEditViewGtk::ClipboardGetSelectionThunk( | 1793 void AutocompleteEditViewGtk::ClipboardGetSelectionThunk( |
1685 GtkClipboard* clipboard, | 1794 GtkClipboard* clipboard, |
1686 GtkSelectionData* selection_data, | 1795 GtkSelectionData* selection_data, |
1687 guint info, | 1796 guint info, |
1688 gpointer object) { | 1797 gpointer object) { |
1689 AutocompleteEditViewGtk* edit_view = | 1798 AutocompleteEditViewGtk* edit_view = |
1690 reinterpret_cast<AutocompleteEditViewGtk*>( | 1799 reinterpret_cast<AutocompleteEditViewGtk*>( |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1724 GURL url; | 1833 GURL url; |
1725 bool write_url; | 1834 bool write_url; |
1726 model_->AdjustTextForCopy(selection.selection_min(), IsSelectAll(), &text, | 1835 model_->AdjustTextForCopy(selection.selection_min(), IsSelectAll(), &text, |
1727 &url, &write_url); | 1836 &url, &write_url); |
1728 if (write_url) { | 1837 if (write_url) { |
1729 selected_text_ = WideToUTF8(text); | 1838 selected_text_ = WideToUTF8(text); |
1730 OwnPrimarySelection(selected_text_); | 1839 OwnPrimarySelection(selected_text_); |
1731 } | 1840 } |
1732 } | 1841 } |
1733 | 1842 |
1734 #if GTK_CHECK_VERSION(2,20,0) | 1843 #if GTK_CHECK_VERSION(2, 20, 0) |
1735 void AutocompleteEditViewGtk::HandlePreeditChanged(GtkWidget* sender, | 1844 void AutocompleteEditViewGtk::HandlePreeditChanged(GtkWidget* sender, |
1736 const gchar* preedit) { | 1845 const gchar* preedit) { |
1737 // GtkTextView won't fire "begin-user-action" and "end-user-action" signals | 1846 // GtkTextView won't fire "begin-user-action" and "end-user-action" signals |
1738 // when changing the preedit string, so we need to call | 1847 // when changing the preedit string, so we need to call |
1739 // OnBeforePossibleChange() and OnAfterPossibleChange() by ourselves. | 1848 // OnBeforePossibleChange() and OnAfterPossibleChange() by ourselves. |
1740 OnBeforePossibleChange(); | 1849 OnBeforePossibleChange(); |
1741 if (preedit && *preedit) { | 1850 if (preedit && *preedit) { |
1742 // GtkTextView will only delete the selection range when committing the | 1851 // GtkTextView will only delete the selection range when committing the |
1743 // preedit string, which will cause very strange behavior, so we need to | 1852 // preedit string, which will cause very strange behavior, so we need to |
1744 // delete the selection range here explicitly. See http://crbug.com/18808. | 1853 // delete the selection range here explicitly. See http://crbug.com/18808. |
1745 if (preedit_.empty()) | 1854 if (preedit_.empty()) |
1746 gtk_text_buffer_delete_selection(text_buffer_, false, true); | 1855 gtk_text_buffer_delete_selection(text_buffer_, false, true); |
1747 preedit_ = UTF8ToWide(preedit); | 1856 preedit_ = UTF8ToWide(preedit); |
1748 } else { | 1857 } else { |
1749 preedit_.clear(); | 1858 preedit_.clear(); |
1750 } | 1859 } |
1751 OnAfterPossibleChange(); | 1860 OnAfterPossibleChange(); |
1752 } | 1861 } |
1753 #endif | 1862 #endif |
1754 | 1863 |
1755 void AutocompleteEditViewGtk::HandleWindowSetFocus( | 1864 void AutocompleteEditViewGtk::HandleWindowSetFocus( |
1756 GtkWindow* sender, GtkWidget* focus) { | 1865 GtkWindow* sender, GtkWidget* focus) { |
1757 // This is actually a guess. If the focused widget changes in "focus-out" | 1866 // This is actually a guess. If the focused widget changes in "focus-out" |
1758 // event handler, then the window will respect that and won't focus | 1867 // event handler, then the window will respect that and won't focus |
1759 // |focus|. I doubt that is likely to happen however. | 1868 // |focus|. I doubt that is likely to happen however. |
1760 going_to_focus_ = focus; | 1869 going_to_focus_ = focus; |
1761 } | 1870 } |
| 1871 |
| 1872 void AutocompleteEditViewGtk::HandleUndoRedo(GtkWidget* sender) { |
| 1873 OnBeforePossibleChange(); |
| 1874 } |
| 1875 |
| 1876 void AutocompleteEditViewGtk::HandleUndoRedoAfter(GtkWidget* sender) { |
| 1877 OnAfterPossibleChange(); |
| 1878 } |
| 1879 |
| 1880 void AutocompleteEditViewGtk::GetTextBufferBounds(GtkTextIter* start, |
| 1881 GtkTextIter* end) const { |
| 1882 gtk_text_buffer_get_start_iter(text_buffer_, start); |
| 1883 gtk_text_buffer_get_iter_at_mark(text_buffer_, end, instant_mark_); |
| 1884 } |
| 1885 |
| 1886 void AutocompleteEditViewGtk::ValidateTextBufferIter(GtkTextIter* iter) const { |
| 1887 if (!instant_mark_) |
| 1888 return; |
| 1889 |
| 1890 GtkTextIter end; |
| 1891 gtk_text_buffer_get_iter_at_mark(text_buffer_, &end, instant_mark_); |
| 1892 if (gtk_text_iter_compare(iter, &end) > 0) |
| 1893 *iter = end; |
| 1894 } |
| 1895 |
| 1896 void AutocompleteEditViewGtk::AdjustVerticalAlignmentOfInstantView() { |
| 1897 // By default, GtkTextView layouts an anchored child widget just above the |
| 1898 // baseline, so we need to move the |instant_view_| down to make sure it |
| 1899 // has the same baseline as the |text_view_|. |
| 1900 PangoLayout* layout = gtk_label_get_layout(GTK_LABEL(instant_view_)); |
| 1901 int height; |
| 1902 pango_layout_get_size(layout, NULL, &height); |
| 1903 PangoLayoutIter* iter = pango_layout_get_iter(layout); |
| 1904 int baseline = pango_layout_iter_get_baseline(iter); |
| 1905 pango_layout_iter_free(iter); |
| 1906 g_object_set(instant_anchor_tag_, "rise", baseline - height, NULL); |
| 1907 } |
OLD | NEW |