Chromium Code Reviews| 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> | |
| 11 | |
| 10 #include "app/gfx/font.h" | 12 #include "app/gfx/font.h" |
| 11 #include "app/l10n_util.h" | 13 #include "app/l10n_util.h" |
| 12 #include "base/gfx/gtk_util.h" | 14 #include "base/gfx/gtk_util.h" |
| 13 #include "base/logging.h" | 15 #include "base/logging.h" |
| 14 #include "base/string_util.h" | 16 #include "base/string_util.h" |
| 15 #include "chrome/app/chrome_dll_resource.h" | 17 #include "chrome/app/chrome_dll_resource.h" |
| 16 #include "chrome/browser/autocomplete/autocomplete_edit.h" | 18 #include "chrome/browser/autocomplete/autocomplete_edit.h" |
| 17 #include "chrome/browser/autocomplete/autocomplete_popup_model.h" | 19 #include "chrome/browser/autocomplete/autocomplete_popup_model.h" |
| 18 #include "chrome/browser/autocomplete/autocomplete_popup_view_gtk.h" | 20 #include "chrome/browser/autocomplete/autocomplete_popup_view_gtk.h" |
| 19 #include "chrome/browser/command_updater.h" | 21 #include "chrome/browser/command_updater.h" |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 145 const double kFontSize = 13.4; // 13.4px == 10pt @ 96dpi | 147 const double kFontSize = 13.4; // 13.4px == 10pt @ 96dpi |
| 146 // On Windows, popups have a font size 5/6 the size of non-popups. | 148 // On Windows, popups have a font size 5/6 the size of non-popups. |
| 147 const double kPopupWindowFontSize = kFontSize * 5.0 / 6.0; | 149 const double kPopupWindowFontSize = kFontSize * 5.0 / 6.0; |
| 148 gtk_util::ForceFontSizePixels(text_view_, | 150 gtk_util::ForceFontSizePixels(text_view_, |
| 149 popup_window_mode_ ? kPopupWindowFontSize : kFontSize); | 151 popup_window_mode_ ? kPopupWindowFontSize : kFontSize); |
| 150 } | 152 } |
| 151 | 153 |
| 152 // The text view was floating. It will now be owned by the alignment. | 154 // The text view was floating. It will now be owned by the alignment. |
| 153 gtk_container_add(GTK_CONTAINER(alignment_.get()), text_view_); | 155 gtk_container_add(GTK_CONTAINER(alignment_.get()), text_view_); |
| 154 | 156 |
| 155 // TODO(deanm): This will probably have to be handled differently with the | 157 // Allows inserting tab characters when pressing tab key, to prevent |
| 156 // tab to search business. Maybe we should just eat the tab characters. | 158 // |text_view_| from moving focus. |
| 157 // We want the tab key to move focus, not insert a tab. | 159 // Tab characters will be filtered out by our "insert-text" signal handler |
| 158 gtk_text_view_set_accepts_tab(GTK_TEXT_VIEW(text_view_), false); | 160 // attached to |text_buffer_| object. |
| 161 // Tab key events will be handled by our "key-press-event" signal handler for | |
| 162 // tab to search feature. | |
| 163 gtk_text_view_set_accepts_tab(GTK_TEXT_VIEW(text_view_), TRUE); | |
| 159 | 164 |
| 160 faded_text_tag_ = gtk_text_buffer_create_tag(text_buffer_, | 165 faded_text_tag_ = gtk_text_buffer_create_tag(text_buffer_, |
| 161 NULL, "foreground", kTextBaseColor, NULL); | 166 NULL, "foreground", kTextBaseColor, NULL); |
| 162 secure_scheme_tag_ = gtk_text_buffer_create_tag(text_buffer_, | 167 secure_scheme_tag_ = gtk_text_buffer_create_tag(text_buffer_, |
| 163 NULL, "foreground", kSecureSchemeColor, NULL); | 168 NULL, "foreground", kSecureSchemeColor, NULL); |
| 164 insecure_scheme_tag_ = gtk_text_buffer_create_tag(text_buffer_, | 169 insecure_scheme_tag_ = gtk_text_buffer_create_tag(text_buffer_, |
| 165 NULL, "foreground", kInsecureSchemeColor, NULL); | 170 NULL, "foreground", kInsecureSchemeColor, NULL); |
| 166 normal_text_tag_ = gtk_text_buffer_create_tag(text_buffer_, | 171 normal_text_tag_ = gtk_text_buffer_create_tag(text_buffer_, |
| 167 NULL, "foreground", "#000000", NULL); | 172 NULL, "foreground", "#000000", NULL); |
| 168 | 173 |
| 169 // NOTE: This code used to connect to "changed", however this was fired too | 174 // NOTE: This code used to connect to "changed", however this was fired too |
| 170 // often and during bad times (our own buffer changes?). It works out much | 175 // often and during bad times (our own buffer changes?). It works out much |
| 171 // better to listen to end-user-action, which should be fired whenever the | 176 // better to listen to end-user-action, which should be fired whenever the |
| 172 // user makes some sort of change to the buffer. | 177 // user makes some sort of change to the buffer. |
| 173 g_signal_connect(text_buffer_, "begin-user-action", | 178 g_signal_connect(text_buffer_, "begin-user-action", |
| 174 G_CALLBACK(&HandleBeginUserActionThunk), this); | 179 G_CALLBACK(&HandleBeginUserActionThunk), this); |
| 175 g_signal_connect(text_buffer_, "end-user-action", | 180 g_signal_connect(text_buffer_, "end-user-action", |
| 176 G_CALLBACK(&HandleEndUserActionThunk), this); | 181 G_CALLBACK(&HandleEndUserActionThunk), this); |
| 182 g_signal_connect(text_buffer_, "insert-text", | |
| 183 G_CALLBACK(&HandleInsertTextThunk), this); | |
| 177 // We connect to key press and release for special handling of a few keys. | 184 // We connect to key press and release for special handling of a few keys. |
| 178 g_signal_connect(text_view_, "key-press-event", | 185 g_signal_connect(text_view_, "key-press-event", |
| 179 G_CALLBACK(&HandleKeyPressThunk), this); | 186 G_CALLBACK(&HandleKeyPressThunk), this); |
| 180 g_signal_connect(text_view_, "key-release-event", | 187 g_signal_connect(text_view_, "key-release-event", |
| 181 G_CALLBACK(&HandleKeyReleaseThunk), this); | 188 G_CALLBACK(&HandleKeyReleaseThunk), this); |
| 182 g_signal_connect(text_view_, "button-press-event", | 189 g_signal_connect(text_view_, "button-press-event", |
| 183 G_CALLBACK(&HandleViewButtonPressThunk), this); | 190 G_CALLBACK(&HandleViewButtonPressThunk), this); |
| 184 g_signal_connect(text_view_, "button-release-event", | 191 g_signal_connect(text_view_, "button-release-event", |
| 185 G_CALLBACK(&HandleViewButtonReleaseThunk), this); | 192 G_CALLBACK(&HandleViewButtonReleaseThunk), this); |
| 186 g_signal_connect(text_view_, "focus-in-event", | 193 g_signal_connect(text_view_, "focus-in-event", |
| 187 G_CALLBACK(&HandleViewFocusInThunk), this); | 194 G_CALLBACK(&HandleViewFocusInThunk), this); |
| 188 g_signal_connect(text_view_, "focus-out-event", | 195 g_signal_connect(text_view_, "focus-out-event", |
| 189 G_CALLBACK(&HandleViewFocusOutThunk), this); | 196 G_CALLBACK(&HandleViewFocusOutThunk), this); |
| 190 // NOTE: The GtkTextView documentation asks you not to connect to this | 197 // NOTE: The GtkTextView documentation asks you not to connect to this |
| 191 // signal, but it is very convenient and clean for catching up/down. | 198 // signal, but it is very convenient and clean for catching up/down. |
| 192 g_signal_connect(text_view_, "move-cursor", | 199 g_signal_connect(text_view_, "move-cursor", |
| 193 G_CALLBACK(&HandleViewMoveCursorThunk), this); | 200 G_CALLBACK(&HandleViewMoveCursorThunk), this); |
| 194 // Override the size request. We want to keep the original height request | 201 // Override the size request. We want to keep the original height request |
| 195 // from the widget, since that's font dependent. We want to ignore the width | 202 // from the widget, since that's font dependent. We want to ignore the width |
| 196 // so we don't force a minimum width based on the text length. | 203 // so we don't force a minimum width based on the text length. |
| 197 g_signal_connect(text_view_, "size-request", | 204 g_signal_connect(text_view_, "size-request", |
| 198 G_CALLBACK(&HandleViewSizeRequestThunk), this); | 205 G_CALLBACK(&HandleViewSizeRequestThunk), this); |
| 199 g_signal_connect(text_view_, "populate-popup", | 206 g_signal_connect(text_view_, "populate-popup", |
| 200 G_CALLBACK(&HandlePopulatePopupThunk), this); | 207 G_CALLBACK(&HandlePopulatePopupThunk), this); |
| 201 mark_set_handler_id_ = g_signal_connect( | 208 mark_set_handler_id_ = g_signal_connect( |
| 202 text_buffer_, "mark-set", G_CALLBACK(&HandleMarkSetThunk), this); | 209 text_buffer_, "mark-set", G_CALLBACK(&HandleMarkSetThunk), this); |
| 203 g_signal_connect(text_view_, "drag-data-received", | 210 g_signal_connect(text_view_, "drag-data-received", |
| 204 G_CALLBACK(&HandleDragDataReceivedThunk), this); | 211 G_CALLBACK(&HandleDragDataReceivedThunk), this); |
| 212 g_signal_connect(text_view_, "backspace", | |
| 213 G_CALLBACK(&HandleBackSpaceThunk), this); | |
| 205 | 214 |
| 206 #if !defined(TOOLKIT_VIEWS) | 215 #if !defined(TOOLKIT_VIEWS) |
| 207 registrar_.Add(this, | 216 registrar_.Add(this, |
| 208 NotificationType::BROWSER_THEME_CHANGED, | 217 NotificationType::BROWSER_THEME_CHANGED, |
| 209 NotificationService::AllSources()); | 218 NotificationService::AllSources()); |
| 210 theme_provider_->InitThemesFor(this); | 219 theme_provider_->InitThemesFor(this); |
| 211 #else | 220 #else |
| 212 // Manually invoke SetBaseColor() because TOOLKIT_VIEWS doesn't observe | 221 // Manually invoke SetBaseColor() because TOOLKIT_VIEWS doesn't observe |
| 213 // themes. | 222 // themes. |
| 214 SetBaseColor(); | 223 SetBaseColor(); |
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 495 g_object_set(G_OBJECT(faded_text_tag_), "foreground", kTextBaseColor, NULL); | 504 g_object_set(G_OBJECT(faded_text_tag_), "foreground", kTextBaseColor, NULL); |
| 496 g_object_set(G_OBJECT(normal_text_tag_), "foreground", "#000000", NULL); | 505 g_object_set(G_OBJECT(normal_text_tag_), "foreground", "#000000", NULL); |
| 497 } | 506 } |
| 498 } | 507 } |
| 499 | 508 |
| 500 void AutocompleteEditViewGtk::HandleBeginUserAction() { | 509 void AutocompleteEditViewGtk::HandleBeginUserAction() { |
| 501 OnBeforePossibleChange(); | 510 OnBeforePossibleChange(); |
| 502 } | 511 } |
| 503 | 512 |
| 504 void AutocompleteEditViewGtk::HandleEndUserAction() { | 513 void AutocompleteEditViewGtk::HandleEndUserAction() { |
| 505 // Eat any newline / paragraphs that might have come in, for example in a | |
| 506 // copy and paste. We want to make sure our widget stays single line. | |
| 507 for (;;) { | |
| 508 GtkTextIter cur; | |
| 509 gtk_text_buffer_get_start_iter(text_buffer_, &cur); | |
| 510 | |
| 511 // If there is a line ending, this should put us right before the newline | |
| 512 // or carriage return / newline (or Unicode) sequence. If not, we're done. | |
| 513 if (gtk_text_iter_forward_to_line_end(&cur) == FALSE) | |
| 514 break; | |
| 515 | |
| 516 // Stepping to the next cursor position should put us on the other side of | |
| 517 // the newline / paragraph / etc sequence, and then delete this range. | |
| 518 GtkTextIter next_line = cur; | |
| 519 gtk_text_iter_forward_cursor_position(&next_line); | |
| 520 gtk_text_buffer_delete(text_buffer_, &cur, &next_line); | |
| 521 | |
| 522 // We've invalidated our iterators, gotta start again. | |
| 523 } | |
| 524 | |
| 525 OnAfterPossibleChange(); | 514 OnAfterPossibleChange(); |
| 526 } | 515 } |
| 527 | 516 |
| 528 gboolean AutocompleteEditViewGtk::HandleKeyPress(GtkWidget* widget, | 517 gboolean AutocompleteEditViewGtk::HandleKeyPress(GtkWidget* widget, |
| 529 GdkEventKey* event) { | 518 GdkEventKey* event) { |
| 530 // This is very similar to the special casing of the return key in the | 519 GtkWidgetClass* klass = GTK_WIDGET_GET_CLASS(widget); |
| 531 // GtkTextView key_press default handler. TODO(deanm): We do however omit | 520 |
| 532 // some IME related code, this might become a problem if an IME wants to | 521 // Call the default handler, so that IME can work as normal. |
| 533 // handle enter. We can get at the im_context and do it ourselves if needed. | 522 // New line and tab characters will be filtered out by our "insert-text" |
| 534 if (event->keyval == GDK_Return || | 523 // signal handler attached to |text_buffer_| object. |
| 535 event->keyval == GDK_ISO_Enter || | 524 klass->key_press_event(widget, event); |
| 536 event->keyval == GDK_KP_Enter || | 525 |
| 537 event->keyval == GDK_Tab || | 526 if ((event->keyval == GDK_Tab || event->keyval == GDK_ISO_Left_Tab || |
| 538 (event->keyval == GDK_Escape && | 527 event->keyval == GDK_KP_Tab) && !(event->state & GDK_CONTROL_MASK)) { |
| 539 (event->state & gtk_accelerator_get_default_mod_mask()) == 0)) { | 528 if (model_->is_keyword_hint() && !model_->keyword().empty()) { |
| 540 // Handle IME. This is basically taken from GtkTextView and reworked a bit. | 529 model_->AcceptKeyword(); |
| 541 GtkTextIter iter; | |
| 542 GtkTextView* text_view = GTK_TEXT_VIEW(text_view_); | |
| 543 GtkTextMark* insert = gtk_text_buffer_get_insert(text_buffer_); | |
| 544 gtk_text_buffer_get_iter_at_mark(text_buffer_, &iter, insert); | |
| 545 gboolean can_insert = gtk_text_iter_can_insert(&iter, text_view->editable); | |
| 546 if (gtk_im_context_filter_keypress(text_view->im_context, event)) { | |
| 547 // The IME handled it, do the follow up IME handling. | |
| 548 if (!can_insert) { | |
| 549 gtk_im_context_reset(text_view->im_context); | |
| 550 } else { | |
| 551 text_view->need_im_reset = TRUE; | |
| 552 } | |
| 553 } else { | 530 } else { |
| 554 // Ok, not handled by the IME, we can handle it. | 531 // Handle move focus by ourselves. |
| 555 if (event->keyval == GDK_Tab) { | 532 static guint signal_id = g_signal_lookup("move-focus", GTK_TYPE_WIDGET); |
| 556 if (model_->is_keyword_hint() && !model_->keyword().empty()) { | 533 g_signal_emit(widget, signal_id, 0, (event->state & GDK_SHIFT_MASK) ? |
| 557 model_->AcceptKeyword(); | 534 GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD); |
| 558 } else { | |
| 559 return FALSE; // Let GtkTextView handle the tab focus change. | |
| 560 } | |
| 561 } else if (event->keyval == GDK_Escape) { | |
| 562 model_->OnEscapeKeyPressed(); | |
| 563 } else { | |
| 564 bool alt_held = (event->state & GDK_MOD1_MASK); | |
| 565 model_->AcceptInput(alt_held ? NEW_FOREGROUND_TAB : CURRENT_TAB, false); | |
| 566 } | |
| 567 } | 535 } |
| 568 return TRUE; // Don't propagate into GtkTextView. | 536 } else if (event->keyval == GDK_Return || |
| 537 event->keyval == GDK_ISO_Enter || | |
| 538 event->keyval == GDK_KP_Enter) { | |
| 539 bool alt_held = (event->state & GDK_MOD1_MASK); | |
| 540 model_->AcceptInput(alt_held ? NEW_FOREGROUND_TAB : CURRENT_TAB, false); | |
| 541 } else if (event->keyval == GDK_Escape && | |
| 542 (event->state & gtk_accelerator_get_default_mod_mask()) == 0) { | |
| 543 model_->OnEscapeKeyPressed(); | |
| 569 } | 544 } |
| 570 | 545 |
| 571 return FALSE; // Propagate into GtkTextView. | 546 // Stop propagating the event to prevent the default handler from being |
| 547 // called again. | |
| 548 return TRUE; | |
| 572 } | 549 } |
| 573 | 550 |
| 574 gboolean AutocompleteEditViewGtk::HandleKeyRelease(GtkWidget* widget, | 551 gboolean AutocompleteEditViewGtk::HandleKeyRelease(GtkWidget* widget, |
| 575 GdkEventKey* event) { | 552 GdkEventKey* event) { |
| 576 // Even though we handled the press ourselves, let GtkTextView handle the | 553 // Even though we handled the press ourselves, let GtkTextView handle the |
| 577 // release. It shouldn't do anything particularly interesting, but it will | 554 // release. It shouldn't do anything particularly interesting, but it will |
| 578 // handle the IME work for us. | 555 // handle the IME work for us. |
| 579 return FALSE; // Propagate into GtkTextView. | 556 return FALSE; // Propagate into GtkTextView. |
| 580 } | 557 } |
| 581 | 558 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 639 GtkMovementStep step, | 616 GtkMovementStep step, |
| 640 gint count, | 617 gint count, |
| 641 gboolean extendion_selection) { | 618 gboolean extendion_selection) { |
| 642 // Handle up/down/pgup/pgdn movement on our own. | 619 // Handle up/down/pgup/pgdn movement on our own. |
| 643 int move_amount = count; | 620 int move_amount = count; |
| 644 if (step == GTK_MOVEMENT_PAGES) | 621 if (step == GTK_MOVEMENT_PAGES) |
| 645 move_amount = model_->result().size() * ((count < 0) ? -1 : 1); | 622 move_amount = model_->result().size() * ((count < 0) ? -1 : 1); |
| 646 else if (step != GTK_MOVEMENT_DISPLAY_LINES) | 623 else if (step != GTK_MOVEMENT_DISPLAY_LINES) |
| 647 return; // Propagate into GtkTextView | 624 return; // Propagate into GtkTextView |
| 648 model_->OnUpOrDownKeyPressed(move_amount); | 625 model_->OnUpOrDownKeyPressed(move_amount); |
| 626 | |
| 649 // move-cursor doesn't use a signal accumulator on the return value (it | 627 // move-cursor doesn't use a signal accumulator on the return value (it |
| 650 // just ignores then), so we have to stop the propagation. | 628 // just ignores then), so we have to stop the propagation. |
| 651 g_signal_stop_emission_by_name(text_view_, "move-cursor"); | 629 static guint signal_id = g_signal_lookup("move-cursor", GTK_TYPE_TEXT_VIEW); |
| 630 g_signal_stop_emission(text_view_, signal_id, 0); | |
| 652 } | 631 } |
| 653 | 632 |
| 654 void AutocompleteEditViewGtk::HandleViewSizeRequest(GtkRequisition* req) { | 633 void AutocompleteEditViewGtk::HandleViewSizeRequest(GtkRequisition* req) { |
| 655 // Don't force a minimum width, but use the font-relative height. This is a | 634 // Don't force a minimum width, but use the font-relative height. This is a |
| 656 // run-first handler, so the default handler was already called. | 635 // run-first handler, so the default handler was already called. |
| 657 req->width = 1; | 636 req->width = 1; |
| 658 } | 637 } |
| 659 | 638 |
| 660 void AutocompleteEditViewGtk::HandlePopulatePopup(GtkMenu* menu) { | 639 void AutocompleteEditViewGtk::HandlePopulatePopup(GtkMenu* menu) { |
| 661 GtkWidget* separator = gtk_separator_menu_item_new(); | 640 GtkWidget* separator = gtk_separator_menu_item_new(); |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 755 | 734 |
| 756 guchar* text = gtk_selection_data_get_text(selection_data); | 735 guchar* text = gtk_selection_data_get_text(selection_data); |
| 757 if (!text) | 736 if (!text) |
| 758 return; | 737 return; |
| 759 | 738 |
| 760 std::wstring possible_url = UTF8ToWide(reinterpret_cast<char*>(text)); | 739 std::wstring possible_url = UTF8ToWide(reinterpret_cast<char*>(text)); |
| 761 g_free(text); | 740 g_free(text); |
| 762 if (model_->CanPasteAndGo(CollapseWhitespace(possible_url, true))) { | 741 if (model_->CanPasteAndGo(CollapseWhitespace(possible_url, true))) { |
| 763 model_->PasteAndGo(); | 742 model_->PasteAndGo(); |
| 764 gtk_drag_finish(context, TRUE, TRUE, time); | 743 gtk_drag_finish(context, TRUE, TRUE, time); |
| 765 g_signal_stop_emission_by_name(text_view_, "drag-data-received"); | 744 |
| 745 static guint signal_id = | |
| 746 g_signal_lookup("drag-data-received", GTK_TYPE_WIDGET); | |
| 747 g_signal_stop_emission(text_view_, signal_id, 0); | |
| 766 } | 748 } |
| 767 } | 749 } |
| 768 | 750 |
| 751 void AutocompleteEditViewGtk::HandleInsertText( | |
| 752 GtkTextBuffer* buffer, GtkTextIter* location, const gchar* text, gint len) { | |
| 753 std::string filtered_text; | |
| 754 filtered_text.reserve(len); | |
| 755 | |
| 756 // Filter out new line and tab characters. | |
| 757 // |text| is guaranteed to be a valid UTF-8 string, so it's safe here to | |
| 758 // filter byte by byte. | |
| 759 for (gint i = 0; i < len; ++i) { | |
| 760 gchar c = text[i]; | |
| 761 if (c == '\n' || c == '\r' || c == '\t') | |
| 762 continue; | |
| 763 | |
| 764 filtered_text.push_back(c); | |
| 765 } | |
| 766 | |
| 767 if (filtered_text.length()) { | |
| 768 // Call the default handler to insert filtered text. | |
| 769 GtkTextBufferClass* klass = GTK_TEXT_BUFFER_GET_CLASS(buffer); | |
| 770 klass->insert_text(buffer, location, filtered_text.data(), | |
| 771 static_cast<gint>(filtered_text.length())); | |
| 772 } | |
| 773 | |
| 774 // Stop propagating the signal emission to prevent the default handler from | |
| 775 // being called again. | |
| 776 static guint signal_id = g_signal_lookup("insert-text", GTK_TYPE_TEXT_BUFFER); | |
| 777 g_signal_stop_emission(buffer, signal_id, 0); | |
| 778 } | |
| 779 | |
| 780 void AutocompleteEditViewGtk::HandleBackSpace() { | |
| 781 // Checks if it's currently in keyword search mode. | |
| 782 if (model_->is_keyword_hint() || model_->keyword().empty()) | |
| 783 return; // Propgate into GtkTextView. | |
| 784 | |
| 785 GtkTextIter sel_start, sel_end; | |
| 786 // Checks if there is some text selected. | |
| 787 if (gtk_text_buffer_get_selection_bounds(text_buffer_, &sel_start, &sel_end)) | |
| 788 return; // Propgate into GtkTextView. | |
| 789 | |
| 790 GtkTextIter start; | |
| 791 gtk_text_buffer_get_start_iter(text_buffer_, &start); | |
| 792 | |
| 793 if (!gtk_text_iter_equal(&start, &sel_start)) | |
| 794 return; // Propgate into GtkTextView. | |
|
Dean McNamee
2009/08/12 15:17:55
I am missing why we look at the selection. Don't
James Su
2009/08/12 15:40:10
This piece of code just follows the logic of windo
| |
| 795 | |
| 796 // We're showing a keyword and the user pressed backspace at the beginning | |
| 797 // of the text. Delete the selected keyword. | |
| 798 model_->ClearKeyword(GetText()); | |
| 799 | |
| 800 // Stop propagating the signal emission into GtkTextView. | |
| 801 static guint signal_id = g_signal_lookup("backspace", GTK_TYPE_TEXT_VIEW); | |
| 802 g_signal_stop_emission(text_view_, signal_id, 0); | |
| 803 } | |
| 804 | |
| 769 void AutocompleteEditViewGtk::SelectAllInternal(bool reversed, | 805 void AutocompleteEditViewGtk::SelectAllInternal(bool reversed, |
| 770 bool update_primary_selection) { | 806 bool update_primary_selection) { |
| 771 GtkTextIter start, end; | 807 GtkTextIter start, end; |
| 772 if (reversed) { | 808 if (reversed) { |
| 773 gtk_text_buffer_get_bounds(text_buffer_, &end, &start); | 809 gtk_text_buffer_get_bounds(text_buffer_, &end, &start); |
| 774 } else { | 810 } else { |
| 775 gtk_text_buffer_get_bounds(text_buffer_, &start, &end); | 811 gtk_text_buffer_get_bounds(text_buffer_, &start, &end); |
| 776 } | 812 } |
| 777 if (!update_primary_selection) | 813 if (!update_primary_selection) |
| 778 StartUpdatingHighlightedText(); | 814 StartUpdatingHighlightedText(); |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 894 const std::string& selected_text) { | 930 const std::string& selected_text) { |
| 895 GtkClipboard* clipboard = | 931 GtkClipboard* clipboard = |
| 896 gtk_widget_get_clipboard(text_view_, GDK_SELECTION_PRIMARY); | 932 gtk_widget_get_clipboard(text_view_, GDK_SELECTION_PRIMARY); |
| 897 DCHECK(clipboard); | 933 DCHECK(clipboard); |
| 898 if (!clipboard) | 934 if (!clipboard) |
| 899 return; | 935 return; |
| 900 | 936 |
| 901 gtk_clipboard_set_text( | 937 gtk_clipboard_set_text( |
| 902 clipboard, selected_text.data(), selected_text.size()); | 938 clipboard, selected_text.data(), selected_text.size()); |
| 903 } | 939 } |
| OLD | NEW |