GTK: Fix profile selection bubble to match the chrome-theme when selected.

BUG=none
TEST=none


Review URL: http://codereview.chromium.org/8402005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@107495 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.cc b/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.cc
index 732d983..c92a7902 100644
--- a/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.cc
+++ b/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.cc
@@ -16,6 +16,8 @@
 #include "chrome/browser/ui/gtk/gtk_chrome_link_button.h"
 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
 #include "chrome/browser/ui/gtk/location_bar_view_gtk.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "content/public/browser/notification_source.h"
 #include "grit/generated_resources.h"
 #include "ui/base/gtk/gtk_hig_constants.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -37,6 +39,7 @@
                                          const gfx::Rect* rect)
     : contents_(NULL),
       theme_service_(GtkThemeService::GetFrom(browser->profile())),
+      new_profile_link_(NULL),
       minimum_width_(kBubbleMinWidth) {
   avatar_menu_model_.reset(new AvatarMenuModel(
       &g_browser_process->profile_manager()->GetProfileInfoCache(),
@@ -56,6 +59,10 @@
                             this);  // |delegate|
   g_signal_connect(contents_, "destroy",
                    G_CALLBACK(&OnDestroyThunk), this);
+
+  registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
+                 content::Source<ThemeService>(theme_service_));
+  theme_service_->InitThemesFor(this);
 }
 
 AvatarMenuBubbleGtk::~AvatarMenuBubbleGtk() {
@@ -91,6 +98,15 @@
   bubble_->Close();
 }
 
