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

Side by Side Diff: chrome/browser/ui/gtk/browser_titlebar.cc

Issue 231733005: Delete the GTK+ port of Chrome. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remerge to ToT Created 6 years, 8 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) 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 #include "chrome/browser/ui/gtk/browser_titlebar.h"
6
7 #include <gdk/gdkkeysyms.h>
8 #include <gtk/gtk.h>
9
10 #include <string>
11 #include <vector>
12
13 #include "base/command_line.h"
14 #include "base/i18n/rtl.h"
15 #include "base/memory/singleton.h"
16 #include "base/prefs/pref_service.h"
17 #include "base/strings/string_piece.h"
18 #include "base/strings/string_tokenizer.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "chrome/app/chrome_command_ids.h"
21 #include "chrome/browser/browser_process.h"
22 #include "chrome/browser/chrome_notification_types.h"
23 #include "chrome/browser/profiles/avatar_menu.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/browser/profiles/profile_info_cache.h"
26 #include "chrome/browser/profiles/profile_manager.h"
27 #include "chrome/browser/themes/theme_properties.h"
28 #include "chrome/browser/ui/browser.h"
29 #include "chrome/browser/ui/browser_commands.h"
30 #include "chrome/browser/ui/gtk/accelerators_gtk.h"
31 #include "chrome/browser/ui/gtk/avatar_menu_bubble_gtk.h"
32 #include "chrome/browser/ui/gtk/avatar_menu_button_gtk.h"
33 #include "chrome/browser/ui/gtk/browser_window_gtk.h"
34 #include "chrome/browser/ui/gtk/custom_button.h"
35 #if defined(USE_GCONF)
36 #include "chrome/browser/ui/gtk/gconf_titlebar_listener.h"
37 #endif
38 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
39 #include "chrome/browser/ui/gtk/gtk_util.h"
40 #include "chrome/browser/ui/gtk/menu_gtk.h"
41 #include "chrome/browser/ui/gtk/nine_box.h"
42 #include "chrome/browser/ui/gtk/tabs/tab_strip_gtk.h"
43 #include "chrome/browser/ui/gtk/unity_service.h"
44 #include "chrome/browser/ui/tabs/tab_strip_model.h"
45 #include "chrome/browser/ui/toolbar/encoding_menu_controller.h"
46 #include "chrome/browser/ui/toolbar/wrench_menu_model.h"
47 #include "chrome/common/chrome_switches.h"
48 #include "chrome/common/pref_names.h"
49 #include "content/public/browser/notification_service.h"
50 #include "content/public/browser/web_contents.h"
51 #include "grit/generated_resources.h"
52 #include "grit/theme_resources.h"
53 #include "grit/ui_resources.h"
54 #include "ui/base/gtk/gtk_hig_constants.h"
55 #include "ui/base/l10n/l10n_util.h"
56 #include "ui/base/resource/resource_bundle.h"
57 #include "ui/base/x/active_window_watcher_x.h"
58 #include "ui/gfx/image/image.h"
59
60 using content::WebContents;
61
62 namespace {
63
64 // The space above the titlebars.
65 const int kTitlebarHeight = 14;
66
67 // The thickness in pixels of the tab border.
68 const int kTabOuterThickness = 1;
69
70 // Amount to offset the tab images relative to the background.
71 const int kNormalVerticalOffset = kTitlebarHeight + kTabOuterThickness;
72
73 // A linux specific menu item for toggling window decorations.
74 const int kShowWindowDecorationsCommand = 200;
75
76 const int kAvatarBottomSpacing = 1;
77 // There are 2 px on each side of the avatar (between the frame border and
78 // it on the left, and between it and the tabstrip on the right).
79 const int kAvatarSideSpacing = 2;
80
81 // There is a 4px gap between the icon and the title text.
82 const int kIconTitleSpacing = 4;
83
84 // Padding around the icon when in app mode or popup mode.
85 const int kAppModePaddingTop = 5;
86 const int kAppModePaddingBottom = 4;
87 const int kAppModePaddingLeft = 2;
88
89 // The left padding of the tab strip. In Views, the tab strip has a left
90 // margin of FrameBorderThickness + kClientEdgeThickness. This offset is to
91 // account for kClientEdgeThickness.
92 const int kTabStripLeftPadding = 1;
93
94 // Spacing between buttons of the titlebar.
95 const int kButtonSpacing = 2;
96
97 // Spacing around outside of titlebar buttons.
98 const int kButtonOuterPadding = 2;
99
100 // Spacing between tabstrip and window control buttons (when the window is
101 // maximized).
102 const int kMaximizedTabstripPadding = 16;
103
104 gboolean OnMouseMoveEvent(GtkWidget* widget, GdkEventMotion* event,
105 BrowserWindowGtk* browser_window) {
106 // Reset to the default mouse cursor.
107 browser_window->ResetCustomFrameCursor();
108 return TRUE;
109 }
110
111 // Converts a GdkColor to a color_utils::HSL.
112 color_utils::HSL GdkColorToHSL(const GdkColor* color) {
113 color_utils::HSL hsl;
114 color_utils::SkColorToHSL(SkColorSetRGB(color->red >> 8,
115 color->green >> 8,
116 color->blue >> 8), &hsl);
117 return hsl;
118 }
119
120 // Returns either |one| or |two| based on which has a greater difference in
121 // luminosity.
122 GdkColor PickLuminosityContrastingColor(const GdkColor* base,
123 const GdkColor* one,
124 const GdkColor* two) {
125 // Convert all GdkColors to color_utils::HSLs.
126 color_utils::HSL baseHSL = GdkColorToHSL(base);
127 color_utils::HSL oneHSL = GdkColorToHSL(one);
128 color_utils::HSL twoHSL = GdkColorToHSL(two);
129 double one_difference = fabs(baseHSL.l - oneHSL.l);
130 double two_difference = fabs(baseHSL.l - twoHSL.l);
131
132 // Be biased towards the first color presented.
133 if (two_difference > one_difference + 0.1)
134 return *two;
135 else
136 return *one;
137 }
138
139 } // namespace
140
141 ////////////////////////////////////////////////////////////////////////////////
142 // PopupPageMenuModel
143
144 // A menu model that builds the contents of the menu shown for popups (when the
145 // user clicks on the favicon) and all of its submenus.
146 class PopupPageMenuModel : public ui::SimpleMenuModel {
147 public:
148 PopupPageMenuModel(ui::SimpleMenuModel::Delegate* delegate, Browser* browser);
149 virtual ~PopupPageMenuModel() { }
150
151 private:
152 void Build();
153
154 // Models for submenus referenced by this model. SimpleMenuModel only uses
155 // weak references so these must be kept for the lifetime of the top-level
156 // model.
157 scoped_ptr<ZoomMenuModel> zoom_menu_model_;
158 scoped_ptr<EncodingMenuModel> encoding_menu_model_;
159 Browser* browser_; // weak
160
161 DISALLOW_COPY_AND_ASSIGN(PopupPageMenuModel);
162 };
163
164 PopupPageMenuModel::PopupPageMenuModel(
165 ui::SimpleMenuModel::Delegate* delegate,
166 Browser* browser)
167 : ui::SimpleMenuModel(delegate), browser_(browser) {
168 Build();
169 }
170
171 void PopupPageMenuModel::Build() {
172 AddItemWithStringId(IDC_BACK, IDS_CONTENT_CONTEXT_BACK);
173 AddItemWithStringId(IDC_FORWARD, IDS_CONTENT_CONTEXT_FORWARD);
174 AddItemWithStringId(IDC_RELOAD, IDS_APP_MENU_RELOAD);
175 AddSeparator(ui::NORMAL_SEPARATOR);
176 AddItemWithStringId(IDC_SHOW_AS_TAB, IDS_SHOW_AS_TAB);
177 AddSeparator(ui::NORMAL_SEPARATOR);
178 AddItemWithStringId(IDC_CUT, IDS_CUT);
179 AddItemWithStringId(IDC_COPY, IDS_COPY);
180 AddItemWithStringId(IDC_PASTE, IDS_PASTE);
181 AddSeparator(ui::NORMAL_SEPARATOR);
182 AddItemWithStringId(IDC_FIND, IDS_FIND);
183 AddItemWithStringId(IDC_PRINT, IDS_PRINT);
184 zoom_menu_model_.reset(new ZoomMenuModel(delegate()));
185 AddSubMenuWithStringId(IDC_ZOOM_MENU, IDS_ZOOM_MENU, zoom_menu_model_.get());
186
187 encoding_menu_model_.reset(new EncodingMenuModel(browser_));
188 AddSubMenuWithStringId(IDC_ENCODING_MENU, IDS_ENCODING_MENU,
189 encoding_menu_model_.get());
190
191 AddSeparator(ui::NORMAL_SEPARATOR);
192 AddItemWithStringId(IDC_CLOSE_WINDOW, IDS_CLOSE);
193 }
194
195 ////////////////////////////////////////////////////////////////////////////////
196 // BrowserTitlebar
197
198 // static
199 const char BrowserTitlebar::kDefaultButtonString[] = ":minimize,maximize,close";
200
201 BrowserTitlebar::BrowserTitlebar(BrowserWindowGtk* browser_window,
202 GtkWindow* window)
203 : browser_window_(browser_window),
204 window_(window),
205 container_(NULL),
206 container_hbox_(NULL),
207 titlebar_left_buttons_vbox_(NULL),
208 titlebar_right_buttons_vbox_(NULL),
209 titlebar_left_buttons_hbox_(NULL),
210 titlebar_right_buttons_hbox_(NULL),
211 titlebar_left_avatar_frame_(NULL),
212 titlebar_right_avatar_frame_(NULL),
213 titlebar_left_label_frame_(NULL),
214 titlebar_right_label_frame_(NULL),
215 avatar_(NULL),
216 avatar_label_(NULL),
217 avatar_label_bg_(NULL),
218 top_padding_left_(NULL),
219 top_padding_right_(NULL),
220 titlebar_alignment_(NULL),
221 app_mode_favicon_(NULL),
222 app_mode_title_(NULL),
223 using_custom_frame_(false),
224 window_has_focus_(false),
225 display_avatar_on_left_(false),
226 theme_service_(NULL) {
227 }
228
229 void BrowserTitlebar::Init() {
230 // The widget hierarchy is shown below.
231 //
232 // +- EventBox (container_) ------------------------------------------------+
233 // +- HBox (container_hbox_) -----------------------------------------------+
234 // |+ VBox ---++- Algn. -++- Alignment --------------++- Algn. -++ VBox ---+|
235 // || titlebar||titlebar || (titlebar_alignment_) ||titlebar || titlebar||
236 // || left ||left || ||right || right ||
237 // || button ||spy || ||spy || button ||
238 // || vbox ||frame ||+- TabStripGtk ---------+||frame || vbox ||
239 // || || || tab tab tabclose ||| || ||
240 // || || ||+------------------------+|| || ||
241 // |+---------++---------++--------------------------++---------++---------+|
242 // +------------------------------------------------------------------------+
243 //
244 // There are two vboxes on either side of |container_hbox_| because when the
245 // desktop is GNOME, the button placement is configurable based on a metacity
246 // gconf key. We can't just have one vbox and move it back and forth because
247 // the gconf language allows you to place buttons on both sides of the
248 // window. This being Linux, I'm sure there's a bunch of people who have
249 // already configured their window manager to do so and we don't want to get
250 // confused when that happens. The actual contents of these vboxes are lazily
251 // generated so they don't interfere with alignment when everything is
252 // stuffed in the other box.
253 //
254 // Each vbox has the following hierarchy if it contains buttons:
255 //
256 // +- VBox (titlebar_{l,r}_buttons_vbox_) ---------+
257 // |+- Fixed (top_padding_{l,r}_) ----------------+|
258 // ||+- HBox (titlebar_{l,r}_buttons_hbox_ ------+||
259 // ||| (buttons of a configurable layout) |||
260 // ||+-------------------------------------------+||
261 // |+---------------------------------------------+|
262 // +-----------------------------------------------+
263 //
264 // The two spy alignments are only allocated if this window is an incognito
265 // window. Only one of them holds the spy image.
266 //
267 // If we're a popup window or in app mode, we don't display the spy guy or
268 // the tab strip. Instead, put an hbox in titlebar_alignment_ in place of
269 // the tab strip.
270 // +- Alignment (titlebar_alignment_) -----------------------------------+
271 // |+ HBox -------------------------------------------------------------+|
272 // ||+- TabStripGtk -++- Image ----------------++- Label --------------+||
273 // ||| hidden ++ (app_mode_favicon_) || (app_mode_title_) |||
274 // ||| || favicon || page title |||
275 // ||+---------------++------------------------++----------------------+||
276 // |+-------------------------------------------------------------------+|
277 // +---------------------------------------------------------------------+
278 container_hbox_ = gtk_hbox_new(FALSE, 0);
279
280 container_ = gtk_event_box_new();
281 gtk_widget_set_name(container_, "chrome-browser-titlebar");
282 gtk_event_box_set_visible_window(GTK_EVENT_BOX(container_), FALSE);
283 gtk_container_add(GTK_CONTAINER(container_), container_hbox_);
284
285 g_signal_connect(container_, "scroll-event", G_CALLBACK(OnScrollThunk), this);
286
287 g_signal_connect(window_, "window-state-event",
288 G_CALLBACK(OnWindowStateChangedThunk), this);
289
290 // Allocate the two button boxes on the left and right parts of the bar. These
291 // are always allocated, but only displayed in incognito mode or when using
292 // multiple profiles.
293 titlebar_left_buttons_vbox_ = gtk_vbox_new(FALSE, 0);
294 gtk_box_pack_start(GTK_BOX(container_hbox_), titlebar_left_buttons_vbox_,
295 FALSE, FALSE, 0);
296 titlebar_left_avatar_frame_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
297 gtk_widget_set_no_show_all(titlebar_left_avatar_frame_, TRUE);
298 gtk_alignment_set_padding(GTK_ALIGNMENT(titlebar_left_avatar_frame_), 0,
299 kAvatarBottomSpacing, kAvatarSideSpacing, kAvatarSideSpacing);
300 gtk_box_pack_start(GTK_BOX(container_hbox_), titlebar_left_avatar_frame_,
301 FALSE, FALSE, 0);
302
303 titlebar_left_label_frame_ = gtk_alignment_new(0.0, 0.5, 0.0, 0.0);
304 gtk_widget_set_no_show_all(titlebar_left_label_frame_, TRUE);
305 gtk_alignment_set_padding(GTK_ALIGNMENT(titlebar_left_label_frame_), 0,
306 kAvatarBottomSpacing, kAvatarSideSpacing, kAvatarSideSpacing);
307 gtk_box_pack_start(GTK_BOX(container_hbox_), titlebar_left_label_frame_,
308 FALSE, FALSE, 0);
309
310 titlebar_right_avatar_frame_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
311 gtk_widget_set_no_show_all(titlebar_right_avatar_frame_, TRUE);
312 gtk_alignment_set_padding(GTK_ALIGNMENT(titlebar_right_avatar_frame_), 0,
313 kAvatarBottomSpacing, kAvatarSideSpacing, kAvatarSideSpacing);
314 gtk_box_pack_end(GTK_BOX(container_hbox_), titlebar_right_avatar_frame_,
315 FALSE, FALSE, 0);
316
317 titlebar_right_label_frame_ = gtk_alignment_new(0.0, 0.5, 0.0, 0.0);
318 gtk_widget_set_no_show_all(titlebar_right_label_frame_, TRUE);
319 gtk_alignment_set_padding(GTK_ALIGNMENT(titlebar_right_label_frame_), 0,
320 kAvatarBottomSpacing, kAvatarSideSpacing, kAvatarSideSpacing);
321 gtk_box_pack_end(GTK_BOX(container_hbox_), titlebar_right_label_frame_,
322 FALSE, FALSE, 0);
323
324 titlebar_right_buttons_vbox_ = gtk_vbox_new(FALSE, 0);
325 gtk_box_pack_end(GTK_BOX(container_hbox_), titlebar_right_buttons_vbox_,
326 FALSE, FALSE, 0);
327
328 // Create the Avatar button and listen for notifications. It must always be
329 // created because a new profile can be added at any time.
330 avatar_button_.reset(new AvatarMenuButtonGtk(browser_window_->browser()));
331
332 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
333 content::NotificationService::AllSources());
334
335 #if defined(USE_GCONF)
336 // Either read the gconf database and register for updates (on GNOME), or use
337 // the default value (anywhere else).
338 GConfTitlebarListener::GetInstance()->SetTitlebarButtons(this);
339 #else
340 BuildButtons(kDefaultButtonString);
341 #endif
342
343 UpdateAvatar();
344
345 // We use an alignment to control the titlebar height.
346 titlebar_alignment_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
347 if (browser_window_->browser()->is_type_tabbed()) {
348 gtk_box_pack_start(GTK_BOX(container_hbox_), titlebar_alignment_, TRUE,
349 TRUE, 0);
350
351 // Put the tab strip in the titlebar.
352 gtk_container_add(GTK_CONTAINER(titlebar_alignment_),
353 browser_window_->tabstrip()->widget());
354 } else {
355 // App mode specific widgets.
356 gtk_box_pack_start(GTK_BOX(container_hbox_), titlebar_alignment_, TRUE,
357 TRUE, 0);
358 GtkWidget* app_mode_hbox = gtk_hbox_new(FALSE, kIconTitleSpacing);
359 gtk_container_add(GTK_CONTAINER(titlebar_alignment_), app_mode_hbox);
360
361 // Put the tab strip in the hbox even though we don't show it. Sometimes
362 // we need the position of the tab strip so make sure it's in our widget
363 // hierarchy.
364 gtk_box_pack_start(GTK_BOX(app_mode_hbox),
365 browser_window_->tabstrip()->widget(), FALSE, FALSE, 0);
366
367 GtkWidget* favicon_event_box = gtk_event_box_new();
368 gtk_event_box_set_visible_window(GTK_EVENT_BOX(favicon_event_box), FALSE);
369 g_signal_connect(favicon_event_box, "button-press-event",
370 G_CALLBACK(OnFaviconMenuButtonPressedThunk), this);
371 gtk_box_pack_start(GTK_BOX(app_mode_hbox), favicon_event_box, FALSE,
372 FALSE, 0);
373 // We use the app logo as a placeholder image so the title doesn't jump
374 // around.
375 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
376 app_mode_favicon_ = gtk_image_new_from_pixbuf(rb.GetNativeImageNamed(
377 IDR_PRODUCT_LOGO_16, ui::ResourceBundle::RTL_ENABLED).ToGdkPixbuf());
378 g_object_set_data(G_OBJECT(app_mode_favicon_), "left-align-popup",
379 reinterpret_cast<void*>(true));
380 gtk_container_add(GTK_CONTAINER(favicon_event_box), app_mode_favicon_);
381
382 app_mode_title_ = gtk_label_new(NULL);
383 gtk_label_set_ellipsize(GTK_LABEL(app_mode_title_), PANGO_ELLIPSIZE_END);
384 gtk_misc_set_alignment(GTK_MISC(app_mode_title_), 0.0, 0.5);
385 gtk_box_pack_start(GTK_BOX(app_mode_hbox), app_mode_title_, TRUE, TRUE,
386 0);
387
388 UpdateTitleAndIcon();
389 }
390
391 theme_service_ = GtkThemeService::GetFrom(
392 browser_window_->browser()->profile());
393 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
394 content::Source<ThemeService>(theme_service_));
395 theme_service_->InitThemesFor(this);
396
397 gtk_widget_show_all(container_);
398
399 ui::ActiveWindowWatcherX::AddObserver(this);
400 }
401
402 BrowserTitlebar::~BrowserTitlebar() {
403 ui::ActiveWindowWatcherX::RemoveObserver(this);
404 #if defined(USE_GCONF)
405 GConfTitlebarListener::GetInstance()->RemoveObserver(this);
406 #endif
407 }
408
409 void BrowserTitlebar::BuildButtons(const std::string& button_string) {
410 // Clear out all previous data.
411 close_button_.reset();
412 restore_button_.reset();
413 maximize_button_.reset();
414 minimize_button_.reset();
415 gtk_util::RemoveAllChildren(titlebar_left_buttons_vbox_);
416 gtk_util::RemoveAllChildren(titlebar_right_buttons_vbox_);
417 titlebar_left_buttons_hbox_ = NULL;
418 titlebar_right_buttons_hbox_ = NULL;
419 top_padding_left_ = NULL;
420 top_padding_right_ = NULL;
421
422 bool left_side = true;
423 base::StringTokenizer tokenizer(button_string, ":,");
424 tokenizer.set_options(base::StringTokenizer::RETURN_DELIMS);
425 int left_count = 0;
426 int right_count = 0;
427 while (tokenizer.GetNext()) {
428 if (tokenizer.token_is_delim()) {
429 if (*tokenizer.token_begin() == ':')
430 left_side = false;
431 } else {
432 base::StringPiece token = tokenizer.token_piece();
433 if (BuildButton(token.as_string(), left_side))
434 (left_side ? left_count : right_count)++;
435 }
436 }
437
438 // If we are in incognito mode, add the spy guy to either the end of the left
439 // or the beginning of the right depending on which side has fewer buttons.
440 display_avatar_on_left_ = right_count > left_count;
441
442 // Now show the correct widgets in the two hierarchies.
443 if (using_custom_frame_) {
444 gtk_widget_show_all(titlebar_left_buttons_vbox_);
445 gtk_widget_show_all(titlebar_right_buttons_vbox_);
446 }
447 UpdateMaximizeRestoreVisibility();
448 }
449
450 bool BrowserTitlebar::BuildButton(const std::string& button_token,
451 bool left_side) {
452 if (button_token == "minimize") {
453 minimize_button_.reset(CreateTitlebarButton("minimize", left_side));
454
455 gtk_widget_size_request(minimize_button_->widget(),
456 &minimize_button_req_);
457 return true;
458 } else if (button_token == "maximize") {
459 restore_button_.reset(CreateTitlebarButton("unmaximize", left_side));
460 maximize_button_.reset(CreateTitlebarButton("maximize", left_side));
461
462 gtk_util::SetButtonClickableByMouseButtons(maximize_button_->widget(),
463 true, true, true);
464 gtk_widget_size_request(restore_button_->widget(),
465 &restore_button_req_);
466 return true;
467 } else if (button_token == "close") {
468 close_button_.reset(CreateTitlebarButton("close", left_side));
469 close_button_->set_flipped(left_side);
470
471 gtk_widget_size_request(close_button_->widget(), &close_button_req_);
472 return true;
473 }
474 // Ignore any other values like "pin" since we don't have images for
475 // those.
476 return false;
477 }
478
479 GtkWidget* BrowserTitlebar::GetButtonHBox(bool left_side) {
480 if (left_side && titlebar_left_buttons_hbox_)
481 return titlebar_left_buttons_hbox_;
482 else if (!left_side && titlebar_right_buttons_hbox_)
483 return titlebar_right_buttons_hbox_;
484
485 // We put the min/max/restore/close buttons in a vbox so they are top aligned
486 // (up to padding) and don't vertically stretch.
487 GtkWidget* vbox = left_side ? titlebar_left_buttons_vbox_ :
488 titlebar_right_buttons_vbox_;
489
490 GtkWidget* top_padding = gtk_fixed_new();
491 gtk_widget_set_size_request(top_padding, -1, kButtonOuterPadding);
492 gtk_box_pack_start(GTK_BOX(vbox), top_padding, FALSE, FALSE, 0);
493
494 GtkWidget* buttons_hbox = gtk_hbox_new(FALSE, kButtonSpacing);
495 gtk_box_pack_start(GTK_BOX(vbox), buttons_hbox, FALSE, FALSE, 0);
496
497 if (left_side) {
498 titlebar_left_buttons_hbox_ = buttons_hbox;
499 top_padding_left_ = top_padding;
500 } else {
501 titlebar_right_buttons_hbox_ = buttons_hbox;
502 top_padding_right_ = top_padding;
503 }
504
505 return buttons_hbox;
506 }
507
508 CustomDrawButton* BrowserTitlebar::CreateTitlebarButton(
509 const std::string& button_name, bool left_side) {
510 int normal_image_id;
511 int pressed_image_id;
512 int hover_image_id;
513 int tooltip_id;
514 GetButtonResources(button_name, &normal_image_id, &pressed_image_id,
515 &hover_image_id, &tooltip_id);
516
517 CustomDrawButton* button = new CustomDrawButton(normal_image_id,
518 pressed_image_id,
519 hover_image_id,
520 0);
521 gtk_widget_add_events(GTK_WIDGET(button->widget()), GDK_POINTER_MOTION_MASK);
522 g_signal_connect(button->widget(), "clicked",
523 G_CALLBACK(OnButtonClickedThunk), this);
524 g_signal_connect(button->widget(), "motion-notify-event",
525 G_CALLBACK(OnMouseMoveEvent), browser_window_);
526
527 std::string localized_tooltip = l10n_util::GetStringUTF8(tooltip_id);
528 gtk_widget_set_tooltip_text(button->widget(),
529 localized_tooltip.c_str());
530
531 GtkWidget* box = GetButtonHBox(left_side);
532 gtk_box_pack_start(GTK_BOX(box), button->widget(), FALSE, FALSE, 0);
533 return button;
534 }
535
536 void BrowserTitlebar::GetButtonResources(const std::string& button_name,
537 int* normal_image_id,
538 int* pressed_image_id,
539 int* hover_image_id,
540 int* tooltip_id) const {
541 if (button_name == "close") {
542 *normal_image_id = IDR_CLOSE;
543 *pressed_image_id = IDR_CLOSE_P;
544 *hover_image_id = IDR_CLOSE_H;
545 *tooltip_id = IDS_XPFRAME_CLOSE_TOOLTIP;
546 } else if (button_name == "minimize") {
547 *normal_image_id = IDR_MINIMIZE;
548 *pressed_image_id = IDR_MINIMIZE_P;
549 *hover_image_id = IDR_MINIMIZE_H;
550 *tooltip_id = IDS_XPFRAME_MINIMIZE_TOOLTIP;
551 } else if (button_name == "maximize") {
552 *normal_image_id = IDR_MAXIMIZE;
553 *pressed_image_id = IDR_MAXIMIZE_P;
554 *hover_image_id = IDR_MAXIMIZE_H;
555 *tooltip_id = IDS_XPFRAME_MAXIMIZE_TOOLTIP;
556 } else if (button_name == "unmaximize") {
557 *normal_image_id = IDR_RESTORE;
558 *pressed_image_id = IDR_RESTORE_P;
559 *hover_image_id = IDR_RESTORE_H;
560 *tooltip_id = IDS_XPFRAME_RESTORE_TOOLTIP;
561 }
562 }
563
564 void BrowserTitlebar::UpdateButtonBackground(CustomDrawButton* button) {
565 SkColor color = theme_service_->GetColor(
566 ThemeProperties::COLOR_BUTTON_BACKGROUND);
567 SkBitmap background = theme_service_->GetImageNamed(
568 IDR_THEME_WINDOW_CONTROL_BACKGROUND).AsBitmap();
569
570 // TODO(erg): For now, we just use a completely black mask and we can get
571 // away with this in the short term because our buttons are rectangles. We
572 // should get Glen to make properly hinted masks that match our min/max/close
573 // buttons (which have some odd alpha blending around the
574 // edges). http://crbug.com/103661
575 SkBitmap mask;
576 mask.setConfig(SkBitmap::kARGB_8888_Config,
577 button->SurfaceWidth(), button->SurfaceHeight(), 0);
578 mask.allocPixels();
579 mask.eraseColor(SK_ColorBLACK);
580
581 button->SetBackground(color, background, mask);
582 }
583
584 void BrowserTitlebar::UpdateCustomFrame(bool use_custom_frame) {
585 using_custom_frame_ = use_custom_frame;
586 if (!use_custom_frame ||
587 (browser_window_->IsMaximized() && unity::IsRunning())) {
588 if (titlebar_left_buttons_vbox_)
589 gtk_widget_hide(titlebar_left_buttons_vbox_);
590 if (titlebar_right_buttons_vbox_)
591 gtk_widget_hide(titlebar_right_buttons_vbox_);
592 } else {
593 if (titlebar_left_buttons_vbox_)
594 gtk_widget_show_all(titlebar_left_buttons_vbox_);
595 if (titlebar_right_buttons_vbox_)
596 gtk_widget_show_all(titlebar_right_buttons_vbox_);
597 }
598 UpdateTitlebarAlignment();
599 UpdateMaximizeRestoreVisibility();
600 }
601
602 void BrowserTitlebar::UpdateTitleAndIcon() {
603 if (!app_mode_title_)
604 return;
605
606 // Get the page title and elide it to the available space.
607 base::string16 title =
608 browser_window_->browser()->GetWindowTitleForCurrentTab();
609 gtk_label_set_text(GTK_LABEL(app_mode_title_),
610 base::UTF16ToUTF8(title).c_str());
611
612 if (browser_window_->browser()->is_app()) {
613 switch (browser_window_->browser()->type()) {
614 case Browser::TYPE_POPUP: {
615 // Update the system app icon. We don't need to update the icon in the
616 // top left of the custom frame, that will get updated when the
617 // throbber is updated.
618 Profile* profile = browser_window_->browser()->profile();
619 gfx::Image icon = browser_window_->browser()->GetCurrentPageIcon();
620 if (icon.IsEmpty()) {
621 gtk_util::SetWindowIcon(window_, profile);
622 } else {
623 gtk_util::SetWindowIcon(window_, profile, icon.ToGdkPixbuf());
624 }
625 break;
626 }
627 case Browser::TYPE_TABBED: {
628 NOTREACHED() << "We should never have a tabbed app window.";
629 break;
630 }
631 }
632 }
633 }
634
635 void BrowserTitlebar::UpdateThrobber(WebContents* web_contents) {
636 DCHECK(app_mode_favicon_);
637
638 if (web_contents && web_contents->IsLoading()) {
639 GdkPixbuf* icon_pixbuf =
640 throbber_.GetNextFrame(web_contents->IsWaitingForResponse());
641 gtk_image_set_from_pixbuf(GTK_IMAGE(app_mode_favicon_), icon_pixbuf);
642 } else {
643 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
644
645 // Note: we want to exclude the application popup/panel window.
646 if ((browser_window_->browser()->is_app() &&
647 !browser_window_->browser()->is_type_tabbed()) ||
648 browser_window_->browser()->is_type_popup()) {
649 gfx::Image icon = browser_window_->browser()->GetCurrentPageIcon();
650 if (icon.IsEmpty()) {
651 // Fallback to the Chromium icon if the page has no icon.
652 gtk_image_set_from_pixbuf(GTK_IMAGE(app_mode_favicon_),
653 rb.GetNativeImageNamed(IDR_PRODUCT_LOGO_16).ToGdkPixbuf());
654 } else {
655 gtk_image_set_from_pixbuf(GTK_IMAGE(app_mode_favicon_),
656 icon.ToGdkPixbuf());
657 }
658 } else {
659 gtk_image_set_from_pixbuf(GTK_IMAGE(app_mode_favicon_),
660 rb.GetNativeImageNamed(IDR_PRODUCT_LOGO_16).ToGdkPixbuf());
661 }
662 throbber_.Reset();
663 }
664 }
665
666 void BrowserTitlebar::UpdateTitlebarAlignment() {
667 if (browser_window_->browser()->is_type_tabbed()) {
668 int top_padding = 0;
669 int side_padding = 0;
670 int vertical_offset = kNormalVerticalOffset;
671
672 if (using_custom_frame_) {
673 if (!browser_window_->IsMaximized()) {
674 top_padding = kTitlebarHeight;
675 } else if (using_custom_frame_ && browser_window_->IsMaximized()) {
676 vertical_offset = 0;
677 if (!unity::IsRunning())
678 side_padding = kMaximizedTabstripPadding;
679 }
680 }
681
682 int right_padding = 0;
683 int left_padding = kTabStripLeftPadding;
684 if (titlebar_right_buttons_hbox_)
685 right_padding = side_padding;
686 if (titlebar_left_buttons_hbox_)
687 left_padding = side_padding;
688
689 gtk_alignment_set_padding(GTK_ALIGNMENT(titlebar_alignment_),
690 top_padding, 0,
691 left_padding, right_padding);
692 browser_window_->tabstrip()->SetVerticalOffset(vertical_offset);
693 } else {
694 if (using_custom_frame_ && !browser_window_->IsFullscreen()) {
695 gtk_alignment_set_padding(GTK_ALIGNMENT(titlebar_alignment_),
696 kAppModePaddingTop, kAppModePaddingBottom, kAppModePaddingLeft, 0);
697 gtk_widget_show(titlebar_alignment_);
698 } else {
699 gtk_widget_hide(titlebar_alignment_);
700 }
701 }
702
703 // Resize the buttons so that the clickable area extends all the way to the
704 // edge of the browser window.
705 GtkRequisition close_button_req = close_button_req_;
706 GtkRequisition minimize_button_req = minimize_button_req_;
707 GtkRequisition restore_button_req = restore_button_req_;
708 if (using_custom_frame_ && browser_window_->IsMaximized()) {
709 close_button_req.width += kButtonOuterPadding;
710 close_button_req.height += kButtonOuterPadding;
711 minimize_button_req.height += kButtonOuterPadding;
712 restore_button_req.height += kButtonOuterPadding;
713 if (top_padding_left_)
714 gtk_widget_hide(top_padding_left_);
715 if (top_padding_right_)
716 gtk_widget_hide(top_padding_right_);
717 } else {
718 if (top_padding_left_)
719 gtk_widget_show(top_padding_left_);
720 if (top_padding_right_)
721 gtk_widget_show(top_padding_right_);
722 }
723 if (close_button_.get()) {
724 gtk_widget_set_size_request(close_button_->widget(),
725 close_button_req.width,
726 close_button_req.height);
727 }
728 if (minimize_button_.get()) {
729 gtk_widget_set_size_request(minimize_button_->widget(),
730 minimize_button_req.width,
731 minimize_button_req.height);
732 }
733 if (maximize_button_.get()) {
734 gtk_widget_set_size_request(restore_button_->widget(),
735 restore_button_req.width,
736 restore_button_req.height);
737 }
738 }
739
740 void BrowserTitlebar::UpdateTextColor() {
741 if (!app_mode_title_)
742 return;
743
744 if (theme_service_ && theme_service_->UsingNativeTheme()) {
745 // We don't really have any good options here.
746 //
747 // Colors from window manager themes aren't exposed in GTK; the window
748 // manager is a separate component and when there is information sharing
749 // (in the case of metacity), it's one way where the window manager reads
750 // data from the GTK theme (which allows us to do a decent job with
751 // picking the frame color).
752 //
753 // We probably won't match in the majority of cases, but we can at the
754 // very least make things legible. The default metacity and xfwm themes
755 // on ubuntu have white text hardcoded. Determine whether black or white
756 // has more luminosity contrast and then set that color as the text
757 // color.
758 GdkColor frame_color;
759 if (window_has_focus_) {
760 frame_color = theme_service_->GetGdkColor(
761 ThemeProperties::COLOR_FRAME);
762 } else {
763 frame_color = theme_service_->GetGdkColor(
764 ThemeProperties::COLOR_FRAME_INACTIVE);
765 }
766 GdkColor text_color = PickLuminosityContrastingColor(
767 &frame_color, &ui::kGdkWhite, &ui::kGdkBlack);
768 gtk_util::SetLabelColor(app_mode_title_, &text_color);
769 } else {
770 gtk_util::SetLabelColor(app_mode_title_, &ui::kGdkWhite);
771 }
772 }
773
774 void BrowserTitlebar::UpdateAvatarLabel() {
775 if (theme_service_ && avatar_label_) {
776 GdkColor text_color =
777 theme_service_->GetGdkColor(ThemeProperties::COLOR_MANAGED_USER_LABEL);
778 GdkColor label_background = theme_service_->GetGdkColor(
779 ThemeProperties::COLOR_MANAGED_USER_LABEL_BACKGROUND);
780 gtk_util::SetLabelColor(avatar_label_, &text_color);
781 gtk_widget_modify_bg(
782 GTK_WIDGET(avatar_label_bg_), GTK_STATE_NORMAL, &label_background);
783 char* markup = g_markup_printf_escaped(
784 "<span size='small'>%s</span>",
785 l10n_util::GetStringUTF8(IDS_MANAGED_USER_AVATAR_LABEL).c_str());
786 gtk_label_set_markup(GTK_LABEL(avatar_label_), markup);
787 g_free(markup);
788 }
789 }
790
791 void BrowserTitlebar::UpdateAvatar() {
792 // Remove previous state.
793 gtk_util::RemoveAllChildren(titlebar_left_avatar_frame_);
794 gtk_util::RemoveAllChildren(titlebar_right_avatar_frame_);
795 gtk_util::RemoveAllChildren(titlebar_left_label_frame_);
796 gtk_util::RemoveAllChildren(titlebar_right_label_frame_);
797
798 if (!ShouldDisplayAvatar())
799 return;
800
801 if (!avatar_) {
802 if (IsOffTheRecord()) {
803 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
804 gfx::Image avatar_image =
805 rb.GetNativeImageNamed(IDR_OTR_ICON, ui::ResourceBundle::RTL_ENABLED);
806 avatar_ = gtk_image_new_from_pixbuf(avatar_image.ToGdkPixbuf());
807 gtk_misc_set_alignment(GTK_MISC(avatar_), 0.0, 1.0);
808 gtk_widget_set_size_request(avatar_, -1, 0);
809 } else {
810 // Use a clickable avatar.
811 avatar_ = avatar_button_->widget();
812 }
813 }
814
815 gtk_widget_show_all(avatar_);
816
817 Profile* profile = browser_window_->browser()->profile();
818 if (profile->IsManaged()) {
819 avatar_label_ = gtk_label_new(NULL);
820 gtk_misc_set_padding(GTK_MISC(avatar_label_), 10, 2);
821 avatar_label_bg_ = gtk_event_box_new();
822 gtk_container_add(GTK_CONTAINER(avatar_label_bg_), avatar_label_);
823 g_signal_connect(avatar_label_bg_, "button-press-event",
824 G_CALLBACK(OnAvatarLabelButtonPressedThunk), this);
825 UpdateAvatarLabel();
826 gtk_widget_show(avatar_label_bg_);
827 gtk_widget_show(avatar_label_);
828 if (display_avatar_on_left_) {
829 gtk_container_add(GTK_CONTAINER(titlebar_left_label_frame_),
830 avatar_label_bg_);
831 gtk_widget_show(titlebar_left_label_frame_);
832 gtk_widget_hide(titlebar_right_label_frame_);
833 } else {
834 gtk_container_add(GTK_CONTAINER(titlebar_right_label_frame_),
835 avatar_label_bg_);
836 gtk_widget_show(titlebar_right_label_frame_);
837 gtk_widget_hide(titlebar_left_label_frame_);
838 }
839 }
840
841 if (display_avatar_on_left_) {
842 gtk_container_add(GTK_CONTAINER(titlebar_left_avatar_frame_), avatar_);
843 gtk_widget_show(titlebar_left_avatar_frame_);
844 gtk_widget_hide(titlebar_right_avatar_frame_);
845 } else {
846 gtk_container_add(GTK_CONTAINER(titlebar_right_avatar_frame_), avatar_);
847 gtk_widget_show(titlebar_right_avatar_frame_);
848 gtk_widget_hide(titlebar_left_avatar_frame_);
849 }
850
851 if (IsOffTheRecord())
852 return;
853
854 bool is_gaia_picture = false;
855 gfx::Image avatar;
856 ProfileInfoCache& cache =
857 g_browser_process->profile_manager()->GetProfileInfoCache();
858 size_t index = cache.GetIndexOfProfileWithPath(profile->GetPath());
859 if (index == std::string::npos)
860 return;
861
862 is_gaia_picture =
863 cache.IsUsingGAIAPictureOfProfileAtIndex(index) &&
864 cache.GetGAIAPictureOfProfileAtIndex(index);
865 avatar = cache.GetAvatarIconOfProfileAtIndex(index);
866 avatar_button_->SetIcon(avatar, is_gaia_picture);
867 avatar_button_->set_menu_frame_style(display_avatar_on_left_ ?
868 BubbleGtk::ANCHOR_TOP_LEFT : BubbleGtk::ANCHOR_TOP_RIGHT);
869 }
870
871 void BrowserTitlebar::MaximizeButtonClicked() {
872 GdkEvent* event = gtk_get_current_event();
873 if (event->button.button == 1) {
874 gtk_window_maximize(window_);
875 } else {
876 GtkWidget* widget = GTK_WIDGET(window_);
877 GdkScreen* screen = gtk_widget_get_screen(widget);
878 gint monitor = gdk_screen_get_monitor_at_window(
879 screen, gtk_widget_get_window(widget));
880 GdkRectangle screen_rect;
881 gdk_screen_get_monitor_geometry(screen, monitor, &screen_rect);
882
883 gint x, y;
884 gtk_window_get_position(window_, &x, &y);
885
886 GtkAllocation allocation;
887 gtk_widget_get_allocation(widget, &allocation);
888 gint width = allocation.width;
889 gint height = allocation.height;
890
891 if (event->button.button == 3) {
892 x = 0;
893 width = screen_rect.width;
894 } else if (event->button.button == 2) {
895 y = 0;
896 height = screen_rect.height;
897 }
898
899 browser_window_->SetBounds(gfx::Rect(x, y, width, height));
900 }
901 gdk_event_free(event);
902 }
903
904 void BrowserTitlebar::UpdateMaximizeRestoreVisibility() {
905 if (maximize_button_.get()) {
906 if (browser_window_->IsMaximized()) {
907 gtk_widget_hide(maximize_button_->widget());
908 gtk_widget_show(restore_button_->widget());
909 } else {
910 gtk_widget_hide(restore_button_->widget());
911 gtk_widget_show(maximize_button_->widget());
912 }
913 }
914 }
915
916 gboolean BrowserTitlebar::OnWindowStateChanged(GtkWindow* window,
917 GdkEventWindowState* event) {
918 UpdateMaximizeRestoreVisibility();
919 UpdateTitlebarAlignment();
920 UpdateTextColor();
921 return FALSE;
922 }
923
924 gboolean BrowserTitlebar::OnScroll(GtkWidget* widget, GdkEventScroll* event) {
925 Browser* browser = browser_window_->browser();
926 int index = browser->tab_strip_model()->active_index();
927 if (event->direction == GDK_SCROLL_LEFT ||
928 event->direction == GDK_SCROLL_UP) {
929 if (index != 0)
930 chrome::SelectPreviousTab(browser);
931 } else if (index + 1 < browser->tab_strip_model()->count()) {
932 chrome::SelectNextTab(browser);
933 }
934 return TRUE;
935 }
936
937 void BrowserTitlebar::OnButtonClicked(GtkWidget* button) {
938 if (close_button_.get() && close_button_->widget() == button) {
939 browser_window_->Close();
940 } else if (restore_button_.get() && restore_button_->widget() == button) {
941 browser_window_->UnMaximize();
942 } else if (maximize_button_.get() && maximize_button_->widget() == button) {
943 MaximizeButtonClicked();
944 } else if (minimize_button_.get() && minimize_button_->widget() == button) {
945 gtk_window_iconify(window_);
946 }
947 }
948
949 gboolean BrowserTitlebar::OnFaviconMenuButtonPressed(GtkWidget* widget,
950 GdkEventButton* event) {
951 if (event->button != 1)
952 return FALSE;
953
954 if (!favicon_menu_model_.get()) {
955 favicon_menu_model_.reset(
956 new PopupPageMenuModel(this, browser_window_->browser()));
957
958 favicon_menu_.reset(new MenuGtk(NULL, favicon_menu_model_.get()));
959 }
960
961 favicon_menu_->PopupForWidget(app_mode_favicon_, event->button, event->time);
962
963 return TRUE;
964 }
965
966 gboolean BrowserTitlebar::OnAvatarLabelButtonPressed(GtkWidget* widget,
967 GdkEventButton* event) {
968 if (event->button != 1)
969 return FALSE;
970
971 // Show the avatar menu bubble with the upward arrow at the x position where
972 // the user has clicked.
973 gfx::Rect rect = gtk_util::WidgetBounds(widget);
974 rect.set_x(event->x);
975 rect.set_width(0);
976 new AvatarMenuBubbleGtk(
977 browser_window_->browser(), widget, BubbleGtk::ANCHOR_TOP_RIGHT, &rect);
978 return TRUE;
979 }
980
981 void BrowserTitlebar::ShowContextMenu(GdkEventButton* event) {
982 if (!context_menu_.get()) {
983 context_menu_model_.reset(new ContextMenuModel(this));
984 context_menu_.reset(new MenuGtk(NULL, context_menu_model_.get()));
985 }
986
987 context_menu_->PopupAsContext(gfx::Point(event->x_root, event->y_root),
988 event->time);
989 }
990
991 bool BrowserTitlebar::IsCommandIdEnabled(int command_id) const {
992 if (command_id == kShowWindowDecorationsCommand)
993 return true;
994
995 return chrome::IsCommandEnabled(browser_window_->browser(), command_id);
996 }
997
998 bool BrowserTitlebar::IsCommandIdChecked(int command_id) const {
999 if (command_id == kShowWindowDecorationsCommand) {
1000 PrefService* prefs = browser_window_->browser()->profile()->GetPrefs();
1001 return !prefs->GetBoolean(prefs::kUseCustomChromeFrame);
1002 }
1003
1004 EncodingMenuController controller;
1005 if (controller.DoesCommandBelongToEncodingMenu(command_id)) {
1006 WebContents* web_contents =
1007 browser_window_->browser()->tab_strip_model()->GetActiveWebContents();
1008 if (web_contents) {
1009 return controller.IsItemChecked(browser_window_->browser()->profile(),
1010 web_contents->GetEncoding(),
1011 command_id);
1012 }
1013 return false;
1014 }
1015
1016 NOTREACHED();
1017 return false;
1018 }
1019
1020 void BrowserTitlebar::ExecuteCommand(int command_id, int event_flags) {
1021 if (command_id == kShowWindowDecorationsCommand) {
1022 PrefService* prefs = browser_window_->browser()->profile()->GetPrefs();
1023 prefs->SetBoolean(prefs::kUseCustomChromeFrame,
1024 !prefs->GetBoolean(prefs::kUseCustomChromeFrame));
1025 return;
1026 }
1027
1028 chrome::ExecuteCommand(browser_window_->browser(), command_id);
1029 }
1030
1031 bool BrowserTitlebar::GetAcceleratorForCommandId(
1032 int command_id,
1033 ui::Accelerator* out_accelerator) {
1034 const ui::Accelerator* accelerator =
1035 AcceleratorsGtk::GetInstance()->GetPrimaryAcceleratorForCommand(
1036 command_id);
1037 if (!accelerator)
1038 return false;
1039 *out_accelerator = *accelerator;
1040 return true;
1041 }
1042
1043 void BrowserTitlebar::Observe(int type,
1044 const content::NotificationSource& source,
1045 const content::NotificationDetails& details) {
1046 switch (type) {
1047 case chrome::NOTIFICATION_BROWSER_THEME_CHANGED: {
1048 UpdateTextColor();
1049 UpdateAvatarLabel();
1050
1051 if (minimize_button_.get())
1052 UpdateButtonBackground(minimize_button_.get());
1053 if (maximize_button_.get())
1054 UpdateButtonBackground(maximize_button_.get());
1055 if (restore_button_.get())
1056 UpdateButtonBackground(restore_button_.get());
1057 if (close_button_.get())
1058 UpdateButtonBackground(close_button_.get());
1059 break;
1060 }
1061
1062 case chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED:
1063 if (!IsOffTheRecord())
1064 UpdateAvatar();
1065 break;
1066
1067 default:
1068 NOTREACHED();
1069 }
1070 }
1071
1072 void BrowserTitlebar::ActiveWindowChanged(GdkWindow* active_window) {
1073 // Can be called during shutdown; BrowserWindowGtk will set our |window_|
1074 // to NULL during that time.
1075 if (!window_)
1076 return;
1077
1078 window_has_focus_ =
1079 gtk_widget_get_window(GTK_WIDGET(window_)) == active_window;
1080 UpdateTextColor();
1081 }
1082
1083 bool BrowserTitlebar::ShouldDisplayAvatar() {
1084 if (IsOffTheRecord())
1085 return true;
1086
1087 if (!browser_window_->browser()->is_type_tabbed())
1088 return false;
1089
1090 return AvatarMenu::ShouldShowAvatarMenu();
1091 }
1092
1093 bool BrowserTitlebar::IsOffTheRecord() {
1094 return browser_window_->browser()->profile()->IsOffTheRecord();
1095 }
1096
1097 BrowserTitlebar::ContextMenuModel::ContextMenuModel(
1098 ui::SimpleMenuModel::Delegate* delegate)
1099 : SimpleMenuModel(delegate) {
1100 AddItemWithStringId(IDC_NEW_TAB, IDS_TAB_CXMENU_NEWTAB);
1101 AddItemWithStringId(IDC_RESTORE_TAB, IDS_RESTORE_TAB);
1102 AddSeparator(ui::NORMAL_SEPARATOR);
1103 AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER);
1104 AddSeparator(ui::NORMAL_SEPARATOR);
1105 AddCheckItemWithStringId(kShowWindowDecorationsCommand,
1106 IDS_SHOW_WINDOW_DECORATIONS_MENU);
1107 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698