summaryrefslogtreecommitdiffstats
path: root/chrome_frame
diff options
context:
space:
mode:
Diffstat (limited to 'chrome_frame')
-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
8 files changed, 107 insertions, 54 deletions
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_