Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(89)

Side by Side Diff: chrome/browser/media/ash_desktop_media_list.cc

Issue 100833002: Add AshDesktopMediaList and enable Desktop Capture API on Chrome OS. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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/ash_desktop_media_list.h"
6
7 #include <map>
8
9 #include "ash/shell.h"
10 #include "ash/shell_window_ids.h"
11 #include "base/hash.h"
12 #include "base/logging.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/media/desktop_media_list_observer.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "grit/generated_resources.h"
17 #include "media/base/video_util.h"
18 #include "ui/base/l10n/l10n_util.h"
19 #include "ui/compositor/dip_util.h"
20 #include "ui/gfx/image/image.h"
21 #include "ui/snapshot/snapshot.h"
22
23 using content::BrowserThread;
24 using content::DesktopMediaID;
25
26 namespace {
27
28 // Update the list twice per second.
29 const int kDefaultUpdatePeriod = 500;
30
31 } // namespace
32
33 AshDesktopMediaList::SourceDescription::SourceDescription(
34 DesktopMediaID id,
35 const base::string16& name)
36 : id(id),
37 name(name) {
38 }
39
40 AshDesktopMediaList::AshDesktopMediaList(int source_types)
41 : source_types_(source_types),
42 update_period_(base::TimeDelta::FromMilliseconds(kDefaultUpdatePeriod)),
43 thumbnail_size_(100, 100),
44 view_dialog_id_(-1),
45 observer_(NULL),
46 pending_window_capture_requests_(0),
47 weak_factory_(this) {
48 }
49
50 AshDesktopMediaList::~AshDesktopMediaList() {}
51
52 void AshDesktopMediaList::SetUpdatePeriod(base::TimeDelta period) {
53 DCHECK(!observer_);
54 update_period_ = period;
55 }
56
57 void AshDesktopMediaList::SetThumbnailSize(
58 const gfx::Size& thumbnail_size) {
59 thumbnail_size_ = thumbnail_size;
60 }
61
62 void AshDesktopMediaList::SetViewDialogWindowId(
63 content::DesktopMediaID::Id dialog_id) {
64 view_dialog_id_ = dialog_id;
65 }
66
67 void AshDesktopMediaList::StartUpdating(DesktopMediaListObserver* observer) {
68 DCHECK(!observer_);
69
70 observer_ = observer;
71 Refresh();
72 }
73
74 int AshDesktopMediaList::GetSourceCount() const {
75 return sources_.size();
76 }
77
78 const DesktopMediaList::Source& AshDesktopMediaList::GetSource(
79 int index) const {
80 return sources_[index];
81 }
82
83 // static
84 bool AshDesktopMediaList::CompareSources(const SourceDescription& a,
85 const SourceDescription& b) {
86 return a.id < b.id;
87 }
88
89 void AshDesktopMediaList::Refresh() {
90 std::vector<SourceDescription> new_sources;
91 EnumerateSources(&new_sources);
92
93 // Sort the list of sources so that they appear in a predictable order.
94 std::sort(new_sources.begin(), new_sources.end(), CompareSources);
95
96 // Step through |new_sources| adding and removing entries from |sources_|, and
97 // notifying the |observer_|, until two match. Requires that |sources| and
98 // |sources_| have the same ordering.
99 size_t pos = 0;
100 while (pos < sources_.size() || pos < new_sources.size()) {
101 // If |sources_[pos]| is not in |new_sources| then remove it.
102 if (pos < sources_.size() &&
103 (pos == new_sources.size() || sources_[pos].id < new_sources[pos].id)) {
104 sources_.erase(sources_.begin() + pos);
105 observer_->OnSourceRemoved(pos);
106 continue;
107 }
108
109 if (pos == sources_.size() || !(sources_[pos].id == new_sources[pos].id)) {
110 sources_.insert(sources_.begin() + pos, Source());
111 sources_[pos].id = new_sources[pos].id;
112 sources_[pos].name = new_sources[pos].name;
113 observer_->OnSourceAdded(pos);
114 } else if (sources_[pos].name != new_sources[pos].name) {
115 sources_[pos].name = new_sources[pos].name;
116 observer_->OnSourceNameChanged(pos);
117 }
118
119 ++pos;
120 }
121
122 DCHECK_EQ(new_sources.size(), sources_.size());
123 }
124
125 void AshDesktopMediaList::EnumerateWindowsForRoot(
126 std::vector<AshDesktopMediaList::SourceDescription>* sources,
127 aura::Window* root_window,
128 int container_id) {
129 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
130
131 aura::Window* container = ash::Shell::GetContainer(root_window, container_id);
132 if (!container)
133 return;
134 for (aura::Window::Windows::const_iterator it = container->children().begin();
135 it != container->children().end(); ++it) {
136 if (!(*it)->IsVisible() || !(*it)->CanFocus())
137 continue;
138 content::DesktopMediaID id =
139 content::DesktopMediaID::RegisterAuraWindow(*it);
140 if (id.id == view_dialog_id_)
141 continue;
142 SourceDescription window_source(id, (*it)->title());
143 sources->push_back(window_source);
144
145 CaptureThumbnail(window_source.id, *it);
146 }
147 }
148
149 void AshDesktopMediaList::EnumerateSources(
150 std::vector<AshDesktopMediaList::SourceDescription>* sources) {
151 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
152
153 aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows();
154
155 for (aura::Window::Windows::const_iterator iter = root_windows.begin();
156 iter != root_windows.end(); ++iter) {
157 if (source_types_ & SCREENS) {
158 SourceDescription screen_source(
159 content::DesktopMediaID::RegisterAuraWindow(*iter), (*iter)->title());
160 sources->push_back(screen_source);
161
162 CaptureThumbnail(screen_source.id, *iter);
163 }
164
165 if (source_types_ & WINDOWS) {
166 EnumerateWindowsForRoot(
167 sources, *iter, ash::internal::kShellWindowId_DefaultContainer);
168 EnumerateWindowsForRoot(
169 sources, *iter, ash::internal::kShellWindowId_AlwaysOnTopContainer);
170 EnumerateWindowsForRoot(
171 sources, *iter, ash::internal::kShellWindowId_DockedContainer);
172 }
173 }
174 }
175
176 void AshDesktopMediaList::CaptureThumbnail(content::DesktopMediaID id,
177 aura::Window* window) {
178 gfx::Rect window_rect(window->bounds().width(), window->bounds().height());
179 gfx::Rect scaled_rect = media::ComputeLetterboxRegion(
180 gfx::Rect(thumbnail_size_), window_rect.size());
181
182 ++pending_window_capture_requests_;
183 ui::GrapWindowSnapshotAsync(
184 window, window_rect,
185 scaled_rect.size(),
186 BrowserThread::GetBlockingPool(),
187 base::Bind(&AshDesktopMediaList::OnThumbnailCaptured,
188 weak_factory_.GetWeakPtr(),
189 id));
190 }
191
192 void AshDesktopMediaList::OnThumbnailCaptured(content::DesktopMediaID id,
193 const gfx::Image& image) {
194 for (size_t i = 0; i < sources_.size(); ++i) {
195 if (sources_[i].id == id) {
196 sources_[i].thumbnail = image.AsImageSkia();
197 observer_->OnSourceThumbnailChanged(i);
198 break;
199 }
200 }
201
202 --pending_window_capture_requests_;
203 DCHECK_GE(pending_window_capture_requests_, 0);
204
205 if (!pending_window_capture_requests_) {
206 // Once we've finished capturing all windows post a task for the next list
207 // update.
208 BrowserThread::PostDelayedTask(
209 BrowserThread::UI, FROM_HERE,
210 base::Bind(&AshDesktopMediaList::Refresh,
211 weak_factory_.GetWeakPtr()),
212 update_period_);
213 }
214 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698