+void AvatarMenuBubbleGtk::Observe(int type,
+                                  const content::NotificationSource& source,
+                                  const content::NotificationDetails& details) {
+  DCHECK_EQ(type, chrome::NOTIFICATION_BROWSER_THEME_CHANGED);
+  gtk_chrome_link_button_set_use_gtk_theme(
+      GTK_CHROME_LINK_BUTTON(new_profile_link_),
+      theme_service_->UsingNativeTheme());
+}
+
 void AvatarMenuBubbleGtk::OnSizeRequest(GtkWidget* widget,
                                         GtkRequisition* req) {
   // Always use the maximum width ever requested.
@@ -129,15 +145,15 @@
   gtk_box_pack_start(GTK_BOX(contents_), gtk_hseparator_new(), TRUE, TRUE, 0);
 
   // The new profile link.
-  GtkWidget* new_profile_link = gtk_chrome_link_button_new(
+  new_profile_link_ = gtk_chrome_link_button_new(
       l10n_util::GetStringUTF8(IDS_PROFILES_CREATE_NEW_PROFILE_LINK).c_str());
-  g_signal_connect(new_profile_link, "clicked",
+  g_signal_connect(new_profile_link_, "clicked",
                    G_CALLBACK(OnNewProfileLinkClickedThunk), this);
 
   GtkWidget* link_align = gtk_alignment_new(0, 0, 0, 0);
   gtk_alignment_set_padding(GTK_ALIGNMENT(link_align),
                             0, 0, kNewProfileLinkLeftPadding, 0);
-  gtk_container_add(GTK_CONTAINER(link_align), new_profile_link);
+  gtk_container_add(GTK_CONTAINER(link_align), new_profile_link_);
 
   gtk_box_pack_start(GTK_BOX(contents_), link_align, FALSE, FALSE, 0);
 }
diff --git a/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.h b/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.h
index a31addc..22e59823 100644
--- a/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.h
+++ b/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.h
@@ -16,6 +16,8 @@
 #include "chrome/browser/profiles/avatar_menu_model_observer.h"
 #include "chrome/browser/ui/gtk/avatar_menu_item_gtk.h"
 #include "chrome/browser/ui/gtk/bubble/bubble_gtk.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
 #include "ui/base/gtk/gtk_signal.h"
 
 class AvatarMenuModel;
@@ -26,7 +28,8 @@
 // It displays a list of profiles and allows users to switch between profiles.
 class AvatarMenuBubbleGtk : public BubbleDelegateGtk,
                             public AvatarMenuModelObserver,
-                            public AvatarMenuItemGtk::Delegate {
+                            public AvatarMenuItemGtk::Delegate,
+                            public content::NotificationObserver {
  public:
   AvatarMenuBubbleGtk(Browser* browser,
                       GtkWidget* anchor,
@@ -43,9 +46,13 @@
       AvatarMenuModel* avatar_menu_model) OVERRIDE;
 
   // AvatarMenuItemGtk::Delegate implementation.
-  virtual void OpenProfile(size_t profile_index);
+  virtual void OpenProfile(size_t profile_index) OVERRIDE;
+  virtual void EditProfile(size_t profile_index) OVERRIDE;
 
-  virtual void EditProfile(size_t profile_index);
+  // content::NotificationObserver implementation.
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
 
  private:
   // Notified when |contents_| is destroyed so we can delete our instance.
@@ -69,6 +76,10 @@
   // A weak pointer to the theme service.
   GtkThemeService* theme_service_;
 
+  // A weak pointer to the new proifle link to keep its theme information
+  // updated.
+  GtkWidget* new_profile_link_;
+
   // A vector of all profile items in the menu.
   std::vector<AvatarMenuItemGtk*> items_;
 
@@ -76,6 +87,8 @@
   // from automatically reducing its size when hovering over a profile item.
   int minimum_width_;
 
+  content::NotificationRegistrar registrar_;
+
   DISALLOW_COPY_AND_ASSIGN(AvatarMenuBubbleGtk);
 };
 
diff --git a/chrome/browser/ui/gtk/avatar_menu_item_gtk.cc b/chrome/browser/ui/gtk/avatar_menu_item_gtk.cc
index b0bb3eaa..fd6ee9f 100644
--- a/chrome/browser/ui/gtk/avatar_menu_item_gtk.cc
+++ b/chrome/browser/ui/gtk/avatar_menu_item_gtk.cc
@@ -10,6 +10,8 @@
 #include "chrome/browser/ui/gtk/gtk_chrome_link_button.h"
 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
 #include "chrome/browser/ui/gtk/gtk_util.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "content/public/browser/notification_source.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
 #include "grit/theme_resources_standard.h"
@@ -32,6 +34,12 @@
 // elided.
 const int kUserNameMaxWidth = 200;
 
+// The color of the item highlight when we're in chrome-theme mode.
+const GdkColor kHighlightColor = GDK_COLOR_RGB(0xe3, 0xed, 0xf6);
+
+// The color of the background when we're in chrome-theme mode.
+const GdkColor kBackgroundColor = GDK_COLOR_RGB(0xff, 0xff, 0xff);
+
 }  // namespace
 
 AvatarMenuItemGtk::AvatarMenuItemGtk(Delegate* delegate,
@@ -41,10 +49,16 @@
     : delegate_(delegate),
       item_(item),
       item_index_(item_index),
+      theme_service_(theme_service),
       status_label_(NULL),
       link_alignment_(NULL),
+      edit_profile_link_(NULL),
       ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
-  Init(theme_service);
+  Init(theme_service_);
+
+  registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
+                 content::Source<ThemeService>(theme_service_));
+  theme_service_->InitThemesFor(this);
 }
 
 AvatarMenuItemGtk::~AvatarMenuItemGtk() {
@@ -73,9 +87,7 @@
   if (event->detail == GDK_NOTIFY_INFERIOR)
     return FALSE;
 
-  GtkStyle* style = gtk_rc_get_style(widget);
-  GdkColor highlight_color = style->bg[GTK_STATE_SELECTED];
-  gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &highlight_color);
+  gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &highlighted_color_);
   if (item_.active) {
     gtk_widget_hide(status_label_);
     gtk_widget_show(link_alignment_);
@@ -89,7 +101,7 @@
   if (event->detail == GDK_NOTIFY_INFERIOR)
     return FALSE;
 
-  gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, NULL);
+  gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, unhighlighted_color_);
   if (item_.active) {
     gtk_widget_show(status_label_);
     gtk_widget_hide(link_alignment_);
@@ -102,6 +114,32 @@
   delegate_->EditProfile(item_index_);
 }
 
