summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-09 06:40:57 +0000
committerwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-09 06:40:57 +0000
commit64f001a8a74f5d861d9948155c92419f53928e50 (patch)
tree4f215495257c68c34f8f1bbc4724e35a73be1788
parent253071feeaf010115a8fbe498d1ebd634c2d1626 (diff)
downloadchromium_src-64f001a8a74f5d861d9948155c92419f53928e50.zip
chromium_src-64f001a8a74f5d861d9948155c92419f53928e50.tar.gz
chromium_src-64f001a8a74f5d861d9948155c92419f53928e50.tar.bz2
Implement stop/go button for Linux.
Refactored code out of CustomDrawButton into CustomDrawButtonBase to be shared with GoButtonGtk. Replaced the existing non-togglable go button with GoButtonGtk. Note that tooltip support isn't done yet, as it changes based on the state of the location bar and the go/stop state. Add a simple test. Fix some minor lint errors. BUG=9381 Review URL: http://codereview.chromium.org/62154 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13409 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/gtk/browser_toolbar_gtk.cc8
-rw-r--r--chrome/browser/gtk/browser_toolbar_gtk.h5
-rw-r--r--chrome/browser/gtk/browser_window_gtk.cc5
-rw-r--r--chrome/browser/gtk/custom_button.cc63
-rw-r--r--chrome/browser/gtk/custom_button.h32
-rw-r--r--chrome/browser/gtk/go_button_gtk.cc156
-rw-r--r--chrome/browser/gtk/go_button_gtk.h76
-rw-r--r--chrome/browser/gtk/go_button_gtk_unittest.cc130
-rw-r--r--chrome/browser/views/go_button.cc3
-rw-r--r--chrome/browser/views/go_button.h9
-rw-r--r--chrome/chrome.gyp5
11 files changed, 452 insertions, 40 deletions
diff --git a/chrome/browser/gtk/browser_toolbar_gtk.cc b/chrome/browser/gtk/browser_toolbar_gtk.cc
index 37cbd5d..8455157 100644
--- a/chrome/browser/gtk/browser_toolbar_gtk.cc
+++ b/chrome/browser/gtk/browser_toolbar_gtk.cc
@@ -13,6 +13,7 @@
#include "chrome/browser/browser.h"
#include "chrome/browser/gtk/back_forward_menu_model_gtk.h"
#include "chrome/browser/gtk/custom_button.h"
+#include "chrome/browser/gtk/go_button_gtk.h"
#include "chrome/browser/gtk/location_bar_view_gtk.h"
#include "chrome/browser/gtk/nine_box.h"
#include "chrome/browser/gtk/standard_menus.h"
@@ -121,7 +122,8 @@ void BrowserToolbarGtk::Init(Profile* profile,
location_bar_->Init();
gtk_box_pack_start(GTK_BOX(toolbar_), location_bar_->widget(), TRUE, TRUE, 0);
- go_.reset(BuildToolbarButton(IDR_GO, IDR_GO_P, IDR_GO_H, 0, L""));
+ go_.reset(new GoButtonGtk(browser_));
+ gtk_box_pack_start(GTK_BOX(toolbar_), go_->widget(), FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(toolbar_), gtk_label_new(" "), FALSE, FALSE, 0);
@@ -285,8 +287,6 @@ void BrowserToolbarGtk::OnButtonClick(GtkWidget* button,
tag = IDC_FORWARD;
else if (button == toolbar->reload_->widget())
tag = IDC_RELOAD;
- else if (button == toolbar->go_->widget())
- tag = IDC_GO;
else if (toolbar->home_.get() && button == toolbar->home_->widget())
tag = IDC_HOME;
else if (button == toolbar->star_->widget())
@@ -295,7 +295,7 @@ void BrowserToolbarGtk::OnButtonClick(GtkWidget* button,
if (tag == IDC_BACK || tag == IDC_FORWARD)
toolbar->show_menu_factory_.RevokeAll();
- DCHECK(tag != -1) << "Impossible button click callback";
+ DCHECK_NE(tag, -1) << "Impossible button click callback";
toolbar->browser_->ExecuteCommand(tag);
}
diff --git a/chrome/browser/gtk/browser_toolbar_gtk.h b/chrome/browser/gtk/browser_toolbar_gtk.h
index 1223061..3f391a7 100644
--- a/chrome/browser/gtk/browser_toolbar_gtk.h
+++ b/chrome/browser/gtk/browser_toolbar_gtk.h
@@ -18,6 +18,7 @@ class BackForwardMenuModelGtk;
class Browser;
class CustomContainerButton;
class CustomDrawButton;
+class GoButtonGtk;
class LocationBar;
class LocationBarViewGtk;
class NineBox;
@@ -47,6 +48,8 @@ class BrowserToolbarGtk : public CommandUpdater::CommandObserver,
virtual LocationBar* GetLocationBar() const;
+ GoButtonGtk* GetGoButton() { return go_.get(); }
+
// Overridden from CommandUpdater::CommandObserver:
virtual void EnabledStateChangedForCommand(int id, bool enabled);
@@ -130,7 +133,7 @@ class BrowserToolbarGtk : public CommandUpdater::CommandObserver,
scoped_ptr<CustomDrawButton> reload_;
scoped_ptr<CustomDrawButton> home_; // May be NULL.
scoped_ptr<ToolbarStarToggleGtk> star_;
- scoped_ptr<CustomDrawButton> go_;
+ scoped_ptr<GoButtonGtk> go_;
scoped_ptr<CustomContainerButton> page_menu_button_, app_menu_button_;
// The model that contains the security level, text, icon to display...
diff --git a/chrome/browser/gtk/browser_window_gtk.cc b/chrome/browser/gtk/browser_window_gtk.cc
index 7e0e81e..d8417ab 100644
--- a/chrome/browser/gtk/browser_window_gtk.cc
+++ b/chrome/browser/gtk/browser_window_gtk.cc
@@ -20,6 +20,7 @@
#include "chrome/browser/browser_list.h"
#include "chrome/browser/gtk/bookmark_bar_gtk.h"
#include "chrome/browser/gtk/browser_toolbar_gtk.h"
+#include "chrome/browser/gtk/go_button_gtk.h"
#include "chrome/browser/gtk/infobar_container_gtk.h"
#include "chrome/browser/gtk/find_bar_gtk.h"
#include "chrome/browser/gtk/status_bubble_gtk.h"
@@ -413,8 +414,8 @@ void BrowserWindowGtk::SetFocusToLocationBar() {
}
void BrowserWindowGtk::UpdateStopGoState(bool is_loading) {
- // Need to implement stop/go button.
- // http://code.google.com/p/chromium/issues/detail?id=9381
+ toolbar_->GetGoButton()->ChangeMode(
+ is_loading ? GoButtonGtk::MODE_STOP : GoButtonGtk::MODE_GO);
}
void BrowserWindowGtk::UpdateToolbar(TabContents* contents,
diff --git a/chrome/browser/gtk/custom_button.cc b/chrome/browser/gtk/custom_button.cc
index 150d29f..4ff475c 100644
--- a/chrome/browser/gtk/custom_button.cc
+++ b/chrome/browser/gtk/custom_button.cc
@@ -10,10 +10,11 @@
#include "grit/theme_resources.h"
-CustomDrawButton::CustomDrawButton(int normal_id,
- int active_id, int highlight_id, int depressed_id) {
- widget_.Own(gtk_button_new());
-
+CustomDrawButtonBase::CustomDrawButtonBase(
+ int normal_id,
+ int active_id,
+ int highlight_id,
+ int depressed_id) {
// Load the button images from the resource bundle.
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
pixbufs_[GTK_STATE_NORMAL] = normal_id ? rb.LoadPixbuf(normal_id) : NULL;
@@ -23,35 +24,21 @@ CustomDrawButton::CustomDrawButton(int normal_id,
pixbufs_[GTK_STATE_SELECTED] = NULL;
pixbufs_[GTK_STATE_INSENSITIVE] =
depressed_id ? rb.LoadPixbuf(depressed_id) : NULL;
-
- gtk_widget_set_size_request(widget_.get(),
- gdk_pixbuf_get_width(pixbufs_[0]),
- gdk_pixbuf_get_height(pixbufs_[0]));
-
- gtk_widget_set_app_paintable(widget_.get(), TRUE);
- // We effectively double-buffer by virtue of having only one image...
- gtk_widget_set_double_buffered(widget_.get(), FALSE);
- g_signal_connect(G_OBJECT(widget_.get()), "expose-event",
- G_CALLBACK(OnExpose), this);
}
-CustomDrawButton::~CustomDrawButton() {
+CustomDrawButtonBase::~CustomDrawButtonBase() {
for (size_t i = 0; i < arraysize(pixbufs_); ++i) {
if (pixbufs_[i])
- gdk_pixbuf_unref(pixbufs_[i]);
+ g_object_unref(pixbufs_[i]);
}
-
- widget_.Destroy();
}
-// static
-gboolean CustomDrawButton::OnExpose(GtkWidget* widget, GdkEventExpose* e,
- CustomDrawButton* button) {
- GdkPixbuf* pixbuf = button->pixbufs_[GTK_WIDGET_STATE(widget)];
+gboolean CustomDrawButtonBase::OnExpose(GtkWidget* widget, GdkEventExpose* e) {
+ GdkPixbuf* pixbuf = pixbufs(GTK_WIDGET_STATE(widget));
// Fall back to the default image if we don't have one for this state.
if (!pixbuf)
- pixbuf = button->pixbufs_[GTK_STATE_NORMAL];
+ pixbuf = pixbufs(GTK_STATE_NORMAL);
if (!pixbuf)
return FALSE;
@@ -66,6 +53,36 @@ gboolean CustomDrawButton::OnExpose(GtkWidget* widget, GdkEventExpose* e,
return TRUE;
}
+CustomDrawButton::CustomDrawButton(
+ int normal_id,
+ int active_id,
+ int highlight_id,
+ int depressed_id)
+ : button_base_(normal_id, active_id, highlight_id, depressed_id) {
+ widget_.Own(gtk_button_new());
+
+ gtk_widget_set_size_request(widget_.get(),
+ gdk_pixbuf_get_width(button_base_.pixbufs(0)),
+ gdk_pixbuf_get_height(button_base_.pixbufs(0)));
+
+ gtk_widget_set_app_paintable(widget_.get(), TRUE);
+ // We effectively double-buffer by virtue of having only one image...
+ gtk_widget_set_double_buffered(widget_.get(), FALSE);
+ g_signal_connect(G_OBJECT(widget_.get()), "expose-event",
+ G_CALLBACK(OnExpose), this);
+}
+
+CustomDrawButton::~CustomDrawButton() {
+ widget_.Destroy();
+}
+
+// static
+gboolean CustomDrawButton::OnExpose(GtkWidget* widget,
+ GdkEventExpose* e,
+ CustomDrawButton* button) {
+ return button->button_base_.OnExpose(widget, e);
+}
+
// static
CustomDrawButton* CustomDrawButton::AddBarCloseButton(GtkWidget* hbox) {
CustomDrawButton* rv = new CustomDrawButton(IDR_CLOSE_BAR, IDR_CLOSE_BAR_P,
diff --git a/chrome/browser/gtk/custom_button.h b/chrome/browser/gtk/custom_button.h
index 518f069..96b4ad6 100644
--- a/chrome/browser/gtk/custom_button.h
+++ b/chrome/browser/gtk/custom_button.h
@@ -17,6 +17,29 @@ class NineBox;
// These classes implement two kinds of custom-drawn buttons. They're
// used on the toolbar and the bookmarks bar.
+// CustomDrawButtonBase provides the base for building a custom drawn button.
+// It handles managing the pixbufs containing all the static images used to draw
+// the button. It also manages painting these pixbufs.
+class CustomDrawButtonBase {
+ public:
+ CustomDrawButtonBase(int normal_id,
+ int active_id,
+ int highlight_id,
+ int depressed_id);
+ ~CustomDrawButtonBase();
+
+ GdkPixbuf* pixbufs(int i) const { return pixbufs_[i]; }
+
+ gboolean OnExpose(GtkWidget* widget, GdkEventExpose* e);
+
+ private:
+ // We store one GdkPixbuf* for each possible state of the button;
+ // INSENSITIVE is the last available state;
+ GdkPixbuf* pixbufs_[GTK_STATE_INSENSITIVE + 1];
+
+ DISALLOW_COPY_AND_ASSIGN(CustomDrawButtonBase);
+};
+
// CustomDrawButton is a plain button where all its various states are drawn
// with static images.
class CustomDrawButton {
@@ -40,15 +63,16 @@ class CustomDrawButton {
private:
// Callback for expose, used to draw the custom graphics.
- static gboolean OnExpose(GtkWidget* widget, GdkEventExpose* e,
+ static gboolean OnExpose(GtkWidget* widget,
+ GdkEventExpose* e,
CustomDrawButton* obj);
// The actual button widget.
OwnedWidgetGtk widget_;
- // We store one GdkPixbuf* for each possible state of the button;
- // INSENSITIVE is the last available state;
- GdkPixbuf* pixbufs_[GTK_STATE_INSENSITIVE + 1];
+ CustomDrawButtonBase button_base_;
+
+ DISALLOW_COPY_AND_ASSIGN(CustomDrawButton);
};
// CustomContainerButton wraps another widget and uses a NineBox of
diff --git a/chrome/browser/gtk/go_button_gtk.cc b/chrome/browser/gtk/go_button_gtk.cc
new file mode 100644
index 0000000..2f32e64
--- /dev/null
+++ b/chrome/browser/gtk/go_button_gtk.cc
@@ -0,0 +1,156 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/gtk/go_button_gtk.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "chrome/app/chrome_dll_resource.h"
+#include "chrome/browser/browser.h"
+#include "grit/theme_resources.h"
+
+GoButtonGtk::GoButtonGtk(Browser* browser)
+ : browser_(browser),
+ button_delay_(0),
+ stop_timer_(this),
+ intended_mode_(MODE_GO),
+ visible_mode_(MODE_GO),
+ state_(BS_NORMAL),
+ go_(IDR_GO, IDR_GO_P, IDR_GO_H, 0),
+ stop_(IDR_STOP, IDR_STOP_P, IDR_STOP_H, 0),
+ widget_(gtk_button_new()) {
+ gtk_widget_set_size_request(widget_.get(),
+ gdk_pixbuf_get_width(go_.pixbufs(0)),
+ gdk_pixbuf_get_height(go_.pixbufs(0)));
+
+ gtk_widget_set_app_paintable(widget_.get(), TRUE);
+ // We effectively double-buffer by virtue of having only one image...
+ gtk_widget_set_double_buffered(widget_.get(), FALSE);
+
+ g_signal_connect(G_OBJECT(widget_.get()), "expose-event",
+ G_CALLBACK(OnExpose), this);
+ g_signal_connect(G_OBJECT(widget_.get()), "enter",
+ G_CALLBACK(OnEnter), this);
+ g_signal_connect(G_OBJECT(widget_.get()), "leave",
+ G_CALLBACK(OnLeave), this);
+ g_signal_connect(G_OBJECT(widget_.get()), "clicked",
+ G_CALLBACK(OnClicked), this);
+ GTK_WIDGET_UNSET_FLAGS(widget_.get(), GTK_CAN_FOCUS);
+
+ // TODO(willchan): Implement tooltips.
+ gtk_widget_set_tooltip_text(widget_.get(), "Implement toggleable tooltips");
+}
+
+GoButtonGtk::~GoButtonGtk() {
+ widget_.Destroy();
+}
+
+void GoButtonGtk::ChangeMode(Mode mode) {
+ if (mode != visible_mode_) {
+ gtk_widget_queue_draw(widget_.get());
+ }
+ stop_timer_.RevokeAll();
+ intended_mode_ = mode;
+ visible_mode_ = mode;
+}
+
+void GoButtonGtk::ScheduleChangeMode(Mode mode) {
+ if (mode == MODE_STOP) {
+ // If we still have a timer running, we can't yet change to a stop sign,
+ // so we'll queue up the change for when the timer expires or for when
+ // the mouse exits the button.
+ if (!stop_timer_.empty() && state() == BS_HOT) {
+ intended_mode_ = MODE_STOP;
+ } else {
+ ChangeMode(MODE_STOP);
+ }
+ } else {
+ // If we want to change the button to a go button, but the user's mouse
+ // is hovering, don't change the mode just yet - this prevents the
+ // stop button changing to a go under the user's mouse cursor.
+ if (visible_mode_ == MODE_STOP && state() == BS_HOT) {
+ intended_mode_ = MODE_GO;
+ } else {
+ ChangeMode(MODE_GO);
+ }
+ }
+}
+
+Task* GoButtonGtk::CreateButtonTimerTask() {
+ return stop_timer_.NewRunnableMethod(&GoButtonGtk::OnButtonTimer);
+}
+
+void GoButtonGtk::OnButtonTimer() {
+ if (intended_mode_ != visible_mode_) {
+ ChangeMode(intended_mode_);
+ }
+
+ stop_timer_.RevokeAll();
+}
+
+// static
+gboolean GoButtonGtk::OnExpose(GtkWidget* widget,
+ GdkEventExpose* e,
+ GoButtonGtk* button) {
+ if (button->visible_mode_ == MODE_GO) {
+ return button->go_.OnExpose(widget, e);
+ } else {
+ return button->stop_.OnExpose(widget, e);
+ }
+}
+
+// static
+gboolean GoButtonGtk::OnEnter(GtkButton* widget, GoButtonGtk* button) {
+ DCHECK_EQ(BS_NORMAL, button->state());
+ button->state_ = BS_HOT;
+ return TRUE;
+}
+
+// static
+gboolean GoButtonGtk::OnLeave(GtkButton* widget, GoButtonGtk* button) {
+ DCHECK_EQ(BS_HOT, button->state());
+ button->state_ = BS_NORMAL;
+ if (button->visible_mode_ != button->intended_mode_) {
+ button->ChangeMode(button->intended_mode_);
+ }
+ return TRUE;
+}
+
+// static
+gboolean GoButtonGtk::OnClicked(GtkButton* widget, GoButtonGtk* button) {
+ if (button->visible_mode_ == MODE_STOP) {
+ if (button->browser_)
+ button->browser_->Stop();
+
+ // The user has clicked, so we can feel free to update the button,
+ // even if the mouse is still hovering.
+ button->ChangeMode(MODE_GO);
+ } else if (button->visible_mode_ == MODE_GO && button->stop_timer_.empty()) {
+ // If the go button is visible and not within the double click timer, go.
+ if (button->browser_)
+ button->browser_->ExecuteCommand(IDC_GO);
+
+ // Figure out the system double-click time.
+ if (button->button_delay_ == 0) {
+ GtkSettings* settings = gtk_settings_get_default();
+ g_object_get(G_OBJECT(settings),
+ "gtk-double-click-time",
+ &button->button_delay_,
+ NULL);
+ }
+
+ // Stop any existing timers.
+ button->stop_timer_.RevokeAll();
+
+ // Start a timer - while this timer is running, the go button
+ // cannot be changed to a stop button. We do not set intended_mode_
+ // to MODE_STOP here as we want to wait for the browser to tell
+ // us that it has started loading (and this may occur only after
+ // some delay).
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ button->CreateButtonTimerTask(),
+ button->button_delay_);
+ }
+
+ return TRUE;
+}
diff --git a/chrome/browser/gtk/go_button_gtk.h b/chrome/browser/gtk/go_button_gtk.h
new file mode 100644
index 0000000..047feec
--- /dev/null
+++ b/chrome/browser/gtk/go_button_gtk.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_GTK_GO_BUTTON_GTK_H_
+#define CHROME_BROWSER_GTK_GO_BUTTON_GTK_H_
+
+#include <gtk/gtk.h>
+
+#include "base/basictypes.h"
+#include "base/task.h"
+#include "chrome/browser/gtk/custom_button.h"
+#include "chrome/common/owned_widget_gtk.h"
+
+class Browser;
+class Task;
+
+class GoButtonGtk {
+ public:
+ enum Mode { MODE_GO = 0, MODE_STOP };
+ enum ButtonState { BS_NORMAL = 0, BS_HOT };
+
+ explicit GoButtonGtk(Browser* browser);
+ ~GoButtonGtk();
+
+ GtkWidget* widget() const { return widget_.get(); }
+ ButtonState state() const { return state_; }
+
+ // Force the button state. Useful for when the foreground tab changes.
+ void ChangeMode(Mode mode);
+
+ // Ask for a specified button state. This is called when the loading state of
+ // the tab changes. This method may postpone the actual ChangeMode() call
+ // until another event (such as waiting for a potential double click to end,
+ // or for the mouse to stop hovering over the button).
+ void ScheduleChangeMode(Mode mode);
+
+ private:
+ friend class GoButtonGtkPeer;
+
+ // gtk signals
+ static gboolean OnExpose(GtkWidget* widget,
+ GdkEventExpose* e,
+ GoButtonGtk* button);
+ static gboolean OnEnter(GtkButton* widget, GoButtonGtk* button);
+ static gboolean OnLeave(GtkButton* widget, GoButtonGtk* button);
+ static gboolean OnClicked(GtkButton* widget, GoButtonGtk* button);
+
+ Task* CreateButtonTimerTask();
+ void OnButtonTimer();
+
+ // Keep a pointer to the Browser object to execute commands on it.
+ Browser* const browser_;
+
+ // Delay time to wait before allowing a mode change. This is to prevent a
+ // mode switch while the user is double clicking.
+ int button_delay_;
+ ScopedRunnableMethodFactory<GoButtonGtk> stop_timer_;
+
+ // The mode we should be in
+ Mode intended_mode_;
+
+ // The currently-visible mode - this may different from the intended mode
+ Mode visible_mode_;
+
+ ButtonState state_;
+
+ CustomDrawButtonBase go_;
+ CustomDrawButtonBase stop_;
+
+ OwnedWidgetGtk widget_;
+
+ DISALLOW_COPY_AND_ASSIGN(GoButtonGtk);
+};
+
+#endif // CHROME_BROWSER_GTK_GO_BUTTON_GTK_H_
diff --git a/chrome/browser/gtk/go_button_gtk_unittest.cc b/chrome/browser/gtk/go_button_gtk_unittest.cc
new file mode 100644
index 0000000..723f587
--- /dev/null
+++ b/chrome/browser/gtk/go_button_gtk_unittest.cc
@@ -0,0 +1,130 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/gtk/go_button_gtk.h"
+#include "base/task.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class GoButtonGtkPeer {
+ public:
+ explicit GoButtonGtkPeer(GoButtonGtk* go) : go_(go) { }
+
+ // const accessors for internal state
+ GoButtonGtk::Mode intended_mode() const { return go_->intended_mode_; }
+ GoButtonGtk::Mode visible_mode() const { return go_->visible_mode_; }
+
+ // mutable accessors for internal state
+ ScopedRunnableMethodFactory<GoButtonGtk>* stop_timer() {
+ return &go_->stop_timer_;
+ }
+
+ // mutators for internal state
+ void set_state(GoButtonGtk::ButtonState state) { go_->state_ = state; }
+ void set_intended_mode(GoButtonGtk::Mode mode) { go_->intended_mode_ = mode; }
+ void set_visible_mode(GoButtonGtk::Mode mode) { go_->visible_mode_ = mode; }
+
+ // forwarders to private methods
+ Task* CreateButtonTimerTask() { return go_->CreateButtonTimerTask(); }
+ gboolean OnLeave() {
+ return GoButtonGtk::OnLeave(GTK_BUTTON(go_->widget()), go_);
+ }
+
+ gboolean OnClicked() {
+ return GoButtonGtk::OnClicked(GTK_BUTTON(go_->widget()), go_);
+ }
+
+ private:
+ GoButtonGtk* const go_;
+};
+
+namespace {
+
+class GoButtonGtkTest : public testing::Test {
+ protected:
+ GoButtonGtkTest() : go_(NULL), peer_(&go_) { }
+
+ protected:
+ GoButtonGtk go_;
+ GoButtonGtkPeer peer_;
+};
+
+TEST_F(GoButtonGtkTest, ChangeModeGo) {
+ go_.ChangeMode(GoButtonGtk::MODE_GO);
+ EXPECT_EQ(GoButtonGtk::MODE_GO, peer_.intended_mode());
+ EXPECT_EQ(GoButtonGtk::MODE_GO, peer_.visible_mode());
+}
+
+TEST_F(GoButtonGtkTest, ChangeModeStop) {
+ go_.ChangeMode(GoButtonGtk::MODE_GO);
+ EXPECT_EQ(GoButtonGtk::MODE_GO, peer_.intended_mode());
+ EXPECT_EQ(GoButtonGtk::MODE_GO, peer_.visible_mode());
+}
+
+TEST_F(GoButtonGtkTest, ScheduleChangeModeNormalGo) {
+ peer_.set_visible_mode(GoButtonGtk::MODE_STOP);
+ peer_.set_state(GoButtonGtk::BS_NORMAL);
+ go_.ScheduleChangeMode(GoButtonGtk::MODE_GO);
+ EXPECT_EQ(GoButtonGtk::MODE_GO, peer_.intended_mode());
+ EXPECT_EQ(GoButtonGtk::MODE_GO, peer_.visible_mode());
+}
+
+TEST_F(GoButtonGtkTest, ScheduleChangeModeHotGo) {
+ peer_.set_visible_mode(GoButtonGtk::MODE_STOP);
+ peer_.set_state(GoButtonGtk::BS_HOT);
+ go_.ScheduleChangeMode(GoButtonGtk::MODE_GO);
+ EXPECT_EQ(GoButtonGtk::MODE_GO, peer_.intended_mode());
+ EXPECT_EQ(GoButtonGtk::MODE_STOP, peer_.visible_mode());
+}
+
+TEST_F(GoButtonGtkTest, ScheduleChangeModeNormalStop) {
+ peer_.set_visible_mode(GoButtonGtk::MODE_GO);
+ peer_.set_state(GoButtonGtk::BS_NORMAL);
+ go_.ScheduleChangeMode(GoButtonGtk::MODE_STOP);
+ EXPECT_EQ(GoButtonGtk::MODE_STOP, peer_.intended_mode());
+ EXPECT_EQ(GoButtonGtk::MODE_STOP, peer_.visible_mode());
+}
+
+TEST_F(GoButtonGtkTest, ScheduleChangeModeHotStop) {
+ peer_.set_visible_mode(GoButtonGtk::MODE_GO);
+ peer_.set_state(GoButtonGtk::BS_HOT);
+ go_.ScheduleChangeMode(GoButtonGtk::MODE_STOP);
+ EXPECT_EQ(GoButtonGtk::MODE_STOP, peer_.intended_mode());
+ EXPECT_EQ(GoButtonGtk::MODE_STOP, peer_.visible_mode());
+}
+
+TEST_F(GoButtonGtkTest, ScheduleChangeModeTimerHotStop) {
+ peer_.set_visible_mode(GoButtonGtk::MODE_GO);
+ peer_.set_state(GoButtonGtk::BS_HOT);
+ scoped_ptr<Task> task(peer_.CreateButtonTimerTask());
+ go_.ScheduleChangeMode(GoButtonGtk::MODE_STOP);
+ EXPECT_EQ(GoButtonGtk::MODE_STOP, peer_.intended_mode());
+ EXPECT_EQ(GoButtonGtk::MODE_GO, peer_.visible_mode());
+}
+
+TEST_F(GoButtonGtkTest, OnLeaveIntendedStop) {
+ peer_.set_state(GoButtonGtk::BS_HOT);
+ peer_.set_visible_mode(GoButtonGtk::MODE_GO);
+ peer_.set_intended_mode(GoButtonGtk::MODE_STOP);
+ EXPECT_TRUE(peer_.OnLeave());
+ EXPECT_EQ(GoButtonGtk::MODE_STOP, peer_.visible_mode());
+ EXPECT_EQ(GoButtonGtk::MODE_STOP, peer_.intended_mode());
+}
+
+TEST_F(GoButtonGtkTest, OnLeaveIntendedGo) {
+ peer_.set_state(GoButtonGtk::BS_HOT);
+ peer_.set_visible_mode(GoButtonGtk::MODE_STOP);
+ peer_.set_intended_mode(GoButtonGtk::MODE_GO);
+ EXPECT_TRUE(peer_.OnLeave());
+ EXPECT_EQ(GoButtonGtk::MODE_GO, peer_.visible_mode());
+ EXPECT_EQ(GoButtonGtk::MODE_GO, peer_.intended_mode());
+}
+
+TEST_F(GoButtonGtkTest, OnClickedStop) {
+ peer_.set_visible_mode(GoButtonGtk::MODE_STOP);
+ EXPECT_TRUE(peer_.OnClicked());
+ EXPECT_EQ(GoButtonGtk::MODE_GO, peer_.visible_mode());
+ EXPECT_EQ(GoButtonGtk::MODE_GO, peer_.intended_mode());
+}
+
+} // namespace
diff --git a/chrome/browser/views/go_button.cc b/chrome/browser/views/go_button.cc
index 48773ae..f276e92 100644
--- a/chrome/browser/views/go_button.cc
+++ b/chrome/browser/views/go_button.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/views/go_button.h"
+#include "base/message_loop.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/views/event_utils.h"
@@ -97,8 +98,6 @@ void GoButton::ButtonPressed(views::Button* button) {
// GoButton, View overrides:
void GoButton::OnMouseExited(const views::MouseEvent& e) {
- using namespace views;
-
if (visible_mode_ != intended_mode_)
ChangeMode(intended_mode_);
diff --git a/chrome/browser/views/go_button.h b/chrome/browser/views/go_button.h
index a830191..cdd5bea 100644
--- a/chrome/browser/views/go_button.h
+++ b/chrome/browser/views/go_button.h
@@ -5,8 +5,9 @@
#ifndef CHROME_BROWSER_VIEWS_GO_BUTTON_H__
#define CHROME_BROWSER_VIEWS_GO_BUTTON_H__
-#include "chrome/views/controls/button/image_button.h"
+#include "base/basictypes.h"
#include "base/task.h"
+#include "chrome/views/controls/button/image_button.h"
class Browser;
class LocationBarView;
@@ -26,11 +27,11 @@ class LocationBarView;
class GoButton : public views::ToggleImageButton,
public views::ButtonListener {
public:
+ typedef enum Mode { MODE_GO = 0, MODE_STOP };
+
GoButton(LocationBarView* location_bar, Browser* Browser);
virtual ~GoButton();
- typedef enum Mode { MODE_GO = 0, MODE_STOP };
-
// Force the button state
void ChangeMode(Mode mode);
@@ -60,7 +61,7 @@ class GoButton : public views::ToggleImageButton,
// The currently-visible mode - this may different from the intended mode
Mode visible_mode_;
- DISALLOW_EVIL_CONSTRUCTORS(GoButton);
+ DISALLOW_COPY_AND_ASSIGN(GoButton);
};
#endif // CHROME_BROWSER_VIEWS_GO_BUTTON_H__
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 4130904..4707153 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -698,6 +698,8 @@
'browser/gtk/download_item_gtk.h',
'browser/gtk/download_shelf_gtk.cc',
'browser/gtk/download_shelf_gtk.h',
+ 'browser/gtk/go_button_gtk.cc',
+ 'browser/gtk/go_button_gtk.h',
'browser/gtk/infobar_gtk.cc',
'browser/gtk/infobar_gtk.h',
'browser/gtk/infobar_container_gtk.cc',
@@ -2098,6 +2100,7 @@
'browser/extensions/test_extension_loader.cc',
'browser/extensions/user_script_master_unittest.cc',
'browser/google_url_tracker_unittest.cc',
+ 'browser/gtk/go_button_gtk_unittest.cc',
'browser/gtk/tabs/tab_renderer_gtk_unittest.cc',
'browser/history/expire_history_backend_unittest.cc',
'browser/history/history_backend_unittest.cc',
@@ -2237,6 +2240,7 @@
'sources!': [
'browser/back_forward_menu_model_unittest.cc',
'browser/download/download_manager_unittest.cc',
+ 'browser/gtk/go_button_gtk_unittest.cc',
'browser/gtk/tabs/tab_renderer_gtk_unittest.cc',
'browser/navigation_controller_unittest.cc',
'browser/sessions/session_backend_unittest.cc',
@@ -2259,6 +2263,7 @@
],
'sources!': [
'browser/gtk/tabs/tab_renderer_gtk_unittest.cc',
+ 'browser/gtk/tabs/tab_renderer_gtk_unittest.cc',
'common/file_descriptor_set_unittest.cc',
'common/net/url_util_unittest.cc',
],