This source file includes following definitions.
- weak_factory_
- GetNavigator
- DoAddDownload
- IsShowing
- IsClosing
- DoShow
- DoClose
- browser
- Closed
- Observe
- GetHeight
- RemoveDownloadItem
- GetHBox
- MaybeShowMoreDownloadItems
- OnButtonClick
- AutoCloseIfPossible
- CancelAutoClose
- ItemOpened
- SetCloseOnMouseOut
- WillProcessEvent
- DidProcessEvent
- IsCursorInShelfZone
- MouseLeftShelf
- MouseEnteredShelf
#include "chrome/browser/ui/gtk/download/download_shelf_gtk.h"
#include <string>
#include "base/bind.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/download/download_item_model.h"
#include "chrome/browser/download/download_stats.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/chrome_pages.h"
#include "chrome/browser/ui/gtk/browser_window_gtk.h"
#include "chrome/browser/ui/gtk/custom_button.h"
#include "chrome/browser/ui/gtk/download/download_item_gtk.h"
#include "chrome/browser/ui/gtk/gtk_chrome_link_button.h"
#include "chrome/browser/ui/gtk/gtk_chrome_shrinkable_hbox.h"
#include "chrome/browser/ui/gtk/gtk_theme_service.h"
#include "chrome/browser/ui/gtk/gtk_util.h"
#include "content/public/browser/download_item.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/page_navigator.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "grit/ui_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/gtk/gtk_screen_util.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/gtk_util.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/insets.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
namespace {
const int kDownloadItemHeight = DownloadShelf::kSmallProgressIconSize;
const int kDownloadItemPadding = 10;
const int kTopBottomPadding = 4;
const int kLeftPadding = 2;
const int kRightPadding = 10;
const int kShelfAnimationDurationMs = 120;
const int kAutoCloseDelayMs = 300;
const int kShelfAuraSize = 40;
}
using content::DownloadItem;
DownloadShelfGtk::DownloadShelfGtk(Browser* browser, GtkWidget* parent)
: browser_(browser),
is_showing_(false),
theme_service_(GtkThemeService::GetFrom(browser->profile())),
close_on_mouse_out_(false),
mouse_in_shelf_(false),
weak_factory_(this) {
top_border_ = gtk_event_box_new();
gtk_widget_set_size_request(GTK_WIDGET(top_border_), 0, 1);
items_hbox_.Own(gtk_chrome_shrinkable_hbox_new(
TRUE, FALSE, kDownloadItemPadding));
gtk_widget_set_size_request(items_hbox_.get(), 0, kDownloadItemHeight);
GtkWidget* outer_hbox = gtk_hbox_new(FALSE, kDownloadItemPadding);
gtk_box_pack_start(GTK_BOX(outer_hbox), items_hbox_.get(), TRUE, TRUE, 0);
GtkWidget* padding = gtk_alignment_new(0, 0, 1, 1);
gtk_alignment_set_padding(GTK_ALIGNMENT(padding),
kTopBottomPadding - 1, kTopBottomPadding, kLeftPadding, kRightPadding);
padding_bg_ = gtk_event_box_new();
gtk_container_add(GTK_CONTAINER(padding_bg_), padding);
gtk_container_add(GTK_CONTAINER(padding), outer_hbox);
GtkWidget* vbox = gtk_vbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), top_border_, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), padding_bg_, FALSE, FALSE, 0);
shelf_.Own(gtk_event_box_new());
gtk_container_add(GTK_CONTAINER(shelf_.get()), vbox);
close_button_.reset(CustomDrawButton::CloseButtonBar(theme_service_));
gtk_util::CenterWidgetInHBox(outer_hbox, close_button_->widget(), true, 0);
g_signal_connect(close_button_->widget(), "clicked",
G_CALLBACK(OnButtonClickThunk), this);
link_button_ = theme_service_->BuildChromeLinkButton(
l10n_util::GetStringUTF8(IDS_SHOW_ALL_DOWNLOADS));
g_signal_connect(link_button_, "clicked",
G_CALLBACK(OnButtonClickThunk), this);
gtk_util::SetButtonTriggersNavigation(link_button_);
gtk_util::ForceFontSizePixels(GTK_CHROME_LINK_BUTTON(link_button_)->label,
13.4);
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
GtkWidget* download_image = gtk_image_new_from_pixbuf(
rb.GetNativeImageNamed(IDR_DOWNLOADS_FAVICON).ToGdkPixbuf());
gtk_util::CenterWidgetInHBox(outer_hbox, link_button_, true, 0);
gtk_util::CenterWidgetInHBox(outer_hbox, download_image, true, 0);
slide_widget_.reset(new SlideAnimatorGtk(shelf_.get(),
SlideAnimatorGtk::UP,
kShelfAnimationDurationMs,
false, true, this));
theme_service_->InitThemesFor(this);
registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
content::Source<ThemeService>(theme_service_));
gtk_widget_show_all(shelf_.get());
gtk_box_pack_end(GTK_BOX(parent), slide_widget_->widget(),
FALSE, FALSE, 0);
gtk_box_reorder_child(GTK_BOX(parent), slide_widget_->widget(), 0);
}
DownloadShelfGtk::~DownloadShelfGtk() {
for (std::vector<DownloadItemGtk*>::iterator iter = download_items_.begin();
iter != download_items_.end(); ++iter) {
delete *iter;
}
shelf_.Destroy();
items_hbox_.Destroy();
SetCloseOnMouseOut(false);
}
content::PageNavigator* DownloadShelfGtk::GetNavigator() {
return browser_;
}
void DownloadShelfGtk::DoAddDownload(DownloadItem* download) {
download_items_.push_back(new DownloadItemGtk(this, download));
}
bool DownloadShelfGtk::IsShowing() const {
return slide_widget_->IsShowing();
}
bool DownloadShelfGtk::IsClosing() const {
return slide_widget_->IsClosing();
}
void DownloadShelfGtk::DoShow() {
slide_widget_->Open();
browser_->UpdateDownloadShelfVisibility(true);
CancelAutoClose();
}
void DownloadShelfGtk::DoClose(CloseReason reason) {
gdk_window_raise(gtk_widget_get_window(shelf_.get()));
slide_widget_->Close();
browser_->UpdateDownloadShelfVisibility(false);
int num_in_progress = 0;
for (size_t i = 0; i < download_items_.size(); ++i) {
if (download_items_[i]->download()->GetState() == DownloadItem::IN_PROGRESS)
++num_in_progress;
}
RecordDownloadShelfClose(
download_items_.size(), num_in_progress, reason == AUTOMATIC);
SetCloseOnMouseOut(false);
}
Browser* DownloadShelfGtk::browser() const {
return browser_;
}
void DownloadShelfGtk::Closed() {
if (is_hidden())
return;
size_t i = 0;
while (i < download_items_.size()) {
DownloadItem* download = download_items_[i]->download();
DownloadItem::DownloadState state = download->GetState();
bool is_transfer_done = state == DownloadItem::COMPLETE ||
state == DownloadItem::CANCELLED ||
state == DownloadItem::INTERRUPTED;
if (is_transfer_done && !download->IsDangerous()) {
RemoveDownloadItem(download_items_[i]);
} else {
download->SetOpened(true);
++i;
}
}
}
void DownloadShelfGtk::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
if (type == chrome::NOTIFICATION_BROWSER_THEME_CHANGED) {
GdkColor color = theme_service_->GetGdkColor(
ThemeProperties::COLOR_TOOLBAR);
gtk_widget_modify_bg(padding_bg_, GTK_STATE_NORMAL, &color);
color = theme_service_->GetBorderColor();
gtk_widget_modify_bg(top_border_, GTK_STATE_NORMAL, &color);
bool use_default_color = theme_service_->GetColor(
ThemeProperties::COLOR_BOOKMARK_TEXT) ==
ThemeProperties::GetDefaultColor(
ThemeProperties::COLOR_BOOKMARK_TEXT);
GdkColor bookmark_color = theme_service_->GetGdkColor(
ThemeProperties::COLOR_BOOKMARK_TEXT);
gtk_chrome_link_button_set_normal_color(
GTK_CHROME_LINK_BUTTON(link_button_),
use_default_color ? NULL : &bookmark_color);
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
close_button_->SetBackground(
theme_service_->GetColor(ThemeProperties::COLOR_TAB_TEXT),
rb.GetImageNamed(IDR_CLOSE_1).AsBitmap(),
rb.GetImageNamed(IDR_CLOSE_1_MASK).AsBitmap());
}
}
int DownloadShelfGtk::GetHeight() const {
GtkAllocation allocation;
gtk_widget_get_allocation(slide_widget_->widget(), &allocation);
return allocation.height;
}
void DownloadShelfGtk::RemoveDownloadItem(DownloadItemGtk* download_item) {
DCHECK(download_item);
std::vector<DownloadItemGtk*>::iterator i =
find(download_items_.begin(), download_items_.end(), download_item);
DCHECK(i != download_items_.end());
download_items_.erase(i);
delete download_item;
if (download_items_.empty()) {
slide_widget_->CloseWithoutAnimation();
browser_->UpdateDownloadShelfVisibility(false);
} else {
AutoCloseIfPossible();
}
}
GtkWidget* DownloadShelfGtk::GetHBox() const {
return items_hbox_.get();
}
void DownloadShelfGtk::MaybeShowMoreDownloadItems() {
gtk_widget_show_all(items_hbox_.get());
}
void DownloadShelfGtk::OnButtonClick(GtkWidget* button) {
if (button == close_button_->widget()) {
Close(USER_ACTION);
} else {
chrome::ShowDownloads(browser_);
}
}
void DownloadShelfGtk::AutoCloseIfPossible() {
for (std::vector<DownloadItemGtk*>::iterator iter = download_items_.begin();
iter != download_items_.end(); ++iter) {
if (!(*iter)->download()->GetOpened())
return;
}
SetCloseOnMouseOut(true);
}
void DownloadShelfGtk::CancelAutoClose() {
SetCloseOnMouseOut(false);
weak_factory_.InvalidateWeakPtrs();
}
void DownloadShelfGtk::ItemOpened() {
AutoCloseIfPossible();
}
void DownloadShelfGtk::SetCloseOnMouseOut(bool close) {
if (close_on_mouse_out_ == close)
return;
close_on_mouse_out_ = close;
mouse_in_shelf_ = close;
if (close)
base::MessageLoopForUI::current()->AddObserver(this);
else
base::MessageLoopForUI::current()->RemoveObserver(this);
}
void DownloadShelfGtk::WillProcessEvent(GdkEvent* event) {
}
void DownloadShelfGtk::DidProcessEvent(GdkEvent* event) {
gfx::Point cursor_screen_coords;
switch (event->type) {
case GDK_MOTION_NOTIFY:
cursor_screen_coords =
gfx::Point(event->motion.x_root, event->motion.y_root);
break;
case GDK_LEAVE_NOTIFY:
cursor_screen_coords =
gfx::Point(event->crossing.x_root, event->crossing.y_root);
break;
default:
return;
}
bool mouse_in_shelf = IsCursorInShelfZone(cursor_screen_coords);
if (mouse_in_shelf == mouse_in_shelf_)
return;
mouse_in_shelf_ = mouse_in_shelf;
if (mouse_in_shelf)
MouseEnteredShelf();
else
MouseLeftShelf();
}
bool DownloadShelfGtk::IsCursorInShelfZone(
const gfx::Point& cursor_screen_coords) {
bool realized = (shelf_.get() &&
gtk_widget_get_window(shelf_.get()));
if (!realized)
return false;
gfx::Rect bounds = ui::GetWidgetScreenBounds(shelf_.get());
bounds.Inset(gfx::Insets(-kShelfAuraSize, 0, 0, 0));
return bounds.Contains(cursor_screen_coords);
}
void DownloadShelfGtk::MouseLeftShelf() {
DCHECK(close_on_mouse_out_);
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(
&DownloadShelfGtk::Close, weak_factory_.GetWeakPtr(), AUTOMATIC),
base::TimeDelta::FromMilliseconds(kAutoCloseDelayMs));
}
void DownloadShelfGtk::MouseEnteredShelf() {
weak_factory_.InvalidateWeakPtrs();
}