From b4df1318e6c909cf91f6e6c2e6dd74833de05748 Mon Sep 17 00:00:00 2001 From: Glenn Ruehle Date: Sun, 16 Dec 2012 10:44:02 -0800 Subject: [PATCH 01/12] Initial file association on mac. --- appshell/cefclient_mac.mm | 64 +++++++++++++++++++++++++++++++++++-- appshell/client_handler.cpp | 7 ++++ appshell/client_handler.h | 1 + appshell/mac/Info.plist | 35 ++++++++++++++++++++ 4 files changed, 105 insertions(+), 2 deletions(-) diff --git a/appshell/cefclient_mac.mm b/appshell/cefclient_mac.mm index 7f48c4ff1..bdad6a762 100644 --- a/appshell/cefclient_mac.mm +++ b/appshell/cefclient_mac.mm @@ -45,6 +45,9 @@ // Memory AutoRelease pool. static NSAutoreleasePool* g_autopool = nil; +// Files passed to the app at startup +static NSMutableArray* pendingOpenFiles; + // Provide the CefAppProtocol implementation required by CEF. @interface ClientApplication : NSApplication { @private @@ -262,6 +265,8 @@ - (void)cleanup:(id)window { // Receives notifications from the application. Will delete itself when done. @interface ClientAppDelegate : NSObject - (void)createApp:(id)object; +- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename; +- (BOOL)application:(NSApplication *)theApplication openFiles:(NSArray *)filenames; @end @implementation ClientAppDelegate @@ -396,14 +401,37 @@ - (void)createApp:(id)object { window_info.SetAsChild(contentView, 0, 0, content_rect.size.width, content_rect.size.height); NSString* str = [[startupUrl absoluteString] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - CefBrowserHost::CreateBrowser(window_info, g_handler.get(), + CefBrowserHost::CreateBrowserSync(window_info, g_handler.get(), [str UTF8String], settings); + + if (pendingOpenFiles) { + // Set the appshell.startupFiles property after a short delay to give the window + // object a chance to initialize + [self performSelector:@selector(sendStartupFilesToApp) withObject:self afterDelay:0.5]; + } // Show the window. [mainWnd display]; [mainWnd makeKeyAndOrderFront: nil]; } +- (void)sendStartupFilesToApp { + std::string fileArray = "["; + NSUInteger count = [pendingOpenFiles count]; + for (NSUInteger i = 0; i < count; i++) { + NSString* filename = [pendingOpenFiles objectAtIndex:i]; + + fileArray += ("'" + std::string([filename UTF8String]) + "'"); + if (i < count - 1) + fileArray += ","; + } + fileArray += "]"; + + std::string cmd = "appshell.startupFiles=" + fileArray; + g_handler->GetBrowser()->GetMainFrame()->ExecuteJavaScript(CefString(cmd), + g_handler->GetBrowser()->GetMainFrame()->GetURL(), 0); + +} // Sent by the default notification center immediately before the application // terminates. - (void)applicationWillTerminate:(NSNotification *)aNotification { @@ -434,6 +462,35 @@ - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)theAp return NSTerminateNow; } +- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename { + if (g_handler) { + CefRefPtr browser = ClientHandler::GetBrowserForNativeWindow([NSApp keyWindow]); + g_handler->SendOpenFileCommand(browser, CefString([filename UTF8String])); + } else { + // App is just starting up. Save the filename so we can open it later. + if (!pendingOpenFiles) { + pendingOpenFiles = [[NSMutableArray alloc] init]; + [pendingOpenFiles addObject:filename]; + } + } + return YES; +} + +- (BOOL)application:(NSApplication *)theApplication openFiles:(NSArray *)filenames { + if (g_handler) { + CefRefPtr browser = ClientHandler::GetBrowserForNativeWindow([NSApp keyWindow]); + for (NSUInteger i = 0; i < [filenames count]; i++) { + g_handler->SendOpenFileCommand(browser, CefString([[filenames objectAtIndex:i] UTF8String])); + } + } else { + // App is just starting up. Save the filenames so we can open them later. + pendingOpenFiles = [[NSMutableArray alloc] init]; + for (NSUInteger i = 0; i < [filenames count]; i++) { + [pendingOpenFiles addObject:[filenames objectAtIndex:i]]; + } + } + return YES; +} @end @@ -441,6 +498,8 @@ int main(int argc, char* argv[]) { // Initialize the AutoRelease pool. g_autopool = [[NSAutoreleasePool alloc] init]; + pendingOpenFiles = nil; + CefMainArgs main_args(argc, argv); // Delete Special Characters Palette from Edit menu. @@ -461,6 +520,8 @@ int main(int argc, char* argv[]) { // Initialize the ClientApplication instance. [ClientApplication sharedApplication]; + NSObject* delegate = [[ClientAppDelegate alloc] init]; + [NSApp setDelegate:delegate]; // Parse command line arguments. AppInitCommandLine(argc, argv); @@ -528,7 +589,6 @@ int main(int argc, char* argv[]) { } // Create the application delegate and window. - NSObject* delegate = [[ClientAppDelegate alloc] init]; [delegate performSelectorOnMainThread:@selector(createApp:) withObject:nil waitUntilDone:NO]; diff --git a/appshell/client_handler.cpp b/appshell/client_handler.cpp index ea061166e..45214e892 100644 --- a/appshell/client_handler.cpp +++ b/appshell/client_handler.cpp @@ -340,6 +340,13 @@ bool ClientHandler::SendJSCommand(CefRefPtr browser, const CefString return browser->SendProcessMessage(PID_RENDERER, message); } +void ClientHandler::SendOpenFileCommand(CefRefPtr browser, const CefString &filename) { + std::string filenameStr(filename); + std::string cmd = "require('command/CommandManager').execute('file.open',{fullPath:'" + filenameStr + "'})"; + browser->GetMainFrame()->ExecuteJavaScript(CefString(cmd.c_str()), + browser->GetMainFrame()->GetURL(), 0); +} + void ClientHandler::DispatchCloseToNextBrowser() { // If the inner loop iterates thru all browsers and there's still at least one diff --git a/appshell/client_handler.h b/appshell/client_handler.h index c08f665b7..e64581b52 100644 --- a/appshell/client_handler.h +++ b/appshell/client_handler.h @@ -185,6 +185,7 @@ class ClientHandler : public CefClient, // If callback is specified, it will be called with the result from the command. bool SendJSCommand(CefRefPtr browser, const CefString& command, CefRefPtr callback = NULL); + void SendOpenFileCommand(CefRefPtr browser, const CefString& filename); void DispatchCloseToNextBrowser(); void AbortQuit(); static CefRefPtr GetBrowserForNativeWindow(void* window); diff --git a/appshell/mac/Info.plist b/appshell/mac/Info.plist index 20af6a814..e3d8cc9a5 100644 --- a/appshell/mac/Info.plist +++ b/appshell/mac/Info.plist @@ -24,5 +24,40 @@ MainMenu NSPrincipalClass NSApplication + CFBundleDocumentTypes + + + CFBundleTypeName + HTML source + CFBundleTypeRole + Editor + CFBundleTypeExtensions + + htm + html + + + + CFBundleTypeName + JavaScript source + CFBundleTypeExtensions + + js + + CFBundleTypeRole + Editor + + + CFBundleTypeName + CSS source + CFBundleTypeRole + Editor + CFBundleTypeExtensions + + css + less + + + From 12a8754c16c6f57bedfc70a84caf87d355fd3cf9 Mon Sep 17 00:00:00 2001 From: Glenn Ruehle Date: Sun, 16 Dec 2012 15:13:25 -0800 Subject: [PATCH 02/12] Add drag and drop to open files. Windows only. --- appshell/cefclient_win.cpp | 21 +++++++++++++++++++++ appshell/client_handler_win.cpp | 11 +++++++++++ 2 files changed, 32 insertions(+) diff --git a/appshell/cefclient_win.cpp b/appshell/cefclient_win.cpp index 2d173d5e3..a83ebaf7a 100644 --- a/appshell/cefclient_win.cpp +++ b/appshell/cefclient_win.cpp @@ -19,6 +19,8 @@ #include "string_util.h" #include "client_switches.h" +#include +#include #include #define MAX_LOADSTRING 100 @@ -538,12 +540,25 @@ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { if (!hWnd) return FALSE; + DragAcceptFiles(hWnd, TRUE); RestoreWindowPlacement(hWnd, showCmd); UpdateWindow(hWnd); return TRUE; } +LRESULT HandleDropFiles(HDROP hDrop, CefRefPtr handler, CefRefPtr browser) { + UINT fileCount = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); + for (UINT i = 0; i < fileCount; i++) { + wchar_t filename[MAX_PATH]; + DragQueryFile(hDrop, i, filename, MAX_PATH); + std::wstring pathStr(filename); + replace(pathStr.begin(), pathStr.end(), '\\', '/'); + handler->SendOpenFileCommand(browser, CefString(pathStr)); + } + return 0; +} + // // FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) // @@ -817,6 +832,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, // The frame window has exited PostQuitMessage(0); return 0; + + case WM_DROPFILES: + if (g_handler.get()) { + return HandleDropFiles((HDROP)wParam, g_handler, g_handler->GetBrowser()); + } + return 0; } return DefWindowProc(hWnd, message, wParam, lParam); diff --git a/appshell/client_handler_win.cpp b/appshell/client_handler_win.cpp index a112dc40e..d0b2b6fe4 100644 --- a/appshell/client_handler_win.cpp +++ b/appshell/client_handler_win.cpp @@ -14,6 +14,10 @@ // The global ClientHandler reference. extern CefRefPtr g_handler; +// WM_DROPFILES handler, defined in cefclient_win.cpp +extern LRESULT HandleDropFiles(HDROP hDrop, CefRefPtr handler, CefRefPtr browser); + + bool ClientHandler::OnBeforePopup(CefRefPtr parentBrowser, const CefPopupFeatures& popupFeatures, CefWindowInfo& windowInfo, @@ -149,6 +153,12 @@ LRESULT CALLBACK PopupWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPa return 0; } break; + + case WM_DROPFILES: + if (g_handler.get() && browser.get()) { + return HandleDropFiles((HDROP)wParam, g_handler, browser); + } + break; } if (g_popupWndOldProc) @@ -202,6 +212,7 @@ void ClientHandler::PopupCreated(CefRefPtr browser) HWND hWnd = browser->GetHost()->GetWindowHandle(); AttachWindProcToPopup(hWnd); LoadWindowsIcons(hWnd); + DragAcceptFiles(hWnd, true); browser->GetHost()->SetFocus(true); } From 7ab6a7e28dcf6650d0ec8c388d52b4856ee29dc3 Mon Sep 17 00:00:00 2001 From: Glenn Ruehle Date: Sun, 16 Dec 2012 15:16:21 -0800 Subject: [PATCH 03/12] Missing include. --- appshell/client_handler_win.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/appshell/client_handler_win.cpp b/appshell/client_handler_win.cpp index d0b2b6fe4..b63617def 100644 --- a/appshell/client_handler_win.cpp +++ b/appshell/client_handler_win.cpp @@ -9,6 +9,8 @@ #include "include/cef_frame.h" #include "resource.h" +#include + #define CLOSING_PROP L"CLOSING" // The global ClientHandler reference. From b4141bde35cd4eba730ee181efcdbdfb4ca103e3 Mon Sep 17 00:00:00 2001 From: Glenn Ruehle Date: Sun, 16 Dec 2012 10:44:02 -0800 Subject: [PATCH 04/12] Initial file association on mac. --- appshell/cefclient_mac.mm | 64 +++++++++++++++++++++++++++++++++++-- appshell/client_handler.cpp | 7 ++++ appshell/client_handler.h | 1 + appshell/mac/Info.plist | 35 ++++++++++++++++++++ 4 files changed, 105 insertions(+), 2 deletions(-) diff --git a/appshell/cefclient_mac.mm b/appshell/cefclient_mac.mm index 7f48c4ff1..bdad6a762 100644 --- a/appshell/cefclient_mac.mm +++ b/appshell/cefclient_mac.mm @@ -45,6 +45,9 @@ // Memory AutoRelease pool. static NSAutoreleasePool* g_autopool = nil; +// Files passed to the app at startup +static NSMutableArray* pendingOpenFiles; + // Provide the CefAppProtocol implementation required by CEF. @interface ClientApplication : NSApplication { @private @@ -262,6 +265,8 @@ - (void)cleanup:(id)window { // Receives notifications from the application. Will delete itself when done. @interface ClientAppDelegate : NSObject - (void)createApp:(id)object; +- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename; +- (BOOL)application:(NSApplication *)theApplication openFiles:(NSArray *)filenames; @end @implementation ClientAppDelegate @@ -396,14 +401,37 @@ - (void)createApp:(id)object { window_info.SetAsChild(contentView, 0, 0, content_rect.size.width, content_rect.size.height); NSString* str = [[startupUrl absoluteString] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - CefBrowserHost::CreateBrowser(window_info, g_handler.get(), + CefBrowserHost::CreateBrowserSync(window_info, g_handler.get(), [str UTF8String], settings); + + if (pendingOpenFiles) { + // Set the appshell.startupFiles property after a short delay to give the window + // object a chance to initialize + [self performSelector:@selector(sendStartupFilesToApp) withObject:self afterDelay:0.5]; + } // Show the window. [mainWnd display]; [mainWnd makeKeyAndOrderFront: nil]; } +- (void)sendStartupFilesToApp { + std::string fileArray = "["; + NSUInteger count = [pendingOpenFiles count]; + for (NSUInteger i = 0; i < count; i++) { + NSString* filename = [pendingOpenFiles objectAtIndex:i]; + + fileArray += ("'" + std::string([filename UTF8String]) + "'"); + if (i < count - 1) + fileArray += ","; + } + fileArray += "]"; + + std::string cmd = "appshell.startupFiles=" + fileArray; + g_handler->GetBrowser()->GetMainFrame()->ExecuteJavaScript(CefString(cmd), + g_handler->GetBrowser()->GetMainFrame()->GetURL(), 0); + +} // Sent by the default notification center immediately before the application // terminates. - (void)applicationWillTerminate:(NSNotification *)aNotification { @@ -434,6 +462,35 @@ - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)theAp return NSTerminateNow; } +- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename { + if (g_handler) { + CefRefPtr browser = ClientHandler::GetBrowserForNativeWindow([NSApp keyWindow]); + g_handler->SendOpenFileCommand(browser, CefString([filename UTF8String])); + } else { + // App is just starting up. Save the filename so we can open it later. + if (!pendingOpenFiles) { + pendingOpenFiles = [[NSMutableArray alloc] init]; + [pendingOpenFiles addObject:filename]; + } + } + return YES; +} + +- (BOOL)application:(NSApplication *)theApplication openFiles:(NSArray *)filenames { + if (g_handler) { + CefRefPtr browser = ClientHandler::GetBrowserForNativeWindow([NSApp keyWindow]); + for (NSUInteger i = 0; i < [filenames count]; i++) { + g_handler->SendOpenFileCommand(browser, CefString([[filenames objectAtIndex:i] UTF8String])); + } + } else { + // App is just starting up. Save the filenames so we can open them later. + pendingOpenFiles = [[NSMutableArray alloc] init]; + for (NSUInteger i = 0; i < [filenames count]; i++) { + [pendingOpenFiles addObject:[filenames objectAtIndex:i]]; + } + } + return YES; +} @end @@ -441,6 +498,8 @@ int main(int argc, char* argv[]) { // Initialize the AutoRelease pool. g_autopool = [[NSAutoreleasePool alloc] init]; + pendingOpenFiles = nil; + CefMainArgs main_args(argc, argv); // Delete Special Characters Palette from Edit menu. @@ -461,6 +520,8 @@ int main(int argc, char* argv[]) { // Initialize the ClientApplication instance. [ClientApplication sharedApplication]; + NSObject* delegate = [[ClientAppDelegate alloc] init]; + [NSApp setDelegate:delegate]; // Parse command line arguments. AppInitCommandLine(argc, argv); @@ -528,7 +589,6 @@ int main(int argc, char* argv[]) { } // Create the application delegate and window. - NSObject* delegate = [[ClientAppDelegate alloc] init]; [delegate performSelectorOnMainThread:@selector(createApp:) withObject:nil waitUntilDone:NO]; diff --git a/appshell/client_handler.cpp b/appshell/client_handler.cpp index ea061166e..45214e892 100644 --- a/appshell/client_handler.cpp +++ b/appshell/client_handler.cpp @@ -340,6 +340,13 @@ bool ClientHandler::SendJSCommand(CefRefPtr browser, const CefString return browser->SendProcessMessage(PID_RENDERER, message); } +void ClientHandler::SendOpenFileCommand(CefRefPtr browser, const CefString &filename) { + std::string filenameStr(filename); + std::string cmd = "require('command/CommandManager').execute('file.open',{fullPath:'" + filenameStr + "'})"; + browser->GetMainFrame()->ExecuteJavaScript(CefString(cmd.c_str()), + browser->GetMainFrame()->GetURL(), 0); +} + void ClientHandler::DispatchCloseToNextBrowser() { // If the inner loop iterates thru all browsers and there's still at least one diff --git a/appshell/client_handler.h b/appshell/client_handler.h index c08f665b7..e64581b52 100644 --- a/appshell/client_handler.h +++ b/appshell/client_handler.h @@ -185,6 +185,7 @@ class ClientHandler : public CefClient, // If callback is specified, it will be called with the result from the command. bool SendJSCommand(CefRefPtr browser, const CefString& command, CefRefPtr callback = NULL); + void SendOpenFileCommand(CefRefPtr browser, const CefString& filename); void DispatchCloseToNextBrowser(); void AbortQuit(); static CefRefPtr GetBrowserForNativeWindow(void* window); diff --git a/appshell/mac/Info.plist b/appshell/mac/Info.plist index 20af6a814..e3d8cc9a5 100644 --- a/appshell/mac/Info.plist +++ b/appshell/mac/Info.plist @@ -24,5 +24,40 @@ MainMenu NSPrincipalClass NSApplication + CFBundleDocumentTypes + + + CFBundleTypeName + HTML source + CFBundleTypeRole + Editor + CFBundleTypeExtensions + + htm + html + + + + CFBundleTypeName + JavaScript source + CFBundleTypeExtensions + + js + + CFBundleTypeRole + Editor + + + CFBundleTypeName + CSS source + CFBundleTypeRole + Editor + CFBundleTypeExtensions + + css + less + + + From 8aae674b4e78be50904750bb9af91f60c38b9c60 Mon Sep 17 00:00:00 2001 From: Glenn Ruehle Date: Sun, 16 Dec 2012 15:13:25 -0800 Subject: [PATCH 05/12] Add drag and drop to open files. Windows only. --- appshell/cefclient_win.cpp | 21 +++++++++++++++++++++ appshell/client_handler_win.cpp | 11 +++++++++++ 2 files changed, 32 insertions(+) diff --git a/appshell/cefclient_win.cpp b/appshell/cefclient_win.cpp index 2d173d5e3..a83ebaf7a 100644 --- a/appshell/cefclient_win.cpp +++ b/appshell/cefclient_win.cpp @@ -19,6 +19,8 @@ #include "string_util.h" #include "client_switches.h" +#include +#include #include #define MAX_LOADSTRING 100 @@ -538,12 +540,25 @@ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { if (!hWnd) return FALSE; + DragAcceptFiles(hWnd, TRUE); RestoreWindowPlacement(hWnd, showCmd); UpdateWindow(hWnd); return TRUE; } +LRESULT HandleDropFiles(HDROP hDrop, CefRefPtr handler, CefRefPtr browser) { + UINT fileCount = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); + for (UINT i = 0; i < fileCount; i++) { + wchar_t filename[MAX_PATH]; + DragQueryFile(hDrop, i, filename, MAX_PATH); + std::wstring pathStr(filename); + replace(pathStr.begin(), pathStr.end(), '\\', '/'); + handler->SendOpenFileCommand(browser, CefString(pathStr)); + } + return 0; +} + // // FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) // @@ -817,6 +832,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, // The frame window has exited PostQuitMessage(0); return 0; + + case WM_DROPFILES: + if (g_handler.get()) { + return HandleDropFiles((HDROP)wParam, g_handler, g_handler->GetBrowser()); + } + return 0; } return DefWindowProc(hWnd, message, wParam, lParam); diff --git a/appshell/client_handler_win.cpp b/appshell/client_handler_win.cpp index a112dc40e..d0b2b6fe4 100644 --- a/appshell/client_handler_win.cpp +++ b/appshell/client_handler_win.cpp @@ -14,6 +14,10 @@ // The global ClientHandler reference. extern CefRefPtr g_handler; +// WM_DROPFILES handler, defined in cefclient_win.cpp +extern LRESULT HandleDropFiles(HDROP hDrop, CefRefPtr handler, CefRefPtr browser); + + bool ClientHandler::OnBeforePopup(CefRefPtr parentBrowser, const CefPopupFeatures& popupFeatures, CefWindowInfo& windowInfo, @@ -149,6 +153,12 @@ LRESULT CALLBACK PopupWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPa return 0; } break; + + case WM_DROPFILES: + if (g_handler.get() && browser.get()) { + return HandleDropFiles((HDROP)wParam, g_handler, browser); + } + break; } if (g_popupWndOldProc) @@ -202,6 +212,7 @@ void ClientHandler::PopupCreated(CefRefPtr browser) HWND hWnd = browser->GetHost()->GetWindowHandle(); AttachWindProcToPopup(hWnd); LoadWindowsIcons(hWnd); + DragAcceptFiles(hWnd, true); browser->GetHost()->SetFocus(true); } From 730ebd9ab862354b64059ace71c4832fc22ba071 Mon Sep 17 00:00:00 2001 From: Glenn Ruehle Date: Sun, 16 Dec 2012 15:16:21 -0800 Subject: [PATCH 06/12] Missing include. --- appshell/client_handler_win.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/appshell/client_handler_win.cpp b/appshell/client_handler_win.cpp index d0b2b6fe4..b63617def 100644 --- a/appshell/client_handler_win.cpp +++ b/appshell/client_handler_win.cpp @@ -9,6 +9,8 @@ #include "include/cef_frame.h" #include "resource.h" +#include + #define CLOSING_PROP L"CLOSING" // The global ClientHandler reference. From 45194d3ab9c792c6b0a0044c66ecd5b133ac1b54 Mon Sep 17 00:00:00 2001 From: Glenn Ruehle Date: Tue, 22 Jan 2013 16:44:55 -0800 Subject: [PATCH 07/12] Better startup file implementation. --- appshell/appshell_extensions.cpp | 12 +++++++++ appshell/appshell_extensions.js | 17 +++++++++++++ appshell/appshell_extensions_mac.mm | 8 ++++++ appshell/appshell_extensions_platform.h | 2 ++ appshell/cefclient_mac.mm | 33 ++++++++++--------------- appshell/client_handler.cpp | 1 + appshell/mac/Info.plist | 27 ++++++++++++++++++++ 7 files changed, 80 insertions(+), 20 deletions(-) diff --git a/appshell/appshell_extensions.cpp b/appshell/appshell_extensions.cpp index feda35f77..2f4619392 100644 --- a/appshell/appshell_extensions.cpp +++ b/appshell/appshell_extensions.cpp @@ -334,6 +334,18 @@ class ProcessMessageDelegate : public ClientHandler::ProcessMessageDelegate { ExtensionString path = argList->GetString(1); error = ShowFolderInOSWindow(path); } + } else if (message_name == "GetPendingFilesToOpen") { + // Parameters: + // 0: int32 - callback id + if (argList->GetSize() != 1) { + error = ERR_INVALID_PARAMS; + } + + if (error == NO_ERROR) { + ExtensionString files; + error = GetPendingFilesToOpen(files); + responseArgs->SetString(2, files.c_str()); + } } else if (message_name == "AddMenu") { // Parameters: // 0: int32 - callback id diff --git a/appshell/appshell_extensions.js b/appshell/appshell_extensions.js index 7ff48e173..46b4a64ac 100644 --- a/appshell/appshell_extensions.js +++ b/appshell/appshell_extensions.js @@ -375,6 +375,23 @@ if (!appshell.app) { OpenURLInDefaultBrowser(callback, url); }; + /** + * Get files passed to app at startup. + * + * @param {function(err, files)} callback Asynchronous callback function with two arguments: + * err - error code + * files - Array of file paths to open + * + * @return None. This is an asynchronous call that sends all return information to the callback. + */ + native function GetPendingFilesToOpen(); + appshell.app.getPendingFilesToOpen = function (callback) { + GetPendingFilesToOpen(function (err, files) { + // "files" is a string, convert to Array + callback(err, err ? [] : JSON.parse(files)); + }); + }; + /** * Set menu enabled/checked state. * @param {string} command ID of the menu item. diff --git a/appshell/appshell_extensions_mac.mm b/appshell/appshell_extensions_mac.mm index 296ebe5c9..66efe7b1e 100644 --- a/appshell/appshell_extensions_mac.mm +++ b/appshell/appshell_extensions_mac.mm @@ -27,6 +27,7 @@ #include +extern ExtensionString gPendingFilesToOpen; @interface ChromeWindowsTerminatedObserver : NSObject - (void)appTerminated:(NSNotification *)note; @@ -586,6 +587,13 @@ int32 ShowFolderInOSWindow(ExtensionString pathname) return NO_ERROR; } +int32 GetPendingFilesToOpen(ExtensionString& files) +{ + files = gPendingFilesToOpen; +// gPendingFilesToOpen = "[]"; + return NO_ERROR; +} + int32 GetMenuPosition(CefRefPtr browser, const ExtensionString& commandId, ExtensionString& parentId, int& index) { index = -1; diff --git a/appshell/appshell_extensions_platform.h b/appshell/appshell_extensions_platform.h index cdbf7dd5c..09bdb0a66 100644 --- a/appshell/appshell_extensions_platform.h +++ b/appshell/appshell_extensions_platform.h @@ -98,6 +98,8 @@ void BringBrowserWindowToFront(CefRefPtr browser); int32 ShowFolderInOSWindow(ExtensionString pathname); +int32 GetPendingFilesToOpen(ExtensionString& files); + int32 AddMenu(CefRefPtr browser, ExtensionString title, ExtensionString command, ExtensionString position, ExtensionString relativeId); diff --git a/appshell/cefclient_mac.mm b/appshell/cefclient_mac.mm index d2ffea044..511adc9c0 100644 --- a/appshell/cefclient_mac.mm +++ b/appshell/cefclient_mac.mm @@ -48,6 +48,7 @@ // Files passed to the app at startup static NSMutableArray* pendingOpenFiles; +ExtensionString gPendingFilesToOpen; // Provide the CefAppProtocol implementation required by CEF. @interface ClientApplication : NSApplication { @@ -429,9 +430,18 @@ - (void)createApp:(id)object { [str UTF8String], settings); if (pendingOpenFiles) { - // Set the appshell.startupFiles property after a short delay to give the window - // object a chance to initialize - [self performSelector:@selector(sendStartupFilesToApp) withObject:self afterDelay:0.5]; + NSUInteger count = [pendingOpenFiles count]; + gPendingFilesToOpen = "["; + for (NSUInteger i = 0; i < count; i++) { + NSString* filename = [pendingOpenFiles objectAtIndex:i]; + + gPendingFilesToOpen += ("\"" + std::string([filename UTF8String]) + "\""); + if (i < count - 1) + gPendingFilesToOpen += ","; + } + gPendingFilesToOpen += "]"; + } else { + gPendingFilesToOpen = "[]"; } // Show the window. @@ -439,23 +449,6 @@ - (void)createApp:(id)object { [mainWnd makeKeyAndOrderFront: nil]; } -- (void)sendStartupFilesToApp { - std::string fileArray = "["; - NSUInteger count = [pendingOpenFiles count]; - for (NSUInteger i = 0; i < count; i++) { - NSString* filename = [pendingOpenFiles objectAtIndex:i]; - - fileArray += ("'" + std::string([filename UTF8String]) + "'"); - if (i < count - 1) - fileArray += ","; - } - fileArray += "]"; - - std::string cmd = "appshell.startupFiles=" + fileArray; - g_handler->GetBrowser()->GetMainFrame()->ExecuteJavaScript(CefString(cmd), - g_handler->GetBrowser()->GetMainFrame()->GetURL(), 0); - -} // Sent by the default notification center immediately before the application // terminates. - (void)applicationWillTerminate:(NSNotification *)aNotification { diff --git a/appshell/client_handler.cpp b/appshell/client_handler.cpp index 45214e892..6aed3b283 100644 --- a/appshell/client_handler.cpp +++ b/appshell/client_handler.cpp @@ -342,6 +342,7 @@ bool ClientHandler::SendJSCommand(CefRefPtr browser, const CefString void ClientHandler::SendOpenFileCommand(CefRefPtr browser, const CefString &filename) { std::string filenameStr(filename); + // FIXME: Use SendJSCommand once it supports parameters std::string cmd = "require('command/CommandManager').execute('file.open',{fullPath:'" + filenameStr + "'})"; browser->GetMainFrame()->ExecuteJavaScript(CefString(cmd.c_str()), browser->GetMainFrame()->GetURL(), 0); diff --git a/appshell/mac/Info.plist b/appshell/mac/Info.plist index 1761556a9..dc1967616 100644 --- a/appshell/mac/Info.plist +++ b/appshell/mac/Info.plist @@ -26,6 +26,19 @@ NSApplication CFBundleDocumentTypes + + CFBundleTypeName + Text files + CFBundleTypeRole + Editor + LSItemContentTypes + + public.text + public.source-code + public.script + public.shell-script + + CFBundleTypeName HTML source @@ -58,6 +71,20 @@ less + + CFBundleTypeName + Markdown + CFBundleTypeRole + Editor + CFBundleTypeExtensions + + md + mkd + mkdn + mdown + markdown + + From d87b6e65b2e2940657a2dd1f6421a87ddcc8265e Mon Sep 17 00:00:00 2001 From: Glenn Ruehle Date: Thu, 24 Jan 2013 10:46:01 -0800 Subject: [PATCH 08/12] Add support for drag onto app icon on Windows. --- appshell/appshell_extensions_win.cpp | 7 +++++ appshell/cefclient_win.cpp | 38 ++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/appshell/appshell_extensions_win.cpp b/appshell/appshell_extensions_win.cpp index 48636a01f..3c6644109 100644 --- a/appshell/appshell_extensions_win.cpp +++ b/appshell/appshell_extensions_win.cpp @@ -51,6 +51,7 @@ time_t FiletimeToTime(FILETIME const& ft); extern HINSTANCE hInst; extern HACCEL hAccelTable; +extern std::wstring gFilesToOpen; // constants #define MAX_LOADSTRING 100 @@ -798,6 +799,12 @@ int32 ShowFolderInOSWindow(ExtensionString pathname) { return NO_ERROR; } +int32 GetPendingFilesToOpen(ExtensionString& files) { + files = gFilesToOpen; + ConvertToUnixPath(files); + gFilesToOpen = L""; + return NO_ERROR; +} // Return index where menu or menu item should be placed. // -1 indicates append. -2 indicates 'before' - WINAPI supports diff --git a/appshell/cefclient_win.cpp b/appshell/cefclient_win.cpp index 1e3b09614..b68c67586 100644 --- a/appshell/cefclient_win.cpp +++ b/appshell/cefclient_win.cpp @@ -39,6 +39,7 @@ DWORD g_appStartupTime; HINSTANCE hInst; // current instance HACCEL hAccelTable; HWND hWndMain; +std::wstring gFilesToOpen; // Filenames passed as arguments to app TCHAR szTitle[MAX_LOADSTRING]; // The title bar text TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name char szWorkingDir[MAX_PATH]; // The current working directory @@ -84,6 +85,41 @@ void SaveWindowRect(HWND hWnd); void RestoreWindowRect(int& left, int& top, int& width, int& height, int& showCmd); void RestoreWindowPlacement(HWND hWnd, int showCmd); +bool IsFilename(const std::wstring& str) { + // Cheesy check to see if the passed in string is a filename -- + // look for a colon (after the drive letter) and a dot (for extension) + // This should probably be made more robust... + + return (str.find_first_of(':') != std::string::npos && + str.find_first_of('.') != std::string::npos); +} + +std::wstring GetFilenamesFromCommandLine() { + std::wstring result = L"[]"; + + if (AppGetCommandLine()->HasArguments()) { + bool firstEntry = true; + std::vector args; + AppGetCommandLine()->GetArguments(args); + std::vector::iterator iterator; + + result = L"["; + for (iterator = args.begin(); iterator != args.end(); iterator++) { + std::wstring argument = (*iterator).ToWString(); + if (IsFilename(argument)) { + if (!firstEntry) { + result += L","; + } + firstEntry = false; + result += L"\"" + argument + L"\""; + } + } + result += L"]"; + } + + return result; +} + // Program entry point function. int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, @@ -184,6 +220,8 @@ int APIENTRY wWinMain(HINSTANCE hInstance, if (!InitInstance (hInstance, nCmdShow)) return FALSE; + gFilesToOpen = GetFilenamesFromCommandLine(); + int result = 0; if (!settings.multi_threaded_message_loop) { From 5d1b4af2bdf420f370f6354b58e5841eb4bbfe2f Mon Sep 17 00:00:00 2001 From: Glenn Ruehle Date: Thu, 24 Jan 2013 10:49:38 -0800 Subject: [PATCH 09/12] Re-enable code. --- appshell/appshell_extensions_mac.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appshell/appshell_extensions_mac.mm b/appshell/appshell_extensions_mac.mm index 66efe7b1e..54a23069b 100644 --- a/appshell/appshell_extensions_mac.mm +++ b/appshell/appshell_extensions_mac.mm @@ -590,7 +590,7 @@ int32 ShowFolderInOSWindow(ExtensionString pathname) int32 GetPendingFilesToOpen(ExtensionString& files) { files = gPendingFilesToOpen; -// gPendingFilesToOpen = "[]"; + gPendingFilesToOpen = "[]"; return NO_ERROR; } From 19c08b15bd0323881d90aab4f07b370b510975d3 Mon Sep 17 00:00:00 2001 From: Glenn Ruehle Date: Fri, 25 Jan 2013 17:15:11 -0800 Subject: [PATCH 10/12] Improve IsFilename() check. --- appshell/cefclient_win.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/appshell/cefclient_win.cpp b/appshell/cefclient_win.cpp index b68c67586..b3794cfd3 100644 --- a/appshell/cefclient_win.cpp +++ b/appshell/cefclient_win.cpp @@ -86,12 +86,8 @@ void RestoreWindowRect(int& left, int& top, int& width, int& height, int& showCm void RestoreWindowPlacement(HWND hWnd, int showCmd); bool IsFilename(const std::wstring& str) { - // Cheesy check to see if the passed in string is a filename -- - // look for a colon (after the drive letter) and a dot (for extension) - // This should probably be made more robust... - - return (str.find_first_of(':') != std::string::npos && - str.find_first_of('.') != std::string::npos); + // See if we can access the passed in value + return (GetFileAttributes(str.c_str()) != INVALID_FILE_ATTRIBUTES); } std::wstring GetFilenamesFromCommandLine() { From 3f2506a1f526594b7df848eea6bf1962500c7759 Mon Sep 17 00:00:00 2001 From: Glenn Ruehle Date: Mon, 28 Jan 2013 13:52:36 -0800 Subject: [PATCH 11/12] Fix tab/space inconsistency. --- appshell/mac/Info.plist | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/appshell/mac/Info.plist b/appshell/mac/Info.plist index dc1967616..59d395a14 100644 --- a/appshell/mac/Info.plist +++ b/appshell/mac/Info.plist @@ -34,9 +34,9 @@ LSItemContentTypes public.text - public.source-code - public.script - public.shell-script + public.source-code + public.script + public.shell-script @@ -79,9 +79,9 @@ CFBundleTypeExtensions md - mkd - mkdn - mdown + mkd + mkdn + mdown markdown From a30f0fc447f0e6dcbd9885e26261740e16c60c82 Mon Sep 17 00:00:00 2001 From: Glenn Ruehle Date: Wed, 13 Feb 2013 16:47:12 -0800 Subject: [PATCH 12/12] Fixed crash on quit. --- appshell/cefclient_mac.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appshell/cefclient_mac.mm b/appshell/cefclient_mac.mm index 511adc9c0..5472dbe7c 100644 --- a/appshell/cefclient_mac.mm +++ b/appshell/cefclient_mac.mm @@ -471,7 +471,7 @@ -(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theAppli } - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)theApplication { - if (!g_isTerminating && g_handler.get() && !g_handler->AppIsQuitting() && g_handler->HasWindows()) { + if (!g_isTerminating && g_handler.get() && !g_handler->AppIsQuitting() && g_handler->HasWindows() && [NSApp keyWindow]) { g_handler->DispatchCloseToNextBrowser(); return NSTerminateCancel; }