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