| OLD | NEW |
| 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 <algorithm> | 10 #include <algorithm> |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 101 scheme_security_level_(ToolbarModel::NORMAL), | 101 scheme_security_level_(ToolbarModel::NORMAL), |
| 102 mark_set_handler_id_(0), | 102 mark_set_handler_id_(0), |
| 103 button_1_pressed_(false), | 103 button_1_pressed_(false), |
| 104 text_selected_during_click_(false), | 104 text_selected_during_click_(false), |
| 105 text_view_focused_before_button_press_(false), | 105 text_view_focused_before_button_press_(false), |
| 106 #if !defined(TOOLKIT_VIEWS) | 106 #if !defined(TOOLKIT_VIEWS) |
| 107 theme_provider_(GtkThemeProvider::GetFrom(profile)), | 107 theme_provider_(GtkThemeProvider::GetFrom(profile)), |
| 108 #endif | 108 #endif |
| 109 enter_was_pressed_(false), | 109 enter_was_pressed_(false), |
| 110 tab_was_pressed_(false), | 110 tab_was_pressed_(false), |
| 111 paste_clipboard_requested_(false) { | 111 paste_clipboard_requested_(false), |
| 112 enter_was_inserted_(false) { |
| 112 model_->SetPopupModel(popup_view_->GetModel()); | 113 model_->SetPopupModel(popup_view_->GetModel()); |
| 113 } | 114 } |
| 114 | 115 |
| 115 AutocompleteEditViewGtk::~AutocompleteEditViewGtk() { | 116 AutocompleteEditViewGtk::~AutocompleteEditViewGtk() { |
| 116 NotificationService::current()->Notify( | 117 NotificationService::current()->Notify( |
| 117 NotificationType::AUTOCOMPLETE_EDIT_DESTROYED, | 118 NotificationType::AUTOCOMPLETE_EDIT_DESTROYED, |
| 118 Source<AutocompleteEditViewGtk>(this), | 119 Source<AutocompleteEditViewGtk>(this), |
| 119 NotificationService::NoDetails()); | 120 NotificationService::NoDetails()); |
| 120 | 121 |
| 121 // Explicitly teardown members which have a reference to us. Just to be safe | 122 // Explicitly teardown members which have a reference to us. Just to be safe |
| (...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 455 text_before_change_ = GetText(); | 456 text_before_change_ = GetText(); |
| 456 sel_before_change_ = GetSelection(); | 457 sel_before_change_ = GetSelection(); |
| 457 } | 458 } |
| 458 | 459 |
| 459 // TODO(deanm): This is mostly stolen from Windows, and will need some work. | 460 // TODO(deanm): This is mostly stolen from Windows, and will need some work. |
| 460 bool AutocompleteEditViewGtk::OnAfterPossibleChange() { | 461 bool AutocompleteEditViewGtk::OnAfterPossibleChange() { |
| 461 // If the change is caused by an Enter key press event, and the event was not | 462 // If the change is caused by an Enter key press event, and the event was not |
| 462 // handled by IME, then it's an unexpected change and shall be reverted here. | 463 // handled by IME, then it's an unexpected change and shall be reverted here. |
| 463 // {Start|Finish}UpdatingHighlightedText() are called here to prevent the | 464 // {Start|Finish}UpdatingHighlightedText() are called here to prevent the |
| 464 // PRIMARY selection from being changed. | 465 // PRIMARY selection from being changed. |
| 465 if (enter_was_pressed_ && | 466 if (enter_was_pressed_ && enter_was_inserted_) { |
| 466 (char_inserted_ == '\n' || char_inserted_ == '\r')) { | |
| 467 StartUpdatingHighlightedText(); | 467 StartUpdatingHighlightedText(); |
| 468 SetTextAndSelectedRange(text_before_change_, sel_before_change_); | 468 SetTextAndSelectedRange(text_before_change_, sel_before_change_); |
| 469 FinishUpdatingHighlightedText(); | 469 FinishUpdatingHighlightedText(); |
| 470 return false; | 470 return false; |
| 471 } | 471 } |
| 472 | 472 |
| 473 CharRange new_sel = GetSelection(); | 473 CharRange new_sel = GetSelection(); |
| 474 int length = GetTextLength(); | 474 int length = GetTextLength(); |
| 475 bool selection_differs = (new_sel.cp_min != sel_before_change_.cp_min) || | 475 bool selection_differs = (new_sel.cp_min != sel_before_change_.cp_min) || |
| 476 (new_sel.cp_max != sel_before_change_.cp_max); | 476 (new_sel.cp_max != sel_before_change_.cp_max); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 590 // handler will delete current selection range and insert '\n' and always | 590 // handler will delete current selection range and insert '\n' and always |
| 591 // return TRUE. We need to prevent |text_view_| from performing this default | 591 // return TRUE. We need to prevent |text_view_| from performing this default |
| 592 // action if IME did not handle the key event, because we don't want the | 592 // action if IME did not handle the key event, because we don't want the |
| 593 // content of omnibox to be changed before triggering our special behavior. | 593 // content of omnibox to be changed before triggering our special behavior. |
| 594 // Otherwise our special behavior would not be performed correctly. | 594 // Otherwise our special behavior would not be performed correctly. |
| 595 // | 595 // |
| 596 // But there is no way for us to prevent GtkTextView from handling the key | 596 // But there is no way for us to prevent GtkTextView from handling the key |
| 597 // event and performing built-in operation. So in order to achieve our goal, | 597 // event and performing built-in operation. So in order to achieve our goal, |
| 598 // "insert-text" signal of |text_buffer_| object is intercepted, and | 598 // "insert-text" signal of |text_buffer_| object is intercepted, and |
| 599 // following actions are done in the signal handler: | 599 // following actions are done in the signal handler: |
| 600 // - If there is only one character in inserted text, save it in | 600 // - If there is only one character in inserted text, and it's '\n' or '\r', |
| 601 // char_inserted_. | 601 // then set |enter_was_inserted_| to true. |
| 602 // - Filter out all new line and tab characters. | 602 // - Filter out all new line and tab characters. |
| 603 // | 603 // |
| 604 // So if |char_inserted_| equals '\n' after calling |text_view_|'s | 604 // So if |enter_was_inserted_| is true after calling |text_view_|'s default |
| 605 // default signal handler against an Enter key press event, then we know that | 605 // signal handler against an Enter key press event, then we know that the |
| 606 // the Enter key press event was handled by GtkTextView rather than IME, and | 606 // Enter key press event was handled by GtkTextView rather than IME, and can |
| 607 // can perform the special behavior for Enter key safely. | 607 // perform the special behavior for Enter key safely. |
| 608 // | 608 // |
| 609 // Now the last thing is to prevent the content of omnibox from being changed | 609 // Now the last thing is to prevent the content of omnibox from being changed |
| 610 // by GtkTextView when Enter key is pressed. As OnBeforePossibleChange() and | 610 // by GtkTextView when Enter key is pressed. As OnBeforePossibleChange() and |
| 611 // OnAfterPossibleChange() will be called by GtkTextView before and after | 611 // OnAfterPossibleChange() will be called by GtkTextView before and after |
| 612 // changing the content, and the content is already saved in | 612 // changing the content, and the content is already saved in |
| 613 // OnBeforePossibleChange(), so if the Enter key press event was not handled | 613 // OnBeforePossibleChange(), so if the Enter key press event was not handled |
| 614 // by IME, it's easy to restore the content in OnAfterPossibleChange(), as if | 614 // by IME, it's easy to restore the content in OnAfterPossibleChange(), as if |
| 615 // it's not changed at all. | 615 // it's not changed at all. |
| 616 | 616 |
| 617 GtkWidgetClass* klass = GTK_WIDGET_GET_CLASS(widget); | 617 GtkWidgetClass* klass = GTK_WIDGET_GET_CLASS(widget); |
| 618 | 618 |
| 619 enter_was_pressed_ = (event->keyval == GDK_Return || | 619 enter_was_pressed_ = (event->keyval == GDK_Return || |
| 620 event->keyval == GDK_ISO_Enter || | 620 event->keyval == GDK_ISO_Enter || |
| 621 event->keyval == GDK_KP_Enter); | 621 event->keyval == GDK_KP_Enter); |
| 622 | 622 |
| 623 // Set |tab_was_pressed_| to true if it's a Tab key press event, so that our | 623 // Set |tab_was_pressed_| to true if it's a Tab key press event, so that our |
| 624 // handler of "move-focus" signal can trigger Tab to search behavior when | 624 // handler of "move-focus" signal can trigger Tab to search behavior when |
| 625 // necessary. | 625 // necessary. |
| 626 tab_was_pressed_ = ((event->keyval == GDK_Tab || | 626 tab_was_pressed_ = ((event->keyval == GDK_Tab || |
| 627 event->keyval == GDK_ISO_Left_Tab || | 627 event->keyval == GDK_ISO_Left_Tab || |
| 628 event->keyval == GDK_KP_Tab) && | 628 event->keyval == GDK_KP_Tab) && |
| 629 !(event->state & GDK_CONTROL_MASK)); | 629 !(event->state & GDK_CONTROL_MASK)); |
| 630 | 630 |
| 631 // Reset |char_inserted_|, which may be set in the "insert-text" signal | 631 // Reset |enter_was_inserted_|, which may be set in the "insert-text" signal |
| 632 // handler, so that we'll know if an Enter key event was handled by IME. | 632 // handler, so that we'll know if an Enter key event was handled by IME. |
| 633 char_inserted_ = 0; | 633 enter_was_inserted_ = false; |
| 634 | 634 |
| 635 // Reset |paste_clipboard_requested_| to make sure we won't misinterpret this | 635 // Reset |paste_clipboard_requested_| to make sure we won't misinterpret this |
| 636 // key input action as a paste action. | 636 // key input action as a paste action. |
| 637 paste_clipboard_requested_ = false; | 637 paste_clipboard_requested_ = false; |
| 638 | 638 |
| 639 // Call the default handler, so that IME can work as normal. | 639 // Call the default handler, so that IME can work as normal. |
| 640 // New line characters will be filtered out by our "insert-text" | 640 // New line characters will be filtered out by our "insert-text" |
| 641 // signal handler attached to |text_buffer_| object. | 641 // signal handler attached to |text_buffer_| object. |
| 642 gboolean result = klass->key_press_event(widget, event); | 642 gboolean result = klass->key_press_event(widget, event); |
| 643 | 643 |
| 644 // Set |tab_was_pressed_| to false, to make sure Tab to search behavior can | 644 // Set |tab_was_pressed_| to false, to make sure Tab to search behavior can |
| 645 // only be triggered by pressing Tab key. | 645 // only be triggered by pressing Tab key. |
| 646 tab_was_pressed_ = false; | 646 tab_was_pressed_ = false; |
| 647 | 647 |
| 648 if (enter_was_pressed_ && | 648 if (enter_was_pressed_ && enter_was_inserted_) { |
| 649 (char_inserted_ == '\n' || char_inserted_ == '\r')) { | |
| 650 bool alt_held = (event->state & GDK_MOD1_MASK); | 649 bool alt_held = (event->state & GDK_MOD1_MASK); |
| 651 model_->AcceptInput(alt_held ? NEW_FOREGROUND_TAB : CURRENT_TAB, false); | 650 model_->AcceptInput(alt_held ? NEW_FOREGROUND_TAB : CURRENT_TAB, false); |
| 652 result = TRUE; | 651 result = TRUE; |
| 653 } else if (!result && event->keyval == GDK_Escape && | 652 } else if (!result && event->keyval == GDK_Escape && |
| 654 (event->state & gtk_accelerator_get_default_mod_mask()) == 0) { | 653 (event->state & gtk_accelerator_get_default_mod_mask()) == 0) { |
| 655 // We can handle the Escape key if |text_view_| did not handle it. | 654 // We can handle the Escape key if |text_view_| did not handle it. |
| 656 // If it's not handled by us, then we need to propagate it up to the parent | 655 // If it's not handled by us, then we need to propagate it up to the parent |
| 657 // widgets, so that Escape accelerator can still work. | 656 // widgets, so that Escape accelerator can still work. |
| 658 result = model_->OnEscapeKeyPressed(); | 657 result = model_->OnEscapeKeyPressed(); |
| 659 } else if (event->keyval == GDK_Control_L || event->keyval == GDK_Control_R) { | 658 } else if (event->keyval == GDK_Control_L || event->keyval == GDK_Control_R) { |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 933 filtered_text.reserve(len); | 932 filtered_text.reserve(len); |
| 934 | 933 |
| 935 // Filter out new line and tab characters. | 934 // Filter out new line and tab characters. |
| 936 // |text| is guaranteed to be a valid UTF-8 string, so it's safe here to | 935 // |text| is guaranteed to be a valid UTF-8 string, so it's safe here to |
| 937 // filter byte by byte. | 936 // filter byte by byte. |
| 938 // | 937 // |
| 939 // If there was only a single character, then it might be generated by a key | 938 // If there was only a single character, then it might be generated by a key |
| 940 // event. In this case, we save the single character to help our | 939 // event. In this case, we save the single character to help our |
| 941 // "key-press-event" signal handler distinguish if an Enter key event is | 940 // "key-press-event" signal handler distinguish if an Enter key event is |
| 942 // handled by IME or not. | 941 // handled by IME or not. |
| 943 if (len == 1) | 942 if (len == 1 && (text[0] == '\n' || text[0] == '\r')) |
| 944 char_inserted_ = text[0]; | 943 enter_was_inserted_ = true; |
| 945 | 944 |
| 946 for (gint i = 0; i < len; ++i) { | 945 for (gint i = 0; i < len; ++i) { |
| 947 gchar c = text[i]; | 946 gchar c = text[i]; |
| 948 if (c == '\n' || c == '\r' || c == '\t') | 947 if (c == '\n' || c == '\r' || c == '\t') |
| 949 continue; | 948 continue; |
| 950 | 949 |
| 951 filtered_text.push_back(c); | 950 filtered_text.push_back(c); |
| 952 } | 951 } |
| 953 | 952 |
| 954 if (filtered_text.length()) { | 953 if (filtered_text.length()) { |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1176 std::string utf8 = WideToUTF8(text); | 1175 std::string utf8 = WideToUTF8(text); |
| 1177 gtk_text_buffer_set_text(text_buffer_, utf8.data(), utf8.length()); | 1176 gtk_text_buffer_set_text(text_buffer_, utf8.data(), utf8.length()); |
| 1178 SetSelectedRange(range); | 1177 SetSelectedRange(range); |
| 1179 } | 1178 } |
| 1180 | 1179 |
| 1181 void AutocompleteEditViewGtk::SetSelectedRange(const CharRange& range) { | 1180 void AutocompleteEditViewGtk::SetSelectedRange(const CharRange& range) { |
| 1182 GtkTextIter insert, bound; | 1181 GtkTextIter insert, bound; |
| 1183 ItersFromCharRange(range, &bound, &insert); | 1182 ItersFromCharRange(range, &bound, &insert); |
| 1184 gtk_text_buffer_select_range(text_buffer_, &insert, &bound); | 1183 gtk_text_buffer_select_range(text_buffer_, &insert, &bound); |
| 1185 } | 1184 } |
| OLD | NEW |