diff options
Diffstat (limited to 'chrome_frame')
-rw-r--r-- | chrome_frame/chrome_active_document.cc | 13 | ||||
-rw-r--r-- | chrome_frame/chrome_active_document.h | 7 | ||||
-rw-r--r-- | chrome_frame/chrome_frame_activex_base.h | 37 | ||||
-rw-r--r-- | chrome_frame/chrome_frame_automation.cc | 32 | ||||
-rw-r--r-- | chrome_frame/chrome_frame_automation.h | 8 | ||||
-rw-r--r-- | chrome_frame/custom_sync_call_context.h | 26 | ||||
-rw-r--r-- | chrome_frame/utils.cc | 34 | ||||
-rw-r--r-- | chrome_frame/utils.h | 4 |
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_ |