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

Initial implementation of drag and drop to open files #190

Merged
merged 17 commits into from
Feb 15, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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