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.
5 #include "win8/metro_driver/stdafx.h"
6 #include "win8/metro_driver/chrome_app_view_ash.h"
8 #include <corewindow.h>
10 #include <windows.foundation.h>
12 #include "base/bind.h"
13 #include "base/command_line.h"
14 #include "base/files/file_path.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/path_service.h"
17 #include "base/single_thread_task_runner.h"
18 #include "base/win/metro.h"
19 #include "base/win/win_util.h"
20 #include "base/win/windows_version.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "ipc/ipc_channel.h"
23 #include "ipc/ipc_channel_proxy.h"
24 #include "ipc/ipc_sender.h"
25 #include "ui/events/gesture_detection/motion_event.h"
26 #include "ui/gfx/geometry/point_conversions.h"
27 #include "ui/gfx/win/dpi.h"
28 #include "ui/metro_viewer/metro_viewer_messages.h"
29 #include "win8/metro_driver/file_picker_ash.h"
30 #include "win8/metro_driver/ime/ime_popup_monitor.h"
31 #include "win8/metro_driver/ime/input_source.h"
32 #include "win8/metro_driver/ime/text_service.h"
33 #include "win8/metro_driver/metro_driver.h"
34 #include "win8/metro_driver/winrt_utils.h"
35 #include "win8/viewer/metro_viewer_constants.h"
37 typedef winfoundtn::ITypedEventHandler
<
38 winapp::Core::CoreApplicationView
*,
39 winapp::Activation::IActivatedEventArgs
*> ActivatedHandler
;
41 typedef winfoundtn::ITypedEventHandler
<
42 winui::Core::CoreWindow
*,
43 winui::Core::PointerEventArgs
*> PointerEventHandler
;
45 typedef winfoundtn::ITypedEventHandler
<
46 winui::Core::CoreWindow
*,
47 winui::Core::KeyEventArgs
*> KeyEventHandler
;
49 typedef winfoundtn::ITypedEventHandler
<
50 winui::Core::CoreDispatcher
*,
51 winui::Core::AcceleratorKeyEventArgs
*> AcceleratorKeyEventHandler
;
53 typedef winfoundtn::ITypedEventHandler
<
54 winui::Core::CoreWindow
*,
55 winui::Core::CharacterReceivedEventArgs
*> CharEventHandler
;
57 typedef winfoundtn::ITypedEventHandler
<
58 winui::Core::CoreWindow
*,
59 winui::Core::WindowActivatedEventArgs
*> WindowActivatedHandler
;
61 typedef winfoundtn::ITypedEventHandler
<
62 winui::Core::CoreWindow
*,
63 winui::Core::WindowSizeChangedEventArgs
*> SizeChangedHandler
;
65 typedef winfoundtn::ITypedEventHandler
<
66 winui::Input::EdgeGesture
*,
67 winui::Input::EdgeGestureEventArgs
*> EdgeEventHandler
;
69 // This function is exported by chrome.exe.
70 typedef int (__cdecl
*BreakpadExceptionHandler
)(EXCEPTION_POINTERS
* info
);
72 // Global information used across the metro driver.
74 winapp::Activation::ApplicationExecutionState previous_state
;
75 winapp::Core::ICoreApplicationExit
* app_exit
;
76 BreakpadExceptionHandler breakpad_exception_handler
;
79 extern float GetModernUIScale();
90 const int kChromeChannelPollTimerMs
= 100;
92 // Helper function to send keystrokes via the SendInput function.
93 // mnemonic_char: The keystroke to be sent.
94 // modifiers: Combination with Alt, Ctrl, Shift, etc.
96 WORD mnemonic_char
, KeyModifier modifiers
) {
97 INPUT keys
[4] = {}; // Keyboard events
98 int key_count
= 0; // Number of generated events
100 if (modifiers
& SHIFT
) {
101 keys
[key_count
].type
= INPUT_KEYBOARD
;
102 keys
[key_count
].ki
.wVk
= VK_SHIFT
;
103 keys
[key_count
].ki
.wScan
= MapVirtualKey(VK_SHIFT
, 0);
107 if (modifiers
& CONTROL
) {
108 keys
[key_count
].type
= INPUT_KEYBOARD
;
109 keys
[key_count
].ki
.wVk
= VK_CONTROL
;
110 keys
[key_count
].ki
.wScan
= MapVirtualKey(VK_CONTROL
, 0);
114 if (modifiers
& ALT
) {
115 keys
[key_count
].type
= INPUT_KEYBOARD
;
116 keys
[key_count
].ki
.wVk
= VK_MENU
;
117 keys
[key_count
].ki
.wScan
= MapVirtualKey(VK_MENU
, 0);
121 keys
[key_count
].type
= INPUT_KEYBOARD
;
122 keys
[key_count
].ki
.wVk
= mnemonic_char
;
123 keys
[key_count
].ki
.wScan
= MapVirtualKey(mnemonic_char
, 0);
126 bool should_sleep
= key_count
> 1;
129 for (int i
= 0; i
< key_count
; i
++) {
130 SendInput(1, &keys
[ i
], sizeof(keys
[0]));
131 keys
[i
].ki
.dwFlags
|= KEYEVENTF_KEYUP
;
136 // Now send key ups in reverse order.
137 for (int i
= key_count
; i
; i
--) {
138 SendInput(1, &keys
[ i
- 1 ], sizeof(keys
[0]));
144 class ChromeChannelListener
: public IPC::Listener
{
146 ChromeChannelListener(base::MessageLoop
* ui_loop
, ChromeAppViewAsh
* app_view
)
147 : ui_task_runner_(ui_loop
->task_runner()), app_view_(app_view
) {}
149 bool OnMessageReceived(const IPC::Message
& message
) override
{
150 IPC_BEGIN_MESSAGE_MAP(ChromeChannelListener
, message
)
151 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ActivateDesktop
,
153 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MetroExit
, OnMetroExit
)
154 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_OpenURLOnDesktop
,
156 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursor
, OnSetCursor
)
157 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileOpen
,
158 OnDisplayFileOpenDialog
)
159 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileSaveAs
,
160 OnDisplayFileSaveAsDialog
)
161 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplaySelectFolder
,
162 OnDisplayFolderPicker
)
163 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursorPos
, OnSetCursorPos
)
164 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeCancelComposition
,
165 OnImeCancelComposition
)
166 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeTextInputClientUpdated
,
167 OnImeTextInputClientChanged
)
168 IPC_MESSAGE_UNHANDLED(__debugbreak())
169 IPC_END_MESSAGE_MAP()
173 void OnChannelError() override
{
174 DVLOG(1) << "Channel error. Exiting.";
175 ui_task_runner_
->PostTask(
177 base::Bind(&ChromeAppViewAsh::OnMetroExit
, base::Unretained(app_view_
),
178 TERMINATE_USING_KEY_SEQUENCE
));
180 // In early Windows 8 versions the code above sometimes fails so we call
181 // it a second time with a NULL window which just calls Exit().
182 ui_task_runner_
->PostDelayedTask(
184 base::Bind(&ChromeAppViewAsh::OnMetroExit
, base::Unretained(app_view_
),
185 TERMINATE_USING_PROCESS_EXIT
),
186 base::TimeDelta::FromMilliseconds(100));
190 void OnActivateDesktop(const base::FilePath
& shortcut
, bool ash_exit
) {
191 ui_task_runner_
->PostTask(
192 FROM_HERE
, base::Bind(&ChromeAppViewAsh::OnActivateDesktop
,
193 base::Unretained(app_view_
), shortcut
, ash_exit
));
197 ui_task_runner_
->PostTask(
199 base::Bind(&ChromeAppViewAsh::OnMetroExit
, base::Unretained(app_view_
),
200 TERMINATE_USING_KEY_SEQUENCE
));
203 void OnOpenURLOnDesktop(const base::FilePath
& shortcut
,
204 const base::string16
& url
) {
205 ui_task_runner_
->PostTask(
206 FROM_HERE
, base::Bind(&ChromeAppViewAsh::OnOpenURLOnDesktop
,
207 base::Unretained(app_view_
), shortcut
, url
));
210 void OnSetCursor(int64 cursor
) {
211 ui_task_runner_
->PostTask(
213 base::Bind(&ChromeAppViewAsh::OnSetCursor
, base::Unretained(app_view_
),
214 reinterpret_cast<HCURSOR
>(cursor
)));
217 void OnDisplayFileOpenDialog(const base::string16
& title
,
218 const base::string16
& filter
,
219 const base::FilePath
& default_path
,
220 bool allow_multiple_files
) {
221 ui_task_runner_
->PostTask(
222 FROM_HERE
, base::Bind(&ChromeAppViewAsh::OnDisplayFileOpenDialog
,
223 base::Unretained(app_view_
), title
, filter
,
224 default_path
, allow_multiple_files
));
227 void OnDisplayFileSaveAsDialog(
228 const MetroViewerHostMsg_SaveAsDialogParams
& params
) {
229 ui_task_runner_
->PostTask(
230 FROM_HERE
, base::Bind(&ChromeAppViewAsh::OnDisplayFileSaveAsDialog
,
231 base::Unretained(app_view_
), params
));
234 void OnDisplayFolderPicker(const base::string16
& title
) {
235 ui_task_runner_
->PostTask(
236 FROM_HERE
, base::Bind(&ChromeAppViewAsh::OnDisplayFolderPicker
,
237 base::Unretained(app_view_
), title
));
240 void OnSetCursorPos(int x
, int y
) {
241 VLOG(1) << "In IPC OnSetCursorPos: " << x
<< ", " << y
;
242 ui_task_runner_
->PostTask(FROM_HERE
,
243 base::Bind(&ChromeAppViewAsh::OnSetCursorPos
,
244 base::Unretained(app_view_
), x
, y
));
247 void OnImeCancelComposition() {
248 ui_task_runner_
->PostTask(
249 FROM_HERE
, base::Bind(&ChromeAppViewAsh::OnImeCancelComposition
,
250 base::Unretained(app_view_
)));
253 void OnImeTextInputClientChanged(
254 const std::vector
<int32
>& input_scopes
,
255 const std::vector
<metro_viewer::CharacterBounds
>& character_bounds
) {
256 ui_task_runner_
->PostTask(
257 FROM_HERE
, base::Bind(&ChromeAppViewAsh::OnImeUpdateTextInputClient
,
258 base::Unretained(app_view_
), input_scopes
,
262 scoped_refptr
<base::SingleThreadTaskRunner
> ui_task_runner_
;
263 ChromeAppViewAsh
* app_view_
;
266 void RunMessageLoop(winui::Core::ICoreDispatcher
* dispatcher
) {
267 // We're entering a nested message loop, let's allow dispatching
268 // tasks while we're in there.
269 base::MessageLoop::current()->SetNestableTasksAllowed(true);
271 // Enter main core message loop. There are several ways to exit it
273 // 1 - User action like ALT-F4.
274 // 2 - Calling ICoreApplicationExit::Exit().
275 // 3- Posting WM_CLOSE to the core window.
276 dispatcher
->ProcessEvents(
277 winui::Core::CoreProcessEventsOption
278 ::CoreProcessEventsOption_ProcessUntilQuit
);
280 // Wind down the thread's chrome message loop.
281 base::MessageLoop::current()->Quit();
284 // Helper to return the state of the shift/control/alt keys.
285 uint32
GetKeyboardEventFlags() {
287 if (base::win::IsShiftPressed())
288 flags
|= ui::EF_SHIFT_DOWN
;
289 if (base::win::IsCtrlPressed())
290 flags
|= ui::EF_CONTROL_DOWN
;
291 if (base::win::IsAltPressed())
292 flags
|= ui::EF_ALT_DOWN
;
296 bool LaunchChromeBrowserProcess(const wchar_t* additional_parameters
,
297 winapp::Activation::IActivatedEventArgs
* args
) {
299 DVLOG(1) << __FUNCTION__
<< ":" << ::GetCommandLineW();
300 winapp::Activation::ActivationKind activation_kind
;
301 CheckHR(args
->get_Kind(&activation_kind
));
303 DVLOG(1) << __FUNCTION__
<< ", activation_kind=" << activation_kind
;
305 if (activation_kind
== winapp::Activation::ActivationKind_Launch
) {
306 mswr::ComPtr
<winapp::Activation::ILaunchActivatedEventArgs
> launch_args
;
307 if (args
->QueryInterface(
308 winapp::Activation::IID_ILaunchActivatedEventArgs
,
309 &launch_args
) == S_OK
) {
310 DVLOG(1) << "Activate: ActivationKind_Launch";
311 mswrw::HString launch_args_str
;
312 launch_args
->get_Arguments(launch_args_str
.GetAddressOf());
313 base::string16
actual_launch_args(
314 MakeStdWString(launch_args_str
.Get()));
315 if (actual_launch_args
== win8::kMetroViewerConnectVerb
) {
316 DVLOG(1) << __FUNCTION__
<< "Not launching chrome server";
323 DVLOG(1) << "Launching chrome server";
324 base::FilePath chrome_exe_path
;
326 if (!PathService::Get(base::FILE_EXE
, &chrome_exe_path
))
329 base::string16 parameters
= L
"--silent-launch --connect-to-metro-viewer ";
330 if (additional_parameters
)
331 parameters
+= additional_parameters
;
333 SHELLEXECUTEINFO sei
= { sizeof(sei
) };
334 sei
.nShow
= SW_SHOWNORMAL
;
335 sei
.lpFile
= chrome_exe_path
.value().c_str();
336 sei
.lpDirectory
= L
"";
337 sei
.lpParameters
= parameters
.c_str();
338 ::ShellExecuteEx(&sei
);
344 // This class helps decoding the pointer properties of an event.
345 class ChromeAppViewAsh::PointerInfoHandler
{
347 PointerInfoHandler(float metro_dpi_scale
, float win32_dpi_scale
)
352 update_kind_(winui::Input::PointerUpdateKind_Other
),
354 mouse_down_flags_(0),
355 is_horizontal_wheel_(0),
356 metro_dpi_scale_(metro_dpi_scale
),
357 win32_dpi_scale_(win32_dpi_scale
) {}
359 HRESULT
Init(winui::Core::IPointerEventArgs
* args
) {
360 HRESULT hr
= args
->get_CurrentPoint(&pointer_point_
);
364 winfoundtn::Point point
;
365 hr
= pointer_point_
->get_Position(&point
);
369 mswr::ComPtr
<winui::Input::IPointerPointProperties
> properties
;
370 hr
= pointer_point_
->get_Properties(&properties
);
374 hr
= properties
->get_PointerUpdateKind(&update_kind_
);
378 hr
= properties
->get_MouseWheelDelta(&wheel_delta_
);
382 is_horizontal_wheel_
= 0;
383 properties
->get_IsHorizontalMouseWheel(&is_horizontal_wheel_
);
385 // The input coordinates are in DIP based on the metro scale factor.
386 // We want to convert it to DIP based on the win32 scale factor.
387 // We scale the point by the metro scale factor and then scale down
388 // via the win32 scale factor which achieves the needful.
389 gfx::Point
dip_point_metro(point
.X
, point
.Y
);
390 gfx::Point scaled_point_metro
=
391 gfx::ToCeiledPoint(gfx::ScalePoint(dip_point_metro
, metro_dpi_scale_
));
392 gfx::Point dip_point_win32
=
393 gfx::ToCeiledPoint(gfx::ScalePoint(scaled_point_metro
,
394 1.0 / win32_dpi_scale_
));
395 x_
= dip_point_win32
.x();
396 y_
= dip_point_win32
.y();
398 pointer_point_
->get_Timestamp(×tamp_
);
399 pointer_point_
->get_PointerId(&pointer_id_
);
400 // Map the OS touch event id to a range allowed by the gesture recognizer.
402 pointer_id_
%= ui::MotionEvent::MAX_TOUCH_POINT_COUNT
;
404 boolean left_button_state
;
405 hr
= properties
->get_IsLeftButtonPressed(&left_button_state
);
408 if (left_button_state
)
409 mouse_down_flags_
|= ui::EF_LEFT_MOUSE_BUTTON
;
411 boolean right_button_state
;
412 hr
= properties
->get_IsRightButtonPressed(&right_button_state
);
415 if (right_button_state
)
416 mouse_down_flags_
|= ui::EF_RIGHT_MOUSE_BUTTON
;
418 boolean middle_button_state
;
419 hr
= properties
->get_IsMiddleButtonPressed(&middle_button_state
);
422 if (middle_button_state
)
423 mouse_down_flags_
|= ui::EF_MIDDLE_MOUSE_BUTTON
;
428 bool IsType(windevs::Input::PointerDeviceType type
) const {
429 mswr::ComPtr
<windevs::Input::IPointerDevice
> pointer_device
;
430 CheckHR(pointer_point_
->get_PointerDevice(&pointer_device
));
431 windevs::Input::PointerDeviceType device_type
;
432 CheckHR(pointer_device
->get_PointerDeviceType(&device_type
));
433 return (device_type
== type
);
436 bool IsMouse() const {
437 return IsType(windevs::Input::PointerDeviceType_Mouse
);
440 bool IsTouch() const {
441 return IsType(windevs::Input::PointerDeviceType_Touch
);
444 int32
wheel_delta() const {
448 // Identifies the button that changed.
449 ui::EventFlags
changed_button() const {
450 switch (update_kind_
) {
451 case winui::Input::PointerUpdateKind_LeftButtonPressed
:
452 return ui::EF_LEFT_MOUSE_BUTTON
;
453 case winui::Input::PointerUpdateKind_LeftButtonReleased
:
454 return ui::EF_LEFT_MOUSE_BUTTON
;
455 case winui::Input::PointerUpdateKind_RightButtonPressed
:
456 return ui::EF_RIGHT_MOUSE_BUTTON
;
457 case winui::Input::PointerUpdateKind_RightButtonReleased
:
458 return ui::EF_RIGHT_MOUSE_BUTTON
;
459 case winui::Input::PointerUpdateKind_MiddleButtonPressed
:
460 return ui::EF_MIDDLE_MOUSE_BUTTON
;
461 case winui::Input::PointerUpdateKind_MiddleButtonReleased
:
462 return ui::EF_MIDDLE_MOUSE_BUTTON
;
468 uint32
mouse_down_flags() const { return mouse_down_flags_
; }
470 int x() const { return x_
; }
471 int y() const { return y_
; }
473 uint32
pointer_id() const {
477 uint64
timestamp() const { return timestamp_
; }
479 winui::Input::PointerUpdateKind
update_kind() const { return update_kind_
; }
481 bool is_horizontal_wheel() const { return !!is_horizontal_wheel_
; }
488 winui::Input::PointerUpdateKind update_kind_
;
489 mswr::ComPtr
<winui::Input::IPointerPoint
> pointer_point_
;
492 // Bitmask of ui::EventFlags corresponding to the buttons that are currently
494 uint32 mouse_down_flags_
;
496 // Set to true for a horizontal wheel message.
497 boolean is_horizontal_wheel_
;
499 // The metro device scale factor as reported by the winrt interfaces.
500 float metro_dpi_scale_
;
501 // The win32 dpi scale which is queried via GetDeviceCaps. Please refer to
502 // ui/gfx/win/dpi.cc for more information.
503 float win32_dpi_scale_
;
505 DISALLOW_COPY_AND_ASSIGN(PointerInfoHandler
);
508 ChromeAppViewAsh::ChromeAppViewAsh()
509 : mouse_down_flags_(ui::EF_NONE
),
510 ui_channel_(nullptr),
511 core_window_hwnd_(NULL
),
515 channel_listener_(NULL
) {
516 DVLOG(1) << __FUNCTION__
;
517 globals
.previous_state
=
518 winapp::Activation::ApplicationExecutionState_NotRunning
;
521 ChromeAppViewAsh::~ChromeAppViewAsh() {
522 DVLOG(1) << __FUNCTION__
;
526 ChromeAppViewAsh::Initialize(winapp::Core::ICoreApplicationView
* view
) {
528 DVLOG(1) << __FUNCTION__
;
529 HRESULT hr
= view_
->add_Activated(mswr::Callback
<ActivatedHandler
>(
530 this, &ChromeAppViewAsh::OnActivate
).Get(),
537 ChromeAppViewAsh::SetWindow(winui::Core::ICoreWindow
* window
) {
539 DVLOG(1) << __FUNCTION__
;
541 // Retrieve the native window handle via the interop layer.
542 mswr::ComPtr
<ICoreWindowInterop
> interop
;
543 HRESULT hr
= window
->QueryInterface(interop
.GetAddressOf());
545 hr
= interop
->get_WindowHandle(&core_window_hwnd_
);
548 text_service_
= metro_driver::CreateTextService(this, core_window_hwnd_
);
550 hr
= window_
->add_SizeChanged(mswr::Callback
<SizeChangedHandler
>(
551 this, &ChromeAppViewAsh::OnSizeChanged
).Get(),
555 // Register for pointer and keyboard notifications. We forward
556 // them to the browser process via IPC.
557 hr
= window_
->add_PointerMoved(mswr::Callback
<PointerEventHandler
>(
558 this, &ChromeAppViewAsh::OnPointerMoved
).Get(),
559 &pointermoved_token_
);
562 hr
= window_
->add_PointerPressed(mswr::Callback
<PointerEventHandler
>(
563 this, &ChromeAppViewAsh::OnPointerPressed
).Get(),
564 &pointerpressed_token_
);
567 hr
= window_
->add_PointerReleased(mswr::Callback
<PointerEventHandler
>(
568 this, &ChromeAppViewAsh::OnPointerReleased
).Get(),
569 &pointerreleased_token_
);
572 hr
= window_
->add_KeyDown(mswr::Callback
<KeyEventHandler
>(
573 this, &ChromeAppViewAsh::OnKeyDown
).Get(),
577 hr
= window_
->add_KeyUp(mswr::Callback
<KeyEventHandler
>(
578 this, &ChromeAppViewAsh::OnKeyUp
).Get(),
582 mswr::ComPtr
<winui::Core::ICoreDispatcher
> dispatcher
;
583 hr
= window_
->get_Dispatcher(dispatcher
.GetAddressOf());
584 CheckHR(hr
, "Get Dispatcher failed.");
586 mswr::ComPtr
<winui::Core::ICoreAcceleratorKeys
> accelerator_keys
;
587 hr
= dispatcher
.CopyTo(__uuidof(winui::Core::ICoreAcceleratorKeys
),
588 reinterpret_cast<void**>(
589 accelerator_keys
.GetAddressOf()));
590 CheckHR(hr
, "QI for ICoreAcceleratorKeys failed.");
591 hr
= accelerator_keys
->add_AcceleratorKeyActivated(
592 mswr::Callback
<AcceleratorKeyEventHandler
>(
593 this, &ChromeAppViewAsh::OnAcceleratorKeyDown
).Get(),
594 &accel_keydown_token_
);
597 hr
= window_
->add_PointerWheelChanged(mswr::Callback
<PointerEventHandler
>(
598 this, &ChromeAppViewAsh::OnWheel
).Get(),
602 hr
= window_
->add_CharacterReceived(mswr::Callback
<CharEventHandler
>(
603 this, &ChromeAppViewAsh::OnCharacterReceived
).Get(),
604 &character_received_token_
);
607 hr
= window_
->add_Activated(mswr::Callback
<WindowActivatedHandler
>(
608 this, &ChromeAppViewAsh::OnWindowActivated
).Get(),
609 &window_activated_token_
);
612 if (base::win::GetVersion() >= base::win::VERSION_WIN8
) {
613 // Register for edge gesture notifications only for Windows 8 and above.
614 mswr::ComPtr
<winui::Input::IEdgeGestureStatics
> edge_gesture_statics
;
615 hr
= winrt_utils::CreateActivationFactory(
616 RuntimeClass_Windows_UI_Input_EdgeGesture
,
617 edge_gesture_statics
.GetAddressOf());
620 mswr::ComPtr
<winui::Input::IEdgeGesture
> edge_gesture
;
621 hr
= edge_gesture_statics
->GetForCurrentView(&edge_gesture
);
624 hr
= edge_gesture
->add_Completed(mswr::Callback
<EdgeEventHandler
>(
625 this, &ChromeAppViewAsh::OnEdgeGestureCompleted
).Get(),
630 // By initializing the direct 3D swap chain with the corewindow
631 // we can now directly blit to it from the browser process.
632 direct3d_helper_
.Initialize(window
);
633 DVLOG(1) << "Initialized Direct3D.";
635 // On Windows 8+ the WinRT interface IDisplayProperties which we use to get
636 // device scale factor does not return the correct values in metro mode.
637 // To workaround this we retrieve the device scale factor via the win32 way
638 // and scale input coordinates accordingly to pass them in DIP to chrome.
639 // TODO(ananta). Investigate and fix.
640 metro_dpi_scale_
= GetModernUIScale();
641 win32_dpi_scale_
= gfx::GetDPIScale();
642 DVLOG(1) << "Metro Scale is " << metro_dpi_scale_
;
643 DVLOG(1) << "Win32 Scale is " << win32_dpi_scale_
;
648 ChromeAppViewAsh::Load(HSTRING entryPoint
) {
649 // On Win7 |entryPoint| is NULL.
650 DVLOG(1) << __FUNCTION__
;
655 ChromeAppViewAsh::Run() {
656 DVLOG(1) << __FUNCTION__
;
657 mswr::ComPtr
<winui::Core::ICoreDispatcher
> dispatcher
;
658 HRESULT hr
= window_
->get_Dispatcher(dispatcher
.GetAddressOf());
659 CheckHR(hr
, "Dispatcher failed.");
661 // Create the IPC channel IO thread. It needs to out-live the ChannelProxy.
662 io_thread_
.reset(new base::Thread("metro_IO_thread"));
663 base::Thread::Options options
;
664 options
.message_loop_type
= base::MessageLoop::TYPE_IO
;
665 io_thread_
->StartWithOptions(options
);
667 ChromeChannelListener
ui_channel_listener(&ui_loop_
, this);
668 channel_listener_
= &ui_channel_listener
;
670 // We can't do anything until the Chrome browser IPC channel is initialized.
671 // Lazy initialization in a timer.
672 ui_loop_
.PostDelayedTask(FROM_HERE
,
673 base::Bind(base::IgnoreResult(&ChromeAppViewAsh::StartChromeOSMode
),
674 base::Unretained(this)),
675 base::TimeDelta::FromMilliseconds(kChromeChannelPollTimerMs
));
677 // Post the task that'll do the inner Metro message pumping to it.
678 ui_loop_
.PostTask(FROM_HERE
, base::Bind(&RunMessageLoop
, dispatcher
.Get()));
681 io_thread_
.reset(NULL
);
682 ui_channel_
.reset(NULL
);
683 channel_listener_
= NULL
;
685 DVLOG(0) << "ProcessEvents done, hr=" << hr
;
690 ChromeAppViewAsh::Uninitialize() {
691 DVLOG(1) << __FUNCTION__
;
692 metro_driver::RemoveImePopupObserver(this);
693 input_source_
.reset();
694 text_service_
.reset();
697 core_window_hwnd_
= NULL
;
702 HRESULT
ChromeAppViewAsh::Unsnap() {
703 mswr::ComPtr
<winui::ViewManagement::IApplicationViewStatics
> view_statics
;
704 HRESULT hr
= winrt_utils::CreateActivationFactory(
705 RuntimeClass_Windows_UI_ViewManagement_ApplicationView
,
706 view_statics
.GetAddressOf());
709 winui::ViewManagement::ApplicationViewState state
=
710 winui::ViewManagement::ApplicationViewState_FullScreenLandscape
;
711 hr
= view_statics
->get_Value(&state
);
714 if (state
== winui::ViewManagement::ApplicationViewState_Snapped
) {
715 boolean success
= FALSE
;
716 hr
= view_statics
->TryUnsnap(&success
);
718 if (FAILED(hr
) || !success
) {
719 LOG(ERROR
) << "Failed to unsnap. Error 0x" << hr
;
727 void ChromeAppViewAsh::OnActivateDesktop(const base::FilePath
& file_path
,
729 DVLOG(1) << "ChannelAppViewAsh::OnActivateDesktop\n";
732 // As we are the top level window, the exiting is done async so we manage
733 // to execute the entire function including the final Send().
734 OnMetroExit(TERMINATE_USING_KEY_SEQUENCE
);
737 // We are just executing delegate_execute here without parameters. Assumption
738 // here is that this process will be reused by shell when asking for
739 // IExecuteCommand interface.
741 // TODO(shrikant): Consolidate ShellExecuteEx with SEE_MASK_FLAG_LOG_USAGE
742 // and place it metro.h or similar accessible file from all code code paths
743 // using this function.
744 SHELLEXECUTEINFO sei
= { sizeof(sei
) };
745 sei
.fMask
= SEE_MASK_FLAG_LOG_USAGE
;
746 sei
.nShow
= SW_SHOWNORMAL
;
747 sei
.lpFile
= file_path
.value().c_str();
748 sei
.lpParameters
= NULL
;
750 sei
.fMask
|= SEE_MASK_NOCLOSEPROCESS
;
751 ::ShellExecuteExW(&sei
);
753 ::TerminateProcess(sei
.hProcess
, 0);
754 ::CloseHandle(sei
.hProcess
);
758 void ChromeAppViewAsh::OnOpenURLOnDesktop(const base::FilePath
& shortcut
,
759 const base::string16
& url
) {
760 base::FilePath::StringType file
= shortcut
.value();
761 SHELLEXECUTEINFO sei
= { sizeof(sei
) };
762 sei
.fMask
= SEE_MASK_FLAG_LOG_USAGE
;
763 sei
.nShow
= SW_SHOWNORMAL
;
764 sei
.lpFile
= file
.c_str();
765 sei
.lpDirectory
= L
"";
766 sei
.lpParameters
= url
.c_str();
767 ShellExecuteEx(&sei
);
770 void ChromeAppViewAsh::OnSetCursor(HCURSOR cursor
) {
772 last_cursor_
= cursor
;
775 void ChromeAppViewAsh::OnDisplayFileOpenDialog(
776 const base::string16
& title
,
777 const base::string16
& filter
,
778 const base::FilePath
& default_path
,
779 bool allow_multiple_files
) {
780 DVLOG(1) << __FUNCTION__
;
782 // The OpenFilePickerSession instance is deleted when we receive a
783 // callback from the OpenFilePickerSession class about the completion of the
785 FilePickerSessionBase
* file_picker_
=
786 new OpenFilePickerSession(this,
790 allow_multiple_files
);
794 void ChromeAppViewAsh::OnDisplayFileSaveAsDialog(
795 const MetroViewerHostMsg_SaveAsDialogParams
& params
) {
796 DVLOG(1) << __FUNCTION__
;
798 // The SaveFilePickerSession instance is deleted when we receive a
799 // callback from the SaveFilePickerSession class about the completion of the
801 FilePickerSessionBase
* file_picker_
=
802 new SaveFilePickerSession(this, params
);
806 void ChromeAppViewAsh::OnDisplayFolderPicker(const base::string16
& title
) {
807 DVLOG(1) << __FUNCTION__
;
808 // The FolderPickerSession instance is deleted when we receive a
809 // callback from the FolderPickerSession class about the completion of the
811 FilePickerSessionBase
* file_picker_
= new FolderPickerSession(this, title
);
815 void ChromeAppViewAsh::OnSetCursorPos(int x
, int y
) {
817 ::SetCursorPos(x
, y
);
818 DVLOG(1) << "In UI OnSetCursorPos: " << x
<< ", " << y
;
819 ui_channel_
->Send(new MetroViewerHostMsg_SetCursorPosAck());
820 // Generate a fake mouse move which matches the SetCursor coordinates as
821 // the browser expects to receive a mouse move for these coordinates.
822 // It is not clear why we don't receive a real mouse move in response to
823 // the SetCursorPos calll above.
824 ui_channel_
->Send(new MetroViewerHostMsg_MouseMoved(x
, y
, 0));
828 void ChromeAppViewAsh::OnOpenFileCompleted(
829 OpenFilePickerSession
* open_file_picker
,
831 DVLOG(1) << __FUNCTION__
;
832 DVLOG(1) << "Success: " << success
;
834 if (open_file_picker
->allow_multi_select()) {
835 ui_channel_
->Send(new MetroViewerHostMsg_MultiFileOpenDone(
836 success
, open_file_picker
->filenames()));
838 ui_channel_
->Send(new MetroViewerHostMsg_FileOpenDone(
839 success
, base::FilePath(open_file_picker
->result())));
842 delete open_file_picker
;
845 void ChromeAppViewAsh::OnSaveFileCompleted(
846 SaveFilePickerSession
* save_file_picker
,
848 DVLOG(1) << __FUNCTION__
;
849 DVLOG(1) << "Success: " << success
;
851 ui_channel_
->Send(new MetroViewerHostMsg_FileSaveAsDone(
853 base::FilePath(save_file_picker
->result()),
854 save_file_picker
->filter_index()));
856 delete save_file_picker
;
859 void ChromeAppViewAsh::OnFolderPickerCompleted(
860 FolderPickerSession
* folder_picker
,
862 DVLOG(1) << __FUNCTION__
;
863 DVLOG(1) << "Success: " << success
;
865 ui_channel_
->Send(new MetroViewerHostMsg_SelectFolderDone(
867 base::FilePath(folder_picker
->result())));
869 delete folder_picker
;
872 void ChromeAppViewAsh::OnImeCancelComposition() {
875 text_service_
->CancelComposition();
878 void ChromeAppViewAsh::OnImeUpdateTextInputClient(
879 const std::vector
<int32
>& input_scopes
,
880 const std::vector
<metro_viewer::CharacterBounds
>& character_bounds
) {
883 text_service_
->OnDocumentChanged(input_scopes
, character_bounds
);
886 void ChromeAppViewAsh::OnImePopupChanged(ImePopupObserver::EventType event
) {
890 case ImePopupObserver::kPopupShown
:
891 ui_channel_
->Send(new MetroViewerHostMsg_ImeCandidatePopupChanged(true));
893 case ImePopupObserver::kPopupHidden
:
894 ui_channel_
->Send(new MetroViewerHostMsg_ImeCandidatePopupChanged(false));
896 case ImePopupObserver::kPopupUpdated
:
897 // TODO(kochi): Support this event for W3C IME API proposal.
898 // See crbug.com/238585.
901 NOTREACHED() << "unknown event type: " << event
;
906 // Function to Exit metro chrome cleanly. If we are in the foreground
907 // then we try and exit by sending an Alt+F4 key combination to the core
908 // window which ensures that the chrome application tile does not show up in
909 // the running metro apps list on the top left corner.
910 void ChromeAppViewAsh::OnMetroExit(MetroTerminateMethod method
) {
911 if (base::win::GetVersion() >= base::win::VERSION_WIN8
) {
912 HWND core_window
= core_window_hwnd();
913 if (method
== TERMINATE_USING_KEY_SEQUENCE
&& core_window
!= NULL
&&
914 core_window
== ::GetForegroundWindow()) {
915 DVLOG(1) << "We are in the foreground. Exiting via Alt F4";
916 SendKeySequence(VK_F4
, ALT
);
918 ui_channel_
->Close();
920 globals
.app_exit
->Exit();
924 ui_channel_
->Close();
926 HWND core_window
= core_window_hwnd();
927 ::PostMessage(core_window
, WM_CLOSE
, 0, 0);
929 globals
.app_exit
->Exit();
933 void ChromeAppViewAsh::OnInputSourceChanged() {
941 if (!input_source_
->GetActiveSource(&langid
, &is_ime
)) {
942 LOG(ERROR
) << "GetActiveSource failed";
945 ui_channel_
->Send(new MetroViewerHostMsg_ImeInputSourceChanged(langid
,
949 void ChromeAppViewAsh::OnCompositionChanged(
950 const base::string16
& text
,
951 int32 selection_start
,
953 const std::vector
<metro_viewer::UnderlineInfo
>& underlines
) {
954 ui_channel_
->Send(new MetroViewerHostMsg_ImeCompositionChanged(
955 text
, selection_start
, selection_end
, underlines
));
958 void ChromeAppViewAsh::OnTextCommitted(const base::string16
& text
) {
959 ui_channel_
->Send(new MetroViewerHostMsg_ImeTextCommitted(text
));
962 void ChromeAppViewAsh::SendMouseButton(int x
,
965 ui::EventType event_type
,
967 ui::EventFlags changed_button
,
968 bool is_horizontal_wheel
) {
971 MetroViewerHostMsg_MouseButtonParams params
;
972 params
.x
= static_cast<int32
>(x
);
973 params
.y
= static_cast<int32
>(y
);
974 params
.extra
= static_cast<int32
>(extra
);
975 params
.event_type
= event_type
;
976 params
.flags
= static_cast<int32
>(flags
);
977 params
.changed_button
= changed_button
;
978 params
.is_horizontal_wheel
= is_horizontal_wheel
;
979 ui_channel_
->Send(new MetroViewerHostMsg_MouseButton(params
));
982 void ChromeAppViewAsh::GenerateMouseEventFromMoveIfNecessary(
983 const PointerInfoHandler
& pointer
) {
984 ui::EventType event_type
;
985 // For aura we want the flags to include the button that was released, thus
986 // we or the old and new.
987 uint32 mouse_down_flags
= pointer
.mouse_down_flags() | mouse_down_flags_
;
988 mouse_down_flags_
= pointer
.mouse_down_flags();
989 switch (pointer
.update_kind()) {
990 case winui::Input::PointerUpdateKind_LeftButtonPressed
:
991 case winui::Input::PointerUpdateKind_RightButtonPressed
:
992 case winui::Input::PointerUpdateKind_MiddleButtonPressed
:
993 event_type
= ui::ET_MOUSE_PRESSED
;
995 case winui::Input::PointerUpdateKind_LeftButtonReleased
:
996 case winui::Input::PointerUpdateKind_RightButtonReleased
:
997 case winui::Input::PointerUpdateKind_MiddleButtonReleased
:
998 event_type
= ui::ET_MOUSE_RELEASED
;
1003 SendMouseButton(pointer
.x(), pointer
.y(), 0, event_type
,
1004 mouse_down_flags
| GetKeyboardEventFlags(),
1005 pointer
.changed_button(), pointer
.is_horizontal_wheel());
1008 HRESULT
ChromeAppViewAsh::OnActivate(
1009 winapp::Core::ICoreApplicationView
*,
1010 winapp::Activation::IActivatedEventArgs
* args
) {
1011 DVLOG(1) << __FUNCTION__
;
1012 // Note: If doing more work in this function, you migth need to call
1013 // get_PreviousExecutionState() and skip the work if the result is
1014 // ApplicationExecutionState_Running and globals.previous_state is too.
1015 args
->get_PreviousExecutionState(&globals
.previous_state
);
1016 DVLOG(1) << "Previous Execution State: " << globals
.previous_state
;
1018 winapp::Activation::ActivationKind activation_kind
;
1019 CheckHR(args
->get_Kind(&activation_kind
));
1020 DVLOG(1) << "Activation kind: " << activation_kind
;
1022 if (activation_kind
== winapp::Activation::ActivationKind_Search
)
1023 HandleSearchRequest(args
);
1024 else if (activation_kind
== winapp::Activation::ActivationKind_Protocol
)
1025 HandleProtocolRequest(args
);
1027 LaunchChromeBrowserProcess(NULL
, args
);
1028 // We call ICoreWindow::Activate after the handling for the search/protocol
1029 // requests because Chrome can be launched to handle a search request which
1030 // in turn launches the chrome browser process in desktop mode via
1031 // ShellExecute. If we call ICoreWindow::Activate before this, then
1032 // Windows kills the metro chrome process when it calls ShellExecute. Seems
1034 window_
->Activate();
1038 HRESULT
ChromeAppViewAsh::OnPointerMoved(winui::Core::ICoreWindow
* sender
,
1039 winui::Core::IPointerEventArgs
* args
) {
1043 PointerInfoHandler
pointer(metro_dpi_scale_
, win32_dpi_scale_
);
1044 HRESULT hr
= pointer
.Init(args
);
1048 if (pointer
.IsMouse()) {
1049 // If the mouse was moved towards the charms or the OS specific section,
1050 // the cursor may change from what the browser last set. Restore it here.
1051 if (::GetCursor() != last_cursor_
)
1052 SetCursor(last_cursor_
);
1054 GenerateMouseEventFromMoveIfNecessary(pointer
);
1055 ui_channel_
->Send(new MetroViewerHostMsg_MouseMoved(
1058 mouse_down_flags_
| GetKeyboardEventFlags()));
1060 DCHECK(pointer
.IsTouch());
1061 ui_channel_
->Send(new MetroViewerHostMsg_TouchMoved(pointer
.x(),
1063 pointer
.timestamp(),
1064 pointer
.pointer_id()));
1069 // NOTE: From experimentation, it seems like Metro only sends a PointerPressed
1070 // event for the first button pressed and the last button released in a sequence
1072 // For example, a sequence of LEFT_DOWN, RIGHT_DOWN, LEFT_UP, RIGHT_UP results
1073 // only in PointerPressed(LEFT)/PointerReleased(RIGHT) events. Intermediary
1074 // presses and releases are tracked in OnPointMoved().
1075 HRESULT
ChromeAppViewAsh::OnPointerPressed(
1076 winui::Core::ICoreWindow
* sender
,
1077 winui::Core::IPointerEventArgs
* args
) {
1081 PointerInfoHandler
pointer(metro_dpi_scale_
, win32_dpi_scale_
);
1082 HRESULT hr
= pointer
.Init(args
);
1086 if (pointer
.IsMouse()) {
1087 mouse_down_flags_
= pointer
.mouse_down_flags();
1088 SendMouseButton(pointer
.x(), pointer
.y(), 0, ui::ET_MOUSE_PRESSED
,
1089 mouse_down_flags_
| GetKeyboardEventFlags(),
1090 pointer
.changed_button(), pointer
.is_horizontal_wheel());
1092 DCHECK(pointer
.IsTouch());
1093 ui_channel_
->Send(new MetroViewerHostMsg_TouchDown(pointer
.x(),
1095 pointer
.timestamp(),
1096 pointer
.pointer_id()));
1101 HRESULT
ChromeAppViewAsh::OnPointerReleased(
1102 winui::Core::ICoreWindow
* sender
,
1103 winui::Core::IPointerEventArgs
* args
) {
1107 PointerInfoHandler
pointer(metro_dpi_scale_
, win32_dpi_scale_
);
1108 HRESULT hr
= pointer
.Init(args
);
1112 if (pointer
.IsMouse()) {
1113 mouse_down_flags_
= ui::EF_NONE
;
1114 SendMouseButton(pointer
.x(), pointer
.y(), 0, ui::ET_MOUSE_RELEASED
,
1115 static_cast<uint32
>(pointer
.changed_button()) |
1116 GetKeyboardEventFlags(),
1117 pointer
.changed_button(),
1118 pointer
.is_horizontal_wheel());
1120 DCHECK(pointer
.IsTouch());
1121 ui_channel_
->Send(new MetroViewerHostMsg_TouchUp(pointer
.x(),
1123 pointer
.timestamp(),
1124 pointer
.pointer_id()));
1129 HRESULT
ChromeAppViewAsh::OnWheel(
1130 winui::Core::ICoreWindow
* sender
,
1131 winui::Core::IPointerEventArgs
* args
) {
1135 PointerInfoHandler
pointer(metro_dpi_scale_
, win32_dpi_scale_
);
1136 HRESULT hr
= pointer
.Init(args
);
1139 DCHECK(pointer
.IsMouse());
1140 SendMouseButton(pointer
.x(), pointer
.y(), pointer
.wheel_delta(),
1141 ui::ET_MOUSEWHEEL
, GetKeyboardEventFlags(), ui::EF_NONE
,
1142 pointer
.is_horizontal_wheel());
1146 HRESULT
ChromeAppViewAsh::OnKeyDown(
1147 winui::Core::ICoreWindow
* sender
,
1148 winui::Core::IKeyEventArgs
* args
) {
1152 winsys::VirtualKey virtual_key
;
1153 HRESULT hr
= args
->get_VirtualKey(&virtual_key
);
1156 winui::Core::CorePhysicalKeyStatus status
;
1157 hr
= args
->get_KeyStatus(&status
);
1161 ui_channel_
->Send(new MetroViewerHostMsg_KeyDown(virtual_key
,
1164 GetKeyboardEventFlags()));
1168 HRESULT
ChromeAppViewAsh::OnKeyUp(
1169 winui::Core::ICoreWindow
* sender
,
1170 winui::Core::IKeyEventArgs
* args
) {
1174 winsys::VirtualKey virtual_key
;
1175 HRESULT hr
= args
->get_VirtualKey(&virtual_key
);
1178 winui::Core::CorePhysicalKeyStatus status
;
1179 hr
= args
->get_KeyStatus(&status
);
1183 ui_channel_
->Send(new MetroViewerHostMsg_KeyUp(virtual_key
,
1186 GetKeyboardEventFlags()));
1190 HRESULT
ChromeAppViewAsh::OnAcceleratorKeyDown(
1191 winui::Core::ICoreDispatcher
* sender
,
1192 winui::Core::IAcceleratorKeyEventArgs
* args
) {
1196 winsys::VirtualKey virtual_key
;
1197 HRESULT hr
= args
->get_VirtualKey(&virtual_key
);
1200 winui::Core::CorePhysicalKeyStatus status
;
1201 hr
= args
->get_KeyStatus(&status
);
1205 winui::Core::CoreAcceleratorKeyEventType event_type
;
1206 hr
= args
->get_EventType(&event_type
);
1210 uint32 keyboard_flags
= GetKeyboardEventFlags();
1212 switch (event_type
) {
1213 case winui::Core::CoreAcceleratorKeyEventType_SystemCharacter
:
1214 ui_channel_
->Send(new MetroViewerHostMsg_Character(virtual_key
,
1220 case winui::Core::CoreAcceleratorKeyEventType_SystemKeyDown
:
1221 // Don't send the Alt + F4 combination to Chrome as this is intended to
1222 // shut the metro environment down. Reason we check for Control here is
1223 // Windows does not shutdown metro if Ctrl is pressed along with Alt F4.
1224 // Other key combinations with Alt F4 shutdown metro.
1225 if ((virtual_key
== VK_F4
) && ((keyboard_flags
& ui::EF_ALT_DOWN
) &&
1226 !(keyboard_flags
& ui::EF_CONTROL_DOWN
)))
1228 // Don't send the EF_ALT_DOWN modifier along with the IPC message for
1229 // the Alt or F10 key. The accelerator for VKEY_MENU is registered
1230 // without modifiers in Chrome for historical reasons. Not sending the
1231 // EF_ALT_DOWN modifier ensures that the accelerator is processed
1233 if (virtual_key
== winsys::VirtualKey_Menu
)
1234 keyboard_flags
&= ~ui::EF_ALT_DOWN
;
1235 ui_channel_
->Send(new MetroViewerHostMsg_KeyDown(virtual_key
,
1241 case winui::Core::CoreAcceleratorKeyEventType_SystemKeyUp
:
1242 ui_channel_
->Send(new MetroViewerHostMsg_KeyUp(virtual_key
,
1254 HRESULT
ChromeAppViewAsh::OnCharacterReceived(
1255 winui::Core::ICoreWindow
* sender
,
1256 winui::Core::ICharacterReceivedEventArgs
* args
) {
1260 unsigned int char_code
= 0;
1261 HRESULT hr
= args
->get_KeyCode(&char_code
);
1265 winui::Core::CorePhysicalKeyStatus status
;
1266 hr
= args
->get_KeyStatus(&status
);
1270 ui_channel_
->Send(new MetroViewerHostMsg_Character(char_code
,
1273 GetKeyboardEventFlags()));
1277 HRESULT
ChromeAppViewAsh::OnWindowActivated(
1278 winui::Core::ICoreWindow
* sender
,
1279 winui::Core::IWindowActivatedEventArgs
* args
) {
1284 winui::Core::CoreWindowActivationState state
;
1285 HRESULT hr
= args
->get_WindowActivationState(&state
);
1289 // Treat both full activation (Ash was reopened from the Start Screen or
1290 // from any other Metro entry point in Windows) and pointer activation
1291 // (user clicked back in Ash after using another app on another monitor)
1293 if (state
== winui::Core::CoreWindowActivationState_CodeActivated
||
1294 state
== winui::Core::CoreWindowActivationState_PointerActivated
) {
1295 ui_channel_
->Send(new MetroViewerHostMsg_WindowActivated(false));
1298 // On Windows 7, we force a repaint when the window is activated.
1299 ui_channel_
->Send(new MetroViewerHostMsg_WindowActivated(true));
1302 text_service_
->OnWindowActivated();
1306 HRESULT
ChromeAppViewAsh::HandleSearchRequest(
1307 winapp::Activation::IActivatedEventArgs
* args
) {
1308 mswr::ComPtr
<winapp::Activation::ISearchActivatedEventArgs
> search_args
;
1309 CheckHR(args
->QueryInterface(
1310 winapp::Activation::IID_ISearchActivatedEventArgs
, &search_args
));
1313 DVLOG(1) << "Launched to handle search request";
1314 LaunchChromeBrowserProcess(L
"--windows8-search", args
);
1317 mswrw::HString search_string
;
1318 CheckHR(search_args
->get_QueryText(search_string
.GetAddressOf()));
1319 base::string16
search_text(MakeStdWString(search_string
.Get()));
1321 ui_loop_
.PostTask(FROM_HERE
,
1322 base::Bind(&ChromeAppViewAsh::OnSearchRequest
,
1323 base::Unretained(this),
1328 HRESULT
ChromeAppViewAsh::HandleProtocolRequest(
1329 winapp::Activation::IActivatedEventArgs
* args
) {
1330 DVLOG(1) << __FUNCTION__
;
1332 DVLOG(1) << "Launched to handle url request";
1334 mswr::ComPtr
<winapp::Activation::IProtocolActivatedEventArgs
>
1336 CheckHR(args
->QueryInterface(
1337 winapp::Activation::IID_IProtocolActivatedEventArgs
,
1340 mswr::ComPtr
<winfoundtn::IUriRuntimeClass
> uri
;
1341 protocol_args
->get_Uri(&uri
);
1343 uri
->get_AbsoluteUri(url
.GetAddressOf());
1344 base::string16
actual_url(MakeStdWString(url
.Get()));
1345 DVLOG(1) << "Received url request: " << actual_url
;
1347 ui_loop_
.PostTask(FROM_HERE
,
1348 base::Bind(&ChromeAppViewAsh::OnNavigateToUrl
,
1349 base::Unretained(this),
1354 HRESULT
ChromeAppViewAsh::OnEdgeGestureCompleted(
1355 winui::Input::IEdgeGesture
* gesture
,
1356 winui::Input::IEdgeGestureEventArgs
* args
) {
1358 ui_channel_
->Send(new MetroViewerHostMsg_EdgeGesture());
1362 void ChromeAppViewAsh::OnSearchRequest(const base::string16
& search_string
) {
1364 ui_channel_
->Send(new MetroViewerHostMsg_SearchRequest(search_string
));
1367 void ChromeAppViewAsh::OnNavigateToUrl(const base::string16
& url
) {
1369 ui_channel_
->Send(new MetroViewerHostMsg_OpenURL(url
));
1372 HRESULT
ChromeAppViewAsh::OnSizeChanged(winui::Core::ICoreWindow
* sender
,
1373 winui::Core::IWindowSizeChangedEventArgs
* args
) {
1374 if (!window_
|| !ui_channel_
) {
1378 // winui::Core::IWindowSizeChangedEventArgs args->Size appears to return
1379 // scaled values under HiDPI. We will instead use GetWindowRect() which
1380 // should always return values in Pixels.
1382 ::GetWindowRect(core_window_hwnd_
, &rect
);
1384 uint32 cx
= static_cast<uint32
>(rect
.right
- rect
.left
);
1385 uint32 cy
= static_cast<uint32
>(rect
.bottom
- rect
.top
);
1387 DVLOG(1) << "Window size changed: width=" << cx
<< ", height=" << cy
;
1388 ui_channel_
->Send(new MetroViewerHostMsg_WindowSizeChanged(cx
, cy
));
1392 void ChromeAppViewAsh::StartChromeOSMode() {
1393 static int ms_elapsed
= 0;
1395 if (!IPC::Channel::IsNamedServerInitialized(
1396 win8::kMetroViewerIPCChannelName
) && ms_elapsed
< 10000) {
1398 ui_loop_
.PostDelayedTask(FROM_HERE
,
1399 base::Bind(base::IgnoreResult(&ChromeAppViewAsh::StartChromeOSMode
),
1400 base::Unretained(this)),
1401 base::TimeDelta::FromMilliseconds(kChromeChannelPollTimerMs
));
1405 if (!IPC::Channel::IsNamedServerInitialized(
1406 win8::kMetroViewerIPCChannelName
)) {
1407 DVLOG(1) << "Failed to connect to chrome channel : "
1408 << win8::kMetroViewerIPCChannelName
;
1409 DVLOG(1) << "Exiting. Elapsed time :" << ms_elapsed
;
1410 PostMessage(core_window_hwnd_
, WM_CLOSE
, 0, 0);
1414 DVLOG(1) << "Found channel : " << win8::kMetroViewerIPCChannelName
;
1416 DCHECK(channel_listener_
);
1418 // In Aura mode we create an IPC channel to the browser, then ask it to
1421 IPC::ChannelProxy::Create(win8::kMetroViewerIPCChannelName
,
1422 IPC::Channel::MODE_NAMED_CLIENT
,
1424 io_thread_
->task_runner());
1425 DVLOG(1) << "Created channel proxy";
1427 // Upon receipt of the MetroViewerHostMsg_SetTargetSurface message the
1428 // browser will use D3D from the browser process to present to our Window.
1429 ui_channel_
->Send(new MetroViewerHostMsg_SetTargetSurface(
1430 gfx::NativeViewId(core_window_hwnd_
),
1432 DVLOG(1) << "ICoreWindow sent " << core_window_hwnd_
;
1434 // Send an initial size message so that the Ash root window host gets sized
1437 ::GetWindowRect(core_window_hwnd_
, &rect
);
1439 new MetroViewerHostMsg_WindowSizeChanged(rect
.right
- rect
.left
,
1440 rect
.bottom
- rect
.top
));
1442 input_source_
= metro_driver::InputSource::Create();
1443 if (input_source_
) {
1444 input_source_
->AddObserver(this);
1445 // Send an initial input source.
1446 OnInputSourceChanged();
1449 // Start receiving IME popup window notifications.
1450 metro_driver::AddImePopupObserver(this);
1452 DVLOG(1) << "Channel setup complete";
1455 ///////////////////////////////////////////////////////////////////////////////
1457 ChromeAppViewFactory::ChromeAppViewFactory(
1458 winapp::Core::ICoreApplication
* icore_app
) {
1459 mswr::ComPtr
<winapp::Core::ICoreApplication
> core_app(icore_app
);
1460 mswr::ComPtr
<winapp::Core::ICoreApplicationExit
> app_exit
;
1461 CheckHR(core_app
.As(&app_exit
));
1462 globals
.app_exit
= app_exit
.Detach();
1466 ChromeAppViewFactory::CreateView(winapp::Core::IFrameworkView
** view
) {
1467 *view
= mswr::Make
<ChromeAppViewAsh
>().Detach();
1468 return (*view
) ? S_OK
: E_OUTOFMEMORY
;