summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-08 21:58:19 +0000
committerjhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-08 21:58:19 +0000
commit01a8de9777621f0f4bc3f270d680d134dd435612 (patch)
tree8f99c6dcb83c711a3fd3e2389400967f27a3b533
parent02e80deede0729617aeb87128b1db3cd14b36d6b (diff)
downloadchromium_src-01a8de9777621f0f4bc3f270d680d134dd435612.zip
chromium_src-01a8de9777621f0f4bc3f270d680d134dd435612.tar.gz
chromium_src-01a8de9777621f0f4bc3f270d680d134dd435612.tar.bz2
Implement mouse input handling for the close button in the Linux tabstrip.
Review URL: http://codereview.chromium.org/63136 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13382 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/gtk/tabs/tab_gtk.cc37
-rw-r--r--chrome/browser/gtk/tabs/tab_gtk.h15
-rw-r--r--chrome/browser/gtk/tabs/tab_renderer_gtk.cc20
-rw-r--r--chrome/browser/gtk/tabs/tab_renderer_gtk.h19
-rw-r--r--chrome/browser/gtk/tabs/tab_strip_gtk.cc50
-rw-r--r--chrome/browser/gtk/tabs/tab_strip_gtk.h8
6 files changed, 131 insertions, 18 deletions
diff --git a/chrome/browser/gtk/tabs/tab_gtk.cc b/chrome/browser/gtk/tabs/tab_gtk.cc
index 3cd6869..46823fe 100644
--- a/chrome/browser/gtk/tabs/tab_gtk.cc
+++ b/chrome/browser/gtk/tabs/tab_gtk.cc
@@ -20,7 +20,8 @@ static const SkScalar kTabBottomCurveWidth = 3;
TabGtk::TabGtk(TabDelegate* delegate)
: TabRendererGtk(),
delegate_(delegate),
- closing_(false) {
+ closing_(false),
+ mouse_pressed_(false) {
}
TabGtk::~TabGtk() {
@@ -33,6 +34,40 @@ bool TabGtk::IsPointInBounds(const gfx::Point& point) {
return in_bounds;
}
+bool TabGtk::OnMotionNotify(const gfx::Point& point) {
+ CloseButtonState state;
+ if (close_button_bounds().Contains(point)) {
+ if (mouse_pressed_) {
+ state = BS_PUSHED;
+ } else {
+ state = BS_HOT;
+ }
+ } else {
+ state = BS_NORMAL;
+ }
+
+ bool need_redraw = (close_button_state() != state);
+ set_close_button_state(state);
+ return need_redraw;
+}
+
+bool TabGtk::OnMousePress() {
+ if (close_button_state() == BS_HOT) {
+ mouse_pressed_ = true;
+ set_close_button_state(BS_PUSHED);
+ return true;
+ }
+
+ return false;
+}
+
+void TabGtk::OnMouseRelease() {
+ mouse_pressed_ = false;
+
+ if (close_button_state() == BS_PUSHED)
+ delegate_->CloseTab(this);
+}
+
///////////////////////////////////////////////////////////////////////////////
// TabGtk, TabRendererGtk overrides:
diff --git a/chrome/browser/gtk/tabs/tab_gtk.h b/chrome/browser/gtk/tabs/tab_gtk.h
index 07a853e..b36aaf4 100644
--- a/chrome/browser/gtk/tabs/tab_gtk.h
+++ b/chrome/browser/gtk/tabs/tab_gtk.h
@@ -74,6 +74,18 @@ class TabGtk : public TabRendererGtk {
// TabRendererGtk overrides:
virtual bool IsSelected() const;
+ // Sent by the tabstrip when the mouse moves within this tab. Mouse is at
+ // |point|. Returns true if the tabstrip needs to be redrawn as a result
+ // of the motion.
+ bool OnMotionNotify(const gfx::Point& point);
+
+ // Sent by the tabstrip when the mouse clicks within this tab. Returns true
+ // if the tabstrip needs to be redrawn as a result of the click.
+ bool OnMousePress();
+
+ // Sent by the tabstrip when the mouse click is released.
+ void OnMouseRelease();
+
private:
// Creates a clickable region of the tab's visual representation. Used for
// hit-testing. Caller is responsible for destroying the region.
@@ -86,6 +98,9 @@ class TabGtk : public TabRendererGtk {
// True if the tab is being animated closed.
bool closing_;
+ // Set if the mouse is pressed anywhere inside the tab.
+ bool mouse_pressed_;
+
DISALLOW_COPY_AND_ASSIGN(TabGtk);
};
diff --git a/chrome/browser/gtk/tabs/tab_renderer_gtk.cc b/chrome/browser/gtk/tabs/tab_renderer_gtk.cc
index 2e22487..34388a5 100644
--- a/chrome/browser/gtk/tabs/tab_renderer_gtk.cc
+++ b/chrome/browser/gtk/tabs/tab_renderer_gtk.cc
@@ -144,7 +144,8 @@ TabRendererGtk::TabRendererGtk()
fav_icon_hiding_offset_(0),
should_display_crashed_favicon_(false),
hovering_(false),
- loading_animation_(&loading_animation_data) {
+ loading_animation_(&loading_animation_data),
+ close_button_state_(BS_NORMAL) {
InitResources();
}
@@ -322,10 +323,25 @@ void TabRendererGtk::Paint(ChromeCanvasPaint* canvas) {
title_bounds_.y(), title_bounds_.width(),
title_bounds_.height());
- canvas->DrawBitmapInt(*close_button_.normal,
+ SkBitmap close_button = *close_button_.normal;
+ if (close_button_state_ == BS_HOT)
+ close_button = *close_button_.hot;
+ else if (close_button_state_ == BS_PUSHED)
+ close_button = *close_button_.pushed;
+
+ canvas->DrawBitmapInt(close_button,
close_button_bounds_.x(), close_button_bounds_.y());
}
+void TabRendererGtk::SetHovering(bool hovering) {
+ hovering_ = hovering;
+
+ // If the mouse is not hovering over the tab, the close button can't be
+ // highlighted.
+ if (!hovering)
+ close_button_state_ = BS_NORMAL;
+}
+
void TabRendererGtk::Layout() {
gfx::Rect local_bounds = bounds_;
if (local_bounds.IsEmpty())
diff --git a/chrome/browser/gtk/tabs/tab_renderer_gtk.h b/chrome/browser/gtk/tabs/tab_renderer_gtk.h
index 07c7614..28fd233 100644
--- a/chrome/browser/gtk/tabs/tab_renderer_gtk.h
+++ b/chrome/browser/gtk/tabs/tab_renderer_gtk.h
@@ -28,6 +28,13 @@ class TabRendererGtk {
ANIMATION_LOADING
};
+ // Possible close button states
+ enum CloseButtonState {
+ BS_NORMAL,
+ BS_HOT,
+ BS_PUSHED
+ };
+
class LoadingAnimation {
public:
struct Data {
@@ -110,14 +117,21 @@ class TabRendererGtk {
void Paint(ChromeCanvasPaint* canvas);
// Sets the hovering status of the tab.
- void SetHovering(bool hovering) { hovering_ = hovering; }
+ void SetHovering(bool hovering);
protected:
const gfx::Rect& title_bounds() const { return title_bounds_; }
+ const gfx::Rect& close_button_bounds() const { return close_button_bounds_; }
+ CloseButtonState close_button_state() const { return close_button_state_; }
// Returns the title of the Tab.
std::wstring GetTitle() const;
+ // Sets whether the close button should be highlighted or not.
+ void set_close_button_state(CloseButtonState state) {
+ close_button_state_ = state;
+ }
+
private:
// Model data. We store this here so that we don't need to ask the underlying
// model, which is tricky since instances of this object can outlive the
@@ -221,6 +235,9 @@ class TabRendererGtk {
// Set when the mouse is hovering over this tab and the tab is not selected.
bool hovering_;
+ // The state of the close button as it relates to mouse input.
+ CloseButtonState close_button_state_;
+
// Contains the loading animation state.
LoadingAnimation loading_animation_;
diff --git a/chrome/browser/gtk/tabs/tab_strip_gtk.cc b/chrome/browser/gtk/tabs/tab_strip_gtk.cc
index ff4b636..0704de0 100644
--- a/chrome/browser/gtk/tabs/tab_strip_gtk.cc
+++ b/chrome/browser/gtk/tabs/tab_strip_gtk.cc
@@ -75,11 +75,14 @@ void TabStripGtk::Init() {
g_signal_connect(G_OBJECT(tabstrip_.get()), "motion-notify-event",
G_CALLBACK(OnMotionNotify), this);
g_signal_connect(G_OBJECT(tabstrip_.get()), "button-press-event",
- G_CALLBACK(OnButtonPress), this);
+ G_CALLBACK(OnMousePress), this);
+ g_signal_connect(G_OBJECT(tabstrip_.get()), "button-release-event",
+ G_CALLBACK(OnMouseRelease), this);
g_signal_connect(G_OBJECT(tabstrip_.get()), "leave-notify-event",
G_CALLBACK(OnLeaveNotify), this);
gtk_widget_add_events(tabstrip_.get(),
- GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_LEAVE_NOTIFY_MASK);
+ GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |GDK_LEAVE_NOTIFY_MASK);
gtk_widget_show_all(tabstrip_.get());
bounds_ = GetInitialWidgetBounds(tabstrip_.get());
@@ -452,7 +455,7 @@ gboolean TabStripGtk::OnMotionNotify(GtkWidget* widget, GdkEventMotion* event,
int old_hover_index = tabstrip->hover_index_;
tabstrip->hover_index_ = -1;
- gfx::Point coord(event->x, event->y);
+ gfx::Point point(event->x, event->y);
// Get a rough estimate for which tab the mouse is over.
int index = event->x / (tabstrip->current_unselected_width_ + kTabHOffset);
@@ -474,16 +477,16 @@ gboolean TabStripGtk::OnMotionNotify(GtkWidget* widget, GdkEventMotion* event,
// finally the tab to the right (tabs stack to the left.)
if (tabstrip->model()->selected_index() == index &&
- tabstrip->GetTabAt(index)->IsPointInBounds(coord)) {
+ tabstrip->GetTabAt(index)->IsPointInBounds(point)) {
tabstrip->hover_index_ = index;
} else if (index > 0 &&
- tabstrip->GetTabAt(index - 1)->IsPointInBounds(coord)) {
+ tabstrip->GetTabAt(index - 1)->IsPointInBounds(point)) {
tabstrip->hover_index_ = index - 1;
} else if (tabstrip->model()->selected_index() != index &&
- tabstrip->GetTabAt(index)->IsPointInBounds(coord)) {
+ tabstrip->GetTabAt(index)->IsPointInBounds(point)) {
tabstrip->hover_index_ = index;
} else if (index < tab_count - 1 &&
- tabstrip->GetTabAt(index + 1)->IsPointInBounds(coord)) {
+ tabstrip->GetTabAt(index + 1)->IsPointInBounds(point)) {
tabstrip->hover_index_ = index + 1;
}
@@ -498,16 +501,39 @@ gboolean TabStripGtk::OnMotionNotify(GtkWidget* widget, GdkEventMotion* event,
gtk_widget_queue_draw(tabstrip->tabstrip_.get());
}
+ // Forward the mouse movement to the tab. Used to handle close button input.
+ if (tabstrip->hover_index_ != -1) {
+ if (tabstrip->GetTabAt(tabstrip->hover_index_)->OnMotionNotify(point))
+ gtk_widget_queue_draw(tabstrip->tabstrip_.get());
+ }
+
return TRUE;
}
// static
-gboolean TabStripGtk::OnButtonPress(GtkWidget* widget, GdkEventButton* event,
- TabStripGtk* tabstrip) {
- if (tabstrip->hover_index_ != -1 &&
- tabstrip->hover_index_ != tabstrip->model()->selected_index()) {
+gboolean TabStripGtk::OnMousePress(GtkWidget* widget, GdkEventButton* event,
+ TabStripGtk* tabstrip) {
+ // TODO(jhawkins): Handle middle and right-click.
+ // TODO(jhawkins): Are there no gdk constants for event->button?
+ if (tabstrip->hover_index_ == -1 || event->button != 1)
+ return TRUE;
+
+ if (tabstrip->GetTabAt(tabstrip->hover_index_)->OnMousePress())
+ gtk_widget_queue_draw(tabstrip->tabstrip_.get());
+ else if (tabstrip->hover_index_ != tabstrip->model()->selected_index())
tabstrip->model()->SelectTabContentsAt(tabstrip->hover_index_, true);
- }
+
+ return TRUE;
+}
+
+// static
+gboolean TabStripGtk::OnMouseRelease(GtkWidget* widget, GdkEventButton* event,
+ TabStripGtk* tabstrip) {
+ if (event->button != 1)
+ return TRUE;
+
+ if (tabstrip->hover_index_ != -1)
+ tabstrip->GetTabAt(tabstrip->hover_index_)->OnMouseRelease();
return TRUE;
}
diff --git a/chrome/browser/gtk/tabs/tab_strip_gtk.h b/chrome/browser/gtk/tabs/tab_strip_gtk.h
index 6d8f17f..fbff765 100644
--- a/chrome/browser/gtk/tabs/tab_strip_gtk.h
+++ b/chrome/browser/gtk/tabs/tab_strip_gtk.h
@@ -85,8 +85,12 @@ class TabStripGtk : public TabStripModelObserver,
TabStripGtk* tabstrip);
// button-press-event handler that handles mouse clicks.
- static gboolean OnButtonPress(GtkWidget* widget, GdkEventButton* event,
- TabStripGtk* tabstrip);
+ static gboolean OnMousePress(GtkWidget* widget, GdkEventButton* event,
+ TabStripGtk* tabstrip);
+
+ // button-release-event handler that handles mouse click releases.
+ static gboolean OnMouseRelease(GtkWidget* widget, GdkEventButton* event,
+ TabStripGtk* tabstrip);
// leave-notify-event handler that signals when the mouse leaves the tabstrip.
static gboolean OnLeaveNotify(GtkWidget* widget, GdkEventCrossing* event,