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