OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ash/system/tray/system_tray.h" | 5 #include "ash/system/tray/system_tray.h" |
6 | 6 |
7 #include "ash/shell.h" | 7 #include "ash/shell.h" |
8 #include "ash/shell/panel_window.h" | 8 #include "ash/shell/panel_window.h" |
9 #include "ash/shell_window_ids.h" | 9 #include "ash/shell_window_ids.h" |
10 #include "ash/system/audio/tray_volume.h" | 10 #include "ash/system/audio/tray_volume.h" |
11 #include "ash/system/bluetooth/tray_bluetooth.h" | 11 #include "ash/system/bluetooth/tray_bluetooth.h" |
12 #include "ash/system/brightness/tray_brightness.h" | 12 #include "ash/system/brightness/tray_brightness.h" |
13 #include "ash/system/date/tray_date.h" | 13 #include "ash/system/date/tray_date.h" |
14 #include "ash/system/drive/tray_drive.h" | 14 #include "ash/system/drive/tray_drive.h" |
15 #include "ash/system/ime/tray_ime.h" | 15 #include "ash/system/ime/tray_ime.h" |
16 #include "ash/system/network/tray_network.h" | 16 #include "ash/system/network/tray_network.h" |
17 #include "ash/system/power/power_status_observer.h" | 17 #include "ash/system/power/power_status_observer.h" |
18 #include "ash/system/power/power_supply_status.h" | 18 #include "ash/system/power/power_supply_status.h" |
19 #include "ash/system/power/tray_power.h" | 19 #include "ash/system/power/tray_power.h" |
20 #include "ash/system/settings/tray_settings.h" | 20 #include "ash/system/settings/tray_settings.h" |
| 21 #include "ash/system/tray/system_tray_bubble.h" |
21 #include "ash/system/tray/system_tray_delegate.h" | 22 #include "ash/system/tray/system_tray_delegate.h" |
22 #include "ash/system/tray/system_tray_item.h" | 23 #include "ash/system/tray/system_tray_item.h" |
23 #include "ash/system/tray/system_tray_widget_delegate.h" | 24 #include "ash/system/tray/system_tray_widget_delegate.h" |
24 #include "ash/system/tray/tray_constants.h" | 25 #include "ash/system/tray/tray_constants.h" |
25 #include "ash/system/tray/tray_empty.h" | 26 #include "ash/system/tray/tray_empty.h" |
26 #include "ash/system/tray_accessibility.h" | 27 #include "ash/system/tray_accessibility.h" |
27 #include "ash/system/tray_caps_lock.h" | 28 #include "ash/system/tray_caps_lock.h" |
28 #include "ash/system/tray_update.h" | 29 #include "ash/system/tray_update.h" |
29 #include "ash/system/user/login_status.h" | 30 #include "ash/system/user/login_status.h" |
30 #include "ash/system/user/tray_user.h" | 31 #include "ash/system/user/tray_user.h" |
31 #include "ash/wm/shadow_types.h" | |
32 #include "ash/wm/shelf_layout_manager.h" | 32 #include "ash/wm/shelf_layout_manager.h" |
33 #include "ash/wm/window_animations.h" | |
34 #include "base/i18n/rtl.h" | 33 #include "base/i18n/rtl.h" |
35 #include "base/logging.h" | 34 #include "base/logging.h" |
36 #include "base/message_loop.h" | |
37 #include "base/message_pump_observer.h" | |
38 #include "base/timer.h" | 35 #include "base/timer.h" |
39 #include "base/utf_string_conversions.h" | 36 #include "base/utf_string_conversions.h" |
40 #include "grit/ash_strings.h" | 37 #include "grit/ash_strings.h" |
41 #include "third_party/skia/include/core/SkCanvas.h" | |
42 #include "third_party/skia/include/core/SkColor.h" | |
43 #include "third_party/skia/include/core/SkPaint.h" | |
44 #include "third_party/skia/include/core/SkPath.h" | |
45 #include "third_party/skia/include/effects/SkBlurImageFilter.h" | |
46 #include "ui/aura/root_window.h" | 38 #include "ui/aura/root_window.h" |
47 #include "ui/base/accessibility/accessible_view_state.h" | 39 #include "ui/base/accessibility/accessible_view_state.h" |
48 #include "ui/base/events.h" | 40 #include "ui/base/events.h" |
49 #include "ui/base/l10n/l10n_util.h" | 41 #include "ui/base/l10n/l10n_util.h" |
50 #include "ui/compositor/layer.h" | |
51 #include "ui/gfx/canvas.h" | 42 #include "ui/gfx/canvas.h" |
52 #include "ui/gfx/screen.h" | |
53 #include "ui/gfx/skia_util.h" | 43 #include "ui/gfx/skia_util.h" |
54 #include "ui/views/border.h" | 44 #include "ui/views/border.h" |
55 #include "ui/views/bubble/bubble_border.h" | |
56 #include "ui/views/bubble/bubble_delegate.h" | |
57 #include "ui/views/bubble/bubble_frame_view.h" | |
58 #include "ui/views/controls/label.h" | 45 #include "ui/views/controls/label.h" |
59 #include "ui/views/layout/box_layout.h" | 46 #include "ui/views/layout/box_layout.h" |
60 #include "ui/views/layout/fill_layout.h" | 47 #include "ui/views/layout/fill_layout.h" |
61 #include "ui/views/view.h" | 48 #include "ui/views/view.h" |
62 #include "ui/views/widget/widget.h" | 49 #include "ui/views/widget/widget.h" |
63 | 50 |
64 namespace ash { | 51 namespace ash { |
65 | 52 |
66 namespace { | 53 namespace { |
67 | 54 |
68 const int kPaddingFromRightEdgeOfScreen = 15; | |
69 const int kPaddingFromBottomOfScreen = 10; | |
70 | |
71 const int kAnimationDurationForPopupMS = 200; | |
72 | |
73 const int kArrowHeight = 10; | |
74 const int kArrowWidth = 20; | |
75 const int kArrowPaddingFromRight = 20; | |
76 | |
77 const int kShadowThickness = 4; | |
78 | |
79 const int kLeftPadding = 4; | |
80 const int kBottomLineHeight = 1; | |
81 | |
82 const SkColor kShadowColor = SkColorSetARGB(0xff, 0, 0, 0); | |
83 | |
84 const SkColor kTrayBackgroundAlpha = 100; | 55 const SkColor kTrayBackgroundAlpha = 100; |
85 const SkColor kTrayBackgroundHoverAlpha = 150; | 56 const SkColor kTrayBackgroundHoverAlpha = 150; |
86 | 57 |
87 void DrawBlurredShadowAroundView(gfx::Canvas* canvas, | |
88 int top, | |
89 int bottom, | |
90 int width, | |
91 const gfx::Insets& inset) { | |
92 SkPath path; | |
93 path.incReserve(4); | |
94 path.moveTo(SkIntToScalar(inset.left() + kShadowThickness), | |
95 SkIntToScalar(top + kShadowThickness + 1)); | |
96 path.lineTo(SkIntToScalar(inset.left() + kShadowThickness), | |
97 SkIntToScalar(bottom)); | |
98 path.lineTo(SkIntToScalar(width), | |
99 SkIntToScalar(bottom)); | |
100 path.lineTo(SkIntToScalar(width), | |
101 SkIntToScalar(top + kShadowThickness + 1)); | |
102 | |
103 SkPaint paint; | |
104 paint.setColor(kShadowColor); | |
105 paint.setStyle(SkPaint::kStroke_Style); | |
106 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); | |
107 paint.setStrokeWidth(SkIntToScalar(3)); | |
108 paint.setImageFilter(new SkBlurImageFilter( | |
109 SkIntToScalar(3), SkIntToScalar(3)))->unref(); | |
110 canvas->sk_canvas()->drawPath(path, paint); | |
111 } | |
112 | |
113 // A view with some special behaviour for tray items in the popup: | |
114 // - changes background color on hover. | |
115 class TrayPopupItemContainer : public views::View { | |
116 public: | |
117 explicit TrayPopupItemContainer(views::View* view) : hover_(false) { | |
118 set_notify_enter_exit_on_child(true); | |
119 set_border(view->border() ? views::Border::CreateEmptyBorder(0, 0, 0, 0) : | |
120 NULL); | |
121 SetLayoutManager(new views::FillLayout); | |
122 SetPaintToLayer(view->layer() != NULL); | |
123 if (view->layer()) | |
124 SetFillsBoundsOpaquely(view->layer()->fills_bounds_opaquely()); | |
125 AddChildView(view); | |
126 SetVisible(view->visible()); | |
127 } | |
128 | |
129 virtual ~TrayPopupItemContainer() {} | |
130 | |
131 private: | |
132 // Overridden from views::View. | |
133 virtual void ChildVisibilityChanged(View* child) OVERRIDE { | |
134 if (visible() == child->visible()) | |
135 return; | |
136 SetVisible(child->visible()); | |
137 PreferredSizeChanged(); | |
138 } | |
139 | |
140 virtual void ChildPreferredSizeChanged(View* child) OVERRIDE { | |
141 PreferredSizeChanged(); | |
142 } | |
143 | |
144 virtual void OnMouseEntered(const views::MouseEvent& event) OVERRIDE { | |
145 hover_ = true; | |
146 SchedulePaint(); | |
147 } | |
148 | |
149 virtual void OnMouseExited(const views::MouseEvent& event) OVERRIDE { | |
150 hover_ = false; | |
151 SchedulePaint(); | |
152 } | |
153 | |
154 virtual void OnPaintBackground(gfx::Canvas* canvas) OVERRIDE { | |
155 if (child_count() == 0) | |
156 return; | |
157 | |
158 views::View* view = child_at(0); | |
159 if (!view->background()) { | |
160 canvas->FillRect(gfx::Rect(size()), | |
161 hover_ ? kHoverBackgroundColor : kBackgroundColor); | |
162 } | |
163 } | |
164 | |
165 bool hover_; | |
166 | |
167 DISALLOW_COPY_AND_ASSIGN(TrayPopupItemContainer); | |
168 }; | |
169 | |
170 class SystemTrayBubbleBackground : public views::Background { | |
171 public: | |
172 explicit SystemTrayBubbleBackground(views::View* owner) | |
173 : owner_(owner) { | |
174 } | |
175 | |
176 virtual ~SystemTrayBubbleBackground() {} | |
177 | |
178 private: | |
179 // Overridden from views::Background. | |
180 virtual void Paint(gfx::Canvas* canvas, views::View* view) const OVERRIDE { | |
181 views::View* last_view = NULL; | |
182 for (int i = 0; i < owner_->child_count(); i++) { | |
183 views::View* v = owner_->child_at(i); | |
184 | |
185 if (!v->border()) { | |
186 canvas->DrawLine(gfx::Point(v->x(), v->y() - 1), | |
187 gfx::Point(v->x() + v->width(), v->y() - 1), | |
188 !last_view || last_view->border() ? kBorderDarkColor : | |
189 kBorderLightColor); | |
190 canvas->DrawLine(gfx::Point(v->x() - 1, v->y() - 1), | |
191 gfx::Point(v->x() - 1, v->y() + v->height() + 1), | |
192 kBorderDarkColor); | |
193 canvas->DrawLine(gfx::Point(v->x() + v->width(), v->y() - 1), | |
194 gfx::Point(v->x() + v->width(), v->y() + v->height() + 1), | |
195 kBorderDarkColor); | |
196 } else if (last_view && !last_view->border()) { | |
197 canvas->DrawLine(gfx::Point(v->x() - 1, v->y() - 1), | |
198 gfx::Point(v->x() + v->width() + 1, v->y() - 1), | |
199 kBorderDarkColor); | |
200 } | |
201 | |
202 last_view = v; | |
203 } | |
204 } | |
205 | |
206 views::View* owner_; | |
207 | |
208 DISALLOW_COPY_AND_ASSIGN(SystemTrayBubbleBackground); | |
209 }; | |
210 | |
211 class SystemTrayBubbleBorder : public views::BubbleBorder { | |
212 public: | |
213 enum ArrowType { | |
214 ARROW_TYPE_NONE, | |
215 ARROW_TYPE_BOTTOM, | |
216 }; | |
217 | |
218 SystemTrayBubbleBorder(views::View* owner, ArrowType arrow_type) | |
219 : views::BubbleBorder(views::BubbleBorder::BOTTOM_RIGHT, | |
220 views::BubbleBorder::NO_SHADOW), | |
221 owner_(owner), | |
222 arrow_type_(arrow_type) { | |
223 set_alignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); | |
224 } | |
225 | |
226 virtual ~SystemTrayBubbleBorder() {} | |
227 | |
228 private: | |
229 // Overridden from views::Border. | |
230 virtual void Paint(const views::View& view, | |
231 gfx::Canvas* canvas) const OVERRIDE { | |
232 views::View* first = NULL, *last = NULL; | |
233 gfx::Insets inset; | |
234 GetInsets(&inset); | |
235 for (int i = 0; i < owner_->child_count(); i++) { | |
236 views::View* v = owner_->child_at(i); | |
237 if (v->border()) { | |
238 if (first) { | |
239 DrawBlurredShadowAroundView(canvas, first->y(), | |
240 last->y() + last->height(), owner_->width(), inset); | |
241 first = NULL; | |
242 last = NULL; | |
243 } | |
244 continue; | |
245 } | |
246 | |
247 if (!first) | |
248 first = v; | |
249 last = v; | |
250 } | |
251 if (first) { | |
252 DrawBlurredShadowAroundView(canvas, first->y(), | |
253 last->y() + last->height(), owner_->width(), inset); | |
254 } | |
255 | |
256 // Draw the bottom line. | |
257 int y = owner_->height() + 1; | |
258 canvas->FillRect(gfx::Rect(kLeftPadding, y, owner_->width(), | |
259 kBottomLineHeight), kBorderDarkColor); | |
260 | |
261 if (!Shell::GetInstance()->shelf()->IsVisible()) | |
262 return; | |
263 | |
264 // Draw the arrow. | |
265 if (arrow_type_ == ARROW_TYPE_BOTTOM) { | |
266 int left_base_x = base::i18n::IsRTL() ? kArrowWidth : | |
267 owner_->width() - kArrowPaddingFromRight - kArrowWidth; | |
268 int left_base_y = y; | |
269 int tip_x = left_base_x + kArrowWidth / 2; | |
270 int tip_y = left_base_y + kArrowHeight; | |
271 SkPath path; | |
272 path.incReserve(4); | |
273 path.moveTo(SkIntToScalar(left_base_x), SkIntToScalar(left_base_y)); | |
274 path.lineTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y)); | |
275 path.lineTo(SkIntToScalar(left_base_x + kArrowWidth), | |
276 SkIntToScalar(left_base_y)); | |
277 | |
278 SkPaint paint; | |
279 paint.setStyle(SkPaint::kFill_Style); | |
280 paint.setColor(kBackgroundColor); | |
281 canvas->DrawPath(path, paint); | |
282 | |
283 // Now draw the arrow border. | |
284 paint.setStyle(SkPaint::kStroke_Style); | |
285 paint.setColor(kBorderDarkColor); | |
286 canvas->DrawPath(path, paint); | |
287 } | |
288 } | |
289 | |
290 views::View* owner_; | |
291 ArrowType arrow_type_; | |
292 | |
293 DISALLOW_COPY_AND_ASSIGN(SystemTrayBubbleBorder); | |
294 }; | |
295 | |
296 } // namespace | 58 } // namespace |
297 | 59 |
298 namespace internal { | 60 namespace internal { |
299 | 61 |
300 class SystemTrayBackground : public views::Background { | 62 class SystemTrayBackground : public views::Background { |
301 public: | 63 public: |
302 SystemTrayBackground() : alpha_(kTrayBackgroundAlpha) {} | 64 SystemTrayBackground() : alpha_(kTrayBackgroundAlpha) {} |
303 virtual ~SystemTrayBackground() {} | 65 virtual ~SystemTrayBackground() {} |
304 | 66 |
305 void set_alpha(int alpha) { alpha_ = alpha; } | 67 void set_alpha(int alpha) { alpha_ = alpha; } |
(...skipping 10 matching lines...) Expand all Loading... |
316 SkScalar radius = SkIntToScalar(kTrayRoundedBorderRadius); | 78 SkScalar radius = SkIntToScalar(kTrayRoundedBorderRadius); |
317 path.addRoundRect(gfx::RectToSkRect(bounds), radius, radius); | 79 path.addRoundRect(gfx::RectToSkRect(bounds), radius, radius); |
318 canvas->DrawPath(path, paint); | 80 canvas->DrawPath(path, paint); |
319 } | 81 } |
320 | 82 |
321 int alpha_; | 83 int alpha_; |
322 | 84 |
323 DISALLOW_COPY_AND_ASSIGN(SystemTrayBackground); | 85 DISALLOW_COPY_AND_ASSIGN(SystemTrayBackground); |
324 }; | 86 }; |
325 | 87 |
326 class SystemTrayBubble; | |
327 | |
328 class SystemTrayBubbleView : public views::BubbleDelegateView { | |
329 public: | |
330 SystemTrayBubbleView(views::View* anchor, | |
331 SystemTrayBubble* host, | |
332 bool can_activate); | |
333 virtual ~SystemTrayBubbleView(); | |
334 | |
335 void SetBubbleBorder(views::BubbleBorder* border) { | |
336 GetBubbleFrameView()->SetBubbleBorder(border); | |
337 } | |
338 | |
339 void UpdateAnchor() { | |
340 SizeToContents(); | |
341 GetWidget()->GetRootView()->SchedulePaint(); | |
342 } | |
343 | |
344 // Called when the host is destroyed. | |
345 void reset_host() { host_ = NULL; } | |
346 | |
347 private: | |
348 // Overridden from views::BubbleDelegateView. | |
349 virtual void Init() OVERRIDE; | |
350 virtual gfx::Rect GetAnchorRect() OVERRIDE; | |
351 // Overridden from views::View. | |
352 virtual void ChildPreferredSizeChanged(View* child) OVERRIDE; | |
353 virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE; | |
354 virtual bool CanActivate() const OVERRIDE; | |
355 virtual gfx::Size GetPreferredSize() OVERRIDE; | |
356 virtual void OnMouseEntered(const views::MouseEvent& event) OVERRIDE; | |
357 virtual void OnMouseExited(const views::MouseEvent& event) OVERRIDE; | |
358 | |
359 SystemTrayBubble* host_; | |
360 bool can_activate_; | |
361 | |
362 DISALLOW_COPY_AND_ASSIGN(SystemTrayBubbleView); | |
363 }; | |
364 | |
365 class SystemTrayBubble : public base::MessagePumpObserver, | |
366 public views::Widget::Observer { | |
367 public: | |
368 enum BubbleType { | |
369 BUBBLE_TYPE_DEFAULT, | |
370 BUBBLE_TYPE_DETAILED, | |
371 BUBBLE_TYPE_NOTIFICATION | |
372 }; | |
373 | |
374 enum AnchorType { | |
375 ANCHOR_TYPE_TRAY, | |
376 ANCHOR_TYPE_BUBBLE | |
377 }; | |
378 | |
379 SystemTrayBubble(ash::SystemTray* tray, | |
380 const std::vector<ash::SystemTrayItem*>& items, | |
381 BubbleType bubble_type); | |
382 virtual ~SystemTrayBubble(); | |
383 | |
384 // Creates |bubble_view_| and a child views for each member of |items_|. | |
385 // Also creates |bubble_widget_| and sets up animations. | |
386 void InitView(views::View* anchor, | |
387 AnchorType anchor_type, | |
388 bool can_activate, | |
389 ash::user::LoginStatus login_status); | |
390 | |
391 gfx::Rect GetAnchorRect() const; | |
392 | |
393 BubbleType bubble_type() const { return bubble_type_; } | |
394 SystemTrayBubbleView* bubble_view() const { return bubble_view_; } | |
395 | |
396 void DestroyItemViews(); | |
397 void StartAutoCloseTimer(int seconds); | |
398 void StopAutoCloseTimer(); | |
399 void RestartAutoCloseTimer(); | |
400 void Close(); | |
401 | |
402 private: | |
403 // Overridden from base::MessagePumpObserver. | |
404 virtual base::EventStatus WillProcessEvent( | |
405 const base::NativeEvent& event) OVERRIDE; | |
406 virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE; | |
407 // Overridden from views::Widget::Observer. | |
408 virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE; | |
409 virtual void OnWidgetVisibilityChanged(views::Widget* widget, | |
410 bool visible) OVERRIDE; | |
411 | |
412 ash::SystemTray* tray_; | |
413 SystemTrayBubbleView* bubble_view_; | |
414 views::Widget* bubble_widget_; | |
415 std::vector<ash::SystemTrayItem*> items_; | |
416 BubbleType bubble_type_; | |
417 AnchorType anchor_type_; | |
418 | |
419 int autoclose_delay_; | |
420 base::OneShotTimer<SystemTrayBubble> autoclose_; | |
421 | |
422 DISALLOW_COPY_AND_ASSIGN(SystemTrayBubble); | |
423 }; | |
424 | |
425 // SystemTrayBubbleView | |
426 | |
427 SystemTrayBubbleView::SystemTrayBubbleView(views::View* anchor, | |
428 SystemTrayBubble* host, | |
429 bool can_activate) | |
430 : views::BubbleDelegateView(anchor, views::BubbleBorder::BOTTOM_RIGHT), | |
431 host_(host), | |
432 can_activate_(can_activate) { | |
433 set_margin(0); | |
434 set_parent_window(ash::Shell::GetInstance()->GetContainer( | |
435 ash::internal::kShellWindowId_SettingBubbleContainer)); | |
436 set_notify_enter_exit_on_child(true); | |
437 } | |
438 | |
439 SystemTrayBubbleView::~SystemTrayBubbleView() { | |
440 // Inform host items (models) that their views are being destroyed. | |
441 if (host_) | |
442 host_->DestroyItemViews(); | |
443 } | |
444 | |
445 void SystemTrayBubbleView::Init() { | |
446 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 1, 1, 1)); | |
447 set_background(new SystemTrayBubbleBackground(this)); | |
448 } | |
449 | |
450 gfx::Rect SystemTrayBubbleView::GetAnchorRect() { | |
451 gfx::Rect rect; | |
452 if (host_) | |
453 rect = host_->GetAnchorRect(); | |
454 if (rect.IsEmpty()) { | |
455 rect = gfx::Screen::GetPrimaryMonitor().bounds(); | |
456 rect = gfx::Rect(base::i18n::IsRTL() ? kPaddingFromRightEdgeOfScreen : | |
457 rect.width() - kPaddingFromRightEdgeOfScreen, | |
458 rect.height() - kPaddingFromBottomOfScreen, | |
459 0, 0); | |
460 } | |
461 return rect; | |
462 } | |
463 | |
464 void SystemTrayBubbleView::ChildPreferredSizeChanged(View* child) { | |
465 SizeToContents(); | |
466 } | |
467 | |
468 void SystemTrayBubbleView::GetAccessibleState(ui::AccessibleViewState* state) { | |
469 if (can_activate_) { | |
470 state->role = ui::AccessibilityTypes::ROLE_WINDOW; | |
471 state->name = l10n_util::GetStringUTF16( | |
472 IDS_ASH_STATUS_TRAY_ACCESSIBLE_NAME); | |
473 } | |
474 } | |
475 | |
476 bool SystemTrayBubbleView::CanActivate() const { | |
477 return can_activate_; | |
478 } | |
479 | |
480 gfx::Size SystemTrayBubbleView::GetPreferredSize() { | |
481 gfx::Size size = views::BubbleDelegateView::GetPreferredSize(); | |
482 return gfx::Size(kTrayPopupWidth, size.height()); | |
483 } | |
484 | |
485 void SystemTrayBubbleView::OnMouseEntered(const views::MouseEvent& event) { | |
486 if (host_) | |
487 host_->StopAutoCloseTimer(); | |
488 } | |
489 | |
490 void SystemTrayBubbleView::OnMouseExited(const views::MouseEvent& event) { | |
491 if (host_) | |
492 host_->RestartAutoCloseTimer(); | |
493 } | |
494 | |
495 // SystemTrayBubble | |
496 | |
497 SystemTrayBubble::SystemTrayBubble( | |
498 ash::SystemTray* tray, | |
499 const std::vector<ash::SystemTrayItem*>& items, | |
500 BubbleType bubble_type) | |
501 : tray_(tray), | |
502 bubble_view_(NULL), | |
503 bubble_widget_(NULL), | |
504 items_(items), | |
505 bubble_type_(bubble_type), | |
506 anchor_type_(ANCHOR_TYPE_TRAY), | |
507 autoclose_delay_(0) { | |
508 } | |
509 | |
510 SystemTrayBubble::~SystemTrayBubble() { | |
511 // The bubble may be closing without having been hidden first. So it may still | |
512 // be in the message-loop's observer list. | |
513 MessageLoopForUI::current()->RemoveObserver(this); | |
514 | |
515 DestroyItemViews(); | |
516 // Reset the host pointer in bubble_view_ in case its destruction is deferred. | |
517 if (bubble_view_) | |
518 bubble_view_->reset_host(); | |
519 if (bubble_widget_) { | |
520 bubble_widget_->RemoveObserver(this); | |
521 // This triggers the destruction of bubble_view_. | |
522 bubble_widget_->Close(); | |
523 } | |
524 } | |
525 | |
526 void SystemTrayBubble::InitView(views::View* anchor, | |
527 AnchorType anchor_type, | |
528 bool can_activate, | |
529 ash::user::LoginStatus login_status) { | |
530 DCHECK(bubble_view_ == NULL); | |
531 anchor_type_ = anchor_type; | |
532 bubble_view_ = new SystemTrayBubbleView(anchor, this, can_activate); | |
533 | |
534 for (std::vector<ash::SystemTrayItem*>::iterator it = items_.begin(); | |
535 it != items_.end(); | |
536 ++it) { | |
537 views::View* view = NULL; | |
538 switch (bubble_type_) { | |
539 case BUBBLE_TYPE_DEFAULT: | |
540 view = (*it)->CreateDefaultView(login_status); | |
541 break; | |
542 case BUBBLE_TYPE_DETAILED: | |
543 view = (*it)->CreateDetailedView(login_status); | |
544 break; | |
545 case BUBBLE_TYPE_NOTIFICATION: | |
546 view = (*it)->CreateNotificationView(login_status); | |
547 break; | |
548 } | |
549 if (view) | |
550 bubble_view_->AddChildView(new TrayPopupItemContainer(view)); | |
551 } | |
552 | |
553 DCHECK(bubble_widget_ == NULL); | |
554 bubble_widget_ = views::BubbleDelegateView::CreateBubble(bubble_view_); | |
555 | |
556 // Must occur after call to CreateBubble() | |
557 bubble_view_->SetAlignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); | |
558 bubble_widget_->non_client_view()->frame_view()->set_background(NULL); | |
559 SystemTrayBubbleBorder::ArrowType arrow_type; | |
560 if (anchor_type_ == ANCHOR_TYPE_TRAY) | |
561 arrow_type = SystemTrayBubbleBorder::ARROW_TYPE_BOTTOM; | |
562 else | |
563 arrow_type = SystemTrayBubbleBorder::ARROW_TYPE_NONE; | |
564 bubble_view_->SetBubbleBorder( | |
565 new SystemTrayBubbleBorder(bubble_view_, arrow_type)); | |
566 | |
567 bubble_widget_->AddObserver(this); | |
568 | |
569 // Setup animation. | |
570 ash::SetWindowVisibilityAnimationType( | |
571 bubble_widget_->GetNativeWindow(), | |
572 ash::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE); | |
573 ash::SetWindowVisibilityAnimationTransition( | |
574 bubble_widget_->GetNativeWindow(), | |
575 ash::ANIMATE_BOTH); | |
576 ash::SetWindowVisibilityAnimationDuration( | |
577 bubble_widget_->GetNativeWindow(), | |
578 base::TimeDelta::FromMilliseconds(kAnimationDurationForPopupMS)); | |
579 | |
580 bubble_view_->Show(); | |
581 } | |
582 | |
583 gfx::Rect SystemTrayBubble::GetAnchorRect() const { | |
584 gfx::Rect rect; | |
585 views::Widget* widget = bubble_view()->anchor_widget(); | |
586 if (widget->IsVisible()) { | |
587 rect = widget->GetWindowScreenBounds(); | |
588 if (anchor_type_ == ANCHOR_TYPE_TRAY) { | |
589 rect.Inset( | |
590 base::i18n::IsRTL() ? kPaddingFromRightEdgeOfScreen : 0, | |
591 0, | |
592 base::i18n::IsRTL() ? 0 : kPaddingFromRightEdgeOfScreen, | |
593 kPaddingFromBottomOfScreen); | |
594 } else if (anchor_type_ == ANCHOR_TYPE_BUBBLE) { | |
595 rect.Inset( | |
596 base::i18n::IsRTL() ? kShadowThickness - 1 : 0, | |
597 0, | |
598 base::i18n::IsRTL() ? 0 : kShadowThickness - 1, | |
599 0); | |
600 } | |
601 } | |
602 return rect; | |
603 } | |
604 | |
605 void SystemTrayBubble::DestroyItemViews() { | |
606 for (std::vector<ash::SystemTrayItem*>::iterator it = items_.begin(); | |
607 it != items_.end(); | |
608 ++it) { | |
609 switch (bubble_type_) { | |
610 case BUBBLE_TYPE_DEFAULT: | |
611 (*it)->DestroyDefaultView(); | |
612 break; | |
613 case BUBBLE_TYPE_DETAILED: | |
614 (*it)->DestroyDetailedView(); | |
615 break; | |
616 case BUBBLE_TYPE_NOTIFICATION: | |
617 (*it)->DestroyNotificationView(); | |
618 break; | |
619 } | |
620 } | |
621 } | |
622 | |
623 void SystemTrayBubble::StartAutoCloseTimer(int seconds) { | |
624 autoclose_.Stop(); | |
625 autoclose_delay_ = seconds; | |
626 if (autoclose_delay_) { | |
627 autoclose_.Start(FROM_HERE, | |
628 base::TimeDelta::FromSeconds(autoclose_delay_), | |
629 this, &SystemTrayBubble::Close); | |
630 } | |
631 } | |
632 | |
633 void SystemTrayBubble::StopAutoCloseTimer() { | |
634 autoclose_.Stop(); | |
635 } | |
636 | |
637 void SystemTrayBubble::RestartAutoCloseTimer() { | |
638 if (autoclose_delay_) | |
639 StartAutoCloseTimer(autoclose_delay_); | |
640 } | |
641 | |
642 void SystemTrayBubble::Close() { | |
643 if (bubble_widget_) | |
644 bubble_widget_->Close(); | |
645 } | |
646 | |
647 base::EventStatus SystemTrayBubble::WillProcessEvent( | |
648 const base::NativeEvent& event) { | |
649 // Check if the user clicked outside of the bubble and close it if they did. | |
650 if (bubble_type_ != BUBBLE_TYPE_NOTIFICATION && | |
651 ui::EventTypeFromNative(event) == ui::ET_MOUSE_PRESSED) { | |
652 gfx::Point cursor_in_view = ui::EventLocationFromNative(event); | |
653 views::View::ConvertPointFromScreen(bubble_view_, &cursor_in_view); | |
654 if (!bubble_view_->HitTest(cursor_in_view)) { | |
655 bubble_widget_->Close(); | |
656 } | |
657 } | |
658 return base::EVENT_CONTINUE; | |
659 } | |
660 | |
661 void SystemTrayBubble::DidProcessEvent(const base::NativeEvent& event) { | |
662 } | |
663 | |
664 void SystemTrayBubble::OnWidgetClosing(views::Widget* widget) { | |
665 CHECK_EQ(bubble_widget_, widget); | |
666 MessageLoopForUI::current()->RemoveObserver(this); | |
667 bubble_widget_ = NULL; | |
668 tray_->RemoveBubble(this); | |
669 } | |
670 | |
671 void SystemTrayBubble::OnWidgetVisibilityChanged(views::Widget* widget, | |
672 bool visible) { | |
673 if (!visible) | |
674 MessageLoopForUI::current()->RemoveObserver(this); | |
675 else | |
676 MessageLoopForUI::current()->AddObserver(this); | |
677 } | |
678 | |
679 // Observe the tray layer animation and update the anchor when it changes. | 88 // Observe the tray layer animation and update the anchor when it changes. |
680 // TODO(stevenjb): Observe or mirror the actual animation, not just the start | 89 // TODO(stevenjb): Observe or mirror the actual animation, not just the start |
681 // and end points. | 90 // and end points. |
682 class SystemTrayLayerAnimationObserver : public ui::LayerAnimationObserver { | 91 class SystemTrayLayerAnimationObserver : public ui::LayerAnimationObserver { |
683 public: | 92 public: |
684 explicit SystemTrayLayerAnimationObserver(SystemTray* host) : host_(host) {} | 93 explicit SystemTrayLayerAnimationObserver(SystemTray* host) : host_(host) {} |
685 | 94 |
686 virtual void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) { | 95 virtual void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) { |
687 host_->UpdateNotificationAnchor(); | 96 host_->UpdateNotificationAnchor(); |
688 } | 97 } |
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1027 canvas->DrawFocusRect(tray_container_->bounds()); | 436 canvas->DrawFocusRect(tray_container_->bounds()); |
1028 } | 437 } |
1029 | 438 |
1030 void SystemTray::UpdateBackground(int alpha) { | 439 void SystemTray::UpdateBackground(int alpha) { |
1031 background_->set_alpha(hide_background_animator_.alpha() + | 440 background_->set_alpha(hide_background_animator_.alpha() + |
1032 hover_background_animator_.alpha()); | 441 hover_background_animator_.alpha()); |
1033 SchedulePaint(); | 442 SchedulePaint(); |
1034 } | 443 } |
1035 | 444 |
1036 } // namespace ash | 445 } // namespace ash |
OLD | NEW |