chrome: Support unload handlers with TryCloseBrowser

TryCloseBrowser should potentially trigger JavaScript unload handlers
and return false. Add CefBrowserHost::IsReadyToBeClosed for detecting
mandatory close state. Enable, for Chrome style browsers, LifeSpanTest
that don't require DoClose(). Update related documentation.
This commit is contained in:
Marshall Greenblatt
2024-10-17 11:05:30 -04:00
parent 265a733807
commit 6e05c14db2
14 changed files with 347 additions and 121 deletions

View File

@@ -131,34 +131,44 @@ class CefLifeSpanHandler : public virtual CefBaseRefCounted {
virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) {}
///
/// Called when a browser has received a request to close. This may result
/// directly from a call to CefBrowserHost::*CloseBrowser() or indirectly if
/// the browser is parented to a top-level window created by CEF and the user
/// attempts to close that window (by clicking the 'X', for example). The
/// DoClose() method will be called after the JavaScript 'onunload' event has
/// been fired.
/// Called when an Alloy style browser is ready to be closed, meaning that the
/// close has already been initiated and that JavaScript unload handlers have
/// already executed or should be ignored. This may result directly from a
/// call to CefBrowserHost::[Try]CloseBrowser() or indirectly if the browser's
/// top-level parent window was created by CEF and the user attempts to
/// close that window (by clicking the 'X', for example). DoClose() will not
/// be called if the browser's host window/view has already been destroyed
/// (via parent window/view hierarchy tear-down, for example), as it is no
/// longer possible to customize the close behavior at that point.
///
/// An application should handle top-level owner window close notifications by
/// calling CefBrowserHost::TryCloseBrowser() or
/// An application should handle top-level parent window close notifications
/// by calling CefBrowserHost::TryCloseBrowser() or
/// CefBrowserHost::CloseBrowser(false) instead of allowing the window to
/// close immediately (see the examples below). This gives CEF an opportunity
/// to process the 'onbeforeunload' event and optionally cancel the close
/// to process JavaScript unload handlers and optionally cancel the close
/// before DoClose() is called.
///
/// When windowed rendering is enabled CEF will internally create a window or
/// view to host the browser. In that case returning false from DoClose() will
/// send the standard close notification to the browser's top-level owner
/// window (e.g. WM_CLOSE on Windows, performClose: on OS X, "delete_event" on
/// Linux or CefWindowDelegate::CanClose() callback from Views). If the
/// browser's host window/view has already been destroyed (via view hierarchy
/// tear-down, for example) then DoClose() will not be called for that browser
/// since is no longer possible to cancel the close.
/// When windowed rendering is enabled CEF will create an internal child
/// window/view to host the browser. In that case returning false from
/// DoClose() will send the standard close notification to the browser's
/// top-level parent window (e.g. WM_CLOSE on Windows, performClose: on OS X,
/// "delete_event" on Linux or CefWindowDelegate::CanClose() callback from
/// Views).
///
/// When windowed rendering is disabled returning false from DoClose() will
/// cause the browser object to be destroyed immediately.
/// When windowed rendering is disabled there is no internal window/view
/// and returning false from DoClose() will cause the browser object to be
/// destroyed immediately.
///
/// If the browser's top-level owner window requires a non-standard close
/// If the browser's top-level parent window requires a non-standard close
/// notification then send that notification from DoClose() and return true.
/// You are still required to complete the browser close as soon as possible
/// (either by calling [Try]CloseBrowser() or by proceeding with window/view
/// hierarchy tear-down), otherwise the browser will be left in a partially
/// closed state that interferes with proper functioning. Top-level windows
/// created on the browser process UI thread can alternately call
/// CefBrowserHost::IsReadyToBeClosed() in the close handler to check close
/// status instead of relying on custom DoClose() handling. See documentation
/// on that method for additional details.
///
/// The CefLifeSpanHandler::OnBeforeClose() method will be called after
/// DoClose() (if DoClose() is called) and immediately before the browser
@@ -174,7 +184,7 @@ class CefLifeSpanHandler : public virtual CefBaseRefCounted {
/// 1. User clicks the window close button which sends a close notification
/// to the application's top-level window.
/// 2. Application's top-level window receives the close notification and
/// calls TryCloseBrowser() (which internally calls CloseBrowser(false)).
/// calls TryCloseBrowser() (similar to calling CloseBrowser(false)).
/// TryCloseBrowser() returns false so the client cancels the window
/// close.
/// 3. JavaScript 'onbeforeunload' handler executes and shows the close
@@ -182,15 +192,18 @@ class CefLifeSpanHandler : public virtual CefBaseRefCounted {
/// CefJSDialogHandler::OnBeforeUnloadDialog()).
/// 4. User approves the close.
/// 5. JavaScript 'onunload' handler executes.
/// 6. CEF sends a close notification to the application's top-level window
/// (because DoClose() returned false by default).
/// 7. Application's top-level window receives the close notification and
/// 6. Application's DoClose() handler is called and returns false by
/// default.
/// 7. CEF sends a close notification to the application's top-level window
/// (because DoClose() returned false).
/// 8. Application's top-level window receives the close notification and
/// calls TryCloseBrowser(). TryCloseBrowser() returns true so the client
/// allows the window close.
/// 8. Application's top-level window is destroyed.
/// 9. Application's OnBeforeClose() handler is called and the browser object
/// 9. Application's top-level window is destroyed, triggering destruction
/// of the child browser window.
/// 10. Application's OnBeforeClose() handler is called and the browser object
/// is destroyed.
/// 10. Application exits by calling CefQuitMessageLoop() if no other browsers
/// 11. Application exits by calling CefQuitMessageLoop() if no other browsers
/// exist.
///
/// Example 2: Using CefBrowserHost::CloseBrowser(false) and implementing the
@@ -208,12 +221,15 @@ class CefLifeSpanHandler : public virtual CefBaseRefCounted {
/// 4. User approves the close.
/// 5. JavaScript 'onunload' handler executes.
/// 6. Application's DoClose() handler is called. Application will:
/// A. Set a flag to indicate that the next close attempt will be allowed.
/// A. Set a flag to indicate that the next top-level window close attempt
/// will be allowed.
/// B. Return false.
/// 7. CEF sends an close notification to the application's top-level window.
/// 7. CEF sends a close notification to the application's top-level window
/// (because DoClose() returned false).
/// 8. Application's top-level window receives the close notification and
/// allows the window to close based on the flag from #6B.
/// 9. Application's top-level window is destroyed.
/// allows the window to close based on the flag from #6A.
/// 9. Application's top-level window is destroyed, triggering destruction
/// of the child browser window.
/// 10. Application's OnBeforeClose() handler is called and the browser object
/// is destroyed.
/// 11. Application exits by calling CefQuitMessageLoop() if no other browsers