summaryrefslogtreecommitdiffstats
path: root/mojo
diff options
context:
space:
mode:
authorben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-24 17:20:56 +0000
committerben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-24 17:20:56 +0000
commit6c9ceab29f79bc3ad6702408b4125ef2c6e9d375 (patch)
tree728b2e07254dc453b1da2601a3e6261e39022560 /mojo
parent94710706b818acd113d6f56c0cdaa787f13b74eb (diff)
downloadchromium_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')
-rw-r--r--mojo/examples/browser/browser.cc35
-rw-r--r--mojo/examples/window_manager/window_manager.cc18
-rw-r--r--mojo/mojo_services.gypi1
-rw-r--r--mojo/services/public/cpp/view_manager/lib/view_manager_client_impl.cc36
-rw-r--r--mojo/services/public/cpp/view_manager/lib/view_manager_client_impl.h5
-rw-r--r--mojo/services/public/cpp/view_manager/node_observer.h2
-rw-r--r--mojo/services/public/cpp/view_manager/tests/view_manager_unittest.cc8
-rw-r--r--mojo/services/public/cpp/view_manager/view_event_dispatcher.h30
-rw-r--r--mojo/services/public/cpp/view_manager/view_manager.h10
-rw-r--r--mojo/services/public/interfaces/view_manager/view_manager.mojom9
-rw-r--r--mojo/services/view_manager/node.cc5
-rw-r--r--mojo/services/view_manager/node.h2
-rw-r--r--mojo/services/view_manager/root_node_manager.cc15
-rw-r--r--mojo/services/view_manager/root_node_manager.h9
-rw-r--r--mojo/services/view_manager/root_view_manager.cc9
-rw-r--r--mojo/services/view_manager/view_manager_service_impl.cc28
-rw-r--r--mojo/services/view_manager/view_manager_service_impl.h3
-rw-r--r--mojo/services/view_manager/view_manager_unittest.cc7
-rw-r--r--mojo/views/native_widget_view_manager.cc5
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() {