Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / gtk / browser_titlebar.cc
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 }