Index: mojo/services/window_manager/window_manager_app.cc |
diff --git a/mojo/services/window_manager/window_manager_app.cc b/mojo/services/window_manager/window_manager_app.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..99d2b356ee1b2c6063b953ec03fe5cbd6fc76cbb |
--- /dev/null |
+++ b/mojo/services/window_manager/window_manager_app.cc |
@@ -0,0 +1,417 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "mojo/services/window_manager/window_manager_app.h" |
+ |
+#include "base/message_loop/message_loop.h" |
+#include "base/stl_util.h" |
+#include "mojo/converters/geometry/geometry_type_converters.h" |
+#include "mojo/converters/input_events/input_events_type_converters.h" |
+#include "mojo/public/cpp/application/application_connection.h" |
+#include "mojo/public/cpp/application/application_impl.h" |
+#include "mojo/public/interfaces/application/shell.mojom.h" |
+#include "mojo/services/window_manager/capture_controller.h" |
+#include "mojo/services/window_manager/focus_controller.h" |
+#include "mojo/services/window_manager/focus_rules.h" |
+#include "mojo/services/window_manager/hit_test.h" |
+#include "mojo/services/window_manager/view_event_dispatcher.h" |
+#include "mojo/services/window_manager/view_target.h" |
+#include "mojo/services/window_manager/view_targeter.h" |
+#include "mojo/services/window_manager/window_manager_delegate.h" |
+#include "third_party/mojo_services/src/view_manager/public/cpp/view.h" |
+#include "third_party/mojo_services/src/view_manager/public/cpp/view_manager.h" |
+ |
+using mojo::ApplicationConnection; |
+using mojo::Id; |
+using mojo::ServiceProvider; |
+using mojo::View; |
+using mojo::WindowManager; |
+ |
+namespace window_manager { |
+ |
+namespace { |
+ |
+Id GetIdForView(View* view) { |
+ return view ? view->id() : 0; |
+} |
+ |
+} // namespace |
+ |
+// Used for calls to Embed() that occur before we've connected to the |
+// ViewManager. |
+struct WindowManagerApp::PendingEmbed { |
+ mojo::String url; |
+ mojo::InterfaceRequest<ServiceProvider> services; |
+ mojo::ServiceProviderPtr exposed_services; |
+}; |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// WindowManagerApp, public: |
+ |
+WindowManagerApp::WindowManagerApp( |
+ ViewManagerDelegate* view_manager_delegate, |
+ WindowManagerDelegate* window_manager_delegate) |
+ : shell_(nullptr), |
+ wrapped_view_manager_delegate_(view_manager_delegate), |
+ window_manager_delegate_(window_manager_delegate), |
+ root_(nullptr) { |
+} |
+ |
+WindowManagerApp::~WindowManagerApp() { |
+ // TODO(msw|sky): Should this destructor explicitly delete the ViewManager? |
+ mojo::ViewManager* cached_view_manager = view_manager(); |
+ for (RegisteredViewIdSet::const_iterator it = registered_view_id_set_.begin(); |
+ cached_view_manager && it != registered_view_id_set_.end(); ++it) { |
+ View* view = cached_view_manager->GetViewById(*it); |
+ if (view && view == root_) |
+ root_ = nullptr; |
+ if (view) |
+ view->RemoveObserver(this); |
+ } |
+ registered_view_id_set_.clear(); |
+ DCHECK(!root_); |
+ |
+ STLDeleteElements(&connections_); |
+} |
+ |
+void WindowManagerApp::AddConnection(WindowManagerImpl* connection) { |
+ DCHECK(connections_.find(connection) == connections_.end()); |
+ connections_.insert(connection); |
+} |
+ |
+void WindowManagerApp::RemoveConnection(WindowManagerImpl* connection) { |
+ DCHECK(connections_.find(connection) != connections_.end()); |
+ connections_.erase(connection); |
+} |
+ |
+bool WindowManagerApp::SetCapture(Id view_id) { |
+ View* view = view_manager()->GetViewById(view_id); |
+ return view && SetCaptureImpl(view); |
+} |
+ |
+bool WindowManagerApp::FocusWindow(Id view_id) { |
+ View* view = view_manager()->GetViewById(view_id); |
+ return view && FocusWindowImpl(view); |
+} |
+ |
+bool WindowManagerApp::ActivateWindow(Id view_id) { |
+ View* view = view_manager()->GetViewById(view_id); |
+ return view && ActivateWindowImpl(view); |
+} |
+ |
+bool WindowManagerApp::IsReady() const { |
+ return !!root_; |
+} |
+ |
+void WindowManagerApp::InitFocus(scoped_ptr<FocusRules> rules) { |
+ DCHECK(root_); |
+ |
+ focus_controller_.reset(new FocusController(rules.Pass())); |
+ focus_controller_->AddObserver(this); |
+ SetFocusController(root_, focus_controller_.get()); |
+ |
+ capture_controller_.reset(new CaptureController); |
+ capture_controller_->AddObserver(this); |
+ SetCaptureController(root_, capture_controller_.get()); |
+} |
+ |
+void WindowManagerApp::Embed( |
+ const mojo::String& url, |
+ mojo::InterfaceRequest<mojo::ServiceProvider> services, |
+ mojo::ServiceProviderPtr exposed_services) { |
+ if (view_manager()) { |
+ window_manager_delegate_->Embed(url, services.Pass(), |
+ exposed_services.Pass()); |
+ return; |
+ } |
+ scoped_ptr<PendingEmbed> pending_embed(new PendingEmbed); |
+ pending_embed->url = url; |
+ pending_embed->services = services.Pass(); |
+ pending_embed->exposed_services = exposed_services.Pass(); |
+ pending_embeds_.push_back(pending_embed.release()); |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// WindowManagerApp, ApplicationDelegate implementation: |
+ |
+void WindowManagerApp::Initialize(mojo::ApplicationImpl* impl) { |
+ shell_ = impl->shell(); |
+ LaunchViewManager(impl); |
+} |
+ |
+bool WindowManagerApp::ConfigureIncomingConnection( |
+ ApplicationConnection* connection) { |
+ connection->AddService<WindowManager>(this); |
+ return true; |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// WindowManagerApp, ViewManagerDelegate implementation: |
+ |
+void WindowManagerApp::OnEmbed( |
+ View* root, |
+ mojo::InterfaceRequest<mojo::ServiceProvider> services, |
+ mojo::ServiceProviderPtr exposed_services) { |
+ DCHECK(!root_); |
+ root_ = root; |
+ |
+ view_event_dispatcher_.reset(new ViewEventDispatcher); |
+ |
+ RegisterSubtree(root_); |
+ |
+ if (wrapped_view_manager_delegate_) { |
+ wrapped_view_manager_delegate_->OnEmbed(root, services.Pass(), |
+ exposed_services.Pass()); |
+ } |
+ |
+ for (PendingEmbed* pending_embed : pending_embeds_) { |
+ Embed(pending_embed->url, pending_embed->services.Pass(), |
+ pending_embed->exposed_services.Pass()); |
+ } |
+ pending_embeds_.clear(); |
+} |
+ |
+void WindowManagerApp::OnViewManagerDisconnected( |
+ mojo::ViewManager* view_manager) { |
+ if (wrapped_view_manager_delegate_) |
+ wrapped_view_manager_delegate_->OnViewManagerDisconnected(view_manager); |
+ |
+ base::MessageLoop* message_loop = base::MessageLoop::current(); |
+ if (message_loop && message_loop->is_running()) |
+ message_loop->Quit(); |
+} |
+ |
+bool WindowManagerApp::OnPerformAction(mojo::View* view, |
+ const std::string& action) { |
+ if (!view) |
+ return false; |
+ if (action == "capture") |
+ return SetCaptureImpl(view); |
+ if (action == "focus") |
+ return FocusWindowImpl(view); |
+ else if (action == "activate") |
+ return ActivateWindowImpl(view); |
+ return false; |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// WindowManagerApp, ViewObserver implementation: |
+ |
+void WindowManagerApp::OnTreeChanged( |
+ const ViewObserver::TreeChangeParams& params) { |
+ if (params.receiver != root_) |
+ return; |
+ DCHECK(params.old_parent || params.new_parent); |
+ if (!params.target) |
+ return; |
+ |
+ if (params.new_parent) { |
+ if (registered_view_id_set_.find(params.target->id()) == |
+ registered_view_id_set_.end()) { |
+ RegisteredViewIdSet::const_iterator it = |
+ registered_view_id_set_.find(params.new_parent->id()); |
+ DCHECK(it != registered_view_id_set_.end()); |
+ RegisterSubtree(params.target); |
+ } |
+ } else if (params.old_parent) { |
+ UnregisterSubtree(params.target); |
+ } |
+} |
+ |
+void WindowManagerApp::OnViewDestroying(View* view) { |
+ Unregister(view); |
+ if (view == root_) { |
+ root_ = nullptr; |
+ if (focus_controller_) |
+ focus_controller_->RemoveObserver(this); |
+ if (capture_controller_) |
+ capture_controller_->RemoveObserver(this); |
+ } |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// WindowManagerApp, ui::EventHandler implementation: |
+ |
+void WindowManagerApp::OnEvent(ui::Event* event) { |
+ if (!window_manager_client_) |
+ return; |
+ |
+ View* view = static_cast<ViewTarget*>(event->target())->view(); |
+ if (!view) |
+ return; |
+ |
+ if (event->IsKeyEvent()) { |
+ const ui::KeyEvent* key_event = static_cast<const ui::KeyEvent*>(event); |
+ if (key_event->type() == ui::ET_KEY_PRESSED) { |
+ ui::Accelerator accelerator = ConvertEventToAccelerator(key_event); |
+ if (accelerator_manager_.Process(accelerator)) |
+ return; |
+ } |
+ } |
+ |
+ if (focus_controller_) |
+ focus_controller_->OnEvent(event); |
+ |
+ window_manager_client_->DispatchInputEventToView(view->id(), |
+ mojo::Event::From(*event)); |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// WindowManagerApp, mojo::FocusControllerObserver implementation: |
+ |
+void WindowManagerApp::OnFocused(View* gained_focus) { |
+ for (Connections::const_iterator it = connections_.begin(); |
+ it != connections_.end(); ++it) { |
+ (*it)->NotifyViewFocused(GetIdForView(gained_focus)); |
+ } |
+} |
+ |
+void WindowManagerApp::OnActivated(View* gained_active) { |
+ for (Connections::const_iterator it = connections_.begin(); |
+ it != connections_.end(); ++it) { |
+ (*it)->NotifyWindowActivated(GetIdForView(gained_active)); |
+ } |
+ if (gained_active) |
+ gained_active->MoveToFront(); |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// WindowManagerApp, mojo::CaptureControllerObserver implementation: |
+ |
+void WindowManagerApp::OnCaptureChanged(View* gained_capture) { |
+ for (Connections::const_iterator it = connections_.begin(); |
+ it != connections_.end(); ++it) { |
+ (*it)->NotifyCaptureChanged(GetIdForView(gained_capture)); |
+ } |
+ if (gained_capture) |
+ gained_capture->MoveToFront(); |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// WindowManagerApp, private: |
+ |
+bool WindowManagerApp::SetCaptureImpl(View* view) { |
+ CHECK(view); |
+ capture_controller_->SetCapture(view); |
+ return capture_controller_->GetCapture() == view; |
+} |
+ |
+bool WindowManagerApp::FocusWindowImpl(View* view) { |
+ CHECK(view); |
+ focus_controller_->FocusView(view); |
+ return focus_controller_->GetFocusedView() == view; |
+} |
+ |
+bool WindowManagerApp::ActivateWindowImpl(View* view) { |
+ CHECK(view); |
+ focus_controller_->ActivateView(view); |
+ return focus_controller_->GetActiveView() == view; |
+} |
+ |
+void WindowManagerApp::RegisterSubtree(View* view) { |
+ view->AddObserver(this); |
+ DCHECK(registered_view_id_set_.find(view->id()) == |
+ registered_view_id_set_.end()); |
+ // All events pass through the root during dispatch, so we only need a handler |
+ // installed there. |
+ if (view == root_) { |
+ ViewTarget* target = ViewTarget::TargetFromView(view); |
+ target->SetEventTargeter(scoped_ptr<ViewTargeter>(new ViewTargeter())); |
+ target->AddPreTargetHandler(this); |
+ view_event_dispatcher_->SetRootViewTarget(target); |
+ } |
+ registered_view_id_set_.insert(view->id()); |
+ View::Children::const_iterator it = view->children().begin(); |
+ for (; it != view->children().end(); ++it) |
+ RegisterSubtree(*it); |
+} |
+ |
+void WindowManagerApp::UnregisterSubtree(View* view) { |
+ for (View* child : view->children()) |
+ UnregisterSubtree(child); |
+ Unregister(view); |
+} |
+ |
+void WindowManagerApp::Unregister(View* view) { |
+ RegisteredViewIdSet::iterator it = registered_view_id_set_.find(view->id()); |
+ if (it == registered_view_id_set_.end()) { |
+ // Because we unregister in OnViewDestroying() we can still get a subsequent |
+ // OnTreeChanged for the same view. Ignore this one. |
+ return; |
+ } |
+ view->RemoveObserver(this); |
+ DCHECK(it != registered_view_id_set_.end()); |
+ registered_view_id_set_.erase(it); |
+} |
+ |
+void WindowManagerApp::DispatchInputEventToView(View* view, |
+ mojo::EventPtr event) { |
+ window_manager_client_->DispatchInputEventToView(view->id(), event.Pass()); |
+} |
+ |
+void WindowManagerApp::SetViewportSize(const gfx::Size& size) { |
+ window_manager_client_->SetViewportSize(mojo::Size::From(size)); |
+} |
+ |
+void WindowManagerApp::LaunchViewManager(mojo::ApplicationImpl* app) { |
+ // TODO(sky): figure out logic if this connection goes away. |
+ view_manager_client_factory_.reset( |
+ new mojo::ViewManagerClientFactory(shell_, this)); |
+ |
+ ApplicationConnection* view_manager_app = |
+ app->ConnectToApplication("mojo:view_manager"); |
+ view_manager_app->ConnectToService(&view_manager_service_); |
+ |
+ view_manager_app->AddService<WindowManagerInternal>(this); |
+ view_manager_app->AddService<mojo::NativeViewportEventDispatcher>(this); |
+ |
+ view_manager_app->ConnectToService(&window_manager_client_); |
+} |
+ |
+void WindowManagerApp::Create( |
+ ApplicationConnection* connection, |
+ mojo::InterfaceRequest<WindowManagerInternal> request) { |
+ if (wm_internal_binding_.get()) { |
+ VLOG(1) << |
+ "WindowManager allows only one WindowManagerInternal connection."; |
+ return; |
+ } |
+ wm_internal_binding_.reset( |
+ new mojo::Binding<WindowManagerInternal>(this, request.Pass())); |
+} |
+ |
+void WindowManagerApp::Create(ApplicationConnection* connection, |
+ mojo::InterfaceRequest<WindowManager> request) { |
+ WindowManagerImpl* wm = new WindowManagerImpl(this, false); |
+ wm->Bind(request.PassMessagePipe()); |
+ // WindowManagerImpl is deleted when the connection has an error, or from our |
+ // destructor. |
+} |
+ |
+void WindowManagerApp::Create( |
+ mojo::ApplicationConnection* connection, |
+ mojo::InterfaceRequest<mojo::NativeViewportEventDispatcher> request) { |
+ new NativeViewportEventDispatcherImpl(this, request.Pass()); |
+} |
+ |
+void WindowManagerApp::CreateWindowManagerForViewManagerClient( |
+ uint16_t connection_id, |
+ mojo::ScopedMessagePipeHandle window_manager_pipe) { |
+ // TODO(sky): pass in |connection_id| for validation. |
+ WindowManagerImpl* wm = new WindowManagerImpl(this, true); |
+ wm->Bind(window_manager_pipe.Pass()); |
+ // WindowManagerImpl is deleted when the connection has an error, or from our |
+ // destructor. |
+} |
+ |
+void WindowManagerApp::SetViewManagerClient( |
+ mojo::ScopedMessagePipeHandle view_manager_client_request) { |
+ view_manager_client_.reset( |
+ mojo::ViewManagerClientFactory::WeakBindViewManagerToPipe( |
+ mojo::MakeRequest<mojo::ViewManagerClient>( |
+ view_manager_client_request.Pass()), |
+ view_manager_service_.Pass(), shell_, this)); |
+} |
+ |
+} // namespace window_manager |