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

Side by Side Diff: mojo/examples/window_manager/window_manager.cc

Issue 684543003: Move //mojo/examples to //examples (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 6 years, 1 month 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 2014 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 "base/bind.h"
6 #include "base/macros.h"
7 #include "mojo/application/application_runner_chromium.h"
8 #include "mojo/converters/geometry/geometry_type_converters.h"
9 #include "mojo/converters/input_events/input_events_type_converters.h"
10 #include "mojo/examples/keyboard/keyboard.mojom.h"
11 #include "mojo/examples/window_manager/debug_panel.h"
12 #include "mojo/examples/window_manager/window_manager.mojom.h"
13 #include "mojo/public/c/system/main.h"
14 #include "mojo/public/cpp/application/application_connection.h"
15 #include "mojo/public/cpp/application/application_delegate.h"
16 #include "mojo/public/cpp/application/application_impl.h"
17 #include "mojo/public/cpp/application/interface_factory_impl.h"
18 #include "mojo/public/cpp/application/service_provider_impl.h"
19 #include "mojo/services/public/cpp/view_manager/view.h"
20 #include "mojo/services/public/cpp/view_manager/view_manager.h"
21 #include "mojo/services/public/cpp/view_manager/view_manager_delegate.h"
22 #include "mojo/services/public/cpp/view_manager/view_observer.h"
23 #include "mojo/services/public/interfaces/input_events/input_events.mojom.h"
24 #include "mojo/services/public/interfaces/navigation/navigation.mojom.h"
25 #include "mojo/services/window_manager/window_manager_app.h"
26 #include "mojo/services/window_manager/window_manager_delegate.h"
27 #include "mojo/views/views_init.h"
28 #include "ui/aura/window.h"
29 #include "ui/events/event.h"
30 #include "ui/events/event_constants.h"
31 #include "ui/gfx/geometry/size_conversions.h"
32 #include "ui/wm/core/focus_rules.h"
33
34 #if defined CreateWindow
35 #undef CreateWindow
36 #endif
37
38 namespace mojo {
39 namespace examples {
40
41 class WindowManager;
42
43 namespace {
44
45 const int kBorderInset = 25;
46 const int kControlPanelWidth = 200;
47 const int kTextfieldHeight = 25;
48
49 class WMFocusRules : public wm::FocusRules {
50 public:
51 WMFocusRules(mojo::WindowManagerApp* window_manager_app,
52 mojo::View* window_container)
53 : window_container_(window_container),
54 window_manager_app_(window_manager_app) {}
55 virtual ~WMFocusRules() {}
56
57 private:
58 // Overridden from wm::FocusRules:
59 virtual bool IsToplevelWindow(aura::Window* window) const override {
60 return mojo::WindowManagerApp::GetViewForWindow(window)->parent() ==
61 window_container_;
62 }
63 virtual bool CanActivateWindow(aura::Window* window) const override {
64 return mojo::WindowManagerApp::GetViewForWindow(window)->parent() ==
65 window_container_;
66 }
67 virtual bool CanFocusWindow(aura::Window* window) const override {
68 return true;
69 }
70 virtual aura::Window* GetToplevelWindow(aura::Window* window) const override {
71 mojo::View* view = mojo::WindowManagerApp::GetViewForWindow(window);
72 while (view->parent() != window_container_) {
73 view = view->parent();
74 // Unparented hierarchy, there is no "top level" window.
75 if (!view)
76 return NULL;
77 }
78
79 return window_manager_app_->GetWindowForViewId(view->id());
80 }
81 virtual aura::Window* GetActivatableWindow(
82 aura::Window* window) const override {
83 return GetToplevelWindow(window);
84 }
85 virtual aura::Window* GetFocusableWindow(
86 aura::Window* window) const override {
87 return window;
88 }
89 virtual aura::Window* GetNextActivatableWindow(
90 aura::Window* ignore) const override {
91 aura::Window* activatable = GetActivatableWindow(ignore);
92 const aura::Window::Windows& children = activatable->parent()->children();
93 for (aura::Window::Windows::const_reverse_iterator it = children.rbegin();
94 it != children.rend(); ++it) {
95 if (*it != ignore)
96 return *it;
97 }
98 return NULL;
99 }
100
101 mojo::View* window_container_;
102 mojo::WindowManagerApp* window_manager_app_;
103
104 DISALLOW_COPY_AND_ASSIGN(WMFocusRules);
105 };
106
107 } // namespace
108
109 class WindowManagerConnection : public InterfaceImpl<IWindowManager> {
110 public:
111 explicit WindowManagerConnection(WindowManager* window_manager)
112 : window_manager_(window_manager) {}
113 virtual ~WindowManagerConnection() {}
114
115 private:
116 // Overridden from IWindowManager:
117 virtual void CloseWindow(Id view_id) override;
118 virtual void ShowKeyboard(Id view_id, RectPtr bounds) override;
119 virtual void HideKeyboard(Id view_id) override;
120
121 WindowManager* window_manager_;
122
123 DISALLOW_COPY_AND_ASSIGN(WindowManagerConnection);
124 };
125
126 class NavigatorHostImpl : public InterfaceImpl<NavigatorHost> {
127 public:
128 explicit NavigatorHostImpl(WindowManager* window_manager, Id view_id)
129 : window_manager_(window_manager), view_id_(view_id) {}
130 virtual ~NavigatorHostImpl() {
131 }
132
133 private:
134 virtual void DidNavigateLocally(const mojo::String& url) override;
135 virtual void RequestNavigate(Target target, URLRequestPtr request) override;
136
137 WindowManager* window_manager_;
138 Id view_id_;
139
140 DISALLOW_COPY_AND_ASSIGN(NavigatorHostImpl);
141 };
142
143 class KeyboardManager : public KeyboardClient,
144 public ViewObserver {
145 public:
146 KeyboardManager() : view_manager_(NULL), view_(NULL) {
147 }
148 virtual ~KeyboardManager() {
149 if (view_)
150 view_->parent()->RemoveObserver(this);
151 }
152
153 View* view() { return view_; }
154
155 void Init(ApplicationImpl* application,
156 ViewManager* view_manager,
157 View* parent,
158 const Rect& bounds) {
159 view_manager_ = view_manager;
160 view_ = View::Create(view_manager);
161 view_->SetBounds(bounds);
162 parent->AddChild(view_);
163 view_->Embed("mojo:keyboard");
164 application->ConnectToService("mojo:keyboard", &keyboard_service_);
165 keyboard_service_.set_client(this);
166 parent->AddObserver(this);
167 }
168
169 void Show(Id view_id, const Rect& bounds) {
170 keyboard_service_->SetTarget(view_id);
171 view_->SetVisible(true);
172 }
173
174 void Hide(Id view_id) {
175 keyboard_service_->SetTarget(0);
176 view_->SetVisible(false);
177 }
178
179 private:
180 // KeyboardClient:
181 virtual void OnKeyboardEvent(Id view_id,
182 int32_t code,
183 int32_t flags) override {
184 // TODO(sky): figure this out. Code use to dispatch events, but that's a
185 // hack. Instead strings should be passed through, or maybe a richer text
186 // input interface.
187 }
188
189 // Overridden from ViewObserver:
190 virtual void OnViewBoundsChanged(View* parent,
191 const Rect& old_bounds,
192 const Rect& new_bounds) override {
193 Rect keyboard_bounds(view_->bounds());
194 keyboard_bounds.y =
195 new_bounds.y + new_bounds.height - keyboard_bounds.height;
196 keyboard_bounds.width =
197 keyboard_bounds.width + new_bounds.width - old_bounds.width;
198 view_->SetBounds(keyboard_bounds);
199 }
200 virtual void OnViewDestroyed(View* parent) override {
201 DCHECK_EQ(parent, view_->parent());
202 parent->RemoveObserver(this);
203 view_ = NULL;
204 }
205
206 KeyboardServicePtr keyboard_service_;
207 ViewManager* view_manager_;
208
209 // View the keyboard is attached to.
210 View* view_;
211
212 DISALLOW_COPY_AND_ASSIGN(KeyboardManager);
213 };
214
215 class RootLayoutManager : public ViewObserver {
216 public:
217 RootLayoutManager(ViewManager* view_manager,
218 View* root,
219 Id content_view_id,
220 Id launcher_ui_view_id,
221 Id control_panel_view_id)
222 : root_(root),
223 view_manager_(view_manager),
224 content_view_id_(content_view_id),
225 launcher_ui_view_id_(launcher_ui_view_id),
226 control_panel_view_id_(control_panel_view_id) {}
227 virtual ~RootLayoutManager() {
228 if (root_)
229 root_->RemoveObserver(this);
230 }
231
232 private:
233 // Overridden from ViewObserver:
234 virtual void OnViewBoundsChanged(View* view,
235 const Rect& old_bounds,
236 const Rect& new_bounds) override {
237 DCHECK_EQ(view, root_);
238
239 View* content_view = view_manager_->GetViewById(content_view_id_);
240 content_view->SetBounds(new_bounds);
241
242 int delta_width = new_bounds.width - old_bounds.width;
243 int delta_height = new_bounds.height - old_bounds.height;
244
245 View* launcher_ui_view =
246 view_manager_->GetViewById(launcher_ui_view_id_);
247 Rect launcher_ui_bounds(launcher_ui_view->bounds());
248 launcher_ui_bounds.width += delta_width;
249 launcher_ui_view->SetBounds(launcher_ui_bounds);
250
251 View* control_panel_view =
252 view_manager_->GetViewById(control_panel_view_id_);
253 Rect control_panel_bounds(control_panel_view->bounds());
254 control_panel_bounds.x += delta_width;
255 control_panel_view->SetBounds(control_panel_bounds);
256
257 const View::Children& content_views = content_view->children();
258 View::Children::const_iterator iter = content_views.begin();
259 for(; iter != content_views.end(); ++iter) {
260 View* view = *iter;
261 if (view->id() == control_panel_view->id() ||
262 view->id() == launcher_ui_view->id())
263 continue;
264 Rect view_bounds(view->bounds());
265 view_bounds.width += delta_width;
266 view_bounds.height += delta_height;
267 view->SetBounds(view_bounds);
268 }
269 }
270 virtual void OnViewDestroyed(View* view) override {
271 DCHECK_EQ(view, root_);
272 root_->RemoveObserver(this);
273 root_ = NULL;
274 }
275
276 View* root_;
277 ViewManager* view_manager_;
278 const Id content_view_id_;
279 const Id launcher_ui_view_id_;
280 const Id control_panel_view_id_;
281
282 DISALLOW_COPY_AND_ASSIGN(RootLayoutManager);
283 };
284
285 class Window : public InterfaceFactory<NavigatorHost> {
286 public:
287 Window(WindowManager* window_manager, View* view)
288 : window_manager_(window_manager), view_(view) {}
289
290 virtual ~Window() {}
291
292 View* view() const { return view_; }
293
294 void Embed(const std::string& url) {
295 scoped_ptr<ServiceProviderImpl> service_provider_impl(
296 new ServiceProviderImpl());
297 service_provider_impl->AddService<NavigatorHost>(this);
298 view_->Embed(url, service_provider_impl.Pass());
299 }
300
301 private:
302 // InterfaceFactory<NavigatorHost>
303 virtual void Create(ApplicationConnection* connection,
304 InterfaceRequest<NavigatorHost> request) override {
305 BindToRequest(new NavigatorHostImpl(window_manager_, view_->id()),
306 &request);
307 }
308
309 WindowManager* window_manager_;
310 View* view_;
311 };
312
313 class WindowManager
314 : public ApplicationDelegate,
315 public DebugPanel::Delegate,
316 public ViewManagerDelegate,
317 public WindowManagerDelegate,
318 public ui::EventHandler {
319 public:
320 WindowManager()
321 : shell_(nullptr),
322 window_manager_factory_(this),
323 launcher_ui_(NULL),
324 view_manager_(NULL),
325 window_manager_app_(new WindowManagerApp(this, this)),
326 app_(NULL) {}
327
328 virtual ~WindowManager() {
329 // host() may be destroyed by the time we get here.
330 // TODO: figure out a way to always cleanly remove handler.
331 if (window_manager_app_->host())
332 window_manager_app_->host()->window()->RemovePreTargetHandler(this);
333 }
334
335 void CloseWindow(Id view_id) {
336 WindowVector::iterator iter = GetWindowByViewId(view_id);
337 DCHECK(iter != windows_.end());
338 Window* window = *iter;
339 windows_.erase(iter);
340 window->view()->Destroy();
341 }
342
343 void ShowKeyboard(Id view_id, const Rect& bounds) {
344 // TODO: this needs to validate |view_id|. That is, it shouldn't assume
345 // |view_id| is valid and it also needs to make sure the client that sent
346 // this really owns |view_id|.
347 // TODO: honor |bounds|.
348 if (!keyboard_manager_) {
349 keyboard_manager_.reset(new KeyboardManager);
350 View* parent = view_manager_->GetRoots().back();
351 int ideal_height = 200;
352 // TODO(sky): 10 is a bit of a hack here. There is a bug that causes
353 // white strips to appear when 0 is used. Figure this out!
354 Rect keyboard_bounds;
355 keyboard_bounds.x = 10;
356 keyboard_bounds.y = parent->bounds().height - ideal_height;
357 keyboard_bounds.width = parent->bounds().width - 20;
358 keyboard_bounds.height = ideal_height;
359 keyboard_manager_->Init(app_, view_manager_, parent, keyboard_bounds);
360 }
361 keyboard_manager_->Show(view_id, bounds);
362 }
363
364 void HideKeyboard(Id view_id) {
365 // See comment in ShowKeyboard() about validating args.
366 if (keyboard_manager_)
367 keyboard_manager_->Hide(view_id);
368 }
369
370 void DidNavigateLocally(uint32 source_view_id, const mojo::String& url) {
371 LOG(ERROR) << "DidNavigateLocally: source_view_id: " << source_view_id
372 << " url: " << url.To<std::string>();
373 }
374
375 // Overridden from DebugPanel::Delegate:
376 virtual void CloseTopWindow() override {
377 if (!windows_.empty())
378 CloseWindow(windows_.back()->view()->id());
379 }
380
381 virtual void RequestNavigate(uint32 source_view_id,
382 Target target,
383 URLRequestPtr request) override {
384 OnLaunch(source_view_id, target, request->url);
385 }
386
387 private:
388 typedef std::vector<Window*> WindowVector;
389
390 // Overridden from ApplicationDelegate:
391 virtual void Initialize(ApplicationImpl* app) override {
392 shell_ = app->shell();
393 app_ = app;
394 views_init_.reset(new ViewsInit);
395 window_manager_app_->Initialize(app);
396 }
397
398 virtual bool ConfigureIncomingConnection(
399 ApplicationConnection* connection) override {
400 connection->AddService(&window_manager_factory_);
401 window_manager_app_->ConfigureIncomingConnection(connection);
402 return true;
403 }
404
405 // Overridden from ViewManagerDelegate:
406 virtual void OnEmbed(ViewManager* view_manager,
407 View* root,
408 ServiceProviderImpl* exported_services,
409 scoped_ptr<ServiceProvider> imported_services) override {
410 DCHECK(!view_manager_);
411 view_manager_ = view_manager;
412
413 View* view = View::Create(view_manager_);
414 root->AddChild(view);
415 Rect rect;
416 rect.width = root->bounds().width;
417 rect.height = root->bounds().height;
418 view->SetBounds(rect);
419 content_view_id_ = view->id();
420
421 Id launcher_ui_id = CreateLauncherUI();
422 Id control_panel_id = CreateControlPanel(view);
423
424 root_layout_manager_.reset(
425 new RootLayoutManager(view_manager, root,
426 content_view_id_,
427 launcher_ui_id,
428 control_panel_id));
429 root->AddObserver(root_layout_manager_.get());
430
431 window_manager_app_->host()->window()->AddPreTargetHandler(this);
432
433 window_manager_app_->InitFocus(new WMFocusRules(window_manager_app_.get(),
434 view));
435 }
436 virtual void OnViewManagerDisconnected(ViewManager* view_manager) override {
437 DCHECK_EQ(view_manager_, view_manager);
438 view_manager_ = NULL;
439 base::MessageLoop::current()->Quit();
440 }
441
442 // Overridden from WindowManagerDelegate:
443 virtual void Embed(
444 const String& url,
445 InterfaceRequest<ServiceProvider> service_provider) override {
446 const Id kInvalidSourceViewId = 0;
447 OnLaunch(kInvalidSourceViewId, TARGET_DEFAULT, url);
448 }
449
450 // Overridden from ui::EventHandler:
451 virtual void OnEvent(ui::Event* event) override {
452 View* view = WindowManagerApp::GetViewForWindow(
453 static_cast<aura::Window*>(event->target()));
454 if (event->type() == ui::ET_MOUSE_PRESSED &&
455 !IsDescendantOfKeyboard(view)) {
456 view->SetFocus();
457 }
458 }
459
460 void OnLaunch(uint32 source_view_id,
461 Target requested_target,
462 const mojo::String& url) {
463 Target target = debug_panel_->navigation_target();
464 if (target == TARGET_DEFAULT) {
465 if (requested_target != TARGET_DEFAULT) {
466 target = requested_target;
467 } else {
468 // TODO(aa): Should be TARGET_NEW_NODE if source origin and dest origin
469 // are different?
470 target = TARGET_SOURCE_NODE;
471 }
472 }
473
474 Window* dest_view = NULL;
475 if (target == TARGET_SOURCE_NODE) {
476 WindowVector::iterator source_view = GetWindowByViewId(source_view_id);
477 bool app_initiated = source_view != windows_.end();
478 if (app_initiated)
479 dest_view = *source_view;
480 else if (!windows_.empty())
481 dest_view = windows_.back();
482 }
483
484 if (!dest_view) {
485 dest_view = CreateWindow();
486 windows_.push_back(dest_view);
487 }
488
489 dest_view->Embed(url);
490 }
491
492 // TODO(beng): proper layout manager!!
493 Id CreateLauncherUI() {
494 View* view = view_manager_->GetViewById(content_view_id_);
495 Rect bounds = view->bounds();
496 bounds.x += kBorderInset;
497 bounds.y += kBorderInset;
498 bounds.width -= 2 * kBorderInset;
499 bounds.height = kTextfieldHeight;
500 launcher_ui_ = CreateWindow(bounds);
501 launcher_ui_->Embed("mojo:browser");
502 return launcher_ui_->view()->id();
503 }
504
505 Window* CreateWindow() {
506 View* view = view_manager_->GetViewById(content_view_id_);
507 Rect bounds;
508 bounds.x = kBorderInset;
509 bounds.y = 2 * kBorderInset + kTextfieldHeight;
510 bounds.width = view->bounds().width - 3 * kBorderInset - kControlPanelWidth;
511 bounds.height =
512 view->bounds().height - (3 * kBorderInset + kTextfieldHeight);
513 if (!windows_.empty()) {
514 bounds.x = windows_.back()->view()->bounds().x + 35;
515 bounds.y = windows_.back()->view()->bounds().y + 35;
516 }
517 return CreateWindow(bounds);
518 }
519
520 Window* CreateWindow(const Rect& bounds) {
521 View* content = view_manager_->GetViewById(content_view_id_);
522 View* view = View::Create(view_manager_);
523 content->AddChild(view);
524 view->SetBounds(bounds);
525 view->SetFocus();
526 return new Window(this, view);
527 }
528
529 bool IsDescendantOfKeyboard(View* target) {
530 return keyboard_manager_.get() &&
531 keyboard_manager_->view()->Contains(target);
532 }
533
534 Id CreateControlPanel(View* root) {
535 View* view = View::Create(view_manager_);
536 root->AddChild(view);
537
538 Rect bounds;
539 bounds.x = root->bounds().width - kControlPanelWidth - kBorderInset;
540 bounds.y = kBorderInset * 2 + kTextfieldHeight;
541 bounds.width = kControlPanelWidth;
542 bounds.height =
543 root->bounds().height - kBorderInset * 3 - kTextfieldHeight;
544 view->SetBounds(bounds);
545
546 debug_panel_ = new DebugPanel(this, shell_, view);
547 return view->id();
548 }
549
550 WindowVector::iterator GetWindowByViewId(Id view_id) {
551 for (std::vector<Window*>::iterator iter = windows_.begin();
552 iter != windows_.end();
553 ++iter) {
554 if ((*iter)->view()->id() == view_id) {
555 return iter;
556 }
557 }
558 return windows_.end();
559 }
560
561 Shell* shell_;
562
563 InterfaceFactoryImplWithContext<WindowManagerConnection, WindowManager>
564 window_manager_factory_;
565
566 scoped_ptr<ViewsInit> views_init_;
567 DebugPanel* debug_panel_;
568 Window* launcher_ui_;
569 WindowVector windows_;
570 ViewManager* view_manager_;
571 scoped_ptr<RootLayoutManager> root_layout_manager_;
572
573 scoped_ptr<WindowManagerApp> window_manager_app_;
574
575 // Id of the view most content is added to. The keyboard is NOT added here.
576 Id content_view_id_;
577
578 scoped_ptr<KeyboardManager> keyboard_manager_;
579 ApplicationImpl* app_;
580
581 DISALLOW_COPY_AND_ASSIGN(WindowManager);
582 };
583
584 void WindowManagerConnection::CloseWindow(Id view_id) {
585 window_manager_->CloseWindow(view_id);
586 }
587
588 void WindowManagerConnection::ShowKeyboard(Id view_id, RectPtr bounds) {
589 window_manager_->ShowKeyboard(view_id, *bounds);
590 }
591
592 void WindowManagerConnection::HideKeyboard(Id view_id) {
593 window_manager_->HideKeyboard(view_id);
594 }
595
596 void NavigatorHostImpl::DidNavigateLocally(const mojo::String& url) {
597 window_manager_->DidNavigateLocally(view_id_, url);
598 }
599
600 void NavigatorHostImpl::RequestNavigate(Target target, URLRequestPtr request) {
601 window_manager_->RequestNavigate(view_id_, target, request.Pass());
602 }
603
604 } // namespace examples
605 } // namespace mojo
606
607 MojoResult MojoMain(MojoHandle shell_handle) {
608 mojo::ApplicationRunnerChromium runner(new mojo::examples::WindowManager);
609 return runner.Run(shell_handle);
610 }
OLDNEW
« no previous file with comments | « mojo/examples/window_manager/debug_panel.cc ('k') | mojo/examples/window_manager/window_manager.mojom » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698