| OLD | NEW |
| (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/avatar_menu_bubble_gtk.h" | |
| 6 | |
| 7 #include "base/i18n/rtl.h" | |
| 8 #include "base/strings/utf_string_conversions.h" | |
| 9 #include "chrome/browser/browser_process.h" | |
| 10 #include "chrome/browser/chrome_notification_types.h" | |
| 11 #include "chrome/browser/profiles/avatar_menu.h" | |
| 12 #include "chrome/browser/profiles/profile_info_cache.h" | |
| 13 #include "chrome/browser/profiles/profile_manager.h" | |
| 14 #include "chrome/browser/ui/browser.h" | |
| 15 #include "chrome/browser/ui/gtk/avatar_menu_item_gtk.h" | |
| 16 #include "chrome/browser/ui/gtk/browser_toolbar_gtk.h" | |
| 17 #include "chrome/browser/ui/gtk/browser_window_gtk.h" | |
| 18 #include "chrome/browser/ui/gtk/event_utils.h" | |
| 19 #include "chrome/browser/ui/gtk/gtk_chrome_link_button.h" | |
| 20 #include "chrome/browser/ui/gtk/gtk_theme_service.h" | |
| 21 #include "chrome/browser/ui/gtk/location_bar_view_gtk.h" | |
| 22 #include "content/public/browser/notification_source.h" | |
| 23 #include "grit/generated_resources.h" | |
| 24 #include "ui/base/gtk/gtk_hig_constants.h" | |
| 25 #include "ui/base/l10n/l10n_util.h" | |
| 26 | |
| 27 namespace { | |
| 28 | |
| 29 // The minimum width in pixels of the bubble. | |
| 30 const int kBubbleMinWidth = 175; | |
| 31 | |
| 32 // The number of pixels of padding on the left of the 'New Profile' link at the | |
| 33 // bottom of the bubble. | |
| 34 const int kNewProfileLinkLeftPadding = 40; | |
| 35 | |
| 36 } // namespace | |
| 37 | |
| 38 AvatarMenuBubbleGtk::AvatarMenuBubbleGtk(Browser* browser, | |
| 39 GtkWidget* anchor, | |
| 40 BubbleGtk::FrameStyle arrow, | |
| 41 const gfx::Rect* rect) | |
| 42 : contents_(NULL), | |
| 43 inner_contents_(NULL), | |
| 44 theme_service_(GtkThemeService::GetFrom(browser->profile())), | |
| 45 new_profile_link_(NULL), | |
| 46 minimum_width_(kBubbleMinWidth), | |
| 47 switching_(false) { | |
| 48 avatar_menu_.reset(new AvatarMenu( | |
| 49 &g_browser_process->profile_manager()->GetProfileInfoCache(), | |
| 50 this, browser)); | |
| 51 avatar_menu_->RebuildMenu(); | |
| 52 | |
| 53 OnAvatarMenuChanged(avatar_menu_.get()); | |
| 54 | |
| 55 bubble_ = BubbleGtk::Show(anchor, | |
| 56 rect, | |
| 57 contents_, | |
| 58 arrow, | |
| 59 BubbleGtk::MATCH_SYSTEM_THEME | | |
| 60 BubbleGtk::POPUP_WINDOW | | |
| 61 BubbleGtk::GRAB_INPUT, | |
| 62 theme_service_, | |
| 63 this); // |delegate| | |
| 64 g_signal_connect(contents_, "destroy", | |
| 65 G_CALLBACK(&OnDestroyThunk), this); | |
| 66 } | |
| 67 | |
| 68 AvatarMenuBubbleGtk::~AvatarMenuBubbleGtk() {} | |
| 69 | |
| 70 void AvatarMenuBubbleGtk::OnDestroy(GtkWidget* widget) { | |
| 71 // We are self deleting, we have a destroy signal setup to catch when we | |
| 72 // destroyed (via the BubbleGtk being destroyed), and delete ourself. | |
| 73 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); | |
| 74 } | |
| 75 | |
| 76 void AvatarMenuBubbleGtk::BubbleClosing(BubbleGtk* bubble, | |
| 77 bool closed_by_escape) { | |
| 78 bubble_ = NULL; | |
| 79 } | |
| 80 | |
| 81 void AvatarMenuBubbleGtk::OnAvatarMenuChanged( | |
| 82 AvatarMenu* avatar_menu) { | |
| 83 items_.clear(); | |
| 84 minimum_width_ = kBubbleMinWidth; | |
| 85 | |
| 86 InitContents(); | |
| 87 } | |
| 88 | |
| 89 void AvatarMenuBubbleGtk::OpenProfile(size_t profile_index) { | |
| 90 if (!bubble_) | |
| 91 return; | |
| 92 GdkModifierType modifier_state; | |
| 93 gtk_get_current_event_state(&modifier_state); | |
| 94 guint modifier_state_uint = modifier_state; | |
| 95 avatar_menu_->SwitchToProfile(profile_index, | |
| 96 event_utils::DispositionFromGdkState(modifier_state_uint) == NEW_WINDOW, | |
| 97 ProfileMetrics::SWITCH_PROFILE_ICON); | |
| 98 CloseBubble(); | |
| 99 } | |
| 100 | |
| 101 void AvatarMenuBubbleGtk::EditProfile(size_t profile_index) { | |
| 102 if (!bubble_) | |
| 103 return; | |
| 104 avatar_menu_->EditProfile(profile_index); | |
| 105 CloseBubble(); | |
| 106 } | |
| 107 | |
| 108 void AvatarMenuBubbleGtk::OnSizeRequest(GtkWidget* widget, | |
| 109 GtkRequisition* req) { | |
| 110 // Always use the maximum width ever requested. | |
| 111 if (req->width < minimum_width_) | |
| 112 req->width = minimum_width_; | |
| 113 else | |
| 114 minimum_width_ = req->width; | |
| 115 } | |
| 116 | |
| 117 void AvatarMenuBubbleGtk::OnNewProfileLinkClicked(GtkWidget* link) { | |
| 118 if (!bubble_) | |
| 119 return; | |
| 120 avatar_menu_->AddNewProfile(ProfileMetrics::ADD_NEW_USER_ICON); | |
| 121 CloseBubble(); | |
| 122 } | |
| 123 | |
| 124 void AvatarMenuBubbleGtk::OnSwitchProfileLinkClicked(GtkWidget* link) { | |
| 125 switching_ = true; | |
| 126 OnAvatarMenuChanged(avatar_menu_.get()); | |
| 127 } | |
| 128 | |
| 129 void AvatarMenuBubbleGtk::InitMenuContents() { | |
| 130 size_t profile_count = avatar_menu_->GetNumberOfItems(); | |
| 131 GtkWidget* items_vbox = gtk_vbox_new(FALSE, ui::kContentAreaSpacing); | |
| 132 for (size_t i = 0; i < profile_count; ++i) { | |
| 133 AvatarMenu::Item menu_item = avatar_menu_->GetItemAt(i); | |
| 134 AvatarMenuItemGtk* item = new AvatarMenuItemGtk( | |
| 135 this, menu_item, i, theme_service_); | |
| 136 items_.push_back(item); | |
| 137 | |
| 138 gtk_box_pack_start(GTK_BOX(items_vbox), item->widget(), TRUE, TRUE, 0); | |
| 139 gtk_widget_set_can_focus(item->widget(), TRUE); | |
| 140 if (menu_item.active) | |
| 141 gtk_container_set_focus_child(GTK_CONTAINER(items_vbox), item->widget()); | |
| 142 } | |
| 143 gtk_box_pack_start(GTK_BOX(inner_contents_), items_vbox, TRUE, TRUE, 0); | |
| 144 | |
| 145 if (avatar_menu_->ShouldShowAddNewProfileLink()) { | |
| 146 gtk_box_pack_start(GTK_BOX(inner_contents_), | |
| 147 gtk_hseparator_new(), TRUE, TRUE, 0); | |
| 148 | |
| 149 // The new profile link. | |
| 150 new_profile_link_ = theme_service_->BuildChromeLinkButton( | |
| 151 l10n_util::GetStringUTF8(IDS_PROFILES_CREATE_NEW_PROFILE_LINK)); | |
| 152 g_signal_connect(new_profile_link_, "clicked", | |
| 153 G_CALLBACK(OnNewProfileLinkClickedThunk), this); | |
| 154 | |
| 155 GtkWidget* link_align = gtk_alignment_new(0, 0, 0, 0); | |
| 156 gtk_alignment_set_padding(GTK_ALIGNMENT(link_align), | |
| 157 0, 0, kNewProfileLinkLeftPadding, 0); | |
| 158 gtk_container_add(GTK_CONTAINER(link_align), new_profile_link_); | |
| 159 | |
| 160 gtk_box_pack_start(GTK_BOX(inner_contents_), link_align, FALSE, FALSE, 0); | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 void AvatarMenuBubbleGtk::InitManagedUserContents() { | |
| 165 int active_index = avatar_menu_->GetActiveProfileIndex(); | |
| 166 AvatarMenu::Item menu_item = | |
| 167 avatar_menu_->GetItemAt(active_index); | |
| 168 AvatarMenuItemGtk* item = new AvatarMenuItemGtk( | |
| 169 this, menu_item, active_index, theme_service_); | |
| 170 items_.push_back(item); | |
| 171 | |
| 172 gtk_box_pack_start(GTK_BOX(inner_contents_), item->widget(), TRUE, TRUE, 0); | |
| 173 gtk_box_pack_start(GTK_BOX(inner_contents_), | |
| 174 gtk_hseparator_new(), TRUE, TRUE, 0); | |
| 175 | |
| 176 // Add information about managed users within a hbox. | |
| 177 GtkWidget* managed_user_info = gtk_hbox_new(FALSE, 5); | |
| 178 GdkPixbuf* limited_user_pixbuf = | |
| 179 avatar_menu_->GetManagedUserIcon().ToGdkPixbuf(); | |
| 180 GtkWidget* limited_user_img = gtk_image_new_from_pixbuf(limited_user_pixbuf); | |
| 181 GtkWidget* icon_align = gtk_alignment_new(0, 0, 0, 0); | |
| 182 gtk_container_add(GTK_CONTAINER(icon_align), limited_user_img); | |
| 183 gtk_box_pack_start(GTK_BOX(managed_user_info), icon_align, FALSE, FALSE, 0); | |
| 184 GtkWidget* status_label = | |
| 185 theme_service_->BuildLabel(std::string(), ui::kGdkBlack); | |
| 186 char* markup = g_markup_printf_escaped( | |
| 187 "<span size='small'>%s</span>", | |
| 188 base::UTF16ToUTF8(avatar_menu_->GetManagedUserInformation()).c_str()); | |
| 189 const int kLabelWidth = 150; | |
| 190 gtk_widget_set_size_request(status_label, kLabelWidth, -1); | |
| 191 gtk_label_set_markup(GTK_LABEL(status_label), markup); | |
| 192 gtk_label_set_line_wrap(GTK_LABEL(status_label), TRUE); | |
| 193 gtk_misc_set_alignment(GTK_MISC(status_label), 0, 0); | |
| 194 g_free(markup); | |
| 195 gtk_box_pack_start(GTK_BOX(managed_user_info), status_label, FALSE, FALSE, 0); | |
| 196 gtk_box_pack_start( | |
| 197 GTK_BOX(inner_contents_), managed_user_info, FALSE, FALSE, 0); | |
| 198 | |
| 199 gtk_box_pack_start( | |
| 200 GTK_BOX(inner_contents_), gtk_hseparator_new(), TRUE, TRUE, 0); | |
| 201 | |
| 202 // The switch profile link. | |
| 203 GtkWidget* switch_profile_link = theme_service_->BuildChromeLinkButton( | |
| 204 l10n_util::GetStringUTF8(IDS_PROFILES_SWITCH_PROFILE_LINK)); | |
| 205 g_signal_connect(switch_profile_link, "clicked", | |
| 206 G_CALLBACK(OnSwitchProfileLinkClickedThunk), this); | |
| 207 | |
| 208 GtkWidget* link_align = gtk_alignment_new(0.5, 0, 0, 0); | |
| 209 gtk_container_add(GTK_CONTAINER(link_align), switch_profile_link); | |
| 210 | |
| 211 gtk_box_pack_start(GTK_BOX(inner_contents_), link_align, FALSE, FALSE, 0); | |
| 212 } | |
| 213 | |
| 214 void AvatarMenuBubbleGtk::InitContents() { | |
| 215 // Destroy the old inner contents to allow replacing it. | |
| 216 if (inner_contents_) | |
| 217 gtk_widget_destroy(inner_contents_); | |
| 218 inner_contents_ = gtk_vbox_new(FALSE, ui::kControlSpacing); | |
| 219 if (!contents_) | |
| 220 contents_ = gtk_vbox_new(FALSE, 0); | |
| 221 gtk_container_set_border_width(GTK_CONTAINER(inner_contents_), | |
| 222 ui::kContentAreaBorder); | |
| 223 g_signal_connect(inner_contents_, "size-request", | |
| 224 G_CALLBACK(OnSizeRequestThunk), this); | |
| 225 | |
| 226 if (avatar_menu_->GetManagedUserInformation().empty() || switching_) | |
| 227 InitMenuContents(); | |
| 228 else | |
| 229 InitManagedUserContents(); | |
| 230 gtk_box_pack_start(GTK_BOX(contents_), inner_contents_, TRUE, TRUE, 0); | |
| 231 if (bubble_) | |
| 232 gtk_widget_show_all(contents_); | |
| 233 } | |
| 234 | |
| 235 void AvatarMenuBubbleGtk::CloseBubble() { | |
| 236 if (bubble_) { | |
| 237 bubble_->Close(); | |
| 238 bubble_ = NULL; | |
| 239 } | |
| 240 } | |
| OLD | NEW |