diff options
author | robertshield@chromium.org <robertshield@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-08 17:50:30 +0000 |
---|---|---|
committer | robertshield@chromium.org <robertshield@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-08 17:50:30 +0000 |
commit | d652bfa5646f4abd22b470a88478769c222c2177 (patch) | |
tree | 44f25d8b94f5c939df5ee12201ef6367b508ce25 /win8 | |
parent | a9e5f04481565af0a3c8dbe770b14899f24b68f7 (diff) | |
download | chromium_src-d652bfa5646f4abd22b470a88478769c222c2177.zip chromium_src-d652bfa5646f4abd22b470a88478769c222c2177.tar.gz chromium_src-d652bfa5646f4abd22b470a88478769c222c2177.tar.bz2 |
Manually merging remaining Win8 changes.
BUG=127799
TEST=NONE
Review URL: https://chromiumcodereview.appspot.com/10914160
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@155592 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'win8')
-rw-r--r-- | win8/delegate_execute/command_execute_impl.cc | 12 | ||||
-rw-r--r-- | win8/delegate_execute/delegate_execute.cc | 110 | ||||
-rw-r--r-- | win8/delegate_execute/delegate_execute_operation.cc | 44 | ||||
-rw-r--r-- | win8/delegate_execute/delegate_execute_operation.h | 44 | ||||
-rw-r--r-- | win8/metro_driver/chrome_app_view.cc | 135 | ||||
-rw-r--r-- | win8/metro_driver/chrome_url_launch_handler.cc | 26 | ||||
-rw-r--r-- | win8/metro_driver/metro_driver.gyp | 1 | ||||
-rw-r--r-- | win8/metro_driver/secondary_tile.cc | 7 |
8 files changed, 283 insertions, 96 deletions
diff --git a/win8/delegate_execute/command_execute_impl.cc b/win8/delegate_execute/command_execute_impl.cc index ef1378a..9781386 100644 --- a/win8/delegate_execute/command_execute_impl.cc +++ b/win8/delegate_execute/command_execute_impl.cc @@ -220,7 +220,7 @@ STDMETHODIMP CommandExecuteImpl::Execute() { AtlTrace("Activating for file\n"); hr = activation_manager->ActivateApplication(app_id.c_str(), verb_.c_str(), - AO_NOERRORUI, + AO_NONE, &pid); } else { AtlTrace("Activating for protocol\n"); @@ -388,6 +388,7 @@ HRESULT CommandExecuteImpl::LaunchDesktopChrome() { &proc_info); if (ret) { AtlTrace("Process id is %d\n", proc_info.dwProcessId); + AllowSetForegroundWindow(proc_info.dwProcessId); CloseHandle(proc_info.hProcess); CloseHandle(proc_info.hThread); } else { @@ -417,8 +418,15 @@ EC_HOST_UI_MODE CommandExecuteImpl::GetLaunchMode() { if (parameters_ == ASCIIToWide(switches::kForceImmersive)) { launch_mode = ECHUIM_IMMERSIVE; - AtlTrace("Launch mode forced to %s\n", modes[launch_mode]); launch_mode_determined = true; + } else if (parameters_ == ASCIIToWide(switches::kForceDesktop)) { + launch_mode = ECHUIM_DESKTOP; + launch_mode_determined = true; + } + + if (launch_mode_determined) { + parameters_.clear(); + AtlTrace("Launch mode forced to %s\n", modes[launch_mode]); return launch_mode; } diff --git a/win8/delegate_execute/delegate_execute.cc b/win8/delegate_execute/delegate_execute.cc index 9f3430c..249ad5b 100644 --- a/win8/delegate_execute/delegate_execute.cc +++ b/win8/delegate_execute/delegate_execute.cc @@ -11,8 +11,8 @@ #include "base/at_exit.h" #include "base/command_line.h" #include "base/file_util.h" +#include "base/process_util.h" #include "base/string16.h" -#include "base/string_number_conversions.h" #include "base/utf_string_conversions.h" #include "base/win/scoped_com_initializer.h" #include "base/win/scoped_handle.h" @@ -53,68 +53,74 @@ class DelegateExecuteModule DelegateExecuteModule _AtlModule; -// Relaunch metro Chrome by ShellExecute on |shortcut| with --force-immersive. -// |handle_value| is an optional handle on which this function will wait before -// performing the relaunch. -int RelaunchChrome(const FilePath& shortcut, const string16& handle_value) { - base::win::ScopedHandle handle; - - if (!handle_value.empty()) { - uint32 the_handle = 0; - if (!base::StringToUint(handle_value, &the_handle)) { - // Failed to parse the handle value. Skip the wait but proceed with the - // relaunch. - AtlTrace(L"Failed to parse handle value %ls\n", handle_value.c_str()); +using delegate_execute::DelegateExecuteOperation; +using base::win::ScopedHandle; + +int RelaunchChrome(const DelegateExecuteOperation& operation) { + AtlTrace("Relaunching [%ls] with flags [%s]\n", + operation.mutex().c_str(), operation.relaunch_flags()); + ScopedHandle mutex(OpenMutexW(SYNCHRONIZE, FALSE, operation.mutex().c_str())); + if (mutex.IsValid()) { + const int kWaitSeconds = 5; + DWORD result = ::WaitForSingleObject(mutex, kWaitSeconds * 1000); + if (result == WAIT_ABANDONED) { + // This is the normal case. Chrome exits and windows marks the mutex as + // abandoned. + } else if (result == WAIT_OBJECT_0) { + // This is unexpected. Check if somebody is not closing the mutex on + // RelaunchChromehelper, the mutex should not be closed. + AtlTrace("Unexpected release of the relaunch mutex!!\n"); + } else if (result == WAIT_TIMEOUT) { + // This could mean that Chrome is hung. Proceed to exterminate. + DWORD pid = operation.GetParentPid(); + AtlTrace("%ds timeout. Killing Chrome %d\n", kWaitSeconds, pid); + base::KillProcessById(pid, 0, false); } else { - handle.Set(reinterpret_cast<HANDLE>(the_handle)); + AtlTrace("Failed to wait for relaunch mutex, result is 0x%x\n", result); } - } - - if (handle.IsValid()) { - AtlTrace(L"Waiting for chrome.exe to exit.\n"); - DWORD result = ::WaitForSingleObject(handle, 10 * 1000); - AtlTrace(L"And we're back.\n"); - if (result != WAIT_OBJECT_0) { - AtlTrace(L"Failed to wait for parent to exit; result=%u.\n", result); - // This could mean that Chrome has hung. Conservatively proceed with - // the relaunch anyway. - } - handle.Close(); + } else { + // It is possible that chrome exits so fast that the mutex is not there. + AtlTrace("No relaunch mutex found\n"); } base::win::ScopedCOMInitializer com_initializer; - AtlTrace(L"Launching Chrome via %ls.\n", shortcut.value().c_str()); - int ser = reinterpret_cast<int>( - ::ShellExecute(NULL, NULL, shortcut.value().c_str(), - ASCIIToWide(switches::kForceImmersive).c_str(), NULL, - SW_SHOWNORMAL)); - AtlTrace(L"ShellExecute returned %d.\n", ser); - return ser <= 32; + string16 flags(ASCIIToWide(operation.relaunch_flags())); + SHELLEXECUTEINFO sei = { sizeof(sei) }; + sei.fMask = SEE_MASK_FLAG_LOG_USAGE; + sei.nShow = SW_SHOWNORMAL; + sei.lpFile = operation.shortcut().value().c_str(); + sei.lpParameters = flags.c_str(); + + AtlTrace(L"Relaunching Chrome via shortcut [%ls]\n", sei.lpFile); + + if (!::ShellExecuteExW(&sei)) { + int error = HRESULT_FROM_WIN32(::GetLastError()); + AtlTrace("ShellExecute returned 0x%08X\n", error); + return error; + } + return S_OK; } -// -extern "C" int WINAPI _tWinMain(HINSTANCE , HINSTANCE, - LPTSTR, int nShowCmd) { - using delegate_execute::DelegateExecuteOperation; +extern "C" int WINAPI _tWinMain(HINSTANCE , HINSTANCE, LPTSTR, int nShowCmd) { base::AtExitManager exit_manager; + AtlTrace("delegate_execute enter\n"); CommandLine::Init(0, NULL); - CommandLine* cmd_line = CommandLine::ForCurrentProcess(); + HRESULT ret_code = E_UNEXPECTED; DelegateExecuteOperation operation; - - operation.Initialize(cmd_line); - switch (operation.operation_type()) { - case DelegateExecuteOperation::EXE_MODULE: - return _AtlModule.WinMain(nShowCmd); - - case DelegateExecuteOperation::RELAUNCH_CHROME: - return RelaunchChrome(operation.relaunch_shortcut(), - cmd_line->GetSwitchValueNative(switches::kWaitForHandle)); - - default: - NOTREACHED(); + if (operation.Init(CommandLine::ForCurrentProcess())) { + switch (operation.operation_type()) { + case DelegateExecuteOperation::DELEGATE_EXECUTE: + ret_code = _AtlModule.WinMain(nShowCmd); + break; + case DelegateExecuteOperation::RELAUNCH_CHROME: + ret_code = RelaunchChrome(operation); + break; + default: + NOTREACHED(); + } } - - return 1; + AtlTrace("delegate_execute exit, code = %d\n", ret_code); + return ret_code; } diff --git a/win8/delegate_execute/delegate_execute_operation.cc b/win8/delegate_execute/delegate_execute_operation.cc index e6823f0..f2ba2c4 100644 --- a/win8/delegate_execute/delegate_execute_operation.cc +++ b/win8/delegate_execute/delegate_execute_operation.cc @@ -5,33 +5,49 @@ #include "win8/delegate_execute/delegate_execute_operation.h" #include "base/command_line.h" +#include "base/string_number_conversions.h" +#include "base/string_split.h" #include "chrome/common/chrome_switches.h" namespace delegate_execute { DelegateExecuteOperation::DelegateExecuteOperation() - : operation_type_(EXE_MODULE) { + : operation_type_(DELEGATE_EXECUTE), + relaunch_flags_("") { } DelegateExecuteOperation::~DelegateExecuteOperation() { - Clear(); } -void DelegateExecuteOperation::Initialize(const CommandLine* command_line) { - Clear(); - - // --relaunch-shortcut=PathToShortcut triggers the relaunch Chrome operation. - FilePath shortcut( - command_line->GetSwitchValuePath(switches::kRelaunchShortcut)); - if (!shortcut.empty()) { - relaunch_shortcut_ = shortcut; - operation_type_ = RELAUNCH_CHROME; +bool DelegateExecuteOperation::Init(const CommandLine* cmd_line) { + FilePath shortcut(cmd_line->GetSwitchValuePath(switches::kRelaunchShortcut)); + if (shortcut.empty()) { + operation_type_ = DELEGATE_EXECUTE; + return true; } + relaunch_shortcut_ = shortcut; + mutex_ = cmd_line->GetSwitchValueNative(switches::kWaitForMutex); + if (mutex_.empty()) + return false; + // Add the mode forcing flags, if any. + if (cmd_line->HasSwitch(switches::kForceDesktop)) + relaunch_flags_ = switches::kForceDesktop; + else if (cmd_line->HasSwitch(switches::kForceImmersive)) + relaunch_flags_ = switches::kForceImmersive; + + operation_type_ = RELAUNCH_CHROME; + return true; } -void DelegateExecuteOperation::Clear() { - operation_type_ = EXE_MODULE; - relaunch_shortcut_.clear(); +DWORD DelegateExecuteOperation::GetParentPid() const { + std::vector<string16> parts; + base::SplitString(mutex_, L'.', &parts); + if (parts.size() != 3) + return 0; + DWORD pid; + if (!base::StringToUint(parts[2], reinterpret_cast<uint32*>(&pid))) + return 0; + return pid; } } // namespace delegate_execute diff --git a/win8/delegate_execute/delegate_execute_operation.h b/win8/delegate_execute/delegate_execute_operation.h index 59acfd7a..f2f01cc 100644 --- a/win8/delegate_execute/delegate_execute_operation.h +++ b/win8/delegate_execute/delegate_execute_operation.h @@ -6,44 +6,70 @@ #define WIN8_DELEGATE_EXECUTE_DELEGATE_EXECUTE_OPERATION_H_ #include <atldef.h> +#include <windows.h> #include "base/basictypes.h" #include "base/file_path.h" +#include "base/string16.h" class CommandLine; namespace delegate_execute { // Parses a portion of the DelegateExecute handler's command line to determine -// the desired operation. +// the desired operation. The operation type is decided by looking at the +// command line. The operations are: +// DELEGATE_EXECUTE: +// When the delegate_execute.exe is invoked by windows when a chrome +// activation via the shell, possibly using ShellExecute. Control must +// be given to ATLs WinMain. +// RELAUNCH_CHROME: +// When the delegate_execute.exe is launched by chrome, when chrome needs +// to re-launch itself. The required command line parameters are: +// --relaunch-shortcut=<PathToShortcut> +// --wait-for-mutex=<MutexNamePid> +// The PathToShortcut must be the fully qualified file name to the chrome +// shortcut that has the appId and other 'metro ready' parameters. +// The MutexNamePid is a mutex name that also encodes the process id and +// must follow the format <A>.<B>.<pid> where A and B are arbitray strings +// (usually chrome.relaunch) and pid is the process id of chrome. class DelegateExecuteOperation { public: enum OperationType { - EXE_MODULE, + DELEGATE_EXECUTE, RELAUNCH_CHROME, }; DelegateExecuteOperation(); ~DelegateExecuteOperation(); - void Initialize(const CommandLine* command_line); + bool Init(const CommandLine* cmd_line); OperationType operation_type() const { return operation_type_; } - // Returns the argument to the --relaunch-shortcut switch. Valid only when - // the operation is RELAUNCH_CHROME. - const FilePath& relaunch_shortcut() const { - ATLASSERT(operation_type_ == RELAUNCH_CHROME); + const char* relaunch_flags() const { + return relaunch_flags_; + } + + const string16& mutex() const { + return mutex_; + } + + // Returns the process id of the parent or 0 on failure. + DWORD GetParentPid() const; + + const FilePath& shortcut() const { return relaunch_shortcut_; } private: - void Clear(); - OperationType operation_type_; + const char* relaunch_flags_; FilePath relaunch_shortcut_; + string16 mutex_; + DISALLOW_COPY_AND_ASSIGN(DelegateExecuteOperation); }; diff --git a/win8/metro_driver/chrome_app_view.cc b/win8/metro_driver/chrome_app_view.cc index 7d5580e..e2ec21a 100644 --- a/win8/metro_driver/chrome_app_view.cc +++ b/win8/metro_driver/chrome_app_view.cc @@ -56,8 +56,97 @@ const wchar_t kOSKClassName[] = L"IPTip_Main_Window"; static const int kOSKAdjustmentOffset = 20; +const wchar_t kChromeSubclassWindowProp[] = L"MetroChromeWindowProc"; + namespace { +enum Modifier { + NONE, + SHIFT = 1, + CONTROL = 2, + ALT = 4 +}; + +// Helper function to send keystrokes via the SendInput function. +// Params: +// mnemonic_char: The keystroke to be sent. +// modifiers: Combination with Alt, Ctrl, Shift, etc. +// extended: whether this is an extended key. +// unicode: whether this is a unicode key. +void SendMnemonic(WORD mnemonic_char, Modifier modifiers, bool extended, + bool unicode) { + INPUT keys[4] = {0}; // Keyboard events + int key_count = 0; // Number of generated events + + if (modifiers & SHIFT) { + keys[key_count].type = INPUT_KEYBOARD; + keys[key_count].ki.wVk = VK_SHIFT; + keys[key_count].ki.wScan = MapVirtualKey(VK_SHIFT, 0); + key_count++; + } + + if (modifiers & CONTROL) { + keys[key_count].type = INPUT_KEYBOARD; + keys[key_count].ki.wVk = VK_CONTROL; + keys[key_count].ki.wScan = MapVirtualKey(VK_CONTROL, 0); + key_count++; + } + + if (modifiers & ALT) { + keys[key_count].type = INPUT_KEYBOARD; + keys[key_count].ki.wVk = VK_MENU; + keys[key_count].ki.wScan = MapVirtualKey(VK_MENU, 0); + key_count++; + } + + keys[key_count].type = INPUT_KEYBOARD; + keys[key_count].ki.wVk = mnemonic_char; + keys[key_count].ki.wScan = MapVirtualKey(mnemonic_char, 0); + + if (extended) + keys[key_count].ki.dwFlags |= KEYEVENTF_EXTENDEDKEY; + if (unicode) + keys[key_count].ki.dwFlags |= KEYEVENTF_UNICODE; + key_count++; + + bool should_sleep = key_count > 1; + + // Send key downs + for (int i = 0; i < key_count; i++) { + SendInput(1, &keys[ i ], sizeof(keys[0])); + keys[i].ki.dwFlags |= KEYEVENTF_KEYUP; + if (should_sleep) { + Sleep(10); + } + } + + // Now send key ups in reverse order + for (int i = key_count; i; i--) { + SendInput(1, &keys[ i - 1 ], sizeof(keys[0])); + if (should_sleep) { + Sleep(10); + } + } +} + +void MetroExit() { + if (globals.core_window == ::GetForegroundWindow()) { + DVLOG(1) << "We are in the foreground. Exiting via Alt F4"; + SendMnemonic(VK_F4, ALT, false, false); + DWORD core_window_process_id = 0; + DWORD core_window_thread_id = GetWindowThreadProcessId( + globals.core_window, &core_window_process_id); + if (core_window_thread_id != ::GetCurrentThreadId()) { + // Sleep to give time to the core window thread to get this message. + Sleep(100); + } + } else { + DVLOG(1) << "We are not in the foreground. Exiting normally"; + globals.app_exit->Exit(); + globals.core_window = NULL; + } +} + void AdjustToFitWindow(HWND hwnd, int flags) { RECT rect = {0}; ::GetWindowRect(globals.core_window, &rect); @@ -69,6 +158,35 @@ void AdjustToFitWindow(HWND hwnd, int flags) { SWP_NOZORDER | flags); } +LRESULT CALLBACK ChromeWindowProc(HWND window, + UINT message, + WPARAM wp, + LPARAM lp) { + if (message == WM_SETCURSOR) { + // Override the WM_SETCURSOR message to avoid showing the resize cursor + // as the mouse moves to the edge of the screen. + switch (LOWORD(lp)) { + case HTBOTTOM: + case HTBOTTOMLEFT: + case HTBOTTOMRIGHT: + case HTLEFT: + case HTRIGHT: + case HTTOP: + case HTTOPLEFT: + case HTTOPRIGHT: + lp = MAKELPARAM(HTCLIENT, HIWORD(lp)); + break; + default: + break; + } + } + + WNDPROC old_proc = reinterpret_cast<WNDPROC>( + ::GetProp(window, kChromeSubclassWindowProp)); + DCHECK(old_proc); + return CallWindowProc(old_proc, window, message, wp, lp); +} + void AdjustFrameWindowStyleForMetro(HWND hwnd) { DVLOG(1) << __FUNCTION__; // Ajust the frame so the live preview works and the frame buttons dissapear. @@ -78,6 +196,14 @@ void AdjustFrameWindowStyleForMetro(HWND hwnd) { ::SetWindowLong(hwnd, GWL_EXSTYLE, ::GetWindowLong(hwnd, GWL_EXSTYLE) & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE)); + + // Subclass the wndproc of the frame window, if it's not already there. + if (::GetProp(hwnd, kChromeSubclassWindowProp) == NULL) { + WNDPROC old_chrome_proc = reinterpret_cast<WNDPROC>( + ::SetWindowLong(hwnd, GWL_WNDPROC, + reinterpret_cast<long>(ChromeWindowProc))); + ::SetProp(hwnd, kChromeSubclassWindowProp, old_chrome_proc); + } AdjustToFitWindow(hwnd, SWP_FRAMECHANGED | SWP_NOACTIVATE); } @@ -117,7 +243,7 @@ void CloseFrameWindowInternal(HWND hwnd) { } else { // time to quit DVLOG(1) << "Last host window closed. Calling Exit()."; - globals.app_exit->Exit(); + MetroExit(); } } @@ -486,8 +612,9 @@ DWORD WINAPI HostMainThreadProc(void*) { ::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(); + MetroExit(); return exit_code; } @@ -696,9 +823,11 @@ ChromeAppView::Run() { if (wr != WAIT_OBJECT_0) { DVLOG(1) << "Waiting for host thread failed : " << wr; } + + DVLOG(1) << "Host thread exited"; + ::CloseHandle(globals.host_thread); globals.host_thread = NULL; - return hr; } diff --git a/win8/metro_driver/chrome_url_launch_handler.cc b/win8/metro_driver/chrome_url_launch_handler.cc index 866bccc..7a9a607 100644 --- a/win8/metro_driver/chrome_url_launch_handler.cc +++ b/win8/metro_driver/chrome_url_launch_handler.cc @@ -11,7 +11,7 @@ #include <shlobj.h> #include <string> -#include "base/string_tokenizer.h" +#include "base/command_line.h" #include "winrt_utils.h" @@ -97,22 +97,18 @@ void ChromeUrlLaunchHandler::HandleProtocolLaunch( InitiateNavigationOrSearchRequest(globals.navigation_url.c_str(), 0); } -// The LaunchArgs are in a semi-color separated key_name=key_value list. At -// the moment the only key_name understaood is "url". +// |launch_args| is an encoded command line, minus the executable name. To +// find the URL to launch the first argument is used. If any other parameters +// are encoded in |launch_args| they are ignored. string16 ChromeUrlLaunchHandler::GetUrlFromLaunchArgs( const string16& launch_args) { - WStringTokenizer tokenizer(launch_args, L";="); - bool next_is_url = false; - while (tokenizer.GetNext()) { - if (next_is_url) - return tokenizer.token(); - if (tokenizer.token() == L"url") - next_is_url = true; - } - if (launch_args == L"opennewwindow") { - DVLOG(1) << "Returning new tab url"; - return L"chrome://newtab"; - } + string16 dummy_command_line(L"dummy.exe "); + dummy_command_line.append(launch_args); + CommandLine command_line = CommandLine::FromString(dummy_command_line); + CommandLine::StringVector args = command_line.GetArgs(); + if (args.size() > 0) + return args[0]; + return string16(); } diff --git a/win8/metro_driver/metro_driver.gyp b/win8/metro_driver/metro_driver.gyp index 186d2bd..94960cdf 100644 --- a/win8/metro_driver/metro_driver.gyp +++ b/win8/metro_driver/metro_driver.gyp @@ -31,6 +31,7 @@ 'type': 'shared_library', 'dependencies': [ '../../base/base.gyp:base', + '../../build/temp_gyp/googleurl.gyp:googleurl', '../../crypto/crypto.gyp:crypto', '../../sandbox/sandbox.gyp:sandbox', '../../google_update/google_update.gyp:google_update', diff --git a/win8/metro_driver/secondary_tile.cc b/win8/metro_driver/secondary_tile.cc index 8a54bd7..c784fdc 100644 --- a/win8/metro_driver/secondary_tile.cc +++ b/win8/metro_driver/secondary_tile.cc @@ -15,6 +15,7 @@ #include "base/string_number_conversions.h" #include "base/utf_string_conversions.h" #include "crypto/sha2.h" +#include "googleurl/src/gurl.h" #include "win8/metro_driver/chrome_app_view.h" #include "win8/metro_driver/winrt_utils.h" @@ -91,7 +92,11 @@ void CreateTileOnStartScreen(const string16& title_str, mswrw::HString id; id.Attach(MakeHString(GenerateTileId(url_str))); mswrw::HString args; - args.Attach(MakeHString(string16(L"url=").append(url_str))); + // The url is just passed into the tile agruments as is. Metro and desktop + // chrome will see the arguments as command line parameters. + // A GURL is used to ensure any spaces are properly escaped. + GURL url(url_str); + args.Attach(MakeHString(UTF8ToUTF16(url.spec()))); mswr::ComPtr<winfoundtn::IUriRuntimeClassFactory> uri_factory; hr = winrt_utils::CreateActivationFactory( |