diff --git a/tests/cefclient/cefclient_mac.mm b/tests/cefclient/cefclient_mac.mm index b582733be..aa9cc929c 100644 --- a/tests/cefclient/cefclient_mac.mm +++ b/tests/cefclient/cefclient_mac.mm @@ -36,9 +36,6 @@ char szWorkingDir[512]; // The current working directory const int kWindowWidth = 800; const int kWindowHeight = 600; -// Memory AutoRelease pool. -static NSAutoreleasePool* g_autopool = nil; - // Provide the CefAppProtocol implementation required by CEF. @interface ClientApplication : NSApplication { @private @@ -469,16 +466,22 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) { RunOtherTests(g_handler->GetBrowser()); } -// Sent by the default notification center immediately before the application -// terminates. Quitting CEF is handled in ClientHandler::OnBeforeClose(). +// Called when the application’s Quit menu item is selected. +- (NSApplicationTerminateReply)applicationShouldTerminate: + (NSApplication *)sender { + // Request that all browser windows close. + if (g_handler.get()) + g_handler->CloseAllBrowsers(false); + + // Cancel the termination. The application will exit after all windows have + // closed. + return NSTerminateCancel; +} + +// Sent immediately before the application terminates. This signal should not +// be called because we cancel the termination. - (void)applicationWillTerminate:(NSNotification *)aNotification { - // Release the handler. - g_handler = NULL; - - [self release]; - - // Release the AutoRelease pool. - [g_autopool release]; + ASSERT(false); // Not reached. } @end @@ -497,7 +500,7 @@ int main(int argc, char* argv[]) { getcwd(szWorkingDir, sizeof(szWorkingDir)); // Initialize the AutoRelease pool. - g_autopool = [[NSAutoreleasePool alloc] init]; + NSAutoreleasePool* autopool = [[NSAutoreleasePool alloc] init]; // Initialize the ClientApplication instance. [ClientApplication sharedApplication]; @@ -527,6 +530,15 @@ int main(int argc, char* argv[]) { // Shut down CEF. CefShutdown(); + // Release the handler. + g_handler = NULL; + + // Release the delegate. + [delegate release]; + + // Release the AutoRelease pool. + [autopool release]; + return 0; } diff --git a/tests/cefclient/cefclient_win.cpp b/tests/cefclient/cefclient_win.cpp index 283530b19..7daacdbae 100644 --- a/tests/cefclient/cefclient_win.cpp +++ b/tests/cefclient/cefclient_win.cpp @@ -358,7 +358,8 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); return 0; case IDM_EXIT: - DestroyWindow(hWnd); + if (g_handler.get()) + g_handler->CloseAllBrowsers(false); return 0; case ID_WARN_CONSOLEMESSAGE: if (g_handler.get()) { diff --git a/tests/cefclient/client_handler.cpp b/tests/cefclient/client_handler.cpp index ab950ab1b..4a656f77e 100644 --- a/tests/cefclient/client_handler.cpp +++ b/tests/cefclient/client_handler.cpp @@ -311,6 +311,9 @@ void ClientHandler::OnAfterCreated(CefRefPtr browser) { // We need to keep the main child window, but not popup windows m_Browser = browser; m_BrowserId = browser->GetIdentifier(); + } else if (browser->IsPopup()) { + // Add to the list of popup browsers. + m_PopupBrowsers.push_back(browser); } m_BrowserCount++; @@ -352,6 +355,15 @@ void ClientHandler::OnBeforeClose(CefRefPtr browser) { m_OpenDevToolsURLs.find(browser->GetMainFrame()->GetURL()); if (it != m_OpenDevToolsURLs.end()) m_OpenDevToolsURLs.erase(it); + + // Remove from the browser popup list. + BrowserList::iterator bit = m_PopupBrowsers.begin(); + for (; bit != m_PopupBrowsers.end(); ++bit) { + if ((*bit)->IsSame(browser)) { + m_PopupBrowsers.erase(bit); + break; + } + } } if (--m_BrowserCount == 0) { @@ -560,6 +572,28 @@ void ClientHandler::SetButtonHwnds(CefWindowHandle backHwnd, m_StopHwnd = stopHwnd; } +void ClientHandler::CloseAllBrowsers(bool force_close) { + if (!CefCurrentlyOn(TID_UI)) { + // Execute on the UI thread. + CefPostTask(TID_UI, + NewCefRunnableMethod(this, &ClientHandler::CloseAllBrowsers, + force_close)); + return; + } + + if (!m_PopupBrowsers.empty()) { + // Request that any popup browsers close. + BrowserList::const_iterator it = m_PopupBrowsers.begin(); + for (; it != m_PopupBrowsers.end(); ++it) + (*it)->GetHost()->CloseBrowser(force_close); + } + + if (m_Browser.get()) { + // Request that the main browser close. + m_Browser->GetHost()->CloseBrowser(force_close); + } +} + std::string ClientHandler::GetLogFile() { AutoLock lock_scope(this); return m_LogFile; diff --git a/tests/cefclient/client_handler.h b/tests/cefclient/client_handler.h index c1dc04526..2ed2b1deb 100644 --- a/tests/cefclient/client_handler.h +++ b/tests/cefclient/client_handler.h @@ -6,6 +6,7 @@ #define CEF_TESTS_CEFCLIENT_CLIENT_HANDLER_H_ #pragma once +#include #include #include #include @@ -236,6 +237,9 @@ class ClientHandler : public CefClient, CefRefPtr GetBrowser() { return m_Browser; } int GetBrowserId() { return m_BrowserId; } + // Request that all existing browser windows close. + void CloseAllBrowsers(bool force_close); + // 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. @@ -295,6 +299,10 @@ class ClientHandler : public CefClient, // The child browser window CefRefPtr m_Browser; + // List of any popup browser windows. Only accessed on the CEF UI thread. + typedef std::list > BrowserList; + BrowserList m_PopupBrowsers; + // The main frame window handle CefWindowHandle m_MainHwnd;