- Change the way that application shutdown works in order to support JavaScript 'onbeforeunload' handling (issue #853). See comments in cef_life_span_handler.h for a detailed description of the new shutdown process.
- Fix a crash on Linux during window destruction (issue #681). git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1149 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
parent
e3b297416f
commit
7ded60a218
1
cef.gyp
1
cef.gyp
|
@ -251,6 +251,7 @@
|
|||
'tests/unittests/download_unittest.cc',
|
||||
'tests/unittests/geolocation_unittest.cc',
|
||||
'tests/unittests/jsdialog_unittest.cc',
|
||||
'tests/unittests/life_span_unittest.cc',
|
||||
'tests/unittests/navigation_unittest.cc',
|
||||
'tests/unittests/process_message_unittest.cc',
|
||||
'tests/unittests/request_unittest.cc',
|
||||
|
|
|
@ -219,15 +219,24 @@ typedef struct _cef_browser_host_t {
|
|||
///
|
||||
// Call this function before destroying a contained browser window. This
|
||||
// function performs any internal cleanup that may be needed before the
|
||||
// browser window is destroyed.
|
||||
// browser window is destroyed. See cef_life_span_handler_t::do_close()
|
||||
// documentation for additional usage information.
|
||||
///
|
||||
void (CEF_CALLBACK *parent_window_will_close)(
|
||||
struct _cef_browser_host_t* self);
|
||||
|
||||
///
|
||||
// Closes this browser window.
|
||||
// Request that the browser close. The JavaScript 'onbeforeunload' event will
|
||||
// be fired. If |force_close| is false (0) the event handler, if any, will be
|
||||
// allowed to prompt the user and the user can optionally cancel the close. If
|
||||
// |force_close| is true (1) the prompt will not be displayed and the close
|
||||
// will proceed. Results in a call to cef_life_span_handler_t::do_close() if
|
||||
// the event handler allows the close or if |force_close| is true (1). See
|
||||
// cef_life_span_handler_t::do_close() documentation for additional usage
|
||||
// information.
|
||||
///
|
||||
void (CEF_CALLBACK *close_browser)(struct _cef_browser_host_t* self);
|
||||
void (CEF_CALLBACK *close_browser)(struct _cef_browser_host_t* self,
|
||||
int force_close);
|
||||
|
||||
///
|
||||
// Set focus for the browser window. If |enable| is true (1) focus will be set
|
||||
|
|
|
@ -76,7 +76,7 @@ typedef struct _cef_life_span_handler_t {
|
|||
struct _cef_browser_settings_t* settings, int* no_javascript_access);
|
||||
|
||||
///
|
||||
// Called after a new window is created.
|
||||
// Called after a new browser is created.
|
||||
///
|
||||
void (CEF_CALLBACK *on_after_created)(struct _cef_life_span_handler_t* self,
|
||||
struct _cef_browser_t* browser);
|
||||
|
@ -90,19 +90,73 @@ typedef struct _cef_life_span_handler_t {
|
|||
struct _cef_browser_t* browser);
|
||||
|
||||
///
|
||||
// Called when a window has recieved a request to close. Return false (0) to
|
||||
// proceed with the window close or true (1) to cancel the window close. If
|
||||
// this is a modal window and a custom modal loop implementation was provided
|
||||
// in run_modal() this callback should be used to restore the opener window to
|
||||
// a usable state.
|
||||
// Called when a browser has recieved a request to close. This may result
|
||||
// directly from a call to cef_browser_host_t::close_browser() or indirectly
|
||||
// if the browser is a top-level OS window created by CEF and the user
|
||||
// attempts to close the window. This function will be called after the
|
||||
// JavaScript 'onunload' event has been fired. It will not be called for
|
||||
// browsers after the associated OS window has been destroyed (for those
|
||||
// browsers it is no longer possible to cancel the close).
|
||||
//
|
||||
// If CEF created an OS window for the browser returning false (0) will send
|
||||
// an OS close notification to the browser window's top-level owner (e.g.
|
||||
// WM_CLOSE on Windows, performClose: on OS-X and "delete_event" on Linux). If
|
||||
// no OS window exists (window rendering disabled) returning false (0) will
|
||||
// cause the browser object to be destroyed immediately. Return true (1) if
|
||||
// the browser is parented to another window and that other window needs to
|
||||
// receive close notification via some non-standard technique.
|
||||
//
|
||||
// If an application provides its own top-level window it should handle OS
|
||||
// close notifications by calling cef_browser_host_t::CloseBrowser(false (0))
|
||||
// instead of immediately closing (see the example below). This gives CEF an
|
||||
// opportunity to process the 'onbeforeunload' event and optionally cancel the
|
||||
// close before do_close() is called.
|
||||
//
|
||||
// The cef_life_span_handler_t::OnBeforeclose() function will be called
|
||||
// immediately before the browser object is destroyed. The application should
|
||||
// only exit after OnBeforeclose() has been called for all existing browsers.
|
||||
//
|
||||
// If the browser represents a modal window and a custom modal loop
|
||||
// implementation was provided in cef_life_span_handler_t::run_modal() this
|
||||
// callback should be used to restore the opener window to a usable state.
|
||||
//
|
||||
// By way of example consider what should happen during window close when the
|
||||
// browser is parented to an application-provided top-level OS window. 1.
|
||||
// User clicks the window close button which sends an OS close
|
||||
// notification (e.g. WM_CLOSE on Windows, performClose: on OS-X and
|
||||
// "delete_event" on Linux).
|
||||
// 2. Application's top-level window receives the close notification and:
|
||||
// A. Calls CefBrowserHost::CloseBrowser(false).
|
||||
// B. Cancels the window close.
|
||||
// 3. JavaScript 'onbeforeunload' handler executes and shows the close
|
||||
// confirmation dialog (which can be overridden via
|
||||
// CefJSDialogHandler::OnBeforeUnloadDialog()).
|
||||
// 4. User approves the close. 5. JavaScript 'onunload' handler executes. 6.
|
||||
// Application's do_close() handler is called. Application will:
|
||||
// A. Call CefBrowserHost::ParentWindowWillClose() to notify CEF that the
|
||||
// parent window will be closing.
|
||||
// B. Set a flag to indicate that the next close attempt will be allowed.
|
||||
// C. Return false.
|
||||
// 7. CEF sends an OS close notification. 8. Application's top-level window
|
||||
// receives the OS close notification and
|
||||
// allows the window to close based on the flag from #6B.
|
||||
// 9. Browser OS window is destroyed. 10. Application's
|
||||
// cef_life_span_handler_t::OnBeforeclose() handler is called and
|
||||
// the browser object is destroyed.
|
||||
// 11. Application exits by calling cef_quit_message_loop() if no other
|
||||
// browsers
|
||||
// exist.
|
||||
///
|
||||
int (CEF_CALLBACK *do_close)(struct _cef_life_span_handler_t* self,
|
||||
struct _cef_browser_t* browser);
|
||||
|
||||
///
|
||||
// Called just before a window is closed. If this is a modal window and a
|
||||
// custom modal loop implementation was provided in run_modal() this callback
|
||||
// should be used to exit the custom modal loop.
|
||||
// Called just before a browser is destroyed. Release all references to the
|
||||
// browser object and do not attempt to execute any functions on the browser
|
||||
// object after this callback returns. If this is a modal window and a custom
|
||||
// modal loop implementation was provided in run_modal() this callback should
|
||||
// be used to exit the custom modal loop. See do_close() documentation for
|
||||
// additional usage information.
|
||||
///
|
||||
void (CEF_CALLBACK *on_before_close)(struct _cef_life_span_handler_t* self,
|
||||
struct _cef_browser_t* browser);
|
||||
|
|
|
@ -254,16 +254,24 @@ class CefBrowserHost : public virtual CefBase {
|
|||
///
|
||||
// Call this method before destroying a contained browser window. This method
|
||||
// performs any internal cleanup that may be needed before the browser window
|
||||
// is destroyed.
|
||||
// is destroyed. See CefLifeSpanHandler::DoClose() documentation for
|
||||
// additional usage information.
|
||||
///
|
||||
/*--cef()--*/
|
||||
virtual void ParentWindowWillClose() =0;
|
||||
|
||||
///
|
||||
// Closes this browser window.
|
||||
// Request that the browser close. The JavaScript 'onbeforeunload' event will
|
||||
// be fired. If |force_close| is false the event handler, if any, will be
|
||||
// allowed to prompt the user and the user can optionally cancel the close.
|
||||
// If |force_close| is true the prompt will not be displayed and the close
|
||||
// will proceed. Results in a call to CefLifeSpanHandler::DoClose() if the
|
||||
// event handler allows the close or if |force_close| is true. See
|
||||
// CefLifeSpanHandler::DoClose() documentation for additional usage
|
||||
// information.
|
||||
///
|
||||
/*--cef()--*/
|
||||
virtual void CloseBrowser() =0;
|
||||
virtual void CloseBrowser(bool force_close) =0;
|
||||
|
||||
///
|
||||
// Set focus for the browser window. If |enable| is true focus will be set to
|
||||
|
|
|
@ -77,7 +77,7 @@ class CefLifeSpanHandler : public virtual CefBase {
|
|||
}
|
||||
|
||||
///
|
||||
// Called after a new window is created.
|
||||
// Called after a new browser is created.
|
||||
///
|
||||
/*--cef()--*/
|
||||
virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) {}
|
||||
|
@ -91,19 +91,73 @@ class CefLifeSpanHandler : public virtual CefBase {
|
|||
virtual bool RunModal(CefRefPtr<CefBrowser> browser) { return false; }
|
||||
|
||||
///
|
||||
// Called when a window has recieved a request to close. Return false to
|
||||
// proceed with the window close or true to cancel the window close. If this
|
||||
// is a modal window and a custom modal loop implementation was provided in
|
||||
// RunModal() this callback should be used to restore the opener window to a
|
||||
// usable state.
|
||||
// Called when a browser has recieved a request to close. This may result
|
||||
// directly from a call to CefBrowserHost::CloseBrowser() or indirectly if the
|
||||
// browser is a top-level OS window created by CEF and the user attempts to
|
||||
// close the window. This method will be called after the JavaScript
|
||||
// 'onunload' event has been fired. It will not be called for browsers after
|
||||
// the associated OS window has been destroyed (for those browsers it is no
|
||||
// longer possible to cancel the close).
|
||||
//
|
||||
// If CEF created an OS window for the browser returning false will send an OS
|
||||
// close notification to the browser window's top-level owner (e.g. WM_CLOSE
|
||||
// on Windows, performClose: on OS-X and "delete_event" on Linux). If no OS
|
||||
// window exists (window rendering disabled) returning false will cause the
|
||||
// browser object to be destroyed immediately. Return true if the browser is
|
||||
// parented to another window and that other window needs to receive close
|
||||
// notification via some non-standard technique.
|
||||
//
|
||||
// If an application provides its own top-level window it should handle OS
|
||||
// close notifications by calling CefBrowserHost::CloseBrowser(false) instead
|
||||
// of immediately closing (see the example below). This gives CEF an
|
||||
// opportunity to process the 'onbeforeunload' event and optionally cancel the
|
||||
// close before DoClose() is called.
|
||||
//
|
||||
// The CefLifeSpanHandler::OnBeforeClose() method will be called immediately
|
||||
// before the browser object is destroyed. The application should only exit
|
||||
// after OnBeforeClose() has been called for all existing browsers.
|
||||
//
|
||||
// If the browser represents a modal window and a custom modal loop
|
||||
// implementation was provided in CefLifeSpanHandler::RunModal() this callback
|
||||
// should be used to restore the opener window to a usable state.
|
||||
//
|
||||
// By way of example consider what should happen during window close when the
|
||||
// browser is parented to an application-provided top-level OS window.
|
||||
// 1. User clicks the window close button which sends an OS close
|
||||
// notification (e.g. WM_CLOSE on Windows, performClose: on OS-X and
|
||||
// "delete_event" on Linux).
|
||||
// 2. Application's top-level window receives the close notification and:
|
||||
// A. Calls CefBrowserHost::CloseBrowser(false).
|
||||
// B. Cancels the window close.
|
||||
// 3. JavaScript 'onbeforeunload' handler executes and shows the close
|
||||
// confirmation dialog (which can be overridden via
|
||||
// CefJSDialogHandler::OnBeforeUnloadDialog()).
|
||||
// 4. User approves the close.
|
||||
// 5. JavaScript 'onunload' handler executes.
|
||||
// 6. Application's DoClose() handler is called. Application will:
|
||||
// A. Call CefBrowserHost::ParentWindowWillClose() to notify CEF that the
|
||||
// parent window will be closing.
|
||||
// B. Set a flag to indicate that the next close attempt will be allowed.
|
||||
// C. Return false.
|
||||
// 7. CEF sends an OS close notification.
|
||||
// 8. Application's top-level window receives the OS close notification and
|
||||
// allows the window to close based on the flag from #6B.
|
||||
// 9. Browser OS window is destroyed.
|
||||
// 10. Application's CefLifeSpanHandler::OnBeforeClose() handler is called and
|
||||
// the browser object is destroyed.
|
||||
// 11. Application exits by calling CefQuitMessageLoop() if no other browsers
|
||||
// exist.
|
||||
///
|
||||
/*--cef()--*/
|
||||
virtual bool DoClose(CefRefPtr<CefBrowser> browser) { return false; }
|
||||
|
||||
///
|
||||
// Called just before a window is closed. If this is a modal window and a
|
||||
// custom modal loop implementation was provided in RunModal() this callback
|
||||
// should be used to exit the custom modal loop.
|
||||
// Called just before a browser is destroyed. Release all references to the
|
||||
// browser object and do not attempt to execute any methods on the browser
|
||||
// object after this callback returns. If this is a modal window and a custom
|
||||
// modal loop implementation was provided in RunModal() this callback should
|
||||
// be used to exit the custom modal loop. See DoClose() documentation for
|
||||
// additional usage information.
|
||||
///
|
||||
/*--cef()--*/
|
||||
virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) {}
|
||||
|
|
|
@ -459,19 +459,35 @@ CefRefPtr<CefBrowser> CefBrowserHostImpl::GetBrowser() {
|
|||
return this;
|
||||
}
|
||||
|
||||
void CefBrowserHostImpl::CloseBrowser() {
|
||||
void CefBrowserHostImpl::CloseBrowser(bool force_close) {
|
||||
if (CEF_CURRENTLY_ON_UIT()) {
|
||||
if (IsWindowRenderingDisabled()) {
|
||||
if (AllowDestroyBrowser()) {
|
||||
ParentWindowWillClose();
|
||||
DestroyBrowser();
|
||||
// Exit early if a close attempt is already pending and this method is
|
||||
// called again from somewhere other than WindowDestroyed().
|
||||
if (destruction_state_ >= DESTRUCTION_STATE_PENDING &&
|
||||
(IsWindowRenderingDisabled() || !window_destroyed_)) {
|
||||
if (force_close && destruction_state_ == DESTRUCTION_STATE_PENDING) {
|
||||
// Upgrade the destruction state.
|
||||
destruction_state_ = DESTRUCTION_STATE_ACCEPTED;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (destruction_state_ < DESTRUCTION_STATE_ACCEPTED) {
|
||||
destruction_state_ = (force_close ? DESTRUCTION_STATE_ACCEPTED :
|
||||
DESTRUCTION_STATE_PENDING);
|
||||
}
|
||||
|
||||
content::WebContents* contents = web_contents();
|
||||
if (contents && contents->NeedToFireBeforeUnload()) {
|
||||
// Will result in a call to BeforeUnloadFired() and, if the close isn't
|
||||
// canceled, CloseContents().
|
||||
contents->GetRenderViewHost()->FirePageBeforeUnload(false);
|
||||
} else {
|
||||
PlatformCloseWindow();
|
||||
CloseContents(contents);
|
||||
}
|
||||
} else {
|
||||
CEF_POST_TASK(CEF_UIT,
|
||||
base::Bind(&CefBrowserHostImpl::CloseBrowser, this));
|
||||
base::Bind(&CefBrowserHostImpl::CloseBrowser, this, force_close));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1024,22 +1040,18 @@ bool CefBrowserHostImpl::SendProcessMessage(
|
|||
// CefBrowserHostImpl public methods.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool CefBrowserHostImpl::AllowDestroyBrowser() {
|
||||
if (client_.get()) {
|
||||
CefRefPtr<CefLifeSpanHandler> handler =
|
||||
client_->GetLifeSpanHandler();
|
||||
if (handler.get()) {
|
||||
// Give the client a chance to handle this one.
|
||||
return !handler->DoClose(this);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
void CefBrowserHostImpl::WindowDestroyed() {
|
||||
CEF_REQUIRE_UIT();
|
||||
DCHECK(!window_destroyed_);
|
||||
window_destroyed_ = true;
|
||||
CloseBrowser(true);
|
||||
}
|
||||
|
||||
void CefBrowserHostImpl::DestroyBrowser() {
|
||||
CEF_REQUIRE_UIT();
|
||||
|
||||
destruction_state_ = DESTRUCTION_STATE_COMPLETED;
|
||||
|
||||
if (client_.get()) {
|
||||
CefRefPtr<CefLifeSpanHandler> handler = client_->GetLifeSpanHandler();
|
||||
if (handler.get()) {
|
||||
|
@ -1412,7 +1424,41 @@ void CefBrowserHostImpl::LoadingStateChanged(content::WebContents* source) {
|
|||
}
|
||||
|
||||
void CefBrowserHostImpl::CloseContents(content::WebContents* source) {
|
||||
PlatformCloseWindow();
|
||||
if (destruction_state_ == DESTRUCTION_STATE_COMPLETED)
|
||||
return;
|
||||
|
||||
bool close_browser = true;
|
||||
|
||||
// If this method is called in response to something other than
|
||||
// WindowDestroyed() ask the user if the browser should close.
|
||||
if (IsWindowRenderingDisabled() || !window_destroyed_) {
|
||||
CefRefPtr<CefLifeSpanHandler> handler =
|
||||
client_->GetLifeSpanHandler();
|
||||
if (handler.get()) {
|
||||
close_browser = !handler->DoClose(this);
|
||||
}
|
||||
}
|
||||
|
||||
if (close_browser) {
|
||||
if (destruction_state_ != DESTRUCTION_STATE_ACCEPTED)
|
||||
destruction_state_ = DESTRUCTION_STATE_ACCEPTED;
|
||||
|
||||
if (!IsWindowRenderingDisabled() && !window_destroyed_) {
|
||||
// A window exists so try to close it using the platform method. Will
|
||||
// result in a call to WindowDestroyed() if/when the window is destroyed
|
||||
// via the platform window destruction mechanism.
|
||||
PlatformCloseWindow();
|
||||
} else {
|
||||
// No window exists. Destroy the browser immediately.
|
||||
DestroyBrowser();
|
||||
if (!IsWindowRenderingDisabled()) {
|
||||
// Release the reference added in PlatformCreateWindow().
|
||||
Release();
|
||||
}
|
||||
}
|
||||
} else if (destruction_state_ != DESTRUCTION_STATE_NONE) {
|
||||
destruction_state_ = DESTRUCTION_STATE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
void CefBrowserHostImpl::UpdateTargetURL(content::WebContents* source,
|
||||
|
@ -1439,6 +1485,17 @@ bool CefBrowserHostImpl::AddMessageToConsole(content::WebContents* source,
|
|||
return false;
|
||||
}
|
||||
|
||||
void CefBrowserHostImpl::BeforeUnloadFired(content::WebContents* source,
|
||||
bool proceed,
|
||||
bool* proceed_to_fire_unload) {
|
||||
if (destruction_state_ == DESTRUCTION_STATE_ACCEPTED || proceed) {
|
||||
*proceed_to_fire_unload = true;
|
||||
} else if (!proceed) {
|
||||
*proceed_to_fire_unload = false;
|
||||
destruction_state_ = DESTRUCTION_STATE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
bool CefBrowserHostImpl::TakeFocus(content::WebContents* source,
|
||||
bool reverse) {
|
||||
if (client_.get()) {
|
||||
|
@ -1948,6 +2005,8 @@ CefBrowserHostImpl::CefBrowserHostImpl(
|
|||
queue_messages_(true),
|
||||
main_frame_id_(CefFrameHostImpl::kInvalidFrameId),
|
||||
focused_frame_id_(CefFrameHostImpl::kInvalidFrameId),
|
||||
destruction_state_(DESTRUCTION_STATE_NONE),
|
||||
window_destroyed_(false),
|
||||
is_in_onsetfocus_(false),
|
||||
focus_on_editable_field_(false),
|
||||
file_chooser_pending_(false) {
|
||||
|
|
|
@ -109,7 +109,7 @@ class CefBrowserHostImpl : public CefBrowserHost,
|
|||
|
||||
// CefBrowserHost methods.
|
||||
virtual CefRefPtr<CefBrowser> GetBrowser() OVERRIDE;
|
||||
virtual void CloseBrowser() OVERRIDE;
|
||||
virtual void CloseBrowser(bool force_close) OVERRIDE;
|
||||
virtual void ParentWindowWillClose() OVERRIDE;
|
||||
virtual void SetFocus(bool enable) OVERRIDE;
|
||||
virtual CefWindowHandle GetWindowHandle() OVERRIDE;
|
||||
|
@ -165,9 +165,8 @@ class CefBrowserHostImpl : public CefBrowserHost,
|
|||
CefProcessId target_process,
|
||||
CefRefPtr<CefProcessMessage> message) OVERRIDE;
|
||||
|
||||
// Call LifeSpanHandler before destroying. Returns true if destruction
|
||||
// is allowed at this time.
|
||||
bool AllowDestroyBrowser();
|
||||
// Called when the OS window hosting the browser is destroyed.
|
||||
void WindowDestroyed();
|
||||
|
||||
// Destroy the browser members. This method should only be called after the
|
||||
// native browser window is not longer processing messages.
|
||||
|
@ -253,6 +252,14 @@ class CefBrowserHostImpl : public CefBrowserHost,
|
|||
// Returns false if a popup is already pending.
|
||||
bool SetPendingPopupInfo(scoped_ptr<PendingPopupInfo> info);
|
||||
|
||||
enum DestructionState {
|
||||
DESTRUCTION_STATE_NONE = 0,
|
||||
DESTRUCTION_STATE_PENDING,
|
||||
DESTRUCTION_STATE_ACCEPTED,
|
||||
DESTRUCTION_STATE_COMPLETED
|
||||
};
|
||||
DestructionState destruction_state() const { return destruction_state_; }
|
||||
|
||||
private:
|
||||
// content::WebContentsDelegate methods.
|
||||
virtual content::WebContents* OpenURLFromTab(
|
||||
|
@ -268,6 +275,9 @@ class CefBrowserHostImpl : public CefBrowserHost,
|
|||
const string16& message,
|
||||
int32 line_no,
|
||||
const string16& source_id) OVERRIDE;
|
||||
virtual void BeforeUnloadFired(content::WebContents* source,
|
||||
bool proceed,
|
||||
bool* proceed_to_fire_unload) OVERRIDE;
|
||||
virtual bool TakeFocus(content::WebContents* source,
|
||||
bool reverse) OVERRIDE;
|
||||
virtual void WebContentsFocused(content::WebContents* contents) OVERRIDE;
|
||||
|
@ -483,6 +493,14 @@ class CefBrowserHostImpl : public CefBrowserHost,
|
|||
// Used when no other frame exists. Provides limited functionality.
|
||||
CefRefPtr<CefFrameHostImpl> placeholder_frame_;
|
||||
|
||||
// Represents the current browser destruction state. Only accessed on the UI
|
||||
// thread.
|
||||
DestructionState destruction_state_;
|
||||
|
||||
// True if the OS window hosting the browser has been destroyed. Only accessed
|
||||
// on the UI thread.
|
||||
bool window_destroyed_;
|
||||
|
||||
// True if currently in the OnSetFocus callback. Only accessed on the UI
|
||||
// thread.
|
||||
bool is_in_onsetfocus_;
|
||||
|
|
|
@ -22,15 +22,38 @@
|
|||
namespace {
|
||||
|
||||
void DestroyBrowser(CefRefPtr<CefBrowserHostImpl> browser) {
|
||||
browser->DestroyBrowser();
|
||||
browser->Release();
|
||||
// Force the browser to be destroyed and release the reference added in
|
||||
// PlatformCreateWindow().
|
||||
browser->WindowDestroyed();
|
||||
}
|
||||
|
||||
void window_destroyed(GtkWidget* widget, CefBrowserHostImpl* browser) {
|
||||
void browser_destroy(GtkWidget* widget, CefBrowserHostImpl* browser) {
|
||||
// Destroy the browser host after window destruction is complete.
|
||||
CEF_POST_TASK(CEF_UIT, base::Bind(DestroyBrowser, browser));
|
||||
}
|
||||
|
||||
void window_destroy(GtkWidget* widget, gpointer data) {
|
||||
}
|
||||
|
||||
gboolean window_delete_event(GtkWidget* widget, GdkEvent* event,
|
||||
CefBrowserHostImpl* browser) {
|
||||
// Protect against multiple requests to close while the close is pending.
|
||||
if (browser && browser->destruction_state() <=
|
||||
CefBrowserHostImpl::DESTRUCTION_STATE_PENDING) {
|
||||
if (browser->destruction_state() ==
|
||||
CefBrowserHostImpl::DESTRUCTION_STATE_NONE) {
|
||||
// Request that the browser close.
|
||||
browser->CloseBrowser(false);
|
||||
}
|
||||
|
||||
// Cancel the close.
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Allow the close.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
std::string GetDescriptionFromMimeType(const std::string& mime_type) {
|
||||
// Check for wild card mime types and return an appropriate description.
|
||||
static const struct {
|
||||
|
@ -225,6 +248,11 @@ bool CefBrowserHostImpl::PlatformCreateWindow() {
|
|||
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
|
||||
gtk_widget_show_all(GTK_WIDGET(window));
|
||||
|
||||
g_signal_connect(G_OBJECT(window), "destroy",
|
||||
G_CALLBACK(window_destroy), NULL);
|
||||
g_signal_connect(G_OBJECT(window), "delete_event",
|
||||
G_CALLBACK(window_delete_event), this);
|
||||
|
||||
window_info_.parent_widget = parentView;
|
||||
}
|
||||
|
||||
|
@ -237,7 +265,7 @@ bool CefBrowserHostImpl::PlatformCreateWindow() {
|
|||
window_info_.widget);
|
||||
|
||||
g_signal_connect(G_OBJECT(window_info_.widget), "destroy",
|
||||
G_CALLBACK(window_destroyed), this);
|
||||
G_CALLBACK(browser_destroy), this);
|
||||
|
||||
// As an additional requirement on Linux, we must set the colors for the
|
||||
// render widgets in webkit.
|
||||
|
@ -260,7 +288,14 @@ void CefBrowserHostImpl::PlatformCloseWindow() {
|
|||
if (window_info_.widget != NULL) {
|
||||
GtkWidget* window =
|
||||
gtk_widget_get_toplevel(GTK_WIDGET(window_info_.widget));
|
||||
gtk_signal_emit_by_name(GTK_OBJECT(window), "delete_event");
|
||||
|
||||
// Send the "delete_event" signal.
|
||||
GdkEvent event;
|
||||
memset(&event, 0, sizeof(GdkEvent));
|
||||
event.any.type = GDK_DELETE;
|
||||
event.any.send_event = TRUE;
|
||||
event.any.window = window->window;
|
||||
gtk_main_do_event(&event);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,8 +42,9 @@
|
|||
|
||||
- (void) dealloc {
|
||||
if (browser_) {
|
||||
browser_->DestroyBrowser();
|
||||
browser_->Release();
|
||||
// Force the browser to be destroyed and release the reference added in
|
||||
// PlatformCreateWindow().
|
||||
browser_->WindowDestroyed();
|
||||
}
|
||||
|
||||
[super dealloc];
|
||||
|
@ -68,6 +69,51 @@
|
|||
|
||||
@end
|
||||
|
||||
// Receives notifications from the browser window. Will delete itself when done.
|
||||
@interface CefWindowDelegate : NSObject <NSWindowDelegate> {
|
||||
@private
|
||||
CefBrowserHostImpl* browser_; // weak
|
||||
}
|
||||
|
||||
@property (nonatomic, assign) CefBrowserHostImpl* browser;
|
||||
|
||||
@end
|
||||
|
||||
@implementation CefWindowDelegate
|
||||
|
||||
@synthesize browser = browser_;
|
||||
|
||||
- (BOOL)windowShouldClose:(id)window {
|
||||
// Protect against multiple requests to close while the close is pending.
|
||||
if (browser_ && browser_->destruction_state() <=
|
||||
CefBrowserHostImpl::DESTRUCTION_STATE_PENDING) {
|
||||
if (browser_->destruction_state() ==
|
||||
CefBrowserHostImpl::DESTRUCTION_STATE_NONE) {
|
||||
// Request that the browser close.
|
||||
browser_->CloseBrowser(false);
|
||||
}
|
||||
|
||||
// Cancel the close.
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Clean ourselves up after clearing the stack of anything that might have the
|
||||
// window on it.
|
||||
[self performSelectorOnMainThread:@selector(cleanup:)
|
||||
withObject:window
|
||||
waitUntilDone:NO];
|
||||
|
||||
// Allow the close.
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)cleanup:(id)window {
|
||||
[self release];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
// Accept-types to file-types helper.
|
||||
|
@ -231,6 +277,10 @@ bool CefBrowserHostImpl::PlatformCreateWindow() {
|
|||
contentRect.size.width = window_rect.size.width;
|
||||
contentRect.size.height = window_rect.size.height;
|
||||
|
||||
// Create the delegate for control and browser window events.
|
||||
CefWindowDelegate* delegate = [[CefWindowDelegate alloc] init];
|
||||
delegate.browser = this;
|
||||
|
||||
newWnd = [[UnderlayOpenGLHostingWindow alloc]
|
||||
initWithContentRect:window_rect
|
||||
styleMask:(NSTitledWindowMask |
|
||||
|
@ -240,6 +290,7 @@ bool CefBrowserHostImpl::PlatformCreateWindow() {
|
|||
NSUnifiedTitleAndToolbarWindowMask )
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO];
|
||||
[newWnd setDelegate:delegate];
|
||||
parentView = [newWnd contentView];
|
||||
window_info_.parent_view = parentView;
|
||||
}
|
||||
|
|
|
@ -456,30 +456,24 @@ LPCTSTR CefBrowserHostImpl::GetWndClass() {
|
|||
|
||||
// static
|
||||
LRESULT CALLBACK CefBrowserHostImpl::WndProc(HWND hwnd, UINT message,
|
||||
WPARAM wParam, LPARAM lParam) {
|
||||
WPARAM wParam, LPARAM lParam) {
|
||||
CefBrowserHostImpl* browser =
|
||||
static_cast<CefBrowserHostImpl*>(ui::GetWindowUserData(hwnd));
|
||||
|
||||
switch (message) {
|
||||
case WM_CLOSE:
|
||||
if (browser) {
|
||||
bool handled(false);
|
||||
|
||||
if (browser->client_.get()) {
|
||||
CefRefPtr<CefLifeSpanHandler> handler =
|
||||
browser->client_->GetLifeSpanHandler();
|
||||
if (handler.get()) {
|
||||
// Give the client a chance to handle this one.
|
||||
handled = handler->DoClose(browser);
|
||||
}
|
||||
// Protect against multiple requests to close while the close is pending.
|
||||
if (browser && browser->destruction_state() <= DESTRUCTION_STATE_PENDING) {
|
||||
if (browser->destruction_state() == DESTRUCTION_STATE_NONE) {
|
||||
// Request that the browser close.
|
||||
browser->CloseBrowser(false);
|
||||
}
|
||||
|
||||
if (handled)
|
||||
return 0;
|
||||
|
||||
// We are our own parent in this case.
|
||||
browser->ParentWindowWillClose();
|
||||
// Cancel the close.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allow the close.
|
||||
break;
|
||||
|
||||
case WM_DESTROY:
|
||||
|
@ -487,11 +481,9 @@ LRESULT CALLBACK CefBrowserHostImpl::WndProc(HWND hwnd, UINT message,
|
|||
// Clear the user data pointer.
|
||||
ui::SetWindowUserData(hwnd, NULL);
|
||||
|
||||
// Destroy the browser.
|
||||
browser->DestroyBrowser();
|
||||
|
||||
// Release the reference added in PlatformCreateWindow().
|
||||
browser->Release();
|
||||
// Force the browser to be destroyed and release the reference added in
|
||||
// PlatformCreateWindow().
|
||||
browser->WindowDestroyed();
|
||||
}
|
||||
return 0;
|
||||
|
||||
|
@ -574,8 +566,10 @@ bool CefBrowserHostImpl::PlatformCreateWindow() {
|
|||
}
|
||||
|
||||
void CefBrowserHostImpl::PlatformCloseWindow() {
|
||||
if (window_info_.window != NULL)
|
||||
PostMessage(window_info_.window, WM_CLOSE, 0, 0);
|
||||
if (window_info_.window != NULL) {
|
||||
HWND frameWnd = GetAncestor(window_info_.window, GA_ROOT);
|
||||
PostMessage(frameWnd, WM_CLOSE, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void CefBrowserHostImpl::PlatformSizeTo(int width, int height) {
|
||||
|
|
|
@ -34,10 +34,6 @@
|
|||
#include "sandbox/win/src/sandbox_types.h"
|
||||
#endif
|
||||
|
||||
// Both the CefContext constuctor and the CefContext::RemoveBrowser method need
|
||||
// to initialize or reset to the same value.
|
||||
const int kNextBrowserIdReset = 1;
|
||||
|
||||
// Global CefContext pointer
|
||||
CefRefPtr<CefContext> _Context;
|
||||
|
||||
|
|
|
@ -136,6 +136,14 @@ void CefJavaScriptDialogManager::RunBeforeUnloadDialog(
|
|||
const string16& message_text,
|
||||
bool is_reload,
|
||||
const DialogClosedCallback& callback) {
|
||||
if (browser_->destruction_state() >=
|
||||
CefBrowserHostImpl::DESTRUCTION_STATE_ACCEPTED) {
|
||||
// Currently destroying the browser. Accept the unload without showing
|
||||
// the prompt.
|
||||
callback.Run(true, string16());
|
||||
return;
|
||||
}
|
||||
|
||||
CefRefPtr<CefClient> client = browser_->GetClient();
|
||||
if (client.get()) {
|
||||
CefRefPtr<CefJSDialogHandler> handler = client->GetJSDialogHandler();
|
||||
|
|
|
@ -119,7 +119,8 @@ void CEF_CALLBACK browser_host_parent_window_will_close(
|
|||
CefBrowserHostCppToC::Get(self)->ParentWindowWillClose();
|
||||
}
|
||||
|
||||
void CEF_CALLBACK browser_host_close_browser(struct _cef_browser_host_t* self) {
|
||||
void CEF_CALLBACK browser_host_close_browser(struct _cef_browser_host_t* self,
|
||||
int force_close) {
|
||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||
|
||||
DCHECK(self);
|
||||
|
@ -127,7 +128,8 @@ void CEF_CALLBACK browser_host_close_browser(struct _cef_browser_host_t* self) {
|
|||
return;
|
||||
|
||||
// Execute
|
||||
CefBrowserHostCppToC::Get(self)->CloseBrowser();
|
||||
CefBrowserHostCppToC::Get(self)->CloseBrowser(
|
||||
force_close?true:false);
|
||||
}
|
||||
|
||||
void CEF_CALLBACK browser_host_set_focus(struct _cef_browser_host_t* self,
|
||||
|
|
|
@ -81,14 +81,15 @@ void CefBrowserHostCToCpp::ParentWindowWillClose() {
|
|||
struct_->parent_window_will_close(struct_);
|
||||
}
|
||||
|
||||
void CefBrowserHostCToCpp::CloseBrowser() {
|
||||
void CefBrowserHostCToCpp::CloseBrowser(bool force_close) {
|
||||
if (CEF_MEMBER_MISSING(struct_, close_browser))
|
||||
return;
|
||||
|
||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||
|
||||
// Execute
|
||||
struct_->close_browser(struct_);
|
||||
struct_->close_browser(struct_,
|
||||
force_close);
|
||||
}
|
||||
|
||||
void CefBrowserHostCToCpp::SetFocus(bool enable) {
|
||||
|
|
|
@ -39,7 +39,7 @@ class CefBrowserHostCToCpp
|
|||
// CefBrowserHost methods
|
||||
virtual CefRefPtr<CefBrowser> GetBrowser() OVERRIDE;
|
||||
virtual void ParentWindowWillClose() OVERRIDE;
|
||||
virtual void CloseBrowser() OVERRIDE;
|
||||
virtual void CloseBrowser(bool force_close) OVERRIDE;
|
||||
virtual void SetFocus(bool enable) OVERRIDE;
|
||||
virtual CefWindowHandle GetWindowHandle() OVERRIDE;
|
||||
virtual CefWindowHandle GetOpenerWindowHandle() OVERRIDE;
|
||||
|
|
|
@ -36,6 +36,9 @@ void AppGetSettings(CefSettings& settings);
|
|||
// argument.
|
||||
bool AppIsOffScreenRenderingEnabled();
|
||||
|
||||
// Quit the application message loop.
|
||||
void AppQuitMessageLoop();
|
||||
|
||||
// Implementations for various tests.
|
||||
void RunGetSourceTest(CefRefPtr<CefBrowser> browser);
|
||||
void RunGetTextTest(CefRefPtr<CefBrowser> browser);
|
||||
|
|
|
@ -24,12 +24,31 @@ char szWorkingDir[512]; // The current working directory
|
|||
// The global ClientHandler reference.
|
||||
extern CefRefPtr<ClientHandler> g_handler;
|
||||
|
||||
void destroy(void) {
|
||||
CefQuitMessageLoop();
|
||||
void destroy(GtkWidget* widget, gpointer data) {
|
||||
// Quitting CEF is handled in ClientHandler::OnBeforeClose().
|
||||
}
|
||||
|
||||
gboolean delete_event(GtkWidget* widget, GdkEvent* event,
|
||||
GtkWindow* window) {
|
||||
if (g_handler.get() && !g_handler->IsClosing()) {
|
||||
CefRefPtr<CefBrowser> browser = g_handler->GetBrowser();
|
||||
if (browser.get()) {
|
||||
// Notify the browser window that we would like to close it. This
|
||||
// will result in a call to ClientHandler::DoClose() if the
|
||||
// JavaScript 'onbeforeunload' event handler allows it.
|
||||
browser->GetHost()->CloseBrowser(false);
|
||||
|
||||
// Allow the close.
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// Cancel the close.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void TerminationSignalHandler(int signatl) {
|
||||
destroy();
|
||||
AppQuitMessageLoop();
|
||||
}
|
||||
|
||||
// Callback for Debug > Get Source... menu item.
|
||||
|
@ -404,10 +423,10 @@ int main(int argc, char* argv[]) {
|
|||
|
||||
gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
|
||||
|
||||
g_signal_connect(G_OBJECT(window), "destroy",
|
||||
G_CALLBACK(gtk_widget_destroyed), &window);
|
||||
g_signal_connect(G_OBJECT(window), "destroy",
|
||||
G_CALLBACK(destroy), NULL);
|
||||
g_signal_connect(G_OBJECT(window), "delete_event",
|
||||
G_CALLBACK(delete_event), window);
|
||||
|
||||
// Create the handler.
|
||||
g_handler = new ClientHandler();
|
||||
|
@ -444,4 +463,8 @@ int main(int argc, char* argv[]) {
|
|||
|
||||
std::string AppGetWorkingDirectory() {
|
||||
return szWorkingDir;
|
||||
}
|
||||
}
|
||||
|
||||
void AppQuitMessageLoop() {
|
||||
CefQuitMessageLoop();
|
||||
}
|
||||
|
|
|
@ -155,16 +155,30 @@ static NSAutoreleasePool* g_autopool = nil;
|
|||
// Called when the window is about to close. Perform the self-destruction
|
||||
// sequence by getting rid of the window. By returning YES, we allow the window
|
||||
// to be removed from the screen.
|
||||
- (BOOL)windowShouldClose:(id)window {
|
||||
- (BOOL)windowShouldClose:(id)window {
|
||||
if (g_handler.get() && !g_handler->IsClosing()) {
|
||||
CefRefPtr<CefBrowser> browser = g_handler->GetBrowser();
|
||||
if (browser.get()) {
|
||||
// Notify the browser window that we would like to close it. This
|
||||
// will result in a call to ClientHandler::DoClose() if the
|
||||
// JavaScript 'onbeforeunload' event handler allows it.
|
||||
browser->GetHost()->CloseBrowser(false);
|
||||
|
||||
// Cancel the close.
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to make the window go away.
|
||||
[window autorelease];
|
||||
|
||||
|
||||
// Clean ourselves up after clearing the stack of anything that might have the
|
||||
// window on it.
|
||||
[self performSelectorOnMainThread:@selector(cleanup:)
|
||||
withObject:window
|
||||
waitUntilDone:NO];
|
||||
|
||||
|
||||
// Allow the close.
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
@ -500,11 +514,10 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) {
|
|||
}
|
||||
|
||||
// Sent by the default notification center immediately before the application
|
||||
// terminates.
|
||||
// terminates. Quitting CEF is handled in ClientHandler::OnBeforeClose().
|
||||
- (void)applicationWillTerminate:(NSNotification *)aNotification {
|
||||
// Shut down CEF.
|
||||
// Release the handler.
|
||||
g_handler = NULL;
|
||||
CefShutdown();
|
||||
|
||||
[self release];
|
||||
|
||||
|
@ -555,7 +568,9 @@ int main(int argc, char* argv[]) {
|
|||
// Run the application message loop.
|
||||
CefRunMessageLoop();
|
||||
|
||||
// Don't put anything below this line because it won't be executed.
|
||||
// Shut down CEF.
|
||||
CefShutdown();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -565,3 +580,7 @@ int main(int argc, char* argv[]) {
|
|||
std::string AppGetWorkingDirectory() {
|
||||
return szWorkingDir;
|
||||
}
|
||||
|
||||
void AppQuitMessageLoop() {
|
||||
CefQuitMessageLoop();
|
||||
}
|
||||
|
|
|
@ -42,6 +42,12 @@ BOOL InitInstance(HINSTANCE, int);
|
|||
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
|
||||
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
// Used for processing messages on the main application thread while running
|
||||
// in multi-threaded message loop mode.
|
||||
HWND hMessageWnd = NULL;
|
||||
HWND CreateMessageWindow(HINSTANCE hInstance);
|
||||
LRESULT CALLBACK MessageWndProc(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
// The global ClientHandler reference.
|
||||
extern CefRefPtr<ClientHandler> g_handler;
|
||||
|
||||
|
@ -115,6 +121,10 @@ int APIENTRY wWinMain(HINSTANCE hInstance,
|
|||
// recieves a WM_QUIT message.
|
||||
CefRunMessageLoop();
|
||||
} else {
|
||||
// Create a hidden window for message processing.
|
||||
hMessageWnd = CreateMessageWindow(hInstance);
|
||||
ASSERT(hMessageWnd);
|
||||
|
||||
MSG msg;
|
||||
|
||||
// Run the application message loop.
|
||||
|
@ -125,6 +135,9 @@ int APIENTRY wWinMain(HINSTANCE hInstance,
|
|||
}
|
||||
}
|
||||
|
||||
DestroyWindow(hMessageWnd);
|
||||
hMessageWnd = NULL;
|
||||
|
||||
result = static_cast<int>(msg.wParam);
|
||||
}
|
||||
|
||||
|
@ -541,17 +554,24 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
|||
break;
|
||||
|
||||
case WM_CLOSE:
|
||||
if (g_handler.get()) {
|
||||
if (g_handler.get() && !g_handler->IsClosing()) {
|
||||
CefRefPtr<CefBrowser> browser = g_handler->GetBrowser();
|
||||
if (browser.get()) {
|
||||
// Let the browser window know we are about to destroy it.
|
||||
browser->GetHost()->ParentWindowWillClose();
|
||||
// Notify the browser window that we would like to close it. This
|
||||
// will result in a call to ClientHandler::DoClose() if the
|
||||
// JavaScript 'onbeforeunload' event handler allows it.
|
||||
browser->GetHost()->CloseBrowser(false);
|
||||
|
||||
// Cancel the close.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Allow the close.
|
||||
break;
|
||||
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
// Quitting CEF is handled in ClientHandler::OnBeforeClose().
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -576,9 +596,50 @@ INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
|
|||
return (INT_PTR)FALSE;
|
||||
}
|
||||
|
||||
HWND CreateMessageWindow(HINSTANCE hInstance) {
|
||||
static const wchar_t kWndClass[] = L"ClientMessageWindow";
|
||||
|
||||
WNDCLASSEX wc = {0};
|
||||
wc.cbSize = sizeof(wc);
|
||||
wc.lpfnWndProc = MessageWndProc;
|
||||
wc.hInstance = hInstance;
|
||||
wc.lpszClassName = kWndClass;
|
||||
RegisterClassEx(&wc);
|
||||
|
||||
return CreateWindow(kWndClass, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0,
|
||||
hInstance, 0);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK MessageWndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
LPARAM lParam) {
|
||||
switch (message) {
|
||||
case WM_COMMAND: {
|
||||
int wmId = LOWORD(wParam);
|
||||
switch (wmId) {
|
||||
case ID_QUIT:
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
|
||||
// Global functions
|
||||
|
||||
std::string AppGetWorkingDirectory() {
|
||||
return szWorkingDir;
|
||||
}
|
||||
|
||||
void AppQuitMessageLoop() {
|
||||
CefRefPtr<CefCommandLine> command_line = AppGetCommandLine();
|
||||
if (command_line->HasSwitch(cefclient::kMultiThreadedMessageLoop)) {
|
||||
// Running in multi-threaded message loop mode. Need to execute
|
||||
// PostQuitMessage on the main application thread.
|
||||
ASSERT(hMessageWnd);
|
||||
PostMessage(hMessageWnd, WM_COMMAND, ID_QUIT, 0);
|
||||
} else {
|
||||
CefQuitMessageLoop();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,9 +35,12 @@ enum client_menu_ids {
|
|||
CLIENT_ID_TESTMENU_RADIOITEM3,
|
||||
};
|
||||
|
||||
int ClientHandler::m_BrowserCount = 0;
|
||||
|
||||
ClientHandler::ClientHandler()
|
||||
: m_MainHwnd(NULL),
|
||||
m_BrowserId(0),
|
||||
m_bIsClosing(false),
|
||||
m_EditHwnd(NULL),
|
||||
m_BackHwnd(NULL),
|
||||
m_ForwardHwnd(NULL),
|
||||
|
@ -257,24 +260,26 @@ void ClientHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
|
|||
m_Browser = browser;
|
||||
m_BrowserId = browser->GetIdentifier();
|
||||
}
|
||||
|
||||
m_BrowserCount++;
|
||||
}
|
||||
|
||||
bool ClientHandler::DoClose(CefRefPtr<CefBrowser> browser) {
|
||||
REQUIRE_UI_THREAD();
|
||||
|
||||
// Closing the main window requires special handling. See the DoClose()
|
||||
// documentation in the CEF header for a detailed destription of this
|
||||
// process.
|
||||
if (m_BrowserId == browser->GetIdentifier()) {
|
||||
// Since the main window contains the browser window, we need to close
|
||||
// the parent window instead of the browser window.
|
||||
CloseMainWindow();
|
||||
// Notify the browser that the parent window is about to close.
|
||||
browser->GetHost()->ParentWindowWillClose();
|
||||
|
||||
// Return true here so that we can skip closing the browser window
|
||||
// in this pass. (It will be destroyed due to the call to close
|
||||
// the parent above.)
|
||||
return true;
|
||||
// Set a flag to indicate that the window close should be allowed.
|
||||
m_bIsClosing = true;
|
||||
}
|
||||
|
||||
// A popup browser window is not contained in another window, so we can let
|
||||
// these windows close by themselves.
|
||||
// Allow the close. For windowed browsers this will result in the OS close
|
||||
// event being sent.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -296,6 +301,11 @@ void ClientHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
|
|||
if (it != m_OpenDevToolsURLs.end())
|
||||
m_OpenDevToolsURLs.erase(it);
|
||||
}
|
||||
|
||||
if (--m_BrowserCount == 0) {
|
||||
// All browser windows have closed. Quit the application message loop.
|
||||
AppQuitMessageLoop();
|
||||
}
|
||||
}
|
||||
|
||||
void ClientHandler::OnLoadStart(CefRefPtr<CefBrowser> browser,
|
||||
|
|
|
@ -236,6 +236,11 @@ class ClientHandler : public CefClient,
|
|||
CefRefPtr<CefBrowser> GetBrowser() { return m_Browser; }
|
||||
int GetBrowserId() { return m_BrowserId; }
|
||||
|
||||
// Returns true if the main browser window is currently closing. Used in
|
||||
// combination with DoClose() and the OS close notification to properly handle
|
||||
// 'onbeforeunload' JavaScript events during window close.
|
||||
bool IsClosing() { return m_bIsClosing; }
|
||||
|
||||
std::string GetLogFile();
|
||||
|
||||
void SetLastDownloadFile(const std::string& fileName);
|
||||
|
@ -249,7 +254,6 @@ class ClientHandler : public CefClient,
|
|||
NOTIFY_DOWNLOAD_ERROR,
|
||||
};
|
||||
void SendNotification(NotificationType type);
|
||||
void CloseMainWindow();
|
||||
|
||||
void ShowDevTools(CefRefPtr<CefBrowser> browser);
|
||||
|
||||
|
@ -297,6 +301,9 @@ class ClientHandler : public CefClient,
|
|||
// The child browser id
|
||||
int m_BrowserId;
|
||||
|
||||
// True if the main browser window is currently closing.
|
||||
bool m_bIsClosing;
|
||||
|
||||
// The edit window handle
|
||||
CefWindowHandle m_EditHwnd;
|
||||
|
||||
|
@ -330,6 +337,10 @@ class ClientHandler : public CefClient,
|
|||
// The startup URL.
|
||||
std::string m_StartupURL;
|
||||
|
||||
// Number of currently existing browser windows. The application will exit
|
||||
// when the number of windows reaches 0.
|
||||
static int m_BrowserCount;
|
||||
|
||||
// Include the default reference counting implementation.
|
||||
IMPLEMENT_REFCOUNTING(ClientHandler);
|
||||
// Include the default locking implementation.
|
||||
|
|
|
@ -54,10 +54,6 @@ void ClientHandler::SetNavState(bool canGoBack, bool canGoForward) {
|
|||
gtk_widget_set_sensitive(GTK_WIDGET(m_ForwardHwnd), false);
|
||||
}
|
||||
|
||||
void ClientHandler::CloseMainWindow() {
|
||||
// TODO(port): Close main window.
|
||||
}
|
||||
|
||||
std::string ClientHandler::GetDownloadPath(const std::string& file_name) {
|
||||
return std::string();
|
||||
}
|
||||
|
|
|
@ -65,10 +65,6 @@ void ClientHandler::SetNavState(bool canGoBack, bool canGoForward) {
|
|||
// TODO(port): Change button status.
|
||||
}
|
||||
|
||||
void ClientHandler::CloseMainWindow() {
|
||||
// TODO(port): Close window
|
||||
}
|
||||
|
||||
std::string ClientHandler::GetDownloadPath(const std::string& file_name) {
|
||||
return std::string();
|
||||
}
|
||||
|
|
|
@ -67,10 +67,6 @@ void ClientHandler::SetNavState(bool canGoBack, bool canGoForward) {
|
|||
EnableWindow(m_ForwardHwnd, canGoForward);
|
||||
}
|
||||
|
||||
void ClientHandler::CloseMainWindow() {
|
||||
::PostMessage(m_MainHwnd, WM_CLOSE, 0, 0);
|
||||
}
|
||||
|
||||
std::string ClientHandler::GetDownloadPath(const std::string& file_name) {
|
||||
TCHAR szFolderPath[MAX_PATH];
|
||||
std::string path;
|
||||
|
|
|
@ -15,6 +15,8 @@ std::string AppGetWorkingDirectory() {
|
|||
CefWindowHandle AppGetMainHwnd() {
|
||||
return NULL;
|
||||
}
|
||||
void AppQuitMessageLoop() {
|
||||
}
|
||||
|
||||
// Process entry point.
|
||||
int main(int argc, char* argv[]) {
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#define ID_WARN_CONSOLEMESSAGE 32000
|
||||
#define ID_WARN_DOWNLOADCOMPLETE 32001
|
||||
#define ID_WARN_DOWNLOADERROR 32002
|
||||
#define ID_QUIT 32500
|
||||
#define ID_TESTS_GETSOURCE 32760
|
||||
#define ID_TESTS_GETTEXT 32761
|
||||
#define ID_TESTS_POPUP 32762
|
||||
|
|
|
@ -83,7 +83,7 @@ class TitleTestHandler : public TestHandler {
|
|||
}
|
||||
|
||||
private:
|
||||
virtual void DestroyTest() {
|
||||
virtual void DestroyTest() OVERRIDE {
|
||||
for (int i = 0; i < 5; ++i)
|
||||
EXPECT_TRUE(got_title_[i]) << "step " << i;
|
||||
|
||||
|
|
|
@ -0,0 +1,306 @@
|
|||
// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#include "include/cef_runnable.h"
|
||||
#include "tests/unittests/test_handler.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const char kLifeSpanUrl[] = "http://tests-life-span/test.html";
|
||||
const char kUnloadDialogText[] = "Are you sure?";
|
||||
const char kUnloadMsg[] = "LifeSpanTestHandler.Unload";
|
||||
|
||||
// Browser side.
|
||||
class LifeSpanTestHandler : public TestHandler {
|
||||
public:
|
||||
struct Settings {
|
||||
Settings()
|
||||
: force_close(false),
|
||||
add_onunload_handler(false),
|
||||
allow_do_close(true),
|
||||
accept_before_unload_dialog(true) {}
|
||||
|
||||
bool force_close;
|
||||
bool add_onunload_handler;
|
||||
bool allow_do_close;
|
||||
bool accept_before_unload_dialog;
|
||||
};
|
||||
|
||||
explicit LifeSpanTestHandler(const Settings& settings)
|
||||
: settings_(settings),
|
||||
executing_delay_close_(false) {}
|
||||
|
||||
virtual void RunTest() OVERRIDE {
|
||||
// Add the resources that we will navigate to/from.
|
||||
std::string page = "<html><script>";
|
||||
|
||||
page += "window.onunload = function() { app.sendMessage('" +
|
||||
std::string(kUnloadMsg) + "'); };";
|
||||
|
||||
if (settings_.add_onunload_handler) {
|
||||
page += "window.onbeforeunload = function() { return '" +
|
||||
std::string(kUnloadDialogText) + "'; };";
|
||||
}
|
||||
|
||||
page += "</script><body>Page</body></html>";
|
||||
AddResource(kLifeSpanUrl, page, "text/html");
|
||||
|
||||
// Create the browser.
|
||||
CreateBrowser(kLifeSpanUrl);
|
||||
}
|
||||
|
||||
virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE {
|
||||
got_after_created_.yes();
|
||||
TestHandler::OnAfterCreated(browser);
|
||||
}
|
||||
|
||||
virtual bool DoClose(CefRefPtr<CefBrowser> browser) OVERRIDE {
|
||||
if (executing_delay_close_)
|
||||
return false;
|
||||
|
||||
EXPECT_TRUE(browser->IsSame(GetBrowser()));
|
||||
|
||||
got_do_close_.yes();
|
||||
|
||||
if (!settings_.allow_do_close) {
|
||||
// The close will be canceled.
|
||||
ScheduleDelayClose();
|
||||
}
|
||||
|
||||
return !settings_.allow_do_close;
|
||||
}
|
||||
|
||||
virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE {
|
||||
if (!executing_delay_close_) {
|
||||
got_before_close_.yes();
|
||||
EXPECT_TRUE(browser->IsSame(GetBrowser()));
|
||||
}
|
||||
|
||||
TestHandler::OnBeforeClose(browser);
|
||||
}
|
||||
|
||||
virtual bool OnBeforeUnloadDialog(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
const CefString& message_text,
|
||||
bool is_reload,
|
||||
CefRefPtr<CefJSDialogCallback> callback) OVERRIDE {
|
||||
if (executing_delay_close_) {
|
||||
callback->Continue(true, CefString());
|
||||
return true;
|
||||
}
|
||||
|
||||
EXPECT_TRUE(browser->IsSame(GetBrowser()));
|
||||
EXPECT_STREQ(kUnloadDialogText, message_text.ToString().c_str());
|
||||
EXPECT_FALSE(is_reload);
|
||||
EXPECT_TRUE(callback.get());
|
||||
|
||||
if (!settings_.accept_before_unload_dialog) {
|
||||
// The close will be canceled.
|
||||
ScheduleDelayClose();
|
||||
}
|
||||
|
||||
got_before_unload_dialog_.yes();
|
||||
callback->Continue(settings_.accept_before_unload_dialog, CefString());
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int httpStatusCode) OVERRIDE {
|
||||
got_load_end_.yes();
|
||||
EXPECT_TRUE(browser->IsSame(GetBrowser()));
|
||||
|
||||
// Attempt to close the browser.
|
||||
browser->GetHost()->CloseBrowser(settings_.force_close);
|
||||
}
|
||||
|
||||
virtual bool OnProcessMessageReceived(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) OVERRIDE {
|
||||
const std::string& message_name = message->GetName();
|
||||
if (message_name == kUnloadMsg) {
|
||||
if (!executing_delay_close_)
|
||||
got_unload_message_.yes();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
TrackCallback got_after_created_;
|
||||
TrackCallback got_do_close_;
|
||||
TrackCallback got_before_close_;
|
||||
TrackCallback got_before_unload_dialog_;
|
||||
TrackCallback got_unload_message_;
|
||||
TrackCallback got_load_end_;
|
||||
TrackCallback got_delay_close_;
|
||||
|
||||
private:
|
||||
// Wait a bit to make sure no additional events are received and then close
|
||||
// the window.
|
||||
void ScheduleDelayClose() {
|
||||
CefPostDelayedTask(TID_UI,
|
||||
NewCefRunnableMethod(this, &LifeSpanTestHandler::DelayClose), 100);
|
||||
}
|
||||
|
||||
void DelayClose() {
|
||||
got_delay_close_.yes();
|
||||
executing_delay_close_ = true;
|
||||
DestroyTest();
|
||||
}
|
||||
|
||||
Settings settings_;
|
||||
|
||||
// Forces the window to close (bypasses test conditions).
|
||||
bool executing_delay_close_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(LifeSpanTest, DoCloseAllow) {
|
||||
LifeSpanTestHandler::Settings settings;
|
||||
settings.allow_do_close = true;
|
||||
CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
|
||||
handler->ExecuteTest();
|
||||
|
||||
EXPECT_TRUE(handler->got_after_created_);
|
||||
EXPECT_TRUE(handler->got_do_close_);
|
||||
EXPECT_TRUE(handler->got_before_close_);
|
||||
EXPECT_FALSE(handler->got_before_unload_dialog_);
|
||||
EXPECT_TRUE(handler->got_unload_message_);
|
||||
EXPECT_TRUE(handler->got_load_end_);
|
||||
EXPECT_FALSE(handler->got_delay_close_);
|
||||
}
|
||||
|
||||
TEST(LifeSpanTest, DoCloseAllowForce) {
|
||||
LifeSpanTestHandler::Settings settings;
|
||||
settings.allow_do_close = true;
|
||||
settings.force_close = true;
|
||||
CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
|
||||
handler->ExecuteTest();
|
||||
|
||||
EXPECT_TRUE(handler->got_after_created_);
|
||||
EXPECT_TRUE(handler->got_do_close_);
|
||||
EXPECT_TRUE(handler->got_before_close_);
|
||||
EXPECT_FALSE(handler->got_before_unload_dialog_);
|
||||
EXPECT_TRUE(handler->got_unload_message_);
|
||||
EXPECT_TRUE(handler->got_load_end_);
|
||||
EXPECT_FALSE(handler->got_delay_close_);
|
||||
}
|
||||
|
||||
TEST(LifeSpanTest, DoCloseDisallow) {
|
||||
LifeSpanTestHandler::Settings settings;
|
||||
settings.allow_do_close = false;
|
||||
CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
|
||||
handler->ExecuteTest();
|
||||
|
||||
EXPECT_TRUE(handler->got_after_created_);
|
||||
EXPECT_TRUE(handler->got_do_close_);
|
||||
EXPECT_FALSE(handler->got_before_close_);
|
||||
EXPECT_FALSE(handler->got_before_unload_dialog_);
|
||||
EXPECT_TRUE(handler->got_unload_message_);
|
||||
EXPECT_TRUE(handler->got_load_end_);
|
||||
EXPECT_TRUE(handler->got_delay_close_);
|
||||
}
|
||||
|
||||
TEST(LifeSpanTest, DoCloseDisallowForce) {
|
||||
LifeSpanTestHandler::Settings settings;
|
||||
settings.allow_do_close = false;
|
||||
settings.force_close = true;
|
||||
CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
|
||||
handler->ExecuteTest();
|
||||
|
||||
EXPECT_TRUE(handler->got_after_created_);
|
||||
EXPECT_TRUE(handler->got_do_close_);
|
||||
EXPECT_FALSE(handler->got_before_close_);
|
||||
EXPECT_FALSE(handler->got_before_unload_dialog_);
|
||||
EXPECT_TRUE(handler->got_unload_message_);
|
||||
EXPECT_TRUE(handler->got_load_end_);
|
||||
EXPECT_TRUE(handler->got_delay_close_);
|
||||
}
|
||||
|
||||
TEST(LifeSpanTest, DoCloseDisallowWithOnUnloadAllow) {
|
||||
LifeSpanTestHandler::Settings settings;
|
||||
settings.allow_do_close = false;
|
||||
settings.add_onunload_handler = true;
|
||||
settings.accept_before_unload_dialog = true;
|
||||
CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
|
||||
handler->ExecuteTest();
|
||||
|
||||
EXPECT_TRUE(handler->got_after_created_);
|
||||
EXPECT_TRUE(handler->got_do_close_);
|
||||
EXPECT_FALSE(handler->got_before_close_);
|
||||
EXPECT_TRUE(handler->got_before_unload_dialog_);
|
||||
EXPECT_TRUE(handler->got_unload_message_);
|
||||
EXPECT_TRUE(handler->got_load_end_);
|
||||
EXPECT_TRUE(handler->got_delay_close_);
|
||||
}
|
||||
|
||||
TEST(LifeSpanTest, DoCloseAllowWithOnUnloadForce) {
|
||||
LifeSpanTestHandler::Settings settings;
|
||||
settings.allow_do_close = true;
|
||||
settings.add_onunload_handler = true;
|
||||
settings.force_close = true;
|
||||
CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
|
||||
handler->ExecuteTest();
|
||||
|
||||
EXPECT_TRUE(handler->got_after_created_);
|
||||
EXPECT_TRUE(handler->got_do_close_);
|
||||
EXPECT_TRUE(handler->got_before_close_);
|
||||
EXPECT_FALSE(handler->got_before_unload_dialog_);
|
||||
EXPECT_TRUE(handler->got_unload_message_);
|
||||
EXPECT_TRUE(handler->got_load_end_);
|
||||
EXPECT_FALSE(handler->got_delay_close_);
|
||||
}
|
||||
|
||||
TEST(LifeSpanTest, DoCloseDisallowWithOnUnloadForce) {
|
||||
LifeSpanTestHandler::Settings settings;
|
||||
settings.allow_do_close = false;
|
||||
settings.add_onunload_handler = true;
|
||||
settings.force_close = true;
|
||||
CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
|
||||
handler->ExecuteTest();
|
||||
|
||||
EXPECT_TRUE(handler->got_after_created_);
|
||||
EXPECT_TRUE(handler->got_do_close_);
|
||||
EXPECT_FALSE(handler->got_before_close_);
|
||||
EXPECT_FALSE(handler->got_before_unload_dialog_);
|
||||
EXPECT_TRUE(handler->got_unload_message_);
|
||||
EXPECT_TRUE(handler->got_load_end_);
|
||||
EXPECT_TRUE(handler->got_delay_close_);
|
||||
}
|
||||
|
||||
TEST(LifeSpanTest, OnUnloadAllow) {
|
||||
LifeSpanTestHandler::Settings settings;
|
||||
settings.add_onunload_handler = true;
|
||||
settings.accept_before_unload_dialog = true;
|
||||
CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
|
||||
handler->ExecuteTest();
|
||||
|
||||
EXPECT_TRUE(handler->got_after_created_);
|
||||
EXPECT_TRUE(handler->got_do_close_);
|
||||
EXPECT_TRUE(handler->got_before_close_);
|
||||
EXPECT_TRUE(handler->got_before_unload_dialog_);
|
||||
EXPECT_TRUE(handler->got_unload_message_);
|
||||
EXPECT_TRUE(handler->got_load_end_);
|
||||
EXPECT_FALSE(handler->got_delay_close_);
|
||||
}
|
||||
|
||||
TEST(LifeSpanTest, OnUnloadDisallow) {
|
||||
LifeSpanTestHandler::Settings settings;
|
||||
settings.add_onunload_handler = true;
|
||||
settings.accept_before_unload_dialog = false;
|
||||
CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
|
||||
handler->ExecuteTest();
|
||||
|
||||
EXPECT_TRUE(handler->got_after_created_);
|
||||
EXPECT_FALSE(handler->got_do_close_);
|
||||
EXPECT_FALSE(handler->got_before_close_);
|
||||
EXPECT_TRUE(handler->got_before_unload_dialog_);
|
||||
EXPECT_FALSE(handler->got_unload_message_);
|
||||
EXPECT_TRUE(handler->got_load_end_);
|
||||
EXPECT_TRUE(handler->got_delay_close_);
|
||||
}
|
|
@ -1018,7 +1018,7 @@ class OrderNavTestHandler : public TestHandler {
|
|||
"window.open('" + std::string(KONav2) + "');", CefString(), 0);
|
||||
} else {
|
||||
// Close the popup window.
|
||||
browser_popup_->GetHost()->CloseBrowser();
|
||||
browser_popup_->GetHost()->CloseBrowser(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1502,7 +1502,7 @@ class PopupNavTestHandler : public TestHandler {
|
|||
} else if (url == kPopupNavPopupUrl) {
|
||||
if (allow_) {
|
||||
got_popup_load_end_.yes();
|
||||
browser->GetHost()->CloseBrowser();
|
||||
browser->GetHost()->CloseBrowser(false);
|
||||
DestroyTest();
|
||||
} else {
|
||||
EXPECT_FALSE(true); // Not reached.
|
||||
|
@ -1513,7 +1513,7 @@ class PopupNavTestHandler : public TestHandler {
|
|||
}
|
||||
|
||||
private:
|
||||
virtual void DestroyTest() {
|
||||
virtual void DestroyTest() OVERRIDE {
|
||||
EXPECT_TRUE(got_on_before_popup_);
|
||||
if (allow_)
|
||||
EXPECT_TRUE(got_popup_load_end_);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "include/cef_app.h"
|
||||
#include "include/cef_task.h"
|
||||
#include "tests/cefclient/client_app.h"
|
||||
#include "tests/unittests/test_handler.h"
|
||||
#include "tests/unittests/test_suite.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/command_line.h"
|
||||
|
@ -27,6 +28,10 @@ class CefTestThread : public base::Thread {
|
|||
// Run the test suite.
|
||||
retval_ = test_suite_->Run();
|
||||
|
||||
// Wait for all browsers to exit.
|
||||
while (TestHandler::HasBrowser())
|
||||
base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
|
||||
|
||||
// Quit the CEF message loop.
|
||||
CefPostTask(TID_UI, NewCefRunnableFunction(CefQuitMessageLoop));
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ void NotifyEvent(base::WaitableEvent* event) {
|
|||
|
||||
// TestHandler
|
||||
|
||||
int TestHandler::browser_count_ = 0;
|
||||
|
||||
TestHandler::TestHandler()
|
||||
: browser_id_(0),
|
||||
completion_event_(true, false) {
|
||||
|
@ -28,6 +30,8 @@ TestHandler::~TestHandler() {
|
|||
}
|
||||
|
||||
void TestHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
|
||||
browser_count_++;
|
||||
|
||||
AutoLock lock_scope(this);
|
||||
if (!browser->IsPopup()) {
|
||||
// Keep the main child window, but not popup windows
|
||||
|
@ -37,15 +41,19 @@ void TestHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
|
|||
}
|
||||
|
||||
void TestHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
|
||||
AutoLock lock_scope(this);
|
||||
if (browser_id_ == browser->GetIdentifier()) {
|
||||
// Free the browser pointer so that the browser can be destroyed
|
||||
browser_ = NULL;
|
||||
browser_id_ = 0;
|
||||
{
|
||||
AutoLock lock_scope(this);
|
||||
if (browser_id_ == browser->GetIdentifier()) {
|
||||
// Free the browser pointer so that the browser can be destroyed
|
||||
browser_ = NULL;
|
||||
browser_id_ = 0;
|
||||
|
||||
// Signal that the test is now complete.
|
||||
completion_event_.Signal();
|
||||
// Signal that the test is now complete.
|
||||
completion_event_.Signal();
|
||||
}
|
||||
}
|
||||
|
||||
browser_count_--;
|
||||
}
|
||||
|
||||
CefRefPtr<CefResourceHandler> TestHandler::GetResourceHandler(
|
||||
|
@ -91,7 +99,7 @@ void TestHandler::ExecuteTest() {
|
|||
void TestHandler::DestroyTest() {
|
||||
AutoLock lock_scope(this);
|
||||
if (browser_id_ != 0)
|
||||
browser_->GetHost()->CloseBrowser();
|
||||
browser_->GetHost()->CloseBrowser(false);
|
||||
}
|
||||
|
||||
void TestHandler::CreateBrowser(const CefString& url) {
|
||||
|
|
|
@ -97,6 +97,9 @@ class TestHandler : public CefClient,
|
|||
// returns.
|
||||
void ExecuteTest();
|
||||
|
||||
// Returns true if a browser currently exists.
|
||||
static bool HasBrowser() { return browser_count_ > 0; }
|
||||
|
||||
protected:
|
||||
// Destroy the browser window. Once the window is destroyed test completion
|
||||
// will be signaled.
|
||||
|
@ -128,6 +131,9 @@ class TestHandler : public CefClient,
|
|||
IMPLEMENT_REFCOUNTING(TestHandler);
|
||||
// Include the default locking implementation.
|
||||
IMPLEMENT_LOCKING(TestHandler);
|
||||
|
||||
// Used to track the number of currently existing browser windows.
|
||||
static int browser_count_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#if defined(OS_MACOSX)
|
||||
#include "base/debug/stack_trace.h"
|
||||
#include "base/file_path.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/i18n/icu_util.h"
|
||||
#include "base/path_service.h"
|
||||
#include "base/process_util.h"
|
||||
|
|
Loading…
Reference in New Issue