diff --git a/app.cpp b/app.cpp index 9e617a4..f67ebe4 100644 --- a/app.cpp +++ b/app.cpp @@ -3,10 +3,54 @@ // Project website: https://github.com/cztomczak/phpdesktop #include "app.h" +#include "client.h" +#include "mongoose_server.h" #include "settings.h" #include "include/wrapper/cef_helpers.h" +void CreateMainBrowser() +{ + LOG(INFO) << "Create main browser"; + + json_value* app_settings = Settings(); + CefBrowserSettings browser_settings; + + CefWindowInfo window_info; + std::string runtime_style((*app_settings)["chrome"]["runtime_style"]); + if (runtime_style == "alloy") { + window_info.runtime_style = CEF_RUNTIME_STYLE_ALLOY; + LOG(INFO) << "Runtime style: alloy"; + } else if (runtime_style == "chrome") { + window_info.runtime_style = CEF_RUNTIME_STYLE_CHROME; + LOG(INFO) << "Runtime style: chrome"; + } else { + LOG(WARNING) << "Invalid runtime style in settings.json: " << runtime_style; + window_info.runtime_style = CEF_RUNTIME_STYLE_ALLOY; + } + + // Create window explicitilly TODO + // std::string app_icon_path((*app_settings)["main_window"]["icon"]); + // app_icon_path = GetFullPath(app_icon_path); + // bool center_on_screen = (*app_settings)["main_window"]["center_on_screen"]; + // const char* title = (*Settings())["main_window"]["title"]; + + int default_width = static_cast( + (*app_settings)["main_window"]["default_size"][0]); + int default_height = static_cast( + (*app_settings)["main_window"]["default_size"][1]); + CefRect browser_rect(0, 0, default_width, default_height); + window_info.SetAsChild(nullptr, browser_rect); + + CefBrowserHost::CreateBrowser( + window_info, + Client::GetInstance(), + mongoose_get_url(), + browser_settings, + nullptr, + nullptr); +} + App::App() { } @@ -62,5 +106,5 @@ void App::OnBeforeCommandLineProcessing(const CefString& process_type, void App::OnContextInitialized() { CEF_REQUIRE_UI_THREAD(); - const char* title = (*Settings())["main_window"]["title"]; + CreateMainBrowser(); } diff --git a/client.cpp b/client.cpp index 8e87ba3..974ebcd 100644 --- a/client.cpp +++ b/client.cpp @@ -32,6 +32,26 @@ Client* Client::GetInstance() { } } +bool Client::IsClosing() +{ + return is_closing; +} + +void Client::CloseAllBrowsers(bool force_close) +{ + CEF_REQUIRE_UI_THREAD(); + LOG(INFO) << "Close all browsers"; + + if (browser_list_.empty()) { + return; + } + + BrowserList::const_iterator it = browser_list_.begin(); + for (; it != browser_list_.end(); ++it) { + (*it)->GetHost()->CloseBrowser(force_close); + } +} + // CefContextMenuHandler. #define _MENU_ID_DEVTOOLS MENU_ID_USER_FIRST + 1 @@ -143,8 +163,7 @@ void Client::OnBeforeClose(CefRefPtr browser) // Cookies are not flushed to disk when closing app immediately. // Need to call FlushStore manually when browser is closing. - browser->GetHost()->GetRequestContext()->GetCookieManager(nullptr) - ->FlushStore(nullptr); + browser->GetHost()->GetRequestContext()->GetCookieManager(nullptr)->FlushStore(nullptr); // Remove from the list of existing browsers. BrowserList::iterator bit = browser_list_.begin(); diff --git a/client.h b/client.h index 9ee90f2..7621388 100644 --- a/client.h +++ b/client.h @@ -21,6 +21,8 @@ class Client : public CefClient, // Provide access to the single global instance of this object. static Client* GetInstance(); + bool IsClosing(); + void CloseAllBrowsers(bool force_close); // CefClient. CefRefPtr GetContextMenuHandler() override { @@ -84,6 +86,8 @@ class Client : public CefClient, typedef std::list> BrowserList; BrowserList browser_list_; + bool is_closing = false; + // Include the default reference counting implementation. IMPLEMENT_REFCOUNTING(Client); }; diff --git a/main.mm b/main.mm index da48ff7..96812e5 100644 --- a/main.mm +++ b/main.mm @@ -10,6 +10,7 @@ #include "mongoose_server.h" #include "settings.h" +#include "include/cef_application_mac.h" #include "include/base/cef_logging.h" #include "include/wrapper/cef_helpers.h" #import "include/wrapper/cef_library_loader.h" @@ -24,47 +25,58 @@ // Globals std::string g_cgi_env_from_argv = ""; -void create_browser() -{ - // The call to CreateBrowserSync cannot be in the same block scope - // as the call to CefShutdown otherwise it results in segmentation - // fault with the stack trace as seen below. Making a call to - // browser->Release() did not help. - // ---- - // #0 MaybeSendDestroyedNotification () at - // ./../../chrome/browser/profiles/profile.cc:294 - // #1 0x00007ffff34c74b5 in Shutdown () at - // ../../cef/libcef/browser/browser_context.cc:81 - // ---- - json_value* app_settings = Settings(); - CefBrowserSettings browser_settings; - CefWindowInfo window_info; - std::string runtime_style((*app_settings)["chrome"]["runtime_style"]); - if (runtime_style == "alloy") { - window_info.runtime_style = CEF_RUNTIME_STYLE_ALLOY; - LOG(INFO) << "Runtime style: Alloy"; - } else if (runtime_style == "chrome") { - window_info.runtime_style = CEF_RUNTIME_STYLE_CHROME; - LOG(INFO) << "Runtime style: Chrome"; - } else { - LOG(WARNING) << "Invalid runtime style in settings.json: " << runtime_style; - window_info.runtime_style = CEF_RUNTIME_STYLE_ALLOY; - } - int default_width = static_cast( - (*app_settings)["main_window"]["default_size"][0]); - int default_height = static_cast( - (*app_settings)["main_window"]["default_size"][1]); - CefRect browser_rect(0, 0, default_width, default_height); - window_info.SetAsChild(nullptr, browser_rect); - CefRefPtr browser = CefBrowserHost::CreateBrowserSync( - window_info, - Client::GetInstance(), - mongoose_get_url(), - browser_settings, - nullptr, - nullptr); - LOG(INFO) << "Browser window handle=" << browser->GetHost()->GetWindowHandle(); +@interface SharedAppDelegate : NSObject + - (void)createApplication:(id)object; + - (void)tryToTerminateApplication:(NSApplication*)app; +@end + +@interface SharedApplication : NSApplication { + @private + BOOL handlingSendEvent_; } +@end + +@implementation SharedApplication + - (BOOL)isHandlingSendEvent { + return handlingSendEvent_; + } + + - (void)setHandlingSendEvent:(BOOL)handlingSendEvent { + handlingSendEvent_ = handlingSendEvent; + } + + - (void)sendEvent:(NSEvent*)event { + CefScopedSendingEvent sendingEventScoper; + [super sendEvent:event]; + } + + - (void)terminate:(id)sender { + SharedAppDelegate* delegate = static_cast([NSApp delegate]); + [delegate tryToTerminateApplication:self]; + } +@end + +@implementation SharedAppDelegate + - (void)createApplication:(id)object { + [NSApplication sharedApplication]; + [[NSBundle mainBundle] loadNibNamed:@"MainMenu" + owner:NSApp + topLevelObjects:nil]; + [[NSApplication sharedApplication] setDelegate:self]; + } + + - (void)tryToTerminateApplication:(NSApplication*)app { + Client* client = Client::GetInstance(); + if (client && !client->IsClosing()) { + client->CloseAllBrowsers(false); + } + } + + - (NSApplicationTerminateReply)applicationShouldTerminate: + (NSApplication*)sender { + return NSTerminateNow; + } +@end int main(int argc, char **argv) { // Load the CEF framework library at runtime instead of linking directly @@ -74,6 +86,8 @@ int main(int argc, char **argv) { return 1; } + @autoreleasepool { + // Passing ENV variables to PHP using the --cgi-environment // command line arg passed to app. if (argv) { @@ -221,28 +235,25 @@ int remote_debugging_port( cef_settings.remote_debugging_port = remote_debugging_port; } - // App implements application-level callbacks for the browser - // process. + // App implements application-level callbacks for the browser process. CefRefPtr app(new App); + [SharedApplication sharedApplication]; + // Log messages created by LOG() macro will be written to debug.log // file only after CEF was initialized. Before CEF is initialized // all logs are only printed to console. LOG(INFO) << "Initialize CEF"; - CefInitialize(main_args, cef_settings, app.get(), nullptr); - - // Create window TODO - std::string app_icon_path((*app_settings)["main_window"]["icon"]); - app_icon_path = GetFullPath(app_icon_path); - bool center_on_screen = (*app_settings)["main_window"]["center_on_screen"]; - int default_width = static_cast( - (*app_settings)["main_window"]["default_size"][0]); - int default_height = static_cast( - (*app_settings)["main_window"]["default_size"][1]); + if (!CefInitialize(main_args, cef_settings, app.get(), nullptr)) { + LOG(ERROR) << "Failed to initialize CEF"; + return 1; + } - // Create browser - LOG(INFO) << "Create browser"; - create_browser(); + // Create the application delegate. + NSObject* delegate = [[SharedAppDelegate alloc] init]; + [delegate performSelectorOnMainThread:@selector(createApplication:) + withObject:nil + waitUntilDone:NO]; LOG(INFO) << "Run CEF message loop"; CefRunMessageLoop(); @@ -253,5 +264,7 @@ int remote_debugging_port( LOG(INFO) << "Shutdown CEF"; CefShutdown(); + } // end @autoreleasepool + return 0; } diff --git a/settings.json b/settings.json index 18c89f5..3905b90 100644 --- a/settings.json +++ b/settings.json @@ -33,7 +33,7 @@ "enable_menu": true, "navigation": true, "print": true, - "view_source": true, + "view_source": false, "devtools": true } }