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 #ifndef CHROME_FRAME_CHROME_FRAME_PLUGIN_H_
6 #define CHROME_FRAME_CHROME_FRAME_PLUGIN_H_
11 #include "base/memory/ref_counted.h"
12 #include "base/win/win_util.h"
13 #include "chrome_frame/chrome_frame_automation.h"
14 #include "chrome/common/chrome_paths.h"
15 #include "chrome/common/chrome_paths_internal.h"
16 #include "chrome_frame/simple_resource_loader.h"
17 #include "chrome_frame/navigation_constraints.h"
18 #include "chrome_frame/utils.h"
19 #include "grit/chromium_strings.h"
21 #define IDC_ABOUT_CHROME_FRAME 40018
23 // Helper so that this file doesn't include the messages header.
24 void ChromeFramePluginGetParamsCoordinates(
25 const MiniContextMenuParams
& params
,
29 // A class to implement common functionality for all types of
30 // plugins: ActiveX and ActiveDoc
32 class ChromeFramePlugin
33 : public ChromeFrameDelegateImpl
,
34 public NavigationConstraintsImpl
{
36 ChromeFramePlugin() : ignore_setfocus_(false){
38 ~ChromeFramePlugin() {
43 MESSAGE_HANDLER(WM_SETFOCUS
, OnSetFocus
)
44 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
45 MESSAGE_HANDLER(WM_PARENTNOTIFY
, OnParentNotify
)
49 DVLOG(1) << __FUNCTION__
;
50 DCHECK(!automation_client_
.get());
51 automation_client_
= CreateAutomationClient();
52 if (!automation_client_
.get()) {
53 NOTREACHED() << "new ChromeFrameAutomationClient";
61 DVLOG(1) << __FUNCTION__
;
63 automation_client_
->Uninitialize();
64 automation_client_
= NULL
;
68 bool InitializeAutomation(const std::wstring
& profile_name
,
69 bool incognito
, bool is_widget_mode
,
70 const GURL
& url
, const GURL
& referrer
,
71 bool route_all_top_level_navigations
) {
73 DCHECK(launch_params_
== NULL
);
74 // We don't want to do incognito when privileged, since we're
75 // running in browser chrome or some other privileged context.
76 bool incognito_mode
= !is_privileged() && incognito
;
77 base::FilePath profile_path
;
78 GetProfilePath(profile_name
, &profile_path
);
79 // The profile name could change based on the browser version. For e.g. for
80 // IE6/7 the profile is created in a different folder whose last component
81 // is Google Chrome Frame.
82 base::FilePath actual_profile_name
= profile_path
.BaseName();
83 launch_params_
= new ChromeFrameLaunchParams(url
, referrer
, profile_path
,
84 actual_profile_name
.value(), SimpleResourceLoader::GetLanguage(),
85 incognito_mode
, is_widget_mode
, route_all_top_level_navigations
);
86 return automation_client_
->Initialize(this, launch_params_
);
89 // ChromeFrameDelegate implementation
90 virtual WindowType
GetWindow() const {
91 return (static_cast<const T
*>(this))->m_hWnd
;
94 virtual void GetBounds(RECT
* bounds
) {
96 if (::IsWindow(GetWindow())) {
97 (static_cast<T
*>(this))->GetClientRect(bounds
);
101 virtual std::string
GetDocumentUrl() {
102 return document_url_
;
104 virtual void OnAutomationServerReady() {
107 virtual bool IsValid() const {
108 return automation_client_
.get() != NULL
;
111 virtual void OnHostMoved() {
113 automation_client_
->OnChromeFrameHostMoved();
117 virtual void OnNavigationFailed(int error_code
, const GURL
& gurl
) {
118 OnLoadFailed(error_code
, gurl
.spec());
121 virtual void OnHandleContextMenu(const ContextMenuModel
& menu_model
,
123 const MiniContextMenuParams
& params
) {
124 if (!automation_client_
.get()) {
129 HMENU menu
= BuildContextMenu(menu_model
);
133 T
* self
= static_cast<T
*>(this);
134 if (self
->PreProcessContextMenu(menu
)) {
135 // In order for the context menu to handle keyboard input, give the
136 // ActiveX window focus.
137 ignore_setfocus_
= true;
138 SetFocus(GetWindow());
139 ignore_setfocus_
= false;
140 UINT flags
= align_flags
| TPM_LEFTBUTTON
| TPM_RETURNCMD
| TPM_RECURSE
;
142 ChromeFramePluginGetParamsCoordinates(params
, &x
, &y
);
143 UINT selected
= TrackPopupMenuEx(menu
, flags
, x
, y
, GetWindow(), NULL
);
144 // Menu is over now give focus back to chrome
145 GiveFocusToChrome(false);
146 if (IsValid() && selected
!= 0 &&
147 !self
->HandleContextMenuCommand(selected
, params
)) {
148 automation_client_
->SendContextMenuCommandToChromeFrame(selected
);
155 LRESULT
OnSetFocus(UINT message
, WPARAM wparam
, LPARAM lparam
,
156 BOOL
& handled
) { // NO_LINT
157 if (!ignore_setfocus_
&& IsValid()) {
158 // Pass false to |restore_focus_view|, because we do not want Chrome
159 // to focus the first focusable element in the current view, only the
161 GiveFocusToChrome(false);
166 LRESULT
OnSize(UINT message
, WPARAM wparam
, LPARAM lparam
,
167 BOOL
& handled
) { // NO_LINT
169 // When we get resized, we need to resize the external tab window too.
171 automation_client_
->Resize(LOWORD(lparam
), HIWORD(lparam
),
172 SWP_NOACTIVATE
| SWP_NOZORDER
);
176 LRESULT
OnParentNotify(UINT message
, WPARAM wparam
, LPARAM lparam
,
177 BOOL
& handled
) { // NO_LINT
178 switch (LOWORD(wparam
)) {
182 case WM_XBUTTONDOWN
: {
183 // If we got activated via mouse click on the external tab,
184 // we need to update the state of this thread and tell the
185 // browser that we now have the focus.
186 HWND focus
= ::GetFocus();
187 HWND plugin_window
= GetWindow();
189 // The Chrome-Frame instance may have launched a popup which currently
190 // has focus. Because experimental extension popups are top-level
191 // windows, we have to check that the focus has shifted to a window
192 // that does not share the same GA_ROOTOWNER as the plugin.
193 if (focus
!= plugin_window
&&
194 ::GetAncestor(plugin_window
, GA_ROOTOWNER
) !=
195 ::GetAncestor(focus
, GA_ROOTOWNER
)) {
196 ignore_setfocus_
= true;
197 SetFocus(plugin_window
);
198 ignore_setfocus_
= false;
207 // Return true if context menu should be displayed. The menu could be
208 // modified as well (enable/disable commands, add/remove items).
209 // Override in most-derived class if needed.
210 bool PreProcessContextMenu(HMENU menu
) {
211 // Add an "About" item.
212 AppendMenu(menu
, MF_STRING
, IDC_ABOUT_CHROME_FRAME
,
213 SimpleResourceLoader::Get(IDS_CHROME_FRAME_MENU_ABOUT
).c_str());
217 // Return true if menu command is processed, otherwise the command will be
218 // passed to Chrome for execution. Override in most-derived class if needed.
219 bool HandleContextMenuCommand(UINT cmd
,
220 const MiniContextMenuParams
& params
) {
224 // Allow overriding the type of automation client used, for unit tests.
225 virtual ChromeFrameAutomationClient
* CreateAutomationClient() {
226 return new ChromeFrameAutomationClient
;
229 void GiveFocusToChrome(bool restore_focus_to_view
) {
231 TabProxy
* tab
= automation_client_
->tab();
232 HWND chrome_window
= automation_client_
->tab_window();
233 if (tab
&& ::IsWindow(chrome_window
)) {
234 DVLOG(1) << "Setting initial focus";
235 tab
->SetInitialFocus(base::win::IsShiftPressed(), restore_focus_to_view
);
240 virtual void GetProfilePath(const std::wstring
& profile_name
,
241 base::FilePath
* profile_path
) {
242 return GetChromeFrameProfilePath(profile_name
, profile_path
);
246 // Our gateway to chrome land
247 scoped_refptr
<ChromeFrameAutomationClient
> automation_client_
;
249 // How we launched Chrome.
250 scoped_refptr
<ChromeFrameLaunchParams
> launch_params_
;
252 // Url of the containing document.
253 std::string document_url_
;
255 // We set this flag when we're taking the focus ourselves
256 // and notifying the host browser that we're doing so.
257 // When the flag is not set, we transfer the focus to chrome.
258 bool ignore_setfocus_
;
261 #endif // CHROME_FRAME_CHROME_FRAME_PLUGIN_H_