Skip to content
This repository has been archived by the owner on Sep 2, 2021. It is now read-only.

Commit

Permalink
Merge pull request #190 from adobe/glenn/file-association
Browse files Browse the repository at this point in the history
Initial implementation of drag and drop to open files
  • Loading branch information
redmunds committed Feb 15, 2013
2 parents f254eca + a30f0fc commit 87f9a15
Show file tree
Hide file tree
Showing 11 changed files with 243 additions and 7 deletions.
12 changes: 12 additions & 0 deletions appshell/appshell_extensions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 17 additions & 0 deletions appshell/appshell_extensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
8 changes: 8 additions & 0 deletions appshell/appshell_extensions_mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#include <Cocoa/Cocoa.h>

extern ExtensionString gPendingFilesToOpen;

@interface ChromeWindowsTerminatedObserver : NSObject
- (void)appTerminated:(NSNotification *)note;
Expand Down Expand Up @@ -586,6 +587,13 @@ int32 ShowFolderInOSWindow(ExtensionString pathname)
return NO_ERROR;
}

int32 GetPendingFilesToOpen(ExtensionString& files)
{
files = gPendingFilesToOpen;
gPendingFilesToOpen = "[]";
return NO_ERROR;
}

int32 GetMenuPosition(CefRefPtr<CefBrowser> browser, const ExtensionString& commandId, ExtensionString& parentId, int& index)
{
index = -1;
Expand Down
2 changes: 2 additions & 0 deletions appshell/appshell_extensions_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ void BringBrowserWindowToFront(CefRefPtr<CefBrowser> browser);

int32 ShowFolderInOSWindow(ExtensionString pathname);

int32 GetPendingFilesToOpen(ExtensionString& files);

int32 AddMenu(CefRefPtr<CefBrowser> browser, ExtensionString title, ExtensionString command,
ExtensionString position, ExtensionString relativeId);

Expand Down
7 changes: 7 additions & 0 deletions appshell/appshell_extensions_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
59 changes: 56 additions & 3 deletions appshell/cefclient_mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@
// Memory AutoRelease pool.
static NSAutoreleasePool* g_autopool = nil;

// Files passed to the app at startup
static NSMutableArray* pendingOpenFiles;
ExtensionString gPendingFilesToOpen;

// Provide the CefAppProtocol implementation required by CEF.
@interface ClientApplication : NSApplication<CefAppProtocol> {
@private
Expand Down Expand Up @@ -286,6 +290,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
Expand Down Expand Up @@ -420,8 +426,23 @@ - (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) {
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.
[mainWnd display];
Expand Down Expand Up @@ -450,21 +471,52 @@ -(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;
}
g_isTerminating = true;
return NSTerminateNow;
}

- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename {
if (g_handler) {
CefRefPtr<CefBrowser> 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<CefBrowser> 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


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.
Expand All @@ -485,6 +537,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);
Expand Down Expand Up @@ -552,7 +606,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];

Expand Down
59 changes: 57 additions & 2 deletions appshell/cefclient_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#include "client_switches.h"
#include "native_menu_model.h"

#include <algorithm>
#include <ShellAPI.h>
#include <ShlObj.h>

#define MAX_LOADSTRING 100
Expand All @@ -37,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
Expand Down Expand Up @@ -82,6 +85,37 @@ 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) {
// See if we can access the passed in value
return (GetFileAttributes(str.c_str()) != INVALID_FILE_ATTRIBUTES);
}

std::wstring GetFilenamesFromCommandLine() {
std::wstring result = L"[]";

if (AppGetCommandLine()->HasArguments()) {
bool firstEntry = true;
std::vector<CefString> args;
AppGetCommandLine()->GetArguments(args);
std::vector<CefString>::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,
Expand Down Expand Up @@ -182,6 +216,8 @@ int APIENTRY wWinMain(HINSTANCE hInstance,
if (!InitInstance (hInstance, nCmdShow))
return FALSE;

gFilesToOpen = GetFilenamesFromCommandLine();

int result = 0;

if (!settings.multi_threaded_message_loop) {
Expand Down Expand Up @@ -520,12 +556,25 @@ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) {
if (!hWndMain)
return FALSE;

DragAcceptFiles(hWndMain, TRUE);
RestoreWindowPlacement(hWndMain, showCmd);
UpdateWindow(hWndMain);

\
return TRUE;
}

LRESULT HandleDropFiles(HDROP hDrop, CefRefPtr<ClientHandler> handler, CefRefPtr<CefBrowser> 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)
//
Expand Down Expand Up @@ -806,6 +855,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
PostQuitMessage(0);
return 0;

case WM_DROPFILES:
if (g_handler.get()) {
return HandleDropFiles((HDROP)wParam, g_handler, g_handler->GetBrowser());
}
return 0;

case WM_INITMENUPOPUP:
HMENU menu = (HMENU)wParam;
int count = GetMenuItemCount(menu);
Expand Down Expand Up @@ -912,4 +967,4 @@ CefString AppGetProductVersionString() {
s.append(L"/");
s.append(version);
return CefString(s);
}
}
8 changes: 8 additions & 0 deletions appshell/client_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,14 @@ bool ClientHandler::SendJSCommand(CefRefPtr<CefBrowser> browser, const CefString
return browser->SendProcessMessage(PID_RENDERER, message);
}

void ClientHandler::SendOpenFileCommand(CefRefPtr<CefBrowser> 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);
}

void ClientHandler::DispatchCloseToNextBrowser()
{
// If the inner loop iterates thru all browsers and there's still at least one
Expand Down
1 change: 1 addition & 0 deletions appshell/client_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ class ClientHandler : public CefClient,
// If callback is specified, it will be called with the result from the command.
bool SendJSCommand(CefRefPtr<CefBrowser> browser, const CefString& command, CefRefPtr<CommandCallback> callback = NULL);

void SendOpenFileCommand(CefRefPtr<CefBrowser> browser, const CefString& filename);
void DispatchCloseToNextBrowser();
void AbortQuit();
static CefRefPtr<CefBrowser> GetBrowserForNativeWindow(void* window);
Expand Down
15 changes: 13 additions & 2 deletions appshell/client_handler_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@
#include "resource.h"
#include "native_menu_model.h"

#include <ShellAPI.h>

#define CLOSING_PROP L"CLOSING"

// The global ClientHandler reference.
extern CefRefPtr<ClientHandler> g_handler;

// WM_DROPFILES handler, defined in cefclient_win.cpp
extern LRESULT HandleDropFiles(HDROP hDrop, CefRefPtr<ClientHandler> handler, CefRefPtr<CefBrowser> browser);

// Additional globals
extern HACCEL hAccelTable;

Expand Down Expand Up @@ -151,6 +155,12 @@ LRESULT CALLBACK PopupWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPa
}
break;

case WM_DROPFILES:
if (g_handler.get() && browser.get()) {
return HandleDropFiles((HDROP)wParam, g_handler, browser);
}
break;

case WM_INITMENUPOPUP:
HMENU menu = (HMENU)wParam;
int count = GetMenuItemCount(menu);
Expand Down Expand Up @@ -216,6 +226,7 @@ void ClientHandler::PopupCreated(CefRefPtr<CefBrowser> browser)
HWND hWnd = browser->GetHost()->GetWindowHandle();
AttachWindProcToPopup(hWnd);
LoadWindowsIcons(hWnd);
DragAcceptFiles(hWnd, true);
browser->GetHost()->SetFocus(true);
}

Expand Down Expand Up @@ -261,4 +272,4 @@ bool ClientHandler::OnKeyEvent(CefRefPtr<CefBrowser> browser,
const CefKeyEvent& event,
CefEventHandle os_event) {
return false;
}
}
Loading

0 comments on commit 87f9a15

Please sign in to comment.