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

Side by Side Diff: mash/browser/browser.cc

Issue 1981623002: Add a basic browser to mash that uses the navigation service. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: . Created 4 years, 7 months 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
OLDNEW
(Empty)
1 // Copyright 2016 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 "mash/browser/browser.h"
6
7 #include "base/macros.h"
8 #include "base/memory/weak_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/string16.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/timer/timer.h"
14 #include "components/mus/public/cpp/window.h"
15 #include "components/mus/public/cpp/window_tree_connection.h"
16 #include "mash/public/interfaces/launchable.mojom.h"
17 #include "mojo/converters/geometry/geometry_type_converters.h"
18 #include "mojo/public/c/system/main.h"
19 #include "services/navigation/public/interfaces/view.mojom.h"
20 #include "services/shell/public/cpp/application_runner.h"
21 #include "services/shell/public/cpp/connector.h"
22 #include "services/shell/public/cpp/shell_client.h"
23 #include "services/tracing/public/cpp/tracing_impl.h"
24 #include "ui/aura/mus/mus_util.h"
25 #include "ui/gfx/canvas.h"
26 #include "ui/gfx/paint_throbber.h"
27 #include "ui/gfx/text_constants.h"
28 #include "ui/native_theme/native_theme.h"
29 #include "ui/views/background.h"
30 #include "ui/views/controls/button/label_button.h"
31 #include "ui/views/controls/textfield/textfield.h"
32 #include "ui/views/controls/textfield/textfield_controller.h"
33 #include "ui/views/mus/aura_init.h"
34 #include "ui/views/mus/window_manager_connection.h"
35 #include "ui/views/widget/widget_delegate.h"
36 #include "url/gurl.h"
37
38 namespace views {
39 class AuraInit;
sky 2016/05/16 15:31:58 You shouldn't need to forward declare this as you
40 }
41
42 namespace mash {
43 namespace browser {
44
45 void EnableButton(views::CustomButton* button, bool enabled) {
46 button->SetState(enabled ? views::Button::STATE_NORMAL
47 : views::Button::STATE_DISABLED);
48 }
49
50 class ProgressBar : public views::View {
sky 2016/05/16 15:31:58 Did you try using the ProgressBar in views?
51 public:
52 ProgressBar() {}
53 ~ProgressBar() override {}
54
55 void SetProgress(double progress) {
56 progress_ = progress;
57 SchedulePaint();
58 }
59
60 private:
61 void OnPaint(gfx::Canvas* canvas) override {
62 if (progress_ == 0.f) {
63 gfx::Rect progress_rect = GetLocalBounds();
64 progress_rect.set_y(progress_rect.bottom() - 1);
65 progress_rect.set_height(1);
66 canvas->FillRect(progress_rect, SK_ColorGRAY);
67 } else {
68 gfx::Rect progress_rect = GetLocalBounds();
69 progress_rect.set_width(progress_rect.width() * progress_);
70 canvas->FillRect(progress_rect, SK_ColorRED);
71 }
72 }
73
74 double progress_ = 0.f;
75
76 DISALLOW_COPY_AND_ASSIGN(ProgressBar);
77 };
78
79 class Throbber : public views::View {
80 public:
81 Throbber() : timer_(false, true), weak_factory_(this) {}
82 ~Throbber() override {}
83
84 void Throb() {
sky 2016/05/16 15:31:58 nit: you have a Stop(), I would be inclined to cal
85 throbbing_ = true;
sky 2016/05/16 15:31:58 DCHECK(!throbbing_), or perhaps early out if alrea
86 start_time_ = base::TimeTicks();
sky 2016/05/16 15:31:58 base::TimeTicks::Now()?
87 SchedulePaint();
88 timer_.Start(
89 FROM_HERE, base::TimeDelta::FromMilliseconds(16),
sky 2016/05/16 15:31:58 You sure you want 16? We changed chrome to 30 a wh
90 base::Bind(&Throbber::SchedulePaint,
91 weak_factory_.GetWeakPtr()));
92 }
93
94 void Stop() {
95 throbbing_ = false;
96 if (timer_.IsRunning())
97 timer_.Stop();
98 SchedulePaint();
99 }
100
101 private:
102 void OnPaint(gfx::Canvas* canvas) override {
103 if (!throbbing_)
104 return;
105
106 if (start_time_ == base::TimeTicks())
sky 2016/05/16 15:31:58 How come you set this here and not in Throb?
107 start_time_ = base::TimeTicks::Now();
108
109 gfx::PaintThrobberSpinning(
110 canvas, GetLocalBounds(),
111 GetNativeTheme()->GetSystemColor(
112 ui::NativeTheme::kColorId_ThrobberSpinningColor),
113 base::TimeTicks::Now() - start_time_);
114 }
115
116 bool throbbing_ = false;
117 base::TimeTicks start_time_;
118 base::Timer timer_;
119 base::WeakPtrFactory<Throbber> weak_factory_;
120
121 DISALLOW_COPY_AND_ASSIGN(Throbber);
122 };
123
124 class UI : public views::WidgetDelegateView,
125 public views::ButtonListener,
126 public views::TextfieldController,
127 public navigation::mojom::ViewClient {
128 public:
129 enum class Type {
130 WINDOW,
131 POPUP
132 };
133
134 UI(Browser* browser,
135 Type type,
136 navigation::mojom::ViewPtr view,
137 navigation::mojom::ViewClientRequest request)
138 : browser_(browser),
139 type_(type),
140 back_button_(new views::LabelButton(this, L"Back")),
141 forward_button_(new views::LabelButton(this, L"Forward")),
142 reload_button_(new views::LabelButton(this, L"Reload")),
143 prompt_(new views::Textfield),
144 throbber_(new Throbber),
145 progress_bar_(new ProgressBar),
146 view_(std::move(view)),
147 view_client_binding_(this, std::move(request)) {
148 set_background(views::Background::CreateStandardPanelBackground());
149 prompt_->set_controller(this);
150 back_button_->set_request_focus_on_press(false);
151 forward_button_->set_request_focus_on_press(false);
152 reload_button_->set_request_focus_on_press(false);
153 AddChildView(back_button_);
154 AddChildView(forward_button_);
155 AddChildView(reload_button_);
156 AddChildView(prompt_);
157 AddChildView(throbber_);
158 AddChildView(progress_bar_);
159 }
160 ~UI() override {
161 browser_->RemoveWindow(GetWidget());
162 }
163
164 void NavigateTo(const GURL& url) {
165 view_->NavigateTo(url);
166 }
167
168 private:
169 // Overridden from views::WidgetDelegate:
170 views::View* GetContentsView() override { return this; }
171 base::string16 GetWindowTitle() const override {
172 // TODO(beng): use resources.
173 if (current_title_.empty())
174 return base::ASCIIToUTF16("Browser");
175 base::string16 format = base::ASCIIToUTF16("%s - Browser");
176 base::ReplaceFirstSubstringAfterOffset(
177 &format, 0, base::ASCIIToUTF16("%s"), current_title_);
178 return format;
179 }
180 bool CanResize() const override { return true; }
181 bool CanMaximize() const override { return true; }
182 bool CanMinimize() const override { return true; }
183
184 // views::ButtonListener:
185 void ButtonPressed(views::Button* sender,
186 const ui::Event& event) override {
187 if (sender == back_button_) {
188 view_->GoBack();
189 } else if (sender == forward_button_) {
190 view_->GoForward();
191 } else if (sender == reload_button_) {
192 if (is_loading_)
193 view_->Stop();
194 else
195 view_->Reload(false);
196 }
197 }
198
199 // Overridden from views::View:
200 void Layout() override {
201 gfx::Rect local_bounds = GetLocalBounds();
202 gfx::Rect bounds = local_bounds;
203 bounds.Inset(5, 5);
204
205 gfx::Size ps = back_button_->GetPreferredSize();
206 back_button_->SetBoundsRect(
207 gfx::Rect(bounds.x(), bounds.y(), ps.width(), ps.height()));
sky 2016/05/16 15:31:58 nit: run git cl format
208 ps = forward_button_->GetPreferredSize();
209 forward_button_->SetBoundsRect(
210 gfx::Rect(back_button_->bounds().right() + 5, bounds.y(),
211 ps.width(), ps.height()));
212 ps = reload_button_->GetPreferredSize();
213 reload_button_->SetBoundsRect(
214 gfx::Rect(forward_button_->bounds().right() + 5, bounds.y(),
215 ps.width(), ps.height()));
216
217 ps = prompt_->GetPreferredSize();
218 int prompt_y =
219 bounds.y() + (reload_button_->bounds().height() - ps.height()) / 2;
220 int width =
221 bounds.width() - reload_button_->bounds().right() - ps.height() - 10;
222 prompt_->SetBoundsRect(
223 gfx::Rect(reload_button_->bounds().right() + 5, prompt_y, width,
224 ps.height()));
225 throbber_->SetBoundsRect(
226 gfx::Rect(prompt_->bounds().right() + 5, prompt_->bounds().y(),
227 ps.height(), ps.height()));
228
229 gfx::Rect progress_bar_rect(
230 local_bounds.x(), back_button_->bounds().bottom() + 5,
231 local_bounds.width(), 2);
232 progress_bar_->SetBoundsRect(progress_bar_rect);
233
234 if (content_area_) {
235 int x = local_bounds.x();
236 int y = type_ == Type::POPUP ? 0 : progress_bar_->bounds().bottom();
237 gfx::Point offset(x, y);
238 ConvertPointToWidget(this, &offset);
239 int width = local_bounds.width();
240 int height = local_bounds.height() - y;
241 content_area_->SetBounds(
242 gfx::Rect(offset.x(), offset.y(), width, height));
243 }
244 }
245 void ViewHierarchyChanged(
246 const views::View::ViewHierarchyChangedDetails& details) override {
247 if (details.is_add && GetWidget() && !content_area_) {
248 mus::Window* window = aura::GetMusWindow(GetWidget()->GetNativeWindow());
249 content_area_ = window->connection()->NewWindow(nullptr);
250 window->AddChild(content_area_);
251
252 mus::mojom::WindowTreeClientPtr client;
253 view_->GetWindowTreeClient(GetProxy(&client));
254 content_area_->Embed(std::move(client));
255 }
256 }
257
258 // Overridden from views::TextFieldController:
259 bool HandleKeyEvent(views::Textfield* sender,
260 const ui::KeyEvent& key_event) override {
261 switch (key_event.key_code()) {
262 case ui::VKEY_RETURN: {
263 view_->NavigateTo(GURL(prompt_->text()));
264 } break;
265 default:
266 break;
267 }
268 return false;
269 }
270
271 // navigation::mojom::ViewClient:
272 void LoadingStateChanged(bool is_loading) override {
273 is_loading_ = is_loading;
274 if (is_loading_) {
275 //reload_button_->SetText(L"Stop");
sky 2016/05/16 15:31:58 ?
276 throbber_->Throb();
277 } else {
278 reload_button_->SetText(L"Reload");
279 throbber_->Stop();
280 progress_bar_->SetProgress(0.f);
281 }
282 }
283 void NavigationStateChanged(const GURL& url,
284 const mojo::String& title,
285 bool can_go_back,
286 bool can_go_forward) override {
287 EnableButton(back_button_, can_go_back);
288 EnableButton(forward_button_, can_go_forward);
289 prompt_->SetText(base::UTF8ToUTF16(url.spec()));
290 current_title_ = base::UTF8ToUTF16(title.get());
291 GetWidget()->UpdateWindowTitle();
292 }
293 void LoadProgressChanged(double progress) override {
294 progress_bar_->SetProgress(progress);
295 }
296 void ViewCreated(navigation::mojom::ViewPtr view,
297 navigation::mojom::ViewClientRequest request,
298 bool is_popup,
299 mojo::RectPtr initial_rect,
300 bool user_gesture) override {
301 views::Widget* window = views::Widget::CreateWindowWithContextAndBounds(
302 new UI(browser_, is_popup ? UI::Type::POPUP : UI::Type::WINDOW,
303 std::move(view), std::move(request)), nullptr,
304 initial_rect.To<gfx::Rect>());
305 window->Show();
306 browser_->AddWindow(window);
307 }
308 void Close() override {
309 GetWidget()->Close();
310 }
311
312 Browser* browser_;
313
314 Type type_;
315
316 views::LabelButton* back_button_;
317 views::LabelButton* forward_button_;
318 views::LabelButton* reload_button_;
319 views::Textfield* prompt_;
320 Throbber* throbber_;
321 ProgressBar* progress_bar_;
322
323 mus::Window* content_area_ = nullptr;
324
325 navigation::mojom::ViewPtr view_;
326 mojo::Binding<navigation::mojom::ViewClient> view_client_binding_;
327
328 bool is_loading_ = false;
329 base::string16 current_title_;
330
331 DISALLOW_COPY_AND_ASSIGN(UI);
332 };
333
334 Browser::Browser() {}
335 Browser::~Browser() {}
336
337 void Browser::AddWindow(views::Widget* window) {
338 windows_.push_back(window);
339 }
340
341 void Browser::RemoveWindow(views::Widget* window) {
342 auto it = std::find(windows_.begin(), windows_.end(), window);
343 DCHECK(it != windows_.end());
344 windows_.erase(it);
345 if (windows_.empty())
346 base::MessageLoop::current()->QuitWhenIdle();
347 }
348
349 void Browser::Initialize(shell::Connector* connector,
350 const shell::Identity& identity,
351 uint32_t id) {
352 connector_ = connector;
353 tracing_.Initialize(connector, identity.name());
354
355 aura_init_.reset(new views::AuraInit(connector, "views_mus_resources.pak"));
356 views::WindowManagerConnection::Create(connector, identity);
357 }
358
359 bool Browser::AcceptConnection(shell::Connection* connection) {
360 connection->AddInterface<mojom::Launchable>(this);
361 return true;
362 }
363
364 void Browser::Launch(uint32_t what, mojom::LaunchMode how) {
365 bool reuse = how == mojom::LaunchMode::REUSE ||
366 how == mojom::LaunchMode::DEFAULT;
367 if (reuse && !windows_.empty()) {
368 windows_.back()->Activate();
369 return;
370 }
371
372 navigation::mojom::ViewFactoryPtr view_factory;
373 connector_->ConnectToInterface("exe:navigation", &view_factory);
374 navigation::mojom::ViewPtr view;
375 navigation::mojom::ViewClientPtr view_client;
376 navigation::mojom::ViewClientRequest view_client_request =
377 GetProxy(&view_client);
378 view_factory->CreateView(std::move(view_client), GetProxy(&view));
379 UI* ui = new UI(this, UI::Type::WINDOW, std::move(view),
380 std::move(view_client_request));
381 views::Widget* window = views::Widget::CreateWindowWithContextAndBounds(
382 ui, nullptr, gfx::Rect(10, 10, 1024, 600));
383 ui->NavigateTo(GURL("http://www.google.com/"));
384 window->Show();
385 AddWindow(window);
386 }
387
388 void Browser::Create(shell::Connection* connection,
389 mojom::LaunchableRequest request) {
390 bindings_.AddBinding(this, std::move(request));
391 }
392
393 } // namespace browser
394 } // namespace mash
OLDNEW
« mash/browser/browser.h ('K') | « mash/browser/browser.h ('k') | mash/browser/main.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698