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

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

Powered by Google App Engine
This is Rietveld 408576698