[email protected] | 3b63f8f4 | 2011-03-28 01:54:15 | [diff] [blame] | 1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef CHROME_FRAME_CHROME_FRAME_PLUGIN_H_ |
| 6 | #define CHROME_FRAME_CHROME_FRAME_PLUGIN_H_ |
| 7 | |
[email protected] | bbfa9a1 | 2010-08-10 14:09:37 | [diff] [blame] | 8 | #include <string> |
| 9 | #include <vector> |
| 10 | |
[email protected] | 3b63f8f4 | 2011-03-28 01:54:15 | [diff] [blame] | 11 | #include "base/memory/ref_counted.h" |
[email protected] | a8e2058 | 2010-12-31 17:18:50 | [diff] [blame] | 12 | #include "base/win/win_util.h" |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 13 | #include "chrome_frame/chrome_frame_automation.h" |
[email protected] | bc73b4e5 | 2010-03-26 04:16:20 | [diff] [blame] | 14 | #include "chrome/common/chrome_paths.h" |
| 15 | #include "chrome/common/chrome_paths_internal.h" |
[email protected] | 36a26ed | 2010-03-24 03:09:05 | [diff] [blame] | 16 | #include "chrome_frame/simple_resource_loader.h" |
[email protected] | 0753db59 | 2010-12-15 14:45:05 | [diff] [blame] | 17 | #include "chrome_frame/navigation_constraints.h" |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 18 | #include "chrome_frame/utils.h" |
[email protected] | 36a26ed | 2010-03-24 03:09:05 | [diff] [blame] | 19 | #include "grit/chromium_strings.h" |
| 20 | |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 21 | #define IDC_ABOUT_CHROME_FRAME 40018 |
| 22 | |
[email protected] | a22f7e0 | 2011-02-09 07:15:35 | [diff] [blame] | 23 | // Helper so that this file doesn't include the messages header. |
| 24 | void ChromeFramePluginGetParamsCoordinates( |
| 25 | const MiniContextMenuParams& params, |
| 26 | int* x, |
| 27 | int* y); |
| 28 | |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 29 | // A class to implement common functionality for all types of |
[email protected] | 99d81e5b | 2011-06-29 02:29:53 | [diff] [blame] | 30 | // plugins: ActiveX and ActiveDoc |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 31 | template <typename T> |
[email protected] | 0753db59 | 2010-12-15 14:45:05 | [diff] [blame] | 32 | class ChromeFramePlugin |
| 33 | : public ChromeFrameDelegateImpl, |
| 34 | public NavigationConstraintsImpl { |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 35 | public: |
[email protected] | 0753db59 | 2010-12-15 14:45:05 | [diff] [blame] | 36 | ChromeFramePlugin() : ignore_setfocus_(false){ |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 37 | } |
| 38 | ~ChromeFramePlugin() { |
| 39 | Uninitialize(); |
| 40 | } |
| 41 | |
[email protected] | 045229a7 | 2010-03-03 22:11:19 | [diff] [blame] | 42 | BEGIN_MSG_MAP(T) |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 43 | MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) |
| 44 | MESSAGE_HANDLER(WM_SIZE, OnSize) |
| 45 | MESSAGE_HANDLER(WM_PARENTNOTIFY, OnParentNotify) |
| 46 | END_MSG_MAP() |
| 47 | |
| 48 | bool Initialize() { |
[email protected] | 2b9a9f16 | 2010-10-19 20:30:45 | [diff] [blame] | 49 | DVLOG(1) << __FUNCTION__; |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 50 | DCHECK(!automation_client_.get()); |
[email protected] | b0febbf | 2009-11-12 17:49:35 | [diff] [blame] | 51 | automation_client_ = CreateAutomationClient(); |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 52 | if (!automation_client_.get()) { |
| 53 | NOTREACHED() << "new ChromeFrameAutomationClient"; |
| 54 | return false; |
| 55 | } |
| 56 | |
| 57 | return true; |
| 58 | } |
| 59 | |
| 60 | void Uninitialize() { |
[email protected] | 2b9a9f16 | 2010-10-19 20:30:45 | [diff] [blame] | 61 | DVLOG(1) << __FUNCTION__; |
[email protected] | 045229a7 | 2010-03-03 22:11:19 | [diff] [blame] | 62 | if (IsValid()) { |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 63 | automation_client_->Uninitialize(); |
[email protected] | b0febbf | 2009-11-12 17:49:35 | [diff] [blame] | 64 | automation_client_ = NULL; |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 65 | } |
| 66 | } |
| 67 | |
| 68 | bool InitializeAutomation(const std::wstring& profile_name, |
| 69 | const std::wstring& extra_chrome_arguments, |
[email protected] | e150e82 | 2010-06-03 23:10:55 | [diff] [blame] | 70 | bool incognito, bool is_widget_mode, |
[email protected] | 9eeb35e | 2010-09-30 21:38:50 | [diff] [blame] | 71 | const GURL& url, const GURL& referrer, |
| 72 | bool route_all_top_level_navigations) { |
[email protected] | 045229a7 | 2010-03-03 22:11:19 | [diff] [blame] | 73 | DCHECK(IsValid()); |
[email protected] | bbfa9a1 | 2010-08-10 14:09:37 | [diff] [blame] | 74 | DCHECK(launch_params_ == NULL); |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 75 | // We don't want to do incognito when privileged, since we're |
| 76 | // running in browser chrome or some other privileged context. |
[email protected] | 0753db59 | 2010-12-15 14:45:05 | [diff] [blame] | 77 | bool incognito_mode = !is_privileged() && incognito; |
[email protected] | bc73b4e5 | 2010-03-26 04:16:20 | [diff] [blame] | 78 | FilePath profile_path; |
| 79 | GetProfilePath(profile_name, &profile_path); |
[email protected] | 1d27bbe | 2010-09-10 00:32:06 | [diff] [blame] | 80 | // The profile name could change based on the browser version. For e.g. for |
| 81 | // IE6/7 the profile is created in a different folder whose last component |
| 82 | // is Google Chrome Frame. |
| 83 | FilePath actual_profile_name = profile_path.BaseName(); |
[email protected] | bbfa9a1 | 2010-08-10 14:09:37 | [diff] [blame] | 84 | launch_params_ = new ChromeFrameLaunchParams(url, referrer, profile_path, |
[email protected] | 6ae3d49 | 2010-10-20 14:01:21 | [diff] [blame] | 85 | actual_profile_name.value(), SimpleResourceLoader::GetLanguage(), |
| 86 | extra_chrome_arguments, incognito_mode, is_widget_mode, |
| 87 | route_all_top_level_navigations); |
[email protected] | bbfa9a1 | 2010-08-10 14:09:37 | [diff] [blame] | 88 | return automation_client_->Initialize(this, launch_params_); |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 89 | } |
| 90 | |
| 91 | // ChromeFrameDelegate implementation |
| 92 | virtual WindowType GetWindow() const { |
| 93 | return (static_cast<const T*>(this))->m_hWnd; |
| 94 | } |
| 95 | |
| 96 | virtual void GetBounds(RECT* bounds) { |
| 97 | if (bounds) { |
| 98 | if (::IsWindow(GetWindow())) { |
| 99 | (static_cast<T*>(this))->GetClientRect(bounds); |
| 100 | } |
| 101 | } |
| 102 | } |
| 103 | virtual std::string GetDocumentUrl() { |
| 104 | return document_url_; |
| 105 | } |
| 106 | virtual void OnAutomationServerReady() { |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 107 | } |
| 108 | |
| 109 | virtual bool IsValid() const { |
| 110 | return automation_client_.get() != NULL; |
| 111 | } |
| 112 | |
[email protected] | 2b19e2fe | 2010-02-16 02:24:18 | [diff] [blame] | 113 | virtual void OnHostMoved() { |
[email protected] | 045229a7 | 2010-03-03 22:11:19 | [diff] [blame] | 114 | if (IsValid()) |
| 115 | automation_client_->OnChromeFrameHostMoved(); |
[email protected] | 2b19e2fe | 2010-02-16 02:24:18 | [diff] [blame] | 116 | } |
| 117 | |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 118 | protected: |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 119 | virtual void OnNavigationFailed(int error_code, const GURL& gurl) { |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 120 | OnLoadFailed(error_code, gurl.spec()); |
| 121 | } |
| 122 | |
[email protected] | b516e2d | 2011-07-12 16:54:12 | [diff] [blame] | 123 | virtual void OnHandleContextMenu(const ContextMenuModel& menu_model, |
[email protected] | 35f13ab | 2009-12-16 23:59:17 | [diff] [blame] | 124 | int align_flags, |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 125 | const MiniContextMenuParams& params) { |
[email protected] | b516e2d | 2011-07-12 16:54:12 | [diff] [blame] | 126 | if (!automation_client_.get()) { |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 127 | NOTREACHED(); |
| 128 | return; |
| 129 | } |
| 130 | |
[email protected] | b516e2d | 2011-07-12 16:54:12 | [diff] [blame] | 131 | HMENU menu = BuildContextMenu(menu_model); |
| 132 | if (!menu) |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 133 | return; |
| 134 | |
[email protected] | 4e676aa | 2010-02-12 18:19:07 | [diff] [blame] | 135 | T* self = static_cast<T*>(this); |
[email protected] | b516e2d | 2011-07-12 16:54:12 | [diff] [blame] | 136 | if (self->PreProcessContextMenu(menu)) { |
[email protected] | 4e676aa | 2010-02-12 18:19:07 | [diff] [blame] | 137 | // In order for the context menu to handle keyboard input, give the |
| 138 | // ActiveX window focus. |
| 139 | ignore_setfocus_ = true; |
| 140 | SetFocus(GetWindow()); |
| 141 | ignore_setfocus_ = false; |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 142 | UINT flags = align_flags | TPM_LEFTBUTTON | TPM_RETURNCMD | TPM_RECURSE; |
[email protected] | a22f7e0 | 2011-02-09 07:15:35 | [diff] [blame] | 143 | int x, y; |
| 144 | ChromeFramePluginGetParamsCoordinates(params, &x, &y); |
[email protected] | b516e2d | 2011-07-12 16:54:12 | [diff] [blame] | 145 | UINT selected = TrackPopupMenuEx(menu, flags, x, y, GetWindow(), NULL); |
[email protected] | 4e676aa | 2010-02-12 18:19:07 | [diff] [blame] | 146 | // Menu is over now give focus back to chrome |
[email protected] | 1fd4569 | 2010-04-19 21:01:18 | [diff] [blame] | 147 | GiveFocusToChrome(false); |
[email protected] | 045229a7 | 2010-03-03 22:11:19 | [diff] [blame] | 148 | if (IsValid() && selected != 0 && |
| 149 | !self->HandleContextMenuCommand(selected, params)) { |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 150 | automation_client_->SendContextMenuCommandToChromeFrame(selected); |
| 151 | } |
| 152 | } |
| 153 | |
[email protected] | b516e2d | 2011-07-12 16:54:12 | [diff] [blame] | 154 | DestroyMenu(menu); |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 155 | } |
| 156 | |
| 157 | LRESULT OnSetFocus(UINT message, WPARAM wparam, LPARAM lparam, |
| 158 | BOOL& handled) { // NO_LINT |
[email protected] | 045229a7 | 2010-03-03 22:11:19 | [diff] [blame] | 159 | if (!ignore_setfocus_ && IsValid()) { |
[email protected] | 26edf1d | 2010-10-13 17:53:04 | [diff] [blame] | 160 | // Pass false to |restore_focus_view|, because we do not want Chrome |
| 161 | // to focus the first focusable element in the current view, only the |
| 162 | // view itself. |
| 163 | GiveFocusToChrome(false); |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 164 | } |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 165 | return 0; |
| 166 | } |
| 167 | |
| 168 | LRESULT OnSize(UINT message, WPARAM wparam, LPARAM lparam, |
| 169 | BOOL& handled) { // NO_LINT |
| 170 | handled = FALSE; |
| 171 | // When we get resized, we need to resize the external tab window too. |
[email protected] | 045229a7 | 2010-03-03 22:11:19 | [diff] [blame] | 172 | if (IsValid()) |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 173 | automation_client_->Resize(LOWORD(lparam), HIWORD(lparam), |
| 174 | SWP_NOACTIVATE | SWP_NOZORDER); |
| 175 | return 0; |
| 176 | } |
| 177 | |
| 178 | LRESULT OnParentNotify(UINT message, WPARAM wparam, LPARAM lparam, |
| 179 | BOOL& handled) { // NO_LINT |
| 180 | switch (LOWORD(wparam)) { |
| 181 | case WM_LBUTTONDOWN: |
| 182 | case WM_MBUTTONDOWN: |
| 183 | case WM_RBUTTONDOWN: |
| 184 | case WM_XBUTTONDOWN: { |
| 185 | // If we got activated via mouse click on the external tab, |
| 186 | // we need to update the state of this thread and tell the |
| 187 | // browser that we now have the focus. |
| 188 | HWND focus = ::GetFocus(); |
| 189 | HWND plugin_window = GetWindow(); |
[email protected] | 01e79d8 | 2010-09-07 20:34:42 | [diff] [blame] | 190 | |
| 191 | // The Chrome-Frame instance may have launched a popup which currently |
| 192 | // has focus. Because experimental extension popups are top-level |
| 193 | // windows, we have to check that the focus has shifted to a window |
| 194 | // that does not share the same GA_ROOTOWNER as the plugin. |
| 195 | if (focus != plugin_window && |
| 196 | ::GetAncestor(plugin_window, GA_ROOTOWNER) != |
| 197 | ::GetAncestor(focus, GA_ROOTOWNER)) { |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 198 | ignore_setfocus_ = true; |
| 199 | SetFocus(plugin_window); |
| 200 | ignore_setfocus_ = false; |
| 201 | } |
| 202 | break; |
| 203 | } |
| 204 | } |
| 205 | |
| 206 | return 0; |
| 207 | } |
| 208 | |
| 209 | // Return true if context menu should be displayed. The menu could be |
| 210 | // modified as well (enable/disable commands, add/remove items). |
| 211 | // Override in most-derived class if needed. |
| 212 | bool PreProcessContextMenu(HMENU menu) { |
[email protected] | 50f5316 | 2009-10-23 19:16:20 | [diff] [blame] | 213 | // Add an "About" item. |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 214 | AppendMenu(menu, MF_STRING, IDC_ABOUT_CHROME_FRAME, |
[email protected] | 36a26ed | 2010-03-24 03:09:05 | [diff] [blame] | 215 | SimpleResourceLoader::Get(IDS_CHROME_FRAME_MENU_ABOUT).c_str()); |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 216 | return true; |
| 217 | } |
| 218 | |
| 219 | // Return true if menu command is processed, otherwise the command will be |
| 220 | // passed to Chrome for execution. Override in most-derived class if needed. |
[email protected] | e150e82 | 2010-06-03 23:10:55 | [diff] [blame] | 221 | bool HandleContextMenuCommand(UINT cmd, |
[email protected] | f5494d4 | 2010-12-23 22:15:34 | [diff] [blame] | 222 | const MiniContextMenuParams& params) { |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 223 | return false; |
| 224 | } |
| 225 | |
| 226 | // Allow overriding the type of automation client used, for unit tests. |
| 227 | virtual ChromeFrameAutomationClient* CreateAutomationClient() { |
| 228 | return new ChromeFrameAutomationClient; |
| 229 | } |
| 230 | |
[email protected] | 1fd4569 | 2010-04-19 21:01:18 | [diff] [blame] | 231 | void GiveFocusToChrome(bool restore_focus_to_view) { |
[email protected] | 045229a7 | 2010-03-03 22:11:19 | [diff] [blame] | 232 | if (IsValid()) { |
| 233 | TabProxy* tab = automation_client_->tab(); |
| 234 | HWND chrome_window = automation_client_->tab_window(); |
| 235 | if (tab && ::IsWindow(chrome_window)) { |
[email protected] | 2b9a9f16 | 2010-10-19 20:30:45 | [diff] [blame] | 236 | DVLOG(1) << "Setting initial focus"; |
[email protected] | a8e2058 | 2010-12-31 17:18:50 | [diff] [blame] | 237 | tab->SetInitialFocus(base::win::IsShiftPressed(), restore_focus_to_view); |
[email protected] | 045229a7 | 2010-03-03 22:11:19 | [diff] [blame] | 238 | } |
[email protected] | b95f550f | 2009-11-19 05:35:22 | [diff] [blame] | 239 | } |
| 240 | } |
| 241 | |
[email protected] | bc73b4e5 | 2010-03-26 04:16:20 | [diff] [blame] | 242 | virtual void GetProfilePath(const std::wstring& profile_name, |
| 243 | FilePath* profile_path) { |
| 244 | chrome::GetChromeFrameUserDataDirectory(profile_path); |
| 245 | *profile_path = profile_path->Append(profile_name); |
[email protected] | 2b9a9f16 | 2010-10-19 20:30:45 | [diff] [blame] | 246 | DVLOG(1) << __FUNCTION__ << ": " << profile_path->value(); |
[email protected] | bc73b4e5 | 2010-03-26 04:16:20 | [diff] [blame] | 247 | } |
| 248 | |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 249 | protected: |
| 250 | // Our gateway to chrome land |
[email protected] | b0febbf | 2009-11-12 17:49:35 | [diff] [blame] | 251 | scoped_refptr<ChromeFrameAutomationClient> automation_client_; |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 252 | |
[email protected] | bbfa9a1 | 2010-08-10 14:09:37 | [diff] [blame] | 253 | // How we launched Chrome. |
| 254 | scoped_refptr<ChromeFrameLaunchParams> launch_params_; |
| 255 | |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 256 | // Url of the containing document. |
| 257 | std::string document_url_; |
| 258 | |
| 259 | // We set this flag when we're taking the focus ourselves |
| 260 | // and notifying the host browser that we're doing so. |
| 261 | // When the flag is not set, we transfer the focus to chrome. |
| 262 | bool ignore_setfocus_; |
[email protected] | f781782 | 2009-09-24 05:11:58 | [diff] [blame] | 263 | }; |
| 264 | |
| 265 | #endif // CHROME_FRAME_CHROME_FRAME_PLUGIN_H_ |