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