1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/media/desktop_media_picker.h" 6 7 #include "base/callback.h" 8 #include "chrome/browser/media/desktop_media_list.h" 9 #include "chrome/browser/media/desktop_media_list_observer.h" 10 #include "chrome/browser/ui/ash/ash_util.h" 11 #include "chrome/browser/ui/views/constrained_window_views.h" 12 #include "components/web_modal/web_contents_modal_dialog_manager.h" 13 #include "content/public/browser/browser_thread.h" 14 #include "grit/generated_resources.h" 15 #include "ui/aura/window_tree_host.h" 16 #include "ui/base/l10n/l10n_util.h" 17 #include "ui/events/event_constants.h" 18 #include "ui/events/keycodes/keyboard_codes.h" 19 #include "ui/gfx/canvas.h" 20 #include "ui/native_theme/native_theme.h" 21 #include "ui/views/background.h" 22 #include "ui/views/bubble/bubble_frame_view.h" 23 #include "ui/views/controls/image_view.h" 24 #include "ui/views/controls/label.h" 25 #include "ui/views/controls/scroll_view.h" 26 #include "ui/views/layout/box_layout.h" 27 #include "ui/views/layout/layout_constants.h" 28 #include "ui/views/widget/widget.h" 29 #include "ui/views/window/dialog_client_view.h" 30 #include "ui/views/window/dialog_delegate.h" 31 #include "ui/wm/core/shadow_types.h" 32 33 using content::DesktopMediaID; 34 35 namespace { 36 37 const int kThumbnailWidth = 160; 38 const int kThumbnailHeight = 100; 39 const int kThumbnailMargin = 10; 40 const int kLabelHeight = 40; 41 const int kListItemWidth = kThumbnailMargin * 2 + kThumbnailWidth; 42 const int kListItemHeight = 43 kThumbnailMargin * 2 + kThumbnailHeight + kLabelHeight; 44 const int kListColumns = 3; 45 const int kTotalListWidth = kListColumns * kListItemWidth; 46 47 const int kDesktopMediaSourceViewGroupId = 1; 48 49 const char kDesktopMediaSourceViewClassName[] = 50 "DesktopMediaPicker_DesktopMediaSourceView"; 51 52 content::DesktopMediaID::Id AcceleratedWidgetToDesktopMediaId( 53 gfx::AcceleratedWidget accelerated_widget) { 54 #if defined(OS_WIN) 55 return reinterpret_cast<content::DesktopMediaID::Id>(accelerated_widget); 56 #else 57 return static_cast<content::DesktopMediaID::Id>(accelerated_widget); 58 #endif 59 } 60 61 int GetMediaListViewHeightForRows(size_t rows) { 62 return kListItemHeight * rows; 63 } 64 65 class DesktopMediaListView; 66 class DesktopMediaPickerDialogView; 67 class DesktopMediaPickerViews; 68 69 // View used for each item in DesktopMediaListView. Shows a single desktop media 70 // source as a thumbnail with the title under it. 71 class DesktopMediaSourceView : public views::View { 72 public: 73 DesktopMediaSourceView(DesktopMediaListView* parent, 74 DesktopMediaID source_id); 75 virtual ~DesktopMediaSourceView(); 76 77 // Updates thumbnail and title from |source|. 78 void SetName(const base::string16& name); 79 void SetThumbnail(const gfx::ImageSkia& thumbnail); 80 81 // Id for the source shown by this View. 82 const DesktopMediaID& source_id() const { 83 return source_id_; 84 } 85 86 // Returns true if the source is selected. 87 bool is_selected() const { return selected_; } 88 89 // Updates selection state of the element. If |selected| is true then also 90 // calls SetSelected(false) for the source view that was selected before that 91 // (if any). 92 void SetSelected(bool selected); 93 94 // views::View interface. 95 virtual const char* GetClassName() const OVERRIDE; 96 virtual void Layout() OVERRIDE; 97 virtual views::View* GetSelectedViewForGroup(int group) OVERRIDE; 98 virtual bool IsGroupFocusTraversable() const OVERRIDE; 99 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; 100 virtual void OnFocus() OVERRIDE; 101 virtual void OnBlur() OVERRIDE; 102 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE; 103 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE; 104 105 private: 106 DesktopMediaListView* parent_; 107 DesktopMediaID source_id_; 108 109 views::ImageView* image_view_; 110 views::Label* label_; 111 112 bool selected_; 113 114 DISALLOW_COPY_AND_ASSIGN(DesktopMediaSourceView); 115 }; 116 117 // View that shows list of desktop media sources available from 118 // DesktopMediaList. 119 class DesktopMediaListView : public views::View, 120 public DesktopMediaListObserver { 121 public: 122 DesktopMediaListView(DesktopMediaPickerDialogView* parent, 123 scoped_ptr<DesktopMediaList> media_list); 124 virtual ~DesktopMediaListView(); 125 126 void StartUpdating(content::DesktopMediaID::Id dialog_window_id); 127 128 // Called by DesktopMediaSourceView when selection has changed. 129 void OnSelectionChanged(); 130 131 // Called by DesktopMediaSourceView when a source has been double-clicked. 132 void OnDoubleClick(); 133 134 // Returns currently selected source. 135 DesktopMediaSourceView* GetSelection(); 136 137 // views::View overrides. 138 virtual gfx::Size GetPreferredSize() const OVERRIDE; 139 virtual void Layout() OVERRIDE; 140 virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE; 141 142 private: 143 // DesktopMediaList::Observer interface 144 virtual void OnSourceAdded(int index) OVERRIDE; 145 virtual void OnSourceRemoved(int index) OVERRIDE; 146 virtual void OnSourceMoved(int old_index, int new_index) OVERRIDE; 147 virtual void OnSourceNameChanged(int index) OVERRIDE; 148 virtual void OnSourceThumbnailChanged(int index) OVERRIDE; 149 150 DesktopMediaPickerDialogView* parent_; 151 scoped_ptr<DesktopMediaList> media_list_; 152 153 DISALLOW_COPY_AND_ASSIGN(DesktopMediaListView); 154 }; 155 156 // Dialog view used for DesktopMediaPickerViews. 157 class DesktopMediaPickerDialogView : public views::DialogDelegateView { 158 public: 159 DesktopMediaPickerDialogView(content::WebContents* parent_web_contents, 160 gfx::NativeWindow context, 161 gfx::NativeWindow parent_window, 162 DesktopMediaPickerViews* parent, 163 const base::string16& app_name, 164 const base::string16& target_name, 165 scoped_ptr<DesktopMediaList> media_list); 166 virtual ~DesktopMediaPickerDialogView(); 167 168 // Called by parent (DesktopMediaPickerViews) when it's destroyed. 169 void DetachParent(); 170 171 // Called by DesktopMediaListView. 172 void OnSelectionChanged(); 173 void OnDoubleClick(); 174 175 // views::View overrides. 176 virtual gfx::Size GetPreferredSize() const OVERRIDE; 177 virtual void Layout() OVERRIDE; 178 179 // views::DialogDelegateView overrides. 180 virtual ui::ModalType GetModalType() const OVERRIDE; 181 virtual base::string16 GetWindowTitle() const OVERRIDE; 182 virtual bool IsDialogButtonEnabled(ui::DialogButton button) const OVERRIDE; 183 virtual base::string16 GetDialogButtonLabel( 184 ui::DialogButton button) const OVERRIDE; 185 virtual bool Accept() OVERRIDE; 186 virtual void DeleteDelegate() OVERRIDE; 187 188 void OnMediaListRowsChanged(); 189 190 private: 191 DesktopMediaPickerViews* parent_; 192 base::string16 app_name_; 193 194 views::Label* label_; 195 views::ScrollView* scroll_view_; 196 DesktopMediaListView* list_view_; 197 198 DISALLOW_COPY_AND_ASSIGN(DesktopMediaPickerDialogView); 199 }; 200 201 // Implementation of DesktopMediaPicker for Views. 202 class DesktopMediaPickerViews : public DesktopMediaPicker { 203 public: 204 DesktopMediaPickerViews(); 205 virtual ~DesktopMediaPickerViews(); 206 207 void NotifyDialogResult(DesktopMediaID source); 208 209 // DesktopMediaPicker overrides. 210 virtual void Show(content::WebContents* web_contents, 211 gfx::NativeWindow context, 212 gfx::NativeWindow parent, 213 const base::string16& app_name, 214 const base::string16& target_name, 215 scoped_ptr<DesktopMediaList> media_list, 216 const DoneCallback& done_callback) OVERRIDE; 217 218 private: 219 DoneCallback callback_; 220 221 // The |dialog_| is owned by the corresponding views::Widget instance. 222 // When DesktopMediaPickerViews is destroyed the |dialog_| is destroyed 223 // asynchronously by closing the widget. 224 DesktopMediaPickerDialogView* dialog_; 225 226 DISALLOW_COPY_AND_ASSIGN(DesktopMediaPickerViews); 227 }; 228 229 DesktopMediaSourceView::DesktopMediaSourceView( 230 DesktopMediaListView* parent, 231 DesktopMediaID source_id) 232 : parent_(parent), 233 source_id_(source_id), 234 image_view_(new views::ImageView()), 235 label_(new views::Label()), 236 selected_(false) { 237 AddChildView(image_view_); 238 AddChildView(label_); 239 SetFocusable(true); 240 } 241 242 DesktopMediaSourceView::~DesktopMediaSourceView() {} 243 244 void DesktopMediaSourceView::SetName(const base::string16& name) { 245 label_->SetText(name); 246 } 247 248 void DesktopMediaSourceView::SetThumbnail(const gfx::ImageSkia& thumbnail) { 249 image_view_->SetImage(thumbnail); 250 } 251 252 void DesktopMediaSourceView::SetSelected(bool selected) { 253 if (selected == selected_) 254 return; 255 selected_ = selected; 256 257 if (selected) { 258 // Unselect all other sources. 259 Views neighbours; 260 parent()->GetViewsInGroup(GetGroup(), &neighbours); 261 for (Views::iterator i(neighbours.begin()); i != neighbours.end(); ++i) { 262 if (*i != this) { 263 DCHECK_EQ((*i)->GetClassName(), kDesktopMediaSourceViewClassName); 264 DesktopMediaSourceView* source_view = 265 static_cast<DesktopMediaSourceView*>(*i); 266 source_view->SetSelected(false); 267 } 268 } 269 270 const SkColor bg_color = GetNativeTheme()->GetSystemColor( 271 ui::NativeTheme::kColorId_FocusedMenuItemBackgroundColor); 272 set_background(views::Background::CreateSolidBackground(bg_color)); 273 274 parent_->OnSelectionChanged(); 275 } else { 276 set_background(NULL); 277 } 278 279 SchedulePaint(); 280 } 281 282 const char* DesktopMediaSourceView::GetClassName() const { 283 return kDesktopMediaSourceViewClassName; 284 } 285 286 void DesktopMediaSourceView::Layout() { 287 image_view_->SetBounds(kThumbnailMargin, kThumbnailMargin, 288 kThumbnailWidth, kThumbnailHeight); 289 label_->SetBounds(kThumbnailMargin, kThumbnailHeight + kThumbnailMargin, 290 kThumbnailWidth, kLabelHeight); 291 } 292 293 views::View* DesktopMediaSourceView::GetSelectedViewForGroup(int group) { 294 Views neighbours; 295 parent()->GetViewsInGroup(group, &neighbours); 296 if (neighbours.empty()) 297 return NULL; 298 299 for (Views::iterator i(neighbours.begin()); i != neighbours.end(); ++i) { 300 DCHECK_EQ((*i)->GetClassName(), kDesktopMediaSourceViewClassName); 301 DesktopMediaSourceView* source_view = 302 static_cast<DesktopMediaSourceView*>(*i); 303 if (source_view->selected_) 304 return source_view; 305 } 306 return NULL; 307 } 308 309 bool DesktopMediaSourceView::IsGroupFocusTraversable() const { 310 return false; 311 } 312 313 void DesktopMediaSourceView::OnPaint(gfx::Canvas* canvas) { 314 View::OnPaint(canvas); 315 if (HasFocus()) { 316 gfx::Rect bounds(GetLocalBounds()); 317 bounds.Inset(kThumbnailMargin / 2, kThumbnailMargin / 2); 318 canvas->DrawFocusRect(bounds); 319 } 320 } 321 322 void DesktopMediaSourceView::OnFocus() { 323 View::OnFocus(); 324 SetSelected(true); 325 ScrollRectToVisible(gfx::Rect(size())); 326 // We paint differently when focused. 327 SchedulePaint(); 328 } 329 330 void DesktopMediaSourceView::OnBlur() { 331 View::OnBlur(); 332 // We paint differently when focused. 333 SchedulePaint(); 334 } 335 336 bool DesktopMediaSourceView::OnMousePressed(const ui::MouseEvent& event) { 337 if (event.GetClickCount() == 1) { 338 RequestFocus(); 339 } else if (event.GetClickCount() == 2) { 340 RequestFocus(); 341 parent_->OnDoubleClick(); 342 } 343 return true; 344 } 345 346 void DesktopMediaSourceView::OnGestureEvent(ui::GestureEvent* event) { 347 if (event->type() == ui::ET_GESTURE_TAP && 348 event->details().tap_count() == 2) { 349 RequestFocus(); 350 parent_->OnDoubleClick(); 351 event->SetHandled(); 352 return; 353 } 354 355 // Detect tap gesture using ET_GESTURE_TAP_DOWN so the view also gets focused 356 // on the long tap (when the tap gesture starts). 357 if (event->type() == ui::ET_GESTURE_TAP_DOWN) { 358 RequestFocus(); 359 event->SetHandled(); 360 } 361 } 362 363 DesktopMediaListView::DesktopMediaListView( 364 DesktopMediaPickerDialogView* parent, 365 scoped_ptr<DesktopMediaList> media_list) 366 : parent_(parent), 367 media_list_(media_list.Pass()) { 368 media_list_->SetThumbnailSize(gfx::Size(kThumbnailWidth, kThumbnailHeight)); 369 } 370 371 DesktopMediaListView::~DesktopMediaListView() {} 372 373 void DesktopMediaListView::StartUpdating( 374 content::DesktopMediaID::Id dialog_window_id) { 375 media_list_->SetViewDialogWindowId(dialog_window_id); 376 media_list_->StartUpdating(this); 377 } 378 379 void DesktopMediaListView::OnSelectionChanged() { 380 parent_->OnSelectionChanged(); 381 } 382 383 void DesktopMediaListView::OnDoubleClick() { 384 parent_->OnDoubleClick(); 385 } 386 387 DesktopMediaSourceView* DesktopMediaListView::GetSelection() { 388 for (int i = 0; i < child_count(); ++i) { 389 DesktopMediaSourceView* source_view = 390 static_cast<DesktopMediaSourceView*>(child_at(i)); 391 DCHECK_EQ(source_view->GetClassName(), kDesktopMediaSourceViewClassName); 392 if (source_view->is_selected()) 393 return source_view; 394 } 395 return NULL; 396 } 397 398 gfx::Size DesktopMediaListView::GetPreferredSize() const { 399 int total_rows = (child_count() + kListColumns - 1) / kListColumns; 400 return gfx::Size(kTotalListWidth, GetMediaListViewHeightForRows(total_rows)); 401 } 402 403 void DesktopMediaListView::Layout() { 404 int x = 0; 405 int y = 0; 406 407 for (int i = 0; i < child_count(); ++i) { 408 if (x + kListItemWidth > kTotalListWidth) { 409 x = 0; 410 y += kListItemHeight; 411 } 412 413 View* source_view = child_at(i); 414 source_view->SetBounds(x, y, kListItemWidth, kListItemHeight); 415 416 x += kListItemWidth; 417 } 418 419 y += kListItemHeight; 420 SetSize(gfx::Size(kTotalListWidth, y)); 421 } 422 423 bool DesktopMediaListView::OnKeyPressed(const ui::KeyEvent& event) { 424 int position_increment = 0; 425 switch (event.key_code()) { 426 case ui::VKEY_UP: 427 position_increment = -kListColumns; 428 break; 429 case ui::VKEY_DOWN: 430 position_increment = kListColumns; 431 break; 432 case ui::VKEY_LEFT: 433 position_increment = -1; 434 break; 435 case ui::VKEY_RIGHT: 436 position_increment = 1; 437 break; 438 default: 439 return false; 440 } 441 442 if (position_increment != 0) { 443 DesktopMediaSourceView* selected = GetSelection(); 444 DesktopMediaSourceView* new_selected = NULL; 445 446 if (selected) { 447 int index = GetIndexOf(selected); 448 int new_index = index + position_increment; 449 if (new_index >= child_count()) 450 new_index = child_count() - 1; 451 else if (new_index < 0) 452 new_index = 0; 453 if (index != new_index) { 454 new_selected = 455 static_cast<DesktopMediaSourceView*>(child_at(new_index)); 456 } 457 } else if (has_children()) { 458 new_selected = static_cast<DesktopMediaSourceView*>(child_at(0)); 459 } 460 461 if (new_selected) { 462 GetFocusManager()->SetFocusedView(new_selected); 463 } 464 465 return true; 466 } 467 468 return false; 469 } 470 471 void DesktopMediaListView::OnSourceAdded(int index) { 472 const DesktopMediaList::Source& source = media_list_->GetSource(index); 473 DesktopMediaSourceView* source_view = 474 new DesktopMediaSourceView(this, source.id); 475 source_view->SetName(source.name); 476 source_view->SetGroup(kDesktopMediaSourceViewGroupId); 477 AddChildViewAt(source_view, index); 478 479 PreferredSizeChanged(); 480 481 if (child_count() % kListColumns == 1) 482 parent_->OnMediaListRowsChanged(); 483 } 484 485 void DesktopMediaListView::OnSourceRemoved(int index) { 486 DesktopMediaSourceView* view = 487 static_cast<DesktopMediaSourceView*>(child_at(index)); 488 DCHECK(view); 489 DCHECK_EQ(view->GetClassName(), kDesktopMediaSourceViewClassName); 490 bool was_selected = view->is_selected(); 491 RemoveChildView(view); 492 delete view; 493 494 if (was_selected) 495 OnSelectionChanged(); 496 497 PreferredSizeChanged(); 498 499 if (child_count() % kListColumns == 0) 500 parent_->OnMediaListRowsChanged(); 501 } 502 503 void DesktopMediaListView::OnSourceMoved(int old_index, int new_index) { 504 DesktopMediaSourceView* view = 505 static_cast<DesktopMediaSourceView*>(child_at(old_index)); 506 ReorderChildView(view, new_index); 507 PreferredSizeChanged(); 508 } 509 510 void DesktopMediaListView::OnSourceNameChanged(int index) { 511 const DesktopMediaList::Source& source = media_list_->GetSource(index); 512 DesktopMediaSourceView* source_view = 513 static_cast<DesktopMediaSourceView*>(child_at(index)); 514 source_view->SetName(source.name); 515 } 516 517 void DesktopMediaListView::OnSourceThumbnailChanged(int index) { 518 const DesktopMediaList::Source& source = media_list_->GetSource(index); 519 DesktopMediaSourceView* source_view = 520 static_cast<DesktopMediaSourceView*>(child_at(index)); 521 source_view->SetThumbnail(source.thumbnail); 522 } 523 524 DesktopMediaPickerDialogView::DesktopMediaPickerDialogView( 525 content::WebContents* parent_web_contents, 526 gfx::NativeWindow context, 527 gfx::NativeWindow parent_window, 528 DesktopMediaPickerViews* parent, 529 const base::string16& app_name, 530 const base::string16& target_name, 531 scoped_ptr<DesktopMediaList> media_list) 532 : parent_(parent), 533 app_name_(app_name), 534 label_(new views::Label()), 535 scroll_view_(views::ScrollView::CreateScrollViewWithBorder()), 536 list_view_(new DesktopMediaListView(this, media_list.Pass())) { 537 if (app_name == target_name) { 538 label_->SetText( 539 l10n_util::GetStringFUTF16(IDS_DESKTOP_MEDIA_PICKER_TEXT, app_name)); 540 } else { 541 label_->SetText(l10n_util::GetStringFUTF16( 542 IDS_DESKTOP_MEDIA_PICKER_TEXT_DELEGATED, app_name, target_name)); 543 } 544 label_->SetMultiLine(true); 545 label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); 546 AddChildView(label_); 547 548 scroll_view_->SetContents(list_view_); 549 scroll_view_->ClipHeightTo( 550 GetMediaListViewHeightForRows(1), GetMediaListViewHeightForRows(2)); 551 AddChildView(scroll_view_); 552 553 // If |parent_web_contents| is set, the picker will be shown modal to the 554 // web contents. Otherwise, a new dialog widget inside |parent_window| will be 555 // created for the picker. Note that |parent_window| may also be NULL if 556 // parent web contents is not set. In this case the picker will be parented 557 // by a root window. 558 views::Widget* widget = NULL; 559 if (parent_web_contents) 560 widget = CreateWebModalDialogViews(this, parent_web_contents); 561 else 562 widget = DialogDelegate::CreateDialogWidget(this, context, parent_window); 563 564 // DesktopMediaList needs to know the ID of the picker window which 565 // matches the ID it gets from the OS. Depending on the OS and configuration 566 // we get this ID differently. 567 content::DesktopMediaID::Id dialog_window_id = 0; 568 569 // If there is |parent_window| or |parent_web_contents|, the picker window 570 // is embedded in the parent and does not have its own native window id, so we 571 // do not filter in that case. 572 if (!parent_window && !parent_web_contents) { 573 #if defined(USE_ASH) 574 if (chrome::IsNativeWindowInAsh(widget->GetNativeWindow())) { 575 dialog_window_id = content::DesktopMediaID::RegisterAuraWindow( 576 widget->GetNativeWindow()).id; 577 DCHECK_NE(dialog_window_id, 0); 578 } 579 #endif 580 581 if (dialog_window_id == 0) { 582 dialog_window_id = AcceleratedWidgetToDesktopMediaId( 583 widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget()); 584 } 585 } 586 587 list_view_->StartUpdating(dialog_window_id); 588 589 if (parent_web_contents) { 590 web_modal::WebContentsModalDialogManager* manager = 591 web_modal::WebContentsModalDialogManager::FromWebContents( 592 parent_web_contents); 593 manager->ShowModalDialog(widget->GetNativeView()); 594 } else { 595 widget->Show(); 596 } 597 } 598 599 DesktopMediaPickerDialogView::~DesktopMediaPickerDialogView() {} 600 601 void DesktopMediaPickerDialogView::DetachParent() { 602 parent_ = NULL; 603 } 604 605 gfx::Size DesktopMediaPickerDialogView::GetPreferredSize() const { 606 static const size_t kDialogViewWidth = 600; 607 const gfx::Insets title_insets = views::BubbleFrameView::GetTitleInsets(); 608 size_t label_height = 609 label_->GetHeightForWidth(kDialogViewWidth - title_insets.height() * 2); 610 611 return gfx::Size(kDialogViewWidth, 612 views::kPanelVertMargin * 2 + label_height + 613 views::kPanelVerticalSpacing + 614 scroll_view_->GetPreferredSize().height()); 615 } 616 617 void DesktopMediaPickerDialogView::Layout() { 618 // DialogDelegate uses the bubble style frame. 619 const gfx::Insets title_insets = views::BubbleFrameView::GetTitleInsets(); 620 gfx::Rect rect = GetLocalBounds(); 621 622 rect.Inset(title_insets.left(), views::kPanelVertMargin); 623 624 gfx::Rect label_rect(rect.x(), rect.y(), rect.width(), 625 label_->GetHeightForWidth(rect.width())); 626 label_->SetBoundsRect(label_rect); 627 628 int scroll_view_top = label_rect.bottom() + views::kPanelVerticalSpacing; 629 scroll_view_->SetBounds( 630 rect.x(), scroll_view_top, 631 rect.width(), rect.height() - scroll_view_top); 632 } 633 634 ui::ModalType DesktopMediaPickerDialogView::GetModalType() const { 635 return ui::MODAL_TYPE_CHILD; 636 } 637 638 base::string16 DesktopMediaPickerDialogView::GetWindowTitle() const { 639 return l10n_util::GetStringFUTF16(IDS_DESKTOP_MEDIA_PICKER_TITLE, app_name_); 640 } 641 642 bool DesktopMediaPickerDialogView::IsDialogButtonEnabled( 643 ui::DialogButton button) const { 644 if (button == ui::DIALOG_BUTTON_OK) 645 return list_view_->GetSelection() != NULL; 646 return true; 647 } 648 649 base::string16 DesktopMediaPickerDialogView::GetDialogButtonLabel( 650 ui::DialogButton button) const { 651 return l10n_util::GetStringUTF16(button == ui::DIALOG_BUTTON_OK ? 652 IDS_DESKTOP_MEDIA_PICKER_SHARE : IDS_CANCEL); 653 } 654 655 bool DesktopMediaPickerDialogView::Accept() { 656 DesktopMediaSourceView* selection = list_view_->GetSelection(); 657 658 // Ok button should only be enabled when a source is selected. 659 DCHECK(selection); 660 661 DesktopMediaID source; 662 if (selection) 663 source = selection->source_id(); 664 665 if (parent_) 666 parent_->NotifyDialogResult(source); 667 668 // Return true to close the window. 669 return true; 670 } 671 672 void DesktopMediaPickerDialogView::DeleteDelegate() { 673 // If the dialog is being closed then notify the parent about it. 674 if (parent_) 675 parent_->NotifyDialogResult(DesktopMediaID()); 676 delete this; 677 } 678 679 void DesktopMediaPickerDialogView::OnSelectionChanged() { 680 GetDialogClientView()->UpdateDialogButtons(); 681 } 682 683 void DesktopMediaPickerDialogView::OnDoubleClick() { 684 // This will call Accept() and close the dialog. 685 GetDialogClientView()->AcceptWindow(); 686 } 687 688 void DesktopMediaPickerDialogView::OnMediaListRowsChanged() { 689 gfx::Rect widget_bound = GetWidget()->GetWindowBoundsInScreen(); 690 691 int new_height = widget_bound.height() - scroll_view_->height() + 692 scroll_view_->GetPreferredSize().height(); 693 694 GetWidget()->CenterWindow(gfx::Size(widget_bound.width(), new_height)); 695 } 696 697 DesktopMediaPickerViews::DesktopMediaPickerViews() : dialog_(NULL) { 698 } 699 700 DesktopMediaPickerViews::~DesktopMediaPickerViews() { 701 if (dialog_) { 702 dialog_->DetachParent(); 703 dialog_->GetWidget()->Close(); 704 } 705 } 706 707 void DesktopMediaPickerViews::Show(content::WebContents* web_contents, 708 gfx::NativeWindow context, 709 gfx::NativeWindow parent, 710 const base::string16& app_name, 711 const base::string16& target_name, 712 scoped_ptr<DesktopMediaList> media_list, 713 const DoneCallback& done_callback) { 714 callback_ = done_callback; 715 dialog_ = new DesktopMediaPickerDialogView( 716 web_contents, context, parent, this, app_name, target_name, 717 media_list.Pass()); 718 } 719 720 void DesktopMediaPickerViews::NotifyDialogResult(DesktopMediaID source) { 721 // Once this method is called the |dialog_| will close and destroy itself. 722 dialog_->DetachParent(); 723 dialog_ = NULL; 724 725 DCHECK(!callback_.is_null()); 726 727 // Notify the |callback_| asynchronously because it may need to destroy 728 // DesktopMediaPicker. 729 content::BrowserThread::PostTask( 730 content::BrowserThread::UI, FROM_HERE, 731 base::Bind(callback_, source)); 732 callback_.Reset(); 733 } 734 735 } // namespace 736 737 // static 738 scoped_ptr<DesktopMediaPicker> DesktopMediaPicker::Create() { 739 return scoped_ptr<DesktopMediaPicker>(new DesktopMediaPickerViews()); 740 } 741