Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(431)

Side by Side Diff: win8/metro_driver/chrome_app_view.cc

Issue 10875008: Integrate the Windows 8 code into the Chromium tree. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remove conflicting OWNERS file. Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « win8/metro_driver/chrome_app_view.h ('k') | win8/metro_driver/chrome_url_launch_handler.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 "win8/metro_driver/stdafx.h"
6 #include "win8/metro_driver/chrome_app_view.h"
7
8 #include <algorithm>
9 #include <windows.applicationModel.datatransfer.h>
10 #include <windows.foundation.h>
11
12 #include "base/bind.h"
13 #include "base/message_loop.h"
14 #include "base/win/metro.h"
15
16 // This include allows to send WM_SYSCOMMANDs to chrome.
17 #include "chrome/app/chrome_command_ids.h"
18 #include "win8/metro_driver/winrt_utils.h"
19 #include "ui/base/ui_base_switches.h"
20
21 typedef winfoundtn::ITypedEventHandler<
22 winapp::Core::CoreApplicationView*,
23 winapp::Activation::IActivatedEventArgs*> ActivatedHandler;
24
25 typedef winfoundtn::ITypedEventHandler<
26 winui::Core::CoreWindow*,
27 winui::Core::WindowSizeChangedEventArgs*> SizeChangedHandler;
28
29 typedef winfoundtn::ITypedEventHandler<
30 winui::Input::EdgeGesture*,
31 winui::Input::EdgeGestureEventArgs*> EdgeEventHandler;
32
33 typedef winfoundtn::ITypedEventHandler<
34 winapp::DataTransfer::DataTransferManager*,
35 winapp::DataTransfer::DataRequestedEventArgs*> ShareDataRequestedHandler;
36
37 typedef winfoundtn::ITypedEventHandler<
38 winui::ViewManagement::InputPane*,
39 winui::ViewManagement::InputPaneVisibilityEventArgs*>
40 InputPaneEventHandler;
41
42 struct Globals globals;
43
44 // TODO(ananta)
45 // Remove this once we consolidate metro driver with chrome.
46 const wchar_t kMetroGetCurrentTabInfoMessage[] =
47 L"CHROME_METRO_GET_CURRENT_TAB_INFO";
48
49 static const int kFlipWindowsHotKeyId = 0x0000baba;
50
51 static const int kAnimateWindowTimeoutMs = 200;
52
53 static const int kCheckOSKDelayMs = 300;
54
55 const wchar_t kOSKClassName[] = L"IPTip_Main_Window";
56
57 static const int kOSKAdjustmentOffset = 20;
58
59 namespace {
60
61 void AdjustToFitWindow(HWND hwnd, int flags) {
62 RECT rect = {0};
63 ::GetWindowRect(globals.core_window, &rect);
64 int cx = rect.right - rect.left;
65 int cy = rect.bottom - rect.top;
66
67 ::SetWindowPos(hwnd, HWND_TOP,
68 rect.left, rect.top, cx, cy,
69 SWP_NOZORDER | flags);
70 }
71
72 void AdjustFrameWindowStyleForMetro(HWND hwnd) {
73 DVLOG(1) << __FUNCTION__;
74 // Ajust the frame so the live preview works and the frame buttons dissapear.
75 ::SetWindowLong(hwnd, GWL_STYLE,
76 WS_POPUP | (::GetWindowLong(hwnd, GWL_STYLE) &
77 ~(WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU)));
78 ::SetWindowLong(hwnd, GWL_EXSTYLE,
79 ::GetWindowLong(hwnd, GWL_EXSTYLE) & ~(WS_EX_DLGMODALFRAME |
80 WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
81 AdjustToFitWindow(hwnd, SWP_FRAMECHANGED | SWP_NOACTIVATE);
82 }
83
84 void SetFrameWindowInternal(HWND hwnd) {
85 DVLOG(1) << __FUNCTION__ << ", hwnd=" << LONG_PTR(hwnd);
86
87 HWND current_top_frame =
88 !globals.host_windows.empty() ? globals.host_windows.front().first : NULL;
89 if (hwnd != current_top_frame && IsWindow(current_top_frame)) {
90 DVLOG(1) << "Hiding current top window, hwnd="
91 << LONG_PTR(current_top_frame);
92 ::ShowWindow(current_top_frame, SW_HIDE);
93 }
94
95 // If chrome opens a url in a foreground tab, it may call SetFrameWindow
96 // again. Ensure that we don't have dups.
97 globals.host_windows.remove_if([hwnd](std::pair<HWND, bool>& item) {
98 return (item.first == hwnd);
99 });
100
101 globals.host_windows.push_front(std::make_pair(hwnd, false));
102
103 AdjustFrameWindowStyleForMetro(hwnd);
104 }
105
106 void CloseFrameWindowInternal(HWND hwnd) {
107 DVLOG(1) << __FUNCTION__ << ", hwnd=" << LONG_PTR(hwnd);
108
109 globals.host_windows.remove_if([hwnd](std::pair<HWND, bool>& item) {
110 return (item.first == hwnd);
111 });
112
113 if (globals.host_windows.size() > 0) {
114 DVLOG(1) << "Making new top frame window visible:"
115 << reinterpret_cast<int>(globals.host_windows.front().first);
116 AdjustToFitWindow(globals.host_windows.front().first, SWP_SHOWWINDOW);
117 } else {
118 // time to quit
119 DVLOG(1) << "Last host window closed. Calling Exit().";
120 globals.app_exit->Exit();
121 }
122 }
123
124 void FlipFrameWindowsInternal() {
125 DVLOG(1) << __FUNCTION__;
126 // Get the first window in the frame windows queue and push it to the end.
127 // Metroize the next window in the queue.
128 if (globals.host_windows.size() > 1) {
129 std::pair<HWND, bool> current_top_window = globals.host_windows.front();
130 globals.host_windows.pop_front();
131
132 DVLOG(1) << "Making new top frame window visible:"
133 << reinterpret_cast<int>(globals.host_windows.front().first);
134
135 AdjustToFitWindow(globals.host_windows.front().first, SWP_SHOWWINDOW);
136
137 DVLOG(1) << "Hiding current top window:"
138 << reinterpret_cast<int>(current_top_window.first);
139 AnimateWindow(current_top_window.first, kAnimateWindowTimeoutMs,
140 AW_HIDE | AW_HOR_POSITIVE | AW_SLIDE);
141
142 globals.host_windows.push_back(current_top_window);
143 }
144 }
145
146 } // namespace
147
148 HRESULT ChromeAppView::TileRequestCreateDone(
149 winfoundtn::IAsyncOperation<bool>* async,
150 AsyncStatus status) {
151 if (status == Completed) {
152 unsigned char result;
153 CheckHR(async->GetResults(&result));
154 DVLOG(1) << __FUNCTION__ << " result " << static_cast<int>(result);
155 } else {
156 LOG(ERROR) << __FUNCTION__ << " Unexpected async status " << status;
157 }
158
159 return S_OK;
160 }
161
162 void ChromeAppView::DisplayNotification(
163 const ToastNotificationHandler::DesktopNotification& notification) {
164 DVLOG(1) << __FUNCTION__;
165
166 if (IsValidNotification(notification.id)) {
167 NOTREACHED() << "Duplicate notification id passed in.";
168 return;
169 }
170
171 base::AutoLock lock(notification_lock_);
172
173 ToastNotificationHandler* notification_handler =
174 new ToastNotificationHandler;
175
176 notification_map_[notification.id].reset(notification_handler);
177 notification_handler->DisplayNotification(notification);
178 }
179
180 void ChromeAppView::CancelNotification(const std::string& notification) {
181 DVLOG(1) << __FUNCTION__;
182
183 base::AutoLock lock(notification_lock_);
184
185 NotificationMap::iterator index = notification_map_.find(notification);
186 if (index == notification_map_.end()) {
187 NOTREACHED() << "Invalid notification:" << notification.c_str();
188 return;
189 }
190
191 scoped_ptr<ToastNotificationHandler> notification_handler(
192 index->second.release());
193
194 notification_map_.erase(index);
195
196 notification_handler->CancelNotification();
197 }
198
199 // Returns true if the notification passed in is valid.
200 bool ChromeAppView::IsValidNotification(const std::string& notification) {
201 DVLOG(1) << __FUNCTION__;
202
203 base::AutoLock lock(notification_lock_);
204 return notification_map_.find(notification) != notification_map_.end();
205 }
206
207 void ChromeAppView::ShowDialogBox(
208 const MetroDialogBox::DialogBoxInfo& dialog_box_info) {
209 VLOG(1) << __FUNCTION__;
210 dialog_box_.Show(dialog_box_info);
211 }
212
213 void ChromeAppView::DismissDialogBox() {
214 VLOG(1) << __FUNCTION__;
215 dialog_box_.Dismiss();
216 }
217
218 // static
219 HRESULT ChromeAppView::Unsnap() {
220 mswr::ComPtr<winui::ViewManagement::IApplicationViewStatics> view_statics;
221 HRESULT hr = winrt_utils::CreateActivationFactory(
222 RuntimeClass_Windows_UI_ViewManagement_ApplicationView,
223 view_statics.GetAddressOf());
224 CheckHR(hr);
225
226 winui::ViewManagement::ApplicationViewState state =
227 winui::ViewManagement::ApplicationViewState_FullScreenLandscape;
228 hr = view_statics->get_Value(&state);
229 CheckHR(hr);
230
231 if (state == winui::ViewManagement::ApplicationViewState_Snapped) {
232 boolean success = FALSE;
233 hr = view_statics->TryUnsnap(&success);
234
235 if (FAILED(hr) || !success) {
236 LOG(ERROR) << "Failed to unsnap. Error 0x" << hr;
237 if (SUCCEEDED(hr))
238 hr = E_UNEXPECTED;
239 }
240 }
241 return hr;
242 }
243
244 void ChromeAppView::SetFullscreen(bool fullscreen) {
245 VLOG(1) << __FUNCTION__;
246
247 if (osk_offset_adjustment_) {
248 VLOG(1) << "Scrolling the window down by: "
249 << osk_offset_adjustment_;
250
251 ::ScrollWindowEx(globals.host_windows.front().first,
252 0,
253 osk_offset_adjustment_,
254 NULL,
255 NULL,
256 NULL,
257 NULL,
258 SW_INVALIDATE | SW_SCROLLCHILDREN);
259 osk_offset_adjustment_ = 0;
260 }
261 }
262
263 void UnsnapHelper() {
264 ChromeAppView::Unsnap();
265 }
266
267 extern "C" __declspec(dllexport)
268 void MetroUnsnap() {
269 DVLOG(1) << __FUNCTION__;
270 globals.appview_msg_loop->PostTask(
271 FROM_HERE, base::Bind(&UnsnapHelper));
272 }
273
274 extern "C" __declspec(dllexport)
275 HWND GetRootWindow() {
276 DVLOG(1) << __FUNCTION__;
277 return globals.core_window;
278 }
279
280 extern "C" __declspec(dllexport)
281 void SetFrameWindow(HWND hwnd) {
282 DVLOG(1) << __FUNCTION__ << ", hwnd=" << LONG_PTR(hwnd);
283 globals.appview_msg_loop->PostTask(
284 FROM_HERE, base::Bind(&SetFrameWindowInternal, hwnd));
285 }
286
287 // TODO(ananta)
288 // Handle frame window close by deleting it from the window list and making the
289 // next guy visible.
290 extern "C" __declspec(dllexport)
291 void CloseFrameWindow(HWND hwnd) {
292 DVLOG(1) << __FUNCTION__ << ", hwnd=" << LONG_PTR(hwnd);
293
294 // This is a hack to ensure that the BrowserViewLayout code layout happens
295 // just at the right time to hide the switcher button if it is visible.
296 globals.appview_msg_loop->PostDelayedTask(
297 FROM_HERE, base::Bind(&CloseFrameWindowInternal, hwnd),
298 base::TimeDelta::FromMilliseconds(50));
299 }
300
301 // Returns the initial url. This returns a valid url only if we were launched
302 // into metro via a url navigation.
303 extern "C" __declspec(dllexport)
304 const wchar_t* GetInitialUrl() {
305 DVLOG(1) << __FUNCTION__;
306 bool was_initial_activation = globals.is_initial_activation;
307 globals.is_initial_activation = false;
308 if (!was_initial_activation || globals.navigation_url.empty())
309 return L"";
310
311 const wchar_t* initial_url = globals.navigation_url.c_str();
312 DVLOG(1) << initial_url;
313 return initial_url;
314 }
315
316 // Returns the initial search string. This returns a valid url only if we were
317 // launched into metro via the search charm
318 extern "C" __declspec(dllexport)
319 const wchar_t* GetInitialSearchString() {
320 DVLOG(1) << __FUNCTION__;
321 bool was_initial_activation = globals.is_initial_activation;
322 globals.is_initial_activation = false;
323 if (!was_initial_activation || globals.search_string.empty())
324 return L"";
325
326 const wchar_t* initial_search_string = globals.search_string.c_str();
327 DVLOG(1) << initial_search_string;
328 return initial_search_string;
329 }
330
331 // Returns the launch type.
332 extern "C" __declspec(dllexport)
333 base::win::MetroLaunchType GetLaunchType(
334 base::win::MetroPreviousExecutionState* previous_state) {
335 if (previous_state) {
336 *previous_state = static_cast<base::win::MetroPreviousExecutionState>(
337 globals.previous_state);
338 }
339 return static_cast<base::win::MetroLaunchType>(
340 globals.initial_activation_kind);
341 }
342
343 extern "C" __declspec(dllexport)
344 void FlipFrameWindows() {
345 DVLOG(1) << __FUNCTION__;
346 globals.appview_msg_loop->PostTask(
347 FROM_HERE, base::Bind(&FlipFrameWindowsInternal));
348 }
349
350 extern "C" __declspec(dllexport)
351 void DisplayNotification(const char* origin_url, const char* icon_url,
352 const wchar_t* title, const wchar_t* body,
353 const wchar_t* display_source,
354 const char* notification_id) {
355 // TODO(ananta)
356 // Needs implementation.
357 DVLOG(1) << __FUNCTION__;
358
359 ToastNotificationHandler::DesktopNotification notification(origin_url,
360 icon_url,
361 title,
362 body,
363 display_source,
364 notification_id);
365 globals.appview_msg_loop->PostTask(
366 FROM_HERE, base::Bind(&ChromeAppView::DisplayNotification,
367 globals.view, notification));
368 }
369
370 extern "C" __declspec(dllexport)
371 bool CancelNotification(const char* notification_id) {
372 // TODO(ananta)
373 // Needs implementation.
374 DVLOG(1) << __FUNCTION__;
375
376 if (!globals.view->IsValidNotification(notification_id)) {
377 NOTREACHED() << "Invalid notification id :" << notification_id;
378 return false;
379 }
380
381 globals.appview_msg_loop->PostTask(
382 FROM_HERE, base::Bind(&ChromeAppView::CancelNotification,
383 globals.view, std::string(notification_id)));
384 return true;
385 }
386
387 // Returns command line switches if any to be used by metro chrome.
388 extern "C" __declspec(dllexport)
389 const wchar_t* GetMetroCommandLineSwitches() {
390 DVLOG(1) << __FUNCTION__;
391 // The metro_command_line_switches field should be filled up once.
392 // ideally in ChromeAppView::Activate.
393 return globals.metro_command_line_switches.c_str();
394 }
395
396 // Provides functionality to display a metro style dialog box with two buttons.
397 // Only one dialog box can be displayed at any given time.
398 extern "C" __declspec(dllexport)
399 void ShowDialogBox(
400 const wchar_t* title,
401 const wchar_t* content,
402 const wchar_t* button1_label,
403 const wchar_t* button2_label,
404 base::win::MetroDialogButtonPressedHandler button1_handler,
405 base::win::MetroDialogButtonPressedHandler button2_handler) {
406 VLOG(1) << __FUNCTION__;
407
408 DCHECK(title);
409 DCHECK(content);
410 DCHECK(button1_label);
411 DCHECK(button2_label);
412 DCHECK(button1_handler);
413 DCHECK(button2_handler);
414
415 MetroDialogBox::DialogBoxInfo dialog_box_info;
416 dialog_box_info.title = title;
417 dialog_box_info.content = content;
418 dialog_box_info.button1_label = button1_label;
419 dialog_box_info.button2_label = button2_label;
420 dialog_box_info.button1_handler = button1_handler;
421 dialog_box_info.button2_handler = button2_handler;
422
423 globals.appview_msg_loop->PostTask(
424 FROM_HERE, base::Bind(
425 &ChromeAppView::ShowDialogBox, globals.view, dialog_box_info));
426 }
427
428 // Provides functionality to dismiss the previously displayed metro style
429 // dialog box.
430 extern "C" __declspec(dllexport)
431 void DismissDialogBox() {
432 VLOG(1) << __FUNCTION__;
433
434 globals.appview_msg_loop->PostTask(
435 FROM_HERE, base::Bind(
436 &ChromeAppView::DismissDialogBox,
437 globals.view));
438 }
439
440 extern "C" __declspec(dllexport)
441 void SetFullscreen(bool fullscreen) {
442 VLOG(1) << __FUNCTION__;
443
444 globals.appview_msg_loop->PostTask(
445 FROM_HERE, base::Bind(
446 &ChromeAppView::SetFullscreen,
447 globals.view, fullscreen));
448 }
449
450 BOOL CALLBACK CoreWindowFinder(HWND hwnd, LPARAM) {
451 char classname[128];
452 if (::GetClassNameA(hwnd, classname, ARRAYSIZE(classname))) {
453 if (lstrcmpiA("Windows.UI.Core.CoreWindow", classname) == 0) {
454 globals.core_window = hwnd;
455 return FALSE;
456 }
457 }
458 return TRUE;
459 }
460
461 template <typename ContainerT>
462 void CloseSecondaryWindows(ContainerT& windows) {
463 DVLOG(1) << "Closing secondary windows", windows.size();
464 std::for_each(windows.begin(), windows.end(), [](HWND hwnd) {
465 ::PostMessageW(hwnd, WM_CLOSE, 0, 0);
466 });
467 windows.clear();
468 }
469
470 void EndChromeSession() {
471 DVLOG(1) << "Sending chrome WM_ENDSESSION window message.";
472 ::SendMessage(globals.host_windows.front().first, WM_ENDSESSION, FALSE,
473 ENDSESSION_CLOSEAPP);
474 }
475
476 DWORD WINAPI HostMainThreadProc(void*) {
477 // Test feature - devs have requested the ability to easily add metro-chrome
478 // command line arguments. This is hard since shortcut arguments are ignored,
479 // by Metro, so we instead read them directly from the pinned taskbar
480 // shortcut. This may call Coinitialize and there is tell of badness
481 // occurring if CoInitialize is called on a metro thread.
482 globals.metro_command_line_switches =
483 winrt_utils::ReadArgumentsFromPinnedTaskbarShortcut();
484
485 globals.g_core_proc = reinterpret_cast<WNDPROC>(
486 ::SetWindowLong(globals.core_window, GWL_WNDPROC,
487 reinterpret_cast<long>(ChromeAppView::CoreWindowProc)));
488 DWORD exit_code = globals.host_main(globals.host_context);
489 DVLOG(1) << "host thread done, exit_code=" << exit_code;
490 globals.app_exit->Exit();
491 return exit_code;
492 }
493
494 ChromeAppView::ChromeAppView()
495 : osk_visible_notification_received_(false),
496 osk_offset_adjustment_(0) {
497 globals.previous_state =
498 winapp::Activation::ApplicationExecutionState_NotRunning;
499 }
500
501 ChromeAppView::~ChromeAppView() {
502 DVLOG(1) << __FUNCTION__;
503 }
504
505 IFACEMETHODIMP
506 ChromeAppView::Initialize(winapp::Core::ICoreApplicationView* view) {
507 view_ = view;
508 DVLOG(1) << __FUNCTION__;
509 globals.main_thread_id = ::GetCurrentThreadId();
510
511 HRESULT hr = view_->add_Activated(mswr::Callback<ActivatedHandler>(
512 this, &ChromeAppView::OnActivate).Get(),
513 &activated_token_);
514 CheckHR(hr);
515 return hr;
516 }
517
518 IFACEMETHODIMP
519 ChromeAppView::SetWindow(winui::Core::ICoreWindow* window) {
520 window_ = window;
521 DVLOG(1) << __FUNCTION__;
522
523 HRESULT hr = url_launch_handler_.Initialize();
524 CheckHR(hr, "Failed to initialize url launch handler.");
525
526 // Register for size notifications.
527 hr = window_->add_SizeChanged(mswr::Callback<SizeChangedHandler>(
528 this, &ChromeAppView::OnSizeChanged).Get(),
529 &sizechange_token_);
530 CheckHR(hr);
531
532 // Register for edge gesture notifications.
533 mswr::ComPtr<winui::Input::IEdgeGestureStatics> edge_gesture_statics;
534 hr = winrt_utils::CreateActivationFactory(
535 RuntimeClass_Windows_UI_Input_EdgeGesture,
536 edge_gesture_statics.GetAddressOf());
537 CheckHR(hr, "Failed to activate IEdgeGestureStatics.");
538
539 mswr::ComPtr<winui::Input::IEdgeGesture> edge_gesture;
540 hr = edge_gesture_statics->GetForCurrentView(&edge_gesture);
541 CheckHR(hr);
542
543 hr = edge_gesture->add_Completed(mswr::Callback<EdgeEventHandler>(
544 this, &ChromeAppView::OnEdgeGestureCompleted).Get(),
545 &edgeevent_token_);
546 CheckHR(hr);
547
548 // Register for share notifications.
549 mswr::ComPtr<winapp::DataTransfer::IDataTransferManagerStatics>
550 data_mgr_statics;
551 hr = winrt_utils::CreateActivationFactory(
552 RuntimeClass_Windows_ApplicationModel_DataTransfer_DataTransferManager,
553 data_mgr_statics.GetAddressOf());
554 CheckHR(hr, "Failed to activate IDataTransferManagerStatics.");
555
556 mswr::ComPtr<winapp::DataTransfer::IDataTransferManager> data_transfer_mgr;
557 hr = data_mgr_statics->GetForCurrentView(&data_transfer_mgr);
558 CheckHR(hr, "Failed to get IDataTransferManager for current view.");
559
560 hr = data_transfer_mgr->add_DataRequested(
561 mswr::Callback<ShareDataRequestedHandler>(
562 this, &ChromeAppView::OnShareDataRequested).Get(),
563 &share_data_requested_token_);
564 CheckHR(hr);
565
566 // TODO(ananta)
567 // The documented InputPane notifications don't fire on Windows 8 in metro
568 // chrome. Uncomment this once we figure out why they don't fire.
569 // RegisterInputPaneNotifications();
570
571 hr = winrt_utils::CreateActivationFactory(
572 RuntimeClass_Windows_UI_ViewManagement_ApplicationView,
573 app_view_.GetAddressOf());
574 CheckHR(hr);
575
576 DVLOG(1) << "Created appview instance.";
577
578 hr = devices_handler_.Initialize(window);
579 // Don't check or return the failure here, we need to let the app
580 // initialization succeed. Even if we won't be able to access devices
581 // we still want to allow the app to start.
582 LOG_IF(ERROR, FAILED(hr)) << "Failed to initialize devices handler.";
583 return S_OK;
584 }
585
586 IFACEMETHODIMP
587 ChromeAppView::Load(HSTRING entryPoint) {
588 DVLOG(1) << __FUNCTION__;
589 return S_OK;
590 }
591
592 void RunMessageLoop(winui::Core::ICoreDispatcher* dispatcher) {
593 // We're entering a nested message loop, let's allow dispatching
594 // tasks while we're in there.
595 MessageLoop::current()->SetNestableTasksAllowed(true);
596
597 // Enter main core message loop. There are several ways to exit it
598 // Nicely:
599 // 1 - User action like ALT-F4.
600 // 2 - Calling ICoreApplicationExit::Exit().
601 // 3- Posting WM_CLOSE to the core window.
602 HRESULT hr = dispatcher->ProcessEvents(
603 winui::Core::CoreProcessEventsOption
604 ::CoreProcessEventsOption_ProcessUntilQuit);
605
606 // Wind down the thread's chrome message loop.
607 MessageLoop::current()->Quit();
608 }
609
610 void ChromeAppView::CheckForOSKActivation() {
611 // Hack for checking if the OSK was displayed while we are in the foreground.
612 // The input pane notifications which are supposed to fire when the OSK is
613 // shown and hidden don't seem to be firing in Windows 8 metro for us.
614 // The current hack is supposed to workaround that issue till we figure it
615 // out. Logic is to find the OSK window and see if we are the foreground
616 // process. If yes then fire the notification once for when the OSK is shown
617 // and once for when it is hidden.
618 // TODO(ananta)
619 // Take this out when the documented input pane notifcation issues are
620 // addressed.
621 HWND osk = ::FindWindow(kOSKClassName, NULL);
622 if (::IsWindow(osk)) {
623 HWND foreground_window = ::GetForegroundWindow();
624 if (globals.host_windows.size() > 0 &&
625 foreground_window == globals.host_windows.front().first) {
626 RECT osk_rect = {0};
627 ::GetWindowRect(osk, &osk_rect);
628
629 if (::IsWindowVisible(osk) && ::IsWindowEnabled(osk)) {
630 if (!globals.view->osk_visible_notification_received()) {
631 DVLOG(1) << "Found KB window while we are in the forground.";
632 HandleInputPaneVisible(osk_rect);
633 }
634 } else if (osk_visible_notification_received()) {
635 DVLOG(1) << "KB window hidden while we are in the foreground.";
636 HandleInputPaneHidden(osk_rect);
637 }
638 }
639 }
640 MessageLoop::current()->PostDelayedTask(
641 FROM_HERE,
642 base::Bind(&ChromeAppView::CheckForOSKActivation,
643 base::Unretained(this)),
644 base::TimeDelta::FromMilliseconds(kCheckOSKDelayMs));
645 }
646
647 IFACEMETHODIMP
648 ChromeAppView::Run() {
649 DVLOG(1) << __FUNCTION__ << ", hwnd=" << LONG_PTR(window_.Get());
650 mswr::ComPtr<winui::Core::ICoreDispatcher> dispatcher;
651 HRESULT hr = window_->get_Dispatcher(&dispatcher);
652 CheckHR(hr, "Dispatcher failed.");
653
654 hr = window_->Activate();
655 if (SUCCEEDED(hr)) {
656 // TODO(cpu): Draw something here.
657 } else {
658 DVLOG(1) << "Activate failed, hr=" << hr;
659 }
660
661 // Create a message loop to allow message passing into this thread.
662 MessageLoop msg_loop(MessageLoop::TYPE_UI);
663
664 // Announce our message loop to the world.
665 globals.appview_msg_loop = msg_loop.message_loop_proxy();
666
667 // And post the task that'll do the inner Metro message pumping to it.
668 msg_loop.PostTask(FROM_HERE, base::Bind(&RunMessageLoop, dispatcher.Get()));
669
670 // Post the recurring task which checks for OSK activation in metro chrome.
671 // Please refer to the comments in the CheckForOSKActivation function for why
672 // this is needed.
673 // TODO(ananta)
674 // Take this out when the documented OSK notifications start working.
675 msg_loop.PostDelayedTask(
676 FROM_HERE,
677 base::Bind(&ChromeAppView::CheckForOSKActivation,
678 base::Unretained(this)),
679 base::TimeDelta::FromMilliseconds(kCheckOSKDelayMs));
680
681 msg_loop.Run();
682
683 globals.appview_msg_loop = NULL;
684
685 DVLOG(0) << "ProcessEvents done, hr=" << hr;
686
687 // We join here with chrome's main thread so that the chrome is not killed
688 // while a critical operation is still in progress. Now, if there are host
689 // windows active it is possible we end up stuck on the wait below therefore
690 // we tell chrome to close its windows.
691 if (!globals.host_windows.empty()) {
692 DVLOG(1) << "Chrome still has windows open!";
693 EndChromeSession();
694 }
695 DWORD wr = ::WaitForSingleObject(globals.host_thread, INFINITE);
696 if (wr != WAIT_OBJECT_0) {
697 DVLOG(1) << "Waiting for host thread failed : " << wr;
698 }
699 ::CloseHandle(globals.host_thread);
700 globals.host_thread = NULL;
701
702 return hr;
703 }
704
705 IFACEMETHODIMP
706 ChromeAppView::Uninitialize() {
707 DVLOG(1) << __FUNCTION__;
708 window_ = nullptr;
709 view_ = nullptr;
710 base::AutoLock lock(notification_lock_);
711 notification_map_.clear();
712 return S_OK;
713 }
714
715 HRESULT ChromeAppView::RegisterInputPaneNotifications() {
716 DVLOG(1) << __FUNCTION__;
717
718 mswr::ComPtr<winui::ViewManagement::IInputPaneStatics>
719 input_pane_statics;
720 HRESULT hr = winrt_utils::CreateActivationFactory(
721 RuntimeClass_Windows_UI_ViewManagement_InputPane,
722 input_pane_statics.GetAddressOf());
723 CheckHR(hr);
724
725 hr = input_pane_statics->GetForCurrentView(&input_pane_);
726 CheckHR(hr);
727 DVLOG(1) << "Got input pane.";
728
729 hr = input_pane_->add_Showing(
730 mswr::Callback<InputPaneEventHandler>(
731 this, &ChromeAppView::OnInputPaneVisible).Get(),
732 &input_pane_visible_token_);
733 CheckHR(hr);
734
735 DVLOG(1) << "Added showing event handler for input pane",
736 input_pane_visible_token_.value;
737
738 hr = input_pane_->add_Hiding(
739 mswr::Callback<InputPaneEventHandler>(
740 this, &ChromeAppView::OnInputPaneHiding).Get(),
741 &input_pane_hiding_token_);
742 CheckHR(hr);
743
744 DVLOG(1) << "Added hiding event handler for input pane, value="
745 << input_pane_hiding_token_.value;
746 return hr;
747 }
748
749 HRESULT ChromeAppView::OnActivate(winapp::Core::ICoreApplicationView*,
750 winapp::Activation::IActivatedEventArgs* args) {
751 DVLOG(1) << __FUNCTION__;
752
753 args->get_PreviousExecutionState(&globals.previous_state);
754 DVLOG(1) << "Previous Execution State: " << globals.previous_state;
755
756 window_->Activate();
757 url_launch_handler_.Activate(args);
758
759 if (globals.previous_state ==
760 winapp::Activation::ApplicationExecutionState_Running &&
761 globals.host_thread) {
762 DVLOG(1) << "Already running. Skipping rest of OnActivate.";
763 return S_OK;
764 }
765
766 do {
767 ::Sleep(10);
768 ::EnumThreadWindows(globals.main_thread_id, &CoreWindowFinder, 0);
769 } while (globals.core_window == NULL);
770
771 DVLOG(1) << "CoreWindow found: " << std::hex << globals.core_window;
772
773 if (!globals.host_thread) {
774 globals.host_thread =
775 ::CreateThread(NULL, 0, HostMainThreadProc, NULL, 0, NULL);
776
777 if (!globals.host_thread) {
778 NOTREACHED() << "thread creation failed.";
779 return E_UNEXPECTED;
780 }
781 }
782
783 if (RegisterHotKey(globals.core_window, kFlipWindowsHotKeyId,
784 MOD_CONTROL, VK_F12)) {
785 DVLOG(1) << "Registered flip window hotkey.";
786 } else {
787 VPLOG(1) << "Failed to register flip window hotkey.";
788 }
789 HRESULT hr = settings_handler_.Initialize();
790 CheckHR(hr,"Failed to initialize settings handler.");
791 return hr;
792 }
793
794 // We subclass the core window for moving the associated chrome window when the
795 // core window is moved around, typically in the snap view operation. The
796 // size changes are handled in the documented size changed event.
797 LRESULT CALLBACK ChromeAppView::CoreWindowProc(
798 HWND window, UINT message, WPARAM wp, LPARAM lp) {
799
800 static const UINT kBrowserClosingMessage =
801 ::RegisterWindowMessage(L"DefaultBrowserClosing");
802
803 if (message == WM_WINDOWPOSCHANGED) {
804 WINDOWPOS* pos = reinterpret_cast<WINDOWPOS*>(lp);
805 if (!(pos->flags & SWP_NOMOVE)) {
806 DVLOG(1) << "WM_WINDOWPOSCHANGED. Moving the chrome window.";
807 globals.view->OnPositionChanged(pos->x, pos->y);
808 }
809 } else if (message == WM_HOTKEY && wp == kFlipWindowsHotKeyId) {
810 FlipFrameWindows();
811 } else if (message == kBrowserClosingMessage) {
812 DVLOG(1) << "Received DefaultBrowserClosing window message.";
813 // Ensure that the view is uninitialized. The kBrowserClosingMessage
814 // means that the app is going to be terminated, i.e. the proper
815 // uninitialization sequence does not occur.
816 globals.view->Uninitialize();
817 if (!globals.host_windows.empty()) {
818 EndChromeSession();
819 }
820 }
821 return CallWindowProc(globals.g_core_proc, window, message, wp, lp);
822 }
823
824 HRESULT ChromeAppView::OnSizeChanged(winui::Core::ICoreWindow* sender,
825 winui::Core::IWindowSizeChangedEventArgs* args) {
826 if (!globals.host_windows.size()) {
827 return S_OK;
828 }
829
830 winfoundtn::Size size;
831 args->get_Size(&size);
832
833 int cx = static_cast<int>(size.Width);
834 int cy = static_cast<int>(size.Height);
835
836 if (!::SetWindowPos(globals.host_windows.front().first, NULL, 0, 0, cx, cy,
837 SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED)) {
838 DVLOG(1) << "SetWindowPos failed.";
839 }
840 DVLOG(1) << "size changed cx=" << cx;
841 DVLOG(1) << "size changed cy=" << cy;
842
843 winui::ViewManagement::ApplicationViewState view_state =
844 winui::ViewManagement::ApplicationViewState_FullScreenLandscape;
845 app_view_->get_Value(&view_state);
846
847 HWND top_level_frame = globals.host_windows.front().first;
848 if (view_state == winui::ViewManagement::ApplicationViewState_Snapped) {
849 DVLOG(1) << "Enabling metro snap mode.";
850 ::PostMessageW(top_level_frame, WM_SYSCOMMAND, IDC_METRO_SNAP_ENABLE, 0);
851 } else {
852 ::PostMessageW(top_level_frame, WM_SYSCOMMAND, IDC_METRO_SNAP_DISABLE, 0);
853 }
854 return S_OK;
855 }
856
857 HRESULT ChromeAppView::OnPositionChanged(int x, int y) {
858 DVLOG(1) << __FUNCTION__;
859
860 ::SetWindowPos(globals.host_windows.front().first, NULL, x, y, 0, 0,
861 SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOSIZE);
862 return S_OK;
863 }
864
865 HRESULT ChromeAppView::OnEdgeGestureCompleted(
866 winui::Input::IEdgeGesture* gesture,
867 winui::Input::IEdgeGestureEventArgs* args) {
868 DVLOG(1) << "edge gesture completed.";
869
870 winui::ViewManagement::ApplicationViewState view_state =
871 winui::ViewManagement::ApplicationViewState_FullScreenLandscape;
872 app_view_->get_Value(&view_state);
873 // We don't want fullscreen chrome unless we are fullscreen metro.
874 if ((view_state == winui::ViewManagement::ApplicationViewState_Filled) ||
875 (view_state == winui::ViewManagement::ApplicationViewState_Snapped)) {
876 DVLOG(1) << "No full screen in snapped view state:" << view_state;
877 return S_OK;
878 }
879
880 // Deactivate anything pending, e.g., the wrench or a context menu.
881 BOOL success = ::ReleaseCapture();
882 DCHECK(success) << "Couldn't ReleaseCapture() before going full screen";
883
884 DVLOG(1) << "Going full screen.";
885 ::PostMessageW(globals.host_windows.front().first, WM_SYSCOMMAND,
886 IDC_FULLSCREEN, 0);
887 return S_OK;
888 }
889
890 HRESULT ChromeAppView::OnShareDataRequested(
891 winapp::DataTransfer::IDataTransferManager* data_transfer_mgr,
892 winapp::DataTransfer::IDataRequestedEventArgs* event_args) {
893
894 DVLOG(1) << "Share data requested.";
895
896 // The current tab info is retrieved from Chrome via a registered window
897 // message.
898
899 static const UINT get_current_tab_info =
900 RegisterWindowMessage(kMetroGetCurrentTabInfoMessage);
901
902 static const int kGetTabInfoTimeoutMs = 1000;
903
904 mswr::ComPtr<winapp::DataTransfer::IDataRequest> data_request;
905 HRESULT hr = event_args->get_Request(&data_request);
906 CheckHR(hr);
907
908 mswr::ComPtr<winapp::DataTransfer::IDataPackage> data_package;
909 hr = data_request->get_Data(&data_package);
910 CheckHR(hr);
911
912 base::win::CurrentTabInfo current_tab_info;
913 current_tab_info.title = NULL;
914 current_tab_info.url = NULL;
915
916 DWORD_PTR result = 0;
917
918 if (!SendMessageTimeout(globals.host_windows.front().first,
919 get_current_tab_info,
920 reinterpret_cast<WPARAM>(&current_tab_info),
921 0,
922 SMTO_ABORTIFHUNG,
923 kGetTabInfoTimeoutMs,
924 &result)) {
925 VPLOG(1) << "Failed to retrieve tab info from chrome.";
926 return E_FAIL;
927 }
928
929 if (!current_tab_info.title || !current_tab_info.url) {
930 DVLOG(1) << "Failed to retrieve tab info from chrome.";
931 return E_FAIL;
932 }
933
934 string16 current_title(current_tab_info.title);
935 string16 current_url(current_tab_info.url);
936
937 LocalFree(current_tab_info.title);
938 LocalFree(current_tab_info.url);
939
940 mswr::ComPtr<winapp::DataTransfer::IDataPackagePropertySet> data_properties;
941 hr = data_package->get_Properties(&data_properties);
942
943 mswrw::HString title;
944 title.Attach(MakeHString(current_title));
945 data_properties->put_Title(title.Get());
946
947 mswr::ComPtr<winfoundtn::IUriRuntimeClassFactory> uri_factory;
948 hr = winrt_utils::CreateActivationFactory(
949 RuntimeClass_Windows_Foundation_Uri,
950 uri_factory.GetAddressOf());
951 CheckHR(hr);
952
953 mswrw::HString url;
954 url.Attach(MakeHString(current_url));
955 mswr::ComPtr<winfoundtn::IUriRuntimeClass> uri;
956 hr = uri_factory->CreateUri(url.Get(), &uri);
957 CheckHR(hr);
958
959 hr = data_package->SetUri(uri.Get());
960 CheckHR(hr);
961
962 return S_OK;
963 }
964
965 void ChromeAppView::HandleInputPaneVisible(const RECT& osk_rect) {
966 DCHECK(!osk_visible_notification_received_);
967
968 DVLOG(1) << __FUNCTION__;
969 DVLOG(1) << "OSK width:" << osk_rect.right - osk_rect.left;
970 DVLOG(1) << "OSK height:" << osk_rect.bottom - osk_rect.top;
971
972 globals.host_windows.front().second = false;
973
974 POINT cursor_pos = {0};
975 GetCursorPos(&cursor_pos);
976
977 osk_offset_adjustment_ = 0;
978
979 if (::PtInRect(&osk_rect, cursor_pos)) {
980 DVLOG(1) << "OSK covering focus point.";
981 int osk_height = osk_rect.bottom - osk_rect.top;
982
983 osk_offset_adjustment_ = osk_height + kOSKAdjustmentOffset;
984
985 DVLOG(1) << "Scrolling window by offset: " << osk_offset_adjustment_;
986 ::ScrollWindowEx(globals.host_windows.front().first,
987 0,
988 -osk_offset_adjustment_,
989 NULL,
990 NULL,
991 NULL,
992 NULL,
993 SW_INVALIDATE | SW_SCROLLCHILDREN);
994
995 globals.host_windows.front().second = true;
996 }
997 osk_visible_notification_received_ = true;
998 }
999
1000 void ChromeAppView::HandleInputPaneHidden(const RECT& osk_rect) {
1001 DCHECK(osk_visible_notification_received_);
1002 DVLOG(1) << __FUNCTION__;
1003 DVLOG(1) << "OSK width:" << osk_rect.right - osk_rect.left;
1004 DVLOG(1) << "OSK height:" << osk_rect.bottom - osk_rect.top;
1005 osk_visible_notification_received_ = false;
1006 if (globals.host_windows.front().second == true) {
1007
1008 if (osk_offset_adjustment_) {
1009 DVLOG(1) << "Restoring scrolled window offset: "
1010 << osk_offset_adjustment_;
1011
1012 ::ScrollWindowEx(globals.host_windows.front().first,
1013 0,
1014 osk_offset_adjustment_,
1015 NULL,
1016 NULL,
1017 NULL,
1018 NULL,
1019 SW_INVALIDATE | SW_SCROLLCHILDREN);
1020 }
1021
1022 globals.host_windows.front().second = false;
1023 }
1024 }
1025
1026 HRESULT ChromeAppView::OnInputPaneVisible(
1027 winui::ViewManagement::IInputPane* input_pane,
1028 winui::ViewManagement::IInputPaneVisibilityEventArgs* event_args) {
1029 DVLOG(1) << __FUNCTION__;
1030 return S_OK;
1031 }
1032
1033 HRESULT ChromeAppView::OnInputPaneHiding(
1034 winui::ViewManagement::IInputPane* input_pane,
1035 winui::ViewManagement::IInputPaneVisibilityEventArgs* event_args) {
1036 DVLOG(1) << __FUNCTION__;
1037 return S_OK;
1038 }
1039
1040 ///////////////////////////////////////////////////////////////////////////////
1041
1042 ChromeAppViewFactory::ChromeAppViewFactory(
1043 winapp::Core::ICoreApplication* icore_app,
1044 LPTHREAD_START_ROUTINE host_main,
1045 void* host_context) {
1046 globals.host_main = host_main;
1047 globals.host_context = host_context;
1048 mswr::ComPtr<winapp::Core::ICoreApplication> core_app(icore_app);
1049 mswr::ComPtr<winapp::Core::ICoreApplicationExit> app_exit;
1050 CheckHR(core_app.As(&app_exit));
1051 globals.app_exit = app_exit.Detach();
1052 }
1053
1054 IFACEMETHODIMP
1055 ChromeAppViewFactory::CreateView(winapp::Core::IFrameworkView** view) {
1056 globals.view = mswr::Make<ChromeAppView>().Detach();
1057 *view = globals.view;
1058 return (*view) ? S_OK : E_OUTOFMEMORY;
1059 }
OLDNEW
« no previous file with comments | « win8/metro_driver/chrome_app_view.h ('k') | win8/metro_driver/chrome_url_launch_handler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698