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/threading/thread.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/gestures/gesture_sequence.h"
26 #include "ui/metro_viewer/metro_viewer_messages.h"
27 #include "win8/metro_driver/file_picker_ash.h"
28 #include "win8/metro_driver/ime/ime_popup_monitor.h"
29 #include "win8/metro_driver/ime/input_source.h"
30 #include "win8/metro_driver/ime/text_service.h"
31 #include "win8/metro_driver/metro_driver.h"
32 #include "win8/metro_driver/winrt_utils.h"
33 #include "win8/viewer/metro_viewer_constants.h"
35 typedef winfoundtn::ITypedEventHandler
<
36 winapp::Core::CoreApplicationView
*,
37 winapp::Activation::IActivatedEventArgs
*> ActivatedHandler
;
39 typedef winfoundtn::ITypedEventHandler
<
40 winui::Core::CoreWindow
*,
41 winui::Core::PointerEventArgs
*> PointerEventHandler
;
43 typedef winfoundtn::ITypedEventHandler
<
44 winui::Core::CoreWindow
*,
45 winui::Core::KeyEventArgs
*> KeyEventHandler
;
47 typedef winfoundtn::ITypedEventHandler
<
48 winui::Core::CoreDispatcher
*,
49 winui::Core::AcceleratorKeyEventArgs
*> AcceleratorKeyEventHandler
;
51 typedef winfoundtn::ITypedEventHandler
<
52 winui::Core::CoreWindow
*,
53 winui::Core::CharacterReceivedEventArgs
*> CharEventHandler
;
55 typedef winfoundtn::ITypedEventHandler
<
56 winui::Core::CoreWindow
*,
57 winui::Core::WindowActivatedEventArgs
*> WindowActivatedHandler
;
59 typedef winfoundtn::ITypedEventHandler
<
60 winui::Core::CoreWindow
*,
61 winui::Core::WindowSizeChangedEventArgs
*> SizeChangedHandler
;
63 typedef winfoundtn::ITypedEventHandler
<
64 winui::Input::EdgeGesture
*,
65 winui::Input::EdgeGestureEventArgs
*> EdgeEventHandler
;
67 // This function is exported by chrome.exe.
68 typedef int (__cdecl
*BreakpadExceptionHandler
)(EXCEPTION_POINTERS
* info
);
70 // Global information used across the metro driver.
72 winapp::Activation::ApplicationExecutionState previous_state
;
73 winapp::Core::ICoreApplicationExit
* app_exit
;
74 BreakpadExceptionHandler breakpad_exception_handler
;
86 // Helper function to send keystrokes via the SendInput function.
87 // mnemonic_char: The keystroke to be sent.
88 // modifiers: Combination with Alt, Ctrl, Shift, etc.
90 WORD mnemonic_char
, KeyModifier modifiers
) {
91 INPUT keys
[4] = {0}; // Keyboard events
92 int key_count
= 0; // Number of generated events
94 if (modifiers
& SHIFT
) {
95 keys
[key_count
].type
= INPUT_KEYBOARD
;
96 keys
[key_count
].ki
.wVk
= VK_SHIFT
;
97 keys
[key_count
].ki
.wScan
= MapVirtualKey(VK_SHIFT
, 0);
101 if (modifiers
& CONTROL
) {
102 keys
[key_count
].type
= INPUT_KEYBOARD
;
103 keys
[key_count
].ki
.wVk
= VK_CONTROL
;
104 keys
[key_count
].ki
.wScan
= MapVirtualKey(VK_CONTROL
, 0);
108 if (modifiers
& ALT
) {
109 keys
[key_count
].type
= INPUT_KEYBOARD
;
110 keys
[key_count
].ki
.wVk
= VK_MENU
;
111 keys
[key_count
].ki
.wScan
= MapVirtualKey(VK_MENU
, 0);
115 keys
[key_count
].type
= INPUT_KEYBOARD
;
116 keys
[key_count
].ki
.wVk
= mnemonic_char
;
117 keys
[key_count
].ki
.wScan
= MapVirtualKey(mnemonic_char
, 0);
120 bool should_sleep
= key_count
> 1;
123 for (int i
= 0; i
< key_count
; i
++) {
124 SendInput(1, &keys
[ i
], sizeof(keys
[0]));
125 keys
[i
].ki
.dwFlags
|= KEYEVENTF_KEYUP
;
130 // Now send key ups in reverse order.
131 for (int i
= key_count
; i
; i
--) {
132 SendInput(1, &keys
[ i
- 1 ], sizeof(keys
[0]));
138 class ChromeChannelListener
: public IPC::Listener
{
140 ChromeChannelListener(base::MessageLoop
* ui_loop
, ChromeAppViewAsh
* app_view
)
141 : ui_proxy_(ui_loop
->message_loop_proxy()),
142 app_view_(app_view
) {}
144 virtual bool OnMessageReceived(const IPC::Message
& message
) OVERRIDE
{
145 IPC_BEGIN_MESSAGE_MAP(ChromeChannelListener
, message
)
146 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ActivateDesktop
,
148 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MetroExit
, OnMetroExit
)
149 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_OpenURLOnDesktop
,
151 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursor
, OnSetCursor
)
152 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileOpen
,
153 OnDisplayFileOpenDialog
)
154 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplayFileSaveAs
,
155 OnDisplayFileSaveAsDialog
)
156 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_DisplaySelectFolder
,
157 OnDisplayFolderPicker
)
158 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursorPos
, OnSetCursorPos
)
159 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeCancelComposition
,
160 OnImeCancelComposition
)
161 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeTextInputClientUpdated
,
162 OnImeTextInputClientChanged
)
163 IPC_MESSAGE_UNHANDLED(__debugbreak())
164 IPC_END_MESSAGE_MAP()
168 virtual void OnChannelError() OVERRIDE
{
169 DVLOG(1) << "Channel error. Exiting.";
170 ui_proxy_
->PostTask(FROM_HERE
,
171 base::Bind(&ChromeAppViewAsh::OnMetroExit
, base::Unretained(app_view_
),
172 TERMINATE_USING_KEY_SEQUENCE
));
174 // In early Windows 8 versions the code above sometimes fails so we call
175 // it a second time with a NULL window which just calls Exit().
176 ui_proxy_
->PostDelayedTask(FROM_HERE
,
177 base::Bind(&ChromeAppViewAsh::OnMetroExit
, base::Unretained(app_view_
),
178 TERMINATE_USING_PROCESS_EXIT
),
179 base::TimeDelta::FromMilliseconds(100));
183 void OnActivateDesktop(const base::FilePath
& shortcut
, bool ash_exit
) {
184 ui_proxy_
->PostTask(FROM_HERE
,
185 base::Bind(&ChromeAppViewAsh::OnActivateDesktop
,
186 base::Unretained(app_view_
),
187 shortcut
, ash_exit
));
191 ui_proxy_
->PostTask(FROM_HERE
,
192 base::Bind(&ChromeAppViewAsh::OnMetroExit
,
193 base::Unretained(app_view_
), TERMINATE_USING_KEY_SEQUENCE
));
196 void OnOpenURLOnDesktop(const base::FilePath
& shortcut
,
197 const base::string16
& url
) {
198 ui_proxy_
->PostTask(FROM_HERE
,
199 base::Bind(&ChromeAppViewAsh::OnOpenURLOnDesktop
,
200 base::Unretained(app_view_
),
204 void OnSetCursor(int64 cursor
) {
205 ui_proxy_
->PostTask(FROM_HERE
,
206 base::Bind(&ChromeAppViewAsh::OnSetCursor
,
207 base::Unretained(app_view_
),
208 reinterpret_cast<HCURSOR
>(cursor
)));
211 void OnDisplayFileOpenDialog(const base::string16
& title
,
212 const base::string16
& filter
,
213 const base::FilePath
& default_path
,
214 bool allow_multiple_files
) {
215 ui_proxy_
->PostTask(FROM_HERE
,
216 base::Bind(&ChromeAppViewAsh::OnDisplayFileOpenDialog
,
217 base::Unretained(app_view_
),
221 allow_multiple_files
));
224 void OnDisplayFileSaveAsDialog(
225 const MetroViewerHostMsg_SaveAsDialogParams
& params
) {
228 base::Bind(&ChromeAppViewAsh::OnDisplayFileSaveAsDialog
,
229 base::Unretained(app_view_
),
233 void OnDisplayFolderPicker(const base::string16
& title
) {
236 base::Bind(&ChromeAppViewAsh::OnDisplayFolderPicker
,
237 base::Unretained(app_view_
),
241 void OnSetCursorPos(int x
, int y
) {
242 VLOG(1) << "In IPC OnSetCursorPos: " << x
<< ", " << y
;
245 base::Bind(&ChromeAppViewAsh::OnSetCursorPos
,
246 base::Unretained(app_view_
),
250 void OnImeCancelComposition() {
253 base::Bind(&ChromeAppViewAsh::OnImeCancelComposition
,
254 base::Unretained(app_view_
)));
257 void OnImeTextInputClientChanged(
258 const std::vector
<int32
>& input_scopes
,
259 const std::vector
<metro_viewer::CharacterBounds
>& character_bounds
) {
262 base::Bind(&ChromeAppViewAsh::OnImeUpdateTextInputClient
,
263 base::Unretained(app_view_
),
268 scoped_refptr
<base::MessageLoopProxy
> ui_proxy_
;
269 ChromeAppViewAsh
* app_view_
;
272 bool WaitForChromeIPCConnection(const std::string
& channel_name
) {
274 while (!IPC::Channel::IsNamedServerInitialized(channel_name
) &&
275 ms_elapsed
< 10000) {
279 return IPC::Channel::IsNamedServerInitialized(channel_name
);
282 void RunMessageLoop(winui::Core::ICoreDispatcher
* dispatcher
) {
283 // We're entering a nested message loop, let's allow dispatching
284 // tasks while we're in there.
285 base::MessageLoop::current()->SetNestableTasksAllowed(true);
287 // Enter main core message loop. There are several ways to exit it
289 // 1 - User action like ALT-F4.
290 // 2 - Calling ICoreApplicationExit::Exit().
291 // 3- Posting WM_CLOSE to the core window.
292 HRESULT hr
= dispatcher
->ProcessEvents(
293 winui::Core::CoreProcessEventsOption
294 ::CoreProcessEventsOption_ProcessUntilQuit
);
296 // Wind down the thread's chrome message loop.
297 base::MessageLoop::current()->Quit();
300 // Helper to return the state of the shift/control/alt keys.
301 uint32
GetKeyboardEventFlags() {
303 if (base::win::IsShiftPressed())
304 flags
|= ui::EF_SHIFT_DOWN
;
305 if (base::win::IsCtrlPressed())
306 flags
|= ui::EF_CONTROL_DOWN
;
307 if (base::win::IsAltPressed())
308 flags
|= ui::EF_ALT_DOWN
;
312 bool LaunchChromeBrowserProcess(const wchar_t* additional_parameters
,
313 winapp::Activation::IActivatedEventArgs
* args
) {
315 DVLOG(1) << __FUNCTION__
<< ":" << ::GetCommandLineW();
316 winapp::Activation::ActivationKind activation_kind
;
317 CheckHR(args
->get_Kind(&activation_kind
));
319 DVLOG(1) << __FUNCTION__
<< ", activation_kind=" << activation_kind
;
321 if (activation_kind
== winapp::Activation::ActivationKind_Launch
) {
322 mswr::ComPtr
<winapp::Activation::ILaunchActivatedEventArgs
> launch_args
;
323 if (args
->QueryInterface(
324 winapp::Activation::IID_ILaunchActivatedEventArgs
,
325 &launch_args
) == S_OK
) {
326 DVLOG(1) << "Activate: ActivationKind_Launch";
327 mswrw::HString launch_args_str
;
328 launch_args
->get_Arguments(launch_args_str
.GetAddressOf());
329 base::string16
actual_launch_args(
330 MakeStdWString(launch_args_str
.Get()));
331 if (actual_launch_args
== win8::kMetroViewerConnectVerb
) {
332 DVLOG(1) << __FUNCTION__
<< "Not launching chrome server";
339 DVLOG(1) << "Launching chrome server";
340 base::FilePath chrome_exe_path
;
342 if (!PathService::Get(base::FILE_EXE
, &chrome_exe_path
))
345 base::string16 parameters
= L
"--silent-launch --viewer-connect ";
346 if (additional_parameters
)
347 parameters
+= additional_parameters
;
349 SHELLEXECUTEINFO sei
= { sizeof(sei
) };
350 sei
.nShow
= SW_SHOWNORMAL
;
351 sei
.lpFile
= chrome_exe_path
.value().c_str();
352 sei
.lpDirectory
= L
"";
353 sei
.lpParameters
= parameters
.c_str();
354 ::ShellExecuteEx(&sei
);
360 // This class helps decoding the pointer properties of an event.
361 class ChromeAppViewAsh::PointerInfoHandler
{
367 update_kind_(winui::Input::PointerUpdateKind_Other
),
370 mouse_down_flags_(0),
371 is_horizontal_wheel_(0) {}
373 HRESULT
Init(winui::Core::IPointerEventArgs
* args
) {
374 HRESULT hr
= args
->get_CurrentPoint(&pointer_point_
);
378 winfoundtn::Point point
;
379 hr
= pointer_point_
->get_Position(&point
);
383 mswr::ComPtr
<winui::Input::IPointerPointProperties
> properties
;
384 hr
= pointer_point_
->get_Properties(&properties
);
388 hr
= properties
->get_PointerUpdateKind(&update_kind_
);
392 hr
= properties
->get_MouseWheelDelta(&wheel_delta_
);
396 is_horizontal_wheel_
= 0;
397 properties
->get_IsHorizontalMouseWheel(&is_horizontal_wheel_
);
402 pointer_point_
->get_Timestamp(×tamp_
);
403 pointer_point_
->get_PointerId(&pointer_id_
);
404 // Map the OS touch event id to a range allowed by the gesture recognizer.
406 pointer_id_
%= ui::GestureSequence::kMaxGesturePoints
;
408 boolean left_button_state
;
409 hr
= properties
->get_IsLeftButtonPressed(&left_button_state
);
412 if (left_button_state
)
413 mouse_down_flags_
|= ui::EF_LEFT_MOUSE_BUTTON
;
415 boolean right_button_state
;
416 hr
= properties
->get_IsRightButtonPressed(&right_button_state
);
419 if (right_button_state
)
420 mouse_down_flags_
|= ui::EF_RIGHT_MOUSE_BUTTON
;
422 boolean middle_button_state
;
423 hr
= properties
->get_IsMiddleButtonPressed(&middle_button_state
);
426 if (middle_button_state
)
427 mouse_down_flags_
|= ui::EF_MIDDLE_MOUSE_BUTTON
;
432 bool IsType(windevs::Input::PointerDeviceType type
) const {
433 mswr::ComPtr
<windevs::Input::IPointerDevice
> pointer_device
;
434 CheckHR(pointer_point_
->get_PointerDevice(&pointer_device
));
435 windevs::Input::PointerDeviceType device_type
;
436 CheckHR(pointer_device
->get_PointerDeviceType(&device_type
));
437 return (device_type
== type
);
440 bool IsMouse() const {
441 return IsType(windevs::Input::PointerDeviceType_Mouse
);
444 bool IsTouch() const {
445 return IsType(windevs::Input::PointerDeviceType_Touch
);
448 int32
wheel_delta() const {
452 // Identifies the button that changed.
453 ui::EventFlags
changed_button() const {
454 switch (update_kind_
) {
455 case winui::Input::PointerUpdateKind_LeftButtonPressed
:
456 return ui::EF_LEFT_MOUSE_BUTTON
;
457 case winui::Input::PointerUpdateKind_LeftButtonReleased
:
458 return ui::EF_LEFT_MOUSE_BUTTON
;
459 case winui::Input::PointerUpdateKind_RightButtonPressed
:
460 return ui::EF_RIGHT_MOUSE_BUTTON
;
461 case winui::Input::PointerUpdateKind_RightButtonReleased
:
462 return ui::EF_RIGHT_MOUSE_BUTTON
;
463 case winui::Input::PointerUpdateKind_MiddleButtonPressed
:
464 return ui::EF_MIDDLE_MOUSE_BUTTON
;
465 case winui::Input::PointerUpdateKind_MiddleButtonReleased
:
466 return ui::EF_MIDDLE_MOUSE_BUTTON
;
472 uint32
mouse_down_flags() const { return mouse_down_flags_
; }
474 int x() const { return x_
; }
475 int y() const { return y_
; }
477 uint32
pointer_id() const {
481 uint64
timestamp() const { return timestamp_
; }
483 winui::Input::PointerUpdateKind
update_kind() const { return update_kind_
; }
485 bool is_horizontal_wheel() const { return !!is_horizontal_wheel_
; }
492 winui::Input::PointerUpdateKind update_kind_
;
493 mswr::ComPtr
<winui::Input::IPointerPoint
> pointer_point_
;
496 // Bitmask of ui::EventFlags corresponding to the buttons that are currently
498 uint32 mouse_down_flags_
;
500 // Set to true for a horizontal wheel message.
501 boolean is_horizontal_wheel_
;
503 DISALLOW_COPY_AND_ASSIGN(PointerInfoHandler
);
506 ChromeAppViewAsh::ChromeAppViewAsh()
507 : mouse_down_flags_(ui::EF_NONE
),
508 ui_channel_(nullptr),
509 core_window_hwnd_(NULL
) {
510 DVLOG(1) << __FUNCTION__
;
511 globals
.previous_state
=
512 winapp::Activation::ApplicationExecutionState_NotRunning
;
515 ChromeAppViewAsh::~ChromeAppViewAsh() {
516 DVLOG(1) << __FUNCTION__
;
520 ChromeAppViewAsh::Initialize(winapp::Core::ICoreApplicationView
* view
) {
522 DVLOG(1) << __FUNCTION__
;
523 HRESULT hr
= view_
->add_Activated(mswr::Callback
<ActivatedHandler
>(
524 this, &ChromeAppViewAsh::OnActivate
).Get(),
531 ChromeAppViewAsh::SetWindow(winui::Core::ICoreWindow
* window
) {
533 DVLOG(1) << __FUNCTION__
;
535 // Retrieve the native window handle via the interop layer.
536 mswr::ComPtr
<ICoreWindowInterop
> interop
;
537 HRESULT hr
= window
->QueryInterface(interop
.GetAddressOf());
539 hr
= interop
->get_WindowHandle(&core_window_hwnd_
);
542 text_service_
= metro_driver::CreateTextService(this, core_window_hwnd_
);
544 hr
= window_
->add_SizeChanged(mswr::Callback
<SizeChangedHandler
>(
545 this, &ChromeAppViewAsh::OnSizeChanged
).Get(),
549 // Register for pointer and keyboard notifications. We forward
550 // them to the browser process via IPC.
551 hr
= window_
->add_PointerMoved(mswr::Callback
<PointerEventHandler
>(
552 this, &ChromeAppViewAsh::OnPointerMoved
).Get(),
553 &pointermoved_token_
);
556 hr
= window_
->add_PointerPressed(mswr::Callback
<PointerEventHandler
>(
557 this, &ChromeAppViewAsh::OnPointerPressed
).Get(),
558 &pointerpressed_token_
);
561 hr
= window_
->add_PointerReleased(mswr::Callback
<PointerEventHandler
>(
562 this, &ChromeAppViewAsh::OnPointerReleased
).Get(),
563 &pointerreleased_token_
);
566 hr
= window_
->add_KeyDown(mswr::Callback
<KeyEventHandler
>(
567 this, &ChromeAppViewAsh::OnKeyDown
).Get(),
571 hr
= window_
->add_KeyUp(mswr::Callback
<KeyEventHandler
>(
572 this, &ChromeAppViewAsh::OnKeyUp
).Get(),
576 mswr::ComPtr
<winui::Core::ICoreDispatcher
> dispatcher
;
577 hr
= window_
->get_Dispatcher(dispatcher
.GetAddressOf());
578 CheckHR(hr
, "Get Dispatcher failed.");
580 mswr::ComPtr
<winui::Core::ICoreAcceleratorKeys
> accelerator_keys
;
581 hr
= dispatcher
.CopyTo(__uuidof(winui::Core::ICoreAcceleratorKeys
),
582 reinterpret_cast<void**>(
583 accelerator_keys
.GetAddressOf()));
584 CheckHR(hr
, "QI for ICoreAcceleratorKeys failed.");
585 hr
= accelerator_keys
->add_AcceleratorKeyActivated(
586 mswr::Callback
<AcceleratorKeyEventHandler
>(
587 this, &ChromeAppViewAsh::OnAcceleratorKeyDown
).Get(),
588 &accel_keydown_token_
);
591 hr
= window_
->add_PointerWheelChanged(mswr::Callback
<PointerEventHandler
>(
592 this, &ChromeAppViewAsh::OnWheel
).Get(),
596 hr
= window_
->add_CharacterReceived(mswr::Callback
<CharEventHandler
>(
597 this, &ChromeAppViewAsh::OnCharacterReceived
).Get(),
598 &character_received_token_
);
601 hr
= window_
->add_Activated(mswr::Callback
<WindowActivatedHandler
>(
602 this, &ChromeAppViewAsh::OnWindowActivated
).Get(),
603 &window_activated_token_
);
606 if (base::win::GetVersion() >= base::win::VERSION_WIN8
) {
607 // Register for edge gesture notifications only for Windows 8 and above.
608 mswr::ComPtr
<winui::Input::IEdgeGestureStatics
> edge_gesture_statics
;
609 hr
= winrt_utils::CreateActivationFactory(
610 RuntimeClass_Windows_UI_Input_EdgeGesture
,
611 edge_gesture_statics
.GetAddressOf());
614 mswr::ComPtr
<winui::Input::IEdgeGesture
> edge_gesture
;
615 hr
= edge_gesture_statics
->GetForCurrentView(&edge_gesture
);
618 hr
= edge_gesture
->add_Completed(mswr::Callback
<EdgeEventHandler
>(
619 this, &ChromeAppViewAsh::OnEdgeGestureCompleted
).Get(),
624 // By initializing the direct 3D swap chain with the corewindow
625 // we can now directly blit to it from the browser process.
626 direct3d_helper_
.Initialize(window
);
627 DVLOG(1) << "Initialized Direct3D.";
632 ChromeAppViewAsh::Load(HSTRING entryPoint
) {
633 // On Win7 |entryPoint| is NULL.
634 DVLOG(1) << __FUNCTION__
;
639 ChromeAppViewAsh::Run() {
640 DVLOG(1) << __FUNCTION__
;
641 mswr::ComPtr
<winui::Core::ICoreDispatcher
> dispatcher
;
642 HRESULT hr
= window_
->get_Dispatcher(dispatcher
.GetAddressOf());
643 CheckHR(hr
, "Dispatcher failed.");
645 hr
= window_
->Activate();
647 DLOG(WARNING
) << "activation failed hr=" << hr
;
651 // Create the IPC channel IO thread. It needs to out-live the ChannelProxy.
652 base::Thread
io_thread("metro_IO_thread");
653 base::Thread::Options options
;
654 options
.message_loop_type
= base::MessageLoop::TYPE_IO
;
655 io_thread
.StartWithOptions(options
);
657 // Start up Chrome and wait for the desired IPC server connection to exist.
658 WaitForChromeIPCConnection(win8::kMetroViewerIPCChannelName
);
660 // In Aura mode we create an IPC channel to the browser, then ask it to
662 ChromeChannelListener
ui_channel_listener(&ui_loop_
, this);
663 IPC::ChannelProxy
ui_channel(win8::kMetroViewerIPCChannelName
,
664 IPC::Channel::MODE_NAMED_CLIENT
,
665 &ui_channel_listener
,
666 io_thread
.message_loop_proxy());
667 ui_channel_
= &ui_channel
;
669 // Upon receipt of the MetroViewerHostMsg_SetTargetSurface message the
670 // browser will use D3D from the browser process to present to our Window.
671 ui_channel_
->Send(new MetroViewerHostMsg_SetTargetSurface(
672 gfx::NativeViewId(core_window_hwnd_
)));
673 DVLOG(1) << "ICoreWindow sent " << core_window_hwnd_
;
675 // Send an initial size message so that the Ash root window host gets sized
678 ::GetWindowRect(core_window_hwnd_
, &rect
);
680 new MetroViewerHostMsg_WindowSizeChanged(rect
.right
- rect
.left
,
681 rect
.bottom
- rect
.top
));
683 input_source_
= metro_driver::InputSource::Create();
685 input_source_
->AddObserver(this);
686 // Send an initial input source.
687 OnInputSourceChanged();
690 // Start receiving IME popup window notifications.
691 metro_driver::AddImePopupObserver(this);
693 // And post the task that'll do the inner Metro message pumping to it.
694 ui_loop_
.PostTask(FROM_HERE
, base::Bind(&RunMessageLoop
, dispatcher
.Get()));
697 DVLOG(0) << "ProcessEvents done, hr=" << hr
;
702 ChromeAppViewAsh::Uninitialize() {
703 DVLOG(1) << __FUNCTION__
;
704 metro_driver::RemoveImePopupObserver(this);
705 input_source_
.reset();
706 text_service_
.reset();
709 core_window_hwnd_
= NULL
;
714 HRESULT
ChromeAppViewAsh::Unsnap() {
715 mswr::ComPtr
<winui::ViewManagement::IApplicationViewStatics
> view_statics
;
716 HRESULT hr
= winrt_utils::CreateActivationFactory(
717 RuntimeClass_Windows_UI_ViewManagement_ApplicationView
,
718 view_statics
.GetAddressOf());
721 winui::ViewManagement::ApplicationViewState state
=
722 winui::ViewManagement::ApplicationViewState_FullScreenLandscape
;
723 hr
= view_statics
->get_Value(&state
);
726 if (state
== winui::ViewManagement::ApplicationViewState_Snapped
) {
727 boolean success
= FALSE
;
728 hr
= view_statics
->TryUnsnap(&success
);
730 if (FAILED(hr
) || !success
) {
731 LOG(ERROR
) << "Failed to unsnap. Error 0x" << hr
;
739 void ChromeAppViewAsh::OnActivateDesktop(const base::FilePath
& file_path
,
741 DVLOG(1) << "ChannelAppViewAsh::OnActivateDesktop\n";
744 // As we are the top level window, the exiting is done async so we manage
745 // to execute the entire function including the final Send().
746 OnMetroExit(TERMINATE_USING_KEY_SEQUENCE
);
749 // We are just executing delegate_execute here without parameters. Assumption
750 // here is that this process will be reused by shell when asking for
751 // IExecuteCommand interface.
753 // TODO(shrikant): Consolidate ShellExecuteEx with SEE_MASK_FLAG_LOG_USAGE
754 // and place it metro.h or similar accessible file from all code code paths
755 // using this function.
756 SHELLEXECUTEINFO sei
= { sizeof(sei
) };
757 sei
.fMask
= SEE_MASK_FLAG_LOG_USAGE
;
758 sei
.nShow
= SW_SHOWNORMAL
;
759 sei
.lpFile
= file_path
.value().c_str();
760 sei
.lpParameters
= NULL
;
762 sei
.fMask
|= SEE_MASK_NOCLOSEPROCESS
;
763 ::ShellExecuteExW(&sei
);
765 ::TerminateProcess(sei
.hProcess
, 0);
766 ::CloseHandle(sei
.hProcess
);
770 void ChromeAppViewAsh::OnOpenURLOnDesktop(const base::FilePath
& shortcut
,
771 const base::string16
& url
) {
772 base::FilePath::StringType file
= shortcut
.value();
773 SHELLEXECUTEINFO sei
= { sizeof(sei
) };
774 sei
.fMask
= SEE_MASK_FLAG_LOG_USAGE
;
775 sei
.nShow
= SW_SHOWNORMAL
;
776 sei
.lpFile
= file
.c_str();
777 sei
.lpDirectory
= L
"";
778 sei
.lpParameters
= url
.c_str();
779 BOOL result
= ShellExecuteEx(&sei
);
782 void ChromeAppViewAsh::OnSetCursor(HCURSOR cursor
) {
783 ::SetCursor(HCURSOR(cursor
));
786 void ChromeAppViewAsh::OnDisplayFileOpenDialog(
787 const base::string16
& title
,
788 const base::string16
& filter
,
789 const base::FilePath
& default_path
,
790 bool allow_multiple_files
) {
791 DVLOG(1) << __FUNCTION__
;
793 // The OpenFilePickerSession instance is deleted when we receive a
794 // callback from the OpenFilePickerSession class about the completion of the
796 FilePickerSessionBase
* file_picker_
=
797 new OpenFilePickerSession(this,
801 allow_multiple_files
);
805 void ChromeAppViewAsh::OnDisplayFileSaveAsDialog(
806 const MetroViewerHostMsg_SaveAsDialogParams
& params
) {
807 DVLOG(1) << __FUNCTION__
;
809 // The SaveFilePickerSession instance is deleted when we receive a
810 // callback from the SaveFilePickerSession class about the completion of the
812 FilePickerSessionBase
* file_picker_
=
813 new SaveFilePickerSession(this, params
);
817 void ChromeAppViewAsh::OnDisplayFolderPicker(const base::string16
& title
) {
818 DVLOG(1) << __FUNCTION__
;
819 // The FolderPickerSession instance is deleted when we receive a
820 // callback from the FolderPickerSession class about the completion of the
822 FilePickerSessionBase
* file_picker_
= new FolderPickerSession(this, title
);
826 void ChromeAppViewAsh::OnSetCursorPos(int x
, int y
) {
828 ::SetCursorPos(x
, y
);
829 DVLOG(1) << "In UI OnSetCursorPos: " << x
<< ", " << y
;
830 ui_channel_
->Send(new MetroViewerHostMsg_SetCursorPosAck());
831 // Generate a fake mouse move which matches the SetCursor coordinates as
832 // the browser expects to receive a mouse move for these coordinates.
833 // It is not clear why we don't receive a real mouse move in response to
834 // the SetCursorPos calll above.
835 ui_channel_
->Send(new MetroViewerHostMsg_MouseMoved(x
, y
, 0));
839 void ChromeAppViewAsh::OnOpenFileCompleted(
840 OpenFilePickerSession
* open_file_picker
,
842 DVLOG(1) << __FUNCTION__
;
843 DVLOG(1) << "Success: " << success
;
845 if (open_file_picker
->allow_multi_select()) {
846 ui_channel_
->Send(new MetroViewerHostMsg_MultiFileOpenDone(
847 success
, open_file_picker
->filenames()));
849 ui_channel_
->Send(new MetroViewerHostMsg_FileOpenDone(
850 success
, base::FilePath(open_file_picker
->result())));
853 delete open_file_picker
;
856 void ChromeAppViewAsh::OnSaveFileCompleted(
857 SaveFilePickerSession
* save_file_picker
,
859 DVLOG(1) << __FUNCTION__
;
860 DVLOG(1) << "Success: " << success
;
862 ui_channel_
->Send(new MetroViewerHostMsg_FileSaveAsDone(
864 base::FilePath(save_file_picker
->result()),
865 save_file_picker
->filter_index()));
867 delete save_file_picker
;
870 void ChromeAppViewAsh::OnFolderPickerCompleted(
871 FolderPickerSession
* folder_picker
,
873 DVLOG(1) << __FUNCTION__
;
874 DVLOG(1) << "Success: " << success
;
876 ui_channel_
->Send(new MetroViewerHostMsg_SelectFolderDone(
878 base::FilePath(folder_picker
->result())));
880 delete folder_picker
;
883 void ChromeAppViewAsh::OnImeCancelComposition() {
886 text_service_
->CancelComposition();
889 void ChromeAppViewAsh::OnImeUpdateTextInputClient(
890 const std::vector
<int32
>& input_scopes
,
891 const std::vector
<metro_viewer::CharacterBounds
>& character_bounds
) {
894 text_service_
->OnDocumentChanged(input_scopes
, character_bounds
);
897 void ChromeAppViewAsh::OnImePopupChanged(ImePopupObserver::EventType event
) {
901 case ImePopupObserver::kPopupShown
:
902 ui_channel_
->Send(new MetroViewerHostMsg_ImeCandidatePopupChanged(true));
904 case ImePopupObserver::kPopupHidden
:
905 ui_channel_
->Send(new MetroViewerHostMsg_ImeCandidatePopupChanged(false));
907 case ImePopupObserver::kPopupUpdated
:
908 // TODO(kochi): Support this event for W3C IME API proposal.
909 // See crbug.com/238585.
912 NOTREACHED() << "unknown event type: " << event
;
917 // Function to Exit metro chrome cleanly. If we are in the foreground
918 // then we try and exit by sending an Alt+F4 key combination to the core
919 // window which ensures that the chrome application tile does not show up in
920 // the running metro apps list on the top left corner.
921 void ChromeAppViewAsh::OnMetroExit(MetroTerminateMethod method
) {
922 if (base::win::GetVersion() >= base::win::VERSION_WIN8
) {
923 HWND core_window
= core_window_hwnd();
924 if (method
== TERMINATE_USING_KEY_SEQUENCE
&& core_window
!= NULL
&&
925 core_window
== ::GetForegroundWindow()) {
926 DVLOG(1) << "We are in the foreground. Exiting via Alt F4";
927 SendKeySequence(VK_F4
, ALT
);
931 ui_channel_
->Close();
933 globals
.app_exit
->Exit();
936 void ChromeAppViewAsh::OnInputSourceChanged() {
942 if (!input_source_
->GetActiveSource(&langid
, &is_ime
)) {
943 LOG(ERROR
) << "GetActiveSource failed";
946 ui_channel_
->Send(new MetroViewerHostMsg_ImeInputSourceChanged(langid
,
950 void ChromeAppViewAsh::OnCompositionChanged(
951 const base::string16
& text
,
952 int32 selection_start
,
954 const std::vector
<metro_viewer::UnderlineInfo
>& underlines
) {
955 ui_channel_
->Send(new MetroViewerHostMsg_ImeCompositionChanged(
956 text
, selection_start
, selection_end
, underlines
));
959 void ChromeAppViewAsh::OnTextCommitted(const base::string16
& text
) {
960 ui_channel_
->Send(new MetroViewerHostMsg_ImeTextCommitted(text
));
963 void ChromeAppViewAsh::SendMouseButton(int x
,
966 ui::EventType event_type
,
968 ui::EventFlags changed_button
,
969 bool is_horizontal_wheel
) {
970 MetroViewerHostMsg_MouseButtonParams params
;
971 params
.x
= static_cast<int32
>(x
);
972 params
.y
= static_cast<int32
>(y
);
973 params
.extra
= static_cast<int32
>(extra
);
974 params
.event_type
= event_type
;
975 params
.flags
= static_cast<int32
>(flags
);
976 params
.changed_button
= changed_button
;
977 params
.is_horizontal_wheel
= is_horizontal_wheel
;
978 ui_channel_
->Send(new MetroViewerHostMsg_MouseButton(params
));
981 void ChromeAppViewAsh::GenerateMouseEventFromMoveIfNecessary(
982 const PointerInfoHandler
& pointer
) {
983 ui::EventType event_type
;
984 // For aura we want the flags to include the button that was released, thus
985 // we or the old and new.
986 uint32 mouse_down_flags
= pointer
.mouse_down_flags() | mouse_down_flags_
;
987 mouse_down_flags_
= pointer
.mouse_down_flags();
988 switch (pointer
.update_kind()) {
989 case winui::Input::PointerUpdateKind_LeftButtonPressed
:
990 case winui::Input::PointerUpdateKind_RightButtonPressed
:
991 case winui::Input::PointerUpdateKind_MiddleButtonPressed
:
992 event_type
= ui::ET_MOUSE_PRESSED
;
994 case winui::Input::PointerUpdateKind_LeftButtonReleased
:
995 case winui::Input::PointerUpdateKind_RightButtonReleased
:
996 case winui::Input::PointerUpdateKind_MiddleButtonReleased
:
997 event_type
= ui::ET_MOUSE_RELEASED
;
1002 SendMouseButton(pointer
.x(), pointer
.y(), 0, event_type
,
1003 mouse_down_flags
| GetKeyboardEventFlags(),
1004 pointer
.changed_button(), pointer
.is_horizontal_wheel());
1007 HRESULT
ChromeAppViewAsh::OnActivate(
1008 winapp::Core::ICoreApplicationView
*,
1009 winapp::Activation::IActivatedEventArgs
* args
) {
1010 DVLOG(1) << __FUNCTION__
;
1011 // Note: If doing more work in this function, you migth need to call
1012 // get_PreviousExecutionState() and skip the work if the result is
1013 // ApplicationExecutionState_Running and globals.previous_state is too.
1014 args
->get_PreviousExecutionState(&globals
.previous_state
);
1015 DVLOG(1) << "Previous Execution State: " << globals
.previous_state
;
1017 winapp::Activation::ActivationKind activation_kind
;
1018 CheckHR(args
->get_Kind(&activation_kind
));
1019 DVLOG(1) << "Activation kind: " << activation_kind
;
1021 if (activation_kind
== winapp::Activation::ActivationKind_Search
)
1022 HandleSearchRequest(args
);
1023 else if (activation_kind
== winapp::Activation::ActivationKind_Protocol
)
1024 HandleProtocolRequest(args
);
1026 LaunchChromeBrowserProcess(NULL
, args
);
1027 // We call ICoreWindow::Activate after the handling for the search/protocol
1028 // requests because Chrome can be launched to handle a search request which
1029 // in turn launches the chrome browser process in desktop mode via
1030 // ShellExecute. If we call ICoreWindow::Activate before this, then
1031 // Windows kills the metro chrome process when it calls ShellExecute. Seems
1033 window_
->Activate();
1037 HRESULT
ChromeAppViewAsh::OnPointerMoved(winui::Core::ICoreWindow
* sender
,
1038 winui::Core::IPointerEventArgs
* args
) {
1039 PointerInfoHandler pointer
;
1040 HRESULT hr
= pointer
.Init(args
);
1044 if (pointer
.IsMouse()) {
1045 GenerateMouseEventFromMoveIfNecessary(pointer
);
1046 ui_channel_
->Send(new MetroViewerHostMsg_MouseMoved(
1049 mouse_down_flags_
| GetKeyboardEventFlags()));
1051 DCHECK(pointer
.IsTouch());
1052 ui_channel_
->Send(new MetroViewerHostMsg_TouchMoved(pointer
.x(),
1054 pointer
.timestamp(),
1055 pointer
.pointer_id()));
1060 // NOTE: From experimentation, it seems like Metro only sends a PointerPressed
1061 // event for the first button pressed and the last button released in a sequence
1063 // For example, a sequence of LEFT_DOWN, RIGHT_DOWN, LEFT_UP, RIGHT_UP results
1064 // only in PointerPressed(LEFT)/PointerReleased(RIGHT) events. Intermediary
1065 // presses and releases are tracked in OnPointMoved().
1066 HRESULT
ChromeAppViewAsh::OnPointerPressed(
1067 winui::Core::ICoreWindow
* sender
,
1068 winui::Core::IPointerEventArgs
* args
) {
1069 PointerInfoHandler pointer
;
1070 HRESULT hr
= pointer
.Init(args
);
1074 if (pointer
.IsMouse()) {
1075 mouse_down_flags_
= pointer
.mouse_down_flags();
1076 SendMouseButton(pointer
.x(), pointer
.y(), 0, ui::ET_MOUSE_PRESSED
,
1077 mouse_down_flags_
| GetKeyboardEventFlags(),
1078 pointer
.changed_button(), pointer
.is_horizontal_wheel());
1080 DCHECK(pointer
.IsTouch());
1081 ui_channel_
->Send(new MetroViewerHostMsg_TouchDown(pointer
.x(),
1083 pointer
.timestamp(),
1084 pointer
.pointer_id()));
1089 HRESULT
ChromeAppViewAsh::OnPointerReleased(
1090 winui::Core::ICoreWindow
* sender
,
1091 winui::Core::IPointerEventArgs
* args
) {
1092 PointerInfoHandler pointer
;
1093 HRESULT hr
= pointer
.Init(args
);
1097 if (pointer
.IsMouse()) {
1098 mouse_down_flags_
= ui::EF_NONE
;
1099 SendMouseButton(pointer
.x(), pointer
.y(), 0, ui::ET_MOUSE_RELEASED
,
1100 static_cast<uint32
>(pointer
.changed_button()) |
1101 GetKeyboardEventFlags(),
1102 pointer
.changed_button(),
1103 pointer
.is_horizontal_wheel());
1105 DCHECK(pointer
.IsTouch());
1106 ui_channel_
->Send(new MetroViewerHostMsg_TouchUp(pointer
.x(),
1108 pointer
.timestamp(),
1109 pointer
.pointer_id()));
1114 HRESULT
ChromeAppViewAsh::OnWheel(
1115 winui::Core::ICoreWindow
* sender
,
1116 winui::Core::IPointerEventArgs
* args
) {
1117 PointerInfoHandler pointer
;
1118 HRESULT hr
= pointer
.Init(args
);
1121 DCHECK(pointer
.IsMouse());
1122 SendMouseButton(pointer
.x(), pointer
.y(), pointer
.wheel_delta(),
1123 ui::ET_MOUSEWHEEL
, ui::EF_NONE
, ui::EF_NONE
,
1124 pointer
.is_horizontal_wheel());
1128 HRESULT
ChromeAppViewAsh::OnKeyDown(
1129 winui::Core::ICoreWindow
* sender
,
1130 winui::Core::IKeyEventArgs
* args
) {
1131 winsys::VirtualKey virtual_key
;
1132 HRESULT hr
= args
->get_VirtualKey(&virtual_key
);
1135 winui::Core::CorePhysicalKeyStatus status
;
1136 hr
= args
->get_KeyStatus(&status
);
1140 ui_channel_
->Send(new MetroViewerHostMsg_KeyDown(virtual_key
,
1143 GetKeyboardEventFlags()));
1147 HRESULT
ChromeAppViewAsh::OnKeyUp(
1148 winui::Core::ICoreWindow
* sender
,
1149 winui::Core::IKeyEventArgs
* args
) {
1150 winsys::VirtualKey virtual_key
;
1151 HRESULT hr
= args
->get_VirtualKey(&virtual_key
);
1154 winui::Core::CorePhysicalKeyStatus status
;
1155 hr
= args
->get_KeyStatus(&status
);
1159 ui_channel_
->Send(new MetroViewerHostMsg_KeyUp(virtual_key
,
1162 GetKeyboardEventFlags()));
1166 HRESULT
ChromeAppViewAsh::OnAcceleratorKeyDown(
1167 winui::Core::ICoreDispatcher
* sender
,
1168 winui::Core::IAcceleratorKeyEventArgs
* args
) {
1169 winsys::VirtualKey virtual_key
;
1170 HRESULT hr
= args
->get_VirtualKey(&virtual_key
);
1173 winui::Core::CorePhysicalKeyStatus status
;
1174 hr
= args
->get_KeyStatus(&status
);
1178 winui::Core::CoreAcceleratorKeyEventType event_type
;
1179 hr
= args
->get_EventType(&event_type
);
1183 uint32 keyboard_flags
= GetKeyboardEventFlags();
1185 switch (event_type
) {
1186 case winui::Core::CoreAcceleratorKeyEventType_SystemCharacter
:
1187 ui_channel_
->Send(new MetroViewerHostMsg_Character(virtual_key
,
1193 case winui::Core::CoreAcceleratorKeyEventType_SystemKeyDown
:
1194 // Don't send the Alt + F4 combination to Chrome as this is intended to
1195 // shut the metro environment down. Reason we check for Control here is
1196 // Windows does not shutdown metro if Ctrl is pressed along with Alt F4.
1197 // Other key combinations with Alt F4 shutdown metro.
1198 if ((virtual_key
== VK_F4
) && ((keyboard_flags
& ui::EF_ALT_DOWN
) &&
1199 !(keyboard_flags
& ui::EF_CONTROL_DOWN
)))
1201 ui_channel_
->Send(new MetroViewerHostMsg_KeyDown(virtual_key
,
1207 case winui::Core::CoreAcceleratorKeyEventType_SystemKeyUp
:
1208 ui_channel_
->Send(new MetroViewerHostMsg_KeyUp(virtual_key
,
1220 HRESULT
ChromeAppViewAsh::OnCharacterReceived(
1221 winui::Core::ICoreWindow
* sender
,
1222 winui::Core::ICharacterReceivedEventArgs
* args
) {
1223 unsigned int char_code
= 0;
1224 HRESULT hr
= args
->get_KeyCode(&char_code
);
1228 winui::Core::CorePhysicalKeyStatus status
;
1229 hr
= args
->get_KeyStatus(&status
);
1233 ui_channel_
->Send(new MetroViewerHostMsg_Character(char_code
,
1236 GetKeyboardEventFlags()));
1240 HRESULT
ChromeAppViewAsh::OnWindowActivated(
1241 winui::Core::ICoreWindow
* sender
,
1242 winui::Core::IWindowActivatedEventArgs
* args
) {
1243 winui::Core::CoreWindowActivationState state
;
1244 HRESULT hr
= args
->get_WindowActivationState(&state
);
1248 // Treat both full activation (Ash was reopened from the Start Screen or from
1249 // any other Metro entry point in Windows) and pointer activation (user
1250 // clicked back in Ash after using another app on another monitor) the same.
1251 if (state
== winui::Core::CoreWindowActivationState_CodeActivated
||
1252 state
== winui::Core::CoreWindowActivationState_PointerActivated
) {
1254 text_service_
->OnWindowActivated();
1255 ui_channel_
->Send(new MetroViewerHostMsg_WindowActivated());
1260 HRESULT
ChromeAppViewAsh::HandleSearchRequest(
1261 winapp::Activation::IActivatedEventArgs
* args
) {
1262 mswr::ComPtr
<winapp::Activation::ISearchActivatedEventArgs
> search_args
;
1263 CheckHR(args
->QueryInterface(
1264 winapp::Activation::IID_ISearchActivatedEventArgs
, &search_args
));
1267 DVLOG(1) << "Launched to handle search request";
1268 LaunchChromeBrowserProcess(L
"--windows8-search", args
);
1271 mswrw::HString search_string
;
1272 CheckHR(search_args
->get_QueryText(search_string
.GetAddressOf()));
1273 base::string16
search_text(MakeStdWString(search_string
.Get()));
1275 ui_loop_
.PostTask(FROM_HERE
,
1276 base::Bind(&ChromeAppViewAsh::OnSearchRequest
,
1277 base::Unretained(this),
1282 HRESULT
ChromeAppViewAsh::HandleProtocolRequest(
1283 winapp::Activation::IActivatedEventArgs
* args
) {
1284 DVLOG(1) << __FUNCTION__
;
1286 DVLOG(1) << "Launched to handle url request";
1288 mswr::ComPtr
<winapp::Activation::IProtocolActivatedEventArgs
>
1290 CheckHR(args
->QueryInterface(
1291 winapp::Activation::IID_IProtocolActivatedEventArgs
,
1294 mswr::ComPtr
<winfoundtn::IUriRuntimeClass
> uri
;
1295 protocol_args
->get_Uri(&uri
);
1297 uri
->get_AbsoluteUri(url
.GetAddressOf());
1298 base::string16
actual_url(MakeStdWString(url
.Get()));
1299 DVLOG(1) << "Received url request: " << actual_url
;
1301 ui_loop_
.PostTask(FROM_HERE
,
1302 base::Bind(&ChromeAppViewAsh::OnNavigateToUrl
,
1303 base::Unretained(this),
1308 HRESULT
ChromeAppViewAsh::OnEdgeGestureCompleted(
1309 winui::Input::IEdgeGesture
* gesture
,
1310 winui::Input::IEdgeGestureEventArgs
* args
) {
1311 ui_channel_
->Send(new MetroViewerHostMsg_EdgeGesture());
1315 void ChromeAppViewAsh::OnSearchRequest(const base::string16
& search_string
) {
1316 DCHECK(ui_channel_
);
1317 ui_channel_
->Send(new MetroViewerHostMsg_SearchRequest(search_string
));
1320 void ChromeAppViewAsh::OnNavigateToUrl(const base::string16
& url
) {
1321 DCHECK(ui_channel_
);
1322 ui_channel_
->Send(new MetroViewerHostMsg_OpenURL(url
));
1325 HRESULT
ChromeAppViewAsh::OnSizeChanged(winui::Core::ICoreWindow
* sender
,
1326 winui::Core::IWindowSizeChangedEventArgs
* args
) {
1331 // winui::Core::IWindowSizeChangedEventArgs args->Size appears to return
1332 // scaled values under HiDPI. We will instead use GetWindowRect() which
1333 // should always return values in Pixels.
1335 ::GetWindowRect(core_window_hwnd_
, &rect
);
1337 uint32 cx
= static_cast<uint32
>(rect
.right
- rect
.left
);
1338 uint32 cy
= static_cast<uint32
>(rect
.bottom
- rect
.top
);
1340 DVLOG(1) << "Window size changed: width=" << cx
<< ", height=" << cy
;
1341 ui_channel_
->Send(new MetroViewerHostMsg_WindowSizeChanged(cx
, cy
));
1345 ///////////////////////////////////////////////////////////////////////////////
1347 ChromeAppViewFactory::ChromeAppViewFactory(
1348 winapp::Core::ICoreApplication
* icore_app
) {
1349 mswr::ComPtr
<winapp::Core::ICoreApplication
> core_app(icore_app
);
1350 mswr::ComPtr
<winapp::Core::ICoreApplicationExit
> app_exit
;
1351 CheckHR(core_app
.As(&app_exit
));
1352 globals
.app_exit
= app_exit
.Detach();
1356 ChromeAppViewFactory::CreateView(winapp::Core::IFrameworkView
** view
) {
1357 *view
= mswr::Make
<ChromeAppViewAsh
>().Detach();
1358 return (*view
) ? S_OK
: E_OUTOFMEMORY
;