Home | History | Annotate | Download | only in views
      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