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

Unified 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 side-by-side diff with in-line comments
Download patch
« 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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: win8/metro_driver/chrome_app_view.cc
diff --git a/win8/metro_driver/chrome_app_view.cc b/win8/metro_driver/chrome_app_view.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7d5580efa3d80bcea099c52d623c043937c3e57c
--- /dev/null
+++ b/win8/metro_driver/chrome_app_view.cc
@@ -0,0 +1,1059 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "win8/metro_driver/stdafx.h"
+#include "win8/metro_driver/chrome_app_view.h"
+
+#include <algorithm>
+#include <windows.applicationModel.datatransfer.h>
+#include <windows.foundation.h>
+
+#include "base/bind.h"
+#include "base/message_loop.h"
+#include "base/win/metro.h"
+
+// This include allows to send WM_SYSCOMMANDs to chrome.
+#include "chrome/app/chrome_command_ids.h"
+#include "win8/metro_driver/winrt_utils.h"
+#include "ui/base/ui_base_switches.h"
+
+typedef winfoundtn::ITypedEventHandler<
+ winapp::Core::CoreApplicationView*,
+ winapp::Activation::IActivatedEventArgs*> ActivatedHandler;
+
+typedef winfoundtn::ITypedEventHandler<
+ winui::Core::CoreWindow*,
+ winui::Core::WindowSizeChangedEventArgs*> SizeChangedHandler;
+
+typedef winfoundtn::ITypedEventHandler<
+ winui::Input::EdgeGesture*,
+ winui::Input::EdgeGestureEventArgs*> EdgeEventHandler;
+
+typedef winfoundtn::ITypedEventHandler<
+ winapp::DataTransfer::DataTransferManager*,
+ winapp::DataTransfer::DataRequestedEventArgs*> ShareDataRequestedHandler;
+
+typedef winfoundtn::ITypedEventHandler<
+ winui::ViewManagement::InputPane*,
+ winui::ViewManagement::InputPaneVisibilityEventArgs*>
+ InputPaneEventHandler;
+
+struct Globals globals;
+
+// TODO(ananta)
+// Remove this once we consolidate metro driver with chrome.
+const wchar_t kMetroGetCurrentTabInfoMessage[] =
+ L"CHROME_METRO_GET_CURRENT_TAB_INFO";
+
+static const int kFlipWindowsHotKeyId = 0x0000baba;
+
+static const int kAnimateWindowTimeoutMs = 200;
+
+static const int kCheckOSKDelayMs = 300;
+
+const wchar_t kOSKClassName[] = L"IPTip_Main_Window";
+
+static const int kOSKAdjustmentOffset = 20;
+
+namespace {
+
+void AdjustToFitWindow(HWND hwnd, int flags) {
+ RECT rect = {0};
+ ::GetWindowRect(globals.core_window, &rect);
+ int cx = rect.right - rect.left;
+ int cy = rect.bottom - rect.top;
+
+ ::SetWindowPos(hwnd, HWND_TOP,
+ rect.left, rect.top, cx, cy,
+ SWP_NOZORDER | flags);
+}
+
+void AdjustFrameWindowStyleForMetro(HWND hwnd) {
+ DVLOG(1) << __FUNCTION__;
+ // Ajust the frame so the live preview works and the frame buttons dissapear.
+ ::SetWindowLong(hwnd, GWL_STYLE,
+ WS_POPUP | (::GetWindowLong(hwnd, GWL_STYLE) &
+ ~(WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME | WS_SYSMENU)));
+ ::SetWindowLong(hwnd, GWL_EXSTYLE,
+ ::GetWindowLong(hwnd, GWL_EXSTYLE) & ~(WS_EX_DLGMODALFRAME |
+ WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
+ AdjustToFitWindow(hwnd, SWP_FRAMECHANGED | SWP_NOACTIVATE);
+}
+
+void SetFrameWindowInternal(HWND hwnd) {
+ DVLOG(1) << __FUNCTION__ << ", hwnd=" << LONG_PTR(hwnd);
+
+ HWND current_top_frame =
+ !globals.host_windows.empty() ? globals.host_windows.front().first : NULL;
+ if (hwnd != current_top_frame && IsWindow(current_top_frame)) {
+ DVLOG(1) << "Hiding current top window, hwnd="
+ << LONG_PTR(current_top_frame);
+ ::ShowWindow(current_top_frame, SW_HIDE);
+ }
+
+ // If chrome opens a url in a foreground tab, it may call SetFrameWindow
+ // again. Ensure that we don't have dups.
+ globals.host_windows.remove_if([hwnd](std::pair<HWND, bool>& item) {
+ return (item.first == hwnd);
+ });
+
+ globals.host_windows.push_front(std::make_pair(hwnd, false));
+
+ AdjustFrameWindowStyleForMetro(hwnd);
+}
+
+void CloseFrameWindowInternal(HWND hwnd) {
+ DVLOG(1) << __FUNCTION__ << ", hwnd=" << LONG_PTR(hwnd);
+
+ globals.host_windows.remove_if([hwnd](std::pair<HWND, bool>& item) {
+ return (item.first == hwnd);
+ });
+
+ if (globals.host_windows.size() > 0) {
+ DVLOG(1) << "Making new top frame window visible:"
+ << reinterpret_cast<int>(globals.host_windows.front().first);
+ AdjustToFitWindow(globals.host_windows.front().first, SWP_SHOWWINDOW);
+ } else {
+ // time to quit
+ DVLOG(1) << "Last host window closed. Calling Exit().";
+ globals.app_exit->Exit();
+ }
+}
+
+void FlipFrameWindowsInternal() {
+ DVLOG(1) << __FUNCTION__;
+ // Get the first window in the frame windows queue and push it to the end.
+ // Metroize the next window in the queue.
+ if (globals.host_windows.size() > 1) {
+ std::pair<HWND, bool> current_top_window = globals.host_windows.front();
+ globals.host_windows.pop_front();
+
+ DVLOG(1) << "Making new top frame window visible:"
+ << reinterpret_cast<int>(globals.host_windows.front().first);
+
+ AdjustToFitWindow(globals.host_windows.front().first, SWP_SHOWWINDOW);
+
+ DVLOG(1) << "Hiding current top window:"
+ << reinterpret_cast<int>(current_top_window.first);
+ AnimateWindow(current_top_window.first, kAnimateWindowTimeoutMs,
+ AW_HIDE | AW_HOR_POSITIVE | AW_SLIDE);
+
+ globals.host_windows.push_back(current_top_window);
+ }
+}
+
+} // namespace
+
+HRESULT ChromeAppView::TileRequestCreateDone(
+ winfoundtn::IAsyncOperation<bool>* async,
+ AsyncStatus status) {
+ if (status == Completed) {
+ unsigned char result;
+ CheckHR(async->GetResults(&result));
+ DVLOG(1) << __FUNCTION__ << " result " << static_cast<int>(result);
+ } else {
+ LOG(ERROR) << __FUNCTION__ << " Unexpected async status " << status;
+ }
+
+ return S_OK;
+}
+
+void ChromeAppView::DisplayNotification(
+ const ToastNotificationHandler::DesktopNotification& notification) {
+ DVLOG(1) << __FUNCTION__;
+
+ if (IsValidNotification(notification.id)) {
+ NOTREACHED() << "Duplicate notification id passed in.";
+ return;
+ }
+
+ base::AutoLock lock(notification_lock_);
+
+ ToastNotificationHandler* notification_handler =
+ new ToastNotificationHandler;
+
+ notification_map_[notification.id].reset(notification_handler);
+ notification_handler->DisplayNotification(notification);
+}
+
+void ChromeAppView::CancelNotification(const std::string& notification) {
+ DVLOG(1) << __FUNCTION__;
+
+ base::AutoLock lock(notification_lock_);
+
+ NotificationMap::iterator index = notification_map_.find(notification);
+ if (index == notification_map_.end()) {
+ NOTREACHED() << "Invalid notification:" << notification.c_str();
+ return;
+ }
+
+ scoped_ptr<ToastNotificationHandler> notification_handler(
+ index->second.release());
+
+ notification_map_.erase(index);
+
+ notification_handler->CancelNotification();
+}
+
+// Returns true if the notification passed in is valid.
+bool ChromeAppView::IsValidNotification(const std::string& notification) {
+ DVLOG(1) << __FUNCTION__;
+
+ base::AutoLock lock(notification_lock_);
+ return notification_map_.find(notification) != notification_map_.end();
+}
+
+void ChromeAppView::ShowDialogBox(
+ const MetroDialogBox::DialogBoxInfo& dialog_box_info) {
+ VLOG(1) << __FUNCTION__;
+ dialog_box_.Show(dialog_box_info);
+}
+
+void ChromeAppView::DismissDialogBox() {
+ VLOG(1) << __FUNCTION__;
+ dialog_box_.Dismiss();
+}
+
+// static
+HRESULT ChromeAppView::Unsnap() {
+ mswr::ComPtr<winui::ViewManagement::IApplicationViewStatics> view_statics;
+ HRESULT hr = winrt_utils::CreateActivationFactory(
+ RuntimeClass_Windows_UI_ViewManagement_ApplicationView,
+ view_statics.GetAddressOf());
+ CheckHR(hr);
+
+ winui::ViewManagement::ApplicationViewState state =
+ winui::ViewManagement::ApplicationViewState_FullScreenLandscape;
+ hr = view_statics->get_Value(&state);
+ CheckHR(hr);
+
+ if (state == winui::ViewManagement::ApplicationViewState_Snapped) {
+ boolean success = FALSE;
+ hr = view_statics->TryUnsnap(&success);
+
+ if (FAILED(hr) || !success) {
+ LOG(ERROR) << "Failed to unsnap. Error 0x" << hr;
+ if (SUCCEEDED(hr))
+ hr = E_UNEXPECTED;
+ }
+ }
+ return hr;
+}
+
+void ChromeAppView::SetFullscreen(bool fullscreen) {
+ VLOG(1) << __FUNCTION__;
+
+ if (osk_offset_adjustment_) {
+ VLOG(1) << "Scrolling the window down by: "
+ << osk_offset_adjustment_;
+
+ ::ScrollWindowEx(globals.host_windows.front().first,
+ 0,
+ osk_offset_adjustment_,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ SW_INVALIDATE | SW_SCROLLCHILDREN);
+ osk_offset_adjustment_ = 0;
+ }
+}
+
+void UnsnapHelper() {
+ ChromeAppView::Unsnap();
+}
+
+extern "C" __declspec(dllexport)
+void MetroUnsnap() {
+ DVLOG(1) << __FUNCTION__;
+ globals.appview_msg_loop->PostTask(
+ FROM_HERE, base::Bind(&UnsnapHelper));
+}
+
+extern "C" __declspec(dllexport)
+HWND GetRootWindow() {
+ DVLOG(1) << __FUNCTION__;
+ return globals.core_window;
+}
+
+extern "C" __declspec(dllexport)
+void SetFrameWindow(HWND hwnd) {
+ DVLOG(1) << __FUNCTION__ << ", hwnd=" << LONG_PTR(hwnd);
+ globals.appview_msg_loop->PostTask(
+ FROM_HERE, base::Bind(&SetFrameWindowInternal, hwnd));
+}
+
+// TODO(ananta)
+// Handle frame window close by deleting it from the window list and making the
+// next guy visible.
+extern "C" __declspec(dllexport)
+ void CloseFrameWindow(HWND hwnd) {
+ DVLOG(1) << __FUNCTION__ << ", hwnd=" << LONG_PTR(hwnd);
+
+ // This is a hack to ensure that the BrowserViewLayout code layout happens
+ // just at the right time to hide the switcher button if it is visible.
+ globals.appview_msg_loop->PostDelayedTask(
+ FROM_HERE, base::Bind(&CloseFrameWindowInternal, hwnd),
+ base::TimeDelta::FromMilliseconds(50));
+}
+
+// Returns the initial url. This returns a valid url only if we were launched
+// into metro via a url navigation.
+extern "C" __declspec(dllexport)
+const wchar_t* GetInitialUrl() {
+ DVLOG(1) << __FUNCTION__;
+ bool was_initial_activation = globals.is_initial_activation;
+ globals.is_initial_activation = false;
+ if (!was_initial_activation || globals.navigation_url.empty())
+ return L"";
+
+ const wchar_t* initial_url = globals.navigation_url.c_str();
+ DVLOG(1) << initial_url;
+ return initial_url;
+}
+
+// Returns the initial search string. This returns a valid url only if we were
+// launched into metro via the search charm
+extern "C" __declspec(dllexport)
+const wchar_t* GetInitialSearchString() {
+ DVLOG(1) << __FUNCTION__;
+ bool was_initial_activation = globals.is_initial_activation;
+ globals.is_initial_activation = false;
+ if (!was_initial_activation || globals.search_string.empty())
+ return L"";
+
+ const wchar_t* initial_search_string = globals.search_string.c_str();
+ DVLOG(1) << initial_search_string;
+ return initial_search_string;
+}
+
+// Returns the launch type.
+extern "C" __declspec(dllexport)
+base::win::MetroLaunchType GetLaunchType(
+ base::win::MetroPreviousExecutionState* previous_state) {
+ if (previous_state) {
+ *previous_state = static_cast<base::win::MetroPreviousExecutionState>(
+ globals.previous_state);
+ }
+ return static_cast<base::win::MetroLaunchType>(
+ globals.initial_activation_kind);
+}
+
+extern "C" __declspec(dllexport)
+void FlipFrameWindows() {
+ DVLOG(1) << __FUNCTION__;
+ globals.appview_msg_loop->PostTask(
+ FROM_HERE, base::Bind(&FlipFrameWindowsInternal));
+}
+
+extern "C" __declspec(dllexport)
+void DisplayNotification(const char* origin_url, const char* icon_url,
+ const wchar_t* title, const wchar_t* body,
+ const wchar_t* display_source,
+ const char* notification_id) {
+ // TODO(ananta)
+ // Needs implementation.
+ DVLOG(1) << __FUNCTION__;
+
+ ToastNotificationHandler::DesktopNotification notification(origin_url,
+ icon_url,
+ title,
+ body,
+ display_source,
+ notification_id);
+ globals.appview_msg_loop->PostTask(
+ FROM_HERE, base::Bind(&ChromeAppView::DisplayNotification,
+ globals.view, notification));
+}
+
+extern "C" __declspec(dllexport)
+bool CancelNotification(const char* notification_id) {
+ // TODO(ananta)
+ // Needs implementation.
+ DVLOG(1) << __FUNCTION__;
+
+ if (!globals.view->IsValidNotification(notification_id)) {
+ NOTREACHED() << "Invalid notification id :" << notification_id;
+ return false;
+ }
+
+ globals.appview_msg_loop->PostTask(
+ FROM_HERE, base::Bind(&ChromeAppView::CancelNotification,
+ globals.view, std::string(notification_id)));
+ return true;
+}
+
+// Returns command line switches if any to be used by metro chrome.
+extern "C" __declspec(dllexport)
+const wchar_t* GetMetroCommandLineSwitches() {
+ DVLOG(1) << __FUNCTION__;
+ // The metro_command_line_switches field should be filled up once.
+ // ideally in ChromeAppView::Activate.
+ return globals.metro_command_line_switches.c_str();
+}
+
+// Provides functionality to display a metro style dialog box with two buttons.
+// Only one dialog box can be displayed at any given time.
+extern "C" __declspec(dllexport)
+void ShowDialogBox(
+ const wchar_t* title,
+ const wchar_t* content,
+ const wchar_t* button1_label,
+ const wchar_t* button2_label,
+ base::win::MetroDialogButtonPressedHandler button1_handler,
+ base::win::MetroDialogButtonPressedHandler button2_handler) {
+ VLOG(1) << __FUNCTION__;
+
+ DCHECK(title);
+ DCHECK(content);
+ DCHECK(button1_label);
+ DCHECK(button2_label);
+ DCHECK(button1_handler);
+ DCHECK(button2_handler);
+
+ MetroDialogBox::DialogBoxInfo dialog_box_info;
+ dialog_box_info.title = title;
+ dialog_box_info.content = content;
+ dialog_box_info.button1_label = button1_label;
+ dialog_box_info.button2_label = button2_label;
+ dialog_box_info.button1_handler = button1_handler;
+ dialog_box_info.button2_handler = button2_handler;
+
+ globals.appview_msg_loop->PostTask(
+ FROM_HERE, base::Bind(
+ &ChromeAppView::ShowDialogBox, globals.view, dialog_box_info));
+}
+
+// Provides functionality to dismiss the previously displayed metro style
+// dialog box.
+extern "C" __declspec(dllexport)
+void DismissDialogBox() {
+ VLOG(1) << __FUNCTION__;
+
+ globals.appview_msg_loop->PostTask(
+ FROM_HERE, base::Bind(
+ &ChromeAppView::DismissDialogBox,
+ globals.view));
+}
+
+extern "C" __declspec(dllexport)
+void SetFullscreen(bool fullscreen) {
+ VLOG(1) << __FUNCTION__;
+
+ globals.appview_msg_loop->PostTask(
+ FROM_HERE, base::Bind(
+ &ChromeAppView::SetFullscreen,
+ globals.view, fullscreen));
+}
+
+BOOL CALLBACK CoreWindowFinder(HWND hwnd, LPARAM) {
+ char classname[128];
+ if (::GetClassNameA(hwnd, classname, ARRAYSIZE(classname))) {
+ if (lstrcmpiA("Windows.UI.Core.CoreWindow", classname) == 0) {
+ globals.core_window = hwnd;
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+template <typename ContainerT>
+void CloseSecondaryWindows(ContainerT& windows) {
+ DVLOG(1) << "Closing secondary windows", windows.size();
+ std::for_each(windows.begin(), windows.end(), [](HWND hwnd) {
+ ::PostMessageW(hwnd, WM_CLOSE, 0, 0);
+ });
+ windows.clear();
+}
+
+void EndChromeSession() {
+ DVLOG(1) << "Sending chrome WM_ENDSESSION window message.";
+ ::SendMessage(globals.host_windows.front().first, WM_ENDSESSION, FALSE,
+ ENDSESSION_CLOSEAPP);
+}
+
+DWORD WINAPI HostMainThreadProc(void*) {
+ // Test feature - devs have requested the ability to easily add metro-chrome
+ // command line arguments. This is hard since shortcut arguments are ignored,
+ // by Metro, so we instead read them directly from the pinned taskbar
+ // shortcut. This may call Coinitialize and there is tell of badness
+ // occurring if CoInitialize is called on a metro thread.
+ globals.metro_command_line_switches =
+ winrt_utils::ReadArgumentsFromPinnedTaskbarShortcut();
+
+ globals.g_core_proc = reinterpret_cast<WNDPROC>(
+ ::SetWindowLong(globals.core_window, GWL_WNDPROC,
+ reinterpret_cast<long>(ChromeAppView::CoreWindowProc)));
+ DWORD exit_code = globals.host_main(globals.host_context);
+ DVLOG(1) << "host thread done, exit_code=" << exit_code;
+ globals.app_exit->Exit();
+ return exit_code;
+}
+
+ChromeAppView::ChromeAppView()
+ : osk_visible_notification_received_(false),
+ osk_offset_adjustment_(0) {
+ globals.previous_state =
+ winapp::Activation::ApplicationExecutionState_NotRunning;
+}
+
+ChromeAppView::~ChromeAppView() {
+ DVLOG(1) << __FUNCTION__;
+}
+
+IFACEMETHODIMP
+ChromeAppView::Initialize(winapp::Core::ICoreApplicationView* view) {
+ view_ = view;
+ DVLOG(1) << __FUNCTION__;
+ globals.main_thread_id = ::GetCurrentThreadId();
+
+ HRESULT hr = view_->add_Activated(mswr::Callback<ActivatedHandler>(
+ this, &ChromeAppView::OnActivate).Get(),
+ &activated_token_);
+ CheckHR(hr);
+ return hr;
+}
+
+IFACEMETHODIMP
+ChromeAppView::SetWindow(winui::Core::ICoreWindow* window) {
+ window_ = window;
+ DVLOG(1) << __FUNCTION__;
+
+ HRESULT hr = url_launch_handler_.Initialize();
+ CheckHR(hr, "Failed to initialize url launch handler.");
+
+ // Register for size notifications.
+ hr = window_->add_SizeChanged(mswr::Callback<SizeChangedHandler>(
+ this, &ChromeAppView::OnSizeChanged).Get(),
+ &sizechange_token_);
+ CheckHR(hr);
+
+ // Register for edge gesture notifications.
+ mswr::ComPtr<winui::Input::IEdgeGestureStatics> edge_gesture_statics;
+ hr = winrt_utils::CreateActivationFactory(
+ RuntimeClass_Windows_UI_Input_EdgeGesture,
+ edge_gesture_statics.GetAddressOf());
+ CheckHR(hr, "Failed to activate IEdgeGestureStatics.");
+
+ mswr::ComPtr<winui::Input::IEdgeGesture> edge_gesture;
+ hr = edge_gesture_statics->GetForCurrentView(&edge_gesture);
+ CheckHR(hr);
+
+ hr = edge_gesture->add_Completed(mswr::Callback<EdgeEventHandler>(
+ this, &ChromeAppView::OnEdgeGestureCompleted).Get(),
+ &edgeevent_token_);
+ CheckHR(hr);
+
+ // Register for share notifications.
+ mswr::ComPtr<winapp::DataTransfer::IDataTransferManagerStatics>
+ data_mgr_statics;
+ hr = winrt_utils::CreateActivationFactory(
+ RuntimeClass_Windows_ApplicationModel_DataTransfer_DataTransferManager,
+ data_mgr_statics.GetAddressOf());
+ CheckHR(hr, "Failed to activate IDataTransferManagerStatics.");
+
+ mswr::ComPtr<winapp::DataTransfer::IDataTransferManager> data_transfer_mgr;
+ hr = data_mgr_statics->GetForCurrentView(&data_transfer_mgr);
+ CheckHR(hr, "Failed to get IDataTransferManager for current view.");
+
+ hr = data_transfer_mgr->add_DataRequested(
+ mswr::Callback<ShareDataRequestedHandler>(
+ this, &ChromeAppView::OnShareDataRequested).Get(),
+ &share_data_requested_token_);
+ CheckHR(hr);
+
+ // TODO(ananta)
+ // The documented InputPane notifications don't fire on Windows 8 in metro
+ // chrome. Uncomment this once we figure out why they don't fire.
+ // RegisterInputPaneNotifications();
+
+ hr = winrt_utils::CreateActivationFactory(
+ RuntimeClass_Windows_UI_ViewManagement_ApplicationView,
+ app_view_.GetAddressOf());
+ CheckHR(hr);
+
+ DVLOG(1) << "Created appview instance.";
+
+ hr = devices_handler_.Initialize(window);
+ // Don't check or return the failure here, we need to let the app
+ // initialization succeed. Even if we won't be able to access devices
+ // we still want to allow the app to start.
+ LOG_IF(ERROR, FAILED(hr)) << "Failed to initialize devices handler.";
+ return S_OK;
+}
+
+IFACEMETHODIMP
+ChromeAppView::Load(HSTRING entryPoint) {
+ DVLOG(1) << __FUNCTION__;
+ return S_OK;
+}
+
+void RunMessageLoop(winui::Core::ICoreDispatcher* dispatcher) {
+ // We're entering a nested message loop, let's allow dispatching
+ // tasks while we're in there.
+ MessageLoop::current()->SetNestableTasksAllowed(true);
+
+ // Enter main core message loop. There are several ways to exit it
+ // Nicely:
+ // 1 - User action like ALT-F4.
+ // 2 - Calling ICoreApplicationExit::Exit().
+ // 3- Posting WM_CLOSE to the core window.
+ HRESULT hr = dispatcher->ProcessEvents(
+ winui::Core::CoreProcessEventsOption
+ ::CoreProcessEventsOption_ProcessUntilQuit);
+
+ // Wind down the thread's chrome message loop.
+ MessageLoop::current()->Quit();
+}
+
+void ChromeAppView::CheckForOSKActivation() {
+ // Hack for checking if the OSK was displayed while we are in the foreground.
+ // The input pane notifications which are supposed to fire when the OSK is
+ // shown and hidden don't seem to be firing in Windows 8 metro for us.
+ // The current hack is supposed to workaround that issue till we figure it
+ // out. Logic is to find the OSK window and see if we are the foreground
+ // process. If yes then fire the notification once for when the OSK is shown
+ // and once for when it is hidden.
+ // TODO(ananta)
+ // Take this out when the documented input pane notifcation issues are
+ // addressed.
+ HWND osk = ::FindWindow(kOSKClassName, NULL);
+ if (::IsWindow(osk)) {
+ HWND foreground_window = ::GetForegroundWindow();
+ if (globals.host_windows.size() > 0 &&
+ foreground_window == globals.host_windows.front().first) {
+ RECT osk_rect = {0};
+ ::GetWindowRect(osk, &osk_rect);
+
+ if (::IsWindowVisible(osk) && ::IsWindowEnabled(osk)) {
+ if (!globals.view->osk_visible_notification_received()) {
+ DVLOG(1) << "Found KB window while we are in the forground.";
+ HandleInputPaneVisible(osk_rect);
+ }
+ } else if (osk_visible_notification_received()) {
+ DVLOG(1) << "KB window hidden while we are in the foreground.";
+ HandleInputPaneHidden(osk_rect);
+ }
+ }
+ }
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&ChromeAppView::CheckForOSKActivation,
+ base::Unretained(this)),
+ base::TimeDelta::FromMilliseconds(kCheckOSKDelayMs));
+}
+
+IFACEMETHODIMP
+ChromeAppView::Run() {
+ DVLOG(1) << __FUNCTION__ << ", hwnd=" << LONG_PTR(window_.Get());
+ mswr::ComPtr<winui::Core::ICoreDispatcher> dispatcher;
+ HRESULT hr = window_->get_Dispatcher(&dispatcher);
+ CheckHR(hr, "Dispatcher failed.");
+
+ hr = window_->Activate();
+ if (SUCCEEDED(hr)) {
+ // TODO(cpu): Draw something here.
+ } else {
+ DVLOG(1) << "Activate failed, hr=" << hr;
+ }
+
+ // Create a message loop to allow message passing into this thread.
+ MessageLoop msg_loop(MessageLoop::TYPE_UI);
+
+ // Announce our message loop to the world.
+ globals.appview_msg_loop = msg_loop.message_loop_proxy();
+
+ // And post the task that'll do the inner Metro message pumping to it.
+ msg_loop.PostTask(FROM_HERE, base::Bind(&RunMessageLoop, dispatcher.Get()));
+
+ // Post the recurring task which checks for OSK activation in metro chrome.
+ // Please refer to the comments in the CheckForOSKActivation function for why
+ // this is needed.
+ // TODO(ananta)
+ // Take this out when the documented OSK notifications start working.
+ msg_loop.PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&ChromeAppView::CheckForOSKActivation,
+ base::Unretained(this)),
+ base::TimeDelta::FromMilliseconds(kCheckOSKDelayMs));
+
+ msg_loop.Run();
+
+ globals.appview_msg_loop = NULL;
+
+ DVLOG(0) << "ProcessEvents done, hr=" << hr;
+
+ // We join here with chrome's main thread so that the chrome is not killed
+ // while a critical operation is still in progress. Now, if there are host
+ // windows active it is possible we end up stuck on the wait below therefore
+ // we tell chrome to close its windows.
+ if (!globals.host_windows.empty()) {
+ DVLOG(1) << "Chrome still has windows open!";
+ EndChromeSession();
+ }
+ DWORD wr = ::WaitForSingleObject(globals.host_thread, INFINITE);
+ if (wr != WAIT_OBJECT_0) {
+ DVLOG(1) << "Waiting for host thread failed : " << wr;
+ }
+ ::CloseHandle(globals.host_thread);
+ globals.host_thread = NULL;
+
+ return hr;
+}
+
+IFACEMETHODIMP
+ChromeAppView::Uninitialize() {
+ DVLOG(1) << __FUNCTION__;
+ window_ = nullptr;
+ view_ = nullptr;
+ base::AutoLock lock(notification_lock_);
+ notification_map_.clear();
+ return S_OK;
+}
+
+HRESULT ChromeAppView::RegisterInputPaneNotifications() {
+ DVLOG(1) << __FUNCTION__;
+
+ mswr::ComPtr<winui::ViewManagement::IInputPaneStatics>
+ input_pane_statics;
+ HRESULT hr = winrt_utils::CreateActivationFactory(
+ RuntimeClass_Windows_UI_ViewManagement_InputPane,
+ input_pane_statics.GetAddressOf());
+ CheckHR(hr);
+
+ hr = input_pane_statics->GetForCurrentView(&input_pane_);
+ CheckHR(hr);
+ DVLOG(1) << "Got input pane.";
+
+ hr = input_pane_->add_Showing(
+ mswr::Callback<InputPaneEventHandler>(
+ this, &ChromeAppView::OnInputPaneVisible).Get(),
+ &input_pane_visible_token_);
+ CheckHR(hr);
+
+ DVLOG(1) << "Added showing event handler for input pane",
+ input_pane_visible_token_.value;
+
+ hr = input_pane_->add_Hiding(
+ mswr::Callback<InputPaneEventHandler>(
+ this, &ChromeAppView::OnInputPaneHiding).Get(),
+ &input_pane_hiding_token_);
+ CheckHR(hr);
+
+ DVLOG(1) << "Added hiding event handler for input pane, value="
+ << input_pane_hiding_token_.value;
+ return hr;
+}
+
+HRESULT ChromeAppView::OnActivate(winapp::Core::ICoreApplicationView*,
+ winapp::Activation::IActivatedEventArgs* args) {
+ DVLOG(1) << __FUNCTION__;
+
+ args->get_PreviousExecutionState(&globals.previous_state);
+ DVLOG(1) << "Previous Execution State: " << globals.previous_state;
+
+ window_->Activate();
+ url_launch_handler_.Activate(args);
+
+ if (globals.previous_state ==
+ winapp::Activation::ApplicationExecutionState_Running &&
+ globals.host_thread) {
+ DVLOG(1) << "Already running. Skipping rest of OnActivate.";
+ return S_OK;
+ }
+
+ do {
+ ::Sleep(10);
+ ::EnumThreadWindows(globals.main_thread_id, &CoreWindowFinder, 0);
+ } while (globals.core_window == NULL);
+
+ DVLOG(1) << "CoreWindow found: " << std::hex << globals.core_window;
+
+ if (!globals.host_thread) {
+ globals.host_thread =
+ ::CreateThread(NULL, 0, HostMainThreadProc, NULL, 0, NULL);
+
+ if (!globals.host_thread) {
+ NOTREACHED() << "thread creation failed.";
+ return E_UNEXPECTED;
+ }
+ }
+
+ if (RegisterHotKey(globals.core_window, kFlipWindowsHotKeyId,
+ MOD_CONTROL, VK_F12)) {
+ DVLOG(1) << "Registered flip window hotkey.";
+ } else {
+ VPLOG(1) << "Failed to register flip window hotkey.";
+ }
+ HRESULT hr = settings_handler_.Initialize();
+ CheckHR(hr,"Failed to initialize settings handler.");
+ return hr;
+}
+
+// We subclass the core window for moving the associated chrome window when the
+// core window is moved around, typically in the snap view operation. The
+// size changes are handled in the documented size changed event.
+LRESULT CALLBACK ChromeAppView::CoreWindowProc(
+ HWND window, UINT message, WPARAM wp, LPARAM lp) {
+
+ static const UINT kBrowserClosingMessage =
+ ::RegisterWindowMessage(L"DefaultBrowserClosing");
+
+ if (message == WM_WINDOWPOSCHANGED) {
+ WINDOWPOS* pos = reinterpret_cast<WINDOWPOS*>(lp);
+ if (!(pos->flags & SWP_NOMOVE)) {
+ DVLOG(1) << "WM_WINDOWPOSCHANGED. Moving the chrome window.";
+ globals.view->OnPositionChanged(pos->x, pos->y);
+ }
+ } else if (message == WM_HOTKEY && wp == kFlipWindowsHotKeyId) {
+ FlipFrameWindows();
+ } else if (message == kBrowserClosingMessage) {
+ DVLOG(1) << "Received DefaultBrowserClosing window message.";
+ // Ensure that the view is uninitialized. The kBrowserClosingMessage
+ // means that the app is going to be terminated, i.e. the proper
+ // uninitialization sequence does not occur.
+ globals.view->Uninitialize();
+ if (!globals.host_windows.empty()) {
+ EndChromeSession();
+ }
+ }
+ return CallWindowProc(globals.g_core_proc, window, message, wp, lp);
+}
+
+HRESULT ChromeAppView::OnSizeChanged(winui::Core::ICoreWindow* sender,
+ winui::Core::IWindowSizeChangedEventArgs* args) {
+ if (!globals.host_windows.size()) {
+ return S_OK;
+ }
+
+ winfoundtn::Size size;
+ args->get_Size(&size);
+
+ int cx = static_cast<int>(size.Width);
+ int cy = static_cast<int>(size.Height);
+
+ if (!::SetWindowPos(globals.host_windows.front().first, NULL, 0, 0, cx, cy,
+ SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED)) {
+ DVLOG(1) << "SetWindowPos failed.";
+ }
+ DVLOG(1) << "size changed cx=" << cx;
+ DVLOG(1) << "size changed cy=" << cy;
+
+ winui::ViewManagement::ApplicationViewState view_state =
+ winui::ViewManagement::ApplicationViewState_FullScreenLandscape;
+ app_view_->get_Value(&view_state);
+
+ HWND top_level_frame = globals.host_windows.front().first;
+ if (view_state == winui::ViewManagement::ApplicationViewState_Snapped) {
+ DVLOG(1) << "Enabling metro snap mode.";
+ ::PostMessageW(top_level_frame, WM_SYSCOMMAND, IDC_METRO_SNAP_ENABLE, 0);
+ } else {
+ ::PostMessageW(top_level_frame, WM_SYSCOMMAND, IDC_METRO_SNAP_DISABLE, 0);
+ }
+ return S_OK;
+}
+
+HRESULT ChromeAppView::OnPositionChanged(int x, int y) {
+ DVLOG(1) << __FUNCTION__;
+
+ ::SetWindowPos(globals.host_windows.front().first, NULL, x, y, 0, 0,
+ SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOSIZE);
+ return S_OK;
+}
+
+HRESULT ChromeAppView::OnEdgeGestureCompleted(
+ winui::Input::IEdgeGesture* gesture,
+ winui::Input::IEdgeGestureEventArgs* args) {
+ DVLOG(1) << "edge gesture completed.";
+
+ winui::ViewManagement::ApplicationViewState view_state =
+ winui::ViewManagement::ApplicationViewState_FullScreenLandscape;
+ app_view_->get_Value(&view_state);
+ // We don't want fullscreen chrome unless we are fullscreen metro.
+ if ((view_state == winui::ViewManagement::ApplicationViewState_Filled) ||
+ (view_state == winui::ViewManagement::ApplicationViewState_Snapped)) {
+ DVLOG(1) << "No full screen in snapped view state:" << view_state;
+ return S_OK;
+ }
+
+ // Deactivate anything pending, e.g., the wrench or a context menu.
+ BOOL success = ::ReleaseCapture();
+ DCHECK(success) << "Couldn't ReleaseCapture() before going full screen";
+
+ DVLOG(1) << "Going full screen.";
+ ::PostMessageW(globals.host_windows.front().first, WM_SYSCOMMAND,
+ IDC_FULLSCREEN, 0);
+ return S_OK;
+}
+
+HRESULT ChromeAppView::OnShareDataRequested(
+ winapp::DataTransfer::IDataTransferManager* data_transfer_mgr,
+ winapp::DataTransfer::IDataRequestedEventArgs* event_args) {
+
+ DVLOG(1) << "Share data requested.";
+
+ // The current tab info is retrieved from Chrome via a registered window
+ // message.
+
+ static const UINT get_current_tab_info =
+ RegisterWindowMessage(kMetroGetCurrentTabInfoMessage);
+
+ static const int kGetTabInfoTimeoutMs = 1000;
+
+ mswr::ComPtr<winapp::DataTransfer::IDataRequest> data_request;
+ HRESULT hr = event_args->get_Request(&data_request);
+ CheckHR(hr);
+
+ mswr::ComPtr<winapp::DataTransfer::IDataPackage> data_package;
+ hr = data_request->get_Data(&data_package);
+ CheckHR(hr);
+
+ base::win::CurrentTabInfo current_tab_info;
+ current_tab_info.title = NULL;
+ current_tab_info.url = NULL;
+
+ DWORD_PTR result = 0;
+
+ if (!SendMessageTimeout(globals.host_windows.front().first,
+ get_current_tab_info,
+ reinterpret_cast<WPARAM>(&current_tab_info),
+ 0,
+ SMTO_ABORTIFHUNG,
+ kGetTabInfoTimeoutMs,
+ &result)) {
+ VPLOG(1) << "Failed to retrieve tab info from chrome.";
+ return E_FAIL;
+ }
+
+ if (!current_tab_info.title || !current_tab_info.url) {
+ DVLOG(1) << "Failed to retrieve tab info from chrome.";
+ return E_FAIL;
+ }
+
+ string16 current_title(current_tab_info.title);
+ string16 current_url(current_tab_info.url);
+
+ LocalFree(current_tab_info.title);
+ LocalFree(current_tab_info.url);
+
+ mswr::ComPtr<winapp::DataTransfer::IDataPackagePropertySet> data_properties;
+ hr = data_package->get_Properties(&data_properties);
+
+ mswrw::HString title;
+ title.Attach(MakeHString(current_title));
+ data_properties->put_Title(title.Get());
+
+ mswr::ComPtr<winfoundtn::IUriRuntimeClassFactory> uri_factory;
+ hr = winrt_utils::CreateActivationFactory(
+ RuntimeClass_Windows_Foundation_Uri,
+ uri_factory.GetAddressOf());
+ CheckHR(hr);
+
+ mswrw::HString url;
+ url.Attach(MakeHString(current_url));
+ mswr::ComPtr<winfoundtn::IUriRuntimeClass> uri;
+ hr = uri_factory->CreateUri(url.Get(), &uri);
+ CheckHR(hr);
+
+ hr = data_package->SetUri(uri.Get());
+ CheckHR(hr);
+
+ return S_OK;
+}
+
+void ChromeAppView::HandleInputPaneVisible(const RECT& osk_rect) {
+ DCHECK(!osk_visible_notification_received_);
+
+ DVLOG(1) << __FUNCTION__;
+ DVLOG(1) << "OSK width:" << osk_rect.right - osk_rect.left;
+ DVLOG(1) << "OSK height:" << osk_rect.bottom - osk_rect.top;
+
+ globals.host_windows.front().second = false;
+
+ POINT cursor_pos = {0};
+ GetCursorPos(&cursor_pos);
+
+ osk_offset_adjustment_ = 0;
+
+ if (::PtInRect(&osk_rect, cursor_pos)) {
+ DVLOG(1) << "OSK covering focus point.";
+ int osk_height = osk_rect.bottom - osk_rect.top;
+
+ osk_offset_adjustment_ = osk_height + kOSKAdjustmentOffset;
+
+ DVLOG(1) << "Scrolling window by offset: " << osk_offset_adjustment_;
+ ::ScrollWindowEx(globals.host_windows.front().first,
+ 0,
+ -osk_offset_adjustment_,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ SW_INVALIDATE | SW_SCROLLCHILDREN);
+
+ globals.host_windows.front().second = true;
+ }
+ osk_visible_notification_received_ = true;
+}
+
+void ChromeAppView::HandleInputPaneHidden(const RECT& osk_rect) {
+ DCHECK(osk_visible_notification_received_);
+ DVLOG(1) << __FUNCTION__;
+ DVLOG(1) << "OSK width:" << osk_rect.right - osk_rect.left;
+ DVLOG(1) << "OSK height:" << osk_rect.bottom - osk_rect.top;
+ osk_visible_notification_received_ = false;
+ if (globals.host_windows.front().second == true) {
+
+ if (osk_offset_adjustment_) {
+ DVLOG(1) << "Restoring scrolled window offset: "
+ << osk_offset_adjustment_;
+
+ ::ScrollWindowEx(globals.host_windows.front().first,
+ 0,
+ osk_offset_adjustment_,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ SW_INVALIDATE | SW_SCROLLCHILDREN);
+ }
+
+ globals.host_windows.front().second = false;
+ }
+}
+
+HRESULT ChromeAppView::OnInputPaneVisible(
+ winui::ViewManagement::IInputPane* input_pane,
+ winui::ViewManagement::IInputPaneVisibilityEventArgs* event_args) {
+ DVLOG(1) << __FUNCTION__;
+ return S_OK;
+}
+
+HRESULT ChromeAppView::OnInputPaneHiding(
+ winui::ViewManagement::IInputPane* input_pane,
+ winui::ViewManagement::IInputPaneVisibilityEventArgs* event_args) {
+ DVLOG(1) << __FUNCTION__;
+ return S_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+ChromeAppViewFactory::ChromeAppViewFactory(
+ winapp::Core::ICoreApplication* icore_app,
+ LPTHREAD_START_ROUTINE host_main,
+ void* host_context) {
+ globals.host_main = host_main;
+ globals.host_context = host_context;
+ mswr::ComPtr<winapp::Core::ICoreApplication> core_app(icore_app);
+ mswr::ComPtr<winapp::Core::ICoreApplicationExit> app_exit;
+ CheckHR(core_app.As(&app_exit));
+ globals.app_exit = app_exit.Detach();
+}
+
+IFACEMETHODIMP
+ChromeAppViewFactory::CreateView(winapp::Core::IFrameworkView** view) {
+ globals.view = mswr::Make<ChromeAppView>().Detach();
+ *view = globals.view;
+ return (*view) ? S_OK : E_OUTOFMEMORY;
+}
« 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