Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(464)

Side by Side Diff: chrome/browser/gtk/extension_installed_bubble_gtk.cc

Issue 6251001: Move chrome/browser/gtk/ to chrome/browser/ui/gtk/... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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/extension_installed_bubble_gtk.h"
6
7 #include <string>
8
9 #include "app/l10n_util.h"
10 #include "app/resource_bundle.h"
11 #include "base/i18n/rtl.h"
12 #include "base/message_loop.h"
13 #include "base/utf_string_conversions.h"
14 #include "chrome/browser/gtk/browser_actions_toolbar_gtk.h"
15 #include "chrome/browser/gtk/browser_toolbar_gtk.h"
16 #include "chrome/browser/gtk/browser_window_gtk.h"
17 #include "chrome/browser/gtk/gtk_theme_provider.h"
18 #include "chrome/browser/gtk/gtk_util.h"
19 #include "chrome/browser/gtk/location_bar_view_gtk.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/common/extensions/extension.h"
22 #include "chrome/common/extensions/extension_action.h"
23 #include "chrome/common/notification_details.h"
24 #include "chrome/common/notification_source.h"
25 #include "chrome/common/notification_type.h"
26 #include "gfx/gtk_util.h"
27 #include "grit/generated_resources.h"
28 #include "grit/theme_resources.h"
29
30 namespace {
31
32 const int kHorizontalColumnSpacing = 10;
33 const int kIconPadding = 3;
34 const int kIconSize = 43;
35 const int kTextColumnVerticalSpacing = 7;
36 const int kTextColumnWidth = 350;
37
38 // When showing the bubble for a new browser action, we may have to wait for
39 // the toolbar to finish animating to know where the item's final position
40 // will be.
41 const int kAnimationWaitRetries = 10;
42 const int kAnimationWaitMS = 50;
43
44 // Padding between content and edge of info bubble.
45 const int kContentBorder = 7;
46
47 } // namespace
48
49 void ExtensionInstalledBubbleGtk::Show(const Extension* extension,
50 Browser* browser,
51 SkBitmap icon) {
52 new ExtensionInstalledBubbleGtk(extension, browser, icon);
53 }
54
55 ExtensionInstalledBubbleGtk::ExtensionInstalledBubbleGtk(
56 const Extension* extension, Browser *browser, SkBitmap icon)
57 : extension_(extension),
58 browser_(browser),
59 icon_(icon),
60 animation_wait_retries_(kAnimationWaitRetries) {
61 AddRef(); // Balanced in Close().
62
63 if (!extension_->omnibox_keyword().empty()) {
64 type_ = OMNIBOX_KEYWORD;
65 } else if (extension_->browser_action()) {
66 type_ = BROWSER_ACTION;
67 } else if (extension->page_action() &&
68 !extension->page_action()->default_icon_path().empty()) {
69 type_ = PAGE_ACTION;
70 } else {
71 type_ = GENERIC;
72 }
73
74 // |extension| has been initialized but not loaded at this point. We need
75 // to wait on showing the Bubble until not only the EXTENSION_LOADED gets
76 // fired, but all of the EXTENSION_LOADED Observers have run. Only then can we
77 // be sure that a browser action or page action has had views created which we
78 // can inspect for the purpose of pointing to them.
79 registrar_.Add(this, NotificationType::EXTENSION_LOADED,
80 Source<Profile>(browser->profile()));
81 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
82 Source<Profile>(browser->profile()));
83 }
84
85 ExtensionInstalledBubbleGtk::~ExtensionInstalledBubbleGtk() {}
86
87 void ExtensionInstalledBubbleGtk::Observe(NotificationType type,
88 const NotificationSource& source,
89 const NotificationDetails& details) {
90 if (type == NotificationType::EXTENSION_LOADED) {
91 const Extension* extension = Details<const Extension>(details).ptr();
92 if (extension == extension_) {
93 // PostTask to ourself to allow all EXTENSION_LOADED Observers to run.
94 MessageLoopForUI::current()->PostTask(FROM_HERE, NewRunnableMethod(this,
95 &ExtensionInstalledBubbleGtk::ShowInternal));
96 }
97 } else if (type == NotificationType::EXTENSION_UNLOADED) {
98 const Extension* extension =
99 Details<UnloadedExtensionInfo>(details)->extension;
100 if (extension == extension_)
101 extension_ = NULL;
102 } else {
103 NOTREACHED() << L"Received unexpected notification";
104 }
105 }
106
107 void ExtensionInstalledBubbleGtk::ShowInternal() {
108 BrowserWindowGtk* browser_window =
109 BrowserWindowGtk::GetBrowserWindowForNativeWindow(
110 browser_->window()->GetNativeHandle());
111
112 GtkWidget* reference_widget = NULL;
113
114 if (type_ == BROWSER_ACTION) {
115 BrowserActionsToolbarGtk* toolbar =
116 browser_window->GetToolbar()->GetBrowserActionsToolbar();
117
118 if (toolbar->animating() && animation_wait_retries_-- > 0) {
119 MessageLoopForUI::current()->PostDelayedTask(
120 FROM_HERE,
121 NewRunnableMethod(this, &ExtensionInstalledBubbleGtk::ShowInternal),
122 kAnimationWaitMS);
123 return;
124 }
125
126 reference_widget = toolbar->GetBrowserActionWidget(extension_);
127 // glib delays recalculating layout, but we need reference_widget to know
128 // its coordinates, so we force a check_resize here.
129 gtk_container_check_resize(GTK_CONTAINER(
130 browser_window->GetToolbar()->widget()));
131 // If the widget is not visible then browser_window could be incognito
132 // with this extension disabled. Try showing it on the chevron.
133 // If that fails, fall back to default position.
134 if (reference_widget && !GTK_WIDGET_VISIBLE(reference_widget)) {
135 reference_widget = GTK_WIDGET_VISIBLE(toolbar->chevron()) ?
136 toolbar->chevron() : NULL;
137 }
138 } else if (type_ == PAGE_ACTION) {
139 LocationBarViewGtk* location_bar_view =
140 browser_window->GetToolbar()->GetLocationBarView();
141 location_bar_view->SetPreviewEnabledPageAction(extension_->page_action(),
142 true); // preview_enabled
143 reference_widget = location_bar_view->GetPageActionWidget(
144 extension_->page_action());
145 // glib delays recalculating layout, but we need reference_widget to know
146 // it's coordinates, so we force a check_resize here.
147 gtk_container_check_resize(GTK_CONTAINER(
148 browser_window->GetToolbar()->widget()));
149 DCHECK(reference_widget);
150 } else if (type_ == OMNIBOX_KEYWORD) {
151 LocationBarViewGtk* location_bar_view =
152 browser_window->GetToolbar()->GetLocationBarView();
153 reference_widget = location_bar_view->location_entry_widget();
154 DCHECK(reference_widget);
155 }
156
157 // Default case.
158 if (reference_widget == NULL)
159 reference_widget = browser_window->GetToolbar()->GetAppMenuButton();
160
161 GtkThemeProvider* theme_provider = GtkThemeProvider::GetFrom(
162 browser_->profile());
163
164 // Setup the InfoBubble content.
165 GtkWidget* bubble_content = gtk_hbox_new(FALSE, kHorizontalColumnSpacing);
166 gtk_container_set_border_width(GTK_CONTAINER(bubble_content), kContentBorder);
167
168 if (!icon_.isNull()) {
169 // Scale icon down to 43x43, but allow smaller icons (don't scale up).
170 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&icon_);
171 gfx::Size size(icon_.width(), icon_.height());
172 if (size.width() > kIconSize || size.height() > kIconSize) {
173 if (size.width() > size.height()) {
174 size.set_height(size.height() * kIconSize / size.width());
175 size.set_width(kIconSize);
176 } else {
177 size.set_width(size.width() * kIconSize / size.height());
178 size.set_height(kIconSize);
179 }
180
181 GdkPixbuf* old = pixbuf;
182 pixbuf = gdk_pixbuf_scale_simple(pixbuf, size.width(), size.height(),
183 GDK_INTERP_BILINEAR);
184 g_object_unref(old);
185 }
186
187 // Put Icon in top of the left column.
188 GtkWidget* icon_column = gtk_vbox_new(FALSE, 0);
189 // Use 3 pixel padding to get visual balance with InfoBubble border on the
190 // left.
191 gtk_box_pack_start(GTK_BOX(bubble_content), icon_column, FALSE, FALSE,
192 kIconPadding);
193 GtkWidget* image = gtk_image_new_from_pixbuf(pixbuf);
194 g_object_unref(pixbuf);
195 gtk_box_pack_start(GTK_BOX(icon_column), image, FALSE, FALSE, 0);
196 }
197
198 // Center text column.
199 GtkWidget* text_column = gtk_vbox_new(FALSE, kTextColumnVerticalSpacing);
200 gtk_box_pack_start(GTK_BOX(bubble_content), text_column, FALSE, FALSE, 0);
201
202 // Heading label
203 GtkWidget* heading_label = gtk_label_new(NULL);
204 string16 extension_name = UTF8ToUTF16(extension_->name());
205 base::i18n::AdjustStringForLocaleDirection(&extension_name);
206 std::string heading_text = l10n_util::GetStringFUTF8(
207 IDS_EXTENSION_INSTALLED_HEADING, extension_name);
208 char* markup = g_markup_printf_escaped("<span size=\"larger\">%s</span>",
209 heading_text.c_str());
210 gtk_label_set_markup(GTK_LABEL(heading_label), markup);
211 g_free(markup);
212
213 gtk_label_set_line_wrap(GTK_LABEL(heading_label), TRUE);
214 gtk_widget_set_size_request(heading_label, kTextColumnWidth, -1);
215 gtk_box_pack_start(GTK_BOX(text_column), heading_label, FALSE, FALSE, 0);
216
217 // Page action label
218 if (type_ == PAGE_ACTION) {
219 GtkWidget* info_label = gtk_label_new(l10n_util::GetStringUTF8(
220 IDS_EXTENSION_INSTALLED_PAGE_ACTION_INFO).c_str());
221 gtk_label_set_line_wrap(GTK_LABEL(info_label), TRUE);
222 gtk_widget_set_size_request(info_label, kTextColumnWidth, -1);
223 gtk_box_pack_start(GTK_BOX(text_column), info_label, FALSE, FALSE, 0);
224 }
225
226 // Omnibox keyword label
227 if (type_ == OMNIBOX_KEYWORD) {
228 GtkWidget* info_label = gtk_label_new(l10n_util::GetStringFUTF8(
229 IDS_EXTENSION_INSTALLED_OMNIBOX_KEYWORD_INFO,
230 UTF8ToUTF16(extension_->omnibox_keyword())).c_str());
231 gtk_label_set_line_wrap(GTK_LABEL(info_label), TRUE);
232 gtk_widget_set_size_request(info_label, kTextColumnWidth, -1);
233 gtk_box_pack_start(GTK_BOX(text_column), info_label, FALSE, FALSE, 0);
234 }
235
236 // Manage label
237 GtkWidget* manage_label = gtk_label_new(
238 l10n_util::GetStringUTF8(IDS_EXTENSION_INSTALLED_MANAGE_INFO).c_str());
239 gtk_label_set_line_wrap(GTK_LABEL(manage_label), TRUE);
240 gtk_widget_set_size_request(manage_label, kTextColumnWidth, -1);
241 gtk_box_pack_start(GTK_BOX(text_column), manage_label, FALSE, FALSE, 0);
242
243 // Create and pack the close button.
244 GtkWidget* close_column = gtk_vbox_new(FALSE, 0);
245 gtk_box_pack_start(GTK_BOX(bubble_content), close_column, FALSE, FALSE, 0);
246 close_button_.reset(CustomDrawButton::CloseButton(theme_provider));
247 g_signal_connect(close_button_->widget(), "clicked",
248 G_CALLBACK(OnButtonClick), this);
249 gtk_box_pack_start(GTK_BOX(close_column), close_button_->widget(),
250 FALSE, FALSE, 0);
251
252 InfoBubbleGtk::ArrowLocationGtk arrow_location =
253 !base::i18n::IsRTL() ?
254 InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT :
255 InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT;
256
257 gfx::Rect bounds = gtk_util::WidgetBounds(reference_widget);
258 if (type_ == OMNIBOX_KEYWORD) {
259 // Reverse the arrow for omnibox keywords, since the bubble will be on the
260 // other side of the window. We also clear the width to avoid centering
261 // the popup on the URL bar.
262 arrow_location =
263 !base::i18n::IsRTL() ?
264 InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT :
265 InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT;
266 if (base::i18n::IsRTL())
267 bounds.Offset(bounds.width(), 0);
268 bounds.set_width(0);
269 }
270
271 info_bubble_ = InfoBubbleGtk::Show(reference_widget,
272 &bounds,
273 bubble_content,
274 arrow_location,
275 true, // match_system_theme
276 true, // grab_input
277 theme_provider,
278 this);
279 }
280
281 // static
282 void ExtensionInstalledBubbleGtk::OnButtonClick(GtkWidget* button,
283 ExtensionInstalledBubbleGtk* bubble) {
284 if (button == bubble->close_button_->widget()) {
285 bubble->info_bubble_->Close();
286 } else {
287 NOTREACHED();
288 }
289 }
290 // InfoBubbleDelegate
291 void ExtensionInstalledBubbleGtk::InfoBubbleClosing(InfoBubbleGtk* info_bubble,
292 bool closed_by_escape) {
293 if (extension_ && type_ == PAGE_ACTION) {
294 // Turn the page action preview off.
295 BrowserWindowGtk* browser_window =
296 BrowserWindowGtk::GetBrowserWindowForNativeWindow(
297 browser_->window()->GetNativeHandle());
298 LocationBarViewGtk* location_bar_view =
299 browser_window->GetToolbar()->GetLocationBarView();
300 location_bar_view->SetPreviewEnabledPageAction(extension_->page_action(),
301 false); // preview_enabled
302 }
303
304 // We need to allow the info bubble to close and remove the widgets from
305 // the window before we call Release() because close_button_ depends
306 // on all references being cleared before it is destroyed.
307 MessageLoopForUI::current()->PostTask(FROM_HERE, NewRunnableMethod(this,
308 &ExtensionInstalledBubbleGtk::Close));
309 }
310
311 void ExtensionInstalledBubbleGtk::Close() {
312 Release(); // Balanced in ctor.
313 info_bubble_ = NULL;
314 }
OLDNEW
« no previous file with comments | « chrome/browser/gtk/extension_installed_bubble_gtk.h ('k') | chrome/browser/gtk/extension_popup_gtk.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698