This source file includes following definitions.
- weak_factory_
- ChangeMode
- Observe
- StoppedShowing
- IsCommandIdChecked
- IsCommandIdEnabled
- IsCommandIdVisible
- GetAcceleratorForCommandId
- ExecuteCommand
- OnClicked
- OnExpose
- OnLeaveNotify
- OnQueryTooltip
- OnButtonPress
- OnMouseMove
- UpdateThemeButtons
- OnDoubleClickTimer
- OnStopToReloadTimer
- ShowReloadMenu
- DoReload
- ReloadMenuEnabled
- ClearCache
#include "chrome/browser/ui/gtk/reload_button_gtk.h"
#include <algorithm>
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/gtk/accelerators_gtk.h"
#include "chrome/browser/ui/gtk/event_utils.h"
#include "chrome/browser/ui/gtk/gtk_chrome_button.h"
#include "chrome/browser/ui/gtk/gtk_theme_service.h"
#include "chrome/browser/ui/gtk/gtk_util.h"
#include "chrome/browser/ui/gtk/location_bar_view_gtk.h"
#include "content/public/browser/notification_source.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "ui/base/l10n/l10n_util.h"
static int GtkButtonWidth = 0;
static const int kReloadMenuTimerDelay = 500;
static const int kReloadMenuItems[] = {
IDS_RELOAD_MENU_NORMAL_RELOAD_ITEM,
IDS_RELOAD_MENU_HARD_RELOAD_ITEM,
IDS_RELOAD_MENU_EMPTY_AND_HARD_RELOAD_ITEM,
};
ReloadButtonGtk::ReloadButtonGtk(LocationBarViewGtk* location_bar,
Browser* browser)
: location_bar_(location_bar),
browser_(browser),
intended_mode_(MODE_RELOAD),
visible_mode_(MODE_RELOAD),
theme_service_(browser ?
GtkThemeService::GetFrom(browser->profile()) : NULL),
reload_(theme_service_, IDR_RELOAD, IDR_RELOAD_P, IDR_RELOAD_H, 0),
stop_(theme_service_, IDR_STOP, IDR_STOP_P, IDR_STOP_H, IDR_STOP_D),
widget_(gtk_chrome_button_new()),
stop_to_reload_timer_delay_(base::TimeDelta::FromMilliseconds(1350)),
menu_visible_(false),
testing_mouse_hovered_(false),
testing_reload_count_(0),
weak_factory_(this) {
menu_model_.reset(new ui::SimpleMenuModel(this));
for (size_t i = 0; i < arraysize(kReloadMenuItems); i++) {
menu_model_->AddItemWithStringId(kReloadMenuItems[i], kReloadMenuItems[i]);
}
gtk_widget_set_size_request(widget(), reload_.Width(), reload_.Height());
gtk_widget_set_app_paintable(widget(), TRUE);
g_signal_connect(widget(), "clicked", G_CALLBACK(OnClickedThunk), this);
g_signal_connect(widget(), "expose-event", G_CALLBACK(OnExposeThunk), this);
g_signal_connect(widget(), "leave-notify-event",
G_CALLBACK(OnLeaveNotifyThunk), this);
gtk_widget_set_can_focus(widget(), FALSE);
gtk_widget_set_has_tooltip(widget(), TRUE);
g_signal_connect(widget(), "query-tooltip", G_CALLBACK(OnQueryTooltipThunk),
this);
g_signal_connect(widget(), "button-press-event",
G_CALLBACK(OnButtonPressThunk), this);
gtk_widget_add_events(widget(), GDK_POINTER_MOTION_MASK);
g_signal_connect(widget(), "motion-notify-event",
G_CALLBACK(OnMouseMoveThunk), this);
g_object_set_data(G_OBJECT(widget()), "left-align-popup",
reinterpret_cast<void*>(true));
hover_controller_.Init(widget());
gtk_util::SetButtonTriggersNavigation(widget());
if (theme_service_) {
theme_service_->InitThemesFor(this);
registrar_.Add(this,
chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
content::Source<ThemeService>(theme_service_));
}
int timer_delay_ms;
GtkSettings* settings = gtk_settings_get_default();
g_object_get(G_OBJECT(settings), "gtk-double-click-time", &timer_delay_ms,
NULL);
double_click_timer_delay_ = base::TimeDelta::FromMilliseconds(timer_delay_ms);
}
ReloadButtonGtk::~ReloadButtonGtk() {
widget_.Destroy();
}
void ReloadButtonGtk::ChangeMode(Mode mode, bool force) {
intended_mode_ = mode;
if (force || ((gtk_widget_get_state(widget()) == GTK_STATE_NORMAL) &&
!testing_mouse_hovered_) || ((mode == MODE_STOP) ?
!double_click_timer_.IsRunning() : (visible_mode_ != MODE_STOP))) {
double_click_timer_.Stop();
stop_to_reload_timer_.Stop();
visible_mode_ = mode;
if (!menu_visible_) {
stop_.set_paint_override(-1);
gtk_chrome_button_unset_paint_state(GTK_CHROME_BUTTON(widget_.get()));
}
UpdateThemeButtons();
gtk_widget_queue_draw(widget());
} else if (visible_mode_ != MODE_RELOAD) {
stop_.set_paint_override(GTK_STATE_INSENSITIVE);
gtk_chrome_button_set_paint_state(GTK_CHROME_BUTTON(widget_.get()),
GTK_STATE_INSENSITIVE);
UpdateThemeButtons();
if (!stop_to_reload_timer_.IsRunning()) {
stop_to_reload_timer_.Start(FROM_HERE, stop_to_reload_timer_delay_, this,
&ReloadButtonGtk::OnStopToReloadTimer);
}
}
}
void ReloadButtonGtk::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
DCHECK(chrome::NOTIFICATION_BROWSER_THEME_CHANGED == type);
GtkThemeService* provider = static_cast<GtkThemeService*>(
content::Source<ThemeService>(source).ptr());
DCHECK_EQ(provider, theme_service_);
GtkButtonWidth = 0;
UpdateThemeButtons();
}
void ReloadButtonGtk::StoppedShowing() {
menu_visible_ = false;
ChangeMode(intended_mode_, true);
}
bool ReloadButtonGtk::IsCommandIdChecked(int command_id) const {
return false;
}
bool ReloadButtonGtk::IsCommandIdEnabled(int command_id) const {
return true;
}
bool ReloadButtonGtk::IsCommandIdVisible(int command_id) const {
return true;
}
bool ReloadButtonGtk::GetAcceleratorForCommandId(
int command_id,
ui::Accelerator* out_accelerator) {
int command = 0;
switch (command_id) {
case IDS_RELOAD_MENU_NORMAL_RELOAD_ITEM:
command = IDC_RELOAD;
break;
case IDS_RELOAD_MENU_HARD_RELOAD_ITEM:
command = IDC_RELOAD_IGNORING_CACHE;
break;
case IDS_RELOAD_MENU_EMPTY_AND_HARD_RELOAD_ITEM:
break;
default:
LOG(ERROR) << "Unknown reload menu command";
}
if (command) {
const ui::Accelerator* accelerator =
AcceleratorsGtk::GetInstance()->
GetPrimaryAcceleratorForCommand(command);
if (accelerator) {
*out_accelerator = *accelerator;
return true;
}
}
return false;
}
void ReloadButtonGtk::ExecuteCommand(int command_id, int event_flags) {
switch (command_id) {
case IDS_RELOAD_MENU_NORMAL_RELOAD_ITEM:
DoReload(IDC_RELOAD);
break;
case IDS_RELOAD_MENU_HARD_RELOAD_ITEM:
DoReload(IDC_RELOAD_IGNORING_CACHE);
break;
case IDS_RELOAD_MENU_EMPTY_AND_HARD_RELOAD_ITEM:
ClearCache();
DoReload(IDC_RELOAD_IGNORING_CACHE);
break;
default:
LOG(ERROR) << "Unknown reload menu command";
}
}
void ReloadButtonGtk::OnClicked(GtkWidget* ) {
weak_factory_.InvalidateWeakPtrs();
if (visible_mode_ == MODE_STOP) {
if (stop_.paint_override() == GTK_STATE_INSENSITIVE)
return;
if (browser_)
chrome::Stop(browser_);
ChangeMode(MODE_RELOAD, true);
} else if (!double_click_timer_.IsRunning()) {
DoReload(0);
}
}
gboolean ReloadButtonGtk::OnExpose(GtkWidget* widget,
GdkEventExpose* e) {
TRACE_EVENT0("ui::gtk", "ReloadButtonGtk::OnExpose");
if (theme_service_ && theme_service_->UsingNativeTheme())
return FALSE;
return ((visible_mode_ == MODE_RELOAD) ? reload_ : stop_).OnExpose(
widget, e, hover_controller_.GetCurrentValue());
}
gboolean ReloadButtonGtk::OnLeaveNotify(GtkWidget* ,
GdkEventCrossing* ) {
ChangeMode(intended_mode_, true);
return FALSE;
}
gboolean ReloadButtonGtk::OnQueryTooltip(GtkWidget* ,
gint ,
gint ,
gboolean ,
GtkTooltip* tooltip) {
if (!location_bar_)
return FALSE;
int reload_tooltip = ReloadMenuEnabled() ?
IDS_TOOLTIP_RELOAD_WITH_MENU : IDS_TOOLTIP_RELOAD;
gtk_tooltip_set_text(tooltip, l10n_util::GetStringUTF8(
(visible_mode_ == MODE_RELOAD) ?
reload_tooltip : IDS_TOOLTIP_STOP).c_str());
return TRUE;
}
gboolean ReloadButtonGtk::OnButtonPress(GtkWidget* widget,
GdkEventButton* event) {
if (!ReloadMenuEnabled() || visible_mode_ == MODE_STOP)
return FALSE;
if (event->button == 3)
ShowReloadMenu(event->button, event->time);
if (event->button != 1)
return FALSE;
y_position_of_last_press_ = static_cast<int>(event->y);
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&ReloadButtonGtk::ShowReloadMenu,
weak_factory_.GetWeakPtr(),
event->button,
event->time),
base::TimeDelta::FromMilliseconds(kReloadMenuTimerDelay));
return FALSE;
}
gboolean ReloadButtonGtk::OnMouseMove(GtkWidget* widget,
GdkEventMotion* event) {
if (!weak_factory_.HasWeakPtrs())
return FALSE;
GtkSettings* settings = gtk_widget_get_settings(widget);
int drag_min_distance;
g_object_get(settings, "gtk-dnd-drag-threshold", &drag_min_distance, NULL);
if (event->y - y_position_of_last_press_ < drag_min_distance)
return FALSE;
weak_factory_.InvalidateWeakPtrs();
ShowReloadMenu( 1, event->time);
return FALSE;
}
void ReloadButtonGtk::UpdateThemeButtons() {
bool use_gtk = theme_service_ && theme_service_->UsingNativeTheme();
if (use_gtk) {
gtk_widget_ensure_style(widget());
GtkStyle* style = gtk_widget_get_style(widget());
GtkIconSet* icon_set = gtk_style_lookup_icon_set(
style,
(visible_mode_ == MODE_RELOAD) ? GTK_STOCK_REFRESH : GTK_STOCK_STOP);
if (icon_set) {
GtkStateType state = gtk_widget_get_state(widget());
if (visible_mode_ == MODE_STOP && stop_.paint_override() != -1)
state = static_cast<GtkStateType>(stop_.paint_override());
GdkPixbuf* pixbuf = gtk_icon_set_render_icon(
icon_set,
style,
gtk_widget_get_direction(widget()),
state,
GTK_ICON_SIZE_SMALL_TOOLBAR,
widget(),
NULL);
gtk_button_set_image(GTK_BUTTON(widget()),
gtk_image_new_from_pixbuf(pixbuf));
g_object_unref(pixbuf);
}
gtk_widget_set_size_request(widget(), -1, -1);
GtkRequisition req;
gtk_widget_size_request(widget(), &req);
GtkButtonWidth = std::max(GtkButtonWidth, req.width);
gtk_widget_set_size_request(widget(), GtkButtonWidth, -1);
gtk_widget_set_app_paintable(widget(), FALSE);
gtk_widget_set_double_buffered(widget(), TRUE);
} else {
gtk_button_set_image(GTK_BUTTON(widget()), NULL);
gtk_widget_set_size_request(widget(), reload_.Width(), reload_.Height());
gtk_widget_set_app_paintable(widget(), TRUE);
gtk_widget_set_double_buffered(widget(), FALSE);
}
gtk_chrome_button_set_use_gtk_rendering(GTK_CHROME_BUTTON(widget()), use_gtk);
}
void ReloadButtonGtk::OnDoubleClickTimer() {
ChangeMode(intended_mode_, false);
}
void ReloadButtonGtk::OnStopToReloadTimer() {
ChangeMode(intended_mode_, true);
}
void ReloadButtonGtk::ShowReloadMenu(int button, guint32 event_time) {
if (!ReloadMenuEnabled() || visible_mode_ == MODE_STOP)
return;
menu_visible_ = true;
menu_.reset(new MenuGtk(this, menu_model_.get()));
reload_.set_paint_override(GTK_STATE_ACTIVE);
gtk_chrome_button_set_paint_state(GTK_CHROME_BUTTON(widget_.get()),
GTK_STATE_ACTIVE);
gtk_widget_queue_draw(widget());
menu_->PopupForWidget(widget(), button, event_time);
}
void ReloadButtonGtk::DoReload(int command) {
double_click_timer_.Start(FROM_HERE, double_click_timer_delay_, this,
&ReloadButtonGtk::OnDoubleClickTimer);
if (browser_) {
GdkModifierType modifier_state;
gtk_get_current_event_state(&modifier_state);
guint modifier_state_uint = modifier_state;
if (command == 0) {
if (modifier_state_uint & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) {
command = IDC_RELOAD_IGNORING_CACHE;
modifier_state_uint &= ~(GDK_SHIFT_MASK | GDK_CONTROL_MASK);
} else {
command = IDC_RELOAD;
}
}
chrome::ExecuteCommandWithDisposition(
browser_, command,
event_utils::DispositionFromGdkState(modifier_state_uint));
}
++testing_reload_count_;
}
bool ReloadButtonGtk::ReloadMenuEnabled() {
return browser_ && chrome::IsDebuggerAttachedToCurrentTab(browser_);
}
void ReloadButtonGtk::ClearCache() {
if (browser_)
chrome::ClearCache(browser_);
}