1dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Draws the view for the balloons. 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chromeos/notifications/notification_panel.h" 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include <algorithm> 1021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chromeos/notifications/balloon_collection_impl.h" 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chromeos/notifications/balloon_view.h" 13dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/common/notification_details.h" 14dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/common/notification_source.h" 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h" 1621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "third_party/cros/chromeos_wm_ipc_enums.h" 1772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h" 1872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/resource/resource_bundle.h" 1972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/canvas.h" 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/background.h" 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/controls/native/native_view_host.h" 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/controls/scroll_view.h" 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/widget/root_view.h" 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/widget/widget_gtk.h" 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#define SET_STATE(state) SetState(state, __PRETTY_FUNCTION__) 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Minimum and maximum size of balloon content. 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kBalloonMinWidth = 300; 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kBalloonMaxWidth = 300; 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kBalloonMinHeight = 24; 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kBalloonMaxHeight = 120; 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Maximum height of the notification panel. 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TODO(oshima): Get this from system's metrics. 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kMaxPanelHeight = 400; 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The duration for a new notification to become stale. 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kStaleTimeoutInSeconds = 10; 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing chromeos::BalloonViewImpl; 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing chromeos::NotificationPanel; 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if !defined(NDEBUG) 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// A utility function to convert State enum to string. 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char* ToStr(const NotificationPanel::State state) { 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (state) { 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case NotificationPanel::FULL: 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return "full"; 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case NotificationPanel::KEEP_SIZE: 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return "keep_size"; 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case NotificationPanel::STICKY_AND_NEW: 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return "sticky_new"; 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case NotificationPanel::MINIMIZED: 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return "minimized"; 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case NotificationPanel::CLOSED: 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return "closed"; 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default: 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return "unknown"; 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochchromeos::BalloonViewImpl* GetBalloonViewOf(const Balloon* balloon) { 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return static_cast<chromeos::BalloonViewImpl*>(balloon->view()); 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// A WidgetGtk that covers entire ScrollView's viewport. Without this, 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// all renderer's native gtk widgets are moved one by one via 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// View::VisibleBoundsInRootChanged() notification, which makes 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// scrolling not smooth. 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass ViewportWidget : public views::WidgetGtk { 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch explicit ViewportWidget(chromeos::NotificationPanel* panel) 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : WidgetGtk(views::WidgetGtk::TYPE_CHILD), 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_(panel) { 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void UpdateControl() { 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (last_point_.get()) 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_->OnMouseMotion(*last_point_.get()); 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // views::WidgetGtk overrides. 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual gboolean OnMotionNotify(GtkWidget* widget, GdkEventMotion* event) { 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gboolean result = WidgetGtk::OnMotionNotify(widget, event); 88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen gdouble x = event->x; 89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen gdouble y = event->y; 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The window_contents_' allocation has been moved off the top left 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // corner, so we need to adjust it. 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GtkAllocation alloc = widget->allocation; 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch x -= alloc.x; 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch y -= alloc.y; 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!last_point_.get()) { 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch last_point_.reset(new gfx::Point(x, y)); 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch last_point_->set_x(x); 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch last_point_->set_y(y); 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_->OnMouseMotion(*last_point_.get()); 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return result; 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual gboolean OnLeaveNotify(GtkWidget* widget, GdkEventCrossing* event) { 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gboolean result = views::WidgetGtk::OnLeaveNotify(widget, event); 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Leave notify can happen if the mouse moves into the child gdk window. 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make sure the mouse is outside of the panel. 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Point p(event->x_root, event->y_root); 112dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen gfx::Rect bounds = GetWindowScreenBounds(); 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!bounds.Contains(p)) { 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_->OnMouseLeave(); 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch last_point_.reset(); 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return result; 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch chromeos::NotificationPanel* panel_; 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<gfx::Point> last_point_; 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DISALLOW_COPY_AND_ASSIGN(ViewportWidget); 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass BalloonSubContainer : public views::View { 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch explicit BalloonSubContainer(int margin) 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : margin_(margin) { 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual ~BalloonSubContainer() {} 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // views::View overrides. 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual gfx::Size GetPreferredSize() { 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return preferred_size_; 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void Layout() { 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Layout bottom up 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int height = 0; 14272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen for (int i = child_count() - 1; i >= 0; --i) { 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View* child = GetChildViewAt(i); 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch child->SetBounds(0, height, child->width(), child->height()); 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch height += child->height() + margin_; 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SchedulePaint(); 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Updates the bound so that it can show all balloons. 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void UpdateBounds() { 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int height = 0; 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int max_width = 0; 15472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen for (int i = child_count() - 1; i >= 0; --i) { 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View* child = GetChildViewAt(i); 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch height += child->height() + margin_; 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch max_width = std::max(max_width, child->width()); 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (height > 0) 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch height -= margin_; 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch preferred_size_.set_width(max_width); 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch preferred_size_.set_height(height); 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SizeToPreferredSize(); 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Returns the bounds that covers new notifications. 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect GetNewBounds() { 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect rect; 16972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen for (int i = child_count() - 1; i >= 0; --i) { 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonViewImpl* view = 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<BalloonViewImpl*>(GetChildViewAt(i)); 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!view->stale()) { 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (rect.IsEmpty()) { 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch rect = view->bounds(); 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch rect = rect.Union(view->bounds()); 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return gfx::Rect(x(), y(), rect.width(), rect.height()); 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Returns # of new notifications. 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int GetNewCount() { 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int count = 0; 18672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen for (int i = child_count() - 1; i >= 0; --i) { 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonViewImpl* view = 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<BalloonViewImpl*>(GetChildViewAt(i)); 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!view->stale()) 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch count++; 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return count; 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make all notifications stale. 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void MakeAllStale() { 19772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen for (int i = child_count() - 1; i >= 0; --i) { 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonViewImpl* view = 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<BalloonViewImpl*>(GetChildViewAt(i)); 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view->set_stale(); 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void DismissAll() { 20572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen for (int i = child_count() - 1; i >= 0; --i) { 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonViewImpl* view = 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<BalloonViewImpl*>(GetChildViewAt(i)); 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view->Close(true); 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonViewImpl* FindBalloonView(const Notification& notification) { 21372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen for (int i = child_count() - 1; i >= 0; --i) { 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonViewImpl* view = 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<BalloonViewImpl*>(GetChildViewAt(i)); 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (view->IsFor(notification)) { 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return view; 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return NULL; 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonViewImpl* FindBalloonView(const gfx::Point point) { 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Point copy(point); 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ConvertPointFromWidget(this, ©); 22672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen for (int i = child_count() - 1; i >= 0; --i) { 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View* view = GetChildViewAt(i); 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (view->bounds().Contains(copy)) 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return static_cast<BalloonViewImpl*>(view); 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return NULL; 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Size preferred_size_; 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int margin_; 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DISALLOW_COPY_AND_ASSIGN(BalloonSubContainer); 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace chromeos { 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass BalloonContainer : public views::View { 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 247513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch explicit BalloonContainer(int margin) 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : margin_(margin), 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sticky_container_(new BalloonSubContainer(margin)), 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch non_sticky_container_(new BalloonSubContainer(margin)) { 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AddChildView(sticky_container_); 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AddChildView(non_sticky_container_); 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual ~BalloonContainer() {} 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // views::View overrides. 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void Layout() { 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int margin = 25972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen (sticky_container_->child_count() != 0 && 26072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen non_sticky_container_->child_count() != 0) ? 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch margin_ : 0; 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sticky_container_->SetBounds( 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 0, 0, width(), sticky_container_->height()); 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch non_sticky_container_->SetBounds( 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 0, sticky_container_->bounds().bottom() + margin, 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch width(), non_sticky_container_->height()); 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual gfx::Size GetPreferredSize() { 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return preferred_size_; 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Returns the size that covers sticky and new notifications. 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Size GetStickyNewSize() { 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect sticky = sticky_container_->bounds(); 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect new_non_sticky = non_sticky_container_->GetNewBounds(); 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (sticky.IsEmpty()) 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return new_non_sticky.size(); 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (new_non_sticky.IsEmpty()) 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return sticky.size(); 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return sticky.Union(new_non_sticky).size(); 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Adds a ballon to the panel. 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void Add(Balloon* balloon) { 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonViewImpl* view = GetBalloonViewOf(balloon); 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetContainerFor(balloon)->AddChildView(view); 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Updates the position of the |balloon|. 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool Update(Balloon* balloon) { 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonViewImpl* view = GetBalloonViewOf(balloon); 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch View* container = NULL; 29472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (view->parent() == sticky_container_) { 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch container = sticky_container_; 29672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } else if (view->parent() == non_sticky_container_) { 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch container = non_sticky_container_; 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (container) { 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch container->RemoveChildView(view); 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch container->AddChildView(view); 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Removes a ballon from the panel. 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonViewImpl* Remove(Balloon* balloon) { 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonViewImpl* view = GetBalloonViewOf(balloon); 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetContainerFor(balloon)->RemoveChildView(view); 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return view; 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Returns the number of notifications added to the panel. 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int GetNotificationCount() { 31772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return sticky_container_->child_count() + 31872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen non_sticky_container_->child_count(); 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Returns the # of new notifications. 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int GetNewNotificationCount() { 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return sticky_container_->GetNewCount() + 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch non_sticky_container_->GetNewCount(); 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Returns the # of sticky and new notifications. 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int GetStickyNewNotificationCount() { 32972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return sticky_container_->child_count() + 330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch non_sticky_container_->GetNewCount(); 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Returns the # of sticky notifications. 334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int GetStickyNotificationCount() { 33572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return sticky_container_->child_count(); 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Returns true if the |view| is contained in the panel. 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool HasBalloonView(View* view) { 34072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return view->parent() == sticky_container_ || 34172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen view->parent() == non_sticky_container_; 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Updates the bounds so that all notifications are visible. 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void UpdateBounds() { 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sticky_container_->UpdateBounds(); 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch non_sticky_container_->UpdateBounds(); 348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch preferred_size_ = sticky_container_->GetPreferredSize(); 349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Size non_sticky_size = non_sticky_container_->GetPreferredSize(); 351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int margin = 352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (!preferred_size_.IsEmpty() && !non_sticky_size.IsEmpty()) ? 353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch margin_ : 0; 354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch preferred_size_.Enlarge(0, non_sticky_size.height() + margin); 355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch preferred_size_.set_width(std::max( 356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch preferred_size_.width(), non_sticky_size.width())); 357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SizeToPreferredSize(); 358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void MakeAllStale() { 361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sticky_container_->MakeAllStale(); 362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch non_sticky_container_->MakeAllStale(); 363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void DismissAllNonSticky() { 366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch non_sticky_container_->DismissAll(); 367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonViewImpl* FindBalloonView(const Notification& notification) { 370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonViewImpl* view = sticky_container_->FindBalloonView(notification); 371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return view ? view : non_sticky_container_->FindBalloonView(notification); 372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonViewImpl* FindBalloonView(const gfx::Point& point) { 375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonViewImpl* view = sticky_container_->FindBalloonView(point); 376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return view ? view : non_sticky_container_->FindBalloonView(point); 377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonSubContainer* GetContainerFor(Balloon* balloon) const { 381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonViewImpl* view = GetBalloonViewOf(balloon); 382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return view->sticky() ? 383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch sticky_container_ : non_sticky_container_; 384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int margin_; 387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Sticky/non-sticky ballon containers. They're child views and 388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // deleted when this container is deleted. 389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonSubContainer* sticky_container_; 390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonSubContainer* non_sticky_container_; 391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Size preferred_size_; 392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DISALLOW_COPY_AND_ASSIGN(BalloonContainer); 394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 396c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochNotificationPanel::NotificationPanel() 397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : balloon_container_(NULL), 398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_widget_(NULL), 399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch container_host_(NULL), 400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch state_(CLOSED), 401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch task_factory_(this), 402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch min_bounds_(0, 0, kBalloonMinWidth, kBalloonMinHeight), 403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch stale_timeout_(1000 * kStaleTimeoutInSeconds), 404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_(NULL), 405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scroll_to_(NULL) { 406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Init(); 407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 409c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochNotificationPanel::~NotificationPanel() { 410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Hide(); 411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// NottificationPanel public. 415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanel::Show() { 417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!panel_widget_) { 418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(oshima): Using window because Popup widget behaves weird 419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // when resizing. This needs to be investigated. 420ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen views::WidgetGtk* widget_gtk = 421ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen new views::WidgetGtk(views::WidgetGtk::TYPE_WINDOW); 422ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Enable double buffering because the panel has both pure views 423ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // control and native controls (scroll bar). 424ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen widget_gtk->EnableDoubleBuffer(true); 425ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen panel_widget_ = widget_gtk; 426ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect bounds = GetPreferredBounds(); 428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bounds = bounds.Union(min_bounds_); 429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_widget_->Init(NULL, bounds); 430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Set minimum bounds so that it can grow freely. 431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_set_size_request(GTK_WIDGET(panel_widget_->GetNativeView()), 432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch min_bounds_.width(), min_bounds_.height()); 433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::NativeViewHost* native = new views::NativeViewHost(); 435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scroll_view_->SetContents(native); 436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_widget_->SetContentsView(scroll_view_.get()); 438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Add the view port after scroll_view is attached to the panel widget. 440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ViewportWidget* widget = new ViewportWidget(this); 441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch container_host_ = widget; 442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch container_host_->Init(NULL, gfx::Rect()); 443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch container_host_->SetContentsView(balloon_container_.get()); 444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The window_contents_ is onwed by the WidgetGtk. Increase ref count 445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // so that window_contents does not get deleted when detached. 446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_object_ref(widget->window_contents()); 447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch native->Attach(widget->window_contents()); 448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UnregisterNotification(); 450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_controller_.reset( 451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new PanelController(this, GTK_WINDOW(panel_widget_->GetNativeView()))); 452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_controller_->Init(false /* don't focus when opened */, 453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect(0, 0, kBalloonMinWidth, 1), 0, 454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WM_IPC_PANEL_USER_RESIZE_VERTICALLY); 455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch registrar_.Add(this, NotificationType::PANEL_STATE_CHANGED, 456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<PanelController>(panel_controller_.get())); 457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_widget_->Show(); 459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanel::Hide() { 462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch balloon_container_->DismissAllNonSticky(); 463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (panel_widget_) { 464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch container_host_->GetRootView()->RemoveChildView(balloon_container_.get()); 465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::NativeViewHost* native = 467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<views::NativeViewHost*>(scroll_view_->GetContents()); 468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch native->Detach(); 469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scroll_view_->SetContents(NULL); 470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch container_host_->Hide(); 471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch container_host_->CloseNow(); 472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch container_host_ = NULL; 473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UnregisterNotification(); 475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_controller_->Close(); 476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MessageLoop::current()->DeleteSoon(FROM_HERE, panel_controller_.release()); 477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We need to remove & detach the scroll view from hierarchy to 478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // avoid GTK deleting child. 479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(oshima): handle this details in WidgetGtk. 480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_widget_->GetRootView()->RemoveChildView(scroll_view_.get()); 481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_widget_->Close(); 482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_widget_ = NULL; 483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// BalloonCollectionImpl::NotificationUI overrides. 488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanel::Add(Balloon* balloon) { 490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch balloon_container_->Add(balloon); 491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (state_ == CLOSED || state_ == MINIMIZED) 492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SET_STATE(STICKY_AND_NEW); 493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Show(); 494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Don't resize the panel yet. The panel will be resized when WebKit tells 495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the size in ResizeNotification. 496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UpdatePanel(false); 497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UpdateControl(); 498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StartStaleTimer(balloon); 499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scroll_to_ = balloon; 500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool NotificationPanel::Update(Balloon* balloon) { 503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return balloon_container_->Update(balloon); 504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanel::Remove(Balloon* balloon) { 507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonViewImpl* view = balloon_container_->Remove(balloon); 508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (view == active_) 509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_ = NULL; 510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (scroll_to_ == balloon) 511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scroll_to_ = NULL; 512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(oshima): May be we shouldn't close 514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // if the mouse pointer is still on the panel. 515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (balloon_container_->GetNotificationCount() == 0) 516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SET_STATE(CLOSED); 517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // no change to the state 518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (state_ == KEEP_SIZE) { 519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Just update the content. 520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UpdateContainerBounds(); 521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (state_ != CLOSED && 523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch balloon_container_->GetStickyNewNotificationCount() == 0) 524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SET_STATE(MINIMIZED); 525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UpdatePanel(true); 526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UpdateControl(); 528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanel::Show(Balloon* balloon) { 531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (state_ == CLOSED || state_ == MINIMIZED) 532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SET_STATE(STICKY_AND_NEW); 533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Show(); 534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UpdatePanel(true); 535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StartStaleTimer(balloon); 536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ScrollBalloonToVisible(balloon); 537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanel::ResizeNotification( 540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Balloon* balloon, const gfx::Size& size) { 541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // restrict to the min & max sizes 542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Size real_size( 543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::max(kBalloonMinWidth, 544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::min(kBalloonMaxWidth, size.width())), 545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::max(kBalloonMinHeight, 546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::min(kBalloonMaxHeight, size.height()))); 547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Don't allow balloons to shrink. This avoids flickering 549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // which sometimes rapidly reports alternating sizes. Special 550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // case for setting the minimum value. 551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Size old_size = balloon->content_size(); 552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (real_size.width() > old_size.width() || 553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch real_size.height() > old_size.height() || 554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch real_size == min_bounds_.size()) { 555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch balloon->set_content_size(real_size); 556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetBalloonViewOf(balloon)->Layout(); 557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UpdatePanel(true); 558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (scroll_to_ == balloon) { 559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ScrollBalloonToVisible(scroll_to_); 560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scroll_to_ = NULL; 561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanel::SetActiveView(BalloonViewImpl* view) { 566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Don't change the active view if it's same notification, 567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // or the notification is being closed. 568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (active_ == view || (view && view->closed())) 569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (active_) 571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_->Deactivated(); 572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_ = view; 573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (active_) 574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_->Activated(); 575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// PanelController overrides. 579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstring16 NotificationPanel::GetPanelTitle() { 581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return string16(l10n_util::GetStringUTF16(IDS_NOTIFICATION_PANEL_TITLE)); 582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 584c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSkBitmap NotificationPanel::GetPanelIcon() { 585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return SkBitmap(); 586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 58872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool NotificationPanel::CanClosePanel() { 58972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return true; 59072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 59172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanel::ClosePanel() { 593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SET_STATE(CLOSED); 594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UpdatePanel(false); 595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 597ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid NotificationPanel::ActivatePanel() { 598ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (active_) 599ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen active_->Activated(); 600ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 601ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// NotificationObserver overrides. 604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanel::Observe(NotificationType type, 606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationSource& source, 607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationDetails& details) { 608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(type == NotificationType::PANEL_STATE_CHANGED); 609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PanelController::State* state = 610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch reinterpret_cast<PanelController::State*>(details.map_key()); 611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (*state) { 612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case PanelController::EXPANDED: 613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Geting expanded in STICKY_AND_NEW or in KEEP_SIZE state means 614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // that a new notification is added, so just leave the 615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // state. Otherwise, expand to full. 616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (state_ != STICKY_AND_NEW && state_ != KEEP_SIZE) 617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SET_STATE(FULL); 618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // When the panel is to be expanded, we either show all, or 619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // show only sticky/new, depending on the state. 620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UpdatePanel(false); 621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case PanelController::MINIMIZED: 623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SET_STATE(MINIMIZED); 624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make all notifications stale when a user minimize the panel. 625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch balloon_container_->MakeAllStale(); 626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case PanelController::INITIAL: 628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << "Transition to Initial state should not happen"; 629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// PanelController public. 634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanel::OnMouseLeave() { 636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetActiveView(NULL); 637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (balloon_container_->GetNotificationCount() == 0) 638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SET_STATE(CLOSED); 639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UpdatePanel(true); 640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanel::OnMouseMotion(const gfx::Point& point) { 643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetActiveView(balloon_container_->FindBalloonView(point)); 644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SET_STATE(KEEP_SIZE); 645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 647c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochNotificationPanelTester* NotificationPanel::GetTester() { 648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!tester_.get()) 649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tester_.reset(new NotificationPanelTester(this)); 650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return tester_.get(); 651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// NotificationPanel private. 655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanel::Init() { 657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!panel_widget_); 658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch balloon_container_.reset(new BalloonContainer(1)); 659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch balloon_container_->set_parent_owned(false); 660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch balloon_container_->set_background( 661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::Background::CreateSolidBackground(ResourceBundle::frame_color)); 662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scroll_view_.reset(new views::ScrollView()); 664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scroll_view_->set_parent_owned(false); 665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scroll_view_->set_background( 666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::Background::CreateSolidBackground(SK_ColorWHITE)); 667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanel::UnregisterNotification() { 670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (panel_controller_.get()) 671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch registrar_.Remove(this, NotificationType::PANEL_STATE_CHANGED, 672c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<PanelController>(panel_controller_.get())); 673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 674c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 675c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanel::ScrollBalloonToVisible(Balloon* balloon) { 676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonViewImpl* view = GetBalloonViewOf(balloon); 677c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!view->closed()) { 678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We can't use View::ScrollRectToVisible because the viewport is not 679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // ancestor of the BalloonViewImpl. 680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Use Widget's coordinate which is same as viewport's coordinates. 681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Point p(0, 0); 682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View::ConvertPointToWidget(view, &p); 683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect visible_rect(p.x(), p.y(), view->width(), view->height()); 684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scroll_view_->ScrollContentsRegionToBeVisible(visible_rect); 685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanel::UpdatePanel(bool update_container_size) { 689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (update_container_size) 690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UpdateContainerBounds(); 691513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch switch (state_) { 692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case KEEP_SIZE: { 693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect min_bounds = GetPreferredBounds(); 694dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen gfx::Rect panel_bounds = panel_widget_->GetWindowScreenBounds(); 695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (min_bounds.height() < panel_bounds.height()) 696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_widget_->SetBounds(min_bounds); 697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else if (min_bounds.height() > panel_bounds.height()) { 698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // need scroll bar 699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int width = balloon_container_->width() + 700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scroll_view_->GetScrollBarWidth(); 701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_bounds.set_width(width); 702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_widget_->SetBounds(panel_bounds); 703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // no change. 706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case CLOSED: 709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Hide(); 710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case MINIMIZED: 712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch balloon_container_->MakeAllStale(); 713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (panel_controller_.get()) 714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_controller_->SetState(PanelController::MINIMIZED); 715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 716c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case FULL: 717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (panel_widget_) { 718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_widget_->SetBounds(GetPreferredBounds()); 719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_controller_->SetState(PanelController::EXPANDED); 720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case STICKY_AND_NEW: 723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (panel_widget_) { 724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_widget_->SetBounds(GetStickyNewBounds()); 725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_controller_->SetState(PanelController::EXPANDED); 726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 731c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanel::UpdateContainerBounds() { 732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch balloon_container_->UpdateBounds(); 733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::NativeViewHost* native = 734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<views::NativeViewHost*>(scroll_view_->GetContents()); 735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Update from WebKit may arrive after the panel is closed/hidden 736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // and viewport widget is detached. 737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (native) { 73872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen native->SetBoundsRect(balloon_container_->bounds()); 739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scroll_view_->Layout(); 740c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 741c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanel::UpdateControl() { 744c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (container_host_) 745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<ViewportWidget*>(container_host_)->UpdateControl(); 746c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Rect NotificationPanel::GetPreferredBounds() { 749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Size pref_size = balloon_container_->GetPreferredSize(); 750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int new_height = std::min(pref_size.height(), kMaxPanelHeight); 751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int new_width = pref_size.width(); 752c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Adjust the width to avoid showing a horizontal scroll bar. 753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (new_height != pref_size.height()) { 754c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_width += scroll_view_->GetScrollBarWidth(); 755c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return gfx::Rect(0, 0, new_width, new_height).Union(min_bounds_); 757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Rect NotificationPanel::GetStickyNewBounds() { 760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Size pref_size = balloon_container_->GetPreferredSize(); 761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Size sticky_size = balloon_container_->GetStickyNewSize(); 762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int new_height = std::min(sticky_size.height(), kMaxPanelHeight); 763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int new_width = pref_size.width(); 764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Adjust the width to avoid showing a horizontal scroll bar. 765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (new_height != pref_size.height()) 766c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch new_width += scroll_view_->GetScrollBarWidth(); 767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return gfx::Rect(0, 0, new_width, new_height).Union(min_bounds_); 768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 769c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 770c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanel::StartStaleTimer(Balloon* balloon) { 771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonViewImpl* view = GetBalloonViewOf(balloon); 772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MessageLoop::current()->PostDelayedTask( 773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FROM_HERE, 774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch task_factory_.NewRunnableMethod( 775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &NotificationPanel::OnStale, view), 776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch stale_timeout_); 777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanel::OnStale(BalloonViewImpl* view) { 780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (balloon_container_->HasBalloonView(view) && !view->stale()) { 781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view->set_stale(); 782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // don't update panel on stale 783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (state_ == KEEP_SIZE) 784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (balloon_container_->GetStickyNewNotificationCount() > 0) { 786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SET_STATE(STICKY_AND_NEW); 787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 788c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SET_STATE(MINIMIZED); 789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UpdatePanel(false); 791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanel::SetState(State new_state, const char* name) { 795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if !defined(NDEBUG) 796513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch DVLOG(1) << "state transition " << ToStr(state_) << " >> " << ToStr(new_state) 797513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch << " in " << name; 798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch state_ = new_state; 800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanel::MarkStale(const Notification& notification) { 803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonViewImpl* view = balloon_container_->FindBalloonView(notification); 804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(view); 805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch OnStale(view); 806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// NotificationPanelTester public. 810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint NotificationPanelTester::GetNotificationCount() const { 812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return panel_->balloon_container_->GetNotificationCount(); 813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint NotificationPanelTester::GetStickyNotificationCount() const { 816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return panel_->balloon_container_->GetStickyNotificationCount(); 817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint NotificationPanelTester::GetNewNotificationCount() const { 820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return panel_->balloon_container_->GetNewNotificationCount(); 821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 823c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanelTester::SetStaleTimeout(int timeout) { 824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_->stale_timeout_ = timeout; 825c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid NotificationPanelTester::MarkStale(const Notification& notification) { 828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch panel_->MarkStale(notification); 829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 830c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 831c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochPanelController* NotificationPanelTester::GetPanelController() const { 832c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return panel_->panel_controller_.get(); 833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 835c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBalloonViewImpl* NotificationPanelTester::GetBalloonView( 836c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BalloonCollectionImpl* collection, 837c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const Notification& notification) { 838201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch Balloon* balloon = collection->FindBalloon(notification); 839201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch DCHECK(balloon); 840c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return GetBalloonViewOf(balloon); 841c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 842c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 843c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool NotificationPanelTester::IsVisible(const BalloonViewImpl* view) const { 844c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect rect = panel_->scroll_view_->GetVisibleRect(); 845c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Point origin(0, 0); 846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View::ConvertPointToView(view, panel_->balloon_container_.get(), 847c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &origin); 84872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return rect.Contains(gfx::Rect(origin, view->size())); 849c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 851c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 852c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool NotificationPanelTester::IsActive(const BalloonViewImpl* view) const { 853c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return panel_->active_ == view; 854c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 855c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 856c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace chromeos 857