blob: a8490aeacd038fb616280e84fc63aa89f036baea [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 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.
initial.commit09911bf2008-07-26 23:55:294
5#include "chrome/browser/external_tab_container.h"
6
[email protected]4a0765a2009-05-08 23:12:257#include "app/win_util.h"
initial.commit09911bf2008-07-26 23:55:298#include "base/logging.h"
[email protected]1eb89e82008-08-15 12:27:039#include "base/win_util.h"
initial.commit09911bf2008-07-26 23:55:2910#include "chrome/browser/automation/automation_provider.h"
[email protected]9f5b80a2009-04-08 01:26:0711#include "chrome/browser/browser.h"
[email protected]6dfed102009-04-28 03:09:5312#include "chrome/browser/extensions/extension_function_dispatcher.h"
[email protected]33ee8da2009-04-16 17:45:3713#include "chrome/browser/load_notification_details.h"
initial.commit09911bf2008-07-26 23:55:2914#include "chrome/browser/profile.h"
[email protected]2e39d2e2009-02-19 18:41:3115#include "chrome/browser/tab_contents/provisional_load_details.h"
[email protected]f3ec7742009-01-15 00:59:1616#include "chrome/browser/tab_contents/tab_contents.h"
[email protected]610d36a2009-05-22 23:00:3817#include "chrome/browser/views/tab_contents/tab_contents_container.h"
initial.commit09911bf2008-07-26 23:55:2918#include "chrome/common/chrome_constants.h"
[email protected]1c58a5c2009-05-21 18:47:1419#include "chrome/common/notification_service.h"
initial.commit09911bf2008-07-26 23:55:2920#include "chrome/test/automation/automation_messages.h"
initial.commit09911bf2008-07-26 23:55:2921
22static const wchar_t kWindowObjectKey[] = L"ChromeWindowObject";
23
24// TODO(sanjeevr): The external_accel_table_ and external_accel_entry_count_
25// member variables are now obsolete and we don't use them.
26// We need to remove them.
27ExternalTabContainer::ExternalTabContainer(
28 AutomationProvider* automation)
29 : automation_(automation),
initial.commit09911bf2008-07-26 23:55:2930 tab_contents_(NULL),
31 external_accel_table_(NULL),
32 external_accel_entry_count_(0),
[email protected]2e39d2e2009-02-19 18:41:3133 tab_contents_container_(NULL),
[email protected]eac83f02009-05-08 18:44:4434 tab_handle_(0),
[email protected]2e39d2e2009-02-19 18:41:3135 ignore_next_load_notification_(false) {
initial.commit09911bf2008-07-26 23:55:2936}
37
38ExternalTabContainer::~ExternalTabContainer() {
[email protected]9095e982009-05-27 17:28:2439 Uninitialize(GetNativeView());
initial.commit09911bf2008-07-26 23:55:2940}
41
[email protected]9095e982009-05-27 17:28:2442bool ExternalTabContainer::Init(Profile* profile,
43 HWND parent,
44 const gfx::Rect& bounds,
45 DWORD style) {
initial.commit09911bf2008-07-26 23:55:2946 if (IsWindow()) {
47 NOTREACHED();
48 return false;
49 }
[email protected]0498f7f82009-02-24 03:04:1250
[email protected]9095e982009-05-27 17:28:2451 set_window_style(WS_POPUP);
[email protected]08ed00a2009-05-28 20:48:1452 views::WidgetWin::Init(NULL, bounds, true);
53 if (!IsWindow()) {
54 NOTREACHED();
55 return false;
56 }
initial.commit09911bf2008-07-26 23:55:2957
58 // We don't ever remove the prop because the lifetime of this object
59 // is the same as the lifetime of the window
[email protected]9095e982009-05-27 17:28:2460 SetProp(GetNativeView(), kWindowObjectKey, this);
initial.commit09911bf2008-07-26 23:55:2961
[email protected]c2dacc92008-10-16 23:51:3862 views::FocusManager* focus_manager =
[email protected]9095e982009-05-27 17:28:2463 views::FocusManager::GetFocusManager(GetNativeView());
initial.commit09911bf2008-07-26 23:55:2964 focus_manager->AddKeystrokeListener(this);
[email protected]0498f7f82009-02-24 03:04:1265
[email protected]57c6a652009-05-04 07:58:3466 tab_contents_ = new TabContents(profile, NULL, MSG_ROUTING_NONE, NULL);
initial.commit09911bf2008-07-26 23:55:2967 tab_contents_->set_delegate(this);
[email protected]3ff34932009-04-07 16:48:0768 tab_contents_->render_view_host()->AllowExternalHostBindings();
[email protected]18cb2572008-08-21 20:34:4569
[email protected]610d36a2009-05-22 23:00:3870 // Create a TabContentsContainer to handle focus cycling using Tab and
initial.commit09911bf2008-07-26 23:55:2971 // Shift-Tab.
[email protected]610d36a2009-05-22 23:00:3872 tab_contents_container_ = new TabContentsContainer;
[email protected]9095e982009-05-27 17:28:2473 SetContentsView(tab_contents_container_);
74
[email protected]b9d227492009-02-10 15:20:2775 // Note that SetTabContents must be called after AddChildView is called
[email protected]610d36a2009-05-22 23:00:3876 tab_contents_container_->ChangeTabContents(tab_contents_);
initial.commit09911bf2008-07-26 23:55:2977
[email protected]ce3fa3c2009-04-20 19:55:5778 NavigationController* controller = &tab_contents_->controller();
[email protected]bfd04a62009-02-01 18:16:5679 registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
[email protected]0e8db942008-09-24 21:21:4880 Source<NavigationController>(controller));
[email protected]2e39d2e2009-02-19 18:41:3181 registrar_.Add(this, NotificationType::FAIL_PROVISIONAL_LOAD_WITH_ERROR,
82 Source<NavigationController>(controller));
[email protected]33ee8da2009-04-16 17:45:3783 registrar_.Add(this, NotificationType::LOAD_STOP,
84 Source<NavigationController>(controller));
[email protected]bfd04a62009-02-01 18:16:5685 NotificationService::current()->Notify(
86 NotificationType::EXTERNAL_TAB_CREATED,
87 Source<NavigationController>(controller),
88 NotificationService::NoDetails());
[email protected]31fb110522009-01-28 21:50:3989
[email protected]0498f7f82009-02-24 03:04:1290 // We need WS_POPUP to be on the window during initialization, but
91 // once initialized we apply the requested style which may or may not
92 // include the popup bit.
93 // Note that it's important to do this before we call SetParent since
94 // during the SetParent call we will otherwise get a WA_ACTIVATE call
95 // that causes us to steal the current focus.
[email protected]9095e982009-05-27 17:28:2496 SetWindowLong(GWL_STYLE, (GetWindowLong(GWL_STYLE) & ~WS_POPUP) | style);
[email protected]0498f7f82009-02-24 03:04:1297
[email protected]31fb110522009-01-28 21:50:3998 // Now apply the parenting and style
99 if (parent)
[email protected]9095e982009-05-27 17:28:24100 SetParent(GetNativeView(), parent);
[email protected]7e503122009-02-04 21:52:48101
[email protected]0498f7f82009-02-24 03:04:12102 ::ShowWindow(tab_contents_->GetNativeView(), SW_SHOWNA);
initial.commit09911bf2008-07-26 23:55:29103 return true;
104}
105
[email protected]9095e982009-05-27 17:28:24106void ExternalTabContainer::SetAccelerators(HACCEL accel_table,
107 int accel_table_entry_count) {
108 external_accel_table_ = accel_table;
109 external_accel_entry_count_ = accel_table_entry_count;
110}
[email protected]91d8fbcc2009-03-05 02:09:41111
[email protected]9095e982009-05-27 17:28:24112void ExternalTabContainer::ProcessUnhandledAccelerator(const MSG& msg) {
113 // We just received an accelerator key that we had sent to external host
114 // back. Since the external host was not interested in handling this, we
115 // need to dispatch this message as if we had just peeked this out. (we
116 // also need to call TranslateMessage to generate a WM_CHAR if needed).
117 TranslateMessage(&msg);
118 DispatchMessage(&msg);
119}
120
121void ExternalTabContainer::SetInitialFocus(bool reverse) {
122 DCHECK(tab_contents_);
initial.commit09911bf2008-07-26 23:55:29123 if (tab_contents_) {
[email protected]9095e982009-05-27 17:28:24124 static_cast<TabContents*>(tab_contents_)->Focus();
125 static_cast<TabContents*>(tab_contents_)->SetInitialFocus(reverse);
initial.commit09911bf2008-07-26 23:55:29126 }
initial.commit09911bf2008-07-26 23:55:29127}
128
[email protected]9095e982009-05-27 17:28:24129// static
130bool ExternalTabContainer::IsExternalTabContainer(HWND window) {
[email protected]5cdc8bd2009-05-27 23:01:21131 if (GetProp(window, kWindowObjectKey) != NULL)
132 return true;
133
134 return false;
initial.commit09911bf2008-07-26 23:55:29135}
136
[email protected]9095e982009-05-27 17:28:24137// static
138ExternalTabContainer* ExternalTabContainer::GetContainerForTab(
139 HWND tab_window) {
140 HWND parent_window = ::GetParent(tab_window);
141 if (!::IsWindow(parent_window)) {
142 return NULL;
initial.commit09911bf2008-07-26 23:55:29143 }
[email protected]9095e982009-05-27 17:28:24144 if (!IsExternalTabContainer(parent_window)) {
145 return NULL;
146 }
147 ExternalTabContainer* container = reinterpret_cast<ExternalTabContainer*>(
148 GetProp(parent_window, kWindowObjectKey));
149 return container;
initial.commit09911bf2008-07-26 23:55:29150}
151
[email protected]9095e982009-05-27 17:28:24152////////////////////////////////////////////////////////////////////////////////
153// ExternalTabContainer, TabContentsDelegate implementation:
[email protected]72baf6762009-05-06 18:45:33154
[email protected]e38f40152008-09-12 23:08:30155void ExternalTabContainer::OpenURLFromTab(TabContents* source,
156 const GURL& url,
[email protected]c0588052008-10-27 23:01:50157 const GURL& referrer,
[email protected]e38f40152008-09-12 23:08:30158 WindowOpenDisposition disposition,
159 PageTransition::Type transition) {
initial.commit09911bf2008-07-26 23:55:29160 switch (disposition) {
161 case CURRENT_TAB:
[email protected]fba16f52009-04-02 22:30:35162 case SINGLETON_TAB:
initial.commit09911bf2008-07-26 23:55:29163 case NEW_FOREGROUND_TAB:
164 case NEW_BACKGROUND_TAB:
165 case NEW_WINDOW:
166 if (automation_) {
[email protected]eac83f02009-05-08 18:44:44167 automation_->Send(new AutomationMsg_OpenURL(0, tab_handle_,
168 url, disposition));
initial.commit09911bf2008-07-26 23:55:29169 }
170 break;
171 default:
172 break;
[email protected]6dfed102009-04-28 03:09:53173 }
initial.commit09911bf2008-07-26 23:55:29174}
175
176void ExternalTabContainer::NavigationStateChanged(const TabContents* source,
[email protected]b9d227492009-02-10 15:20:27177 unsigned changed_flags) {
initial.commit09911bf2008-07-26 23:55:29178 if (automation_) {
[email protected]eac83f02009-05-08 18:44:44179 automation_->Send(new AutomationMsg_NavigationStateChanged(0, tab_handle_,
180 changed_flags));
initial.commit09911bf2008-07-26 23:55:29181 }
182}
183
initial.commit09911bf2008-07-26 23:55:29184void ExternalTabContainer::AddNewContents(TabContents* source,
185 TabContents* new_contents,
186 WindowOpenDisposition disposition,
187 const gfx::Rect& initial_pos,
188 bool user_gesture) {
[email protected]9f5b80a2009-04-08 01:26:07189 if (disposition == NEW_POPUP || disposition == NEW_WINDOW) {
190 Browser::BuildPopupWindowHelper(source, new_contents, initial_pos,
191 Browser::TYPE_POPUP,
192 tab_contents_->profile(), true);
193 } else {
194 NOTREACHED();
195 }
initial.commit09911bf2008-07-26 23:55:29196}
197
initial.commit09911bf2008-07-26 23:55:29198void ExternalTabContainer::ActivateContents(TabContents* contents) {
199}
200
201void ExternalTabContainer::LoadingStateChanged(TabContents* source) {
202}
203
204void ExternalTabContainer::CloseContents(TabContents* source) {
205}
206
[email protected]b9d227492009-02-10 15:20:27207void ExternalTabContainer::MoveContents(TabContents* source,
208 const gfx::Rect& pos) {
initial.commit09911bf2008-07-26 23:55:29209}
210
211bool ExternalTabContainer::IsPopup(TabContents* source) {
212 return false;
213}
214
[email protected]b9d227492009-02-10 15:20:27215void ExternalTabContainer::URLStarredChanged(TabContents* source,
216 bool starred) {
initial.commit09911bf2008-07-26 23:55:29217}
218
219void ExternalTabContainer::UpdateTargetURL(TabContents* source,
220 const GURL& url) {
221 if (automation_) {
222 std::wstring url_string = CA2W(url.spec().c_str());
223 automation_->Send(
[email protected]eac83f02009-05-08 18:44:44224 new AutomationMsg_UpdateTargetUrl(0, tab_handle_, url_string));
initial.commit09911bf2008-07-26 23:55:29225 }
226}
227
228void ExternalTabContainer::ContentsZoomChange(bool zoom_in) {
229}
230
231void ExternalTabContainer::ToolbarSizeChanged(TabContents* source,
[email protected]b9d227492009-02-10 15:20:27232 bool finished) {
initial.commit09911bf2008-07-26 23:55:29233}
234
[email protected]18cb2572008-08-21 20:34:45235void ExternalTabContainer::ForwardMessageToExternalHost(
[email protected]28790922009-03-09 19:48:37236 const std::string& message, const std::string& origin,
237 const std::string& target) {
[email protected]5e40e262008-08-15 20:33:28238 if(automation_) {
239 automation_->Send(
[email protected]eac83f02009-05-08 18:44:44240 new AutomationMsg_ForwardMessageToExternalHost(0, tab_handle_,
241 message, origin, target));
[email protected]5e40e262008-08-15 20:33:28242 }
243}
244
[email protected]9095e982009-05-27 17:28:24245ExtensionFunctionDispatcher* ExternalTabContainer::
246 CreateExtensionFunctionDispatcher(RenderViewHost* render_view_host,
247 const std::string& extension_id) {
248 return new ExtensionFunctionDispatcher(render_view_host, NULL, extension_id);
249}
250
[email protected]1e0a02d62009-04-23 22:55:56251bool ExternalTabContainer::TakeFocus(bool reverse) {
252 if (automation_) {
253 views::FocusManager* focus_manager =
254 views::FocusManager::GetFocusManager(GetNativeView());
255 DCHECK(focus_manager);
256 if (focus_manager) {
257 focus_manager->ClearFocus();
[email protected]eac83f02009-05-08 18:44:44258 automation_->Send(new AutomationMsg_TabbedOut(0, tab_handle_,
[email protected]1e0a02d62009-04-23 22:55:56259 win_util::IsShiftPressed()));
260 }
261 }
262
263 return true;
264}
265
[email protected]9095e982009-05-27 17:28:24266////////////////////////////////////////////////////////////////////////////////
267// ExternalTabContainer, NotificationObserver implementation:
268
initial.commit09911bf2008-07-26 23:55:29269void ExternalTabContainer::Observe(NotificationType type,
270 const NotificationSource& source,
271 const NotificationDetails& details) {
[email protected]33ee8da2009-04-16 17:45:37272 if (!automation_)
273 return;
274
[email protected]2e39d2e2009-02-19 18:41:31275 static const int kHttpClientErrorStart = 400;
276 static const int kHttpServerErrorEnd = 510;
277
[email protected]bfd04a62009-02-01 18:16:56278 switch (type.value) {
[email protected]33ee8da2009-04-16 17:45:37279 case NotificationType::LOAD_STOP: {
280 const LoadNotificationDetails* load =
281 Details<LoadNotificationDetails>(details).ptr();
[email protected]d86153f2009-05-18 21:10:52282 if (load != NULL && PageTransition::IsMainFrame(load->origin())) {
[email protected]eac83f02009-05-08 18:44:44283 automation_->Send(new AutomationMsg_TabLoaded(0, tab_handle_,
284 load->url()));
[email protected]33ee8da2009-04-16 17:45:37285 }
286 break;
[email protected]2e39d2e2009-02-19 18:41:31287 }
[email protected]33ee8da2009-04-16 17:45:37288 case NotificationType::NAV_ENTRY_COMMITTED: {
289 if (ignore_next_load_notification_) {
290 ignore_next_load_notification_ = false;
291 return;
292 }
[email protected]2e39d2e2009-02-19 18:41:31293
[email protected]0e8db942008-09-24 21:21:48294 const NavigationController::LoadCommittedDetails* commit =
295 Details<NavigationController::LoadCommittedDetails>(details).ptr();
296
[email protected]f0a51fb52009-03-05 12:46:38297 if (commit->http_status_code >= kHttpClientErrorStart &&
[email protected]2e39d2e2009-02-19 18:41:31298 commit->http_status_code <= kHttpServerErrorEnd) {
299 automation_->Send(new AutomationMsg_NavigationFailed(
[email protected]eac83f02009-05-08 18:44:44300 0, tab_handle_, commit->http_status_code, commit->entry->url()));
[email protected]2e39d2e2009-02-19 18:41:31301
302 ignore_next_load_notification_ = true;
303 } else {
304 // When the previous entry index is invalid, it will be -1, which
305 // will still make the computation come out right (navigating to the
306 // 0th entry will be +1).
307 automation_->Send(new AutomationMsg_DidNavigate(
[email protected]eac83f02009-05-08 18:44:44308 0, tab_handle_, commit->type,
[email protected]2e39d2e2009-02-19 18:41:31309 commit->previous_entry_index -
[email protected]ce3fa3c2009-04-20 19:55:57310 tab_contents_->controller().last_committed_entry_index(),
[email protected]dc7588ee2009-03-06 21:30:08311 commit->entry->url()));
[email protected]2e39d2e2009-02-19 18:41:31312 }
[email protected]33ee8da2009-04-16 17:45:37313 break;
[email protected]0e8db942008-09-24 21:21:48314 }
[email protected]2e39d2e2009-02-19 18:41:31315 case NotificationType::FAIL_PROVISIONAL_LOAD_WITH_ERROR: {
[email protected]33ee8da2009-04-16 17:45:37316 const ProvisionalLoadDetails* load_details =
317 Details<ProvisionalLoadDetails>(details).ptr();
318 automation_->Send(new AutomationMsg_NavigationFailed(
[email protected]eac83f02009-05-08 18:44:44319 0, tab_handle_, load_details->error_code(), load_details->url()));
[email protected]2e39d2e2009-02-19 18:41:31320
[email protected]33ee8da2009-04-16 17:45:37321 ignore_next_load_notification_ = true;
[email protected]2e39d2e2009-02-19 18:41:31322 break;
323 }
[email protected]0e8db942008-09-24 21:21:48324 default:
325 NOTREACHED();
326 }
initial.commit09911bf2008-07-26 23:55:29327}
328
[email protected]9095e982009-05-27 17:28:24329////////////////////////////////////////////////////////////////////////////////
330// ExternalTabContainer, views::WidgetWin overrides:
331
332void ExternalTabContainer::OnDestroy() {
333 Uninitialize(GetNativeView());
334 WidgetWin::OnDestroy();
initial.commit09911bf2008-07-26 23:55:29335}
336
[email protected]9095e982009-05-27 17:28:24337////////////////////////////////////////////////////////////////////////////////
338// ExternalTabContainer, views::KeystrokeListener implementation:
initial.commit09911bf2008-07-26 23:55:29339
[email protected]060254c2009-05-02 16:45:27340bool ExternalTabContainer::ProcessKeyStroke(HWND window, UINT message,
341 WPARAM wparam, LPARAM lparam) {
initial.commit09911bf2008-07-26 23:55:29342 if (!automation_) {
343 return false;
344 }
345 if ((wparam == VK_TAB) && !win_util::IsCtrlPressed()) {
346 // Tabs are handled separately (except if this is Ctrl-Tab or
347 // Ctrl-Shift-Tab)
348 return false;
349 }
[email protected]060254c2009-05-02 16:45:27350
351 unsigned int flags = HIWORD(lparam);
352 bool alt = (flags & KF_ALTDOWN) != 0;
353 if (!alt && (message == WM_SYSKEYUP || message == WM_KEYUP)) {
354 // In case the Alt key is being released.
355 alt = (wparam == VK_MENU);
356 }
357
358 if ((flags & KF_EXTENDED) || alt || (wparam >= VK_F1 && wparam <= VK_F24) ||
359 wparam == VK_ESCAPE || wparam == VK_RETURN ||
initial.commit09911bf2008-07-26 23:55:29360 win_util::IsShiftPressed() || win_util::IsCtrlPressed()) {
361 // If this is an extended key or if one or more of Alt, Shift and Control
362 // are pressed, this might be an accelerator that the external host wants
363 // to handle. If the host does not handle this accelerator, it will reflect
364 // the accelerator back to us via the ProcessUnhandledAccelerator method.
365 MSG msg = {0};
366 msg.hwnd = window;
367 msg.message = message;
368 msg.wParam = wparam;
369 msg.lParam = lparam;
[email protected]eac83f02009-05-08 18:44:44370 automation_->Send(new AutomationMsg_HandleAccelerator(0, tab_handle_, msg));
initial.commit09911bf2008-07-26 23:55:29371 return true;
372 }
[email protected]060254c2009-05-02 16:45:27373
initial.commit09911bf2008-07-26 23:55:29374 return false;
375}
376
[email protected]9095e982009-05-27 17:28:24377////////////////////////////////////////////////////////////////////////////////
378// ExternalTabContainer, private:
initial.commit09911bf2008-07-26 23:55:29379
[email protected]9095e982009-05-27 17:28:24380void ExternalTabContainer::Uninitialize(HWND window) {
381 if (::IsWindow(window)) {
382 views::FocusManager* focus_manager =
383 views::FocusManager::GetFocusManager(window);
384 if (focus_manager)
385 focus_manager->RemoveKeystrokeListener(this);
386 }
initial.commit09911bf2008-07-26 23:55:29387
[email protected]b9d227492009-02-10 15:20:27388 if (tab_contents_) {
[email protected]9095e982009-05-27 17:28:24389 NotificationService::current()->Notify(
390 NotificationType::EXTERNAL_TAB_CLOSED,
391 Source<NavigationController>(&tab_contents_->controller()),
392 Details<ExternalTabContainer>(this));
393
394 delete tab_contents_;
395 tab_contents_ = NULL;
[email protected]b9d227492009-02-10 15:20:27396 }
397}
398