+void AvatarMenuItemGtk::Observe(int type,
+                                const content::NotificationSource& source,
+                                const content::NotificationDetails& details) {
+  DCHECK_EQ(type, chrome::NOTIFICATION_BROWSER_THEME_CHANGED);
+  bool using_native = theme_service_->UsingNativeTheme();
+
+  if (using_native) {
+    GtkStyle* style = gtk_rc_get_style(widget_.get());
+    highlighted_color_ = style->bg[GTK_STATE_SELECTED];
+    unhighlighted_color_ = NULL;
+  } else {
+    highlighted_color_ = kHighlightColor;
+    unhighlighted_color_ = &kBackgroundColor;
+  }
+
+  // Assume that the widget isn't highlighted since theme changes will almost
+  // never happen while we're up.
+  gtk_widget_modify_bg(widget_.get(), GTK_STATE_NORMAL, unhighlighted_color_);
+
+  if (edit_profile_link_) {
+    gtk_chrome_link_button_set_use_gtk_theme(
+        GTK_CHROME_LINK_BUTTON(edit_profile_link_),
+        using_native);
+  }
+}
+
 void AvatarMenuItemGtk::OnEditProfileLinkClicked(GtkWidget* link) {
   // delegate_->EditProfile() will close the avatar bubble which in turn
   // try to destroy this AvatarMenuItemGtk.
@@ -182,11 +220,11 @@
 
   if (item_.active) {
     // The "edit your profile" link.
-    GtkWidget* edit_profile_link = gtk_chrome_link_button_new(
+    edit_profile_link_ = gtk_chrome_link_button_new(
         l10n_util::GetStringUTF8(IDS_PROFILES_EDIT_PROFILE_LINK).c_str());
 
     link_alignment_ = gtk_alignment_new(0, 0, 0, 0);
-    gtk_container_add(GTK_CONTAINER(link_alignment_), edit_profile_link);
+    gtk_container_add(GTK_CONTAINER(link_alignment_), edit_profile_link_);
 
     // The chrome link button contains a label that won't be shown if the button
     // is set to "no show all", so show all first.
@@ -196,7 +234,7 @@
 
     gtk_box_pack_start(GTK_BOX(item_vbox), link_alignment_, FALSE, FALSE, 0);
 
-    g_signal_connect(edit_profile_link, "clicked",
+    g_signal_connect(edit_profile_link_, "clicked",
                      G_CALLBACK(OnEditProfileLinkClickedThunk), this);
 
     GtkSizeGroup* size_group = gtk_size_group_new(GTK_SIZE_GROUP_BOTH);
diff --git a/chrome/browser/ui/gtk/avatar_menu_item_gtk.h b/chrome/browser/ui/gtk/avatar_menu_item_gtk.h
index 62ff3782..6cfef4904 100644
--- a/chrome/browser/ui/gtk/avatar_menu_item_gtk.h
+++ b/chrome/browser/ui/gtk/avatar_menu_item_gtk.h
@@ -10,6 +10,8 @@
 
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/profiles/avatar_menu_model.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
 #include "ui/base/gtk/gtk_signal.h"
 #include "ui/base/gtk/owned_widget_gtk.h"
 
@@ -19,7 +21,7 @@
 // to be displayed in the AvatarMenuBubble. Clicking the profile will open a new
 // browser window, and when the user hovers over an active profile item, a link
 // is displayed that will allow editing the profile.
-class AvatarMenuItemGtk {
+class AvatarMenuItemGtk : public content::NotificationObserver {
  public:
   // Delegates opening or editing a profile.
   class Delegate {
@@ -43,6 +45,11 @@
   // Returns the root widget for this menu item.
   GtkWidget* widget() { return widget_.get(); }
 
+  // content::NotificationObserver implementation.
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
+
  private:
   CHROMEGTK_CALLBACK_1(AvatarMenuItemGtk, gboolean, OnProfileClick,
                        GdkEventButton*);
@@ -68,6 +75,9 @@
   // The root widget for this menu item.
   ui::OwnedWidgetGtk widget_;
 
+  // Provides colors.
+  GtkThemeService* theme_service_;
+
   // A weak pointer to a label that displays the sync status. It is not shown
   // when the user is hovering over the item if the profile is the active
   // profile.
@@ -77,7 +87,23 @@
   // when the user is hovering over the active profile.
   GtkWidget* link_alignment_;
 
+  // A weak pointer to a GtkChromeLinkButton so we can keep the use_gtk_theme
+  // property up to date.
+  GtkWidget* edit_profile_link_;
+
+  // The highlighted color. Depending on the theme, this is either |widget|'s
+  // bg[GTK_STATE_SELECTED] or a static highlight.
+  GdkColor highlighted_color_;
+
+  // The unhighlighted color. Depending on the theme, this is either NULL or a
+  // pointer to static data.
+  const GdkColor* unhighlighted_color_;
+
   base::WeakPtrFactory<AvatarMenuItemGtk> weak_factory_;
+
+  content::NotificationRegistrar registrar_;
+
+  DISALLOW_COPY_AND_ASSIGN(AvatarMenuItemGtk);
 };
 
 #endif  // CHROME_BROWSER_UI_GTK_AVATAR_MENU_ITEM_GTK_H_