Home | History | Annotate | Download | only in omnibox
      1 // Copyright 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef CHROME_BROWSER_UI_GTK_OMNIBOX_OMNIBOX_VIEW_GTK_H_
      6 #define CHROME_BROWSER_UI_GTK_OMNIBOX_OMNIBOX_VIEW_GTK_H_
      7 
      8 #include <gtk/gtk.h>
      9 
     10 #include <algorithm>
     11 #include <string>
     12 
     13 #include "base/basictypes.h"
     14 #include "base/memory/scoped_ptr.h"
     15 #include "base/strings/string_util.h"
     16 #include "chrome/browser/ui/omnibox/omnibox_view.h"
     17 #include "chrome/browser/ui/toolbar/toolbar_model.h"
     18 #include "content/public/browser/notification_observer.h"
     19 #include "content/public/browser/notification_registrar.h"
     20 #include "ui/base/gtk/gtk_signal.h"
     21 #include "ui/base/gtk/gtk_signal_registrar.h"
     22 #include "ui/base/gtk/owned_widget_gtk.h"
     23 #include "ui/base/window_open_disposition.h"
     24 #include "ui/gfx/rect.h"
     25 
     26 class Browser;
     27 class OmniboxPopupView;
     28 class Profile;
     29 
     30 namespace gfx {
     31 class Font;
     32 }
     33 
     34 class GtkThemeService;
     35 
     36 class OmniboxViewGtk : public OmniboxView,
     37                        public content::NotificationObserver {
     38  public:
     39   // Modeled like the Windows CHARRANGE.  Represent a pair of cursor position
     40   // offsets.  Since GtkTextIters are invalid after the buffer is changed, we
     41   // work in character offsets (not bytes).
     42   struct CharRange {
     43     CharRange() : cp_min(0), cp_max(0) { }
     44     CharRange(int n, int x) : cp_min(n), cp_max(x) { }
     45 
     46     // Returns the start/end of the selection.
     47     int selection_min() const { return std::min(cp_min, cp_max); }
     48     int selection_max() const { return std::max(cp_min, cp_max); }
     49 
     50     // Work in integers to match the gint GTK APIs.
     51     int cp_min;  // For a selection: Represents the start.
     52     int cp_max;  // For a selection: Represents the end (insert position).
     53   };
     54 
     55   // profile parameter is introduced for unittests which can not instantiate
     56   // browser object and pass NULL to the browser parameter.
     57   // In other use case, you should pass browser->profile() object as
     58   // profile parameter.
     59   OmniboxViewGtk(OmniboxEditController* controller,
     60                  ToolbarModel* toolbar_model,
     61                  Browser* browser,
     62                  Profile* profile,
     63                  CommandUpdater* command_updater,
     64                  bool popup_window_mode,
     65                  GtkWidget* location_bar);
     66   virtual ~OmniboxViewGtk();
     67 
     68   // Initialize, create the underlying widgets, etc.
     69   void Init();
     70 
     71   // OmniboxView:
     72   virtual void SaveStateToTab(content::WebContents* tab) OVERRIDE;
     73   virtual void Update(
     74       const content::WebContents* tab_for_state_restoring) OVERRIDE;
     75   virtual string16 GetText() const OVERRIDE;
     76   virtual void SetWindowTextAndCaretPos(const string16& text,
     77                                         size_t caret_pos,
     78                                         bool update_popup,
     79                                         bool notify_text_changed) OVERRIDE;
     80   virtual void SetForcedQuery() OVERRIDE;
     81   virtual bool IsSelectAll() const OVERRIDE;
     82   virtual bool DeleteAtEndPressed() OVERRIDE;
     83   virtual void GetSelectionBounds(string16::size_type* start,
     84                                   string16::size_type* end) const OVERRIDE;
     85   virtual void SelectAll(bool reversed) OVERRIDE;
     86   virtual void UpdatePopup() OVERRIDE;
     87   virtual void SetFocus() OVERRIDE;
     88   virtual void ApplyCaretVisibility() OVERRIDE;
     89   virtual void OnTemporaryTextMaybeChanged(
     90       const string16& display_text,
     91       bool save_original_selection,
     92       bool notify_text_changed) OVERRIDE;
     93   virtual bool OnInlineAutocompleteTextMaybeChanged(
     94       const string16& display_text, size_t user_text_length) OVERRIDE;
     95   virtual void OnRevertTemporaryText() OVERRIDE;
     96   virtual void OnBeforePossibleChange() OVERRIDE;
     97   virtual bool OnAfterPossibleChange() OVERRIDE;
     98   virtual gfx::NativeView GetNativeView() const OVERRIDE;
     99   virtual gfx::NativeView GetRelativeWindowForPopup() const OVERRIDE;
    100   virtual void SetGrayTextAutocompletion(const string16& suggestion) OVERRIDE;
    101   virtual string16 GetGrayTextAutocompletion() const OVERRIDE;
    102   virtual int TextWidth() const OVERRIDE;
    103   virtual bool IsImeComposing() const OVERRIDE;
    104 
    105   // Overridden from content::NotificationObserver:
    106   virtual void Observe(int type,
    107                        const content::NotificationSource& source,
    108                        const content::NotificationDetails& details) OVERRIDE;
    109 
    110   // Sets the colors of the text view according to the theme.
    111   void SetBaseColor();
    112   // Sets the colors of the gray text suggestion view according to the theme.
    113   void UpdateGrayTextViewColors();
    114 
    115   // Returns the text view gtk widget. May return NULL if the widget
    116   // has already been destroyed.
    117   GtkWidget* text_view() {
    118     return text_view_;
    119   }
    120 
    121  private:
    122   friend class OmniboxViewGtkTest;
    123 
    124   CHROMEG_CALLBACK_0(OmniboxViewGtk, void, HandleBeginUserAction,
    125                      GtkTextBuffer*);
    126   CHROMEG_CALLBACK_0(OmniboxViewGtk, void, HandleEndUserAction, GtkTextBuffer*);
    127   CHROMEG_CALLBACK_2(OmniboxViewGtk, void, HandleMarkSet, GtkTextBuffer*,
    128                      GtkTextIter*, GtkTextMark*);
    129   // As above, but called after the default handler.
    130   CHROMEG_CALLBACK_2(OmniboxViewGtk, void, HandleMarkSetAfter, GtkTextBuffer*,
    131                      GtkTextIter*, GtkTextMark*);
    132   CHROMEG_CALLBACK_3(OmniboxViewGtk, void, HandleInsertText, GtkTextBuffer*,
    133                      GtkTextIter*, const gchar*, gint);
    134   CHROMEG_CALLBACK_0(OmniboxViewGtk, void, HandleKeymapDirectionChanged,
    135                      GdkKeymap*);
    136   CHROMEG_CALLBACK_2(OmniboxViewGtk, void, HandleDeleteRange, GtkTextBuffer*,
    137                      GtkTextIter*, GtkTextIter*);
    138   // Unlike above HandleMarkSet and HandleMarkSetAfter, this handler will always
    139   // be connected to the signal.
    140   CHROMEG_CALLBACK_2(OmniboxViewGtk, void, HandleMarkSetAlways, GtkTextBuffer*,
    141                      GtkTextIter*, GtkTextMark*);
    142 
    143   CHROMEGTK_CALLBACK_1(OmniboxViewGtk, gboolean, HandleKeyPress, GdkEventKey*);
    144   CHROMEGTK_CALLBACK_1(OmniboxViewGtk, gboolean, HandleKeyRelease,
    145                        GdkEventKey*);
    146   CHROMEGTK_CALLBACK_1(OmniboxViewGtk, gboolean, HandleViewButtonPress,
    147                        GdkEventButton*);
    148   CHROMEGTK_CALLBACK_1(OmniboxViewGtk, gboolean, HandleViewButtonRelease,
    149                        GdkEventButton*);
    150   CHROMEGTK_CALLBACK_1(OmniboxViewGtk, gboolean, HandleViewFocusIn,
    151                        GdkEventFocus*);
    152   CHROMEGTK_CALLBACK_1(OmniboxViewGtk, gboolean, HandleViewFocusOut,
    153                        GdkEventFocus*);
    154   CHROMEGTK_CALLBACK_1(OmniboxViewGtk, void, HandleViewMoveFocus,
    155                        GtkDirectionType);
    156   CHROMEGTK_CALLBACK_3(OmniboxViewGtk, void, HandleViewMoveCursor,
    157                        GtkMovementStep, gint, gboolean);
    158   CHROMEGTK_CALLBACK_1(OmniboxViewGtk, void, HandleViewSizeRequest,
    159                        GtkRequisition*);
    160   CHROMEGTK_CALLBACK_1(OmniboxViewGtk, void, HandlePopulatePopup, GtkMenu*);
    161   CHROMEGTK_CALLBACK_0(OmniboxViewGtk, void, HandleEditSearchEngines);
    162   CHROMEGTK_CALLBACK_0(OmniboxViewGtk, void, HandlePasteAndGo);
    163   CHROMEGTK_CALLBACK_6(OmniboxViewGtk, void, HandleDragDataReceived,
    164                        GdkDragContext*, gint, gint, GtkSelectionData*,
    165                        guint, guint);
    166   CHROMEGTK_CALLBACK_4(OmniboxViewGtk, void, HandleDragDataGet,
    167                        GdkDragContext*, GtkSelectionData*, guint, guint);
    168   CHROMEGTK_CALLBACK_1(OmniboxViewGtk, void, HandleDragBegin,
    169                        GdkDragContext*);
    170   CHROMEGTK_CALLBACK_1(OmniboxViewGtk, void, HandleDragEnd,
    171                        GdkDragContext*);
    172   CHROMEGTK_CALLBACK_0(OmniboxViewGtk, void, HandleBackSpace);
    173   CHROMEGTK_CALLBACK_0(OmniboxViewGtk, void, HandleCopyClipboard);
    174   CHROMEGTK_CALLBACK_0(OmniboxViewGtk, void, HandleCopyURLClipboard);
    175   CHROMEGTK_CALLBACK_0(OmniboxViewGtk, void, HandleCutClipboard);
    176   CHROMEGTK_CALLBACK_0(OmniboxViewGtk, void, HandlePasteClipboard);
    177   CHROMEGTK_CALLBACK_1(OmniboxViewGtk, gboolean, HandleExposeEvent,
    178                        GdkEventExpose*);
    179   CHROMEGTK_CALLBACK_1(OmniboxViewGtk, void, HandleWidgetDirectionChanged,
    180                        GtkTextDirection);
    181   CHROMEGTK_CALLBACK_2(OmniboxViewGtk, void, HandleDeleteFromCursor,
    182                        GtkDeleteType, gint);
    183   // We connect to this so we can determine our toplevel window, so we can
    184   // listen to focus change events on it.
    185   CHROMEGTK_CALLBACK_1(OmniboxViewGtk, void, HandleHierarchyChanged,
    186                        GtkWidget*);
    187   CHROMEGTK_CALLBACK_1(OmniboxViewGtk, void, HandlePreEditChanged,
    188                        const gchar*);
    189   // Undo/redo operations won't trigger "begin-user-action" and
    190   // "end-user-action" signals, so we need to hook into "undo" and "redo"
    191   // signals and call OnBeforePossibleChange()/OnAfterPossibleChange() by
    192   // ourselves.
    193   CHROMEGTK_CALLBACK_0(OmniboxViewGtk, void, HandleUndoRedo);
    194   CHROMEGTK_CALLBACK_0(OmniboxViewGtk, void, HandleUndoRedoAfter);
    195 
    196   CHROMEG_CALLBACK_1(OmniboxViewGtk, void, HandleWindowSetFocus,
    197                      GtkWindow*, GtkWidget*);
    198 
    199   // Callback function called after context menu is closed.
    200   CHROMEGTK_CALLBACK_0(OmniboxViewGtk, void, HandlePopupMenuDeactivate);
    201 
    202   // Callback for the PRIMARY selection clipboard.
    203   static void ClipboardGetSelectionThunk(GtkClipboard* clipboard,
    204                                          GtkSelectionData* selection_data,
    205                                          guint info,
    206                                          gpointer object);
    207   void ClipboardGetSelection(GtkClipboard* clipboard,
    208                              GtkSelectionData* selection_data,
    209                              guint info);
    210 
    211   void HandleCopyOrCutClipboard(bool copy);
    212 
    213   // OmniboxView overrides.
    214   virtual int GetOmniboxTextLength() const OVERRIDE;
    215   virtual void EmphasizeURLComponents() OVERRIDE;
    216 
    217   // Common implementation for performing a drop on the edit view.
    218   bool OnPerformDropImpl(const string16& text);
    219 
    220   // Returns the font used in |text_view_|.
    221   gfx::Font GetFont();
    222 
    223   // Take control of the PRIMARY selection clipboard with |text|. Use
    224   // |text_buffer_| as the owner, so that this doesn't remove the selection on
    225   // it. This makes use of the above callbacks.
    226   void OwnPrimarySelection(const std::string& text);
    227 
    228   // Gets the GTK_TEXT_WINDOW_WIDGET coordinates for |text_view_| that bound the
    229   // given iters.
    230   gfx::Rect WindowBoundsFromIters(GtkTextIter* iter1, GtkTextIter* iter2);
    231 
    232   // Actual implementation of SelectAll(), but also provides control over
    233   // whether the PRIMARY selection is set to the selected text (in SelectAll(),
    234   // it isn't, but we want set the selection when the user clicks in the entry).
    235   void SelectAllInternal(bool reversed, bool update_primary_selection);
    236 
    237   // Get ready to update |text_buffer_|'s highlighting without making changes to
    238   // the PRIMARY selection.  Removes the clipboard from |text_buffer_| and
    239   // blocks the "mark-set" signal handler.
    240   void StartUpdatingHighlightedText();
    241 
    242   // Finish updating |text_buffer_|'s highlighting such that future changes will
    243   // automatically update the PRIMARY selection.  Undoes
    244   // StartUpdatingHighlightedText()'s changes.
    245   void FinishUpdatingHighlightedText();
    246 
    247   // Get the character indices of the current selection.  This honors
    248   // direction, cp_max is the insertion point, and cp_min is the bound.
    249   CharRange GetSelection() const;
    250 
    251   // Translate from character positions to iterators for the current buffer.
    252   void ItersFromCharRange(const CharRange& range,
    253                           GtkTextIter* iter_min,
    254                           GtkTextIter* iter_max);
    255 
    256   // Returns true if the caret is at the end of the content.
    257   bool IsCaretAtEnd() const;
    258 
    259   // Save |selected_text| as the PRIMARY X selection. Unlike
    260   // OwnPrimarySelection(), this won't set an owner or use callbacks.
    261   void SavePrimarySelection(const std::string& selected_text);
    262 
    263   // Update the field with |text| and set the selection.
    264   void SetTextAndSelectedRange(const string16& text,
    265                                const CharRange& range);
    266 
    267   // Set the selection to |range|.
    268   void SetSelectedRange(const CharRange& range);
    269 
    270   // Adjust the text justification according to the text direction of the widget
    271   // and |text_buffer_|'s content, to make sure the real text justification is
    272   // always in sync with the UI language direction.
    273   void AdjustTextJustification();
    274 
    275   // Get the text direction of |text_buffer_|'s content, by searching the first
    276   // character that has a strong direction.
    277   PangoDirection GetContentDirection();
    278 
    279   // Returns the selected text.
    280   std::string GetSelectedText() const;
    281 
    282   // If the selected text parses as a URL OwnPrimarySelection is invoked.
    283   void UpdatePrimarySelectionIfValidURL();
    284 
    285   // Retrieves the first and last iterators in the |text_buffer_|, but excludes
    286   // the anchor holding the |gray_text_view_| widget.
    287   void GetTextBufferBounds(GtkTextIter* start, GtkTextIter* end) const;
    288 
    289   // Validates an iterator in the |text_buffer_|, to make sure it doesn't go
    290   // beyond the anchor for holding the |gray_text_view_| widget.
    291   void ValidateTextBufferIter(GtkTextIter* iter) const;
    292 
    293   // Adjusts vertical alignment of the |gray_text_view_| in the |text_view_|, to
    294   // make sure they have the same baseline.
    295   void AdjustVerticalAlignmentOfGrayTextView();
    296 
    297   // The Browser that contains this omnibox.
    298   Browser* browser_;
    299 
    300   // The widget we expose, used for vertically centering the real text edit,
    301   // since the height will change based on the font / font size, etc.
    302   ui::OwnedWidgetGtk alignment_;
    303 
    304   // The actual text entry which will be owned by the alignment_.  The
    305   // reference will be set to NULL upon destruction to tell if the gtk
    306   // widget tree has been destroyed. This is because gtk destroies child
    307   // widgets if the parent (alignemtn_)'s refcount does not go down to 0.
    308   GtkWidget* text_view_;
    309 
    310   GtkTextTagTable* tag_table_;
    311   GtkTextBuffer* text_buffer_;
    312   GtkTextTag* faded_text_tag_;
    313   GtkTextTag* secure_scheme_tag_;
    314   GtkTextTag* security_error_scheme_tag_;
    315   GtkTextTag* normal_text_tag_;
    316 
    317   // Objects for the gray suggestion text view.
    318   GtkTextTag* gray_text_anchor_tag_;
    319 
    320   // A widget for displaying gray autocompletion text. It'll be attached to a
    321   // child anchor in the |text_buffer_| object.
    322   GtkWidget* gray_text_view_;
    323 
    324   // A mark to split the content and the gray text anchor. Wherever the end
    325   // iterator of the text buffer is required, the iterator to this mark should
    326   // be used.
    327   GtkTextMark* gray_text_mark_;
    328 
    329   scoped_ptr<OmniboxPopupView> popup_view_;
    330 
    331   // When true, the location bar view is read only and also is has a slightly
    332   // different presentation (smaller font size). This is used for popups.
    333   bool popup_window_mode_;
    334 
    335   ToolbarModel::SecurityLevel security_level_;
    336 
    337   // Selection at the point where the user started using the
    338   // arrows to move around in the popup.
    339   CharRange saved_temporary_selection_;
    340 
    341   // Tracking state before and after a possible change.
    342   string16 text_before_change_;
    343   CharRange sel_before_change_;
    344 
    345   // The most-recently-selected text from the entry that was copied to the
    346   // clipboard.  This is updated on-the-fly as the user selects text. This may
    347   // differ from the actual selected text, such as when 'http://' is prefixed to
    348   // the text.  It is used in cases where we need to make the PRIMARY selection
    349   // persist even after the user has unhighlighted the text in the view
    350   // (e.g. when they highlight some text and then click to unhighlight it, we
    351   // pass this string to SavePrimarySelection()).
    352   std::string selected_text_;
    353 
    354   std::string dragged_text_;
    355   // When we own the X clipboard, this is the text for it.
    356   std::string primary_selection_text_;
    357 
    358   // IDs of the signal handlers for "mark-set" on |text_buffer_|.
    359   gulong mark_set_handler_id_;
    360   gulong mark_set_handler_id2_;
    361 
    362   // Is the first mouse button currently down?  When selection marks get moved,
    363   // we use this to determine if the user was highlighting text with the mouse
    364   // -- if so, we avoid selecting all the text on mouse-up.
    365   bool button_1_pressed_;
    366 
    367   // Supplies colors, et cetera.
    368   GtkThemeService* theme_service_;
    369 
    370   content::NotificationRegistrar registrar_;
    371 
    372   // Indicates if Enter key was pressed.
    373   //
    374   // It's used in the key press handler to detect an Enter key press event
    375   // during sync dispatch of "end-user-action" signal so that an unexpected
    376   // change caused by the event can be ignored in OnAfterPossibleChange().
    377   bool enter_was_pressed_;
    378 
    379   // Indicates if Tab key was pressed.
    380   //
    381   // It's only used in the key press handler to detect a Tab key press event
    382   // during sync dispatch of "move-focus" signal.
    383   bool tab_was_pressed_;
    384 
    385   // Indicates if Shift key was pressed.
    386   // Used in conjunction with the Tab key to determine if either traversal
    387   // needs to move up the results or if the keyword needs to be cleared.
    388   bool shift_was_pressed_;
    389 
    390   // Indicates that user requested to paste clipboard.
    391   // The actual paste clipboard action might be performed later if the
    392   // clipboard is not empty.
    393   bool paste_clipboard_requested_;
    394 
    395   // Text to "Paste and go"; set by HandlePopulatePopup() and consumed by
    396   // HandlePasteAndGo().
    397   string16 sanitized_text_for_paste_and_go_;
    398 
    399   // Indicates if an Enter key press is inserted as text.
    400   // It's used in the key press handler to determine if an Enter key event is
    401   // handled by IME or not.
    402   bool enter_was_inserted_;
    403 
    404   // Indicates whether the IME changed the text.  It's possible for the IME to
    405   // handle a key event but not change the text contents (e.g., when pressing
    406   // shift+del with no selection).
    407   bool text_changed_;
    408 
    409   // Contains the character range that should have a strikethrough (used for
    410   // insecure schemes). If the range is size one or less, no strikethrough
    411   // is needed.
    412   CharRange strikethrough_;
    413 
    414   // Indicates if the selected text is suggested text or not. If the selection
    415   // is not suggested text, that means the user manually made the selection.
    416   bool selection_suggested_;
    417 
    418   // Was delete pressed?
    419   bool delete_was_pressed_;
    420 
    421   // Was the delete key pressed with an empty selection at the end of the edit?
    422   bool delete_at_end_pressed_;
    423 
    424   // Indicates if we are handling a key press event.
    425   bool handling_key_press_;
    426 
    427   // Indicates if omnibox's content maybe changed by a key press event, so that
    428   // we need to call OnAfterPossibleChange() after handling the event.
    429   // This flag should be set for changes directly caused by a key press event,
    430   // including changes to content text, selection range and pre-edit string.
    431   // Changes caused by function calls like SetUserText() should not affect this
    432   // flag.
    433   bool content_maybe_changed_by_key_press_;
    434 
    435   // Set this flag to call UpdatePopup() in lost focus and need to update.
    436   // Because context menu might take the focus, before setting the flag, check
    437   // the focus with model_->has_focus().
    438   bool update_popup_without_focus_;
    439 
    440   // On GTK 2.20+ |pre_edit_| and |pre_edit_size_before_change_| will be used.
    441   const bool supports_pre_edit_;
    442 
    443   // Stores the text being composed by the input method.
    444   string16 pre_edit_;
    445 
    446   // Tracking pre-edit state before and after a possible change. We don't need
    447   // to track pre-edit_'s content, as it'll be treated as part of text content.
    448   size_t pre_edit_size_before_change_;
    449 
    450   // The view that is going to be focused next. Only valid while handling
    451   // "focus-out" events.
    452   GtkWidget* going_to_focus_;
    453 
    454   ui::GtkSignalRegistrar signals_;
    455 
    456   DISALLOW_COPY_AND_ASSIGN(OmniboxViewGtk);
    457 };
    458 
    459 #endif  // CHROME_BROWSER_UI_GTK_OMNIBOX_OMNIBOX_VIEW_GTK_H_
    460