forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add AshDesktopMediaList and enable Desktop Capture API on Chrome OS.
The new AshDesktopMediaList gets list of windows/screens for the window picker dialog which allows to enable Desktop Capture API on Chrome OS. BUG=295102 R=ben@chromium.org, hshi@chromium.org Review URL: https://codereview.chromium.org/100833002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@242361 0039d316-1c4b-4281-b951-d872f2087c98
- Loading branch information
sergeyu@chromium.org
committed
Dec 23, 2013
1 parent
ad780b7
commit ce2807a
Showing
17 changed files
with
615 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,215 @@ | ||
// Copyright 2013 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "chrome/browser/media/desktop_media_list_ash.h" | ||
|
||
#include <map> | ||
|
||
#include "ash/shell.h" | ||
#include "ash/shell_window_ids.h" | ||
#include "base/hash.h" | ||
#include "base/logging.h" | ||
#include "base/strings/utf_string_conversions.h" | ||
#include "base/threading/sequenced_worker_pool.h" | ||
#include "chrome/browser/media/desktop_media_list_observer.h" | ||
#include "content/public/browser/browser_thread.h" | ||
#include "grit/generated_resources.h" | ||
#include "media/base/video_util.h" | ||
#include "ui/base/l10n/l10n_util.h" | ||
#include "ui/compositor/dip_util.h" | ||
#include "ui/gfx/image/image.h" | ||
#include "ui/snapshot/snapshot.h" | ||
|
||
using content::BrowserThread; | ||
using content::DesktopMediaID; | ||
|
||
namespace { | ||
|
||
// Update the list twice per second. | ||
const int kDefaultUpdatePeriod = 500; | ||
|
||
} // namespace | ||
|
||
DesktopMediaListAsh::SourceDescription::SourceDescription( | ||
DesktopMediaID id, | ||
const base::string16& name) | ||
: id(id), | ||
name(name) { | ||
} | ||
|
||
DesktopMediaListAsh::DesktopMediaListAsh(int source_types) | ||
: source_types_(source_types), | ||
update_period_(base::TimeDelta::FromMilliseconds(kDefaultUpdatePeriod)), | ||
thumbnail_size_(100, 100), | ||
view_dialog_id_(-1), | ||
observer_(NULL), | ||
pending_window_capture_requests_(0), | ||
weak_factory_(this) { | ||
} | ||
|
||
DesktopMediaListAsh::~DesktopMediaListAsh() {} | ||
|
||
void DesktopMediaListAsh::SetUpdatePeriod(base::TimeDelta period) { | ||
DCHECK(!observer_); | ||
update_period_ = period; | ||
} | ||
|
||
void DesktopMediaListAsh::SetThumbnailSize( | ||
const gfx::Size& thumbnail_size) { | ||
thumbnail_size_ = thumbnail_size; | ||
} | ||
|
||
void DesktopMediaListAsh::SetViewDialogWindowId( | ||
content::DesktopMediaID::Id dialog_id) { | ||
view_dialog_id_ = dialog_id; | ||
} | ||
|
||
void DesktopMediaListAsh::StartUpdating(DesktopMediaListObserver* observer) { | ||
DCHECK(!observer_); | ||
|
||
observer_ = observer; | ||
Refresh(); | ||
} | ||
|
||
int DesktopMediaListAsh::GetSourceCount() const { | ||
return sources_.size(); | ||
} | ||
|
||
const DesktopMediaList::Source& DesktopMediaListAsh::GetSource( | ||
int index) const { | ||
return sources_[index]; | ||
} | ||
|
||
// static | ||
bool DesktopMediaListAsh::CompareSources(const SourceDescription& a, | ||
const SourceDescription& b) { | ||
return a.id < b.id; | ||
} | ||
|
||
void DesktopMediaListAsh::Refresh() { | ||
std::vector<SourceDescription> new_sources; | ||
EnumerateSources(&new_sources); | ||
|
||
// Sort the list of sources so that they appear in a predictable order. | ||
std::sort(new_sources.begin(), new_sources.end(), CompareSources); | ||
|
||
// Step through |new_sources| adding and removing entries from |sources_|, and | ||
// notifying the |observer_|, until two match. Requires that |sources| and | ||
// |sources_| have the same ordering. | ||
size_t pos = 0; | ||
while (pos < sources_.size() || pos < new_sources.size()) { | ||
// If |sources_[pos]| is not in |new_sources| then remove it. | ||
if (pos < sources_.size() && | ||
(pos == new_sources.size() || sources_[pos].id < new_sources[pos].id)) { | ||
sources_.erase(sources_.begin() + pos); | ||
observer_->OnSourceRemoved(pos); | ||
continue; | ||
} | ||
|
||
if (pos == sources_.size() || !(sources_[pos].id == new_sources[pos].id)) { | ||
sources_.insert(sources_.begin() + pos, Source()); | ||
sources_[pos].id = new_sources[pos].id; | ||
sources_[pos].name = new_sources[pos].name; | ||
observer_->OnSourceAdded(pos); | ||
} else if (sources_[pos].name != new_sources[pos].name) { | ||
sources_[pos].name = new_sources[pos].name; | ||
observer_->OnSourceNameChanged(pos); | ||
} | ||
|
||
++pos; | ||
} | ||
|
||
DCHECK_EQ(new_sources.size(), sources_.size()); | ||
} | ||
|
||
void DesktopMediaListAsh::EnumerateWindowsForRoot( | ||
std::vector<DesktopMediaListAsh::SourceDescription>* sources, | ||
aura::Window* root_window, | ||
int container_id) { | ||
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | ||
|
||
aura::Window* container = ash::Shell::GetContainer(root_window, container_id); | ||
if (!container) | ||
return; | ||
for (aura::Window::Windows::const_iterator it = container->children().begin(); | ||
it != container->children().end(); ++it) { | ||
if (!(*it)->IsVisible() || !(*it)->CanFocus()) | ||
continue; | ||
content::DesktopMediaID id = | ||
content::DesktopMediaID::RegisterAuraWindow(*it); | ||
if (id.id == view_dialog_id_) | ||
continue; | ||
SourceDescription window_source(id, (*it)->title()); | ||
sources->push_back(window_source); | ||
|
||
CaptureThumbnail(window_source.id, *it); | ||
} | ||
} | ||
|
||
void DesktopMediaListAsh::EnumerateSources( | ||
std::vector<DesktopMediaListAsh::SourceDescription>* sources) { | ||
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | ||
|
||
aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows(); | ||
|
||
for (aura::Window::Windows::const_iterator iter = root_windows.begin(); | ||
iter != root_windows.end(); ++iter) { | ||
if (source_types_ & SCREENS) { | ||
SourceDescription screen_source( | ||
content::DesktopMediaID::RegisterAuraWindow(*iter), (*iter)->title()); | ||
sources->push_back(screen_source); | ||
|
||
CaptureThumbnail(screen_source.id, *iter); | ||
} | ||
|
||
if (source_types_ & WINDOWS) { | ||
EnumerateWindowsForRoot( | ||
sources, *iter, ash::internal::kShellWindowId_DefaultContainer); | ||
EnumerateWindowsForRoot( | ||
sources, *iter, ash::internal::kShellWindowId_AlwaysOnTopContainer); | ||
EnumerateWindowsForRoot( | ||
sources, *iter, ash::internal::kShellWindowId_DockedContainer); | ||
} | ||
} | ||
} | ||
|
||
void DesktopMediaListAsh::CaptureThumbnail(content::DesktopMediaID id, | ||
aura::Window* window) { | ||
gfx::Rect window_rect(window->bounds().width(), window->bounds().height()); | ||
gfx::Rect scaled_rect = media::ComputeLetterboxRegion( | ||
gfx::Rect(thumbnail_size_), window_rect.size()); | ||
|
||
++pending_window_capture_requests_; | ||
ui::GrapWindowSnapshotAsync( | ||
window, window_rect, | ||
scaled_rect.size(), | ||
BrowserThread::GetBlockingPool(), | ||
base::Bind(&DesktopMediaListAsh::OnThumbnailCaptured, | ||
weak_factory_.GetWeakPtr(), | ||
id)); | ||
} | ||
|
||
void DesktopMediaListAsh::OnThumbnailCaptured(content::DesktopMediaID id, | ||
const gfx::Image& image) { | ||
for (size_t i = 0; i < sources_.size(); ++i) { | ||
if (sources_[i].id == id) { | ||
sources_[i].thumbnail = image.AsImageSkia(); | ||
observer_->OnSourceThumbnailChanged(i); | ||
break; | ||
} | ||
} | ||
|
||
--pending_window_capture_requests_; | ||
DCHECK_GE(pending_window_capture_requests_, 0); | ||
|
||
if (!pending_window_capture_requests_) { | ||
// Once we've finished capturing all windows post a task for the next list | ||
// update. | ||
BrowserThread::PostDelayedTask( | ||
BrowserThread::UI, FROM_HERE, | ||
base::Bind(&DesktopMediaListAsh::Refresh, | ||
weak_factory_.GetWeakPtr()), | ||
update_period_); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
// Copyright 2013 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef CHROME_BROWSER_MEDIA_DESKTOP_MEDIA_LIST_ASH_H_ | ||
#define CHROME_BROWSER_MEDIA_DESKTOP_MEDIA_LIST_ASH_H_ | ||
|
||
#include "base/basictypes.h" | ||
#include "base/memory/scoped_ptr.h" | ||
#include "base/memory/weak_ptr.h" | ||
#include "base/sequenced_task_runner.h" | ||
#include "chrome/browser/media/desktop_media_list.h" | ||
#include "content/public/browser/desktop_media_id.h" | ||
|
||
class SkBitmap; | ||
|
||
namespace aura { | ||
class Window; | ||
} | ||
|
||
namespace cc { | ||
class CopyOutputResult; | ||
class SingleReleaseCallback; | ||
} | ||
|
||
namespace gfx { | ||
class Image; | ||
} | ||
|
||
// Implementation of DesktopMediaList that shows native screens and | ||
// native windows. | ||
class DesktopMediaListAsh : public DesktopMediaList { | ||
public: | ||
enum SourceTypes { | ||
SCREENS = 1, | ||
WINDOWS = 2, | ||
}; | ||
|
||
explicit DesktopMediaListAsh(int source_types); | ||
virtual ~DesktopMediaListAsh(); | ||
|
||
// DesktopMediaList interface. | ||
virtual void SetUpdatePeriod(base::TimeDelta period) OVERRIDE; | ||
virtual void SetThumbnailSize(const gfx::Size& thumbnail_size) OVERRIDE; | ||
virtual void StartUpdating(DesktopMediaListObserver* observer) OVERRIDE; | ||
virtual int GetSourceCount() const OVERRIDE; | ||
virtual const Source& GetSource(int index) const OVERRIDE; | ||
virtual void SetViewDialogWindowId( | ||
content::DesktopMediaID::Id dialog_id) OVERRIDE; | ||
|
||
private: | ||
// Struct used to represent sources list the model gets from the Worker. | ||
struct SourceDescription { | ||
SourceDescription(content::DesktopMediaID id, const base::string16& name); | ||
|
||
content::DesktopMediaID id; | ||
base::string16 name; | ||
}; | ||
|
||
// Order comparator for sources. Used to sort list of sources. | ||
static bool CompareSources(const SourceDescription& a, | ||
const SourceDescription& b); | ||
|
||
void Refresh(); | ||
void EnumerateWindowsForRoot( | ||
std::vector<DesktopMediaListAsh::SourceDescription>* windows, | ||
aura::Window* root_window, | ||
int container_id); | ||
void EnumerateSources( | ||
std::vector<DesktopMediaListAsh::SourceDescription>* windows); | ||
void CaptureThumbnail(content::DesktopMediaID id, aura::Window* window); | ||
void OnThumbnailCaptured(content::DesktopMediaID id, | ||
const gfx::Image& image); | ||
|
||
int source_types_; | ||
|
||
// Time interval between mode updates. | ||
base::TimeDelta update_period_; | ||
|
||
// Size of thumbnails generated by the model. | ||
gfx::Size thumbnail_size_; | ||
|
||
// ID of the hosting dialog. | ||
content::DesktopMediaID::Id view_dialog_id_; | ||
|
||
// The observer passed to StartUpdating(). | ||
DesktopMediaListObserver* observer_; | ||
|
||
// Current list of sources. | ||
std::vector<Source> sources_; | ||
|
||
int pending_window_capture_requests_; | ||
|
||
base::WeakPtrFactory<DesktopMediaListAsh> weak_factory_; | ||
|
||
DISALLOW_COPY_AND_ASSIGN(DesktopMediaListAsh); | ||
}; | ||
|
||
#endif // CHROME_BROWSER_MEDIA_DESKTOP_MEDIA_LIST_ASH_H_ |
Oops, something went wrong.