diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-24 17:20:56 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-24 17:20:56 +0000 |
commit | 6c9ceab29f79bc3ad6702408b4125ef2c6e9d375 (patch) | |
tree | 728b2e07254dc453b1da2601a3e6261e39022560 /mojo | |
parent | 94710706b818acd113d6f56c0cdaa787f13b74eb (diff) | |
download | chromium_src-6c9ceab29f79bc3ad6702408b4125ef2c6e9d375.zip chromium_src-6c9ceab29f79bc3ad6702408b4125ef2c6e9d375.tar.gz chromium_src-6c9ceab29f79bc3ad6702408b4125ef2c6e9d375.tar.bz2 |
Run input events through a window-manager supplied ViewEventDispatcher so it can implement focus-on-click.
R=sky@chromium.org
http://crbug.com/387212
Review URL: https://codereview.chromium.org/348373002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@279429 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'mojo')
19 files changed, 215 insertions, 22 deletions
diff --git a/mojo/examples/browser/browser.cc b/mojo/examples/browser/browser.cc index fddf0aa..7c39da8 100644 --- a/mojo/examples/browser/browser.cc +++ b/mojo/examples/browser/browser.cc @@ -14,6 +14,7 @@ #include "mojo/services/public/interfaces/navigation/navigation.mojom.h" #include "mojo/views/native_widget_view_manager.h" #include "mojo/views/views_init.h" +#include "ui/aura/client/focus_client.h" #include "ui/events/event.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/controls/textfield/textfield_controller.h" @@ -50,9 +51,10 @@ class BrowserLayoutManager : public views::LayoutManager { // TODO: cleanup! class Browser : public Application, public view_manager::ViewManagerDelegate, - public views::TextfieldController { + public views::TextfieldController, + public view_manager::NodeObserver { public: - Browser() : view_manager_(NULL) {} + Browser() : view_manager_(NULL), root_(NULL), widget_(NULL) {} virtual ~Browser() { } @@ -74,14 +76,14 @@ class Browser : public Application, widget_delegate->GetContentsView()->SetLayoutManager( new BrowserLayoutManager); - views::Widget* widget = new views::Widget; + widget_ = new views::Widget; views::Widget::InitParams params( views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); - params.native_widget = new NativeWidgetViewManager(widget, node); + params.native_widget = new NativeWidgetViewManager(widget_, node); params.delegate = widget_delegate; params.bounds = gfx::Rect(node->bounds().width(), node->bounds().height()); - widget->Init(params); - widget->Show(); + widget_->Init(params); + widget_->Show(); textfield->RequestFocus(); } @@ -90,9 +92,11 @@ class Browser : public Application, view_manager::Node* root) OVERRIDE { // TODO: deal with OnRootAdded() being invoked multiple times. view_manager_ = view_manager; - root->SetActiveView(view_manager::View::Create(view_manager)); - root->SetFocus(); - CreateWidget(root); + root_ = root; + root_->AddObserver(this); + root_->SetActiveView(view_manager::View::Create(view_manager)); + root_->SetFocus(); + CreateWidget(root_); } // views::TextfieldController: @@ -111,9 +115,22 @@ class Browser : public Application, return false; } + // NodeObserver: + virtual void OnNodeFocusChanged(view_manager::Node* gained_focus, + view_manager::Node* lost_focus) OVERRIDE { + aura::client::FocusClient* focus_client = + aura::client::GetFocusClient(widget_->GetNativeView()); + if (lost_focus == root_) + focus_client->FocusWindow(NULL); + else if (gained_focus == root_) + focus_client->FocusWindow(widget_->GetNativeView()); + } + scoped_ptr<ViewsInit> views_init_; view_manager::ViewManager* view_manager_; + view_manager::Node* root_; + views::Widget* widget_; navigation::NavigatorHostPtr navigator_host_; DISALLOW_COPY_AND_ASSIGN(Browser); diff --git a/mojo/examples/window_manager/window_manager.cc b/mojo/examples/window_manager/window_manager.cc index 788d305..55df3c1 100644 --- a/mojo/examples/window_manager/window_manager.cc +++ b/mojo/examples/window_manager/window_manager.cc @@ -9,9 +9,11 @@ #include "mojo/public/cpp/application/application.h" #include "mojo/services/public/cpp/view_manager/node.h" #include "mojo/services/public/cpp/view_manager/view.h" +#include "mojo/services/public/cpp/view_manager/view_event_dispatcher.h" #include "mojo/services/public/cpp/view_manager/view_manager.h" #include "mojo/services/public/cpp/view_manager/view_manager_delegate.h" #include "mojo/services/public/cpp/view_manager/view_observer.h" +#include "mojo/services/public/interfaces/input_events/input_events.mojom.h" #include "mojo/services/public/interfaces/launcher/launcher.mojom.h" #include "mojo/services/public/interfaces/navigation/navigation.mojom.h" #include "ui/events/event_constants.h" @@ -24,6 +26,7 @@ using mojo::view_manager::Id; using mojo::view_manager::Node; using mojo::view_manager::NodeObserver; using mojo::view_manager::View; +using mojo::view_manager::ViewEventDispatcher; using mojo::view_manager::ViewManager; using mojo::view_manager::ViewManagerDelegate; using mojo::view_manager::ViewObserver; @@ -75,7 +78,8 @@ class NavigatorHost : public InterfaceImpl<navigation::NavigatorHost> { class WindowManager : public Application, public ViewObserver, - public ViewManagerDelegate { + public ViewManagerDelegate, + public ViewEventDispatcher { public: WindowManager() : launcher_ui_(NULL), view_manager_(NULL) {} virtual ~WindowManager() {} @@ -137,6 +141,7 @@ class WindowManager : public Application, virtual void OnRootAdded(ViewManager* view_manager, Node* root) OVERRIDE { DCHECK(!view_manager_); view_manager_ = view_manager; + view_manager_->SetEventDispatcher(this); Node* node = Node::Create(view_manager); view_manager->GetRoots().front()->AddChild(node); @@ -151,7 +156,15 @@ class WindowManager : public Application, CreateLauncherUI(); } - virtual void OnLaunch( + // Overridden from ViewEventDispatcher: + virtual void DispatchEvent(View* target, EventPtr event) OVERRIDE { + // TODO(beng): More sophisticated focus handling than this is required! + if (event->action == ui::ET_MOUSE_PRESSED) + target->node()->SetFocus(); + view_manager_->DispatchEvent(target, event.Pass()); + } + + void OnLaunch( uint32 source_node_id, navigation::Target target, const mojo::String& handler_url, @@ -198,6 +211,7 @@ class WindowManager : public Application, node->AddChild(embedded); embedded->SetBounds(bounds); Embed(embedded, url, nav_details.Pass(), response.Pass()); + embedded->SetFocus(); return embedded; } diff --git a/mojo/mojo_services.gypi b/mojo/mojo_services.gypi index 211889c..fdf93f2 100644 --- a/mojo/mojo_services.gypi +++ b/mojo/mojo_services.gypi @@ -326,6 +326,7 @@ 'services/public/cpp/view_manager/node.h', 'services/public/cpp/view_manager/node_observer.h', 'services/public/cpp/view_manager/view.h', + 'services/public/cpp/view_manager/view_event_dispatcher.h', 'services/public/cpp/view_manager/view_manager.h', 'services/public/cpp/view_manager/view_manager_delegate.h', 'services/public/cpp/view_manager/view_observer.h', diff --git a/mojo/services/public/cpp/view_manager/lib/view_manager_client_impl.cc b/mojo/services/public/cpp/view_manager/lib/view_manager_client_impl.cc index cb7b0713..6ff07b0 100644 --- a/mojo/services/public/cpp/view_manager/lib/view_manager_client_impl.cc +++ b/mojo/services/public/cpp/view_manager/lib/view_manager_client_impl.cc @@ -13,6 +13,7 @@ #include "mojo/services/public/cpp/view_manager/lib/view_private.h" #include "mojo/services/public/cpp/view_manager/node_observer.h" #include "mojo/services/public/cpp/view_manager/util.h" +#include "mojo/services/public/cpp/view_manager/view_event_dispatcher.h" #include "mojo/services/public/cpp/view_manager/view_manager_delegate.h" #include "mojo/services/public/cpp/view_manager/view_observer.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -501,7 +502,8 @@ ViewManagerClientImpl::ViewManagerClientImpl(ViewManagerDelegate* delegate) connection_id_(0), next_id_(1), next_server_change_id_(0), - delegate_(delegate) {} + delegate_(delegate), + dispatcher_(NULL) {} ViewManagerClientImpl::~ViewManagerClientImpl() { while (!nodes_.empty()) { @@ -639,6 +641,17 @@ void ViewManagerClientImpl::RemoveView(Id view_id) { //////////////////////////////////////////////////////////////////////////////// // ViewManagerClientImpl, ViewManager implementation: +void ViewManagerClientImpl::SetEventDispatcher( + ViewEventDispatcher* dispatcher) { + CHECK(NULL != GetNodeById(1)); + dispatcher_ = dispatcher; +} + +void ViewManagerClientImpl::DispatchEvent(View* target, EventPtr event) { + CHECK(dispatcher_); + service_->DispatchOnViewInputEvent(target->id(), event.Pass()); +} + const std::string& ViewManagerClientImpl::GetEmbedderURL() const { return creator_url_; } @@ -776,12 +789,25 @@ void ViewManagerClientImpl::OnViewInputEvent( ack_callback.Run(); } +void ViewManagerClientImpl::OnFocusChanged(Id gained_focus_id, + Id lost_focus_id) { + Node* focused = GetNodeById(gained_focus_id); + Node* blurred = GetNodeById(lost_focus_id); + if (blurred) { + FOR_EACH_OBSERVER(NodeObserver, + *NodePrivate(blurred).observers(), + OnNodeFocusChanged(focused, blurred)); + } + if (focused) { + FOR_EACH_OBSERVER(NodeObserver, + *NodePrivate(focused).observers(), + OnNodeFocusChanged(focused, blurred)); + } +} + void ViewManagerClientImpl::DispatchOnViewInputEvent(Id view_id, EventPtr event) { - // For now blindly bounce the message back to the server. Doing this means the - // event is sent to the correct target (|view_id|). - // Note: This function is only invoked on the window manager. - service_->DispatchOnViewInputEvent(view_id, event.Pass()); + dispatcher_->DispatchEvent(GetViewById(view_id), event.Pass()); } //////////////////////////////////////////////////////////////////////////////// diff --git a/mojo/services/public/cpp/view_manager/lib/view_manager_client_impl.h b/mojo/services/public/cpp/view_manager/lib/view_manager_client_impl.h index 01cdc34..aa10bd8 100644 --- a/mojo/services/public/cpp/view_manager/lib/view_manager_client_impl.h +++ b/mojo/services/public/cpp/view_manager/lib/view_manager_client_impl.h @@ -20,6 +20,7 @@ class SkBitmap; namespace mojo { namespace view_manager { +class ViewEventDispatcher; class ViewManager; class ViewManagerTransaction; @@ -84,6 +85,8 @@ class ViewManagerClientImpl : public ViewManager, typedef std::map<Id, View*> IdToViewMap; // Overridden from ViewManager: + virtual void SetEventDispatcher(ViewEventDispatcher* dispatcher) OVERRIDE; + virtual void DispatchEvent(View* target, EventPtr event) OVERRIDE; virtual const std::string& GetEmbedderURL() const OVERRIDE; virtual const std::vector<Node*>& GetRoots() const OVERRIDE; virtual Node* GetNodeById(Id id) OVERRIDE; @@ -120,6 +123,7 @@ class ViewManagerClientImpl : public ViewManager, virtual void OnViewInputEvent(Id view, EventPtr event, const Callback<void()>& callback) OVERRIDE; + virtual void OnFocusChanged(Id gained_focus_id, Id lost_focus_id) OVERRIDE; virtual void DispatchOnViewInputEvent(Id view_id, EventPtr event) OVERRIDE; // Sync the client model with the service by enumerating the pending @@ -145,6 +149,7 @@ class ViewManagerClientImpl : public ViewManager, base::Callback<void(void)> changes_acked_callback_; ViewManagerDelegate* delegate_; + ViewEventDispatcher* dispatcher_; std::vector<Node*> roots_; diff --git a/mojo/services/public/cpp/view_manager/node_observer.h b/mojo/services/public/cpp/view_manager/node_observer.h index 7b0cdb0..523b542 100644 --- a/mojo/services/public/cpp/view_manager/node_observer.h +++ b/mojo/services/public/cpp/view_manager/node_observer.h @@ -56,6 +56,8 @@ class NodeObserver { const gfx::Rect& new_bounds, DispositionChangePhase phase) {} + virtual void OnNodeFocusChanged(Node* gained_focus, Node* lost_focus) {} + protected: virtual ~NodeObserver() {} }; diff --git a/mojo/services/public/cpp/view_manager/tests/view_manager_unittest.cc b/mojo/services/public/cpp/view_manager/tests/view_manager_unittest.cc index e1f19b1..eb98fc7 100644 --- a/mojo/services/public/cpp/view_manager/tests/view_manager_unittest.cc +++ b/mojo/services/public/cpp/view_manager/tests/view_manager_unittest.cc @@ -775,5 +775,13 @@ TEST_F(ViewManagerTest, Reorder) { } } +// TODO(beng): tests for view event dispatcher. +// - verify that we see events for all views. + +// TODO(beng): tests for focus: +// - focus between two nodes known to a connection +// - focus between nodes unknown to one of the connections. +// - focus between nodes unknown to either connection. + } // namespace view_manager } // namespace mojo diff --git a/mojo/services/public/cpp/view_manager/view_event_dispatcher.h b/mojo/services/public/cpp/view_manager/view_event_dispatcher.h new file mode 100644 index 0000000..bfece61 --- /dev/null +++ b/mojo/services/public/cpp/view_manager/view_event_dispatcher.h @@ -0,0 +1,30 @@ +// 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. + +#ifndef MOJO_SERVICES_PUBLIC_CPP_VIEW_MANAGER_VIEW_EVENT_DISPATCHER_H_ +#define MOJO_SERVICES_PUBLIC_CPP_VIEW_MANAGER_VIEW_EVENT_DISPATCHER_H_ + +#include "mojo/services/public/interfaces/input_events/input_events.mojom.h" + +namespace mojo { +namespace view_manager { + +class View; + +// A ViewEventDispatcher is provided by the application rendering at the root +// of a Node hierarchy. It is responsible for targeting input events to the +// relevant Views. This allows window manager features like focus, activation, +// modality, etc. to be implemented. +class ViewEventDispatcher { + public: + virtual void DispatchEvent(View* target, EventPtr event) = 0; + + protected: + virtual ~ViewEventDispatcher() {} +}; + +} // namespace view_manager +} // namespace mojo + +#endif // MOJO_SERVICES_PUBLIC_CPP_VIEW_MANAGER_VIEW_EVENT_DISPATCHER_H_ diff --git a/mojo/services/public/cpp/view_manager/view_manager.h b/mojo/services/public/cpp/view_manager/view_manager.h index 6ed6e90..9b46387 100644 --- a/mojo/services/public/cpp/view_manager/view_manager.h +++ b/mojo/services/public/cpp/view_manager/view_manager.h @@ -9,6 +9,7 @@ #include <vector> #include "mojo/services/public/cpp/view_manager/types.h" +#include "mojo/services/public/interfaces/input_events/input_events.mojom.h" namespace mojo { class Application; @@ -16,6 +17,7 @@ namespace view_manager { class Node; class View; +class ViewEventDispatcher; class ViewManagerDelegate; class ViewManager { @@ -23,6 +25,14 @@ class ViewManager { // Delegate is owned by the caller. static void Create(Application* application, ViewManagerDelegate* delegate); + // Sets the event dispatcher. Can only be called by the app rendering to the + // root Node of the hierarchy. + virtual void SetEventDispatcher(ViewEventDispatcher* dispatcher) = 0; + + // Dispatches the supplied event to the specified View. Can be called only + // by the application that called SetEventDispatcher(). + virtual void DispatchEvent(View* target, EventPtr event) = 0; + // Returns the URL of the application that embedded this application. virtual const std::string& GetEmbedderURL() const = 0; diff --git a/mojo/services/public/interfaces/view_manager/view_manager.mojom b/mojo/services/public/interfaces/view_manager/view_manager.mojom index ea1d3b5..f036b99 100644 --- a/mojo/services/public/interfaces/view_manager/view_manager.mojom +++ b/mojo/services/public/interfaces/view_manager/view_manager.mojom @@ -185,6 +185,15 @@ interface ViewManagerClient { // Invoked when an event is targeted at the specified view. OnViewInputEvent(uint32 view, mojo.Event event) => (); + // Invoked when focus shifts from one Node to another. |gained_focus_id| is + // the id of the node that gained focus, or 0 if the node that gained focus is + // not known to this connection. |lost_focus_id| is likewise the node that + // lost focus. + // TODO(beng): once aura is removed from the service, focus management should + // entirely move to the window manager and this method can be + // removed. + OnFocusChanged(uint32 gained_focus_id, uint32 lost_focus_id); + // TODO(sky): move to separate interface when FIFO sorted out. DispatchOnViewInputEvent(uint32 view, mojo.Event event); diff --git a/mojo/services/view_manager/node.cc b/mojo/services/view_manager/node.cc index cbdd16d..ef05a61 100644 --- a/mojo/services/view_manager/node.cc +++ b/mojo/services/view_manager/node.cc @@ -44,6 +44,11 @@ Node::~Node() { window_.parent()->RemoveChild(&window_); } +// static +Node* Node::NodeForWindow(aura::Window* window) { + return window->GetProperty(kNodeKey); +} + const Node* Node::GetParent() const { if (!window_.parent()) return NULL; diff --git a/mojo/services/view_manager/node.h b/mojo/services/view_manager/node.h index bfee675..57becdc 100644 --- a/mojo/services/view_manager/node.h +++ b/mojo/services/view_manager/node.h @@ -30,6 +30,8 @@ class MOJO_VIEW_MANAGER_EXPORT Node Node(NodeDelegate* delegate, const NodeId& id); virtual ~Node(); + static Node* NodeForWindow(aura::Window* window); + void set_view_id(const ViewId& view_id) { view_id_ = view_id; } const ViewId& view_id() const { return view_id_; } diff --git a/mojo/services/view_manager/root_node_manager.cc b/mojo/services/view_manager/root_node_manager.cc index f5c681f..10a699c 100644 --- a/mojo/services/view_manager/root_node_manager.cc +++ b/mojo/services/view_manager/root_node_manager.cc @@ -9,6 +9,7 @@ #include "mojo/services/public/cpp/input_events/input_events_type_converters.h" #include "mojo/services/view_manager/view.h" #include "mojo/services/view_manager/view_manager_service_impl.h" +#include "ui/aura/client/focus_client.h" #include "ui/aura/env.h" namespace mojo { @@ -51,6 +52,9 @@ RootNodeManager::RootNodeManager(ServiceProvider* service_provider, } RootNodeManager::~RootNodeManager() { + aura::client::FocusClient* focus_client = + aura::client::GetFocusClient(root_.window()); + focus_client->RemoveObserver(this); while (!connections_created_by_connect_.empty()) delete *(connections_created_by_connect_.begin()); // All the connections should have been destroyed. @@ -201,6 +205,17 @@ void RootNodeManager::ProcessViewDeleted(const ViewId& view) { } } +void RootNodeManager::OnWindowFocused(aura::Window* gained_focus, + aura::Window* lost_focus) { + Node* focused_node = gained_focus ? Node::NodeForWindow(gained_focus) : NULL; + Node* blurred_node = lost_focus ? Node::NodeForWindow(lost_focus) : NULL; + for (ConnectionMap::iterator i = connection_map_.begin(); + i != connection_map_.end(); ++i) { + i->second->ProcessFocusChanged(focused_node, blurred_node, + IsChangeSource(i->first)); + } +} + void RootNodeManager::PrepareForChange(ScopedChange* change) { // Should only ever have one change in flight. CHECK(!current_change_); diff --git a/mojo/services/view_manager/root_node_manager.h b/mojo/services/view_manager/root_node_manager.h index dba45d9..b5098fd 100644 --- a/mojo/services/view_manager/root_node_manager.h +++ b/mojo/services/view_manager/root_node_manager.h @@ -15,6 +15,7 @@ #include "mojo/services/view_manager/node_delegate.h" #include "mojo/services/view_manager/root_view_manager.h" #include "mojo/services/view_manager/view_manager_export.h" +#include "ui/aura/client/focus_change_observer.h" namespace ui { class Event; @@ -33,7 +34,9 @@ class ViewManagerServiceImpl; // RootNodeManager is responsible for managing the set of // ViewManagerServiceImpls as well as providing the root of the node hierarchy. -class MOJO_VIEW_MANAGER_EXPORT RootNodeManager : public NodeDelegate { +class MOJO_VIEW_MANAGER_EXPORT RootNodeManager + : public NodeDelegate, + public aura::client::FocusChangeObserver { public: // Used to indicate if the server id should be incremented after notifiying // clients of the change. @@ -158,6 +161,10 @@ class MOJO_VIEW_MANAGER_EXPORT RootNodeManager : public NodeDelegate { typedef std::map<ConnectionSpecificId, ViewManagerServiceImpl*> ConnectionMap; + // Overridden from aura::client::FocusChangeObserver: + virtual void OnWindowFocused(aura::Window* gained_focus, + aura::Window* lost_focus) OVERRIDE; + // Invoked when a connection is about to make a change. Subsequently followed // by FinishChange() once the change is done. // diff --git a/mojo/services/view_manager/root_view_manager.cc b/mojo/services/view_manager/root_view_manager.cc index 0bcdbfb..3f432de 100644 --- a/mojo/services/view_manager/root_view_manager.cc +++ b/mojo/services/view_manager/root_view_manager.cc @@ -37,13 +37,17 @@ class FocusClientImpl : public aura::client::FocusClient, // Overridden from aura::client::FocusClient: virtual void AddObserver(aura::client::FocusChangeObserver* observer) OVERRIDE { + observers_.AddObserver(observer); } virtual void RemoveObserver(aura::client::FocusChangeObserver* observer) OVERRIDE { + observers_.RemoveObserver(observer); } virtual void FocusWindow(aura::Window* window) OVERRIDE { if (window && !window->CanFocus()) return; + if (window == focused_window_) + return; if (focused_window_) observer_manager_.Remove(focused_window_); aura::Window* old_focused_window = focused_window_; @@ -51,6 +55,9 @@ class FocusClientImpl : public aura::client::FocusClient, if (focused_window_) observer_manager_.Add(focused_window_); + FOR_EACH_OBSERVER(aura::client::FocusChangeObserver, + observers_, + OnWindowFocused(focused_window_, old_focused_window)); aura::client::FocusChangeObserver* observer = aura::client::GetFocusChangeObserver(old_focused_window); if (observer) @@ -75,6 +82,7 @@ class FocusClientImpl : public aura::client::FocusClient, aura::Window* focused_window_; ScopedObserver<aura::Window, aura::WindowObserver> observer_manager_; + ObserverList<aura::client::FocusChangeObserver> observers_; DISALLOW_COPY_AND_ASSIGN(FocusClientImpl); }; @@ -148,6 +156,7 @@ void RootViewManager::OnCompositorCreated() { focus_client_.reset(new FocusClientImpl()); aura::client::SetFocusClient(window_tree_host_->window(), focus_client_.get()); + focus_client_->AddObserver(root_node_manager_); window_tree_host_->Show(); diff --git a/mojo/services/view_manager/view_manager_service_impl.cc b/mojo/services/view_manager/view_manager_service_impl.cc index 0af11c3..1540fe2 100644 --- a/mojo/services/view_manager/view_manager_service_impl.cc +++ b/mojo/services/view_manager/view_manager_service_impl.cc @@ -233,6 +233,29 @@ void ViewManagerServiceImpl::ProcessViewDeleted(const ViewId& view, client()->OnViewDeleted(ViewIdToTransportId(view)); } +void ViewManagerServiceImpl::ProcessFocusChanged(const Node* focused_node, + const Node* blurred_node, + bool originated_change) { + if (originated_change) + return; + + Id focused_id = 0; + Id blurred_id = 0; + if (focused_node) { + Id focused_node_id = NodeIdToTransportId(focused_node->id()); + if (known_nodes_.count(focused_node_id) > 0) + focused_id = focused_node_id; + } + if (blurred_node) { + Id blurred_node_id = NodeIdToTransportId(blurred_node->id()); + if (known_nodes_.count(blurred_node_id) > 0) + blurred_id = blurred_node_id; + } + + if (focused_id != 0 || blurred_id != 0) + client()->OnFocusChanged(focused_id, blurred_id); +} + void ViewManagerServiceImpl::OnConnectionError() { if (delete_on_connection_error_) delete this; @@ -392,11 +415,6 @@ bool ViewManagerServiceImpl::SetViewImpl(Node* node, const ViewId& view_id) { this, root_node_manager_, RootNodeManager::CHANGE_TYPE_DONT_ADVANCE_SERVER_CHANGE_ID, false); node->SetView(view); - - // TODO(sky): this is temporary, need a real focus API. - if (view && root_node_manager_->root()->Contains(node)) - node->window()->Focus(); - return true; } diff --git a/mojo/services/view_manager/view_manager_service_impl.h b/mojo/services/view_manager/view_manager_service_impl.h index 53950dc..4290562 100644 --- a/mojo/services/view_manager/view_manager_service_impl.h +++ b/mojo/services/view_manager/view_manager_service_impl.h @@ -99,6 +99,9 @@ class MOJO_VIEW_MANAGER_EXPORT ViewManagerServiceImpl Id server_change_id, bool originated_change); void ProcessViewDeleted(const ViewId& view, bool originated_change); + void ProcessFocusChanged(const Node* focused_node, + const Node* blurred_node, + bool originated_change); // TODO(sky): move this to private section (currently can't because of // bindings). diff --git a/mojo/services/view_manager/view_manager_unittest.cc b/mojo/services/view_manager/view_manager_unittest.cc index ed54092..192e523 100644 --- a/mojo/services/view_manager/view_manager_unittest.cc +++ b/mojo/services/view_manager/view_manager_unittest.cc @@ -346,6 +346,8 @@ class TestViewManagerClientConnection const Callback<void()>& callback) OVERRIDE { tracker_.OnViewInputEvent(view_id, event.Pass()); } + virtual void OnFocusChanged(Id gained_focus_id, + Id lost_focus_id) OVERRIDE {} virtual void DispatchOnViewInputEvent(Id view_id, mojo::EventPtr event) OVERRIDE { } @@ -1365,6 +1367,11 @@ TEST_F(ViewManagerTest, DISABLED_OnViewInput) { // that SetBounsdNodes/AddNode and the like don't result in messages to the // originating connection. +// TODO(beng): Add tests for focus: +// - focus between two nodes known to a connection +// - focus between nodes unknown to one of the connections. +// - focus between nodes unknown to either connection. + } // namespace service } // namespace view_manager } // namespace mojo diff --git a/mojo/views/native_widget_view_manager.cc b/mojo/views/native_widget_view_manager.cc index c5d32e1..49dfeb5 100644 --- a/mojo/views/native_widget_view_manager.cc +++ b/mojo/views/native_widget_view_manager.cc @@ -8,6 +8,7 @@ #include "mojo/services/public/cpp/input_events/input_events_type_converters.h" #include "mojo/services/public/cpp/view_manager/view.h" #include "ui/aura/client/aura_constants.h" +#include "ui/aura/client/default_capture_client.h" #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/base/ime/input_method.h" @@ -103,6 +104,10 @@ NativeWidgetViewManager::NativeWidgetViewManager( aura::client::SetActivationClient(window_tree_host_->window(), focus_client_.get()); window_tree_host_->window()->AddPreTargetHandler(focus_client_.get()); + + aura::client::SetCaptureClient( + window_tree_host_->window(), + new aura::client::DefaultCaptureClient(window_tree_host_->window())); } NativeWidgetViewManager::~NativeWidgetViewManager() { |