summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authoroshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-19 22:43:31 +0000
committeroshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-19 22:43:31 +0000
commit474d7f91ceddff4223df11e42e689934b3988d28 (patch)
treedd9fb9d1e374dabd3aae9375a2756ef8cd7b6040 /chrome/browser
parent29c1498d163ff9a4b476632ebbe5afa396424c21 (diff)
downloadchromium_src-474d7f91ceddff4223df11e42e689934b3988d28.zip
chromium_src-474d7f91ceddff4223df11e42e689934b3988d28.tar.gz
chromium_src-474d7f91ceddff4223df11e42e689934b3988d28.tar.bz2
Don't change the panel state when deleting notifications (and mouse is on the panel)
so that a user can delete multiple notification by clicking mouse on the same position. BUG=33306 TEST=none. I will add tests next week. Review URL: http://codereview.chromium.org/1147003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@42161 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/chromeos/notifications/balloon_view.cc4
-rw-r--r--chrome/browser/chromeos/notifications/balloon_view.h5
-rw-r--r--chrome/browser/chromeos/notifications/notification_panel.cc80
-rw-r--r--chrome/browser/chromeos/notifications/notification_panel.h19
4 files changed, 101 insertions, 7 deletions
diff --git a/chrome/browser/chromeos/notifications/balloon_view.cc b/chrome/browser/chromeos/notifications/balloon_view.cc
index 6b9c4f0..13af28b 100644
--- a/chrome/browser/chromeos/notifications/balloon_view.cc
+++ b/chrome/browser/chromeos/notifications/balloon_view.cc
@@ -45,7 +45,8 @@ BalloonViewImpl::BalloonViewImpl(bool sticky, bool controls)
options_menu_button_(NULL),
stale_(false),
sticky_(sticky),
- controls_(controls) {
+ controls_(controls),
+ closed_by_user_(false) {
// This object is not to be deleted by the views hierarchy,
// as it is owned by the balloon.
set_parent_owned(false);
@@ -114,6 +115,7 @@ void BalloonViewImpl::Update() {
}
void BalloonViewImpl::Close(bool by_user) {
+ closed_by_user_ = by_user;
MessageLoop::current()->PostTask(
FROM_HERE,
method_factory_.NewRunnableMethod(
diff --git a/chrome/browser/chromeos/notifications/balloon_view.h b/chrome/browser/chromeos/notifications/balloon_view.h
index b350b76..61d9e16 100644
--- a/chrome/browser/chromeos/notifications/balloon_view.h
+++ b/chrome/browser/chromeos/notifications/balloon_view.h
@@ -65,6 +65,9 @@ class BalloonViewImpl : public BalloonView,
// True if the notification is sticky.
bool sticky() { return sticky_; }
+ // True if the notification is closed by the dismiss button.
+ bool closed_by_user() { return closed_by_user_; }
+
private:
// views::View interface.
virtual gfx::Size GetPreferredSize() {
@@ -120,6 +123,8 @@ class BalloonViewImpl : public BalloonView,
bool sticky_;
// True if a notification should have info/option/dismiss label/buttons.
bool controls_;
+ // True if the notification is closed by the dismiss button.
+ bool closed_by_user_;
DISALLOW_COPY_AND_ASSIGN(BalloonViewImpl);
};
diff --git a/chrome/browser/chromeos/notifications/notification_panel.cc b/chrome/browser/chromeos/notifications/notification_panel.cc
index 0e76591..a1b5035 100644
--- a/chrome/browser/chromeos/notifications/notification_panel.cc
+++ b/chrome/browser/chromeos/notifications/notification_panel.cc
@@ -32,6 +32,38 @@ const int kStaleTimeoutInSeconds = 10;
using chromeos::BalloonViewImpl;
+class PanelWidget : public views::WidgetGtk {
+ public:
+ explicit PanelWidget(chromeos::NotificationPanel* panel)
+ : WidgetGtk(views::WidgetGtk::TYPE_WINDOW),
+ panel_(panel) {
+ }
+
+ // views::WidgetGtk overrides.
+ virtual gboolean OnMotionNotify(GtkWidget* widget, GdkEventMotion* event) {
+ gboolean result = WidgetGtk::OnMotionNotify(widget, event);
+ panel_->DontUpdatePanelOnStale();
+ return result;
+ }
+
+ virtual gboolean OnLeaveNotify(GtkWidget* widget, GdkEventCrossing* event) {
+ gboolean result = views::WidgetGtk::OnLeaveNotify(widget, event);
+ // Leave notify can happen if the mouse moves into the child gdk window.
+ // Make sure the mouse is outside of the panel.
+ gfx::Point p(event->x_root, event->y_root);
+ gfx::Rect bounds;
+ GetBounds(&bounds, true);
+ if (!bounds.Contains(p)) {
+ panel_->OnMouseLeave();
+ }
+ return result;
+ }
+
+ private:
+ chromeos::NotificationPanel* panel_;
+ DISALLOW_COPY_AND_ASSIGN(PanelWidget);
+};
+
class BalloonSubContainer : public views::View {
public:
explicit BalloonSubContainer(int margin)
@@ -258,7 +290,10 @@ class BalloonContainer : public views::View {
NotificationPanel::NotificationPanel()
: balloon_container_(NULL),
state_(CLOSED),
- task_factory_(this) {
+ task_factory_(this),
+ update_panel_on_mouse_leave_(false),
+ latest_token_(0),
+ stale_token_(0) {
Init();
}
@@ -273,7 +308,7 @@ void NotificationPanel::Show() {
if (!panel_widget_.get()) {
// TODO(oshima): Using window because Popup widget behaves weird
// when resizing. This needs to be investigated.
- panel_widget_.reset(new views::WidgetGtk(views::WidgetGtk::TYPE_WINDOW));
+ panel_widget_.reset(new PanelWidget(this));
gfx::Rect bounds = GetPreferredBounds();
if (bounds.width() < kBalloonMinWidth ||
bounds.height() < kBalloonMinHeight) {
@@ -344,7 +379,13 @@ void NotificationPanel::Remove(Balloon* balloon) {
// no change to the state
if (balloon_container_->GetNotificationCount() == 0)
state_ = CLOSED;
- UpdatePanel(true);
+ if (static_cast<BalloonViewImpl*>(balloon->view())->closed_by_user()) {
+ DontUpdatePanelOnStale();
+ balloon_container_->UpdateBounds();
+ scroll_view_->Layout();
+ } else {
+ UpdatePanel(true);
+ }
}
void NotificationPanel::ResizeNotification(
@@ -396,6 +437,21 @@ void NotificationPanel::OnPanelStateChanged(PanelController::State state) {
}
}
+void NotificationPanel::OnMouseLeave() {
+ if (update_panel_on_mouse_leave_) {
+ // TODO(oshima): We need "AS_IS" state, which simply
+ // keeps the current panel size unless it has less notifications
+ // than it can show.
+ if (balloon_container_->GetStickyNotificationCount() > 0 ||
+ balloon_container_->GetNewNotificationCount() > 0) {
+ state_ = STICKY_AND_NEW;
+ } else {
+ state_ = MINIMIZED;
+ }
+ UpdatePanel(true);
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// NotificationPanel private.
@@ -408,9 +464,12 @@ void NotificationPanel::Init() {
scroll_view_.reset(new views::ScrollView());
scroll_view_->set_parent_owned(false);
scroll_view_->SetContents(balloon_container_);
+ scroll_view_->set_background(
+ views::Background::CreateSolidBackground(SK_ColorWHITE));
}
void NotificationPanel::UpdatePanel(bool contents_changed) {
+ update_panel_on_mouse_leave_ = false;
if (contents_changed) {
balloon_container_->UpdateBounds();
scroll_view_->Layout();
@@ -461,18 +520,29 @@ gfx::Rect NotificationPanel::GetStickyNewBounds() {
return gfx::Rect(0, 0, new_width, new_height);
}
+void NotificationPanel::DontUpdatePanelOnStale() {
+ if (stale_token_ != latest_token_) {
+ stale_token_ = latest_token_;
+ }
+ update_panel_on_mouse_leave_ = true;
+}
+
void NotificationPanel::StartStaleTimer(Balloon* balloon) {
BalloonViewImpl* view = static_cast<BalloonViewImpl*>(balloon->view());
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
task_factory_.NewRunnableMethod(
- &NotificationPanel::OnStale, view),
+ &NotificationPanel::OnStale, view, latest_token_++),
1000 * kStaleTimeoutInSeconds);
}
-void NotificationPanel::OnStale(BalloonViewImpl* view) {
+void NotificationPanel::OnStale(BalloonViewImpl* view, int token) {
if (balloon_container_->HasBalloonView(view) && !view->stale()) {
view->set_stale();
+ // don't update panel on stale
+ if (token < stale_token_) {
+ return;
+ }
if (balloon_container_->GetStickyNotificationCount() > 0) {
state_ = STICKY_AND_NEW;
} else {
diff --git a/chrome/browser/chromeos/notifications/notification_panel.h b/chrome/browser/chromeos/notifications/notification_panel.h
index bbf8740..dfbb47a 100644
--- a/chrome/browser/chromeos/notifications/notification_panel.h
+++ b/chrome/browser/chromeos/notifications/notification_panel.h
@@ -82,6 +82,13 @@ class NotificationPanel : public PanelController::Delegate,
virtual void ClosePanel();
virtual void OnPanelStateChanged(PanelController::State state);
+ // Called when a mouse left the panel window.
+ void OnMouseLeave();
+
+ // Tells that the panel should not update the size or state
+ // when a notification becomes stale.
+ void DontUpdatePanelOnStale();
+
// Returns number of of sticky notifications.
int GetStickyNotificationCount() const;
@@ -113,7 +120,9 @@ class NotificationPanel : public PanelController::Delegate,
// A callback function that is called when the notification
// (that the view is associated with) becomes stale after a timeout.
- void OnStale(BalloonViewImpl* view);
+ // |token| is a unique id assigned to a callback task and is
+ // used to cancel the task.
+ void OnStale(BalloonViewImpl* view, int token);
BalloonContainer* balloon_container_;
scoped_ptr<views::Widget> panel_widget_;
@@ -121,6 +130,14 @@ class NotificationPanel : public PanelController::Delegate,
scoped_ptr<views::ScrollView> scroll_view_;
State state_;
ScopedRunnableMethodFactory<NotificationPanel> task_factory_;
+ bool update_panel_on_mouse_leave_;
+
+ // Task token is an integer value assigned to each task, and
+ // used to cancel the tasks.
+ // The latest task token.
+ int latest_token_;
+ // A task whose token is smaller than this value is stale and skipped.
+ int stale_token_;
DISALLOW_COPY_AND_ASSIGN(NotificationPanel);
};