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