OLD | NEW |
| (Empty) |
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/macros.h" | |
6 #include "base/strings/string_util.h" | |
7 #include "base/strings/utf_string_conversions.h" | |
8 #include "mojo/application/application_runner_chromium.h" | |
9 #include "mojo/common/common_type_converters.h" | |
10 #include "mojo/converters/geometry/geometry_type_converters.h" | |
11 #include "mojo/examples/window_manager/window_manager.mojom.h" | |
12 #include "mojo/public/c/system/main.h" | |
13 #include "mojo/public/cpp/application/application_connection.h" | |
14 #include "mojo/public/cpp/application/application_delegate.h" | |
15 #include "mojo/public/cpp/application/application_impl.h" | |
16 #include "mojo/public/cpp/application/connect.h" | |
17 #include "mojo/services/public/cpp/view_manager/view.h" | |
18 #include "mojo/services/public/cpp/view_manager/view_manager.h" | |
19 #include "mojo/services/public/cpp/view_manager/view_manager_client_factory.h" | |
20 #include "mojo/services/public/cpp/view_manager/view_manager_delegate.h" | |
21 #include "mojo/services/public/interfaces/navigation/navigation.mojom.h" | |
22 #include "mojo/views/native_widget_view_manager.h" | |
23 #include "mojo/views/views_init.h" | |
24 #include "ui/aura/client/focus_client.h" | |
25 #include "ui/aura/window.h" | |
26 #include "ui/events/event.h" | |
27 #include "ui/views/background.h" | |
28 #include "ui/views/controls/textfield/textfield.h" | |
29 #include "ui/views/controls/textfield/textfield_controller.h" | |
30 #include "ui/views/focus/focus_manager.h" | |
31 #include "ui/views/layout/layout_manager.h" | |
32 #include "ui/views/widget/widget.h" | |
33 #include "ui/views/widget/widget_delegate.h" | |
34 #include "ui/views/widget/widget_observer.h" | |
35 #include "url/gurl.h" | |
36 | |
37 namespace mojo { | |
38 namespace examples { | |
39 | |
40 class BrowserLayoutManager : public views::LayoutManager { | |
41 public: | |
42 BrowserLayoutManager() {} | |
43 virtual ~BrowserLayoutManager() {} | |
44 | |
45 private: | |
46 // Overridden from views::LayoutManager: | |
47 virtual void Layout(views::View* host) override { | |
48 // Browser view has one child, a text input field. | |
49 DCHECK_EQ(1, host->child_count()); | |
50 views::View* text_field = host->child_at(0); | |
51 gfx::Size ps = text_field->GetPreferredSize(); | |
52 text_field->SetBoundsRect(gfx::Rect(host->width(), ps.height())); | |
53 } | |
54 virtual gfx::Size GetPreferredSize(const views::View* host) const override { | |
55 return gfx::Size(); | |
56 } | |
57 | |
58 DISALLOW_COPY_AND_ASSIGN(BrowserLayoutManager); | |
59 }; | |
60 | |
61 // KeyboardManager handles notifying the windowmanager when views are focused. | |
62 // To use create one and KeyboardManager will take care of all other details. | |
63 // | |
64 // TODO(sky): it would be nice if this were put in NativeWidgetViewManager, but | |
65 // that requires NativeWidgetViewManager to take an IWindowManager. That may be | |
66 // desirable anyway... | |
67 class KeyboardManager | |
68 : public views::FocusChangeListener, | |
69 public ui::EventHandler, | |
70 public views::WidgetObserver { | |
71 public: | |
72 KeyboardManager(views::Widget* widget, | |
73 IWindowManager* window_manager, | |
74 View* view) | |
75 : widget_(widget), | |
76 window_manager_(window_manager), | |
77 view_(view), | |
78 last_view_id_(0), | |
79 focused_view_(NULL) { | |
80 widget_->GetFocusManager()->AddFocusChangeListener(this); | |
81 widget_->AddObserver(this); | |
82 widget_->GetNativeView()->AddPostTargetHandler(this); | |
83 } | |
84 | |
85 private: | |
86 virtual ~KeyboardManager() { | |
87 widget_->GetFocusManager()->RemoveFocusChangeListener(this); | |
88 widget_->GetNativeView()->RemovePostTargetHandler(this); | |
89 widget_->RemoveObserver(this); | |
90 | |
91 HideKeyboard(); | |
92 } | |
93 | |
94 void ShowKeyboard(views::View* view) { | |
95 if (focused_view_ == view) | |
96 return; | |
97 | |
98 const gfx::Rect bounds_in_widget = | |
99 view->ConvertRectToWidget(gfx::Rect(view->bounds().size())); | |
100 last_view_id_ = view_->id(); | |
101 window_manager_->ShowKeyboard(last_view_id_, | |
102 Rect::From(bounds_in_widget)); | |
103 // TODO(sky): listen for view to be removed. | |
104 focused_view_ = view; | |
105 } | |
106 | |
107 void HideKeyboard() { | |
108 if (!focused_view_) | |
109 return; | |
110 | |
111 window_manager_->HideKeyboard(last_view_id_); | |
112 last_view_id_ = 0; | |
113 focused_view_ = NULL; | |
114 } | |
115 | |
116 // views::FocusChangeListener: | |
117 virtual void OnWillChangeFocus(views::View* focused_before, | |
118 views::View* focused_now) override { | |
119 } | |
120 virtual void OnDidChangeFocus(views::View* focused_before, | |
121 views::View* focused_now) override { | |
122 if (focused_view_ && focused_now != focused_view_) | |
123 HideKeyboard(); | |
124 } | |
125 | |
126 // ui::EventHandler: | |
127 virtual void OnMouseEvent(ui::MouseEvent* event) override { | |
128 views::View* focused_now = widget_->GetFocusManager()->GetFocusedView(); | |
129 if (focused_now && | |
130 focused_now->GetClassName() == views::Textfield::kViewClassName && | |
131 (event->flags() & ui::EF_FROM_TOUCH) != 0) { | |
132 ShowKeyboard(focused_now); | |
133 } | |
134 } | |
135 | |
136 // views::WidgetObserver: | |
137 virtual void OnWidgetDestroying(views::Widget* widget) override { | |
138 delete this; | |
139 } | |
140 | |
141 views::Widget* widget_; | |
142 IWindowManager* window_manager_; | |
143 View* view_; | |
144 Id last_view_id_; | |
145 views::View* focused_view_; | |
146 | |
147 DISALLOW_COPY_AND_ASSIGN(KeyboardManager); | |
148 }; | |
149 | |
150 // This is the basics of creating a views widget with a textfield. | |
151 // TODO: cleanup! | |
152 class Browser : public ApplicationDelegate, | |
153 public ViewManagerDelegate, | |
154 public views::TextfieldController, | |
155 public ViewObserver { | |
156 public: | |
157 Browser() | |
158 : shell_(nullptr), view_manager_(NULL), root_(NULL), widget_(NULL) {} | |
159 | |
160 virtual ~Browser() { | |
161 if (root_) | |
162 root_->RemoveObserver(this); | |
163 } | |
164 | |
165 private: | |
166 // Overridden from ApplicationDelegate: | |
167 virtual void Initialize(ApplicationImpl* app) override { | |
168 shell_ = app->shell(); | |
169 view_manager_client_factory_.reset( | |
170 new ViewManagerClientFactory(shell_, this)); | |
171 views_init_.reset(new ViewsInit); | |
172 app->ConnectToService("mojo:window_manager", &window_manager_); | |
173 } | |
174 | |
175 virtual bool ConfigureIncomingConnection( | |
176 ApplicationConnection* connection) override { | |
177 connection->AddService(view_manager_client_factory_.get()); | |
178 return true; | |
179 } | |
180 | |
181 void CreateWidget(View* view) { | |
182 views::Textfield* textfield = new views::Textfield; | |
183 textfield->set_controller(this); | |
184 | |
185 views::WidgetDelegateView* widget_delegate = new views::WidgetDelegateView; | |
186 widget_delegate->GetContentsView()->set_background( | |
187 views::Background::CreateSolidBackground(SK_ColorBLUE)); | |
188 widget_delegate->GetContentsView()->AddChildView(textfield); | |
189 widget_delegate->GetContentsView()->SetLayoutManager( | |
190 new BrowserLayoutManager); | |
191 | |
192 widget_ = new views::Widget; | |
193 views::Widget::InitParams params( | |
194 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); | |
195 params.native_widget = new NativeWidgetViewManager(widget_, shell_, view); | |
196 params.delegate = widget_delegate; | |
197 params.bounds = gfx::Rect(view->bounds().width, view->bounds().height); | |
198 widget_->Init(params); | |
199 // KeyboardManager handles deleting itself when the widget is destroyed. | |
200 new KeyboardManager(widget_, window_manager_.get(), view); | |
201 widget_->Show(); | |
202 textfield->RequestFocus(); | |
203 } | |
204 | |
205 // ViewManagerDelegate: | |
206 virtual void OnEmbed(ViewManager* view_manager, | |
207 View* root, | |
208 ServiceProviderImpl* exported_services, | |
209 scoped_ptr<ServiceProvider> imported_services) override { | |
210 // TODO: deal with OnEmbed() being invoked multiple times. | |
211 ConnectToService(imported_services.get(), &navigator_host_); | |
212 view_manager_ = view_manager; | |
213 root_ = root; | |
214 root_->AddObserver(this); | |
215 root_->SetFocus(); | |
216 CreateWidget(root_); | |
217 } | |
218 virtual void OnViewManagerDisconnected( | |
219 ViewManager* view_manager) override { | |
220 DCHECK_EQ(view_manager_, view_manager); | |
221 view_manager_ = NULL; | |
222 base::MessageLoop::current()->Quit(); | |
223 } | |
224 | |
225 // views::TextfieldController: | |
226 virtual bool HandleKeyEvent(views::Textfield* sender, | |
227 const ui::KeyEvent& key_event) override { | |
228 if (key_event.key_code() == ui::VKEY_RETURN) { | |
229 GURL url(sender->text()); | |
230 printf("User entered this URL: %s\n", url.spec().c_str()); | |
231 URLRequestPtr request(URLRequest::New()); | |
232 request->url = String::From(url); | |
233 navigator_host_->RequestNavigate(TARGET_NEW_NODE, request.Pass()); | |
234 } | |
235 return false; | |
236 } | |
237 | |
238 // ViewObserver: | |
239 virtual void OnViewFocusChanged(View* gained_focus, | |
240 View* lost_focus) override { | |
241 aura::client::FocusClient* focus_client = | |
242 aura::client::GetFocusClient(widget_->GetNativeView()); | |
243 if (lost_focus == root_) | |
244 focus_client->FocusWindow(NULL); | |
245 else if (gained_focus == root_) | |
246 focus_client->FocusWindow(widget_->GetNativeView()); | |
247 } | |
248 virtual void OnViewDestroyed(View* view) override { | |
249 DCHECK_EQ(root_, view); | |
250 view->RemoveObserver(this); | |
251 root_ = NULL; | |
252 } | |
253 | |
254 Shell* shell_; | |
255 | |
256 scoped_ptr<ViewsInit> views_init_; | |
257 | |
258 ViewManager* view_manager_; | |
259 scoped_ptr<ViewManagerClientFactory> view_manager_client_factory_; | |
260 View* root_; | |
261 views::Widget* widget_; | |
262 NavigatorHostPtr navigator_host_; | |
263 IWindowManagerPtr window_manager_; | |
264 | |
265 DISALLOW_COPY_AND_ASSIGN(Browser); | |
266 }; | |
267 | |
268 } // namespace examples | |
269 } // namespace mojo | |
270 | |
271 MojoResult MojoMain(MojoHandle shell_handle) { | |
272 mojo::ApplicationRunnerChromium runner(new mojo::examples::Browser); | |
273 return runner.Run(shell_handle); | |
274 } | |
OLD | NEW |