diff --git a/Brackets.vcxproj b/Brackets.vcxproj
index 3ae162067..ba39d9a8d 100644
--- a/Brackets.vcxproj
+++ b/Brackets.vcxproj
@@ -1 +1 @@
-DebugWin32Debugx64ReleaseWin32Releasex64{6617FED9-C5D4-4907-BF55-A90062A6683F}Win32ProjBracketsUnicodeApplication$(ExecutablePath);$(MSBuildProjectDirectory)\..\src\third_party\cygwin\bin\;$(MSBuildProjectDirectory)\..\src\third_party\python_26\$(Configuration)\$(OutDir)obj\$(ProjectName)\falsefalsetruetrue$(ProjectName)$(OutDir)\$(ProjectName).exe..\src\third_party\wtl\include;.;..\src\third_party\directxsdk\files\Include;..\src\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)/MP /we4389 %(AdditionalOptions)EnableFastCheckstrueProgramDatabase4351;4396;4503;4819;4100;4121;4125;4127;4130;4131;4189;4201;4238;4244;4245;4310;4355;4428;4481;4505;4510;4512;4530;4610;4611;4701;4702;4706;%(DisableSpecificWarnings)falsetruefalseDisabled_DEBUG;_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_WINDOWS;NOMINMAX;PSAPI_VERSION=1;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_ATL_NO_OPENGL;_HAS_EXCEPTIONS=0;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_ONE_CLICK_SIGNIN;ENABLE_REMOTING=1;ENABLE_WEBRTC=1;ENABLE_CONFIGURATION_POLICY;ENABLE_INPUT_SPEECH;ENABLE_NOTIFICATIONS;ENABLE_GPU=1;ENABLE_EGLIMAGE=1;USE_SKIA=1;__STD_C;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;ENABLE_TASK_MANAGER=1;ENABLE_WEB_INTENTS=1;ENABLE_EXTENSIONS=1;ENABLE_PLUGIN_INSTALLATION=1;ENABLE_PROTECTOR_SERVICE=1;ENABLE_SESSION_SERVICE=1;ENABLE_THEMES=1;ENABLE_BACKGROUND=1;ENABLE_PROMO_RESOURCE_SERVICE=1;ENABLE_AUTOMATION=1;USING_CEF_SHARED;__STDC_FORMAT_MACROS;DYNAMIC_ANNOTATIONS_ENABLED=1;WTF_USE_DYNAMIC_ANNOTATIONS=1;%(PreprocessorDefinitions)MultiThreadedDebugfalsetrueLevel4../src/third_party/directxsdk/files/Lib/x86;../src/third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories)/ignore:4221 %(AdditionalOptions)wininet.lib;dnsapi.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;winmm.lib;shlwapi.lib;atlthunk.lib;comctl32.lib;shlwapi.lib;rpcrt4.lib;opengl32.lib;glu32.lib;lib\$(Configuration)\libcef.lib;%(AdditionalDependencies)../src/third_party/directxsdk/files/Lib/x86;../src/third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories)/ignore:4254 /ignore:4078 /safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions)dbghelp.dll;dwmapi.dll;shell32.dll;uxtheme.dll;%(DelayLoadDLLs)wWinMainCRTStartupfalsetrue$(OutDir)lib\$(TargetName).lib$(OutDir)$(TargetName).map$(OutDir)$(ProjectName).exefalseWindowsMachineX86%(Filename).dlldata.ctrue%(Filename).h%(Filename)_i.c$(IntDir)%(Filename)_p.c%(Filename).tlb../src;$(OutDir)obj/global_intermediate;..\src\third_party\wtl\include;.;..\src\third_party\directxsdk\files\Include;..\src\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)0x0409_DEBUG;_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_WINDOWS;NOMINMAX;PSAPI_VERSION=1;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_ATL_NO_OPENGL;_HAS_EXCEPTIONS=0;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_ONE_CLICK_SIGNIN;ENABLE_REMOTING=1;ENABLE_WEBRTC=1;ENABLE_CONFIGURATION_POLICY;ENABLE_INPUT_SPEECH;ENABLE_NOTIFICATIONS;ENABLE_GPU=1;ENABLE_EGLIMAGE=1;USE_SKIA=1;__STD_C;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;ENABLE_TASK_MANAGER=1;ENABLE_WEB_INTENTS=1;ENABLE_EXTENSIONS=1;ENABLE_PLUGIN_INSTALLATION=1;ENABLE_PROTECTOR_SERVICE=1;ENABLE_SESSION_SERVICE=1;ENABLE_THEMES=1;ENABLE_BACKGROUND=1;ENABLE_PROMO_RESOURCE_SERVICE=1;ENABLE_AUTOMATION=1;USING_CEF_SHARED;__STDC_FORMAT_MACROS;DYNAMIC_ANNOTATIONS_ENABLED=1;WTF_USE_DYNAMIC_ANNOTATIONS=1;%(PreprocessorDefinitions)..\src\third_party\wtl\include;.;..\src\third_party\directxsdk\files\Include;..\src\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)/MP /we4389 %(AdditionalOptions)EnableFastCheckstrueProgramDatabase4351;4396;4503;4819;4100;4121;4125;4127;4130;4131;4189;4201;4238;4244;4245;4310;4355;4428;4481;4505;4510;4512;4530;4610;4611;4701;4702;4706;%(DisableSpecificWarnings)falsetruefalseDisabled_DEBUG;_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_WINDOWS;NOMINMAX;PSAPI_VERSION=1;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_ATL_NO_OPENGL;_HAS_EXCEPTIONS=0;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_ONE_CLICK_SIGNIN;ENABLE_REMOTING=1;ENABLE_WEBRTC=1;ENABLE_CONFIGURATION_POLICY;ENABLE_INPUT_SPEECH;ENABLE_NOTIFICATIONS;ENABLE_GPU=1;ENABLE_EGLIMAGE=1;USE_SKIA=1;__STD_C;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;ENABLE_TASK_MANAGER=1;ENABLE_WEB_INTENTS=1;ENABLE_EXTENSIONS=1;ENABLE_PLUGIN_INSTALLATION=1;ENABLE_PROTECTOR_SERVICE=1;ENABLE_SESSION_SERVICE=1;ENABLE_THEMES=1;ENABLE_BACKGROUND=1;ENABLE_PROMO_RESOURCE_SERVICE=1;ENABLE_AUTOMATION=1;USING_CEF_SHARED;__STDC_FORMAT_MACROS;NO_TCMALLOC;DYNAMIC_ANNOTATIONS_ENABLED=1;WTF_USE_DYNAMIC_ANNOTATIONS=1;%(PreprocessorDefinitions)MultiThreadedDebugfalsetrueLevel4../src/third_party/directxsdk/files/Lib/x86;../src/third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories)/ignore:4221 %(AdditionalOptions)wininet.lib;dnsapi.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;winmm.lib;shlwapi.lib;atlthunk.lib;comctl32.lib;shlwapi.lib;rpcrt4.lib;opengl32.lib;glu32.lib;lib\$(Configuration)\libcef.lib;%(AdditionalDependencies)../src/third_party/directxsdk/files/Lib/x86;../src/third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories)/ignore:4254 /ignore:4078 /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions)dbghelp.dll;dwmapi.dll;shell32.dll;uxtheme.dll;%(DelayLoadDLLs)wWinMainCRTStartupfalsetrue$(OutDir)lib\$(TargetName).lib$(OutDir)$(TargetName).map$(OutDir)$(ProjectName).exefalseWindowsMachineX64%(Filename).dlldata.ctrue%(Filename).h%(Filename)_i.c$(IntDir)%(Filename)_p.c%(Filename).tlb../src;$(OutDir)obj/global_intermediate;..\src\third_party\wtl\include;.;..\src\third_party\directxsdk\files\Include;..\src\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)0x0409_DEBUG;_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_WINDOWS;NOMINMAX;PSAPI_VERSION=1;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_ATL_NO_OPENGL;_HAS_EXCEPTIONS=0;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_ONE_CLICK_SIGNIN;ENABLE_REMOTING=1;ENABLE_WEBRTC=1;ENABLE_CONFIGURATION_POLICY;ENABLE_INPUT_SPEECH;ENABLE_NOTIFICATIONS;ENABLE_GPU=1;ENABLE_EGLIMAGE=1;USE_SKIA=1;__STD_C;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;ENABLE_TASK_MANAGER=1;ENABLE_WEB_INTENTS=1;ENABLE_EXTENSIONS=1;ENABLE_PLUGIN_INSTALLATION=1;ENABLE_PROTECTOR_SERVICE=1;ENABLE_SESSION_SERVICE=1;ENABLE_THEMES=1;ENABLE_BACKGROUND=1;ENABLE_PROMO_RESOURCE_SERVICE=1;ENABLE_AUTOMATION=1;USING_CEF_SHARED;__STDC_FORMAT_MACROS;NO_TCMALLOC;DYNAMIC_ANNOTATIONS_ENABLED=1;WTF_USE_DYNAMIC_ANNOTATIONS=1;%(PreprocessorDefinitions)..\src\third_party\wtl\include;.;..\src\third_party\directxsdk\files\Include;..\src\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)/MP /we4389 /Oy- %(AdditionalOptions)trueProgramDatabase4351;4396;4503;4819;4100;4121;4125;4127;4130;4131;4189;4201;4238;4244;4245;4310;4355;4428;4481;4505;4510;4512;4530;4610;4611;4701;4702;4706;%(DisableSpecificWarnings)falsetrueAnySuitablefalsefalseMaxSpeed_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_WINDOWS;NOMINMAX;PSAPI_VERSION=1;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_ATL_NO_OPENGL;_HAS_EXCEPTIONS=0;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_ONE_CLICK_SIGNIN;ENABLE_REMOTING=1;ENABLE_WEBRTC=1;ENABLE_CONFIGURATION_POLICY;ENABLE_INPUT_SPEECH;ENABLE_NOTIFICATIONS;ENABLE_GPU=1;ENABLE_EGLIMAGE=1;USE_SKIA=1;__STD_C;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;ENABLE_TASK_MANAGER=1;ENABLE_WEB_INTENTS=1;ENABLE_EXTENSIONS=1;ENABLE_PLUGIN_INSTALLATION=1;ENABLE_PROTECTOR_SERVICE=1;ENABLE_SESSION_SERVICE=1;ENABLE_THEMES=1;ENABLE_BACKGROUND=1;ENABLE_PROMO_RESOURCE_SERVICE=1;ENABLE_AUTOMATION=1;USING_CEF_SHARED;__STDC_FORMAT_MACROS;NDEBUG;NVALGRIND;DYNAMIC_ANNOTATIONS_ENABLED=0;%(PreprocessorDefinitions)MultiThreadedfalsetruetrueLevel4../src/third_party/directxsdk/files/Lib/x86;../src/third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories)/ignore:4221 %(AdditionalOptions)wininet.lib;dnsapi.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;winmm.lib;shlwapi.lib;atlthunk.lib;comctl32.lib;shlwapi.lib;rpcrt4.lib;opengl32.lib;glu32.lib;lib\$(Configuration)\libcef.lib;%(AdditionalDependencies)../src/third_party/directxsdk/files/Lib/x86;../src/third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories)/ignore:4254 /ignore:4078 /safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions)dbghelp.dll;dwmapi.dll;shell32.dll;uxtheme.dll;%(DelayLoadDLLs)truewWinMainCRTStartupfalsetrue$(OutDir)lib\$(TargetName).lib$(OutDir)$(TargetName).maptrue$(OutDir)$(ProjectName).exetrueWindowsMachineX86%(Filename).dlldata.ctrue%(Filename).h%(Filename)_i.c$(IntDir)%(Filename)_p.c%(Filename).tlb../src;$(OutDir)obj/global_intermediate;..\src\third_party\wtl\include;.;..\src\third_party\directxsdk\files\Include;..\src\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)0x0409_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_WINDOWS;NOMINMAX;PSAPI_VERSION=1;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_ATL_NO_OPENGL;_HAS_EXCEPTIONS=0;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_ONE_CLICK_SIGNIN;ENABLE_REMOTING=1;ENABLE_WEBRTC=1;ENABLE_CONFIGURATION_POLICY;ENABLE_INPUT_SPEECH;ENABLE_NOTIFICATIONS;ENABLE_GPU=1;ENABLE_EGLIMAGE=1;USE_SKIA=1;__STD_C;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;ENABLE_TASK_MANAGER=1;ENABLE_WEB_INTENTS=1;ENABLE_EXTENSIONS=1;ENABLE_PLUGIN_INSTALLATION=1;ENABLE_PROTECTOR_SERVICE=1;ENABLE_SESSION_SERVICE=1;ENABLE_THEMES=1;ENABLE_BACKGROUND=1;ENABLE_PROMO_RESOURCE_SERVICE=1;ENABLE_AUTOMATION=1;USING_CEF_SHARED;__STDC_FORMAT_MACROS;NDEBUG;NVALGRIND;DYNAMIC_ANNOTATIONS_ENABLED=0;%(PreprocessorDefinitions);%(PreprocessorDefinitions)..\src\third_party\wtl\include;.;..\src\third_party\directxsdk\files\Include;..\src\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)/MP /we4389 /Oy- %(AdditionalOptions)trueProgramDatabase4351;4396;4503;4819;4100;4121;4125;4127;4130;4131;4189;4201;4238;4244;4245;4310;4355;4428;4481;4505;4510;4512;4530;4610;4611;4701;4702;4706;%(DisableSpecificWarnings)falsetrueAnySuitablefalsefalseMaxSpeed_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_WINDOWS;NOMINMAX;PSAPI_VERSION=1;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_ATL_NO_OPENGL;_HAS_EXCEPTIONS=0;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_ONE_CLICK_SIGNIN;ENABLE_REMOTING=1;ENABLE_WEBRTC=1;ENABLE_CONFIGURATION_POLICY;ENABLE_INPUT_SPEECH;ENABLE_NOTIFICATIONS;ENABLE_GPU=1;ENABLE_EGLIMAGE=1;USE_SKIA=1;__STD_C;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;ENABLE_TASK_MANAGER=1;ENABLE_WEB_INTENTS=1;ENABLE_EXTENSIONS=1;ENABLE_PLUGIN_INSTALLATION=1;ENABLE_PROTECTOR_SERVICE=1;ENABLE_SESSION_SERVICE=1;ENABLE_THEMES=1;ENABLE_BACKGROUND=1;ENABLE_PROMO_RESOURCE_SERVICE=1;ENABLE_AUTOMATION=1;USING_CEF_SHARED;__STDC_FORMAT_MACROS;NO_TCMALLOC;NDEBUG;NVALGRIND;DYNAMIC_ANNOTATIONS_ENABLED=0;%(PreprocessorDefinitions)MultiThreadedfalsetruetrueLevel4../src/third_party/directxsdk/files/Lib/x86;../src/third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories)/ignore:4221 %(AdditionalOptions)wininet.lib;dnsapi.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;winmm.lib;shlwapi.lib;atlthunk.lib;comctl32.lib;shlwapi.lib;rpcrt4.lib;opengl32.lib;glu32.lib;lib\$(Configuration)\libcef.lib;%(AdditionalDependencies)../src/third_party/directxsdk/files/Lib/x86;../src/third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories)/ignore:4254 /ignore:4078 /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions)dbghelp.dll;dwmapi.dll;shell32.dll;uxtheme.dll;%(DelayLoadDLLs)truewWinMainCRTStartupfalsetrue$(OutDir)lib\$(TargetName).lib$(OutDir)$(TargetName).maptrue$(OutDir)$(ProjectName).exetrueWindowsMachineX64%(Filename).dlldata.ctrue%(Filename).h%(Filename)_i.c$(IntDir)%(Filename)_p.c%(Filename).tlb../src;$(OutDir)obj/global_intermediate;..\src\third_party\wtl\include;.;..\src\third_party\directxsdk\files\Include;..\src\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)0x0409_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_WINDOWS;NOMINMAX;PSAPI_VERSION=1;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_ATL_NO_OPENGL;_HAS_EXCEPTIONS=0;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_ONE_CLICK_SIGNIN;ENABLE_REMOTING=1;ENABLE_WEBRTC=1;ENABLE_CONFIGURATION_POLICY;ENABLE_INPUT_SPEECH;ENABLE_NOTIFICATIONS;ENABLE_GPU=1;ENABLE_EGLIMAGE=1;USE_SKIA=1;__STD_C;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;ENABLE_TASK_MANAGER=1;ENABLE_WEB_INTENTS=1;ENABLE_EXTENSIONS=1;ENABLE_PLUGIN_INSTALLATION=1;ENABLE_PROTECTOR_SERVICE=1;ENABLE_SESSION_SERVICE=1;ENABLE_THEMES=1;ENABLE_BACKGROUND=1;ENABLE_PROMO_RESOURCE_SERVICE=1;ENABLE_AUTOMATION=1;USING_CEF_SHARED;__STDC_FORMAT_MACROS;NO_TCMALLOC;NDEBUG;NVALGRIND;DYNAMIC_ANNOTATIONS_ENABLED=0;%(PreprocessorDefinitions);%(PreprocessorDefinitions){A9D6DC71-C0DC-4549-AEA0-3B15B44E86A9}false
\ No newline at end of file
+DebugWin32Debugx64ReleaseWin32Releasex64{6617FED9-C5D4-4907-BF55-A90062A6683F}Win32ProjBracketsUnicodeApplication$(ExecutablePath);$(MSBuildProjectDirectory)\..\src\third_party\cygwin\bin\;$(MSBuildProjectDirectory)\..\src\third_party\python_26\$(Configuration)\$(OutDir)obj\$(ProjectName)\falsefalsetruetrue$(ProjectName)$(OutDir)\$(ProjectName).exe..\src\third_party\wtl\include;.;..\src\third_party\directxsdk\files\Include;..\src\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)/MP /we4389 %(AdditionalOptions)EnableFastCheckstrueProgramDatabase4351;4396;4503;4819;4100;4121;4125;4127;4130;4131;4189;4201;4238;4244;4245;4310;4355;4428;4481;4505;4510;4512;4530;4610;4611;4701;4702;4706;%(DisableSpecificWarnings)falsetruefalseDisabled_DEBUG;_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_WINDOWS;NOMINMAX;PSAPI_VERSION=1;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_ATL_NO_OPENGL;_HAS_EXCEPTIONS=0;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_ONE_CLICK_SIGNIN;ENABLE_REMOTING=1;ENABLE_WEBRTC=1;ENABLE_CONFIGURATION_POLICY;ENABLE_INPUT_SPEECH;ENABLE_NOTIFICATIONS;ENABLE_GPU=1;ENABLE_EGLIMAGE=1;USE_SKIA=1;__STD_C;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;ENABLE_TASK_MANAGER=1;ENABLE_WEB_INTENTS=1;ENABLE_EXTENSIONS=1;ENABLE_PLUGIN_INSTALLATION=1;ENABLE_PROTECTOR_SERVICE=1;ENABLE_SESSION_SERVICE=1;ENABLE_THEMES=1;ENABLE_BACKGROUND=1;ENABLE_PROMO_RESOURCE_SERVICE=1;ENABLE_AUTOMATION=1;USING_CEF_SHARED;__STDC_FORMAT_MACROS;DYNAMIC_ANNOTATIONS_ENABLED=1;WTF_USE_DYNAMIC_ANNOTATIONS=1;%(PreprocessorDefinitions)MultiThreadedDebugfalsetrueLevel4../src/third_party/directxsdk/files/Lib/x86;../src/third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories)/ignore:4221 %(AdditionalOptions)wininet.lib;dnsapi.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;winmm.lib;shlwapi.lib;atlthunk.lib;comctl32.lib;shlwapi.lib;rpcrt4.lib;opengl32.lib;glu32.lib;lib\$(Configuration)\libcef.lib;%(AdditionalDependencies)../src/third_party/directxsdk/files/Lib/x86;../src/third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories)/ignore:4254 /ignore:4078 /safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions)dbghelp.dll;dwmapi.dll;shell32.dll;uxtheme.dll;%(DelayLoadDLLs)wWinMainCRTStartupfalsetrue$(OutDir)lib\$(TargetName).lib$(OutDir)$(TargetName).map$(OutDir)$(ProjectName).exefalseWindowsMachineX86%(Filename).dlldata.ctrue%(Filename).h%(Filename)_i.c$(IntDir)%(Filename)_p.c%(Filename).tlb../src;$(OutDir)obj/global_intermediate;..\src\third_party\wtl\include;.;..\src\third_party\directxsdk\files\Include;..\src\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)0x0409_DEBUG;_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_WINDOWS;NOMINMAX;PSAPI_VERSION=1;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_ATL_NO_OPENGL;_HAS_EXCEPTIONS=0;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_ONE_CLICK_SIGNIN;ENABLE_REMOTING=1;ENABLE_WEBRTC=1;ENABLE_CONFIGURATION_POLICY;ENABLE_INPUT_SPEECH;ENABLE_NOTIFICATIONS;ENABLE_GPU=1;ENABLE_EGLIMAGE=1;USE_SKIA=1;__STD_C;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;ENABLE_TASK_MANAGER=1;ENABLE_WEB_INTENTS=1;ENABLE_EXTENSIONS=1;ENABLE_PLUGIN_INSTALLATION=1;ENABLE_PROTECTOR_SERVICE=1;ENABLE_SESSION_SERVICE=1;ENABLE_THEMES=1;ENABLE_BACKGROUND=1;ENABLE_PROMO_RESOURCE_SERVICE=1;ENABLE_AUTOMATION=1;USING_CEF_SHARED;__STDC_FORMAT_MACROS;DYNAMIC_ANNOTATIONS_ENABLED=1;WTF_USE_DYNAMIC_ANNOTATIONS=1;%(PreprocessorDefinitions)..\src\third_party\wtl\include;.;..\src\third_party\directxsdk\files\Include;..\src\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)/MP /we4389 %(AdditionalOptions)EnableFastCheckstrueProgramDatabase4351;4396;4503;4819;4100;4121;4125;4127;4130;4131;4189;4201;4238;4244;4245;4310;4355;4428;4481;4505;4510;4512;4530;4610;4611;4701;4702;4706;%(DisableSpecificWarnings)falsetruefalseDisabled_DEBUG;_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_WINDOWS;NOMINMAX;PSAPI_VERSION=1;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_ATL_NO_OPENGL;_HAS_EXCEPTIONS=0;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_ONE_CLICK_SIGNIN;ENABLE_REMOTING=1;ENABLE_WEBRTC=1;ENABLE_CONFIGURATION_POLICY;ENABLE_INPUT_SPEECH;ENABLE_NOTIFICATIONS;ENABLE_GPU=1;ENABLE_EGLIMAGE=1;USE_SKIA=1;__STD_C;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;ENABLE_TASK_MANAGER=1;ENABLE_WEB_INTENTS=1;ENABLE_EXTENSIONS=1;ENABLE_PLUGIN_INSTALLATION=1;ENABLE_PROTECTOR_SERVICE=1;ENABLE_SESSION_SERVICE=1;ENABLE_THEMES=1;ENABLE_BACKGROUND=1;ENABLE_PROMO_RESOURCE_SERVICE=1;ENABLE_AUTOMATION=1;USING_CEF_SHARED;__STDC_FORMAT_MACROS;NO_TCMALLOC;DYNAMIC_ANNOTATIONS_ENABLED=1;WTF_USE_DYNAMIC_ANNOTATIONS=1;%(PreprocessorDefinitions)MultiThreadedDebugfalsetrueLevel4../src/third_party/directxsdk/files/Lib/x86;../src/third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories)/ignore:4221 %(AdditionalOptions)wininet.lib;dnsapi.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;winmm.lib;shlwapi.lib;atlthunk.lib;comctl32.lib;shlwapi.lib;rpcrt4.lib;opengl32.lib;glu32.lib;lib\$(Configuration)\libcef.lib;%(AdditionalDependencies)../src/third_party/directxsdk/files/Lib/x86;../src/third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories)/ignore:4254 /ignore:4078 /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions)dbghelp.dll;dwmapi.dll;shell32.dll;uxtheme.dll;%(DelayLoadDLLs)wWinMainCRTStartupfalsetrue$(OutDir)lib\$(TargetName).lib$(OutDir)$(TargetName).map$(OutDir)$(ProjectName).exefalseWindowsMachineX64%(Filename).dlldata.ctrue%(Filename).h%(Filename)_i.c$(IntDir)%(Filename)_p.c%(Filename).tlb../src;$(OutDir)obj/global_intermediate;..\src\third_party\wtl\include;.;..\src\third_party\directxsdk\files\Include;..\src\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)0x0409_DEBUG;_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_WINDOWS;NOMINMAX;PSAPI_VERSION=1;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_ATL_NO_OPENGL;_HAS_EXCEPTIONS=0;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_ONE_CLICK_SIGNIN;ENABLE_REMOTING=1;ENABLE_WEBRTC=1;ENABLE_CONFIGURATION_POLICY;ENABLE_INPUT_SPEECH;ENABLE_NOTIFICATIONS;ENABLE_GPU=1;ENABLE_EGLIMAGE=1;USE_SKIA=1;__STD_C;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;ENABLE_TASK_MANAGER=1;ENABLE_WEB_INTENTS=1;ENABLE_EXTENSIONS=1;ENABLE_PLUGIN_INSTALLATION=1;ENABLE_PROTECTOR_SERVICE=1;ENABLE_SESSION_SERVICE=1;ENABLE_THEMES=1;ENABLE_BACKGROUND=1;ENABLE_PROMO_RESOURCE_SERVICE=1;ENABLE_AUTOMATION=1;USING_CEF_SHARED;__STDC_FORMAT_MACROS;NO_TCMALLOC;DYNAMIC_ANNOTATIONS_ENABLED=1;WTF_USE_DYNAMIC_ANNOTATIONS=1;%(PreprocessorDefinitions)..\src\third_party\wtl\include;.;..\src\third_party\directxsdk\files\Include;..\src\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)/MP /we4389 /Oy- %(AdditionalOptions)trueProgramDatabase4351;4396;4503;4819;4100;4121;4125;4127;4130;4131;4189;4201;4238;4244;4245;4310;4355;4428;4481;4505;4510;4512;4530;4610;4611;4701;4702;4706;%(DisableSpecificWarnings)falsetrueAnySuitablefalsefalseMaxSpeed_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_WINDOWS;NOMINMAX;PSAPI_VERSION=1;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_ATL_NO_OPENGL;_HAS_EXCEPTIONS=0;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_ONE_CLICK_SIGNIN;ENABLE_REMOTING=1;ENABLE_WEBRTC=1;ENABLE_CONFIGURATION_POLICY;ENABLE_INPUT_SPEECH;ENABLE_NOTIFICATIONS;ENABLE_GPU=1;ENABLE_EGLIMAGE=1;USE_SKIA=1;__STD_C;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;ENABLE_TASK_MANAGER=1;ENABLE_WEB_INTENTS=1;ENABLE_EXTENSIONS=1;ENABLE_PLUGIN_INSTALLATION=1;ENABLE_PROTECTOR_SERVICE=1;ENABLE_SESSION_SERVICE=1;ENABLE_THEMES=1;ENABLE_BACKGROUND=1;ENABLE_PROMO_RESOURCE_SERVICE=1;ENABLE_AUTOMATION=1;USING_CEF_SHARED;__STDC_FORMAT_MACROS;NDEBUG;NVALGRIND;DYNAMIC_ANNOTATIONS_ENABLED=0;%(PreprocessorDefinitions)MultiThreadedfalsetruetrueLevel4../src/third_party/directxsdk/files/Lib/x86;../src/third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories)/ignore:4221 %(AdditionalOptions)wininet.lib;dnsapi.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;winmm.lib;shlwapi.lib;atlthunk.lib;comctl32.lib;shlwapi.lib;rpcrt4.lib;opengl32.lib;glu32.lib;lib\$(Configuration)\libcef.lib;%(AdditionalDependencies)../src/third_party/directxsdk/files/Lib/x86;../src/third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories)/ignore:4254 /ignore:4078 /safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions)dbghelp.dll;dwmapi.dll;shell32.dll;uxtheme.dll;%(DelayLoadDLLs)truewWinMainCRTStartupfalsetrue$(OutDir)lib\$(TargetName).lib$(OutDir)$(TargetName).maptrue$(OutDir)$(ProjectName).exetrueWindowsMachineX86%(Filename).dlldata.ctrue%(Filename).h%(Filename)_i.c$(IntDir)%(Filename)_p.c%(Filename).tlb../src;$(OutDir)obj/global_intermediate;..\src\third_party\wtl\include;.;..\src\third_party\directxsdk\files\Include;..\src\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)0x0409_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_WINDOWS;NOMINMAX;PSAPI_VERSION=1;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_ATL_NO_OPENGL;_HAS_EXCEPTIONS=0;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_ONE_CLICK_SIGNIN;ENABLE_REMOTING=1;ENABLE_WEBRTC=1;ENABLE_CONFIGURATION_POLICY;ENABLE_INPUT_SPEECH;ENABLE_NOTIFICATIONS;ENABLE_GPU=1;ENABLE_EGLIMAGE=1;USE_SKIA=1;__STD_C;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;ENABLE_TASK_MANAGER=1;ENABLE_WEB_INTENTS=1;ENABLE_EXTENSIONS=1;ENABLE_PLUGIN_INSTALLATION=1;ENABLE_PROTECTOR_SERVICE=1;ENABLE_SESSION_SERVICE=1;ENABLE_THEMES=1;ENABLE_BACKGROUND=1;ENABLE_PROMO_RESOURCE_SERVICE=1;ENABLE_AUTOMATION=1;USING_CEF_SHARED;__STDC_FORMAT_MACROS;NDEBUG;NVALGRIND;DYNAMIC_ANNOTATIONS_ENABLED=0;%(PreprocessorDefinitions);%(PreprocessorDefinitions)..\src\third_party\wtl\include;.;..\src\third_party\directxsdk\files\Include;..\src\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)/MP /we4389 /Oy- %(AdditionalOptions)trueProgramDatabase4351;4396;4503;4819;4100;4121;4125;4127;4130;4131;4189;4201;4238;4244;4245;4310;4355;4428;4481;4505;4510;4512;4530;4610;4611;4701;4702;4706;%(DisableSpecificWarnings)falsetrueAnySuitablefalsefalseMaxSpeed_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_WINDOWS;NOMINMAX;PSAPI_VERSION=1;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_ATL_NO_OPENGL;_HAS_EXCEPTIONS=0;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_ONE_CLICK_SIGNIN;ENABLE_REMOTING=1;ENABLE_WEBRTC=1;ENABLE_CONFIGURATION_POLICY;ENABLE_INPUT_SPEECH;ENABLE_NOTIFICATIONS;ENABLE_GPU=1;ENABLE_EGLIMAGE=1;USE_SKIA=1;__STD_C;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;ENABLE_TASK_MANAGER=1;ENABLE_WEB_INTENTS=1;ENABLE_EXTENSIONS=1;ENABLE_PLUGIN_INSTALLATION=1;ENABLE_PROTECTOR_SERVICE=1;ENABLE_SESSION_SERVICE=1;ENABLE_THEMES=1;ENABLE_BACKGROUND=1;ENABLE_PROMO_RESOURCE_SERVICE=1;ENABLE_AUTOMATION=1;USING_CEF_SHARED;__STDC_FORMAT_MACROS;NO_TCMALLOC;NDEBUG;NVALGRIND;DYNAMIC_ANNOTATIONS_ENABLED=0;%(PreprocessorDefinitions)MultiThreadedfalsetruetrueLevel4../src/third_party/directxsdk/files/Lib/x86;../src/third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories)/ignore:4221 %(AdditionalOptions)wininet.lib;dnsapi.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;winmm.lib;shlwapi.lib;atlthunk.lib;comctl32.lib;shlwapi.lib;rpcrt4.lib;opengl32.lib;glu32.lib;lib\$(Configuration)\libcef.lib;%(AdditionalDependencies)../src/third_party/directxsdk/files/Lib/x86;../src/third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories)/ignore:4254 /ignore:4078 /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions)dbghelp.dll;dwmapi.dll;shell32.dll;uxtheme.dll;%(DelayLoadDLLs)truewWinMainCRTStartupfalsetrue$(OutDir)lib\$(TargetName).lib$(OutDir)$(TargetName).maptrue$(OutDir)$(ProjectName).exetrueWindowsMachineX64%(Filename).dlldata.ctrue%(Filename).h%(Filename)_i.c$(IntDir)%(Filename)_p.c%(Filename).tlb../src;$(OutDir)obj/global_intermediate;..\src\third_party\wtl\include;.;..\src\third_party\directxsdk\files\Include;..\src\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)0x0409_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_WINDOWS;NOMINMAX;PSAPI_VERSION=1;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_ATL_NO_OPENGL;_HAS_EXCEPTIONS=0;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_ONE_CLICK_SIGNIN;ENABLE_REMOTING=1;ENABLE_WEBRTC=1;ENABLE_CONFIGURATION_POLICY;ENABLE_INPUT_SPEECH;ENABLE_NOTIFICATIONS;ENABLE_GPU=1;ENABLE_EGLIMAGE=1;USE_SKIA=1;__STD_C;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;ENABLE_TASK_MANAGER=1;ENABLE_WEB_INTENTS=1;ENABLE_EXTENSIONS=1;ENABLE_PLUGIN_INSTALLATION=1;ENABLE_PROTECTOR_SERVICE=1;ENABLE_SESSION_SERVICE=1;ENABLE_THEMES=1;ENABLE_BACKGROUND=1;ENABLE_PROMO_RESOURCE_SERVICE=1;ENABLE_AUTOMATION=1;USING_CEF_SHARED;__STDC_FORMAT_MACROS;NO_TCMALLOC;NDEBUG;NVALGRIND;DYNAMIC_ANNOTATIONS_ENABLED=0;%(PreprocessorDefinitions);%(PreprocessorDefinitions){A9D6DC71-C0DC-4549-AEA0-3B15B44E86A9}false
\ No newline at end of file
diff --git a/appshell.xcodeproj/project.pbxproj b/appshell.xcodeproj/project.pbxproj
index f9e511571..f83f45d21 100644
--- a/appshell.xcodeproj/project.pbxproj
+++ b/appshell.xcodeproj/project.pbxproj
@@ -58,7 +58,10 @@
50181DE4B5E76F3D4A8AAF31 /* v8exception_ctocpp.cc in Sources */ = {isa = PBXBuildFile; fileRef = E8875422733185EBC5AB471B /* v8exception_ctocpp.cc */; };
5164086404B14363CC7BCBE0 /* libcef_dll_wrapper2.cc in Sources */ = {isa = PBXBuildFile; fileRef = C36233CB23734A273D2D0F79 /* libcef_dll_wrapper2.cc */; };
5241E88E7E6435DE2C0FE500 /* transfer_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B9211C221356E0B082C4816A /* transfer_util.cpp */; };
+ 5B03FFBE66C7EE2CDF6B714E /* client_app_mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = FC33590C4ECC150F9CD14493 /* client_app_mac.mm */; };
+ 5B112E85C066A8D1E8EF68A4 /* appshell_extensions_mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 95AC844F2FA9D42891B3B718 /* appshell_extensions_mac.mm */; };
61A09DAC3E367C528215AB8B /* libcef_dll_wrapper.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A90B310A1CB19C285E2E13FE /* libcef_dll_wrapper.a */; };
+ 6479369F5007A233EABEB8A0 /* appshell_extensions_mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 95AC844F2FA9D42891B3B718 /* appshell_extensions_mac.mm */; };
651022340D1643D1DE957102 /* post_data_element_ctocpp.cc in Sources */ = {isa = PBXBuildFile; fileRef = 235412E5669505A9DD7C2303 /* post_data_element_ctocpp.cc */; };
655F9692081BDAAB642B28DC /* render_process_handler_cpptoc.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8ABFDFF093F6B71602851374 /* render_process_handler_cpptoc.cc */; };
6B295097B29E8FB628815A1B /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = EDDE848ADF50901E338C0DE5 /* MainMenu.xib */; };
@@ -73,6 +76,7 @@
77B44090879F7B257B0A0CEB /* xml_reader_ctocpp.cc in Sources */ = {isa = PBXBuildFile; fileRef = 701C240F17A4F8EFFCC847A2 /* xml_reader_ctocpp.cc */; };
7E9E53F9616772C333B53648 /* scheme_registrar_ctocpp.cc in Sources */ = {isa = PBXBuildFile; fileRef = 55748D6E9030E3B6C840CF5D /* scheme_registrar_ctocpp.cc */; };
7EFAFB1448C87C8DE173F944 /* app_cpptoc.cc in Sources */ = {isa = PBXBuildFile; fileRef = 526E2A18DDBBC48588F9C5D1 /* app_cpptoc.cc */; };
+ 8094DACA8E9D03B15276A209 /* client_app_mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = FC33590C4ECC150F9CD14493 /* client_app_mac.mm */; };
8B08D82804E3AF6B56209362 /* string_visitor_cpptoc.cc in Sources */ = {isa = PBXBuildFile; fileRef = 728F974FA38A31AFD1EBA1ED /* string_visitor_cpptoc.cc */; };
8DE8BB00C9A057C5A5650F3D /* process_message_ctocpp.cc in Sources */ = {isa = PBXBuildFile; fileRef = A51598CF3816523F930B971E /* process_message_ctocpp.cc */; };
8F03DB06DAEB3FCC64DBB7F8 /* stream_reader_ctocpp.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1BE21DEA53CCCB6F82B61230 /* stream_reader_ctocpp.cc */; };
@@ -83,6 +87,7 @@
98D7CA892DCE9560817D8DA3 /* client_app.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C262FF082FED71CE8963FDD5 /* client_app.cpp */; };
990947BBC7343DE4AB4BAB0C /* write_handler_cpptoc.cc in Sources */ = {isa = PBXBuildFile; fileRef = 67053B18354E8CC9611FF337 /* write_handler_cpptoc.cc */; };
99CA415A86381C3A1CD4786B /* cef_zip_archive.cc in Sources */ = {isa = PBXBuildFile; fileRef = EE7BB11CB542B7D63E79B9CA /* cef_zip_archive.cc */; };
+ A53BD3DB0E080310E710A5CE /* appshell_extensions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F41FB3563A8DCA978ABCB8F0 /* appshell_extensions.cpp */; };
A73C3E303E6BB270392F0AE8 /* life_span_handler_cpptoc.cc in Sources */ = {isa = PBXBuildFile; fileRef = EAD92ED581FB452EFBCF7D44 /* life_span_handler_cpptoc.cc */; };
A7C00A73ED6CE468CB8A2DEF /* client_app.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C262FF082FED71CE8963FDD5 /* client_app.cpp */; };
AB081BE46ED66D36C42D7D60 /* post_data_ctocpp.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4DBB14594CDA494499E58C80 /* post_data_ctocpp.cc */; };
@@ -98,6 +103,7 @@
C5EBE4A85C81F593EDF064F5 /* cefclient_mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 79A2E45EB29CAA66453661C6 /* cefclient_mac.mm */; };
C7429BF3C7C74CB98723F6C0 /* command_line_ctocpp.cc in Sources */ = {isa = PBXBuildFile; fileRef = EB60AE270B721E13CF1126AD /* command_line_ctocpp.cc */; };
C90FB710D7B25572E80BFD69 /* v8accessor_cpptoc.cc in Sources */ = {isa = PBXBuildFile; fileRef = 845EEC823278584B42AFB2B7 /* v8accessor_cpptoc.cc */; };
+ CF1EE9AEF2671F90918C896C /* brackets_extensions.js in Resources */ = {isa = PBXBuildFile; fileRef = F55C44F44BBA964EFE0B704F /* brackets_extensions.js */; };
D44993FFF44DE7241797A865 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 117371CDDB44775B39107AA8 /* AppKit.framework */; };
DB1186A70776CD627B4B42AE /* cefclient.icns in Resources */ = {isa = PBXBuildFile; fileRef = 7E44B655C022B8B96CA64796 /* cefclient.icns */; };
DDA2289823F976BECC01755A /* menu_model_ctocpp.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86E19C99BCCDDA939F257FE0 /* menu_model_ctocpp.cc */; };
@@ -112,6 +118,7 @@
F1E056DC74DBC0A17CFBB9FF /* cookie_manager_ctocpp.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F7B40527EE1F8F402382F97 /* cookie_manager_ctocpp.cc */; };
F287A235239E07C7511F19DE /* libcef.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = B65894845851B9D3DEE6BD03 /* libcef.dylib */; };
F453746E3A07998455CA5CD2 /* libcef_dll_wrapper.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2C959542749DCE6EF708F135 /* libcef_dll_wrapper.cc */; };
+ F53B304C1BAF754B5D7CCEC2 /* appshell_extensions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F41FB3563A8DCA978ABCB8F0 /* appshell_extensions.cpp */; };
F558BB943DC32BAA0AB011AA /* v8context_ctocpp.cc in Sources */ = {isa = PBXBuildFile; fileRef = A95031741301CFE71BCF96C9 /* v8context_ctocpp.cc */; };
F7C604529546A7AC1B1AE933 /* stream_writer_ctocpp.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3AC7F60052DF0CFDC362E6B8 /* stream_writer_ctocpp.cc */; };
FF803CCD1CE21AD82FC1FB51 /* cef_byte_read_handler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 486533211D801204BD33CC8D /* cef_byte_read_handler.cc */; };
@@ -248,6 +255,7 @@
26049B47F404C3F1C50C2D66 /* process_message_ctocpp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = process_message_ctocpp.h; sourceTree = ""; };
2AB635C6500A7B6F5FF96611 /* callback_ctocpp.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = callback_ctocpp.cc; sourceTree = ""; };
2BA3A8374DBB04156F6EF07C /* proxy_handler_cpptoc.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = proxy_handler_cpptoc.cc; sourceTree = ""; };
+ 2C6200DAA24D72696664A534 /* appshell_extensions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = appshell_extensions.h; sourceTree = ""; };
2C959542749DCE6EF708F135 /* libcef_dll_wrapper.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = libcef_dll_wrapper.cc; sourceTree = ""; };
2D988111567F6C1E447D780A /* v8handler_cpptoc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = v8handler_cpptoc.h; sourceTree = ""; };
2DB2A4E97F0B4F92A4DBA725 /* cef_menu_model_capi.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cef_menu_model_capi.h; sourceTree = ""; };
@@ -356,6 +364,7 @@
932B910099817CB226487AF4 /* cef_ptr.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cef_ptr.h; sourceTree = ""; };
93B4F36427B200909D58F8F9 /* cef_base.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cef_base.h; sourceTree = ""; };
94288A47CD51C8E44C1D9A7D /* cef_proxy_handler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cef_proxy_handler.h; sourceTree = ""; };
+ 95AC844F2FA9D42891B3B718 /* appshell_extensions_mac.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = appshell_extensions_mac.mm; sourceTree = ""; };
960AF2FA67AD34478B16E1FE /* ffmpegsumo.so */ = {isa = PBXFileReference; lastKnownFileType = text; path = ffmpegsumo.so; sourceTree = ""; };
9B6B1C35B41FBDC6DDEFF52E /* read_handler_cpptoc.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = read_handler_cpptoc.cc; sourceTree = ""; };
9C2240AAB28AC105AD67ACFD /* cef_frame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cef_frame.h; sourceTree = ""; };
@@ -448,6 +457,8 @@
F12B1A4A09CF4E1F813847E0 /* browser_ctocpp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = browser_ctocpp.h; sourceTree = ""; };
F1989B67661244ED4B756EE5 /* libcef.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libcef.dylib; sourceTree = ""; };
F31B254B0DC7D754A1D4D56C /* cef_resource_handler_capi.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cef_resource_handler_capi.h; sourceTree = ""; };
+ F41FB3563A8DCA978ABCB8F0 /* appshell_extensions.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = appshell_extensions.cpp; sourceTree = ""; };
+ F55C44F44BBA964EFE0B704F /* brackets_extensions.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = brackets_extensions.js; sourceTree = ""; };
F7D894242D95F2E165D0ECF6 /* cef_request_capi.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cef_request_capi.h; sourceTree = ""; };
F8650F6813183C119C198C0F /* stream_writer_ctocpp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = stream_writer_ctocpp.h; sourceTree = ""; };
F920274FE06506D9C02842CB /* command_line_ctocpp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = command_line_ctocpp.h; sourceTree = ""; };
@@ -455,6 +466,7 @@
FB03F1F09DDFCCF5D58CF31D /* binary_value_ctocpp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = binary_value_ctocpp.h; sourceTree = ""; };
FB39173002CA728B2B51C8F3 /* frame_ctocpp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = frame_ctocpp.h; sourceTree = ""; };
FB9407413C949B6C12F9549A /* cef_string_wrappers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cef_string_wrappers.h; sourceTree = ""; };
+ FC33590C4ECC150F9CD14493 /* client_app_mac.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = client_app_mac.mm; sourceTree = ""; };
FCBAC4B85685426F6512BE75 /* cef_geolocation_handler_capi.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cef_geolocation_handler_capi.h; sourceTree = ""; };
FF9E4C8D69990559025EF876 /* domevent_listener_cpptoc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = domevent_listener_cpptoc.h; sourceTree = ""; };
/* End PBXFileReference section */
@@ -556,12 +568,17 @@
isa = PBXGroup;
children = (
2CF60921DE182D498BFC8418 /* mac */,
+ F41FB3563A8DCA978ABCB8F0 /* appshell_extensions.cpp */,
+ 2C6200DAA24D72696664A534 /* appshell_extensions.h */,
+ 95AC844F2FA9D42891B3B718 /* appshell_extensions_mac.mm */,
+ F55C44F44BBA964EFE0B704F /* brackets_extensions.js */,
522C920B68963035E6CE38FE /* cefclient.cpp */,
217F2C98268E9035AD8D9C14 /* cefclient.h */,
79A2E45EB29CAA66453661C6 /* cefclient_mac.mm */,
C262FF082FED71CE8963FDD5 /* client_app.cpp */,
E384B4657EF8569EBD6FF325 /* client_app.h */,
EC32618A1323B894948367CF /* client_app_delegates.cpp */,
+ FC33590C4ECC150F9CD14493 /* client_app_mac.mm */,
E7F32E5943867A24A58C24C9 /* client_handler.cpp */,
E058AF089C813B0607A4E889 /* client_handler.h */,
E93F80CFC491C3C09AFDD87B /* client_handler_mac.mm */,
@@ -977,6 +994,7 @@
DB1186A70776CD627B4B42AE /* cefclient.icns in Resources */,
EB4A35C3C60BE898F8FB7EC6 /* InfoPlist.strings in Resources */,
6B295097B29E8FB628815A1B /* MainMenu.xib in Resources */,
+ CF1EE9AEF2671F90918C896C /* brackets_extensions.js in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1102,12 +1120,15 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ F53B304C1BAF754B5D7CCEC2 /* appshell_extensions.cpp in Sources */,
2CC364D7509BFD402CACB9ED /* cefclient.cpp in Sources */,
98D7CA892DCE9560817D8DA3 /* client_app.cpp in Sources */,
44E07FA909A2EC86622D67D8 /* client_app_delegates.cpp in Sources */,
486D6CF9DA73142E734968DC /* client_handler.cpp in Sources */,
ABA1F3972217F5082F33E0A4 /* client_switches.cpp in Sources */,
404420811CFE6F0A01D86D6E /* string_util.cpp in Sources */,
+ 5B112E85C066A8D1E8EF68A4 /* appshell_extensions_mac.mm in Sources */,
+ 8094DACA8E9D03B15276A209 /* client_app_mac.mm in Sources */,
C5EBE4A85C81F593EDF064F5 /* cefclient_mac.mm in Sources */,
7418E8ADE705BE89705C7438 /* client_handler_mac.mm in Sources */,
3DECED27298A79759F892390 /* resource_util_mac.mm in Sources */,
@@ -1118,7 +1139,10 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ A53BD3DB0E080310E710A5CE /* appshell_extensions.cpp in Sources */,
+ 6479369F5007A233EABEB8A0 /* appshell_extensions_mac.mm in Sources */,
A7C00A73ED6CE468CB8A2DEF /* client_app.cpp in Sources */,
+ 5B03FFBE66C7EE2CDF6B714E /* client_app_mac.mm in Sources */,
37732F00B07028873199D832 /* client_app_delegates.cpp in Sources */,
3140F36769DD91AE0E8CCF33 /* client_handler.cpp in Sources */,
260B3DA94CD1F852F773351D /* client_handler_mac.mm in Sources */,
diff --git a/appshell/appshell_extensions.cpp b/appshell/appshell_extensions.cpp
new file mode 100644
index 000000000..5b1aff08b
--- /dev/null
+++ b/appshell/appshell_extensions.cpp
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "appshell/appshell_extensions.h"
+
+namespace appshell_extensions {
+
+namespace {
+
+class ProcessMessageDelegate : public ClientHandler::ProcessMessageDelegate {
+public:
+ ProcessMessageDelegate()
+ {
+ }
+
+ // From ClientHandler::ProcessMessageDelegate.
+ virtual bool OnProcessMessageRecieved(
+ CefRefPtr handler,
+ CefRefPtr browser,
+ CefProcessId source_process,
+ CefRefPtr message) OVERRIDE {
+ std::string message_name = message->GetName();
+ CefRefPtr argList = message->GetArgumentList();
+ int32 callbackId;
+ int32 error = NO_ERROR;
+ CefRefPtr response =
+ CefProcessMessage::Create("invokeCallback");
+ CefRefPtr responseArgs = response->GetArgumentList();
+
+ // V8 extension messages are handled here. These messages come from the
+ // render process thread (in client_app.cpp), and have the following format:
+ // name - the name of the native function to call
+ // argument0 - the id of this message. This id is passed back to the
+ // render process in order to execute callbacks
+ // argument1 - argumentN - the arguments for the function
+
+ if (argList->GetSize() < 1) {
+ fprintf(stderr, "No callback id specified for function %s\n", message_name.c_str());
+ return false;
+ }
+ callbackId = argList->GetInt(0);
+
+ if (message_name == "ShowOpenDialog") {
+ // Parameters:
+ // 0: int32 - callback id
+ // 1: bool - allowMultipleSelection
+ // 2: bool - chooseDirectory
+ // 3: string - title
+ // 4: string - initialPath
+ // 5: string - fileTypes (space-delimited string)
+ if (argList->GetSize() != 6 ||
+ argList->GetType(1) != VTYPE_BOOL ||
+ argList->GetType(2) != VTYPE_BOOL ||
+ argList->GetType(3) != VTYPE_STRING ||
+ argList->GetType(4) != VTYPE_STRING ||
+ argList->GetType(5) != VTYPE_STRING) {
+ error = ERR_INVALID_PARAMS;
+ }
+
+ CefRefPtr selectedFiles = CefListValue::Create();
+
+ if (error == NO_ERROR) {
+ bool allowMultipleSelection = argList->GetBool(1);
+ bool chooseDirectory = argList->GetBool(2);
+ ExtensionString title = argList->GetString(3);
+ ExtensionString initialPath = argList->GetString(4);
+ ExtensionString fileTypes = argList->GetString(5);
+
+ error = ShowOpenDialog(allowMultipleSelection,
+ chooseDirectory,
+ title,
+ initialPath,
+ fileTypes,
+ selectedFiles);
+ }
+
+ // Set response args for this function
+ responseArgs->SetList(2, selectedFiles);
+ } else if (message_name == "ReadDir") {
+ // Parameters:
+ // 0: int32 - callback id
+ // 1: string - directory path
+ if (argList->GetSize() != 2 ||
+ argList->GetType(1) != VTYPE_STRING) {
+ error = ERR_INVALID_PARAMS;
+ }
+
+ CefRefPtr directoryContents = CefListValue::Create();
+
+ if (error == NO_ERROR) {
+ ExtensionString path = argList->GetString(1);
+
+ error = ReadDir(path, directoryContents);
+ }
+
+ // Set response args for this function
+ responseArgs->SetList(2, directoryContents);
+ } else if (message_name == "GetFileModificationTime") {
+ // Parameters:
+ // 0: int32 - callback id
+ // 1: string - filename
+ if (argList->GetSize() != 2 ||
+ argList->GetType(1) != VTYPE_STRING) {
+ error = ERR_INVALID_PARAMS;
+ }
+
+ if (error == NO_ERROR) {
+ ExtensionString filename = argList->GetString(1);
+ uint32 modtime;
+ bool isDir;
+
+ error = GetFileModificationTime(filename, modtime, isDir);
+
+ // Set response args for this function
+ responseArgs->SetInt(2, modtime);
+ responseArgs->SetBool(3, isDir);
+ }
+ } else if (message_name == "ReadFile") {
+ // Parameters:
+ // 0: int32 - callback id
+ // 1: string - filename
+ // 2: string - encoding
+ if (argList->GetSize() != 3 ||
+ argList->GetType(1) != VTYPE_STRING ||
+ argList->GetType(2) != VTYPE_STRING) {
+ error = ERR_INVALID_PARAMS;
+ }
+
+ if (error == NO_ERROR) {
+ ExtensionString filename = argList->GetString(1);
+ ExtensionString encoding = argList->GetString(2);
+ std::string contents = "";
+
+ error = ReadFile(filename, encoding, contents);
+
+ // Set response args for this function
+ responseArgs->SetString(2, contents);
+ }
+ } else if (message_name == "WriteFile") {
+ // Parameters:
+ // 0: int32 - callback id
+ // 1: string - filename
+ // 2: string - data
+ // 3: string - encoding
+ if (argList->GetSize() != 4 ||
+ argList->GetType(1) != VTYPE_STRING ||
+ argList->GetType(2) != VTYPE_STRING ||
+ argList->GetType(3) != VTYPE_STRING) {
+ error = ERR_INVALID_PARAMS;
+ }
+
+ if (error == NO_ERROR) {
+ ExtensionString filename = argList->GetString(1);
+ std::string contents = argList->GetString(2);
+ ExtensionString encoding = argList->GetString(3);
+
+ error = WriteFile(filename, contents, encoding);
+ // No additional response args for this function
+ }
+ } else if (message_name == "SetPosixPermissions") {
+ // Parameters:
+ // 0: int32 - callback id
+ // 1: string - filename
+ // 2: int - mode
+ if (argList->GetSize() != 3 ||
+ argList->GetType(1) != VTYPE_STRING ||
+ argList->GetType(2) != VTYPE_INT) {
+ error = ERR_INVALID_PARAMS;
+ }
+
+ if (error == NO_ERROR) {
+ ExtensionString filename = argList->GetString(1);
+ int32 mode = argList->GetInt(2);
+
+ error = SetPosixPermissions(filename, mode);
+
+ // No additional response args for this function
+ }
+ } else if (message_name == "DeleteFileOrDirectory") {
+ // Parameters:
+ // 0: int32 - callback id
+ // 1: string - filename
+ if (argList->GetSize() != 2 ||
+ argList->GetType(1) != VTYPE_STRING) {
+ error = ERR_INVALID_PARAMS;
+ }
+
+ if (error == NO_ERROR) {
+ ExtensionString filename = argList->GetString(1);
+
+ error = DeleteFileOrDirectory(filename);
+
+ // No additional response args for this function
+ }
+ } else {
+ fprintf(stderr, "Native function not implemented yet: %s\n", message_name.c_str());
+ return false;
+ }
+
+ // Set common response args (callbackId and error)
+ responseArgs->SetInt(0, callbackId);
+ responseArgs->SetInt(1, error);
+
+ // Send response
+ browser->SendProcessMessage(PID_RENDERER, response);
+
+ return true;
+ }
+
+ IMPLEMENT_REFCOUNTING(ProcessMessageDelegate);
+};
+
+} // namespace
+
+void CreateProcessMessageDelegates(
+ ClientHandler::ProcessMessageDelegateSet& delegates) {
+ delegates.insert(new ProcessMessageDelegate);
+}
+
+void CreateRequestDelegates(ClientHandler::RequestDelegateSet& delegates) {
+// delegates.insert(new RequestDelegate);
+}
+
+} // namespace appshell_extensions
diff --git a/appshell/appshell_extensions.h b/appshell/appshell_extensions.h
new file mode 100644
index 000000000..a94ae2cf7
--- /dev/null
+++ b/appshell/appshell_extensions.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#pragma once
+
+#include "client_app.h"
+#include "client_handler.h"
+
+namespace appshell_extensions {
+
+// Delegate creation. Called from ClientApp and ClientHandler.
+void CreateProcessMessageDelegates(
+ ClientHandler::ProcessMessageDelegateSet& delegates);
+void CreateRequestDelegates(ClientHandler::RequestDelegateSet& delegates);
+} // namespace appshell_extensions
+
+// Extension error codes. These MUST be in sync with the error
+// codes in brackets_extensions.js
+#if !defined(OS_WIN) // NO_ERROR is defined on windows
+static const int NO_ERROR = 0;
+#endif
+static const int ERR_UNKNOWN = 1;
+static const int ERR_INVALID_PARAMS = 2;
+static const int ERR_NOT_FOUND = 3;
+static const int ERR_CANT_READ = 4;
+static const int ERR_UNSUPPORTED_ENCODING = 5;
+static const int ERR_CANT_WRITE = 6;
+static const int ERR_OUT_OF_SPACE = 7;
+static const int ERR_NOT_FILE = 8;
+static const int ERR_NOT_DIRECTORY = 9;
+
+#if defined(OS_WIN)
+typedef std::wstring ExtensionString;
+#else
+typedef std::string ExtensionString;
+#endif
+
+// Native extension code. These are implemented in brackets_extensions_mac.mm
+// and brackets_extensions_win.cpp
+int32 ShowOpenDialog(bool allowMulitpleSelection,
+ bool chooseDirectory,
+ ExtensionString title,
+ ExtensionString initialDirectory,
+ ExtensionString fileTypes,
+ CefRefPtr& selectedFiles);
+
+int32 ReadDir(ExtensionString path, CefRefPtr& directoryContents);
+
+int32 GetFileModificationTime(ExtensionString filename, uint32& modtime, bool& isDir);
+
+int32 ReadFile(ExtensionString filename, ExtensionString encoding, std::string& contents);
+
+int32 WriteFile(ExtensionString filename, std::string contents, ExtensionString encoding);
+
+int32 SetPosixPermissions(ExtensionString filename, int32 mode);
+
+int32 DeleteFileOrDirectory(ExtensionString filename);
+
diff --git a/appshell/appshell_extensions_mac.mm b/appshell/appshell_extensions_mac.mm
new file mode 100644
index 000000000..6c3fa35a0
--- /dev/null
+++ b/appshell/appshell_extensions_mac.mm
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "appshell_extensions.h"
+
+#include
+
+// Forward declarations for functions defined later in this file
+void NSArrayToCefList(NSArray* array, CefRefPtr& list);
+int32 ConvertNSErrorCode(NSError* error, bool isReading);
+
+int32 ShowOpenDialog(bool allowMulitpleSelection,
+ bool chooseDirectory,
+ ExtensionString title,
+ ExtensionString initialDirectory,
+ ExtensionString fileTypes,
+ CefRefPtr& selectedFiles)
+{
+ NSArray* allowedFileTypes = nil;
+ BOOL canChooseDirectories = chooseDirectory;
+ BOOL canChooseFiles = !canChooseDirectories;
+
+ if (fileTypes != "")
+ {
+ // fileTypes is a Space-delimited string
+ allowedFileTypes =
+ [[NSString stringWithUTF8String:fileTypes.c_str()]
+ componentsSeparatedByString:@" "];
+ }
+
+ // Initialize the dialog
+ NSOpenPanel* openPanel = [NSOpenPanel openPanel];
+ [openPanel setCanChooseFiles:canChooseFiles];
+ [openPanel setCanChooseDirectories:canChooseDirectories];
+ [openPanel setCanCreateDirectories:canChooseDirectories];
+ [openPanel setAllowsMultipleSelection:allowMulitpleSelection];
+ [openPanel setTitle: [NSString stringWithUTF8String:title.c_str()]];
+
+ if (initialDirectory != "")
+ [openPanel setDirectoryURL:[NSURL URLWithString:[NSString stringWithUTF8String:initialDirectory.c_str()]]];
+
+ [openPanel setAllowedFileTypes:allowedFileTypes];
+
+ if ([openPanel runModal] == NSOKButton)
+ {
+ NSArray* files = [openPanel filenames];
+ NSArrayToCefList(files, selectedFiles);
+ }
+
+ return NO_ERROR;
+}
+
+int32 ReadDir(ExtensionString path, CefRefPtr& directoryContents)
+{
+ NSString* pathStr = [NSString stringWithUTF8String:path.c_str()];
+ NSError* error = nil;
+
+ NSArray* contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:pathStr error:&error];
+
+ if (contents != nil)
+ {
+ NSArrayToCefList(contents, directoryContents);
+ return NO_ERROR;
+ }
+
+ return ConvertNSErrorCode(error, true);
+}
+
+int32 GetFileModificationTime(ExtensionString filename, uint32& modtime, bool& isDir)
+{
+ NSString* path = [NSString stringWithUTF8String:filename.c_str()];
+ BOOL isDirectory;
+
+ if ([[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectory]) {
+ isDir = isDirectory;
+ } else {
+ return ERR_NOT_FOUND;
+ }
+
+ NSError* error = nil;
+ NSDictionary* fileAttribs = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:&error];
+ NSDate *modDate = [fileAttribs valueForKey:NSFileModificationDate];
+ modtime = [modDate timeIntervalSince1970];
+
+ return ConvertNSErrorCode(error, true);
+}
+
+int32 ReadFile(ExtensionString filename, ExtensionString encoding, std::string& contents)
+{
+ NSString* path = [NSString stringWithUTF8String:filename.c_str()];
+
+ NSStringEncoding enc;
+ NSError* error = nil;
+
+ if (encoding == "utf8")
+ enc = NSUTF8StringEncoding;
+ else
+ return ERR_UNSUPPORTED_ENCODING;
+
+ NSString* fileContents = [NSString stringWithContentsOfFile:path encoding:enc error:&error];
+
+ if (fileContents)
+ {
+ contents = [fileContents UTF8String];
+ return NO_ERROR;
+ }
+
+ return ConvertNSErrorCode(error, true);
+}
+
+int32 WriteFile(ExtensionString filename, std::string contents, ExtensionString encoding)
+{
+ NSString* path = [NSString stringWithUTF8String:filename.c_str()];
+ NSString* contentsStr = [NSString stringWithUTF8String:contents.c_str()];
+ NSStringEncoding enc;
+ NSError* error = nil;
+
+ if (encoding == "utf8")
+ enc = NSUTF8StringEncoding;
+ else
+ return ERR_UNSUPPORTED_ENCODING;
+
+ const NSData* encodedContents = [contentsStr dataUsingEncoding:enc];
+ NSUInteger len = [encodedContents length];
+ NSOutputStream* oStream = [NSOutputStream outputStreamToFileAtPath:path append:NO];
+
+ [oStream open];
+ NSInteger res = [oStream write:(const uint8_t*)[encodedContents bytes] maxLength:len];
+ [oStream close];
+
+ if (res == -1) {
+ error = [oStream streamError];
+ }
+
+ return ConvertNSErrorCode(error, false);
+}
+
+int32 SetPosixPermissions(ExtensionString filename, int32 mode)
+{
+ NSError* error = nil;
+
+ NSString* path = [NSString stringWithUTF8String:filename.c_str()];
+ NSDictionary* attrs = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:mode] forKey:NSFilePosixPermissions];
+
+ if ([[NSFileManager defaultManager] setAttributes:attrs ofItemAtPath:path error:&error])
+ return NO_ERROR;
+
+ return ConvertNSErrorCode(error, false);
+}
+
+int32 DeleteFileOrDirectory(ExtensionString filename)
+{
+ NSError* error = nil;
+
+ NSString* path = [NSString stringWithUTF8String:filename.c_str()];
+ BOOL isDirectory;
+
+ // Contrary to the name of this function, we don't actually delete directories
+ if ([[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectory]) {
+ if (isDirectory) {
+ return ERR_NOT_FILE;
+ }
+ } else {
+ return ERR_NOT_FOUND;
+ }
+
+ if ([[NSFileManager defaultManager] removeItemAtPath:path error:&error])
+ return NO_ERROR;
+
+ return ConvertNSErrorCode(error, false);
+}
+
+void NSArrayToCefList(NSArray* array, CefRefPtr& list)
+{
+ for (NSUInteger i = 0; i < [array count]; i++) {
+ list->SetString(i, [[array objectAtIndex:i] UTF8String]);
+ }
+}
+
+int32 ConvertNSErrorCode(NSError* error, bool isReading)
+{
+ if (!error)
+ return NO_ERROR;
+
+ if( [[error domain] isEqualToString: NSPOSIXErrorDomain] )
+ {
+ switch ([error code])
+ {
+ case ENOENT:
+ return ERR_NOT_FOUND;
+ break;
+ case EPERM:
+ case EACCES:
+ return (isReading ? ERR_CANT_READ : ERR_CANT_WRITE);
+ break;
+ case EROFS:
+ return ERR_CANT_WRITE;
+ break;
+ case ENOSPC:
+ return ERR_OUT_OF_SPACE;
+ break;
+ }
+
+ }
+
+
+ switch ([error code])
+ {
+ case NSFileNoSuchFileError:
+ case NSFileReadNoSuchFileError:
+ return ERR_NOT_FOUND;
+ break;
+ case NSFileReadNoPermissionError:
+ return ERR_CANT_READ;
+ break;
+ case NSFileReadInapplicableStringEncodingError:
+ return ERR_UNSUPPORTED_ENCODING;
+ break;
+ case NSFileWriteNoPermissionError:
+ return ERR_CANT_WRITE;
+ break;
+ case NSFileWriteOutOfSpaceError:
+ return ERR_OUT_OF_SPACE;
+ break;
+ }
+
+ // Unknown error
+ return ERR_UNKNOWN;
+}
+
diff --git a/appshell/appshell_extensions_win.cpp b/appshell/appshell_extensions_win.cpp
new file mode 100644
index 000000000..c1f80a020
--- /dev/null
+++ b/appshell/appshell_extensions_win.cpp
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "appshell_extensions.h"
+
+#include
+#include
+#include
+
+// Forward declarations for functions at the bottom of this file
+void FixFilename(ExtensionString& filename);
+int ConvertErrnoCode(int errorCode, bool isReading = true);
+int ConvertWinErrorCode(int errorCode, bool isReading = true);
+
+static int CALLBACK SetInitialPathCallback(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
+{
+ if (BFFM_INITIALIZED == uMsg && NULL != lpData)
+ {
+ SendMessage(hWnd, BFFM_SETSELECTION, TRUE, lpData);
+ }
+
+ return 0;
+}
+
+int32 ShowOpenDialog(bool allowMulitpleSelection,
+ bool chooseDirectory,
+ ExtensionString title,
+ ExtensionString initialDirectory,
+ ExtensionString fileTypes,
+ CefRefPtr& selectedFiles)
+{
+ wchar_t szFile[MAX_PATH];
+ szFile[0] = 0;
+
+ FixFilename(initialDirectory);
+
+ // TODO (issue #64) - This method should be using IFileDialog instead of the
+ /* outdated SHGetPathFromIDList and GetOpenFileName.
+
+ Useful function to parse fileTypesStr:
+ template
+ int inline findAndReplaceString(T& source, const T& find, const T& replace)
+ {
+ int num=0;
+ int fLen = find.size();
+ int rLen = replace.size();
+ for (int pos=0; (pos=source.find(find, pos))!=T::npos; pos+=rLen)
+ {
+ num++;
+ source.replace(pos, fLen, replace);
+ }
+ return num;
+ }
+ */
+
+ if (chooseDirectory) {
+ BROWSEINFO bi = {0};
+ bi.hwndOwner = GetActiveWindow();
+ bi.lpszTitle = title.c_str();
+ bi.ulFlags = BIF_NEWDIALOGSTYLE;
+ bi.lpfn = SetInitialPathCallback;
+ bi.lParam = (LPARAM)initialDirectory.c_str();
+
+ LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
+ if (pidl != 0) {
+ if (SHGetPathFromIDList(pidl, szFile)) {
+ // Add directory path to the result
+ selectedFiles->SetString(0, szFile);
+ }
+ IMalloc* pMalloc = NULL;
+ SHGetMalloc(&pMalloc);
+ if (pMalloc) {
+ pMalloc->Free(pidl);
+ pMalloc->Release();
+ }
+ }
+ } else {
+ OPENFILENAME ofn;
+
+ ZeroMemory(&ofn, sizeof(ofn));
+ ofn.hwndOwner = GetActiveWindow();
+ ofn.lStructSize = sizeof(ofn);
+ ofn.lpstrFile = szFile;
+ ofn.nMaxFile = MAX_PATH;
+
+ allowMulitpleSelection = false; // TODO: Raymond, please implement.
+
+ // TODO (issue #65) - Use passed in file types. Note, when fileTypesStr is null, all files should be shown
+ /* findAndReplaceString( fileTypesStr, std::string(" "), std::string(";*."));
+ LPCWSTR allFilesFilter = L"All Files\0*.*\0\0";*/
+
+ ofn.lpstrFilter = L"All Files\0*.*\0Web Files\0*.js;*.css;*.htm;*.html\0\0";
+
+ ofn.lpstrInitialDir = initialDirectory.c_str();
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | OFN_EXPLORER;
+ if (allowMulitpleSelection)
+ ofn.Flags |= OFN_ALLOWMULTISELECT;
+
+ if (GetOpenFileName(&ofn)) {
+ if (allowMulitpleSelection) {
+ // Multiple selection encodes the files differently
+/*
+ // If multiple files are selected, the first null terminator
+ // signals end of directory that the files are all in
+ std::wstring dir(szFile);
+
+ // Check for two null terminators, which signal that only one file
+ // was selected
+ if (szFile[dir.length() + 1] == '\0') {
+ // Escape the single file path and add it to the JSON array
+ std::wstring escaped;
+ EscapeJSONString(dir, escaped);
+ results += L"\"" + escaped + L"\"";
+ } else {
+ // Multiple files are selected
+ wchar_t fullPath[MAX_PATH];
+ bool firstFile = true;
+ for (int i = dir.length() + 1;;) {
+ // Get the next file name
+ std::wstring file(&szFile[i]);
+
+ // Two adjacent null characters signal the end of the files
+ if (file.length() == 0)
+ break;
+
+ // The filename is relative to the directory that was specified as
+ // the first string
+ if (PathCombine(fullPath, dir.c_str(), file.c_str()) != NULL)
+ {
+ // Append a comma separator if it is not the first file in the list
+ if (firstFile)
+ firstFile = false;
+ else
+ results += L",";
+
+ // Escape the path and add it to the list
+ std::wstring escaped;
+ EscapeJSONString(std::wstring(fullPath), escaped);
+ results += L"\"" + escaped + L"\"";
+ }
+
+ // Go to the start of the next file name
+ i += file.length() + 1;
+ }
+ }
+*/
+ } else {
+ // If multiple files are not allowed, add the single file
+ selectedFiles->SetString(0, szFile);
+ }
+ }
+ }
+
+ return NO_ERROR;
+}
+
+int32 ReadDir(ExtensionString path, CefRefPtr& directoryContents)
+{
+ FixFilename(path);
+
+ path += L"\\*";
+
+ WIN32_FIND_DATA ffd;
+ HANDLE hFind = FindFirstFile(path.c_str(), &ffd);
+
+ std::vector resultFiles;
+ std::vector resultDirs;
+
+ if (hFind != INVALID_HANDLE_VALUE) {
+ do {
+ // Ignore '.' and '..'
+ if (!wcscmp(ffd.cFileName, L".") || !wcscmp(ffd.cFileName, L".."))
+ continue;
+
+ // Collect file and directory names separately
+ if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ resultDirs.push_back(ExtensionString(ffd.cFileName));
+ } else {
+ resultFiles.push_back(ExtensionString(ffd.cFileName));
+ }
+ }
+ while (FindNextFile(hFind, &ffd) != 0);
+
+ FindClose(hFind);
+ }
+ else {
+ return ConvertWinErrorCode(GetLastError());
+ }
+
+ // On Windows, list directories first, then files
+ size_t i, total = 0;
+ for (i = 0; i < resultDirs.size(); i++)
+ directoryContents->SetString(total++, resultDirs[i]);
+ for (i = 0; i < resultFiles.size(); i++)
+ directoryContents->SetString(total++, resultFiles[i]);
+
+ return NO_ERROR;
+}
+
+int32 GetFileModificationTime(ExtensionString filename, uint32& modtime, bool& isDir)
+{
+ FixFilename(filename);
+
+ DWORD dwAttr = GetFileAttributes(filename.c_str());
+
+ if (dwAttr == INVALID_FILE_ATTRIBUTES) {
+ return ConvertWinErrorCode(GetLastError());
+ }
+
+ isDir = ((dwAttr & FILE_ATTRIBUTE_DIRECTORY) != 0);
+
+ struct _stat buffer;
+ if(_wstat(filename.c_str(), &buffer) == -1) {
+ return ConvertErrnoCode(errno);
+ }
+
+ modtime = buffer.st_mtime;
+
+ return NO_ERROR;
+}
+
+int32 ReadFile(ExtensionString filename, ExtensionString encoding, std::string& contents)
+{
+ FixFilename(filename);
+
+ if (encoding != L"utf8")
+ return ERR_UNSUPPORTED_ENCODING;
+
+ DWORD dwAttr;
+ dwAttr = GetFileAttributes(filename.c_str());
+ if (INVALID_FILE_ATTRIBUTES == dwAttr)
+ return ConvertWinErrorCode(GetLastError());
+
+ if (dwAttr & FILE_ATTRIBUTE_DIRECTORY)
+ return ERR_CANT_READ;
+
+ HANDLE hFile = CreateFile(filename.c_str(), GENERIC_READ,
+ 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ int32 error = NO_ERROR;
+
+ if (INVALID_HANDLE_VALUE == hFile)
+ return ConvertWinErrorCode(GetLastError());
+
+ DWORD dwFileSize = GetFileSize(hFile, NULL);
+ DWORD dwBytesRead;
+ char* buffer = (char*)malloc(dwFileSize);
+ if (buffer && ReadFile(hFile, buffer, dwFileSize, &dwBytesRead, NULL)) {
+ contents = std::string(buffer, dwFileSize);
+ }
+ else {
+ if (!buffer)
+ error = ERR_UNKNOWN;
+ else
+ error = ConvertWinErrorCode(GetLastError());
+ }
+ CloseHandle(hFile);
+ if (buffer)
+ free(buffer);
+
+ return error;
+}
+
+int32 WriteFile(ExtensionString filename, std::string contents, ExtensionString encoding)
+{
+ FixFilename(filename);
+
+ if (encoding != L"utf8")
+ return ERR_UNSUPPORTED_ENCODING;
+
+ HANDLE hFile = CreateFile(filename.c_str(), GENERIC_WRITE,
+ 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ DWORD dwBytesWritten;
+ int error = NO_ERROR;
+
+ if (INVALID_HANDLE_VALUE == hFile)
+ return ConvertWinErrorCode(GetLastError(), false);
+
+ // TODO (issue 67) - Should write to temp file and handle encoding
+ if (!WriteFile(hFile, contents.c_str(), contents.length(), &dwBytesWritten, NULL)) {
+ error = ConvertWinErrorCode(GetLastError(), false);
+ }
+
+ CloseHandle(hFile);
+ return error;
+}
+
+int32 SetPosixPermissions(ExtensionString filename, int32 mode)
+{
+ // TODO: Raymond, please implement
+ return NO_ERROR;
+}
+
+int32 DeleteFileOrDirectory(ExtensionString filename)
+{
+ // TODO: Raymond, please implement
+ return NO_ERROR;
+}
+
+void FixFilename(ExtensionString& filename)
+{
+ // Convert '/' to '\'
+ replace(filename.begin(), filename.end(), '/', '\\');
+}
+
+// Maps errors from errno.h to the brackets error codes
+// found in brackets_extensions.js
+int ConvertErrnoCode(int errorCode, bool isReading)
+{
+ switch (errorCode) {
+ case NO_ERROR:
+ return NO_ERROR;
+ case EINVAL:
+ return ERR_INVALID_PARAMS;
+ case ENOENT:
+ return ERR_NOT_FOUND;
+ default:
+ return ERR_UNKNOWN;
+ }
+}
+
+// Maps errors from WinError.h to the brackets error codes
+// found in brackets_extensions.js
+int ConvertWinErrorCode(int errorCode, bool isReading)
+{
+ switch (errorCode) {
+ case NO_ERROR:
+ return NO_ERROR;
+ case ERROR_PATH_NOT_FOUND:
+ case ERROR_FILE_NOT_FOUND:
+ return ERR_NOT_FOUND;
+ case ERROR_ACCESS_DENIED:
+ return isReading ? ERR_CANT_READ : ERR_CANT_WRITE;
+ case ERROR_WRITE_PROTECT:
+ return ERR_CANT_WRITE;
+ case ERROR_HANDLE_DISK_FULL:
+ return ERR_OUT_OF_SPACE;
+ default:
+ return ERR_UNKNOWN;
+ }
+}
+
diff --git a/appshell/brackets_extensions.js b/appshell/brackets_extensions.js
new file mode 100644
index 000000000..f35263e83
--- /dev/null
+++ b/appshell/brackets_extensions.js
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+// This is the JavaScript code for bridging to native functionality
+// See brackets_extentions.mm for implementation of native methods.
+//
+// Note: All file native file i/o functions are synchronous, but are exposed
+// here as asynchronous calls.
+
+/*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, indent: 4, forin: true, maxerr: 50, regexp: true */
+/*global define, native */
+
+var brackets;
+if (!brackets) {
+ brackets = {};
+}
+if (!brackets.fs) {
+ brackets.fs = {};
+}
+if (!brackets.app) {
+ brackets.app = {};
+}
+(function () {
+ // Error values. These MUST be in sync with the error values
+ // at the top of brackets_extensions.h.
+
+ /**
+ * @constant No error.
+ */
+ brackets.fs.NO_ERROR = 0;
+
+ /**
+ * @constant Unknown error occurred.
+ */
+ brackets.fs.ERR_UNKNOWN = 1;
+
+ /**
+ * @constant Invalid parameters passed to function.
+ */
+ brackets.fs.ERR_INVALID_PARAMS = 2;
+
+ /**
+ * @constant File or directory was not found.
+ */
+ brackets.fs.ERR_NOT_FOUND = 3;
+
+ /**
+ * @constant File or directory could not be read.
+ */
+ brackets.fs.ERR_CANT_READ = 4;
+
+ /**
+ * @constant An unsupported encoding value was specified.
+ */
+ brackets.fs.ERR_UNSUPPORTED_ENCODING = 5;
+
+ /**
+ * @constant File could not be written.
+ */
+ brackets.fs.ERR_CANT_WRITE = 6;
+
+ /**
+ * @constant Target directory is out of space. File could not be written.
+ */
+ brackets.fs.ERR_OUT_OF_SPACE = 7;
+
+ /**
+ * @constant Specified path does not point to a file.
+ */
+ brackets.fs.ERR_NOT_FILE = 8;
+
+ /**
+ * @constant Specified path does not point to a directory.
+ */
+ brackets.fs.ERR_NOT_DIRECTORY = 9;
+
+ /**
+ * Display the OS File Open dialog, allowing the user to select
+ * files or directories.
+ *
+ * @param {boolean} allowMultipleSelection If true, multiple files/directories can be selected.
+ * @param {boolean} chooseDirectory If true, only directories can be selected. If false, only
+ * files can be selected.
+ * @param {string} title Tile of the open dialog.
+ * @param {string} initialPath Initial path to display in the dialog. Pass NULL or "" to
+ * display the last path chosen.
+ * @param {Array.} fileTypes Array of strings specifying the selectable file extensions.
+ * These strings should not contain '.'. This parameter is ignored when
+ * chooseDirectory=true.
+ * @param {function(err, selection)} callback Asynchronous callback function. The callback gets two arguments
+ * (err, selection) where selection is an array of the names of the selected files.
+ * Possible error values:
+ * NO_ERROR
+ * ERR_INVALID_PARAMS
+ *
+ * @return None. This is an asynchronous call that sends all return information to the callback.
+ */
+ native function ShowOpenDialog();
+ brackets.fs.showOpenDialog = function (allowMultipleSelection, chooseDirectory, title, initialPath, fileTypes, callback) {
+ setTimeout(function () {
+ ShowOpenDialog(callback, allowMultipleSelection, chooseDirectory,
+ title || 'Open', initialPath || '',
+ fileTypes ? fileTypes.join(' ') : '');
+ }, 10);
+ };
+
+ /**
+ * Reads the contents of a directory.
+ *
+ * @param {string} path The path of the directory to read.
+ * @param {function(err, files)} callback Asynchronous callback function. The callback gets two arguments
+ * (err, files) where files is an array of the names of the files
+ * in the directory excluding '.' and '..'.
+ * Possible error values:
+ * NO_ERROR
+ * ERR_UNKNOWN
+ * ERR_INVALID_PARAMS
+ * ERR_NOT_FOUND
+ * ERR_CANT_READ
+ *
+ * @return None. This is an asynchronous call that sends all return information to the callback.
+ */
+ native function ReadDir();
+ brackets.fs.readdir = function (path, callback) {
+ var resultString = ReadDir(callback, path);
+ };
+
+ /**
+ * Get information for the selected file or directory.
+ *
+ * @param {string} path The path of the file or directory to read.
+ * @param {function(err, stats)} callback Asynchronous callback function. The callback gets two arguments
+ * (err, stats) where stats is an object with isFile() and isDirectory() functions.
+ * Possible error values:
+ * NO_ERROR
+ * ERR_UNKNOWN
+ * ERR_INVALID_PARAMS
+ * ERR_NOT_FOUND
+ *
+ * @return None. This is an asynchronous call that sends all return information to the callback.
+ */
+ native function GetFileModificationTime();
+ brackets.fs.stat = function (path, callback) {
+ GetFileModificationTime(function (err, modtime, isDir) {
+ callback(err, {
+ isFile: function () {
+ return !isDir;
+ },
+ isDirectory: function () {
+ return isDir;
+ },
+ mtime: new Date(modtime * 1000) // modtime is seconds since 1970, convert to ms
+ });
+ }, path);
+ };
+
+ /**
+ * Quits native shell application
+ */
+ native function QuitApplication();
+ brackets.app.quit = function () {
+ QuitApplication();
+ };
+
+ /**
+ * Invokes developer tools application
+ */
+ native function ShowDeveloperTools();
+ brackets.app.showDeveloperTools = function () {
+ ShowDeveloperTools();
+ };
+
+ /**
+ * Reads the entire contents of a file.
+ *
+ * @param {string} path The path of the file to read.
+ * @param {string} encoding The encoding for the file. The only supported encoding is 'utf8'.
+ * @param {function(err, data)} callback Asynchronous callback function. The callback gets two arguments
+ * (err, data) where data is the contents of the file.
+ * Possible error values:
+ * NO_ERROR
+ * ERR_UNKNOWN
+ * ERR_INVALID_PARAMS
+ * ERR_NOT_FOUND
+ * ERR_CANT_READ
+ * ERR_UNSUPPORTED_ENCODING
+ *
+ * @return None. This is an asynchronous call that sends all return information to the callback.
+ */
+ native function ReadFile();
+ brackets.fs.readFile = function (path, encoding, callback) {
+ ReadFile(callback, path, encoding);
+ };
+
+ /**
+ * Write data to a file, replacing the file if it already exists.
+ *
+ * @param {string} path The path of the file to write.
+ * @param {string} data The data to write to the file.
+ * @param {string} encoding The encoding for the file. The only supported encoding is 'utf8'.
+ * @param {function(err)} callback Asynchronous callback function. The callback gets one argument (err).
+ * Possible error values:
+ * NO_ERROR
+ * ERR_UNKNOWN
+ * ERR_INVALID_PARAMS
+ * ERR_UNSUPPORTED_ENCODING
+ * ERR_CANT_WRITE
+ * ERR_OUT_OF_SPACE
+ *
+ * @return None. This is an asynchronous call that sends all return information to the callback.
+ */
+ native function WriteFile();
+ brackets.fs.writeFile = function (path, data, encoding, callback) {
+ WriteFile(callback, path, data, encoding);
+ };
+
+ /**
+ * Set permissions for a file or directory.
+ *
+ * @param {string} path The path of the file or directory
+ * @param {number} mode The permissions for the file or directory, in numeric format (ie 0777)
+ * @param {function(err)} callback Asynchronous callback function. The callback gets one argument (err).
+ * Possible error values:
+ * NO_ERROR
+ * ERR_UNKNOWN
+ * ERR_INVALID_PARAMS
+ * ERR_CANT_WRITE
+ *
+ * @return None. This is an asynchronous call that sends all return information to the callback.
+ */
+ native function SetPosixPermissions();
+ brackets.fs.chmod = function (path, mode, callback) {
+ SetPosixPermissions(callback, path, mode);
+ };
+
+ /**
+ * Delete a file.
+ *
+ * @param {string} path The path of the file to delete
+ * @param {function(err)} callback Asynchronous callback function. The callback gets one argument (err).
+ * Possible error values:
+ * NO_ERROR
+ * ERR_UNKNOWN
+ * ERR_INVALID_PARAMS
+ * ERR_NOT_FOUND
+ * ERR_NOT_FILE
+ *
+ * @return None. This is an asynchronous call that sends all return information to the callback.
+ */
+ native function DeleteFileOrDirectory();
+ brackets.fs.unlink = function (path, callback) {
+ DeleteFileOrDirectory(callback, path);
+ };
+
+ /**
+ * Return the number of milliseconds that have elapsed since the application
+ * was launched.
+ */
+ native function GetElapsedMilliseconds();
+ brackets.app.getElapsedMilliseconds = function () {
+ return GetElapsedMilliseconds();
+ }
+
+ /**
+ * Open the live browser
+ *
+ * @param {string} url
+ * @param {boolean} enableRemoteDebugging
+ * @param {function(err)} callback Asynchronous callback function with one argument (the error)
+ * Possible error values:
+ * NO_ERROR
+ * ERR_INVALID_PARAMS - invalid parameters
+ * ERR_UNKNOWN - unable to launch the browser
+ * ERR_NOT_FOUND - unable to find a browers to launch
+ *
+ * @return None. This is an asynchronous call that sends all return information to the callback.
+ */
+ native function OpenLiveBrowser();
+ brackets.app.openLiveBrowser = function (url, enableRemoteDebugging, callback) {
+ /*
+ // enableRemoteDebugging flag is ignored on mac
+ setTimeout(function() {
+ OpenLiveBrowser(url);
+ callback(getLastError());
+ }, 0);
+ */
+ };
+
+ /**
+ * Attempts to close the live browser. The browser can still give the user a chance to override
+ * the close attempt if there is a page with unsaved changes. This function will fire the
+ * callback when the browser is closed (No_ERROR) or after a three minute timeout (ERR_UNKNOWN).
+ *
+ * @param {function(err)} callback Asynchronous callback function with one argument (the error)
+ * Possible error values:
+ * NO_ERROR (all windows are closed by the time the callback is fired)
+ * ERR_UNKNOWN - windows are currently open, though the user may be getting prompted by the
+ * browser to close them
+ *
+ * @return None. This is an asynchronous call that sends all return information to the callback.
+ */
+ native function CloseLiveBrowser();
+ brackets.app.closeLiveBrowser = function (callback) {
+ /*
+ CloseLiveBrowser(callback);
+ */
+ };
+})();
diff --git a/appshell/cefclient.cpp b/appshell/cefclient.cpp
index b6a8283c1..50516eb79 100644
--- a/appshell/cefclient.cpp
+++ b/appshell/cefclient.cpp
@@ -2,7 +2,7 @@
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
-#include "cefclient/cefclient.h"
+#include "cefclient.h"
#include
#include
#include
@@ -13,10 +13,10 @@
#include "include/cef_frame.h"
#include "include/cef_runnable.h"
#include "include/cef_web_plugin.h"
-#include "cefclient/client_handler.h"
-#include "cefclient/client_switches.h"
-#include "cefclient/string_util.h"
-#include "cefclient/util.h"
+#include "client_handler.h"
+#include "client_switches.h"
+#include "string_util.h"
+#include "util.h"
namespace {
diff --git a/appshell/cefclient.h b/appshell/cefclient.h
index 3b38f0b73..73aa203a3 100644
--- a/appshell/cefclient.h
+++ b/appshell/cefclient.h
@@ -8,7 +8,7 @@
#include
#include "include/cef_base.h"
-#include "cefclient/client_app.h"
+#include "client_app.h"
class CefApp;
class CefBrowser;
diff --git a/appshell/cefclient.rc b/appshell/cefclient.rc
index 29ea626ae..b42a700d3 100644
--- a/appshell/cefclient.rc
+++ b/appshell/cefclient.rc
@@ -28,6 +28,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
// Binary
//
+IDS_BRACKETS_EXTENSIONS BINARY "brackets_extensions.js"
+
/////////////////////////////////////////////////////////////////////////////
//
// Icon
diff --git a/appshell/cefclient_mac.mm b/appshell/cefclient_mac.mm
index cbae9fb75..2eec4acb2 100644
--- a/appshell/cefclient_mac.mm
+++ b/appshell/cefclient_mac.mm
@@ -6,15 +6,18 @@
#include "config.h"
#import
#include
-#include "cefclient/cefclient.h"
+#include "cefclient.h"
#include "include/cef_app.h"
#import "include/cef_application_mac.h"
#include "include/cef_browser.h"
#include "include/cef_frame.h"
#include "include/cef_runnable.h"
-#include "cefclient/client_handler.h"
-#include "cefclient/resource_util.h"
-#include "cefclient/string_util.h"
+#include "client_handler.h"
+#include "resource_util.h"
+#include "string_util.h"
+
+// Application startup time
+CFTimeInterval g_appStartupTime;
// The global ClientHandler reference.
extern CefRefPtr g_handler;
@@ -292,6 +295,9 @@ - (void)createApp:(id)object {
// Populate the settings based on command line arguments.
AppGetBrowserSettings(settings);
+ settings.file_access_from_file_urls_allowed = true;
+ settings.universal_access_from_file_urls_allowed = true;
+
window_info.SetAsChild(contentView, 0, 0, kWindowWidth, kWindowHeight);
CefBrowserHost::CreateBrowser(window_info, g_handler.get(),
"http://www.google.com", settings);
@@ -329,6 +335,9 @@ - (void)applicationWillTerminate:(NSNotification *)aNotification {
int main(int argc, char* argv[]) {
CefMainArgs main_args(argc, argv);
+
+ g_appStartupTime = CFAbsoluteTimeGetCurrent();
+
CefRefPtr app(new ClientApp);
// Execute the secondary process, if any.
diff --git a/appshell/cefclient_win.cpp b/appshell/cefclient_win.cpp
index 196be71ac..2a77217cb 100644
--- a/appshell/cefclient_win.cpp
+++ b/appshell/cefclient_win.cpp
@@ -3,7 +3,7 @@
// can be found in the LICENSE file.
#include "config.h"
-#include "cefclient/cefclient.h"
+#include "cefclient.h"
#include
#include
#include
@@ -14,9 +14,9 @@
#include "include/cef_browser.h"
#include "include/cef_frame.h"
#include "include/cef_runnable.h"
-#include "cefclient/client_handler.h"
-#include "cefclient/resource.h"
-#include "cefclient/string_util.h"
+#include "client_handler.h"
+#include "resource.h"
+#include "string_util.h"
#define MAX_LOADSTRING 100
@@ -289,6 +289,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
// Populate the settings based on command line arguments.
AppGetBrowserSettings(settings);
+ settings.file_access_from_file_urls_allowed = true;
+ settings.universal_access_from_file_urls_allowed = true;
+
// Initialize window info to the defaults for a child window
info.SetAsChild(hWnd, rect);
diff --git a/appshell/client_app.cpp b/appshell/client_app.cpp
index 2a8829a6e..57578d6fe 100644
--- a/appshell/client_app.cpp
+++ b/appshell/client_app.cpp
@@ -52,6 +52,37 @@ void SetList(CefRefPtr source, CefRefPtr target) {
SetListValue(target, i, source->GetValue(i));
}
+CefRefPtr ListValueToV8Value(CefRefPtr value, int index)
+{
+ CefRefPtr new_value;
+
+ CefValueType type = value->GetType(index);
+ switch (type) {
+ case VTYPE_LIST: {
+ CefRefPtr list = value->GetList(index);
+ new_value = CefV8Value::CreateArray(list->GetSize());
+ SetList(list, new_value);
+ } break;
+ case VTYPE_BOOL:
+ new_value = CefV8Value::CreateBool(value->GetBool(index));
+ break;
+ case VTYPE_DOUBLE:
+ new_value = CefV8Value::CreateDouble(value->GetDouble(index));
+ break;
+ case VTYPE_INT:
+ new_value = CefV8Value::CreateInt(value->GetInt(index));
+ break;
+ case VTYPE_STRING:
+ new_value = CefV8Value::CreateString(value->GetString(index));
+ break;
+ default:
+ new_value = CefV8Value::CreateNull();
+ break;
+ }
+
+ return new_value;
+}
+
// Transfer a List value to a V8 array index.
void SetListValue(CefRefPtr list, int index,
CefRefPtr value) {
@@ -100,11 +131,12 @@ void SetList(CefRefPtr source, CefRefPtr target) {
}
-// Handles the native implementation for the client_app extension.
-class ClientAppExtensionHandler : public CefV8Handler {
+// Handles the native implementation for the appshell extension.
+class AppShellExtensionHandler : public CefV8Handler {
public:
- explicit ClientAppExtensionHandler(CefRefPtr client_app)
- : client_app_(client_app) {
+ explicit AppShellExtensionHandler(CefRefPtr client_app)
+ : client_app_(client_app)
+ , messageId(0) {
}
virtual bool Execute(const CefString& name,
@@ -112,62 +144,47 @@ class ClientAppExtensionHandler : public CefV8Handler {
const CefV8ValueList& arguments,
CefRefPtr& retval,
CefString& exception) {
- bool handled = false;
-
- if (name == "sendMessage") {
- // Send a message to the browser process.
- if ((arguments.size() == 1 || arguments.size() == 2) &&
- arguments[0]->IsString()) {
- CefRefPtr browser =
- CefV8Context::GetCurrentContext()->GetBrowser();
- ASSERT(browser.get());
-
- CefString name = arguments[0]->GetStringValue();
- if (!name.empty()) {
- CefRefPtr message =
- CefProcessMessage::Create(name);
-
- // Translate the arguments, if any.
- if (arguments.size() == 2 && arguments[1]->IsArray())
- SetList(arguments[1], message->GetArgumentList());
+ // The only message that is handled here is getElapsedMilliseconds(). All other
+ // messages are passed to the browser process.
+ if (name == "GetElapsedMilliseconds") {
+ retval = CefV8Value::CreateDouble(client_app_->GetElapsedMilliseconds());
+ } else {
+ // Pass all messages to the browser process. Look in appshell_extensions.cpp for implementation.
+ CefRefPtr browser =
+ CefV8Context::GetCurrentContext()->GetBrowser();
+ ASSERT(browser.get());
+ CefRefPtr message =
+ CefProcessMessage::Create(name);
+ CefRefPtr messageArgs = message->GetArgumentList();
+
+ // The first argument must be a callback function
+ if (arguments.size() < 1 || !arguments[0]->IsFunction()) {
+ std::string functionName = name;
+ fprintf(stderr, "Function called without callback param: %s\n", functionName.c_str());
+ return false;
+ }
+
+ // The first argument is the message id
+ client_app_->AddCallback(messageId, CefV8Context::GetCurrentContext(), arguments[0]);
+ SetListValue(messageArgs, 0, CefV8Value::CreateInt(messageId));
+
+ // Pass the rest of the arguments
+ for (unsigned int i = 1; i < arguments.size(); i++)
+ SetListValue(messageArgs, i, arguments[i]);
browser->SendProcessMessage(PID_BROWSER, message);
- handled = true;
- }
- }
- } else if (name == "setMessageCallback") {
- // Set a message callback.
- if (arguments.size() == 2 && arguments[0]->IsString() &&
- arguments[1]->IsFunction()) {
- std::string name = arguments[0]->GetStringValue();
- CefRefPtr context = CefV8Context::GetCurrentContext();
- int browser_id = context->GetBrowser()->GetIdentifier();
- client_app_->SetMessageCallback(name, browser_id, context,
- arguments[1]);
- handled = true;
- }
- } else if (name == "removeMessageCallback") {
- // Remove a message callback.
- if (arguments.size() == 1 && arguments[0]->IsString()) {
- std::string name = arguments[0]->GetStringValue();
- CefRefPtr context = CefV8Context::GetCurrentContext();
- int browser_id = context->GetBrowser()->GetIdentifier();
- bool removed = client_app_->RemoveMessageCallback(name, browser_id);
- retval = CefV8Value::CreateBool(removed);
- handled = true;
+
+ messageId++;
}
- }
-
- if (!handled)
- exception = "Invalid method arguments";
-
- return true;
+
+ return true;
}
private:
- CefRefPtr client_app_;
-
- IMPLEMENT_REFCOUNTING(ClientAppExtensionHandler);
+ CefRefPtr client_app_;
+ int32 messageId;
+
+ IMPLEMENT_REFCOUNTING(AppShellExtensionHandler);
};
} // namespace
@@ -178,31 +195,6 @@ ClientApp::ClientApp()
CreateRenderDelegates(render_delegates_);
}
-void ClientApp::SetMessageCallback(const std::string& message_name,
- int browser_id,
- CefRefPtr context,
- CefRefPtr function) {
- ASSERT(CefCurrentlyOn(TID_RENDERER));
-
- callback_map_.insert(
- std::make_pair(std::make_pair(message_name, browser_id),
- std::make_pair(context, function)));
-}
-
-bool ClientApp::RemoveMessageCallback(const std::string& message_name,
- int browser_id) {
- ASSERT(CefCurrentlyOn(TID_RENDERER));
-
- CallbackMap::iterator it =
- callback_map_.find(std::make_pair(message_name, browser_id));
- if (it != callback_map_.end()) {
- callback_map_.erase(it);
- return true;
- }
-
- return false;
-}
-
void ClientApp::GetProxyForUrl(const CefString& url,
CefProxyInfo& proxy_info) {
proxy_info.proxyType = proxy_type_;
@@ -211,27 +203,11 @@ void ClientApp::GetProxyForUrl(const CefString& url,
}
void ClientApp::OnWebKitInitialized() {
- // Register the client_app extension.
- std::string app_code =
- "var app;"
- "if (!app)"
- " app = {};"
- "(function() {"
- " app.sendMessage = function(name, arguments) {"
- " native function sendMessage();"
- " return sendMessage(name, arguments);"
- " };"
- " app.setMessageCallback = function(name, callback) {"
- " native function setMessageCallback();"
- " return setMessageCallback(name, callback);"
- " };"
- " app.removeMessageCallback = function(name) {"
- " native function removeMessageCallback();"
- " return removeMessageCallback(name);"
- " };"
- "})();";
- CefRegisterExtension("v8/app", app_code,
- new ClientAppExtensionHandler(this));
+ // Register the appshell extension.
+ std::string extension_code = GetExtensionJSSource();
+
+ CefRegisterExtension("appshell", extension_code,
+ new AppShellExtensionHandler(this));
// Execute delegate callbacks.
RenderDelegateSet::iterator it = render_delegates_.begin();
@@ -255,71 +231,42 @@ void ClientApp::OnContextReleased(CefRefPtr browser,
RenderDelegateSet::iterator it = render_delegates_.begin();
for (; it != render_delegates_.end(); ++it)
(*it)->OnContextReleased(this, browser, frame, context);
-
- // Remove any JavaScript callbacks registered for the context that has been
- // released.
- if (!callback_map_.empty()) {
- CallbackMap::iterator it = callback_map_.begin();
- for (; it != callback_map_.end();) {
- if (it->second.first->IsSame(context))
- callback_map_.erase(it++);
- else
- ++it;
- }
- }
}
bool ClientApp::OnProcessMessageRecieved(
- CefRefPtr browser,
- CefProcessId source_process,
- CefRefPtr message) {
- ASSERT(source_process == PID_BROWSER);
+ CefRefPtr browser,
+ CefProcessId source_process,
+ CefRefPtr message) {
+ ASSERT(source_process == PID_BROWSER);
- bool handled = false;
-
- // Execute delegate callbacks.
- RenderDelegateSet::iterator it = render_delegates_.begin();
- for (; it != render_delegates_.end() && !handled; ++it) {
- handled = (*it)->OnProcessMessageRecieved(this, browser, source_process,
- message);
- }
-
- if (handled)
- return true;
-
- // Execute the registered JavaScript callback if any.
- if (!callback_map_.empty()) {
- CefString message_name = message->GetName();
- CallbackMap::const_iterator it = callback_map_.find(
- std::make_pair(message_name.ToString(),
- browser->GetIdentifier()));
- if (it != callback_map_.end()) {
- // Enter the context.
- it->second.first->Enter();
-
- CefV8ValueList arguments;
-
- // First argument is the message name.
- arguments.push_back(CefV8Value::CreateString(message_name));
-
- // Second argument is the list of message arguments.
- CefRefPtr list = message->GetArgumentList();
- CefRefPtr args = CefV8Value::CreateArray(list->GetSize());
- SetList(list, args);
- arguments.push_back(args);
-
- // Execute the callback.
- CefRefPtr retval =
- it->second.second->ExecuteFunction(NULL, arguments);
- if (retval.get()) {
- if (retval->IsBool())
- handled = retval->GetBoolValue();
- }
+ bool handled = false;
- // Exit the context.
- it->second.first->Exit();
+ // Execute delegate callbacks.
+ RenderDelegateSet::iterator it = render_delegates_.begin();
+ for (; it != render_delegates_.end() && !handled; ++it) {
+ handled = (*it)->OnProcessMessageRecieved(this, browser, source_process, message);
}
- }
- return handled;
+ if (!handled) {
+ if (message->GetName() == "invokeCallback") {
+ CefRefPtr messageArgs = message->GetArgumentList();
+ int32 callbackId = messageArgs->GetInt(0);
+
+ CefRefPtr context = callback_map_[callbackId].first;
+ CefRefPtr callbackFunction = callback_map_[callbackId].second;
+ CefV8ValueList arguments;
+ context->Enter();
+
+ for (size_t i = 1; i < messageArgs->GetSize(); i++) {
+ arguments.push_back(ListValueToV8Value(messageArgs, i));
+ }
+
+ callbackFunction->ExecuteFunction(NULL, arguments);
+ context->Exit();
+
+ callback_map_.erase(callbackId);
+ }
+ }
+
+ return handled;
}
diff --git a/appshell/client_app.h b/appshell/client_app.h
index 1d219db18..0a775224a 100644
--- a/appshell/client_app.h
+++ b/appshell/client_app.h
@@ -57,6 +57,7 @@ class ClientApp : public CefApp,
};
typedef std::set > RenderDelegateSet;
+ typedef std::map, CefRefPtr > > CallbackMap;
ClientApp();
@@ -66,24 +67,16 @@ class ClientApp : public CefApp,
proxy_type_ = proxy_type;
proxy_config_ = proxy_config;
}
+
+ void AddCallback(int32 id, CefRefPtr context, CefRefPtr callbackFunction) {
+ callback_map_[id] = std::make_pair(context, callbackFunction);
+ }
+
+ // Platform-specific methods implemented in client_app_mac/client_app_win
+ double GetElapsedMilliseconds();
+ std::string GetExtensionJSSource();
- // Set a JavaScript callback for the specified |message_name| and |browser_id|
- // combination. Will automatically be removed when the associated context is
- // released. Callbacks can also be set in JavaScript using the
- // app.setMessageCallback function.
- void SetMessageCallback(const std::string& message_name,
- int browser_id,
- CefRefPtr context,
- CefRefPtr function);
-
- // Removes the JavaScript callback for the specified |message_name| and
- // |browser_id| combination. Returns true if a callback was removed. Callbacks
- // can also be removed in JavaScript using the app.removeMessageCallback
- // function.
- bool RemoveMessageCallback(const std::string& message_name,
- int browser_id);
-
- private:
+private:
// Creates all of the RenderDelegate objects. Implemented in
// client_app_delegates.
static void CreateRenderDelegates(RenderDelegateSet& delegates);
@@ -121,15 +114,12 @@ class ClientApp : public CefApp,
cef_proxy_type_t proxy_type_;
CefString proxy_config_;
- // Map of message callbacks.
- typedef std::map,
- std::pair, CefRefPtr > >
- CallbackMap;
- CallbackMap callback_map_;
-
// Set of supported RenderDelegates.
RenderDelegateSet render_delegates_;
-
+
+ // Set of callbacks
+ CallbackMap callback_map_;
+
IMPLEMENT_REFCOUNTING(ClientApp);
};
diff --git a/appshell/client_app_delegates.cpp b/appshell/client_app_delegates.cpp
index 9861e1430..f8345d852 100644
--- a/appshell/client_app_delegates.cpp
+++ b/appshell/client_app_delegates.cpp
@@ -2,7 +2,7 @@
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
-#include "cefclient/client_app.h"
+#include "client_app.h"
// static
void ClientApp::CreateRenderDelegates(RenderDelegateSet& delegates) {
diff --git a/appshell/client_app_mac.mm b/appshell/client_app_mac.mm
new file mode 100644
index 000000000..3372f1c6c
--- /dev/null
+++ b/appshell/client_app_mac.mm
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "client_app.h"
+
+#include
+
+#include
+
+extern CFTimeInterval g_appStartupTime;
+
+double ClientApp::GetElapsedMilliseconds()
+{
+ CFAbsoluteTime elapsed = CFAbsoluteTimeGetCurrent() - g_appStartupTime;
+
+ return round(elapsed * 1000);
+}
+
+std::string ClientApp::GetExtensionJSSource()
+{
+ std::string result;
+
+ // This is a hack to grab the extension file from the main app resource bundle.
+ // This code may be run in a sub process in an app that is bundled inside the main app.
+#if 1
+ NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
+ NSString* sourcePath;
+ NSRange range = [bundlePath rangeOfString: @"/Frameworks/"];
+
+ if (range.location == NSNotFound) {
+ sourcePath = [[NSBundle mainBundle] pathForResource: @"brackets_extensions" ofType: @"js"];
+ } else {
+ sourcePath = [bundlePath substringToIndex:range.location];
+ sourcePath = [sourcePath stringByAppendingString:@"/Resources/brackets_extensions.js"];
+ }
+#else
+ NSString* sourcePath = [[NSBundle mainBundle] pathForResource: @"brackets_extensions" ofType: @"js"];
+#endif
+
+ NSString* jsSource = [[NSString alloc] initWithContentsOfFile:sourcePath encoding:NSUTF8StringEncoding error:nil];
+ result = [jsSource UTF8String];
+ [jsSource release];
+
+ return result;
+}
diff --git a/appshell/client_app_win.cpp b/appshell/client_app_win.cpp
new file mode 100644
index 000000000..218f31cb4
--- /dev/null
+++ b/appshell/client_app_win.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "client_app.h"
+#include "resource.h"
+
+#include
+
+std::string ClientApp::GetExtensionJSSource()
+{
+ extern HINSTANCE hInst;
+
+ HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(IDS_BRACKETS_EXTENSIONS), MAKEINTRESOURCE(256));
+ DWORD dwSize;
+ LPBYTE pBytes = NULL;
+
+ if(hRes)
+ {
+ HGLOBAL hGlob = LoadResource(hInst, hRes);
+ if(hGlob)
+ {
+ dwSize = SizeofResource(hInst, hRes);
+ pBytes = (LPBYTE)LockResource(hGlob);
+ }
+ }
+
+ if (pBytes) {
+ std::string result((const char *)pBytes, dwSize);
+ return result;
+ }
+
+ return "";
+}
+
+double ClientApp::GetElapsedMilliseconds()
+{
+ // TODO: Raymond, please implement
+ return 0;
+}
diff --git a/appshell/client_handler.cpp b/appshell/client_handler.cpp
index 86098d305..a94d34b71 100644
--- a/appshell/client_handler.cpp
+++ b/appshell/client_handler.cpp
@@ -2,16 +2,17 @@
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
-#include "cefclient/client_handler.h"
+#include "client_handler.h"
#include
#include
#include
#include "include/cef_browser.h"
#include "include/cef_frame.h"
#include "include/wrapper/cef_stream_resource_handler.h"
-#include "cefclient/cefclient.h"
-#include "cefclient/resource_util.h"
-#include "cefclient/string_util.h"
+#include "cefclient.h"
+#include "resource_util.h"
+#include "string_util.h"
+#include "appshell/appshell_extensions.h"
// Custom menu command Ids.
@@ -294,8 +295,10 @@ void ClientHandler::ShowDevTools(CefRefPtr browser) {
// static
void ClientHandler::CreateProcessMessageDelegates(
ProcessMessageDelegateSet& delegates) {
+ appshell_extensions::CreateProcessMessageDelegates(delegates);
}
// static
void ClientHandler::CreateRequestDelegates(RequestDelegateSet& delegates) {
+ appshell_extensions::CreateRequestDelegates(delegates);
}
diff --git a/appshell/client_handler.h b/appshell/client_handler.h
index ac5846488..7fa2d0bea 100644
--- a/appshell/client_handler.h
+++ b/appshell/client_handler.h
@@ -10,7 +10,7 @@
#include
#include
#include "include/cef_client.h"
-#include "cefclient/util.h"
+#include "util.h"
// Define this value to redirect all popup URLs to the main application browser
diff --git a/appshell/client_handler_mac.mm b/appshell/client_handler_mac.mm
index 8ddb91290..1dd6274a4 100644
--- a/appshell/client_handler_mac.mm
+++ b/appshell/client_handler_mac.mm
@@ -4,10 +4,10 @@
#import
-#include "cefclient/client_handler.h"
+#include "client_handler.h"
#include "include/cef_browser.h"
#include "include/cef_frame.h"
-#include "cefclient/cefclient.h"
+#include "cefclient.h"
// ClientHandler::ClientLifeSpanHandler implementation
diff --git a/appshell/client_handler_win.cpp b/appshell/client_handler_win.cpp
index 34b33c589..ecb3b564c 100644
--- a/appshell/client_handler_win.cpp
+++ b/appshell/client_handler_win.cpp
@@ -3,11 +3,11 @@
// can be found in the LICENSE file.
#include "config.h"
-#include "cefclient/client_handler.h"
+#include "client_handler.h"
#include
#include "include/cef_browser.h"
#include "include/cef_frame.h"
-#include "cefclient/resource.h"
+#include "resource.h"
bool ClientHandler::OnBeforePopup(CefRefPtr parentBrowser,
const CefPopupFeatures& popupFeatures,
diff --git a/appshell/config.h b/appshell/config.h
index 7d5250cc3..c73a72af0 100644
--- a/appshell/config.h
+++ b/appshell/config.h
@@ -1,2 +1,2 @@
-// #define SHOW_TOOLBAR_UI
+#define SHOW_TOOLBAR_UI
diff --git a/appshell/process_helper_mac.cpp b/appshell/process_helper_mac.cpp
index 7354b036a..03fb18ee2 100644
--- a/appshell/process_helper_mac.cpp
+++ b/appshell/process_helper_mac.cpp
@@ -4,10 +4,15 @@
#include "include/cef_app.h"
+#include
+
// This file is shared by cefclient and cef_unittests so don't include using
// a qualified path.
#include "client_app.h" // NOLINT(build/include)
+// Application startup time
+CFTimeInterval g_appStartupTime;
+
// Stub implementations.
std::string AppGetWorkingDirectory() {
return std::string();
@@ -16,10 +21,13 @@ CefWindowHandle AppGetMainHwnd() {
return NULL;
}
+
// Process entry point.
int main(int argc, char* argv[]) {
CefMainArgs main_args(argc, argv);
-
+
+ g_appStartupTime = CFAbsoluteTimeGetCurrent();
+
CefRefPtr app(new ClientApp);
// Execute the secondary process.
diff --git a/appshell/resource.h b/appshell/resource.h
index 74c35fae8..71982f333 100644
--- a/appshell/resource.h
+++ b/appshell/resource.h
@@ -49,6 +49,7 @@
#define IDS_LOCALSTORAGE 1004
#define IDS_XMLHTTPREQUEST 1005
#define IDS_DOMACCESS 1006
+#define IDS_BRACKETS_EXTENSIONS 1007
// Avoid files associated with MacOS
#define _X86_
diff --git a/appshell/resource_util.h b/appshell/resource_util.h
index c382196f4..4de0f0d30 100644
--- a/appshell/resource_util.h
+++ b/appshell/resource_util.h
@@ -12,7 +12,7 @@ class CefStreamReader;
#if defined(OS_WIN)
-#include "cefclient/resource.h"
+#include "resource.h"
// Load a resource of type BINARY
bool LoadBinaryResource(int binaryId, DWORD &dwSize, LPBYTE &pBytes);
diff --git a/appshell/resource_util_mac.mm b/appshell/resource_util_mac.mm
index 98cfd8605..aa33cebd5 100644
--- a/appshell/resource_util_mac.mm
+++ b/appshell/resource_util_mac.mm
@@ -6,9 +6,9 @@
#import
#include
#include
-#include "cefclient/resource_util.h"
+#include "resource_util.h"
#include "include/cef_stream.h"
-#include "cefclient/util.h"
+#include "util.h"
namespace {
diff --git a/appshell/resource_util_win.cpp b/appshell/resource_util_win.cpp
index 8482ac954..bf72e1868 100644
--- a/appshell/resource_util_win.cpp
+++ b/appshell/resource_util_win.cpp
@@ -2,10 +2,10 @@
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
-#include "cefclient/resource_util.h"
+#include "resource_util.h"
#include "include/cef_stream.h"
#include "include/wrapper/cef_byte_read_handler.h"
-#include "cefclient/util.h"
+#include "util.h"
#if defined(OS_WIN)
diff --git a/appshell/string_util.cpp b/appshell/string_util.cpp
index ebeca5c03..8952d1bf3 100644
--- a/appshell/string_util.cpp
+++ b/appshell/string_util.cpp
@@ -2,7 +2,7 @@
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
-#include "cefclient/string_util.h"
+#include "string_util.h"
#include
#include
#include "include/cef_request.h"
diff --git a/appshell_paths.gypi b/appshell_paths.gypi
index a176cd099..9eca5ec90 100755
--- a/appshell_paths.gypi
+++ b/appshell_paths.gypi
@@ -80,6 +80,9 @@
'<@(autogen_client_side)',
],
'appshell_sources_common': [
+ 'appshell/appshell_extensions.cpp',
+ 'appshell/appshell_extensions.h',
+ 'appshell/brackets_extensions.js',
'appshell/config.h',
'appshell/cefclient.cpp',
'appshell/cefclient.h',
@@ -96,8 +99,10 @@
'appshell/util.h',
],
'appshell_sources_win': [
+ 'appshell/appshell_extensions_win.cpp',
'appshell/cefclient.rc',
'appshell/cefclient_win.cpp',
+ 'appshell/client_app_win.cpp',
'appshell/client_handler_win.cpp',
'appshell/resource.h',
'appshell/res/cefclient.ico',
@@ -106,13 +111,19 @@
'appshell/resource_util_win.cpp',
],
'appshell_sources_mac': [
+ 'appshell/appshell_extensions_mac.mm',
+ 'appshell/client_app_mac.mm',
'appshell/cefclient_mac.mm',
'appshell/client_handler_mac.mm',
'appshell/resource_util_mac.mm',
],
'appshell_sources_mac_helper': [
+ 'appshell/appshell_extensions.cpp',
+ 'appshell/appshell_extensions.h',
+ 'appshell/appshell_extensions_mac.mm',
'appshell/client_app.cpp',
'appshell/client_app.h',
+ 'appshell/client_app_mac.mm',
'appshell/client_app_delegates.cpp',
'appshell/client_handler.cpp',
'appshell/client_handler.h',
@@ -131,6 +142,7 @@
'appshell/mac/English.lproj/InfoPlist.strings',
'appshell/mac/English.lproj/MainMenu.xib',
'appshell/mac/Info.plist',
+ 'appshell/brackets_extensions.js',
],
'appshell_sources_linux': [
'appshell/cefclient_gtk.cpp',