OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/gtk/location_bar_view_gtk.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "app/gtk_dnd_util.h" | |
10 #include "app/l10n_util.h" | |
11 #include "app/resource_bundle.h" | |
12 #include "base/basictypes.h" | |
13 #include "base/command_line.h" | |
14 #include "base/i18n/rtl.h" | |
15 #include "base/logging.h" | |
16 #include "base/string_util.h" | |
17 #include "base/utf_string_conversions.h" | |
18 #include "chrome/app/chrome_command_ids.h" | |
19 #include "chrome/browser/accessibility_events.h" | |
20 #include "chrome/browser/alternate_nav_url_fetcher.h" | |
21 #include "chrome/browser/autocomplete/autocomplete_edit_view_gtk.h" | |
22 #include "chrome/browser/autocomplete/autocomplete_popup_model.h" | |
23 #include "chrome/browser/browser_list.h" | |
24 #include "chrome/browser/command_updater.h" | |
25 #include "chrome/browser/content_setting_bubble_model.h" | |
26 #include "chrome/browser/content_setting_image_model.h" | |
27 #include "chrome/browser/defaults.h" | |
28 #include "chrome/browser/extensions/extension_browser_event_router.h" | |
29 #include "chrome/browser/extensions/extension_tabs_module.h" | |
30 #include "chrome/browser/extensions/extension_service.h" | |
31 #include "chrome/browser/gtk/bookmark_bubble_gtk.h" | |
32 #include "chrome/browser/gtk/bookmark_utils_gtk.h" | |
33 #include "chrome/browser/gtk/cairo_cached_surface.h" | |
34 #include "chrome/browser/gtk/content_setting_bubble_gtk.h" | |
35 #include "chrome/browser/gtk/extension_popup_gtk.h" | |
36 #include "chrome/browser/gtk/first_run_bubble.h" | |
37 #include "chrome/browser/gtk/gtk_theme_provider.h" | |
38 #include "chrome/browser/gtk/gtk_util.h" | |
39 #include "chrome/browser/gtk/nine_box.h" | |
40 #include "chrome/browser/gtk/rounded_window.h" | |
41 #include "chrome/browser/gtk/view_id_util.h" | |
42 #include "chrome/browser/instant/instant_controller.h" | |
43 #include "chrome/browser/profiles/profile.h" | |
44 #include "chrome/browser/search_engines/template_url.h" | |
45 #include "chrome/browser/search_engines/template_url_model.h" | |
46 #include "chrome/browser/tab_contents/tab_contents.h" | |
47 #include "chrome/browser/ui/browser.h" | |
48 #include "chrome/browser/ui/omnibox/location_bar_util.h" | |
49 #include "chrome/common/chrome_switches.h" | |
50 #include "chrome/common/extensions/extension.h" | |
51 #include "chrome/common/extensions/extension_action.h" | |
52 #include "chrome/common/extensions/extension_resource.h" | |
53 #include "chrome/common/notification_service.h" | |
54 #include "chrome/common/page_transition_types.h" | |
55 #include "chrome/common/pref_names.h" | |
56 #include "gfx/canvas_skia_paint.h" | |
57 #include "gfx/font.h" | |
58 #include "gfx/gtk_util.h" | |
59 #include "grit/generated_resources.h" | |
60 #include "grit/theme_resources.h" | |
61 #include "net/base/net_util.h" | |
62 #include "webkit/glue/window_open_disposition.h" | |
63 | |
64 namespace { | |
65 | |
66 // We are positioned with a little bit of extra space that we don't use now. | |
67 const int kTopMargin = 1; | |
68 const int kBottomMargin = 1; | |
69 const int kLeftMargin = 1; | |
70 const int kRightMargin = 1; | |
71 // We draw a border on the top and bottom (but not on left or right). | |
72 const int kBorderThickness = 1; | |
73 | |
74 // Left margin of first run bubble. | |
75 const int kFirstRunBubbleLeftMargin = 8; | |
76 // Extra vertical spacing for first run bubble. | |
77 const int kFirstRunBubbleTopMargin = 5; | |
78 | |
79 // The padding around the top, bottom, and sides of the location bar hbox. | |
80 // We don't want to edit control's text to be right against the edge, | |
81 // as well the tab to search box and other widgets need to have the padding on | |
82 // top and bottom to avoid drawing larger than the location bar space. | |
83 const int kHboxBorder = 2; | |
84 | |
85 // Padding between the elements in the bar. | |
86 const int kInnerPadding = 2; | |
87 | |
88 // Padding between the right of the star and the edge of the URL entry. | |
89 const int kStarRightPadding = 2; | |
90 | |
91 // Colors used to draw the EV certificate rounded bubble. | |
92 const GdkColor kEvSecureTextColor = GDK_COLOR_RGB(0x07, 0x95, 0x00); | |
93 const GdkColor kEvSecureBackgroundColor = GDK_COLOR_RGB(0xef, 0xfc, 0xef); | |
94 const GdkColor kEvSecureBorderColor = GDK_COLOR_RGB(0x90, 0xc3, 0x90); | |
95 | |
96 // Colors used to draw the Tab to Search rounded bubble. | |
97 const GdkColor kKeywordBackgroundColor = GDK_COLOR_RGB(0xf0, 0xf4, 0xfa); | |
98 const GdkColor kKeywordBorderColor = GDK_COLOR_RGB(0xcb, 0xde, 0xf7); | |
99 | |
100 // Use weak gray for showing search and keyword hint text. | |
101 const GdkColor kHintTextColor = GDK_COLOR_RGB(0x75, 0x75, 0x75); | |
102 | |
103 // Size of the rounding of the "Search site for:" box. | |
104 const int kCornerSize = 3; | |
105 | |
106 // If widget is visible, increment the int pointed to by count. | |
107 // Suitible for use with gtk_container_foreach. | |
108 void CountVisibleWidgets(GtkWidget* widget, gpointer count) { | |
109 if (GTK_WIDGET_VISIBLE(widget)) | |
110 *static_cast<int*>(count) += 1; | |
111 } | |
112 | |
113 } // namespace | |
114 | |
115 //////////////////////////////////////////////////////////////////////////////// | |
116 // LocationBarViewGtk | |
117 | |
118 // static | |
119 const GdkColor LocationBarViewGtk::kBackgroundColor = | |
120 GDK_COLOR_RGB(255, 255, 255); | |
121 | |
122 LocationBarViewGtk::LocationBarViewGtk(Browser* browser) | |
123 : star_image_(NULL), | |
124 starred_(false), | |
125 site_type_alignment_(NULL), | |
126 site_type_event_box_(NULL), | |
127 location_icon_image_(NULL), | |
128 drag_icon_(NULL), | |
129 enable_location_drag_(false), | |
130 security_info_label_(NULL), | |
131 tab_to_search_box_(NULL), | |
132 tab_to_search_full_label_(NULL), | |
133 tab_to_search_partial_label_(NULL), | |
134 tab_to_search_hint_(NULL), | |
135 tab_to_search_hint_leading_label_(NULL), | |
136 tab_to_search_hint_icon_(NULL), | |
137 tab_to_search_hint_trailing_label_(NULL), | |
138 profile_(NULL), | |
139 command_updater_(browser->command_updater()), | |
140 toolbar_model_(browser->toolbar_model()), | |
141 browser_(browser), | |
142 disposition_(CURRENT_TAB), | |
143 transition_(PageTransition::TYPED), | |
144 first_run_bubble_(this), | |
145 popup_window_mode_(false), | |
146 theme_provider_(NULL), | |
147 hbox_width_(0), | |
148 entry_box_width_(0), | |
149 show_selected_keyword_(false), | |
150 show_keyword_hint_(false), | |
151 update_instant_(true) { | |
152 } | |
153 | |
154 LocationBarViewGtk::~LocationBarViewGtk() { | |
155 // All of our widgets should have be children of / owned by the alignment. | |
156 star_.Destroy(); | |
157 hbox_.Destroy(); | |
158 content_setting_hbox_.Destroy(); | |
159 page_action_hbox_.Destroy(); | |
160 } | |
161 | |
162 void LocationBarViewGtk::Init(bool popup_window_mode) { | |
163 popup_window_mode_ = popup_window_mode; | |
164 | |
165 // Create the widget first, so we can pass it to the AutocompleteEditViewGtk. | |
166 hbox_.Own(gtk_hbox_new(FALSE, kInnerPadding)); | |
167 gtk_container_set_border_width(GTK_CONTAINER(hbox_.get()), kHboxBorder); | |
168 // We will paint for the alignment, to paint the background and border. | |
169 gtk_widget_set_app_paintable(hbox_.get(), TRUE); | |
170 // Redraw the whole location bar when it changes size (e.g., when toggling | |
171 // the home button on/off. | |
172 gtk_widget_set_redraw_on_allocate(hbox_.get(), TRUE); | |
173 | |
174 // Now initialize the AutocompleteEditViewGtk. | |
175 location_entry_.reset(new AutocompleteEditViewGtk(this, | |
176 toolbar_model_, | |
177 profile_, | |
178 command_updater_, | |
179 popup_window_mode_, | |
180 hbox_.get())); | |
181 location_entry_->Init(); | |
182 | |
183 g_signal_connect(hbox_.get(), "expose-event", | |
184 G_CALLBACK(&HandleExposeThunk), this); | |
185 | |
186 BuildSiteTypeArea(); | |
187 | |
188 // Put |tab_to_search_box_|, |location_entry_|, and |tab_to_search_hint_| into | |
189 // a sub hbox, so that we can make this part horizontally shrinkable without | |
190 // affecting other elements in the location bar. | |
191 entry_box_ = gtk_hbox_new(FALSE, kInnerPadding); | |
192 gtk_widget_show(entry_box_); | |
193 gtk_widget_set_size_request(entry_box_, 0, -1); | |
194 gtk_box_pack_start(GTK_BOX(hbox_.get()), entry_box_, TRUE, TRUE, 0); | |
195 | |
196 // We need to adjust the visibility of the search hint widgets according to | |
197 // the horizontal space in the |entry_box_|. | |
198 g_signal_connect(entry_box_, "size-allocate", | |
199 G_CALLBACK(&OnEntryBoxSizeAllocateThunk), this); | |
200 | |
201 // Tab to search (the keyword box on the left hand side). | |
202 tab_to_search_full_label_ = gtk_label_new(NULL); | |
203 tab_to_search_partial_label_ = gtk_label_new(NULL); | |
204 GtkWidget* tab_to_search_label_hbox = gtk_hbox_new(FALSE, 0); | |
205 gtk_box_pack_start(GTK_BOX(tab_to_search_label_hbox), | |
206 tab_to_search_full_label_, FALSE, FALSE, 0); | |
207 gtk_box_pack_start(GTK_BOX(tab_to_search_label_hbox), | |
208 tab_to_search_partial_label_, FALSE, FALSE, 0); | |
209 GtkWidget* tab_to_search_hbox = gtk_hbox_new(FALSE, 0); | |
210 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
211 tab_to_search_magnifier_ = gtk_image_new_from_pixbuf( | |
212 rb.GetPixbufNamed(IDR_KEYWORD_SEARCH_MAGNIFIER)); | |
213 gtk_box_pack_start(GTK_BOX(tab_to_search_hbox), tab_to_search_magnifier_, | |
214 FALSE, FALSE, 0); | |
215 gtk_util::CenterWidgetInHBox(tab_to_search_hbox, tab_to_search_label_hbox, | |
216 false, 0); | |
217 | |
218 // This creates a box around the keyword text with a border, background color, | |
219 // and padding around the text. | |
220 tab_to_search_box_ = gtk_util::CreateGtkBorderBin( | |
221 tab_to_search_hbox, NULL, 1, 1, 1, 3); | |
222 gtk_widget_set_name(tab_to_search_box_, "chrome-tab-to-search-box"); | |
223 gtk_util::ActAsRoundedWindow(tab_to_search_box_, kKeywordBorderColor, | |
224 kCornerSize, | |
225 gtk_util::ROUNDED_ALL, gtk_util::BORDER_ALL); | |
226 // Show all children widgets of |tab_to_search_box_| initially, except | |
227 // |tab_to_search_partial_label_|. | |
228 gtk_widget_show_all(tab_to_search_box_); | |
229 gtk_widget_hide(tab_to_search_box_); | |
230 gtk_widget_hide(tab_to_search_partial_label_); | |
231 gtk_box_pack_start(GTK_BOX(entry_box_), tab_to_search_box_, FALSE, FALSE, 0); | |
232 | |
233 location_entry_alignment_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); | |
234 gtk_container_add(GTK_CONTAINER(location_entry_alignment_), | |
235 location_entry_->GetNativeView()); | |
236 gtk_box_pack_start(GTK_BOX(entry_box_), location_entry_alignment_, | |
237 TRUE, TRUE, 0); | |
238 | |
239 // Tab to search notification (the hint on the right hand side). | |
240 tab_to_search_hint_ = gtk_hbox_new(FALSE, 0); | |
241 gtk_widget_set_name(tab_to_search_hint_, "chrome-tab-to-search-hint"); | |
242 tab_to_search_hint_leading_label_ = gtk_label_new(NULL); | |
243 gtk_widget_set_sensitive(tab_to_search_hint_leading_label_, FALSE); | |
244 tab_to_search_hint_icon_ = gtk_image_new_from_pixbuf( | |
245 rb.GetPixbufNamed(IDR_LOCATION_BAR_KEYWORD_HINT_TAB)); | |
246 tab_to_search_hint_trailing_label_ = gtk_label_new(NULL); | |
247 gtk_widget_set_sensitive(tab_to_search_hint_trailing_label_, FALSE); | |
248 gtk_box_pack_start(GTK_BOX(tab_to_search_hint_), | |
249 tab_to_search_hint_leading_label_, | |
250 FALSE, FALSE, 0); | |
251 gtk_box_pack_start(GTK_BOX(tab_to_search_hint_), | |
252 tab_to_search_hint_icon_, | |
253 FALSE, FALSE, 0); | |
254 gtk_box_pack_start(GTK_BOX(tab_to_search_hint_), | |
255 tab_to_search_hint_trailing_label_, | |
256 FALSE, FALSE, 0); | |
257 // Show all children widgets of |tab_to_search_hint_| initially. | |
258 gtk_widget_show_all(tab_to_search_hint_); | |
259 gtk_widget_hide(tab_to_search_hint_); | |
260 // tab_to_search_hint_ gets hidden initially in OnChanged. Hiding it here | |
261 // doesn't work, someone is probably calling show_all on our parent box. | |
262 gtk_box_pack_end(GTK_BOX(entry_box_), tab_to_search_hint_, FALSE, FALSE, 0); | |
263 | |
264 // We don't show the star in popups, app windows, etc. | |
265 if (browser_defaults::bookmarks_enabled && !ShouldOnlyShowLocation()) { | |
266 CreateStarButton(); | |
267 gtk_box_pack_end(GTK_BOX(hbox_.get()), star_.get(), FALSE, FALSE, 0); | |
268 } | |
269 | |
270 content_setting_hbox_.Own(gtk_hbox_new(FALSE, kInnerPadding + 1)); | |
271 gtk_widget_set_name(content_setting_hbox_.get(), | |
272 "chrome-content-setting-hbox"); | |
273 gtk_box_pack_end(GTK_BOX(hbox_.get()), content_setting_hbox_.get(), | |
274 FALSE, FALSE, 1); | |
275 | |
276 for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) { | |
277 ContentSettingImageViewGtk* content_setting_view = | |
278 new ContentSettingImageViewGtk( | |
279 static_cast<ContentSettingsType>(i), this, profile_); | |
280 content_setting_views_.push_back(content_setting_view); | |
281 gtk_box_pack_end(GTK_BOX(content_setting_hbox_.get()), | |
282 content_setting_view->widget(), FALSE, FALSE, 0); | |
283 } | |
284 | |
285 page_action_hbox_.Own(gtk_hbox_new(FALSE, kInnerPadding)); | |
286 gtk_widget_set_name(page_action_hbox_.get(), | |
287 "chrome-page-action-hbox"); | |
288 gtk_box_pack_end(GTK_BOX(hbox_.get()), page_action_hbox_.get(), | |
289 FALSE, FALSE, 0); | |
290 | |
291 // Now that we've created the widget hierarchy, connect to the main |hbox_|'s | |
292 // size-allocate so we can do proper resizing and eliding on | |
293 // |security_info_label_|. | |
294 g_signal_connect(hbox_.get(), "size-allocate", | |
295 G_CALLBACK(&OnHboxSizeAllocateThunk), this); | |
296 | |
297 registrar_.Add(this, | |
298 NotificationType::BROWSER_THEME_CHANGED, | |
299 NotificationService::AllSources()); | |
300 theme_provider_ = GtkThemeProvider::GetFrom(profile_); | |
301 theme_provider_->InitThemesFor(this); | |
302 } | |
303 | |
304 void LocationBarViewGtk::BuildSiteTypeArea() { | |
305 location_icon_image_ = gtk_image_new(); | |
306 gtk_widget_set_name(location_icon_image_, "chrome-location-icon"); | |
307 | |
308 GtkWidget* icon_alignment = gtk_alignment_new(0, 0, 1, 1); | |
309 gtk_alignment_set_padding(GTK_ALIGNMENT(icon_alignment), 0, 0, 2, 0); | |
310 gtk_container_add(GTK_CONTAINER(icon_alignment), location_icon_image_); | |
311 gtk_widget_show_all(icon_alignment); | |
312 | |
313 security_info_label_ = gtk_label_new(NULL); | |
314 gtk_label_set_ellipsize(GTK_LABEL(security_info_label_), | |
315 PANGO_ELLIPSIZE_MIDDLE); | |
316 gtk_widget_modify_fg(GTK_WIDGET(security_info_label_), GTK_STATE_NORMAL, | |
317 &kEvSecureTextColor); | |
318 gtk_widget_set_name(security_info_label_, | |
319 "chrome-location-bar-security-info-label"); | |
320 | |
321 GtkWidget* site_type_hbox = gtk_hbox_new(FALSE, 1); | |
322 gtk_box_pack_start(GTK_BOX(site_type_hbox), icon_alignment, | |
323 FALSE, FALSE, 0); | |
324 gtk_box_pack_start(GTK_BOX(site_type_hbox), security_info_label_, | |
325 FALSE, FALSE, 2); | |
326 | |
327 site_type_event_box_ = gtk_event_box_new(); | |
328 gtk_widget_modify_bg(site_type_event_box_, GTK_STATE_NORMAL, | |
329 &kEvSecureBackgroundColor); | |
330 g_signal_connect(site_type_event_box_, "drag-data-get", | |
331 G_CALLBACK(&OnIconDragDataThunk), this); | |
332 g_signal_connect(site_type_event_box_, "drag-begin", | |
333 G_CALLBACK(&OnIconDragBeginThunk), this); | |
334 g_signal_connect(site_type_event_box_, "drag-end", | |
335 G_CALLBACK(&OnIconDragEndThunk), this); | |
336 | |
337 // Make the event box not visible so it does not paint a background. | |
338 gtk_event_box_set_visible_window(GTK_EVENT_BOX(site_type_event_box_), | |
339 FALSE); | |
340 gtk_widget_set_name(site_type_event_box_, | |
341 "chrome-location-icon-eventbox"); | |
342 gtk_container_add(GTK_CONTAINER(site_type_event_box_), | |
343 site_type_hbox); | |
344 | |
345 // Put the event box in an alignment to get the padding correct. | |
346 site_type_alignment_ = gtk_alignment_new(0, 0, 1, 1); | |
347 gtk_alignment_set_padding(GTK_ALIGNMENT(site_type_alignment_), | |
348 1, 1, 0, 0); | |
349 gtk_container_add(GTK_CONTAINER(site_type_alignment_), | |
350 site_type_event_box_); | |
351 gtk_box_pack_start(GTK_BOX(hbox_.get()), site_type_alignment_, | |
352 FALSE, FALSE, 0); | |
353 | |
354 g_signal_connect(site_type_event_box_, "button-release-event", | |
355 G_CALLBACK(&OnIconReleasedThunk), this); | |
356 } | |
357 | |
358 void LocationBarViewGtk::SetSiteTypeDragSource() { | |
359 bool enable = !location_entry()->IsEditingOrEmpty(); | |
360 if (enable_location_drag_ == enable) | |
361 return; | |
362 enable_location_drag_ = enable; | |
363 | |
364 if (!enable) { | |
365 gtk_drag_source_unset(site_type_event_box_); | |
366 return; | |
367 } | |
368 | |
369 gtk_drag_source_set(site_type_event_box_, GDK_BUTTON1_MASK, | |
370 NULL, 0, GDK_ACTION_COPY); | |
371 gtk_dnd_util::SetSourceTargetListFromCodeMask(site_type_event_box_, | |
372 gtk_dnd_util::TEXT_PLAIN | | |
373 gtk_dnd_util::TEXT_URI_LIST | | |
374 gtk_dnd_util::CHROME_NAMED_URL); | |
375 } | |
376 | |
377 void LocationBarViewGtk::SetProfile(Profile* profile) { | |
378 profile_ = profile; | |
379 } | |
380 | |
381 TabContents* LocationBarViewGtk::GetTabContents() const { | |
382 return browser_->GetSelectedTabContents(); | |
383 } | |
384 | |
385 void LocationBarViewGtk::SetPreviewEnabledPageAction( | |
386 ExtensionAction *page_action, | |
387 bool preview_enabled) { | |
388 DCHECK(page_action); | |
389 UpdatePageActions(); | |
390 for (ScopedVector<PageActionViewGtk>::iterator iter = | |
391 page_action_views_.begin(); iter != page_action_views_.end(); | |
392 ++iter) { | |
393 if ((*iter)->page_action() == page_action) { | |
394 (*iter)->set_preview_enabled(preview_enabled); | |
395 UpdatePageActions(); | |
396 return; | |
397 } | |
398 } | |
399 } | |
400 | |
401 GtkWidget* LocationBarViewGtk::GetPageActionWidget( | |
402 ExtensionAction *page_action) { | |
403 DCHECK(page_action); | |
404 for (ScopedVector<PageActionViewGtk>::iterator iter = | |
405 page_action_views_.begin(); | |
406 iter != page_action_views_.end(); | |
407 ++iter) { | |
408 if ((*iter)->page_action() == page_action) | |
409 return (*iter)->widget(); | |
410 } | |
411 return NULL; | |
412 } | |
413 | |
414 void LocationBarViewGtk::Update(const TabContents* contents) { | |
415 bool star_enabled = star_.get() && !toolbar_model_->input_in_progress(); | |
416 command_updater_->UpdateCommandEnabled(IDC_BOOKMARK_PAGE, star_enabled); | |
417 if (star_.get()) { | |
418 if (star_enabled) | |
419 gtk_widget_show_all(star_.get()); | |
420 else | |
421 gtk_widget_hide_all(star_.get()); | |
422 } | |
423 UpdateSiteTypeArea(); | |
424 UpdateContentSettingsIcons(); | |
425 UpdatePageActions(); | |
426 location_entry_->Update(contents); | |
427 // The security level (background color) could have changed, etc. | |
428 if (theme_provider_->UseGtkTheme()) { | |
429 // In GTK mode, we need our parent to redraw, as it draws the text entry | |
430 // border. | |
431 gtk_widget_queue_draw(widget()->parent); | |
432 } else { | |
433 gtk_widget_queue_draw(widget()); | |
434 } | |
435 } | |
436 | |
437 void LocationBarViewGtk::OnAutocompleteWillClosePopup() { | |
438 if (!update_instant_) | |
439 return; | |
440 | |
441 InstantController* instant = browser_->instant(); | |
442 if (instant && !instant->commit_on_mouse_up()) | |
443 instant->DestroyPreviewContents(); | |
444 } | |
445 | |
446 void LocationBarViewGtk::OnAutocompleteLosingFocus( | |
447 gfx::NativeView view_gaining_focus) { | |
448 SetSuggestedText(string16()); | |
449 | |
450 InstantController* instant = browser_->instant(); | |
451 if (instant) | |
452 instant->OnAutocompleteLostFocus(view_gaining_focus); | |
453 } | |
454 | |
455 void LocationBarViewGtk::OnAutocompleteWillAccept() { | |
456 update_instant_ = false; | |
457 } | |
458 | |
459 bool LocationBarViewGtk::OnCommitSuggestedText( | |
460 const std::wstring& typed_text) { | |
461 return browser_->instant() && location_entry_->CommitInstantSuggestion(); | |
462 } | |
463 | |
464 bool LocationBarViewGtk::AcceptCurrentInstantPreview() { | |
465 return InstantController::CommitIfCurrent(browser_->instant()); | |
466 } | |
467 | |
468 void LocationBarViewGtk::OnSetSuggestedSearchText( | |
469 const string16& suggested_text) { | |
470 SetSuggestedText(suggested_text); | |
471 } | |
472 | |
473 void LocationBarViewGtk::OnPopupBoundsChanged(const gfx::Rect& bounds) { | |
474 InstantController* instant = browser_->instant(); | |
475 if (instant) | |
476 instant->SetOmniboxBounds(bounds); | |
477 } | |
478 | |
479 void LocationBarViewGtk::OnAutocompleteAccept(const GURL& url, | |
480 WindowOpenDisposition disposition, | |
481 PageTransition::Type transition, | |
482 const GURL& alternate_nav_url) { | |
483 if (url.is_valid()) { | |
484 location_input_ = UTF8ToWide(url.spec()); | |
485 disposition_ = disposition; | |
486 transition_ = transition; | |
487 | |
488 if (command_updater_) { | |
489 if (!alternate_nav_url.is_valid()) { | |
490 command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL); | |
491 } else { | |
492 AlternateNavURLFetcher* fetcher = | |
493 new AlternateNavURLFetcher(alternate_nav_url); | |
494 // The AlternateNavURLFetcher will listen for the pending navigation | |
495 // notification that will be issued as a result of the "open URL." It | |
496 // will automatically install itself into that navigation controller. | |
497 command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL); | |
498 if (fetcher->state() == AlternateNavURLFetcher::NOT_STARTED) { | |
499 // I'm not sure this should be reachable, but I'm not also sure enough | |
500 // that it shouldn't to stick in a NOTREACHED(). In any case, this is | |
501 // harmless. | |
502 delete fetcher; | |
503 } else { | |
504 // The navigation controller will delete the fetcher. | |
505 } | |
506 } | |
507 } | |
508 } | |
509 | |
510 if (browser_->instant() && !location_entry_->model()->popup_model()->IsOpen()) | |
511 browser_->instant()->DestroyPreviewContents(); | |
512 | |
513 update_instant_ = true; | |
514 } | |
515 | |
516 void LocationBarViewGtk::OnChanged() { | |
517 UpdateSiteTypeArea(); | |
518 | |
519 const std::wstring keyword(location_entry_->model()->keyword()); | |
520 const bool is_keyword_hint = location_entry_->model()->is_keyword_hint(); | |
521 show_selected_keyword_ = !keyword.empty() && !is_keyword_hint; | |
522 show_keyword_hint_ = !keyword.empty() && is_keyword_hint; | |
523 | |
524 if (show_selected_keyword_) | |
525 SetKeywordLabel(keyword); | |
526 | |
527 if (show_keyword_hint_) | |
528 SetKeywordHintLabel(keyword); | |
529 | |
530 AdjustChildrenVisibility(); | |
531 | |
532 InstantController* instant = browser_->instant(); | |
533 string16 suggested_text; | |
534 if (update_instant_ && instant && GetTabContents()) { | |
535 if (location_entry_->model()->user_input_in_progress() && | |
536 location_entry_->model()->popup_model()->IsOpen()) { | |
537 instant->Update( | |
538 browser_->GetSelectedTabContentsWrapper(), | |
539 location_entry_->model()->CurrentMatch(), | |
540 WideToUTF16(location_entry_->GetText()), | |
541 location_entry_->model()->UseVerbatimInstant(), | |
542 &suggested_text); | |
543 if (!instant->MightSupportInstant()) { | |
544 location_entry_->model()->FinalizeInstantQuery(std::wstring(), | |
545 std::wstring()); | |
546 } | |
547 } else { | |
548 instant->DestroyPreviewContents(); | |
549 location_entry_->model()->FinalizeInstantQuery(std::wstring(), | |
550 std::wstring()); | |
551 } | |
552 } | |
553 | |
554 SetSuggestedText(suggested_text); | |
555 } | |
556 | |
557 void LocationBarViewGtk::OnSelectionBoundsChanged() { | |
558 NOTIMPLEMENTED(); | |
559 } | |
560 | |
561 void LocationBarViewGtk::CreateStarButton() { | |
562 star_image_ = gtk_image_new(); | |
563 | |
564 GtkWidget* alignment = gtk_alignment_new(0, 0, 1, 1); | |
565 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, | |
566 0, kStarRightPadding); | |
567 gtk_container_add(GTK_CONTAINER(alignment), star_image_); | |
568 | |
569 star_.Own(gtk_event_box_new()); | |
570 gtk_event_box_set_visible_window(GTK_EVENT_BOX(star_.get()), FALSE); | |
571 gtk_container_add(GTK_CONTAINER(star_.get()), alignment); | |
572 gtk_widget_show_all(star_.get()); | |
573 ViewIDUtil::SetID(star_.get(), VIEW_ID_STAR_BUTTON); | |
574 | |
575 gtk_widget_set_tooltip_text(star_.get(), | |
576 l10n_util::GetStringUTF8(IDS_TOOLTIP_STAR).c_str()); | |
577 g_signal_connect(star_.get(), "button-press-event", | |
578 G_CALLBACK(OnStarButtonPressThunk), this); | |
579 } | |
580 | |
581 void LocationBarViewGtk::OnInputInProgress(bool in_progress) { | |
582 // This is identical to the Windows code, except that we don't proxy the call | |
583 // back through the Toolbar, and just access the model here. | |
584 // The edit should make sure we're only notified when something changes. | |
585 DCHECK(toolbar_model_->input_in_progress() != in_progress); | |
586 | |
587 toolbar_model_->set_input_in_progress(in_progress); | |
588 Update(NULL); | |
589 } | |
590 | |
591 void LocationBarViewGtk::OnKillFocus() { | |
592 } | |
593 | |
594 void LocationBarViewGtk::OnSetFocus() { | |
595 AccessibilityTextBoxInfo info( | |
596 profile_, | |
597 l10n_util::GetStringUTF8(IDS_ACCNAME_LOCATION).c_str(), | |
598 false); | |
599 NotificationService::current()->Notify( | |
600 NotificationType::ACCESSIBILITY_CONTROL_FOCUSED, | |
601 Source<Profile>(profile_), | |
602 Details<AccessibilityTextBoxInfo>(&info)); | |
603 | |
604 // Update the keyword and search hint states. | |
605 OnChanged(); | |
606 } | |
607 | |
608 SkBitmap LocationBarViewGtk::GetFavIcon() const { | |
609 return GetTabContents()->GetFavIcon(); | |
610 } | |
611 | |
612 std::wstring LocationBarViewGtk::GetTitle() const { | |
613 return UTF16ToWideHack(GetTabContents()->GetTitle()); | |
614 } | |
615 | |
616 void LocationBarViewGtk::ShowFirstRunBubble(FirstRun::BubbleType bubble_type) { | |
617 // We need the browser window to be shown before we can show the bubble, but | |
618 // we get called before that's happened. | |
619 Task* task = first_run_bubble_.NewRunnableMethod( | |
620 &LocationBarViewGtk::ShowFirstRunBubbleInternal, bubble_type); | |
621 MessageLoop::current()->PostTask(FROM_HERE, task); | |
622 } | |
623 | |
624 void LocationBarViewGtk::SetSuggestedText(const string16& text) { | |
625 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
626 switches::kInstantAutocompleteImmediately)) { | |
627 // This method is internally invoked to reset suggest text, so we only do | |
628 // anything if the text isn't empty. | |
629 // TODO: if we keep autocomplete, make it so this isn't invoked with empty | |
630 // text. | |
631 if (!text.empty()) { | |
632 location_entry_->model()->FinalizeInstantQuery( | |
633 location_entry_->GetText(), | |
634 UTF16ToWide(text)); | |
635 } | |
636 } else { | |
637 location_entry_->SetInstantSuggestion(text); | |
638 } | |
639 } | |
640 | |
641 std::wstring LocationBarViewGtk::GetInputString() const { | |
642 return location_input_; | |
643 } | |
644 | |
645 WindowOpenDisposition LocationBarViewGtk::GetWindowOpenDisposition() const { | |
646 return disposition_; | |
647 } | |
648 | |
649 PageTransition::Type LocationBarViewGtk::GetPageTransition() const { | |
650 return transition_; | |
651 } | |
652 | |
653 void LocationBarViewGtk::AcceptInput() { | |
654 location_entry_->model()->AcceptInput(CURRENT_TAB, false); | |
655 } | |
656 | |
657 void LocationBarViewGtk::FocusLocation(bool select_all) { | |
658 location_entry_->SetFocus(); | |
659 if (select_all) | |
660 location_entry_->SelectAll(true); | |
661 } | |
662 | |
663 void LocationBarViewGtk::FocusSearch() { | |
664 location_entry_->SetFocus(); | |
665 location_entry_->SetForcedQuery(); | |
666 } | |
667 | |
668 void LocationBarViewGtk::UpdateContentSettingsIcons() { | |
669 TabContents* tab_contents = GetTabContents(); | |
670 bool any_visible = false; | |
671 for (ScopedVector<ContentSettingImageViewGtk>::iterator i( | |
672 content_setting_views_.begin()); | |
673 i != content_setting_views_.end(); ++i) { | |
674 (*i)->UpdateFromTabContents( | |
675 toolbar_model_->input_in_progress() ? NULL : tab_contents); | |
676 any_visible = (*i)->IsVisible() || any_visible; | |
677 } | |
678 | |
679 // If there are no visible content things, hide the top level box so it | |
680 // doesn't mess with padding. | |
681 if (any_visible) | |
682 gtk_widget_show(content_setting_hbox_.get()); | |
683 else | |
684 gtk_widget_hide(content_setting_hbox_.get()); | |
685 } | |
686 | |
687 void LocationBarViewGtk::UpdatePageActions() { | |
688 std::vector<ExtensionAction*> page_actions; | |
689 ExtensionService* service = profile_->GetExtensionService(); | |
690 if (!service) | |
691 return; | |
692 | |
693 // Find all the page actions. | |
694 for (size_t i = 0; i < service->extensions()->size(); ++i) { | |
695 if (service->extensions()->at(i)->page_action()) | |
696 page_actions.push_back(service->extensions()->at(i)->page_action()); | |
697 } | |
698 | |
699 // Initialize on the first call, or re-inialize if more extensions have been | |
700 // loaded or added after startup. | |
701 if (page_actions.size() != page_action_views_.size()) { | |
702 page_action_views_.reset(); // Delete the old views (if any). | |
703 | |
704 for (size_t i = 0; i < page_actions.size(); ++i) { | |
705 page_action_views_.push_back( | |
706 new PageActionViewGtk(this, profile_, page_actions[i])); | |
707 gtk_box_pack_end(GTK_BOX(page_action_hbox_.get()), | |
708 page_action_views_[i]->widget(), FALSE, FALSE, 0); | |
709 } | |
710 NotificationService::current()->Notify( | |
711 NotificationType::EXTENSION_PAGE_ACTION_COUNT_CHANGED, | |
712 Source<LocationBar>(this), | |
713 NotificationService::NoDetails()); | |
714 } | |
715 | |
716 TabContents* contents = GetTabContents(); | |
717 if (!page_action_views_.empty() && contents) { | |
718 GURL url = GURL(WideToUTF8(toolbar_model_->GetText())); | |
719 | |
720 for (size_t i = 0; i < page_action_views_.size(); i++) { | |
721 page_action_views_[i]->UpdateVisibility( | |
722 toolbar_model_->input_in_progress() ? NULL : contents, url); | |
723 } | |
724 } | |
725 | |
726 // If there are no visible page actions, hide the hbox too, so that it does | |
727 // not affect the padding in the location bar. | |
728 if (PageActionVisibleCount() && !ShouldOnlyShowLocation()) | |
729 gtk_widget_show(page_action_hbox_.get()); | |
730 else | |
731 gtk_widget_hide(page_action_hbox_.get()); | |
732 } | |
733 | |
734 void LocationBarViewGtk::InvalidatePageActions() { | |
735 size_t count_before = page_action_views_.size(); | |
736 page_action_views_.reset(); | |
737 if (page_action_views_.size() != count_before) { | |
738 NotificationService::current()->Notify( | |
739 NotificationType::EXTENSION_PAGE_ACTION_COUNT_CHANGED, | |
740 Source<LocationBar>(this), | |
741 NotificationService::NoDetails()); | |
742 } | |
743 } | |
744 | |
745 void LocationBarViewGtk::SaveStateToContents(TabContents* contents) { | |
746 location_entry_->SaveStateToTab(contents); | |
747 } | |
748 | |
749 void LocationBarViewGtk::Revert() { | |
750 location_entry_->RevertAll(); | |
751 } | |
752 | |
753 const AutocompleteEditView* LocationBarViewGtk::location_entry() const { | |
754 return location_entry_.get(); | |
755 } | |
756 | |
757 AutocompleteEditView* LocationBarViewGtk::location_entry() { | |
758 return location_entry_.get(); | |
759 } | |
760 | |
761 LocationBarTesting* LocationBarViewGtk::GetLocationBarForTesting() { | |
762 return this; | |
763 } | |
764 | |
765 int LocationBarViewGtk::PageActionCount() { | |
766 return page_action_views_.size(); | |
767 } | |
768 | |
769 int LocationBarViewGtk::PageActionVisibleCount() { | |
770 int count = 0; | |
771 gtk_container_foreach(GTK_CONTAINER(page_action_hbox_.get()), | |
772 CountVisibleWidgets, &count); | |
773 return count; | |
774 } | |
775 | |
776 ExtensionAction* LocationBarViewGtk::GetPageAction(size_t index) { | |
777 if (index >= page_action_views_.size()) { | |
778 NOTREACHED(); | |
779 return NULL; | |
780 } | |
781 | |
782 return page_action_views_[index]->page_action(); | |
783 } | |
784 | |
785 ExtensionAction* LocationBarViewGtk::GetVisiblePageAction(size_t index) { | |
786 size_t visible_index = 0; | |
787 for (size_t i = 0; i < page_action_views_.size(); ++i) { | |
788 if (page_action_views_[i]->IsVisible()) { | |
789 if (index == visible_index++) | |
790 return page_action_views_[i]->page_action(); | |
791 } | |
792 } | |
793 | |
794 NOTREACHED(); | |
795 return NULL; | |
796 } | |
797 | |
798 void LocationBarViewGtk::TestPageActionPressed(size_t index) { | |
799 if (index >= page_action_views_.size()) { | |
800 NOTREACHED(); | |
801 return; | |
802 } | |
803 | |
804 page_action_views_[index]->TestActivatePageAction(); | |
805 } | |
806 | |
807 void LocationBarViewGtk::Observe(NotificationType type, | |
808 const NotificationSource& source, | |
809 const NotificationDetails& details) { | |
810 DCHECK_EQ(type.value, NotificationType::BROWSER_THEME_CHANGED); | |
811 | |
812 if (theme_provider_->UseGtkTheme()) { | |
813 gtk_widget_modify_bg(tab_to_search_box_, GTK_STATE_NORMAL, NULL); | |
814 | |
815 GdkColor border_color = theme_provider_->GetGdkColor( | |
816 BrowserThemeProvider::COLOR_FRAME); | |
817 gtk_util::SetRoundedWindowBorderColor(tab_to_search_box_, border_color); | |
818 | |
819 gtk_util::SetLabelColor(tab_to_search_full_label_, NULL); | |
820 gtk_util::SetLabelColor(tab_to_search_partial_label_, NULL); | |
821 gtk_util::SetLabelColor(tab_to_search_hint_leading_label_, NULL); | |
822 gtk_util::SetLabelColor(tab_to_search_hint_trailing_label_, NULL); | |
823 | |
824 gtk_util::UndoForceFontSize(security_info_label_); | |
825 gtk_util::UndoForceFontSize(tab_to_search_full_label_); | |
826 gtk_util::UndoForceFontSize(tab_to_search_partial_label_); | |
827 gtk_util::UndoForceFontSize(tab_to_search_hint_leading_label_); | |
828 gtk_util::UndoForceFontSize(tab_to_search_hint_trailing_label_); | |
829 | |
830 gtk_alignment_set_padding(GTK_ALIGNMENT(location_entry_alignment_), | |
831 0, 0, 0, 0); | |
832 } else { | |
833 gtk_widget_modify_bg(tab_to_search_box_, GTK_STATE_NORMAL, | |
834 &kKeywordBackgroundColor); | |
835 gtk_util::SetRoundedWindowBorderColor(tab_to_search_box_, | |
836 kKeywordBorderColor); | |
837 | |
838 gtk_util::SetLabelColor(tab_to_search_full_label_, >k_util::kGdkBlack); | |
839 gtk_util::SetLabelColor(tab_to_search_partial_label_, >k_util::kGdkBlack); | |
840 gtk_util::SetLabelColor(tab_to_search_hint_leading_label_, | |
841 &kHintTextColor); | |
842 gtk_util::SetLabelColor(tab_to_search_hint_trailing_label_, | |
843 &kHintTextColor); | |
844 | |
845 // Until we switch to vector graphics, force the font size of labels. | |
846 // 12.1px = 9pt @ 96dpi | |
847 gtk_util::ForceFontSizePixels(security_info_label_, 12.1); | |
848 gtk_util::ForceFontSizePixels(tab_to_search_full_label_, | |
849 browser_defaults::kAutocompleteEditFontPixelSize); | |
850 gtk_util::ForceFontSizePixels(tab_to_search_partial_label_, | |
851 browser_defaults::kAutocompleteEditFontPixelSize); | |
852 gtk_util::ForceFontSizePixels(tab_to_search_hint_leading_label_, | |
853 browser_defaults::kAutocompleteEditFontPixelSize); | |
854 gtk_util::ForceFontSizePixels(tab_to_search_hint_trailing_label_, | |
855 browser_defaults::kAutocompleteEditFontPixelSize); | |
856 | |
857 if (popup_window_mode_) { | |
858 gtk_alignment_set_padding(GTK_ALIGNMENT(location_entry_alignment_), | |
859 kTopMargin + kBorderThickness, | |
860 kBottomMargin + kBorderThickness, | |
861 kBorderThickness, | |
862 kBorderThickness); | |
863 } else { | |
864 gtk_alignment_set_padding(GTK_ALIGNMENT(location_entry_alignment_), | |
865 kTopMargin + kBorderThickness, | |
866 kBottomMargin + kBorderThickness, | |
867 0, 0); | |
868 } | |
869 } | |
870 | |
871 UpdateStarIcon(); | |
872 UpdateSiteTypeArea(); | |
873 UpdateContentSettingsIcons(); | |
874 } | |
875 | |
876 gboolean LocationBarViewGtk::HandleExpose(GtkWidget* widget, | |
877 GdkEventExpose* event) { | |
878 // If we're not using GTK theming, draw our own border over the edge pixels | |
879 // of the background. | |
880 if (!profile_ || | |
881 !GtkThemeProvider::GetFrom(profile_)->UseGtkTheme()) { | |
882 int left, center, right; | |
883 if (popup_window_mode_) { | |
884 left = right = IDR_LOCATIONBG_POPUPMODE_EDGE; | |
885 center = IDR_LOCATIONBG_POPUPMODE_CENTER; | |
886 } else { | |
887 left = IDR_LOCATIONBG_L; | |
888 center = IDR_LOCATIONBG_C; | |
889 right = IDR_LOCATIONBG_R; | |
890 } | |
891 | |
892 NineBox background(left, center, right, | |
893 0, 0, 0, 0, 0, 0); | |
894 background.RenderToWidget(widget); | |
895 } | |
896 | |
897 return FALSE; // Continue propagating the expose. | |
898 } | |
899 | |
900 void LocationBarViewGtk::UpdateSiteTypeArea() { | |
901 // The icon is always visible except when the |tab_to_search_box_| is visible. | |
902 if (!location_entry_->model()->keyword().empty() && | |
903 !location_entry_->model()->is_keyword_hint()) { | |
904 gtk_widget_hide(site_type_area()); | |
905 return; | |
906 } | |
907 | |
908 int resource_id = location_entry_->GetIcon(); | |
909 gtk_image_set_from_pixbuf(GTK_IMAGE(location_icon_image_), | |
910 theme_provider_->GetPixbufNamed(resource_id)); | |
911 | |
912 if (toolbar_model_->GetSecurityLevel() == ToolbarModel::EV_SECURE) { | |
913 if (!gtk_util::IsActingAsRoundedWindow(site_type_event_box_)) { | |
914 // Fun fact: If wee try to make |site_type_event_box_| act as a | |
915 // rounded window while it doesn't have a visible window, GTK interprets | |
916 // this as a sign that it should paint the skyline texture into the | |
917 // omnibox. | |
918 gtk_event_box_set_visible_window(GTK_EVENT_BOX(site_type_event_box_), | |
919 TRUE); | |
920 | |
921 gtk_util::ActAsRoundedWindow(site_type_event_box_, | |
922 kEvSecureBorderColor, | |
923 kCornerSize, | |
924 gtk_util::ROUNDED_ALL, | |
925 gtk_util::BORDER_ALL); | |
926 } | |
927 | |
928 std::wstring info_text = toolbar_model_->GetEVCertName(); | |
929 gtk_label_set_text(GTK_LABEL(security_info_label_), | |
930 WideToUTF8(info_text).c_str()); | |
931 | |
932 UpdateEVCertificateLabelSize(); | |
933 | |
934 gtk_widget_show(GTK_WIDGET(security_info_label_)); | |
935 } else { | |
936 if (gtk_util::IsActingAsRoundedWindow(site_type_event_box_)) { | |
937 gtk_util::StopActingAsRoundedWindow(site_type_event_box_); | |
938 | |
939 gtk_event_box_set_visible_window(GTK_EVENT_BOX(site_type_event_box_), | |
940 FALSE); | |
941 } | |
942 | |
943 gtk_widget_hide(GTK_WIDGET(security_info_label_)); | |
944 } | |
945 | |
946 gtk_widget_show(site_type_area()); | |
947 | |
948 SetSiteTypeDragSource(); | |
949 } | |
950 | |
951 void LocationBarViewGtk::UpdateEVCertificateLabelSize() { | |
952 // Figure out the width of the average character. | |
953 PangoLayout* layout = gtk_label_get_layout(GTK_LABEL(security_info_label_)); | |
954 PangoContext* context = pango_layout_get_context(layout); | |
955 PangoFontMetrics* metrics = pango_context_get_metrics( | |
956 context, | |
957 gtk_widget_get_style(security_info_label_)->font_desc, | |
958 pango_context_get_language(context)); | |
959 int char_width = | |
960 pango_font_metrics_get_approximate_char_width(metrics) / PANGO_SCALE; | |
961 | |
962 // The EV label should never take up more than half the hbox. We try to | |
963 // correct our inaccurate measurement units ("the average character width") | |
964 // by dividing more than an even 2. | |
965 int text_area = security_info_label_->allocation.width + | |
966 entry_box_->allocation.width; | |
967 int max_chars = static_cast<int>(static_cast<float>(text_area) / | |
968 static_cast<float>(char_width) / 2.75); | |
969 // Don't let the label be smaller than 10 characters so that the country | |
970 // code is always visible. | |
971 gtk_label_set_max_width_chars(GTK_LABEL(security_info_label_), | |
972 std::max(10, max_chars)); | |
973 | |
974 pango_font_metrics_unref(metrics); | |
975 } | |
976 | |
977 void LocationBarViewGtk::SetKeywordLabel(const std::wstring& keyword) { | |
978 if (keyword.empty()) | |
979 return; | |
980 | |
981 DCHECK(profile_); | |
982 if (!profile_->GetTemplateURLModel()) | |
983 return; | |
984 | |
985 bool is_extension_keyword; | |
986 const std::wstring short_name = profile_->GetTemplateURLModel()-> | |
987 GetKeywordShortName(keyword, &is_extension_keyword); | |
988 int message_id = is_extension_keyword ? | |
989 IDS_OMNIBOX_EXTENSION_KEYWORD_TEXT : IDS_OMNIBOX_KEYWORD_TEXT; | |
990 string16 full_name = l10n_util::GetStringFUTF16(message_id, | |
991 WideToUTF16Hack(short_name)); | |
992 string16 partial_name = l10n_util::GetStringFUTF16( | |
993 message_id, | |
994 WideToUTF16Hack(location_bar_util::CalculateMinString(short_name))); | |
995 gtk_label_set_text(GTK_LABEL(tab_to_search_full_label_), | |
996 UTF16ToUTF8(full_name).c_str()); | |
997 gtk_label_set_text(GTK_LABEL(tab_to_search_partial_label_), | |
998 UTF16ToUTF8(partial_name).c_str()); | |
999 | |
1000 if (last_keyword_ != keyword) { | |
1001 last_keyword_ = keyword; | |
1002 | |
1003 if (is_extension_keyword) { | |
1004 const TemplateURL* template_url = | |
1005 profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword); | |
1006 const SkBitmap& bitmap = profile_->GetExtensionService()-> | |
1007 GetOmniboxIcon(template_url->GetExtensionId()); | |
1008 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&bitmap); | |
1009 gtk_image_set_from_pixbuf(GTK_IMAGE(tab_to_search_magnifier_), pixbuf); | |
1010 g_object_unref(pixbuf); | |
1011 } else { | |
1012 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
1013 gtk_image_set_from_pixbuf(GTK_IMAGE(tab_to_search_magnifier_), | |
1014 rb.GetPixbufNamed(IDR_OMNIBOX_SEARCH)); | |
1015 } | |
1016 } | |
1017 } | |
1018 | |
1019 void LocationBarViewGtk::SetKeywordHintLabel(const std::wstring& keyword) { | |
1020 if (keyword.empty()) | |
1021 return; | |
1022 | |
1023 DCHECK(profile_); | |
1024 if (!profile_->GetTemplateURLModel()) | |
1025 return; | |
1026 | |
1027 bool is_extension_keyword; | |
1028 const std::wstring short_name = profile_->GetTemplateURLModel()-> | |
1029 GetKeywordShortName(keyword, &is_extension_keyword); | |
1030 int message_id = is_extension_keyword ? | |
1031 IDS_OMNIBOX_EXTENSION_KEYWORD_HINT : IDS_OMNIBOX_KEYWORD_HINT; | |
1032 std::vector<size_t> content_param_offsets; | |
1033 const string16 keyword_hint = l10n_util::GetStringFUTF16( | |
1034 message_id, | |
1035 string16(), | |
1036 WideToUTF16Hack(short_name), | |
1037 &content_param_offsets); | |
1038 if (content_param_offsets.size() != 2) { | |
1039 // See comments on an identical NOTREACHED() in search_provider.cc. | |
1040 NOTREACHED(); | |
1041 return; | |
1042 } | |
1043 | |
1044 std::string leading(UTF16ToUTF8( | |
1045 keyword_hint.substr(0, content_param_offsets.front()))); | |
1046 std::string trailing(UTF16ToUTF8( | |
1047 keyword_hint.substr(content_param_offsets.front()))); | |
1048 gtk_label_set_text(GTK_LABEL(tab_to_search_hint_leading_label_), | |
1049 leading.c_str()); | |
1050 gtk_label_set_text(GTK_LABEL(tab_to_search_hint_trailing_label_), | |
1051 trailing.c_str()); | |
1052 } | |
1053 | |
1054 void LocationBarViewGtk::ShowFirstRunBubbleInternal( | |
1055 FirstRun::BubbleType bubble_type) { | |
1056 if (!location_entry_.get() || !widget()->window) | |
1057 return; | |
1058 | |
1059 GtkWidget* anchor = location_entry_->GetNativeView(); | |
1060 | |
1061 // The bubble needs to be just below the Omnibox and slightly to the right | |
1062 // of star button, so shift x and y co-ordinates. | |
1063 int y_offset = anchor->allocation.height + kFirstRunBubbleTopMargin; | |
1064 int x_offset = 0; | |
1065 if (!base::i18n::IsRTL()) | |
1066 x_offset = kFirstRunBubbleLeftMargin; | |
1067 else | |
1068 x_offset = anchor->allocation.width - kFirstRunBubbleLeftMargin; | |
1069 gfx::Rect rect(x_offset, y_offset, 0, 0); | |
1070 | |
1071 FirstRunBubble::Show(profile_, anchor, rect, bubble_type); | |
1072 } | |
1073 | |
1074 gboolean LocationBarViewGtk::OnIconReleased(GtkWidget* sender, | |
1075 GdkEventButton* event) { | |
1076 TabContents* tab = GetTabContents(); | |
1077 | |
1078 if (event->button == 1) { | |
1079 // Do not show page info if the user has been editing the location | |
1080 // bar, or the location bar is at the NTP. | |
1081 if (location_entry()->IsEditingOrEmpty()) | |
1082 return FALSE; | |
1083 | |
1084 // (0,0) event coordinates indicates that the release came at the end of | |
1085 // a drag. | |
1086 if (event->x == 0 && event->y == 0) | |
1087 return FALSE; | |
1088 | |
1089 NavigationEntry* nav_entry = tab->controller().GetActiveEntry(); | |
1090 if (!nav_entry) { | |
1091 NOTREACHED(); | |
1092 return FALSE; | |
1093 } | |
1094 tab->ShowPageInfo(nav_entry->url(), nav_entry->ssl(), true); | |
1095 return TRUE; | |
1096 } else if (event->button == 2) { | |
1097 // When the user middle clicks on the location icon, try to open the | |
1098 // contents of the PRIMARY selection in the current tab. | |
1099 // If the click was outside our bounds, do nothing. | |
1100 if (!gtk_util::WidgetBounds(sender).Contains( | |
1101 gfx::Point(event->x, event->y))) { | |
1102 return FALSE; | |
1103 } | |
1104 | |
1105 GURL url; | |
1106 if (!gtk_util::URLFromPrimarySelection(profile_, &url)) | |
1107 return FALSE; | |
1108 | |
1109 tab->OpenURL(url, GURL(), CURRENT_TAB, PageTransition::TYPED); | |
1110 return TRUE; | |
1111 } | |
1112 | |
1113 return FALSE; | |
1114 } | |
1115 | |
1116 void LocationBarViewGtk::OnIconDragData(GtkWidget* sender, | |
1117 GdkDragContext* context, | |
1118 GtkSelectionData* data, | |
1119 guint info, guint time) { | |
1120 TabContents* tab = GetTabContents(); | |
1121 if (!tab) | |
1122 return; | |
1123 gtk_dnd_util::WriteURLWithName(data, tab->GetURL(), tab->GetTitle(), info); | |
1124 } | |
1125 | |
1126 void LocationBarViewGtk::OnIconDragBegin(GtkWidget* sender, | |
1127 GdkDragContext* context) { | |
1128 SkBitmap favicon = GetFavIcon(); | |
1129 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&favicon); | |
1130 if (!pixbuf) | |
1131 return; | |
1132 drag_icon_ = bookmark_utils::GetDragRepresentation(pixbuf, | |
1133 WideToUTF16(GetTitle()), theme_provider_); | |
1134 g_object_unref(pixbuf); | |
1135 gtk_drag_set_icon_widget(context, drag_icon_, 0, 0); | |
1136 } | |
1137 | |
1138 void LocationBarViewGtk::OnIconDragEnd(GtkWidget* sender, | |
1139 GdkDragContext* context) { | |
1140 DCHECK(drag_icon_); | |
1141 gtk_widget_destroy(drag_icon_); | |
1142 drag_icon_ = NULL; | |
1143 } | |
1144 | |
1145 void LocationBarViewGtk::OnHboxSizeAllocate(GtkWidget* sender, | |
1146 GtkAllocation* allocation) { | |
1147 if (hbox_width_ != allocation->width) { | |
1148 hbox_width_ = allocation->width; | |
1149 UpdateEVCertificateLabelSize(); | |
1150 } | |
1151 } | |
1152 | |
1153 void LocationBarViewGtk::OnEntryBoxSizeAllocate(GtkWidget* sender, | |
1154 GtkAllocation* allocation) { | |
1155 if (entry_box_width_ != allocation->width) { | |
1156 entry_box_width_ = allocation->width; | |
1157 AdjustChildrenVisibility(); | |
1158 } | |
1159 } | |
1160 | |
1161 gboolean LocationBarViewGtk::OnStarButtonPress(GtkWidget* widget, | |
1162 GdkEventButton* event) { | |
1163 browser_->ExecuteCommand(IDC_BOOKMARK_PAGE); | |
1164 return FALSE; | |
1165 } | |
1166 | |
1167 void LocationBarViewGtk::ShowStarBubble(const GURL& url, | |
1168 bool newly_bookmarked) { | |
1169 if (!star_.get()) | |
1170 return; | |
1171 | |
1172 BookmarkBubbleGtk::Show(star_.get(), profile_, url, newly_bookmarked); | |
1173 } | |
1174 | |
1175 void LocationBarViewGtk::SetStarred(bool starred) { | |
1176 if (starred == starred_) | |
1177 return; | |
1178 | |
1179 starred_ = starred; | |
1180 UpdateStarIcon(); | |
1181 } | |
1182 | |
1183 void LocationBarViewGtk::UpdateStarIcon() { | |
1184 if (!star_.get()) | |
1185 return; | |
1186 | |
1187 gtk_image_set_from_pixbuf(GTK_IMAGE(star_image_), | |
1188 theme_provider_->GetPixbufNamed( | |
1189 starred_ ? IDR_STAR_LIT : IDR_STAR)); | |
1190 } | |
1191 | |
1192 bool LocationBarViewGtk::ShouldOnlyShowLocation() { | |
1193 return browser_->type() != Browser::TYPE_NORMAL; | |
1194 } | |
1195 | |
1196 void LocationBarViewGtk::AdjustChildrenVisibility() { | |
1197 int text_width = location_entry_->TextWidth(); | |
1198 int available_width = entry_box_width_ - text_width - kInnerPadding; | |
1199 | |
1200 // Only one of |tab_to_search_box_| and |tab_to_search_hint_| can be visible | |
1201 // at the same time. | |
1202 if (!show_selected_keyword_ && GTK_WIDGET_VISIBLE(tab_to_search_box_)) { | |
1203 gtk_widget_hide(tab_to_search_box_); | |
1204 } else if (!show_keyword_hint_ && GTK_WIDGET_VISIBLE(tab_to_search_hint_)) { | |
1205 gtk_widget_hide(tab_to_search_hint_); | |
1206 location_entry_->set_enable_tab_to_search(false); | |
1207 } | |
1208 | |
1209 if (show_selected_keyword_) { | |
1210 GtkRequisition box, full_label, partial_label; | |
1211 gtk_widget_size_request(tab_to_search_box_, &box); | |
1212 gtk_widget_size_request(tab_to_search_full_label_, &full_label); | |
1213 gtk_widget_size_request(tab_to_search_partial_label_, &partial_label); | |
1214 int full_partial_width_diff = full_label.width - partial_label.width; | |
1215 int full_box_width; | |
1216 int partial_box_width; | |
1217 if (GTK_WIDGET_VISIBLE(tab_to_search_full_label_)) { | |
1218 full_box_width = box.width; | |
1219 partial_box_width = full_box_width - full_partial_width_diff; | |
1220 } else { | |
1221 partial_box_width = box.width; | |
1222 full_box_width = partial_box_width + full_partial_width_diff; | |
1223 } | |
1224 | |
1225 if (partial_box_width >= entry_box_width_ - kInnerPadding) { | |
1226 gtk_widget_hide(tab_to_search_box_); | |
1227 } else if (full_box_width >= available_width) { | |
1228 gtk_widget_hide(tab_to_search_full_label_); | |
1229 gtk_widget_show(tab_to_search_partial_label_); | |
1230 gtk_widget_show(tab_to_search_box_); | |
1231 } else if (full_box_width < available_width) { | |
1232 gtk_widget_hide(tab_to_search_partial_label_); | |
1233 gtk_widget_show(tab_to_search_full_label_); | |
1234 gtk_widget_show(tab_to_search_box_); | |
1235 } | |
1236 } else if (show_keyword_hint_) { | |
1237 GtkRequisition leading, icon, trailing; | |
1238 gtk_widget_size_request(tab_to_search_hint_leading_label_, &leading); | |
1239 gtk_widget_size_request(tab_to_search_hint_icon_, &icon); | |
1240 gtk_widget_size_request(tab_to_search_hint_trailing_label_, &trailing); | |
1241 int full_width = leading.width + icon.width + trailing.width; | |
1242 | |
1243 if (icon.width >= entry_box_width_ - kInnerPadding) { | |
1244 gtk_widget_hide(tab_to_search_hint_); | |
1245 location_entry_->set_enable_tab_to_search(false); | |
1246 } else if (full_width >= available_width) { | |
1247 gtk_widget_hide(tab_to_search_hint_leading_label_); | |
1248 gtk_widget_hide(tab_to_search_hint_trailing_label_); | |
1249 gtk_widget_show(tab_to_search_hint_); | |
1250 location_entry_->set_enable_tab_to_search(true); | |
1251 } else if (full_width < available_width) { | |
1252 gtk_widget_show(tab_to_search_hint_leading_label_); | |
1253 gtk_widget_show(tab_to_search_hint_trailing_label_); | |
1254 gtk_widget_show(tab_to_search_hint_); | |
1255 location_entry_->set_enable_tab_to_search(true); | |
1256 } | |
1257 } | |
1258 } | |
1259 | |
1260 //////////////////////////////////////////////////////////////////////////////// | |
1261 // LocationBarViewGtk::ContentSettingImageViewGtk | |
1262 LocationBarViewGtk::ContentSettingImageViewGtk::ContentSettingImageViewGtk( | |
1263 ContentSettingsType content_type, | |
1264 const LocationBarViewGtk* parent, | |
1265 Profile* profile) | |
1266 : content_setting_image_model_( | |
1267 ContentSettingImageModel::CreateContentSettingImageModel( | |
1268 content_type)), | |
1269 parent_(parent), | |
1270 profile_(profile), | |
1271 info_bubble_(NULL) { | |
1272 event_box_.Own(gtk_event_box_new()); | |
1273 | |
1274 // Make the event box not visible so it does not paint a background. | |
1275 gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box_.get()), FALSE); | |
1276 g_signal_connect(event_box_.get(), "button-press-event", | |
1277 G_CALLBACK(&OnButtonPressedThunk), this); | |
1278 | |
1279 image_.Own(gtk_image_new()); | |
1280 gtk_container_add(GTK_CONTAINER(event_box_.get()), image_.get()); | |
1281 gtk_widget_hide(widget()); | |
1282 } | |
1283 | |
1284 LocationBarViewGtk::ContentSettingImageViewGtk::~ContentSettingImageViewGtk() { | |
1285 image_.Destroy(); | |
1286 event_box_.Destroy(); | |
1287 | |
1288 if (info_bubble_) | |
1289 info_bubble_->Close(); | |
1290 } | |
1291 | |
1292 void LocationBarViewGtk::ContentSettingImageViewGtk::UpdateFromTabContents( | |
1293 TabContents* tab_contents) { | |
1294 content_setting_image_model_->UpdateFromTabContents(tab_contents); | |
1295 if (content_setting_image_model_->is_visible()) { | |
1296 gtk_image_set_from_pixbuf(GTK_IMAGE(image_.get()), | |
1297 GtkThemeProvider::GetFrom(profile_)->GetPixbufNamed( | |
1298 content_setting_image_model_->get_icon())); | |
1299 | |
1300 gtk_widget_set_tooltip_text(widget(), | |
1301 content_setting_image_model_->get_tooltip().c_str()); | |
1302 gtk_widget_show(widget()); | |
1303 } else { | |
1304 gtk_widget_hide(widget()); | |
1305 } | |
1306 } | |
1307 | |
1308 gboolean LocationBarViewGtk::ContentSettingImageViewGtk::OnButtonPressed( | |
1309 GtkWidget* sender, GdkEvent* event) { | |
1310 TabContents* tab_contents = parent_->GetTabContents(); | |
1311 if (!tab_contents) | |
1312 return true; | |
1313 GURL url = tab_contents->GetURL(); | |
1314 std::wstring display_host; | |
1315 net::AppendFormattedHost(url, | |
1316 UTF8ToWide(profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)), | |
1317 &display_host, | |
1318 NULL, NULL); | |
1319 | |
1320 info_bubble_ = new ContentSettingBubbleGtk( | |
1321 sender, this, | |
1322 ContentSettingBubbleModel::CreateContentSettingBubbleModel( | |
1323 tab_contents, profile_, | |
1324 content_setting_image_model_->get_content_settings_type()), | |
1325 profile_, tab_contents); | |
1326 return TRUE; | |
1327 } | |
1328 | |
1329 void LocationBarViewGtk::ContentSettingImageViewGtk::InfoBubbleClosing( | |
1330 InfoBubbleGtk* info_bubble, | |
1331 bool closed_by_escape) { | |
1332 info_bubble_ = NULL; | |
1333 } | |
1334 | |
1335 //////////////////////////////////////////////////////////////////////////////// | |
1336 // LocationBarViewGtk::PageActionViewGtk | |
1337 | |
1338 LocationBarViewGtk::PageActionViewGtk::PageActionViewGtk( | |
1339 LocationBarViewGtk* owner, Profile* profile, | |
1340 ExtensionAction* page_action) | |
1341 : owner_(NULL), | |
1342 profile_(profile), | |
1343 page_action_(page_action), | |
1344 last_icon_pixbuf_(NULL), | |
1345 tracker_(this), | |
1346 preview_enabled_(false) { | |
1347 event_box_.Own(gtk_event_box_new()); | |
1348 gtk_widget_set_size_request(event_box_.get(), | |
1349 Extension::kPageActionIconMaxSize, | |
1350 Extension::kPageActionIconMaxSize); | |
1351 | |
1352 // Make the event box not visible so it does not paint a background. | |
1353 gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box_.get()), FALSE); | |
1354 g_signal_connect(event_box_.get(), "button-press-event", | |
1355 G_CALLBACK(&OnButtonPressedThunk), this); | |
1356 g_signal_connect_after(event_box_.get(), "expose-event", | |
1357 G_CALLBACK(OnExposeEventThunk), this); | |
1358 | |
1359 image_.Own(gtk_image_new()); | |
1360 gtk_container_add(GTK_CONTAINER(event_box_.get()), image_.get()); | |
1361 | |
1362 const Extension* extension = profile->GetExtensionService()-> | |
1363 GetExtensionById(page_action->extension_id(), false); | |
1364 DCHECK(extension); | |
1365 | |
1366 // Load all the icons declared in the manifest. This is the contents of the | |
1367 // icons array, plus the default_icon property, if any. | |
1368 std::vector<std::string> icon_paths(*page_action->icon_paths()); | |
1369 if (!page_action_->default_icon_path().empty()) | |
1370 icon_paths.push_back(page_action_->default_icon_path()); | |
1371 | |
1372 for (std::vector<std::string>::iterator iter = icon_paths.begin(); | |
1373 iter != icon_paths.end(); ++iter) { | |
1374 tracker_.LoadImage(extension, extension->GetResource(*iter), | |
1375 gfx::Size(Extension::kPageActionIconMaxSize, | |
1376 Extension::kPageActionIconMaxSize), | |
1377 ImageLoadingTracker::DONT_CACHE); | |
1378 } | |
1379 | |
1380 // We set the owner last of all so that we can determine whether we are in | |
1381 // the process of initializing this class or not. | |
1382 owner_ = owner; | |
1383 } | |
1384 | |
1385 LocationBarViewGtk::PageActionViewGtk::~PageActionViewGtk() { | |
1386 image_.Destroy(); | |
1387 event_box_.Destroy(); | |
1388 for (PixbufMap::iterator iter = pixbufs_.begin(); iter != pixbufs_.end(); | |
1389 ++iter) { | |
1390 g_object_unref(iter->second); | |
1391 } | |
1392 if (last_icon_pixbuf_) | |
1393 g_object_unref(last_icon_pixbuf_); | |
1394 } | |
1395 | |
1396 void LocationBarViewGtk::PageActionViewGtk::UpdateVisibility( | |
1397 TabContents* contents, GURL url) { | |
1398 // Save this off so we can pass it back to the extension when the action gets | |
1399 // executed. See PageActionImageView::OnMousePressed. | |
1400 current_tab_id_ = contents ? ExtensionTabUtil::GetTabId(contents) : -1; | |
1401 current_url_ = url; | |
1402 | |
1403 bool visible = contents && | |
1404 (preview_enabled_ || page_action_->GetIsVisible(current_tab_id_)); | |
1405 if (visible) { | |
1406 // Set the tooltip. | |
1407 gtk_widget_set_tooltip_text(event_box_.get(), | |
1408 page_action_->GetTitle(current_tab_id_).c_str()); | |
1409 | |
1410 // Set the image. | |
1411 // It can come from three places. In descending order of priority: | |
1412 // - The developer can set it dynamically by path or bitmap. It will be in | |
1413 // page_action_->GetIcon(). | |
1414 // - The developer can set it dyanmically by index. It will be in | |
1415 // page_action_->GetIconIndex(). | |
1416 // - It can be set in the manifest by path. It will be in page_action_-> | |
1417 // default_icon_path(). | |
1418 | |
1419 // First look for a dynamically set bitmap. | |
1420 SkBitmap icon = page_action_->GetIcon(current_tab_id_); | |
1421 GdkPixbuf* pixbuf = NULL; | |
1422 if (!icon.isNull()) { | |
1423 if (icon.pixelRef() != last_icon_skbitmap_.pixelRef()) { | |
1424 if (last_icon_pixbuf_) | |
1425 g_object_unref(last_icon_pixbuf_); | |
1426 last_icon_skbitmap_ = icon; | |
1427 last_icon_pixbuf_ = gfx::GdkPixbufFromSkBitmap(&icon); | |
1428 } | |
1429 DCHECK(last_icon_pixbuf_); | |
1430 pixbuf = last_icon_pixbuf_; | |
1431 } else { | |
1432 // Otherwise look for a dynamically set index, or fall back to the | |
1433 // default path. | |
1434 int icon_index = page_action_->GetIconIndex(current_tab_id_); | |
1435 std::string icon_path = (icon_index < 0) ? | |
1436 page_action_->default_icon_path() : | |
1437 page_action_->icon_paths()->at(icon_index); | |
1438 if (!icon_path.empty()) { | |
1439 PixbufMap::iterator iter = pixbufs_.find(icon_path); | |
1440 if (iter != pixbufs_.end()) | |
1441 pixbuf = iter->second; | |
1442 } | |
1443 } | |
1444 // The pixbuf might not be loaded yet. | |
1445 if (pixbuf) | |
1446 gtk_image_set_from_pixbuf(GTK_IMAGE(image_.get()), pixbuf); | |
1447 } | |
1448 | |
1449 bool old_visible = IsVisible(); | |
1450 if (visible) | |
1451 gtk_widget_show_all(event_box_.get()); | |
1452 else | |
1453 gtk_widget_hide_all(event_box_.get()); | |
1454 | |
1455 if (visible != old_visible) { | |
1456 NotificationService::current()->Notify( | |
1457 NotificationType::EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED, | |
1458 Source<ExtensionAction>(page_action_), | |
1459 Details<TabContents>(contents)); | |
1460 } | |
1461 } | |
1462 | |
1463 void LocationBarViewGtk::PageActionViewGtk::OnImageLoaded( | |
1464 SkBitmap* image, ExtensionResource resource, int index) { | |
1465 // We loaded icons()->size() icons, plus one extra if the page action had | |
1466 // a default icon. | |
1467 int total_icons = static_cast<int>(page_action_->icon_paths()->size()); | |
1468 if (!page_action_->default_icon_path().empty()) | |
1469 total_icons++; | |
1470 DCHECK(index < total_icons); | |
1471 | |
1472 // Map the index of the loaded image back to its name. If we ever get an | |
1473 // index greater than the number of icons, it must be the default icon. | |
1474 if (image) { | |
1475 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(image); | |
1476 if (index < static_cast<int>(page_action_->icon_paths()->size())) | |
1477 pixbufs_[page_action_->icon_paths()->at(index)] = pixbuf; | |
1478 else | |
1479 pixbufs_[page_action_->default_icon_path()] = pixbuf; | |
1480 } | |
1481 | |
1482 // If we have no owner, that means this class is still being constructed and | |
1483 // we should not UpdatePageActions, since it leads to the PageActions being | |
1484 // destroyed again and new ones recreated (causing an infinite loop). | |
1485 if (owner_) | |
1486 owner_->UpdatePageActions(); | |
1487 } | |
1488 | |
1489 void LocationBarViewGtk::PageActionViewGtk::TestActivatePageAction() { | |
1490 GdkEvent event; | |
1491 event.button.button = 1; | |
1492 OnButtonPressed(widget(), &event); | |
1493 } | |
1494 | |
1495 void LocationBarViewGtk::PageActionViewGtk::InspectPopup( | |
1496 ExtensionAction* action) { | |
1497 ShowPopup(true); | |
1498 } | |
1499 | |
1500 bool LocationBarViewGtk::PageActionViewGtk::ShowPopup(bool devtools) { | |
1501 if (!page_action_->HasPopup(current_tab_id_)) | |
1502 return false; | |
1503 | |
1504 ExtensionPopupGtk::Show( | |
1505 page_action_->GetPopupUrl(current_tab_id_), | |
1506 owner_->browser_, | |
1507 event_box_.get(), | |
1508 devtools); | |
1509 return true; | |
1510 } | |
1511 | |
1512 gboolean LocationBarViewGtk::PageActionViewGtk::OnButtonPressed( | |
1513 GtkWidget* sender, | |
1514 GdkEvent* event) { | |
1515 if (event->button.button != 3) { | |
1516 if (!ShowPopup(false)) { | |
1517 ExtensionBrowserEventRouter::GetInstance()->PageActionExecuted( | |
1518 profile_, | |
1519 page_action_->extension_id(), | |
1520 page_action_->id(), | |
1521 current_tab_id_, | |
1522 current_url_.spec(), | |
1523 event->button.button); | |
1524 } | |
1525 } else { | |
1526 const Extension* extension = profile_->GetExtensionService()-> | |
1527 GetExtensionById(page_action()->extension_id(), false); | |
1528 | |
1529 context_menu_model_ = | |
1530 new ExtensionContextMenuModel(extension, owner_->browser_, this); | |
1531 context_menu_.reset( | |
1532 new MenuGtk(NULL, context_menu_model_.get())); | |
1533 context_menu_->Popup(sender, event); | |
1534 } | |
1535 | |
1536 return TRUE; | |
1537 } | |
1538 | |
1539 gboolean LocationBarViewGtk::PageActionViewGtk::OnExposeEvent( | |
1540 GtkWidget* widget, GdkEventExpose* event) { | |
1541 TabContents* contents = owner_->GetTabContents(); | |
1542 if (!contents) | |
1543 return FALSE; | |
1544 | |
1545 int tab_id = ExtensionTabUtil::GetTabId(contents); | |
1546 if (tab_id < 0) | |
1547 return FALSE; | |
1548 | |
1549 std::string badge_text = page_action_->GetBadgeText(tab_id); | |
1550 if (badge_text.empty()) | |
1551 return FALSE; | |
1552 | |
1553 gfx::CanvasSkiaPaint canvas(event, false); | |
1554 gfx::Rect bounding_rect(widget->allocation); | |
1555 page_action_->PaintBadge(&canvas, bounding_rect, tab_id); | |
1556 return FALSE; | |
1557 } | |
OLD | NEW |