summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/automation/automation_provider.cc3
-rw-r--r--chrome/browser/automation/automation_provider.h3
-rw-r--r--chrome/browser/automation/automation_provider_win.cc5
-rw-r--r--chrome/browser/external_tab_container_win.cc68
-rw-r--r--chrome/browser/external_tab_container_win.h31
-rw-r--r--chrome/test/automation/automation_messages_internal.h8
-rw-r--r--chrome_frame/chrome_active_document.cc13
-rw-r--r--chrome_frame/chrome_active_document.h7
-rw-r--r--chrome_frame/chrome_frame_activex_base.h37
-rw-r--r--chrome_frame/chrome_frame_automation.cc32
-rw-r--r--chrome_frame/chrome_frame_automation.h8
-rw-r--r--chrome_frame/custom_sync_call_context.h26
-rw-r--r--chrome_frame/utils.cc34
-rw-r--r--chrome_frame/utils.h4
14 files changed, 175 insertions, 104 deletions
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc
index 664c639..a7a59ad 100644
--- a/chrome/browser/automation/automation_provider.cc
+++ b/chrome/browser/automation/automation_provider.cc
@@ -381,7 +381,8 @@ void AutomationProvider::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(AutomationMsg_HandleMessageFromExternalHost,
OnMessageFromExternalHost)
IPC_MESSAGE_HANDLER(AutomationMsg_BrowserMove, OnBrowserMoved)
- IPC_MESSAGE_HANDLER(AutomationMsg_RunUnloadHandlers, OnRunUnloadHandlers)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_RunUnloadHandlers,
+ OnRunUnloadHandlers)
IPC_MESSAGE_HANDLER(AutomationMsg_SetZoomLevel, OnSetZoomLevel)
#endif // defined(OS_WIN)
#if defined(OS_CHROMEOS)
diff --git a/chrome/browser/automation/automation_provider.h b/chrome/browser/automation/automation_provider.h
index 2ad6dea..233a8c7 100644
--- a/chrome/browser/automation/automation_provider.h
+++ b/chrome/browser/automation/automation_provider.h
@@ -361,8 +361,7 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>,
void OnBrowserMoved(int handle);
- void OnRunUnloadHandlers(int handle, gfx::NativeWindow notification_window,
- int notification_message);
+ void OnRunUnloadHandlers(int handle, IPC::Message* reply_message);
void OnSetZoomLevel(int handle, int zoom_level);
diff --git a/chrome/browser/automation/automation_provider_win.cc b/chrome/browser/automation/automation_provider_win.cc
index 86dfec1..98ee218 100644
--- a/chrome/browser/automation/automation_provider_win.cc
+++ b/chrome/browser/automation/automation_provider_win.cc
@@ -527,11 +527,10 @@ void AutomationProvider::NavigateExternalTabAtIndex(
}
void AutomationProvider::OnRunUnloadHandlers(
- int handle, gfx::NativeWindow notification_window,
- int notification_message) {
+ int handle, IPC::Message* reply_message) {
ExternalTabContainer* external_tab = GetExternalTabForHandle(handle);
if (external_tab) {
- external_tab->RunUnloadHandlers(notification_window, notification_message);
+ external_tab->RunUnloadHandlers(reply_message);
}
}
diff --git a/chrome/browser/external_tab_container_win.cc b/chrome/browser/external_tab_container_win.cc
index 24d7f60..012a966 100644
--- a/chrome/browser/external_tab_container_win.cc
+++ b/chrome/browser/external_tab_container_win.cc
@@ -57,13 +57,11 @@ ExternalTabContainer::ExternalTabContainer(
handle_top_level_requests_(false),
external_method_factory_(this),
enabled_extension_automation_(false),
- waiting_for_unload_event_(false),
pending_(false),
infobars_enabled_(true),
focus_manager_(NULL),
external_tab_view_(NULL),
- notification_window_(NULL),
- notification_message_(NULL) {
+ unload_reply_message_(NULL) {
}
ExternalTabContainer::~ExternalTabContainer() {
@@ -417,15 +415,16 @@ void ExternalTabContainer::LoadingStateChanged(TabContents* source) {
}
void ExternalTabContainer::CloseContents(TabContents* source) {
- static const int kExternalTabCloseContentsDelayMS = 100;
+ if (!automation_)
+ return;
- if (waiting_for_unload_event_) {
- PostMessage(notification_window_, notification_message_, 0, 0);
- waiting_for_unload_event_ = false;
+ if (unload_reply_message_) {
+ AutomationMsg_RunUnloadHandlers::WriteReplyParams(unload_reply_message_,
+ true);
+ automation_->Send(unload_reply_message_);
+ unload_reply_message_ = NULL;
} else {
- if (automation_) {
- automation_->Send(new AutomationMsg_CloseExternalTab(0, tab_handle_));
- }
+ automation_->Send(new AutomationMsg_CloseExternalTab(0, tab_handle_));
}
}
@@ -612,6 +611,27 @@ void ExternalTabContainer::ShowHtmlDialog(HtmlDialogUIDelegate* delegate,
browser_->window()->ShowHTMLDialog(delegate, parent);
}
+void ExternalTabContainer::BeforeUnloadFired(TabContents* tab,
+ bool proceed,
+ bool* proceed_to_fire_unload) {
+ DCHECK(unload_reply_message_);
+ *proceed_to_fire_unload = true;
+
+ if (!automation_) {
+ delete unload_reply_message_;
+ unload_reply_message_ = NULL;
+ return;
+ }
+
+ if (!proceed) {
+ AutomationMsg_RunUnloadHandlers::WriteReplyParams(unload_reply_message_,
+ false);
+ automation_->Send(unload_reply_message_);
+ unload_reply_message_ = NULL;
+ *proceed_to_fire_unload = false;
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// ExternalTabContainer, NotificationObserver implementation:
@@ -717,20 +737,24 @@ void ExternalTabContainer::OnFinalMessage(HWND window) {
Release();
}
-void ExternalTabContainer::RunUnloadHandlers(
- gfx::NativeWindow notification_window,
- int notification_message) {
- DCHECK(::IsWindow(notification_window));
- if (tab_contents_) {
- notification_window_ = notification_window;
- notification_message_ = notification_message;
+void ExternalTabContainer::RunUnloadHandlers(IPC::Message* reply_message) {
+ if (!automation_) {
+ delete reply_message;
+ return;
+ }
- if (Browser::RunUnloadEventsHelper(tab_contents_)) {
- waiting_for_unload_event_ = true;
- }
+ // If we have a pending unload message, then just respond back to this
+ // request and continue processing the previous unload message.
+ if (unload_reply_message_) {
+ AutomationMsg_RunUnloadHandlers::WriteReplyParams(reply_message, true);
+ automation_->Send(reply_message);
+ return;
}
- if (!waiting_for_unload_event_) {
- PostMessage(notification_window, notification_message, 0, 0);
+ if (tab_contents_ && Browser::RunUnloadEventsHelper(tab_contents_)) {
+ unload_reply_message_ = reply_message;
+ } else {
+ AutomationMsg_RunUnloadHandlers::WriteReplyParams(reply_message, true);
+ automation_->Send(reply_message);
}
}
diff --git a/chrome/browser/external_tab_container_win.h b/chrome/browser/external_tab_container_win.h
index 591a1ff..597901b 100644
--- a/chrome/browser/external_tab_container_win.h
+++ b/chrome/browser/external_tab_container_win.h
@@ -148,15 +148,6 @@ class ExternalTabContainer : public TabContentsDelegate,
const NavigationEntry::SSLStatus& ssl,
bool show_history);
- // Overriden from TabContentsDelegate::AutomationResourceRoutingDelegate
- virtual void RegisterRenderViewHost(RenderViewHost* render_view_host);
- virtual void UnregisterRenderViewHost(RenderViewHost* render_view_host);
-
- // Overridden from NotificationObserver:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
// Handles the context menu display operation. This allows external
// hosts to customize the menu.
virtual bool HandleContextMenu(const ContextMenuParams& params);
@@ -172,6 +163,19 @@ class ExternalTabContainer : public TabContentsDelegate,
virtual void ShowHtmlDialog(HtmlDialogUIDelegate* delegate,
gfx::NativeWindow parent_window);
+ virtual void BeforeUnloadFired(TabContents* tab,
+ bool proceed,
+ bool* proceed_to_fire_unload);
+
+ // Overriden from TabContentsDelegate::AutomationResourceRoutingDelegate
+ virtual void RegisterRenderViewHost(RenderViewHost* render_view_host);
+ virtual void UnregisterRenderViewHost(RenderViewHost* render_view_host);
+
+ // Overridden from NotificationObserver:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
// Returns the ExternalTabContainer instance associated with the cookie
// passed in. It also erases the corresponding reference from the map.
// Returns NULL if we fail to find the cookie in the map.
@@ -204,8 +208,7 @@ class ExternalTabContainer : public TabContentsDelegate,
virtual bool infobars_enabled();
- void RunUnloadHandlers(gfx::NativeWindow notification_window,
- int notification_message);
+ void RunUnloadHandlers(IPC::Message* reply_message);
protected:
// Overridden from views::WidgetWin:
@@ -308,9 +311,6 @@ class ExternalTabContainer : public TabContentsDelegate,
// A mapping between accelerators and commands.
std::map<views::Accelerator, int> accelerator_table_;
- // Set to true if the tab is waiting for the unload event to complete.
- bool waiting_for_unload_event_;
-
// Contains the list of URL requests which are pending waiting for an ack
// from the external host.
std::vector<PendingTopLevelNavigation> pending_open_url_requests_;
@@ -326,8 +326,7 @@ class ExternalTabContainer : public TabContentsDelegate,
views::View* external_tab_view_;
- gfx::NativeWindow notification_window_;
- int notification_message_;
+ IPC::Message* unload_reply_message_;
DISALLOW_COPY_AND_ASSIGN(ExternalTabContainer);
};
diff --git a/chrome/test/automation/automation_messages_internal.h b/chrome/test/automation/automation_messages_internal.h
index 2f413d7..2664ee6 100644
--- a/chrome/test/automation/automation_messages_internal.h
+++ b/chrome/test/automation/automation_messages_internal.h
@@ -1413,12 +1413,8 @@ IPC_BEGIN_MESSAGES(Automation)
// runs unload handlers if any on the current page.
// Request:
// -int: Tab handle
- // -gfx::NativeWindow: notification window
- // -int: notification message.
- // Response:
- // None expected
- IPC_MESSAGE_ROUTED3(AutomationMsg_RunUnloadHandlers, int, gfx::NativeWindow,
- int)
+ // -bool: result: true->unload, false->don't unload
+ IPC_SYNC_MESSAGE_ROUTED1_1(AutomationMsg_RunUnloadHandlers, int, bool)
// This message sets the current zoom level on the tab
// Request:
diff --git a/chrome_frame/chrome_active_document.cc b/chrome_frame/chrome_active_document.cc
index 6d350f8..d5c4250 100644
--- a/chrome_frame/chrome_active_document.cc
+++ b/chrome_frame/chrome_active_document.cc
@@ -876,6 +876,19 @@ void ChromeActiveDocument::OnSetZoomRange(const GUID* cmd_group_guid,
}
}
+void ChromeActiveDocument::OnUnload(const GUID* cmd_group_guid,
+ DWORD command_id,
+ DWORD cmd_exec_opt,
+ VARIANT* in_args,
+ VARIANT* out_args) {
+ if (IsValid() && out_args) {
+ bool should_unload = true;
+ automation_client_->OnUnload(&should_unload);
+ out_args->vt = VT_BOOL;
+ out_args->boolVal = should_unload ? VARIANT_TRUE : VARIANT_FALSE;
+ }
+}
+
void ChromeActiveDocument::OnOpenURL(int tab_handle,
const GURL& url_to_open,
const GURL& referrer,
diff --git a/chrome_frame/chrome_active_document.h b/chrome_frame/chrome_active_document.h
index 146f091..370ba32 100644
--- a/chrome_frame/chrome_active_document.h
+++ b/chrome_frame/chrome_active_document.h
@@ -276,6 +276,7 @@ BEGIN_EXEC_COMMAND_MAP(ChromeActiveDocument)
OnDisplayPrivacyInfo)
EXEC_COMMAND_HANDLER(NULL, OLECMDID_OPTICAL_GETZOOMRANGE, OnGetZoomRange)
EXEC_COMMAND_HANDLER(NULL, OLECMDID_OPTICAL_ZOOM, OnSetZoomRange)
+ EXEC_COMMAND_HANDLER(NULL, OLECMDID_ONUNLOAD, OnUnload)
END_EXEC_COMMAND_MAP()
// IPCs from automation server.
@@ -390,6 +391,12 @@ END_EXEC_COMMAND_MAP()
void OnSetZoomRange(const GUID* cmd_group_guid, DWORD command_id,
DWORD cmd_exec_opt, VARIANT* in_args, VARIANT* out_args);
+ // This function handles the OLECMDID_ONUNLOAD command. It enables Chrome to
+ // invoke before unload and unload handlers on the page if any, thereby
+ // enabling a webpage to potentially cancel the operation.
+ void OnUnload(const GUID* cmd_group_guid, DWORD command_id,
+ DWORD cmd_exec_opt, VARIANT* in_args, VARIANT* out_args);
+
// Call exec on our site's command target
HRESULT IEExec(const GUID* cmd_group_guid, DWORD command_id,
DWORD cmd_exec_opt, VARIANT* in_args, VARIANT* out_args);
diff --git a/chrome_frame/chrome_frame_activex_base.h b/chrome_frame/chrome_frame_activex_base.h
index dae53df..5f281f3 100644
--- a/chrome_frame/chrome_frame_activex_base.h
+++ b/chrome_frame/chrome_frame_activex_base.h
@@ -389,43 +389,6 @@ END_MSG_MAP()
return true;
}
- // IOleInPlaceObject overrides.
- STDMETHOD(InPlaceDeactivate)(void) {
- static UINT onload_handlers_done_msg =
- RegisterWindowMessage(L"ChromeFrame_OnloadHandlersDone");
-
- if (m_bInPlaceActive && IsWindow() && IsValid()) {
- static const int kChromeFrameUnloadEventTimerId = 0xdeadbeef;
- static const int kChromeFrameUnloadEventTimeout = 1000;
-
- // To prevent us from indefinitely waiting for an acknowledgement from
- // Chrome indicating that unload handlers have been run, we set a 1
- // second timer and exit the loop when it fires.
- ::SetTimer(m_hWnd, kChromeFrameUnloadEventTimerId,
- kChromeFrameUnloadEventTimeout, NULL);
-
- automation_client_->RunUnloadHandlers(m_hWnd, onload_handlers_done_msg);
-
- MSG msg = {0};
- while (GetMessage(&msg, NULL, 0, 0)) {
- if (msg.message == onload_handlers_done_msg &&
- msg.hwnd == m_hWnd) {
- break;
- }
-
- if (msg.message == WM_TIMER &&
- msg.wParam == kChromeFrameUnloadEventTimerId) {
- break;
- }
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
-
- ::KillTimer(m_hWnd, kChromeFrameUnloadEventTimerId);
- }
- return IOleInPlaceObjectWindowlessImpl<T>::InPlaceDeactivate();
- }
-
protected:
virtual void GetProfilePath(const std::wstring& profile_name,
FilePath* profile_path) {
diff --git a/chrome_frame/chrome_frame_automation.cc b/chrome_frame/chrome_frame_automation.cc
index 908df61d..67d9ea8 100644
--- a/chrome_frame/chrome_frame_automation.cc
+++ b/chrome_frame/chrome_frame_automation.cc
@@ -122,6 +122,9 @@ class ChromeFrameAutomationProxyImpl::CFMsgDispatcher
case AutomationMsg_GetEnabledExtensions::ID:
InvokeCallback<GetEnabledExtensionsContext>(msg, context);
break;
+ case AutomationMsg_RunUnloadHandlers::ID:
+ InvokeCallback<UnloadContext>(msg, context);
+ break;
default:
NOTREACHED();
}
@@ -1367,19 +1370,6 @@ void ChromeFrameAutomationClient::RemoveBrowsingData(int remove_mask) {
new AutomationMsg_RemoveBrowsingData(0, remove_mask));
}
-void ChromeFrameAutomationClient::RunUnloadHandlers(HWND notification_window,
- int notification_message) {
- if (automation_server_) {
- automation_server_->Send(
- new AutomationMsg_RunUnloadHandlers(0, tab_handle_,
- notification_window,
- notification_message));
- } else {
- // Post this message to ensure that the caller exits his message loop.
- ::PostMessage(notification_window, notification_message, 0, 0);
- }
-}
-
void ChromeFrameAutomationClient::SetUrlFetcher(
PluginUrlRequestManager* url_fetcher) {
DCHECK(url_fetcher != NULL);
@@ -1395,6 +1385,22 @@ void ChromeFrameAutomationClient::SetZoomLevel(PageZoom::Function zoom_level) {
}
}
+void ChromeFrameAutomationClient::OnUnload(bool* should_unload) {
+ *should_unload = true;
+ if (automation_server_) {
+ const DWORD kUnloadEventTimeout = 20000;
+
+ IPC::SyncMessage* msg = new AutomationMsg_RunUnloadHandlers(0, tab_handle_,
+ should_unload);
+ base::WaitableEvent unload_call_finished(false, false);
+ UnloadContext* unload_context = new UnloadContext(&unload_call_finished,
+ should_unload);
+ automation_server_->SendAsAsync(msg, unload_context, this);
+ HANDLE done = unload_call_finished.handle();
+ WaitWithMessageLoop(&done, 1, kUnloadEventTimeout);
+ }
+}
+
//////////////////////////////////////////////////////////////////////////
// PluginUrlRequestDelegate implementation.
// Forward network related responses to Chrome.
diff --git a/chrome_frame/chrome_frame_automation.h b/chrome_frame/chrome_frame_automation.h
index 7bb572a..0890fb7 100644
--- a/chrome_frame/chrome_frame_automation.h
+++ b/chrome_frame/chrome_frame_automation.h
@@ -415,13 +415,13 @@ class ChromeFrameAutomationClient
// For IDeleteBrowsingHistorySupport
void RemoveBrowsingData(int remove_mask);
- // Sends an IPC message to the external tab container requesting it to run
- // unload handlers on the page.
- void RunUnloadHandlers(HWND notification_window, int notification_message);
-
// Sets the current zoom level on the tab.
void SetZoomLevel(PageZoom::Function zoom_level);
+ // Fires before unload and unload handlers on the page if any. Allows the
+ // the website to put up a confirmation dialog on unload.
+ void OnUnload(bool* should_unload);
+
protected:
// ChromeFrameAutomationProxy::LaunchDelegate implementation.
virtual void LaunchComplete(ChromeFrameAutomationProxy* proxy,
diff --git a/chrome_frame/custom_sync_call_context.h b/chrome_frame/custom_sync_call_context.h
index 28812ef..9cbe3d6 100644
--- a/chrome_frame/custom_sync_call_context.h
+++ b/chrome_frame/custom_sync_call_context.h
@@ -6,6 +6,7 @@
#include <vector>
#include "base/ref_counted.h"
+#include "base/waitable_event.h"
#include "chrome_frame/sync_msg_reply_dispatcher.h"
#include "chrome_frame/chrome_frame_automation.h"
#include "ipc/ipc_sync_message.h"
@@ -122,6 +123,31 @@ class BeginNavigateContext
scoped_refptr<ChromeFrameAutomationClient> client_;
};
+// Class that maintains contextual information for the unload operation, i.e.
+// when the user attempts to navigate away from a page rendered in ChromeFrame.
+class UnloadContext
+ : public SyncMessageReplyDispatcher::SyncMessageCallContext {
+ public:
+ typedef Tuple1<bool> output_type;
+ explicit UnloadContext(base::WaitableEvent* unload_done, bool* should_unload)
+ : should_unload_(should_unload),
+ unload_done_(unload_done) {
+ }
+
+ void Completed(bool should_unload) {
+ *should_unload_ = should_unload;
+ unload_done_->Signal();
+ should_unload_ = NULL;
+ unload_done_ = NULL;
+ // This object will be destroyed after this. Cannot access any members
+ // on returning from this function.
+ }
+
+ private:
+ base::WaitableEvent* unload_done_;
+ bool* should_unload_;
+};
+
#endif // CHROME_FRAME_CUSTOM_SYNC_CALL_CONTEXT_H_
diff --git a/chrome_frame/utils.cc b/chrome_frame/utils.cc
index 35fbc83..80095428 100644
--- a/chrome_frame/utils.cc
+++ b/chrome_frame/utils.cc
@@ -1453,3 +1453,37 @@ void PinModule() {
}
}
}
+
+void WaitWithMessageLoop(HANDLE* handles, int count, DWORD timeout) {
+ base::Time now = base::Time::Now();
+ base::Time wait_until = now + base::TimeDelta::FromMilliseconds(timeout);
+
+ while (wait_until >= now) {
+ base::TimeDelta wait_time = wait_until - now;
+ DWORD wait = MsgWaitForMultipleObjects(
+ count, handles, FALSE, static_cast<DWORD>(wait_time.InMilliseconds()),
+ QS_ALLINPUT);
+ switch (wait) {
+ case WAIT_OBJECT_0:
+ case WAIT_TIMEOUT:
+ return;
+
+ case WAIT_OBJECT_0 + 1: {
+ MSG msg = {0};
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ break;
+ }
+
+ default: {
+ NOTREACHED() << "Unexpected return from MsgWaitForMultipleObjects :"
+ << wait;
+ return;
+ }
+ }
+ now = base::Time::Now();
+ }
+}
+
diff --git a/chrome_frame/utils.h b/chrome_frame/utils.h
index e0da6ac..eadad72 100644
--- a/chrome_frame/utils.h
+++ b/chrome_frame/utils.h
@@ -550,4 +550,8 @@ bool CanNavigate(const GURL& url, IInternetSecurityManager* security_manager,
// Call if you make irreversible patches.
void PinModule();
+// Helper function to spin a message loop and dispatch messages while waiting
+// for a handle to be signaled.
+void WaitWithMessageLoop(HANDLE* handles, int count, DWORD timeout);
+
#endif // CHROME_FRAME_UTILS_H_