├── .gitattributes ├── .gitignore ├── Electrino ├── macOS │ ├── Electrino.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcuserdata │ │ │ │ └── pauli.xcuserdatad │ │ │ │ └── UserInterfaceState.xcuserstate │ │ └── xcuserdata │ │ │ └── pauli.xcuserdatad │ │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ │ └── xcschemes │ │ │ ├── Electrino.xcscheme │ │ │ └── xcschememanagement.plist │ └── Electrino │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Base.lproj │ │ └── MainMenu.xib │ │ ├── ENOBrowserWindowController.h │ │ ├── ENOBrowserWindowController.m │ │ ├── ENOBrowserWindowController.xib │ │ ├── ENOJSApp.h │ │ ├── ENOJSApp.m │ │ ├── ENOJSBrowserWindow.h │ │ ├── ENOJSBrowserWindow.m │ │ ├── ENOJSConsole.h │ │ ├── ENOJSConsole.m │ │ ├── ENOJSIPCMain.h │ │ ├── ENOJSIPCMain.m │ │ ├── ENOJSNativeImage.h │ │ ├── ENOJSNativeImage.m │ │ ├── ENOJSPath.h │ │ ├── ENOJSPath.m │ │ ├── ENOJSProcess.h │ │ ├── ENOJSProcess.m │ │ ├── ENOJSTray.h │ │ ├── ENOJSTray.m │ │ ├── ENOJSUrl.h │ │ ├── ENOJSUrl.m │ │ ├── ENOJavaScriptApp.h │ │ ├── ENOJavaScriptApp.m │ │ ├── Info.plist │ │ └── main.m ├── test-app │ ├── index.html │ ├── main.js │ └── package.json ├── test-tray │ ├── index.html │ ├── index.js │ ├── main.js │ └── package.json └── win10 │ ├── Electrino.sln │ ├── Electrino │ ├── App.xaml │ ├── App.xaml.cs │ ├── Assets │ │ ├── LockScreenLogo.scale-200.png │ │ ├── SplashScreen.scale-200.png │ │ ├── Square150x150Logo.scale-200.png │ │ ├── Square44x44Logo.scale-200.png │ │ ├── Square44x44Logo.targetsize-24_altform-unplated.png │ │ ├── StoreLogo.png │ │ └── Wide310x150Logo.scale-200.png │ ├── Electrino.csproj │ ├── Hosting │ │ ├── JavaScriptBackgroundWorkItemCallback.cs │ │ ├── JavaScriptBeforeCollectCallback.cs │ │ ├── JavaScriptContext.cs │ │ ├── JavaScriptEngineException.cs │ │ ├── JavaScriptErrorCode.cs │ │ ├── JavaScriptException.cs │ │ ├── JavaScriptFatalException.cs │ │ ├── JavaScriptMemoryAllocationCallback.cs │ │ ├── JavaScriptMemoryEventType.cs │ │ ├── JavaScriptNativeFunction.cs │ │ ├── JavaScriptObjectBeforeCollectCallback.cs │ │ ├── JavaScriptObjectFinalizeCallback.cs │ │ ├── JavaScriptProjectionEnqueueCallback.cs │ │ ├── JavaScriptPromiseContinuationCallback.cs │ │ ├── JavaScriptPropertyId.cs │ │ ├── JavaScriptPropertyIdType.cs │ │ ├── JavaScriptRuntime.cs │ │ ├── JavaScriptRuntimeAttributes.cs │ │ ├── JavaScriptRuntimeVersion.cs │ │ ├── JavaScriptScriptException.cs │ │ ├── JavaScriptSerializedScriptLoadSourceCallback.cs │ │ ├── JavaScriptSerializedScriptUnloadCallback.cs │ │ ├── JavaScriptSourceContext.cs │ │ ├── JavaScriptThreadServiceCallback.cs │ │ ├── JavaScriptTypedArrayType.cs │ │ ├── JavaScriptUsageException.cs │ │ ├── JavaScriptValue.cs │ │ ├── JavaScriptValueType.cs │ │ └── Native.cs │ ├── JS │ │ ├── JSApp.cs │ │ ├── JSBrowserWindow.cs │ │ ├── JSConsole.cs │ │ ├── JSElectrino.cs │ │ ├── JSModule.cs │ │ ├── JSPath.cs │ │ ├── JSProcess.cs │ │ ├── JSRequire.cs │ │ ├── JSUrl.cs │ │ ├── JTokenToJavaScriptValueConverter.cs │ │ └── JavaScriptValueToJTokenConverter.cs │ ├── JavaScriptApp.cs │ ├── MainPage.xaml │ ├── MainPage.xaml.cs │ ├── Package.appxmanifest │ ├── Properties │ │ ├── AssemblyInfo.cs │ │ └── Default.rd.xml │ └── test-app │ │ ├── index.html │ │ ├── main.js │ │ └── test.js │ └── RenderAPI │ ├── JSOs.cs │ ├── JSProcess.cs │ ├── JSRequire.cs │ ├── Properties │ └── AssemblyInfo.cs │ └── RenderAPI.csproj ├── LICENSE ├── README.md ├── docs └── electron-and-electrino-helloworld-screenshot.png ├── package.json └── test-app ├── index.html ├── main.js └── package.json /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac desktop data 2 | .DS_Store 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Win10 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.userosscache 43 | *.sln.docstates 44 | 45 | # User-specific files (MonoDevelop/Xamarin Studio) 46 | *.userprefs 47 | 48 | # Build results 49 | [Dd]ebug/ 50 | [Dd]ebugPublic/ 51 | [Rr]elease/ 52 | [Rr]eleases/ 53 | x64/ 54 | x86/ 55 | bld/ 56 | [Bb]in/ 57 | [Oo]bj/ 58 | [Ll]og/ 59 | 60 | # Visual Studio 2015 cache/options directory 61 | .vs/ 62 | # Uncomment if you have tasks that create the project's static files in wwwroot 63 | #wwwroot/ 64 | 65 | # MSTest test Results 66 | [Tt]est[Rr]esult*/ 67 | [Bb]uild[Ll]og.* 68 | 69 | # NUNIT 70 | *.VisualState.xml 71 | TestResult.xml 72 | 73 | # Build Results of an ATL Project 74 | [Dd]ebugPS/ 75 | [Rr]eleasePS/ 76 | dlldata.c 77 | 78 | # DNX 79 | project.lock.json 80 | project.fragment.lock.json 81 | artifacts/ 82 | 83 | *_i.c 84 | *_p.c 85 | *_i.h 86 | *.ilk 87 | *.meta 88 | *.obj 89 | *.pch 90 | *.pdb 91 | *.pgc 92 | *.pgd 93 | *.rsp 94 | *.sbr 95 | *.tlb 96 | *.tli 97 | *.tlh 98 | *.tmp 99 | *.tmp_proj 100 | *.log 101 | *.vspscc 102 | *.vssscc 103 | .builds 104 | *.pidb 105 | *.svclog 106 | *.scc 107 | 108 | # Chutzpah Test files 109 | _Chutzpah* 110 | 111 | # Visual C++ cache files 112 | ipch/ 113 | *.aps 114 | *.ncb 115 | *.opendb 116 | *.opensdf 117 | *.sdf 118 | *.cachefile 119 | *.VC.db 120 | *.VC.VC.opendb 121 | 122 | # Visual Studio profiler 123 | *.psess 124 | *.vsp 125 | *.vspx 126 | *.sap 127 | 128 | # TFS 2012 Local Workspace 129 | $tf/ 130 | 131 | # Guidance Automation Toolkit 132 | *.gpState 133 | 134 | # ReSharper is a .NET coding add-in 135 | _ReSharper*/ 136 | *.[Rr]e[Ss]harper 137 | *.DotSettings.user 138 | 139 | # JustCode is a .NET coding add-in 140 | .JustCode 141 | 142 | # TeamCity is a build add-in 143 | _TeamCity* 144 | 145 | # DotCover is a Code Coverage Tool 146 | *.dotCover 147 | 148 | # NCrunch 149 | _NCrunch_* 150 | .*crunch*.local.xml 151 | nCrunchTemp_* 152 | 153 | # MightyMoose 154 | *.mm.* 155 | AutoTest.Net/ 156 | 157 | # Web workbench (sass) 158 | .sass-cache/ 159 | 160 | # Installshield output folder 161 | [Ee]xpress/ 162 | 163 | # DocProject is a documentation generator add-in 164 | DocProject/buildhelp/ 165 | DocProject/Help/*.HxT 166 | DocProject/Help/*.HxC 167 | DocProject/Help/*.hhc 168 | DocProject/Help/*.hhk 169 | DocProject/Help/*.hhp 170 | DocProject/Help/Html2 171 | DocProject/Help/html 172 | 173 | # Click-Once directory 174 | publish/ 175 | 176 | # Publish Web Output 177 | *.[Pp]ublish.xml 178 | *.azurePubxml 179 | # TODO: Comment the next line if you want to checkin your web deploy settings 180 | # but database connection strings (with potential passwords) will be unencrypted 181 | #*.pubxml 182 | *.publishproj 183 | 184 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 185 | # checkin your Azure Web App publish settings, but sensitive information contained 186 | # in these scripts will be unencrypted 187 | PublishScripts/ 188 | 189 | # NuGet Packages 190 | *.nupkg 191 | # The packages folder can be ignored because of Package Restore 192 | **/packages/* 193 | # except build/, which is used as an MSBuild target. 194 | !**/packages/build/ 195 | # Uncomment if necessary however generally it will be regenerated when needed 196 | #!**/packages/repositories.config 197 | # NuGet v3's project.json files produces more ignoreable files 198 | *.nuget.props 199 | *.nuget.targets 200 | 201 | # Microsoft Azure Build Output 202 | csx/ 203 | *.build.csdef 204 | 205 | # Microsoft Azure Emulator 206 | ecf/ 207 | rcf/ 208 | 209 | # Windows Store app package directories and files 210 | AppPackages/ 211 | BundleArtifacts/ 212 | Package.StoreAssociation.xml 213 | _pkginfo.txt 214 | 215 | # Visual Studio cache files 216 | # files ending in .cache can be ignored 217 | *.[Cc]ache 218 | # but keep track of directories ending in .cache 219 | !*.[Cc]ache/ 220 | 221 | # Others 222 | ClientBin/ 223 | ~$* 224 | *~ 225 | *.dbmdl 226 | *.dbproj.schemaview 227 | *.jfm 228 | *.pfx 229 | *.publishsettings 230 | node_modules/ 231 | orleans.codegen.cs 232 | 233 | # Since there are multiple workflows, uncomment next line to ignore bower_components 234 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 235 | #bower_components/ 236 | 237 | # RIA/Silverlight projects 238 | Generated_Code/ 239 | 240 | # Backup & report files from converting an old project file 241 | # to a newer Visual Studio version. Backup files are not needed, 242 | # because we have git ;-) 243 | _UpgradeReport_Files/ 244 | Backup*/ 245 | UpgradeLog*.XML 246 | UpgradeLog*.htm 247 | 248 | # SQL Server files 249 | *.mdf 250 | *.ldf 251 | 252 | # Business Intelligence projects 253 | *.rdl.data 254 | *.bim.layout 255 | *.bim_*.settings 256 | 257 | # Microsoft Fakes 258 | FakesAssemblies/ 259 | 260 | # GhostDoc plugin setting file 261 | *.GhostDoc.xml 262 | 263 | # Node.js Tools for Visual Studio 264 | .ntvs_analysis.dat 265 | 266 | # Visual Studio 6 build log 267 | *.plg 268 | 269 | # Visual Studio 6 workspace options file 270 | *.opt 271 | 272 | # Visual Studio LightSwitch build output 273 | **/*.HTMLClient/GeneratedArtifacts 274 | **/*.DesktopClient/GeneratedArtifacts 275 | **/*.DesktopClient/ModelManifest.xml 276 | **/*.Server/GeneratedArtifacts 277 | **/*.Server/ModelManifest.xml 278 | _Pvt_Extensions 279 | 280 | # Paket dependency manager 281 | .paket/paket.exe 282 | paket-files/ 283 | 284 | # FAKE - F# Make 285 | .fake/ 286 | 287 | # JetBrains Rider 288 | .idea/ 289 | *.sln.iml 290 | 291 | # CodeRush 292 | .cr/ 293 | 294 | # Python Tools for Visual Studio (PTVS) 295 | __pycache__/ 296 | *.pyc 297 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino.xcodeproj/project.xcworkspace/xcuserdata/pauli.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojala/electrino/0bf75954b56440f0a0ec6aa83f2ce50d56ab52e2/Electrino/macOS/Electrino.xcodeproj/project.xcworkspace/xcuserdata/pauli.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Electrino/macOS/Electrino.xcodeproj/xcuserdata/pauli.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino.xcodeproj/xcuserdata/pauli.xcuserdatad/xcschemes/Electrino.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino.xcodeproj/xcuserdata/pauli.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Electrino.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 5AA9DBAD1EB9F58A00EF7CC9 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // Electrino 4 | // 5 | // Created by Pauli Olavi Ojala on 03/05/17. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import 12 | 13 | @interface AppDelegate : NSObject 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // Electrino 4 | // 5 | // Created by Pauli Olavi Ojala on 03/05/17. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import "AppDelegate.h" 12 | #import "ENOJavaScriptApp.h" 13 | #import "ENOBrowserWindowController.h" 14 | 15 | 16 | @interface AppDelegate () 17 | 18 | @end 19 | 20 | 21 | 22 | 23 | @implementation AppDelegate 24 | 25 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification 26 | { 27 | // enable WebKit devtools 28 | [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"WebKitDeveloperExtras"]; 29 | 30 | 31 | NSString *appDir = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"app"]; 32 | NSString *mainJSPath = [appDir stringByAppendingPathComponent:@"main.js"]; 33 | 34 | if ( ![[NSFileManager defaultManager] fileExistsAtPath:mainJSPath]) { 35 | NSLog(@"** no main.js found in dir: %@", appDir); 36 | [NSApp terminate:nil]; // -- 37 | } 38 | 39 | NSString *mainJS = [NSString stringWithContentsOfFile:mainJSPath encoding:NSUTF8StringEncoding error:NULL]; 40 | ENOJavaScriptApp *jsApp = [ENOJavaScriptApp sharedApp]; 41 | NSError *error = nil; 42 | 43 | // app setup 44 | jsApp.jsContext[@"__dirname"] = appDir; 45 | 46 | // load code 47 | if ( ![jsApp loadMainJS:mainJS error:&error]) { 48 | NSLog(@"** could not load main.js: %@, path: %@", error, mainJSPath); 49 | 50 | [self _presentJSError:error message:@"Main program execution failed."]; 51 | 52 | [NSApp terminate:nil]; // -- 53 | } 54 | 55 | // for the old-style WebView, it seems that there needs to be an instance initialized early; 56 | // otherwise it can go into a weird state where scripts and default styles don't load at all. 57 | { 58 | ENOBrowserWindowController *windowController = [[ENOBrowserWindowController alloc] initWithWindowNibName:@"ENOBrowserWindowController"]; 59 | NSWindow *win = windowController.window; 60 | [win setFrame:NSMakeRect(0, 0, 1, 1) display:NO]; 61 | } 62 | 63 | // send 'ready' event to the main app 64 | if ( ![jsApp.jsAppGlobalObject emitReady:&error]) { 65 | NSLog(@"** app.on('ready'): %@", error); 66 | 67 | [self _presentJSError:error message:@"Exception in app.on('ready')"]; 68 | } 69 | } 70 | 71 | - (void)_presentJSError:(NSError *)error message:(NSString *)msg 72 | { 73 | NSAlert *alert = [[NSAlert alloc] init]; 74 | alert.alertStyle = NSCriticalAlertStyle; 75 | alert.messageText = msg ?: @"JavaScript error"; 76 | alert.informativeText = [NSString stringWithFormat:@"\n%@\n\n(On line %@)", error.localizedDescription, error.userInfo[@"SourceLineNumber"]]; 77 | 78 | [alert runModal]; 79 | } 80 | 81 | - (void)applicationWillTerminate:(NSNotification *)aNotification 82 | { 83 | 84 | } 85 | 86 | 87 | @end 88 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "size" : "512x512", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "size" : "512x512", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOBrowserWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ENOBrowserWindowController.h 3 | // Electrino 4 | // 5 | // Created by Pauli Olavi Ojala on 03/05/17. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import 12 | #import 13 | 14 | 15 | @interface ENOBrowserWindowController : NSWindowController 16 | 17 | @property (nonatomic, strong) IBOutlet WebView *testWebView; 18 | 19 | - (instancetype)initAsResizable:(BOOL)resizable hasFrame:(BOOL)hasFrame; 20 | 21 | - (void)loadURL:(NSURL *)url; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOBrowserWindowController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ENOBrowserWindowController.m 3 | // Electrino 4 | // 5 | // Created by Pauli Olavi Ojala on 03/05/17. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import "ENOBrowserWindowController.h" 12 | #import 13 | 14 | 15 | // The new WKWebView class doesn't give access to its JSContext (because it runs in a separate process); 16 | // therefore it doesn't seem suitable for hosting Electrino apps. 17 | // Let's just stick with good old WebView for now. 18 | #define USE_WKWEBVIEW 0 19 | 20 | 21 | #import "ENOJSProcess.h" 22 | 23 | 24 | 25 | @interface ENOBrowserWindowController () 26 | 27 | #if USE_WKWEBVIEW 28 | @property (nonatomic, strong) WKWebView *webView; 29 | #else 30 | @property (nonatomic, strong) WebView *webView; 31 | #endif 32 | 33 | @end 34 | 35 | 36 | 37 | @implementation ENOBrowserWindowController 38 | 39 | - (instancetype)initAsResizable:(BOOL)resizable hasFrame:(BOOL)hasFrame 40 | { 41 | NSWindowStyleMask styleMask = 0; 42 | if (resizable) { 43 | styleMask |= NSWindowStyleMaskResizable; 44 | } 45 | if (hasFrame) { 46 | styleMask |= NSWindowStyleMaskTitled; 47 | styleMask |= NSWindowStyleMaskMiniaturizable; 48 | } 49 | 50 | NSWindow *window = [[NSWindow alloc] initWithContentRect:NSMakeRect(100, 100, 640, 480) 51 | styleMask:styleMask 52 | backing:NSBackingStoreBuffered 53 | defer:NO]; 54 | 55 | window.opaque = NO; 56 | window.hasShadow = YES; 57 | window.ignoresMouseEvents = NO; 58 | window.allowsConcurrentViewDrawing = YES; 59 | window.releasedWhenClosed = NO; 60 | 61 | #if USE_WKWEBVIEW 62 | WKWebViewConfiguration *wkConf = [[WKWebViewConfiguration alloc] init]; 63 | 64 | WKWebView *webView = [[WKWebView alloc] initWithFrame:window.contentView.bounds configuration:wkConf]; 65 | 66 | #else 67 | WebView *webView = [[WebView alloc] initWithFrame:window.contentView.frame]; 68 | 69 | webView.frameLoadDelegate = self; 70 | 71 | webView.drawsBackground = NO; 72 | 73 | WebPreferences *prefs = [webView preferences]; 74 | prefs.javaScriptEnabled = YES; 75 | prefs.plugInsEnabled = NO; 76 | //prefs.defaultFontSize = 20; 77 | 78 | #endif 79 | 80 | window.contentView = webView; 81 | self.webView = webView; 82 | 83 | return [self initWithWindow:window]; 84 | } 85 | 86 | 87 | - (void)loadURL:(NSURL *)url 88 | { 89 | if (url.isFileURL) { 90 | #if USE_WKWEBVIEW 91 | NSString *dir = [url.path stringByDeletingLastPathComponent]; 92 | NSURL *baseURL = [NSURL fileURLWithPath:dir isDirectory:YES]; 93 | 94 | NSLog(@"%s, using WKWebView, %@", __func__, url); 95 | 96 | [self.webView loadFileURL:url allowingReadAccessToURL:baseURL]; 97 | 98 | #else 99 | NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url]; 100 | [self.webView.mainFrame loadRequest:req]; 101 | 102 | #endif 103 | } 104 | else { 105 | NSLog(@"** %s: only supports file urls", __func__); 106 | } 107 | 108 | } 109 | 110 | #if !USE_WKWEBVIEW 111 | - (void)webView:(WebView *)webView didCreateJavaScriptContext:(JSContext *)jsContext forFrame:(WebFrame *)frame 112 | { 113 | ENOJSProcess *process = [[ENOJSProcess alloc] init]; 114 | jsContext[@"process"] = process; 115 | } 116 | 117 | - (void)webView:(WebView *)webView didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame 118 | { 119 | if (frame == self.webView.mainFrame) { 120 | self.window.title = title; 121 | } 122 | } 123 | #endif 124 | 125 | @end 126 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOBrowserWindowController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOJSApp.h: -------------------------------------------------------------------------------- 1 | // 2 | // ENOJSApp.h 3 | // Electrino 4 | // 5 | // Created by Pauli Olavi Ojala on 03/05/17. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import 12 | #import 13 | @class ENOJavaScriptApp; 14 | 15 | 16 | @protocol ENOJSAppExports 17 | 18 | JSExportAs(on, 19 | - (void)on:(NSString *)event withCallback:(JSValue *)cb 20 | ); 21 | 22 | @end 23 | 24 | 25 | @interface ENOJSApp : NSObject 26 | 27 | @property (nonatomic, weak) ENOJavaScriptApp *jsApp; 28 | 29 | - (BOOL)emitReady:(NSError **)outError; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOJSApp.m: -------------------------------------------------------------------------------- 1 | // 2 | // ENOJSApp.m 3 | // Electrino 4 | // 5 | // Created by Pauli Olavi Ojala on 03/05/17. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import "ENOJSApp.h" 12 | #import "ENOJavaScriptApp.h" 13 | 14 | 15 | @interface ENOJSApp () 16 | 17 | @property (nonatomic, strong) NSMutableDictionary *eventCallbacks; 18 | 19 | @end 20 | 21 | 22 | @implementation ENOJSApp 23 | 24 | - (id)init 25 | { 26 | self = [super init]; 27 | 28 | self.eventCallbacks = [NSMutableDictionary dictionary]; 29 | 30 | return self; 31 | } 32 | 33 | - (void)on:(NSString *)event withCallback:(JSValue *)cb 34 | { 35 | if (event.length > 0 && cb) { 36 | NSMutableArray *cbArr = self.eventCallbacks[event] ?: [NSMutableArray array]; 37 | [cbArr addObject:cb]; 38 | 39 | self.eventCallbacks[event] = cbArr; 40 | } 41 | } 42 | 43 | - (BOOL)emitReady:(NSError **)outError 44 | { 45 | self.jsApp.lastException = nil; 46 | 47 | for (JSValue *cb in self.eventCallbacks[@"ready"]) { 48 | //NSLog(@"%s, %@", __func__, cb); 49 | 50 | [cb callWithArguments:@[]]; 51 | 52 | if (self.jsApp.lastException) { 53 | if (outError) { 54 | *outError = [NSError errorWithDomain:kENOJavaScriptErrorDomain 55 | code:102 56 | userInfo:@{ 57 | NSLocalizedDescriptionKey: self.jsApp.lastException, 58 | @"SourceLineNumber": @(self.jsApp.lastExceptionLine), 59 | }]; 60 | } 61 | return NO; 62 | } 63 | } 64 | return YES; 65 | } 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOJSBrowserWindow.h: -------------------------------------------------------------------------------- 1 | ;// 2 | // ENOJSBrowserWindow.h 3 | // Electrino 4 | // 5 | // Created by Pauli Olavi Ojala on 03/05/17. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import 12 | #import 13 | #import "ENOBrowserWindowController.h" 14 | 15 | 16 | @protocol ENOJSBrowserWindowExports 17 | 18 | - (instancetype)initWithOptions:(NSDictionary *)opts; 19 | 20 | - (void)loadURL:(NSString *)url; 21 | 22 | - (BOOL)isVisible; 23 | - (void)show; 24 | - (void)hide; 25 | - (void)focus; 26 | 27 | - (NSDictionary *)getBounds; 28 | 29 | JSExportAs(setPosition, 30 | - (void)setPositionX:(double)x y:(double)y 31 | ); 32 | 33 | JSExportAs(on, 34 | - (void)on:(NSString *)event withCallback:(JSValue *)cb 35 | ); 36 | 37 | @end 38 | 39 | 40 | @interface ENOJSBrowserWindow : NSObject 41 | 42 | @property (nonatomic, strong) ENOBrowserWindowController *windowController; 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOJSBrowserWindow.m: -------------------------------------------------------------------------------- 1 | // 2 | // ENOJSBrowserWindow.m 3 | // Electrino 4 | // 5 | // Created by Pauli Olavi Ojala on 03/05/17. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import "ENOJSBrowserWindow.h" 12 | #import "ENOBrowserWindowController.h" 13 | 14 | 15 | @interface ENOJSBrowserWindow () 16 | 17 | @property (nonatomic, strong) NSMutableDictionary *eventCallbacks; 18 | 19 | @end 20 | 21 | 22 | @implementation ENOJSBrowserWindow 23 | 24 | - (instancetype)initWithOptions:(NSDictionary *)opts 25 | { 26 | self = [super init]; 27 | 28 | //NSLog(@"%s, %@", __func__, opts); 29 | 30 | self.eventCallbacks = [NSMutableDictionary dictionary]; 31 | 32 | id val; 33 | BOOL show = YES; 34 | BOOL resizable = YES; 35 | BOOL hasFrame = YES; 36 | if ((val = opts[@"show"])) { 37 | show = [val boolValue]; 38 | } 39 | if ((val = opts[@"resizable"])) { 40 | resizable = [val boolValue]; 41 | } 42 | if ((val = opts[@"frame"])) { 43 | hasFrame = [val boolValue]; 44 | } 45 | 46 | self.windowController = [[ENOBrowserWindowController alloc] initAsResizable:resizable hasFrame:hasFrame]; 47 | 48 | NSWindow *win = self.windowController.window; 49 | NSRect frame = win.frame; 50 | if ((val = opts[@"width"]) && [val integerValue] > 0) { 51 | frame.size.width = [val doubleValue]; 52 | } 53 | if ((val = opts[@"height"]) && [val integerValue] > 0) { 54 | frame.size.height = [val doubleValue]; 55 | } 56 | 57 | [win setFrame:frame display:NO]; 58 | [win center]; 59 | 60 | if (show) 61 | [self show]; 62 | 63 | return self; 64 | } 65 | 66 | - (void)loadURL:(NSString *)urlStr 67 | { 68 | NSURL *url = [NSURL URLWithString:urlStr]; 69 | 70 | [self.windowController loadURL:url]; 71 | } 72 | 73 | - (void)on:(NSString *)event withCallback:(JSValue *)cb 74 | { 75 | if (event.length > 0 && cb) { 76 | NSMutableArray *cbArr = self.eventCallbacks[event] ?: [NSMutableArray array]; 77 | [cbArr addObject:cb]; 78 | 79 | self.eventCallbacks[event] = cbArr; 80 | } 81 | } 82 | 83 | - (BOOL)isVisible 84 | { 85 | return self.windowController.window.visible; 86 | } 87 | 88 | - (void)show 89 | { 90 | [self.windowController showWindow:nil]; 91 | } 92 | 93 | - (void)hide 94 | { 95 | [self.windowController.window orderOut:nil]; 96 | } 97 | 98 | - (void)focus 99 | { 100 | [self.windowController.window makeKeyWindow]; 101 | } 102 | 103 | - (void)setPositionX:(double)x y:(double)y 104 | { 105 | NSRect r = self.windowController.window.frame; 106 | r.origin = NSMakePoint(x, y - r.size.height); 107 | 108 | //NSLog(@"setting window frame: %@", NSStringFromRect(r)); 109 | [self.windowController.window setFrameOrigin:r.origin]; 110 | } 111 | 112 | - (NSDictionary *)getBounds 113 | { 114 | NSRect r = self.windowController.window.frame; 115 | 116 | return @{ 117 | @"x": @(r.origin.x), 118 | @"y": @(r.origin.y), 119 | @"width": @(r.size.width), 120 | @"height": @(r.size.height), 121 | }; 122 | } 123 | 124 | 125 | @end 126 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOJSConsole.h: -------------------------------------------------------------------------------- 1 | // 2 | // ENOJSConsole.h 3 | // Electrino 4 | // 5 | // Created by Pauli Olavi Ojala on 03/05/17. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import 12 | #import 13 | 14 | 15 | @protocol ENOJSConsoleExports 16 | 17 | @property (nonatomic, copy) void (^log)(NSString *str); 18 | 19 | @end 20 | 21 | 22 | @interface ENOJSConsole : NSObject 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOJSConsole.m: -------------------------------------------------------------------------------- 1 | // 2 | // ENOJSConsole.m 3 | // Electrino 4 | // 5 | // Created by Pauli Olavi Ojala on 03/05/17. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import "ENOJSConsole.h" 12 | 13 | 14 | @implementation ENOJSConsole 15 | 16 | @synthesize log; 17 | 18 | - (id)init 19 | { 20 | self = [super init]; 21 | 22 | self.log = ^(NSString *str){ 23 | NSArray *args = [JSContext currentArguments]; 24 | 25 | if (args.count > 1) { 26 | NSString *argsStr = [[args subarrayWithRange:NSMakeRange(1, args.count - 1)] componentsJoinedByString:@", "]; 27 | str = [str stringByAppendingFormat:@" %@", argsStr]; 28 | } 29 | 30 | NSLog(@"JS: %@", str); 31 | }; 32 | 33 | return self; 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOJSIPCMain.h: -------------------------------------------------------------------------------- 1 | // 2 | // ENOJSIPCMain.h 3 | // Electrino 4 | // 5 | // Created by Pauli Ojala on 17/05/2017. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import 12 | #import 13 | 14 | 15 | @protocol ENOJSIPCMainExports 16 | 17 | JSExportAs(on, 18 | - (void)on:(NSString *)event withCallback:(JSValue *)cb 19 | ); 20 | 21 | @end 22 | 23 | 24 | @interface ENOJSIPCMain : NSObject 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOJSIPCMain.m: -------------------------------------------------------------------------------- 1 | // 2 | // ENOJSIPCMain.m 3 | // Electrino 4 | // 5 | // Created by Pauli Ojala on 17/05/2017. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import "ENOJSIPCMain.h" 12 | 13 | 14 | @interface ENOJSIPCMain () 15 | 16 | @property (nonatomic, strong) NSMutableDictionary *eventCallbacks; 17 | 18 | @end 19 | 20 | 21 | @implementation ENOJSIPCMain 22 | 23 | - (id)init 24 | { 25 | self.eventCallbacks = [NSMutableDictionary dictionary]; 26 | 27 | return self; 28 | } 29 | 30 | - (void)on:(NSString *)event withCallback:(JSValue *)cb 31 | { 32 | if (event.length > 0 && cb) { 33 | NSMutableArray *cbArr = self.eventCallbacks[event] ?: [NSMutableArray array]; 34 | [cbArr addObject:cb]; 35 | 36 | self.eventCallbacks[event] = cbArr; 37 | } 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOJSNativeImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // ENOJSNativeImage.h 3 | // Electrino 4 | // 5 | // Created by Pauli Ojala on 17/05/2017. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import 12 | #import 13 | 14 | 15 | @protocol ENOJSNativeImageAPIExports 16 | 17 | - (id)createFromDataURL:(NSString *)dataURL; 18 | 19 | @end 20 | 21 | 22 | @interface ENOJSNativeImageAPI : NSObject 23 | 24 | @end 25 | 26 | 27 | @interface ENOJSNativeImageInstance : NSObject 28 | 29 | @property (nonatomic, strong) NSImage *image; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOJSNativeImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // ENOJSNativeImage.m 3 | // Electrino 4 | // 5 | // Created by Pauli Ojala on 17/05/2017. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import "ENOJSNativeImage.h" 12 | 13 | 14 | @implementation ENOJSNativeImageAPI 15 | 16 | - (id)createFromDataURL:(NSString *)dataURL 17 | { 18 | NSString *pngPrefix = @"data:image/png;base64,"; 19 | if ( ![dataURL hasPrefix:pngPrefix]) { 20 | NSLog(@"** %s: invalid data url", __func__); 21 | return nil; // -- 22 | } 23 | 24 | NSString *base64Str = [dataURL substringFromIndex:pngPrefix.length]; 25 | 26 | NSData *data = [[NSData alloc] initWithBase64EncodedString:base64Str options:NSDataBase64DecodingIgnoreUnknownCharacters]; 27 | NSImage *image = [[NSImage alloc] initWithData:data]; 28 | 29 | ENOJSNativeImageInstance *jsImage = [[ENOJSNativeImageInstance alloc] init]; 30 | jsImage.image = image; 31 | 32 | return jsImage; 33 | } 34 | 35 | @end 36 | 37 | 38 | 39 | @implementation ENOJSNativeImageInstance 40 | @end 41 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOJSPath.h: -------------------------------------------------------------------------------- 1 | // 2 | // ENOJSPath.h 3 | // Electrino 4 | // 5 | // Created by Pauli Olavi Ojala on 03/05/17. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import 12 | #import 13 | 14 | 15 | @protocol ENOJSPathExports 16 | 17 | @property (nonatomic, copy) NSString *(^join)(); 18 | 19 | @end 20 | 21 | 22 | 23 | @interface ENOJSPath : NSObject 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOJSPath.m: -------------------------------------------------------------------------------- 1 | // 2 | // ENOJSPath.m 3 | // Electrino 4 | // 5 | // Created by Pauli Olavi Ojala on 03/05/17. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import "ENOJSPath.h" 12 | 13 | 14 | @implementation ENOJSPath 15 | 16 | @synthesize join; 17 | 18 | - (id)init 19 | { 20 | self = [super init]; 21 | 22 | self.join = ^NSString *(){ 23 | NSArray *args = [JSContext currentArguments]; 24 | NSString *pathSep = @"/"; 25 | 26 | return [args componentsJoinedByString:pathSep]; 27 | }; 28 | 29 | return self; 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOJSProcess.h: -------------------------------------------------------------------------------- 1 | // 2 | // ENOJSProcess.h 3 | // Electrino 4 | // 5 | // Created by Pauli Olavi Ojala on 03/05/17. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import 12 | #import 13 | 14 | 15 | @protocol ENOJSProcessExports 16 | 17 | @property (nonatomic, copy) NSString *platform; 18 | @property (nonatomic, copy) NSDictionary *versions; 19 | 20 | @end 21 | 22 | 23 | @interface ENOJSProcess : NSObject 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOJSProcess.m: -------------------------------------------------------------------------------- 1 | // 2 | // ENOJSProcess.m 3 | // Electrino 4 | // 5 | // Created by Pauli Olavi Ojala on 03/05/17. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import "ENOJSProcess.h" 12 | 13 | 14 | @implementation ENOJSProcess 15 | 16 | @synthesize platform; 17 | @synthesize versions; 18 | 19 | 20 | - (id)init 21 | { 22 | self = [super init]; 23 | 24 | self.platform = @"darwin"; 25 | 26 | self.versions = @{ 27 | @"electrino": @"0.0.1" 28 | }; 29 | 30 | return self; 31 | } 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOJSTray.h: -------------------------------------------------------------------------------- 1 | // 2 | // ENOJSTray.h 3 | // Electrino 4 | // 5 | // Created by Pauli Ojala on 17/05/2017. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import 12 | #import 13 | 14 | 15 | @protocol ENOJSTrayExports 16 | 17 | - (instancetype)initWithIcon:(id)icon; 18 | 19 | JSExportAs(on, 20 | - (void)on:(NSString *)event withCallback:(JSValue *)cb 21 | ); 22 | 23 | - (NSDictionary *)getBounds; 24 | 25 | @end 26 | 27 | 28 | @interface ENOJSTray : NSObject 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOJSTray.m: -------------------------------------------------------------------------------- 1 | // 2 | // ENOJSTray.m 3 | // Electrino 4 | // 5 | // Created by Pauli Ojala on 17/05/2017. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import "ENOJSTray.h" 12 | #import "ENOJSNativeImage.h" 13 | 14 | 15 | @interface ENOJSTray () 16 | 17 | @property (nonatomic, strong) NSMutableDictionary *eventCallbacks; 18 | 19 | @property (nonatomic, strong) NSStatusItem *statusItem; 20 | 21 | @end 22 | 23 | 24 | @implementation ENOJSTray 25 | 26 | - (instancetype)initWithIcon:(id)icon 27 | { 28 | self = [super init]; 29 | 30 | NSLog(@"%s: %@", __func__, icon); 31 | 32 | self.eventCallbacks = [NSMutableDictionary dictionary]; 33 | 34 | 35 | self.statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength]; 36 | self.statusItem.highlightMode = YES; 37 | 38 | NSStatusBarButton *barButton = self.statusItem.button; 39 | barButton.action = @selector(statusBarButtonAction:); 40 | barButton.target = self; 41 | 42 | NSImage *image = nil; 43 | if ([icon respondsToSelector:@selector(image)]) { 44 | image = [icon image]; 45 | } 46 | if (image) { 47 | image.template = YES; 48 | barButton.image = image; 49 | } 50 | else { 51 | barButton.title = @"E"; 52 | barButton.font = [NSFont systemFontOfSize:17.0 weight:NSFontWeightBlack]; 53 | } 54 | 55 | 56 | return self; 57 | } 58 | 59 | - (void)on:(NSString *)event withCallback:(JSValue *)cb 60 | { 61 | if (event.length > 0 && cb) { 62 | NSMutableArray *cbArr = self.eventCallbacks[event] ?: [NSMutableArray array]; 63 | [cbArr addObject:cb]; 64 | 65 | self.eventCallbacks[event] = cbArr; 66 | } 67 | } 68 | 69 | - (NSDictionary *)getBounds 70 | { 71 | NSView *view = self.statusItem.button; 72 | NSRect frameInWindow = [view convertRect:view.bounds toView:nil]; 73 | NSRect frameOnScreen = [view.window convertRectToScreen:frameInWindow]; 74 | 75 | //NSLog(@"frame %@ - window %@ - screen %@ / %p, %p", NSStringFromRect(view.frame), NSStringFromRect(frameInWindow), NSStringFromRect(frameOnScreen), view, view.window); 76 | 77 | return @{ 78 | @"x": @(frameOnScreen.origin.x), 79 | @"y": @(frameOnScreen.origin.y), 80 | @"width": @(frameOnScreen.size.width), 81 | @"height": @(frameOnScreen.size.width), 82 | }; 83 | } 84 | 85 | 86 | #pragma mark --- actions --- 87 | 88 | - (IBAction)statusBarButtonAction:(id)sender 89 | { 90 | //NSStatusBarButton *barButton = self.statusItem.button; 91 | 92 | for (JSValue *cb in self.eventCallbacks[@"click"]) { 93 | //NSLog(@"%s, %@", __func__, cb); 94 | 95 | [cb callWithArguments:@[]]; 96 | } 97 | 98 | /* 99 | if (self.popover.shown) { 100 | [self.popover close]; 101 | } else { 102 | [self.popover showRelativeToRect:barButton.bounds ofView:barButton preferredEdge:NSMinYEdge]; 103 | 104 | if ( !self.popoverTransiencyMonitor) { 105 | self.popoverTransiencyMonitor = [NSEvent addGlobalMonitorForEventsMatchingMask:(NSLeftMouseDownMask | NSRightMouseDownMask | NSKeyUpMask) handler:^(NSEvent *event) { 106 | [NSEvent removeMonitor:self.popoverTransiencyMonitor]; 107 | self.popoverTransiencyMonitor = nil; 108 | [self.popover close]; 109 | }]; 110 | } 111 | }*/ 112 | } 113 | 114 | 115 | @end 116 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOJSUrl.h: -------------------------------------------------------------------------------- 1 | // 2 | // ENOJSUrl.h 3 | // Electrino 4 | // 5 | // Created by Pauli Olavi Ojala on 03/05/17. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import 12 | #import 13 | 14 | 15 | @protocol ENOJSUrlExports 16 | 17 | @property (nonatomic, copy) NSString *(^format)(NSDictionary *urlDict); 18 | 19 | @end 20 | 21 | 22 | 23 | @interface ENOJSUrl : NSObject 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOJSUrl.m: -------------------------------------------------------------------------------- 1 | // 2 | // ENOJSUrl.m 3 | // Electrino 4 | // 5 | // Created by Pauli Olavi Ojala on 03/05/17. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import "ENOJSUrl.h" 12 | 13 | 14 | @implementation ENOJSUrl 15 | 16 | @synthesize format; 17 | 18 | - (id)init 19 | { 20 | self = [super init]; 21 | 22 | self.format = ^NSString *(NSDictionary *urlDict){ 23 | NSString *protocol = urlDict[@"protocol"]; 24 | NSString *path = urlDict[@"pathname"]; 25 | 26 | //NSLog(@"%s, %@", __func__, urlDict); 27 | 28 | return [NSString stringWithFormat:@"%@//%@", protocol, path]; 29 | }; 30 | 31 | return self; 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOJavaScriptApp.h: -------------------------------------------------------------------------------- 1 | // 2 | // ENOJavaScriptApp.h 3 | // Electrino 4 | // 5 | // Created by Pauli Olavi Ojala on 03/05/17. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import 12 | #import 13 | #import "ENOJSApp.h" 14 | 15 | 16 | extern NSString * const kENOJavaScriptErrorDomain; 17 | 18 | 19 | @interface ENOJavaScriptApp : NSObject 20 | 21 | + (instancetype)sharedApp; 22 | 23 | @property (nonatomic, readonly) JSContext *jsContext; 24 | 25 | @property (nonatomic, readonly) ENOJSApp *jsAppGlobalObject; 26 | 27 | @property (nonatomic, strong) NSString *lastException; 28 | @property (nonatomic, assign) NSInteger lastExceptionLine; 29 | 30 | 31 | - (BOOL)loadMainJS:(NSString *)js error:(NSError **)outError; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/ENOJavaScriptApp.m: -------------------------------------------------------------------------------- 1 | // 2 | // ENOJavaScriptApp.m 3 | // Electrino 4 | // 5 | // Created by Pauli Olavi Ojala on 03/05/17. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import "ENOJavaScriptApp.h" 12 | #import "ENOJSPath.h" 13 | #import "ENOJSUrl.h" 14 | #import "ENOJSBrowserWindow.h" 15 | #import "ENOJSApp.h" 16 | #import "ENOJSProcess.h" 17 | #import "ENOJSConsole.h" 18 | #import "ENOJSTray.h" 19 | #import "ENOJSNativeImage.h" 20 | #import "ENOJSIPCMain.h" 21 | 22 | 23 | NSString * const kENOJavaScriptErrorDomain = @"ENOJavaScriptErrorDomain"; 24 | 25 | 26 | @interface ENOJavaScriptApp () 27 | 28 | @property (nonatomic, strong) JSVirtualMachine *jsVM; 29 | @property (nonatomic, strong) JSContext *jsContext; 30 | @property (nonatomic, strong) NSDictionary *jsModules; 31 | @property (nonatomic, strong) ENOJSApp *jsAppGlobalObject; 32 | @property (nonatomic, strong) ENOJSIPCMain *jsIPCMain; 33 | 34 | @property (nonatomic, assign) BOOL inException; 35 | 36 | @end 37 | 38 | 39 | @implementation ENOJavaScriptApp 40 | 41 | + (instancetype)sharedApp 42 | { 43 | static ENOJavaScriptApp *s_app = nil; 44 | static dispatch_once_t onceToken; 45 | dispatch_once(&onceToken, ^{ 46 | s_app = [[self alloc] init]; 47 | }); 48 | return s_app; 49 | } 50 | 51 | - (id)init 52 | { 53 | self = [super init]; 54 | 55 | 56 | self.jsVM = [[JSVirtualMachine alloc] init]; 57 | self.jsContext = [[JSContext alloc] initWithVirtualMachine:self.jsVM]; 58 | 59 | self.jsAppGlobalObject = [[ENOJSApp alloc] init]; 60 | self.jsAppGlobalObject.jsApp = self; 61 | 62 | self.jsIPCMain = [[ENOJSIPCMain alloc] init]; 63 | 64 | // initialize available modules 65 | 66 | NSMutableDictionary *modules = [NSMutableDictionary dictionary]; 67 | 68 | modules[@"electrino"] = @{ 69 | // singletons 70 | @"app": self.jsAppGlobalObject, 71 | @"ipcMain": self.jsIPCMain, 72 | @"nativeImage": [[ENOJSNativeImageAPI alloc] init], 73 | 74 | // classes that can be constructed 75 | @"BrowserWindow": [ENOJSBrowserWindow class], 76 | @"Tray": [ENOJSTray class], 77 | }; 78 | 79 | modules[@"path"] = [[ENOJSPath alloc] init]; 80 | modules[@"url"] = [[ENOJSUrl alloc] init]; 81 | 82 | self.jsModules = modules; 83 | 84 | 85 | // add exception handler and global functions 86 | 87 | __block __weak ENOJavaScriptApp *weakSelf = self; 88 | 89 | self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exception) { 90 | [weakSelf _jsException:exception]; 91 | }; 92 | 93 | self.jsContext[@"require"] = ^(NSString *arg) { 94 | id module = weakSelf.jsModules[arg]; 95 | return module; 96 | }; 97 | 98 | self.jsContext[@"process"] = [[ENOJSProcess alloc] init]; 99 | self.jsContext[@"console"] = [[ENOJSConsole alloc] init]; 100 | 101 | return self; 102 | } 103 | 104 | - (void)dealloc 105 | { 106 | self.jsContext.exceptionHandler = NULL; 107 | self.jsContext[@"require"] = nil; 108 | } 109 | 110 | - (void)_jsException:(JSValue *)exception 111 | { 112 | NSLog(@"%s, %@", __func__, exception); 113 | 114 | if (self.inException) { // prevent recursion, just in case 115 | return; // -- 116 | } 117 | 118 | self.inException = YES; 119 | 120 | self.lastException = exception.toString; 121 | self.lastExceptionLine = [exception valueForProperty:@"line"].toInt32; 122 | 123 | self.inException = NO; 124 | } 125 | 126 | - (BOOL)loadMainJS:(NSString *)js error:(NSError **)outError 127 | { 128 | self.lastException = nil; 129 | 130 | NSLog(@"%s...", __func__); 131 | 132 | [self.jsContext evaluateScript:js]; 133 | 134 | if (self.lastException) { 135 | if (outError) { 136 | *outError = [NSError errorWithDomain:kENOJavaScriptErrorDomain 137 | code:101 138 | userInfo:@{ 139 | NSLocalizedDescriptionKey: self.lastException, 140 | @"SourceLineNumber": @(self.lastExceptionLine), 141 | }]; 142 | } 143 | return NO; // -- 144 | } 145 | 146 | NSLog(@"%s done", __func__); 147 | 148 | return YES; 149 | } 150 | 151 | 152 | 153 | 154 | @end 155 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | Copyright © 2017 Pauli Olavi Ojala 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /Electrino/macOS/Electrino/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Electrino 4 | // 5 | // Created by Pauli Olavi Ojala on 03/05/17. 6 | // Copyright © 2017 Pauli Olavi Ojala. 7 | // 8 | // This software may be modified and distributed under the terms of the MIT license. See the LICENSE file for details. 9 | // 10 | 11 | #import 12 | 13 | int main(int argc, const char * argv[]) { 14 | return NSApplicationMain(argc, argv); 15 | } 16 | -------------------------------------------------------------------------------- /Electrino/test-app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hello World! 6 | 7 | 8 |

Hello World!

9 | We are using Electrino . 10 | 11 | 12 | -------------------------------------------------------------------------------- /Electrino/test-app/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electrino') 2 | const path = require('path') 3 | const url = require('url') 4 | 5 | // Keep a global reference of the window object, if you don't, the window will 6 | // be closed automatically when the JavaScript object is garbage collected. 7 | let win 8 | 9 | function createWindow () { 10 | // Create the browser window. 11 | win = new BrowserWindow({width: 800, height: 600}) 12 | 13 | // and load the index.html of the app. 14 | win.loadURL(url.format({ 15 | pathname: path.join(__dirname, 'index.html'), 16 | protocol: 'file:', 17 | slashes: true 18 | })) 19 | 20 | // Open the DevTools. 21 | win.webContents.openDevTools() 22 | 23 | // Emitted when the window is closed. 24 | win.on('closed', () => { 25 | // Dereference the window object, usually you would store windows 26 | // in an array if your app supports multi windows, this is the time 27 | // when you should delete the corresponding element. 28 | win = null 29 | }) 30 | } 31 | 32 | // This method will be called when Electron has finished 33 | // initialization and is ready to create browser windows. 34 | // Some APIs can only be used after this event occurs. 35 | app.on('ready', createWindow) 36 | 37 | // Quit when all windows are closed. 38 | app.on('window-all-closed', () => { 39 | // On macOS it is common for applications and their menu bar 40 | // to stay active until the user quits explicitly with Cmd + Q 41 | if (process.platform !== 'darwin') { 42 | app.quit() 43 | } 44 | }) 45 | 46 | app.on('activate', () => { 47 | // On macOS it's common to re-create a window in the app when the 48 | // dock icon is clicked and there are no other windows open. 49 | if (win === null) { 50 | createWindow() 51 | } 52 | }) 53 | -------------------------------------------------------------------------------- /Electrino/test-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "your-app", 3 | "version" : "0.1.0", 4 | "main" : "main.js" 5 | } -------------------------------------------------------------------------------- /Electrino/test-tray/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Sample Menubar App 4 | 5 | 6 | 7 |

Hello Menubar App

8 | 9 | -------------------------------------------------------------------------------- /Electrino/test-tray/index.js: -------------------------------------------------------------------------------- 1 | 2 | console.log("index.js loading") 3 | 4 | document.addEventListener('DOMContentLoaded', () => { 5 | console.log("index.js dom loaded") 6 | 7 | let n = new Notification('You did it!', { 8 | body: 'Nice work.' 9 | }) 10 | 11 | // Tell the notification to show the menubar popup window on click 12 | n.onclick = () => { ipcRenderer.send('show-window') } 13 | 14 | }) 15 | -------------------------------------------------------------------------------- /Electrino/test-tray/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow, ipcMain, Tray, nativeImage} = require('electrino') 2 | const path = require('path') 3 | 4 | const assetsDir = path.join(__dirname, 'assets') 5 | 6 | let tray = undefined 7 | let window = undefined 8 | 9 | app.on('ready', () => { 10 | // Setup the menubar with an icon 11 | 12 | let icon = nativeImage.createFromDataURL(base64Icon) 13 | tray = new Tray(icon) 14 | 15 | // Add a click handler so that when the user clicks on the menubar icon, it shows 16 | // our popup window 17 | tray.on('click', function(event) { 18 | toggleWindow() 19 | 20 | // Show devtools when command clicked 21 | if (window.isVisible() && process.defaultApp && event.metaKey) { 22 | window.openDevTools({mode: 'detach'}) 23 | } 24 | }) 25 | 26 | // Make the popup window for the menubar 27 | window = new BrowserWindow({ 28 | width: 300, 29 | height: 350, 30 | show: false, 31 | frame: false, 32 | resizable: false, 33 | }) 34 | 35 | // Tell the popup window to load our index.html file 36 | window.loadURL(`file://${path.join(__dirname, 'index.html')}`) 37 | 38 | // Only close the window on blur if dev tools isn't opened 39 | window.on('blur', () => { 40 | if(!window.webContents.isDevToolsOpened()) { 41 | window.hide() 42 | } 43 | }) 44 | }) 45 | 46 | const toggleWindow = () => { 47 | if (window.isVisible()) { 48 | window.hide() 49 | } else { 50 | showWindow() 51 | } 52 | } 53 | 54 | const showWindow = () => { 55 | const trayPos = tray.getBounds() 56 | const windowPos = window.getBounds() 57 | let x, y = 0 58 | if (process.platform == 'darwin') { 59 | x = Math.round(trayPos.x + (trayPos.width / 2) - (windowPos.width / 2)) 60 | y = Math.round(trayPos.y + trayPos.height) 61 | } else { 62 | x = Math.round(trayPos.x + (trayPos.width / 2) - (windowPos.width / 2)) 63 | y = Math.round(trayPos.y + trayPos.height * 10) 64 | } 65 | 66 | 67 | window.setPosition(x, y, false) 68 | window.show() 69 | window.focus() 70 | } 71 | 72 | ipcMain.on('show-window', () => { 73 | showWindow() 74 | }) 75 | 76 | app.on('window-all-closed', () => { 77 | // On macOS it is common for applications and their menu bar 78 | // to stay active until the user quits explicitly with Cmd + Q 79 | if (process.platform !== 'darwin') { 80 | app.quit() 81 | } 82 | }) 83 | 84 | // Tray Icon as Base64 so tutorial has less overhead 85 | let base64Icon = `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw 86 | 7AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AkZCg87wZW7ewA 87 | AAp1JREFUOMuV1U2IVlUcx/HPnbc0MWwEF40hRWRQmWhEUi4KorlTQ0zQKgqSxKinRYuWrdq0iIp8DAy 88 | CFmYUUVTYY0Qw0SsYVDQRlFlQU4o4VDMUY9NzWtz/45znzo3yv7n/l3O+53fOPS+F/7R9G0l34Vlap/x 89 | PG+gPby76471jpJdxI4p/x5QrakPVZ3yI4lLSLH4LpetIT5N24AWKpZXAW4boXogFnGxQXEzhdQYHl0v 90 | pbtJkBIOkBqXpVhzAWIPi8hocxCyH5qp0e10oHY6BNy3P7szULyc9hzkGTjat8WPRqctkD3QORrJ211J 91 | srPV7CKP4i7S6CXxF+GtY2lG5D5yg+D6bckHaRXs463dV+OtJVzeBj4Q/inuy2uf4NYPvyVR38Vn4GzD 92 | ZAC5ezHbITsqtEU8HvGcjpFblDncpDma16yhvqit+c3mLuQj3Vm7rJ4r3kW+z+6sD80aKQWcivwm318B 93 | pHk9mA11PuSXil/B1thyrSA9HMI8nMtYNlDszcKdbHVcLkduCO0L1VxTv1VTv5plR3lrCuzga+c2YqB2 94 | QNEfqjV7EWl8c8X78kKleTTfWeuA49maDjlNuz8CHFykOYDEabKvg0Jqh+AB/Z4D7qs+h03gbxyK/FVf 95 | WL6FfsC/8tdGoZ0/hRKZ6A+2pUP1jdZecse01cGcBr2YNzqdcG6q/oDgS+7e3XLeF6j/wTvzM6Lfi2nQ 96 | KP8e0P6Ezn9X2488MvLnW75vwP2wCr8J5eD4upsxaHZzOwNNZcU2c3FfwWg1cDuISfIxH6fzedE8G90s 97 | 8nuXH8B0eoXNc/6tQjsQfXaQz0/BEXUD3W4oF0hQPflTlJwZIl+FcOp86e2vvoj1Le6I/P974ZA2dBXk 98 | 97qQ13Z8+3PS0+AdjKa1R95YOZgAAAABJRU5ErkJggg==` 99 | 100 | -------------------------------------------------------------------------------- /Electrino/test-tray/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "your-app", 3 | "version" : "0.1.0", 4 | "main" : "main.js" 5 | } -------------------------------------------------------------------------------- /Electrino/win10/Electrino.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26430.6 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Electrino", "Electrino\Electrino.csproj", "{1AF63BD2-3E24-4B9D-9336-B97EA3580C09}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RenderAPI", "RenderAPI\RenderAPI.csproj", "{77B6E3D3-17E6-46CB-B699-C118776F54DE}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Debug|ARM = Debug|ARM 14 | Debug|x64 = Debug|x64 15 | Debug|x86 = Debug|x86 16 | Release|Any CPU = Release|Any CPU 17 | Release|ARM = Release|ARM 18 | Release|x64 = Release|x64 19 | Release|x86 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {1AF63BD2-3E24-4B9D-9336-B97EA3580C09}.Debug|Any CPU.ActiveCfg = Debug|x86 23 | {1AF63BD2-3E24-4B9D-9336-B97EA3580C09}.Debug|ARM.ActiveCfg = Debug|ARM 24 | {1AF63BD2-3E24-4B9D-9336-B97EA3580C09}.Debug|ARM.Build.0 = Debug|ARM 25 | {1AF63BD2-3E24-4B9D-9336-B97EA3580C09}.Debug|ARM.Deploy.0 = Debug|ARM 26 | {1AF63BD2-3E24-4B9D-9336-B97EA3580C09}.Debug|x64.ActiveCfg = Debug|x64 27 | {1AF63BD2-3E24-4B9D-9336-B97EA3580C09}.Debug|x64.Build.0 = Debug|x64 28 | {1AF63BD2-3E24-4B9D-9336-B97EA3580C09}.Debug|x64.Deploy.0 = Debug|x64 29 | {1AF63BD2-3E24-4B9D-9336-B97EA3580C09}.Debug|x86.ActiveCfg = Debug|x86 30 | {1AF63BD2-3E24-4B9D-9336-B97EA3580C09}.Debug|x86.Build.0 = Debug|x86 31 | {1AF63BD2-3E24-4B9D-9336-B97EA3580C09}.Debug|x86.Deploy.0 = Debug|x86 32 | {1AF63BD2-3E24-4B9D-9336-B97EA3580C09}.Release|Any CPU.ActiveCfg = Release|x86 33 | {1AF63BD2-3E24-4B9D-9336-B97EA3580C09}.Release|ARM.ActiveCfg = Release|ARM 34 | {1AF63BD2-3E24-4B9D-9336-B97EA3580C09}.Release|ARM.Build.0 = Release|ARM 35 | {1AF63BD2-3E24-4B9D-9336-B97EA3580C09}.Release|ARM.Deploy.0 = Release|ARM 36 | {1AF63BD2-3E24-4B9D-9336-B97EA3580C09}.Release|x64.ActiveCfg = Release|x64 37 | {1AF63BD2-3E24-4B9D-9336-B97EA3580C09}.Release|x64.Build.0 = Release|x64 38 | {1AF63BD2-3E24-4B9D-9336-B97EA3580C09}.Release|x64.Deploy.0 = Release|x64 39 | {1AF63BD2-3E24-4B9D-9336-B97EA3580C09}.Release|x86.ActiveCfg = Release|x86 40 | {1AF63BD2-3E24-4B9D-9336-B97EA3580C09}.Release|x86.Build.0 = Release|x86 41 | {1AF63BD2-3E24-4B9D-9336-B97EA3580C09}.Release|x86.Deploy.0 = Release|x86 42 | {77B6E3D3-17E6-46CB-B699-C118776F54DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {77B6E3D3-17E6-46CB-B699-C118776F54DE}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {77B6E3D3-17E6-46CB-B699-C118776F54DE}.Debug|ARM.ActiveCfg = Debug|ARM 45 | {77B6E3D3-17E6-46CB-B699-C118776F54DE}.Debug|ARM.Build.0 = Debug|ARM 46 | {77B6E3D3-17E6-46CB-B699-C118776F54DE}.Debug|x64.ActiveCfg = Debug|x64 47 | {77B6E3D3-17E6-46CB-B699-C118776F54DE}.Debug|x64.Build.0 = Debug|x64 48 | {77B6E3D3-17E6-46CB-B699-C118776F54DE}.Debug|x86.ActiveCfg = Debug|x86 49 | {77B6E3D3-17E6-46CB-B699-C118776F54DE}.Debug|x86.Build.0 = Debug|x86 50 | {77B6E3D3-17E6-46CB-B699-C118776F54DE}.Release|Any CPU.ActiveCfg = Release|Any CPU 51 | {77B6E3D3-17E6-46CB-B699-C118776F54DE}.Release|Any CPU.Build.0 = Release|Any CPU 52 | {77B6E3D3-17E6-46CB-B699-C118776F54DE}.Release|ARM.ActiveCfg = Release|ARM 53 | {77B6E3D3-17E6-46CB-B699-C118776F54DE}.Release|ARM.Build.0 = Release|ARM 54 | {77B6E3D3-17E6-46CB-B699-C118776F54DE}.Release|x64.ActiveCfg = Release|x64 55 | {77B6E3D3-17E6-46CB-B699-C118776F54DE}.Release|x64.Build.0 = Release|x64 56 | {77B6E3D3-17E6-46CB-B699-C118776F54DE}.Release|x86.ActiveCfg = Release|x86 57 | {77B6E3D3-17E6-46CB-B699-C118776F54DE}.Release|x86.Build.0 = Release|x86 58 | EndGlobalSection 59 | GlobalSection(SolutionProperties) = preSolution 60 | HideSolutionNode = FALSE 61 | EndGlobalSection 62 | EndGlobal 63 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/App.xaml: -------------------------------------------------------------------------------- 1 |  7 | 8 | 9 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices.WindowsRuntime; 6 | using Windows.ApplicationModel; 7 | using Windows.ApplicationModel.Activation; 8 | using Windows.Foundation; 9 | using Windows.Foundation.Collections; 10 | using Windows.UI.Xaml; 11 | using Windows.UI.Xaml.Controls; 12 | using Windows.UI.Xaml.Controls.Primitives; 13 | using Windows.UI.Xaml.Data; 14 | using Windows.UI.Xaml.Input; 15 | using Windows.UI.Xaml.Media; 16 | using Windows.UI.Xaml.Navigation; 17 | using System.Diagnostics; 18 | using System.Threading.Tasks; 19 | using Windows.Storage; 20 | using Windows.UI.ViewManagement; 21 | 22 | namespace Electrino 23 | { 24 | /// 25 | /// Provides application-specific behavior to supplement the default Application class. 26 | /// 27 | sealed partial class App : Application 28 | { 29 | private JavaScriptApp jsApp = new JavaScriptApp(); 30 | private static App instance; 31 | private LaunchActivatedEventArgs launchArgs; 32 | 33 | /// 34 | /// Initializes the singleton application object. This is the first line of authored code 35 | /// executed, and as such is the logical equivalent of main() or WinMain(). 36 | /// 37 | public App() 38 | { 39 | instance = this; 40 | this.InitializeComponent(); 41 | this.Suspending += OnSuspending; 42 | } 43 | 44 | public static void Log(string msg) 45 | { 46 | #if DEBUG 47 | Debug.WriteLine(msg); 48 | #endif 49 | } 50 | 51 | private async void Run() 52 | { 53 | string js = await ReadJS("main.js"); 54 | Log(jsApp.Init()); 55 | Log(jsApp.RunScript(js)); 56 | Ready(); 57 | } 58 | 59 | private async Task ReadJS(string filename) 60 | { 61 | StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///test-app/" + filename)); 62 | string js; 63 | using (StreamReader sRead = new StreamReader(await file.OpenStreamForReadAsync())) 64 | js = await sRead.ReadToEndAsync(); 65 | return js; 66 | } 67 | 68 | /// 69 | /// Invoked when the application is launched normally by the end user. Other entry points 70 | /// will be used such as when the application is launched to open a specific file. 71 | /// 72 | /// Details about the launch request and process. 73 | protected override void OnLaunched(LaunchActivatedEventArgs e) 74 | { 75 | launchArgs = e; 76 | Run(); 77 | } 78 | 79 | private void Ready() { 80 | if (JS.JSApp.GetInstance() != null) 81 | { 82 | JS.JSApp.GetInstance().Call("ready"); 83 | } 84 | } 85 | 86 | private void Suspended() 87 | { 88 | if (JS.JSApp.GetInstance() != null) 89 | { 90 | JS.JSApp.GetInstance().Call("window-all-closed"); 91 | } 92 | } 93 | 94 | public static void NewWindow(int width, int height) 95 | { 96 | if (instance == null) 97 | { 98 | Log("App no ready yet"); 99 | return; 100 | } 101 | App.instance._NewWindow(width, height); 102 | } 103 | 104 | private void _NewWindow(int width, int height) 105 | { 106 | ApplicationView.PreferredLaunchViewSize = new Size(width, height); 107 | ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.PreferredLaunchViewSize; 108 | 109 | Frame rootFrame = Window.Current.Content as Frame; 110 | 111 | // Do not repeat app initialization when the Window already has content, 112 | // just ensure that the window is active 113 | if (rootFrame == null) 114 | { 115 | // Create a Frame to act as the navigation context and navigate to the first page 116 | rootFrame = new Frame(); 117 | 118 | rootFrame.NavigationFailed += OnNavigationFailed; 119 | 120 | // Place the frame in the current Window 121 | Window.Current.Content = rootFrame; 122 | } 123 | 124 | if (rootFrame.Content == null) 125 | { 126 | // When the navigation stack isn't restored navigate to the first page, 127 | // configuring the new page by passing required information as a navigation 128 | // parameter 129 | rootFrame.Navigate(typeof(MainPage), launchArgs.Arguments); 130 | } 131 | // Ensure the current window is active 132 | Window.Current.Activate(); 133 | } 134 | 135 | /// 136 | /// Invoked when Navigation to a certain page fails 137 | /// 138 | /// The Frame which failed navigation 139 | /// Details about the navigation failure 140 | void OnNavigationFailed(object sender, NavigationFailedEventArgs e) 141 | { 142 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName); 143 | } 144 | 145 | /// 146 | /// Invoked when application execution is being suspended. Application state is saved 147 | /// without knowing whether the application will be terminated or resumed with the contents 148 | /// of memory still intact. 149 | /// 150 | /// The source of the suspend request. 151 | /// Details about the suspend request. 152 | private void OnSuspending(object sender, SuspendingEventArgs e) 153 | { 154 | var deferral = e.SuspendingOperation.GetDeferral(); 155 | //TODO: Save application state and stop any background activity 156 | deferral.Complete(); 157 | Suspended(); 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Assets/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojala/electrino/0bf75954b56440f0a0ec6aa83f2ce50d56ab52e2/Electrino/win10/Electrino/Assets/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Assets/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojala/electrino/0bf75954b56440f0a0ec6aa83f2ce50d56ab52e2/Electrino/win10/Electrino/Assets/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Assets/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojala/electrino/0bf75954b56440f0a0ec6aa83f2ce50d56ab52e2/Electrino/win10/Electrino/Assets/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Assets/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojala/electrino/0bf75954b56440f0a0ec6aa83f2ce50d56ab52e2/Electrino/win10/Electrino/Assets/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Assets/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojala/electrino/0bf75954b56440f0a0ec6aa83f2ce50d56ab52e2/Electrino/win10/Electrino/Assets/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Assets/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojala/electrino/0bf75954b56440f0a0ec6aa83f2ce50d56ab52e2/Electrino/win10/Electrino/Assets/StoreLogo.png -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Assets/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojala/electrino/0bf75954b56440f0a0ec6aa83f2ce50d56ab52e2/Electrino/win10/Electrino/Assets/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Electrino.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x86 7 | {1AF63BD2-3E24-4B9D-9336-B97EA3580C09} 8 | AppContainerExe 9 | Properties 10 | Electrino 11 | Electrino 12 | en-US 13 | UAP 14 | 10.0.15063.0 15 | 10.0.10586.0 16 | 14 17 | 512 18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 19 | true 20 | Electrino_TemporaryKey.pfx 21 | True 22 | Always 23 | x86|x64|arm 24 | 25 | 26 | true 27 | bin\x86\Debug\ 28 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 29 | ;2008 30 | full 31 | x86 32 | false 33 | prompt 34 | true 35 | 36 | 37 | bin\x86\Release\ 38 | TRACE;NETFX_CORE;WINDOWS_UWP 39 | true 40 | ;2008 41 | pdbonly 42 | x86 43 | false 44 | prompt 45 | true 46 | true 47 | 48 | 49 | true 50 | bin\ARM\Debug\ 51 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 52 | ;2008 53 | full 54 | ARM 55 | false 56 | prompt 57 | true 58 | 59 | 60 | bin\ARM\Release\ 61 | TRACE;NETFX_CORE;WINDOWS_UWP 62 | true 63 | ;2008 64 | pdbonly 65 | ARM 66 | false 67 | prompt 68 | true 69 | true 70 | 71 | 72 | true 73 | bin\x64\Debug\ 74 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 75 | ;2008 76 | full 77 | x64 78 | false 79 | prompt 80 | true 81 | 82 | 83 | bin\x64\Release\ 84 | TRACE;NETFX_CORE;WINDOWS_UWP 85 | true 86 | ;2008 87 | pdbonly 88 | x64 89 | false 90 | prompt 91 | true 92 | true 93 | 94 | 95 | PackageReference 96 | 97 | 98 | 99 | App.xaml 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | MainPage.xaml 144 | 145 | 146 | 147 | 148 | 149 | Designer 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | MSBuild:Compile 169 | Designer 170 | 171 | 172 | MSBuild:Compile 173 | Designer 174 | 175 | 176 | 177 | 178 | 5.3.3 179 | 180 | 181 | 10.0.2 182 | 183 | 184 | 185 | 186 | {77b6e3d3-17e6-46cb-b699-c118776f54de} 187 | RenderAPI 188 | 189 | 190 | 191 | 192 | 14.0 193 | 194 | 195 | 202 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptBackgroundWorkItemCallback.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | using System; 4 | 5 | /// 6 | /// A background work item callback. 7 | /// 8 | /// 9 | /// This is passed to the host's thread service (if provided) to allow the host to 10 | /// invoke the work item callback on the background thread of its choice. 11 | /// 12 | /// Data argument passed to the thread service. 13 | public delegate void JavaScriptBackgroundWorkItemCallback(IntPtr callbackData); 14 | } 15 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptBeforeCollectCallback.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | using System; 4 | 5 | /// 6 | /// A callback called before collection. 7 | /// 8 | /// The state passed to SetBeforeCollectCallback. 9 | public delegate void JavaScriptBeforeCollectCallback(IntPtr callbackState); 10 | } 11 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptEngineException.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | using System; 4 | using System.Runtime.Serialization; 5 | 6 | /// 7 | /// An exception that occurred in the workings of the JavaScript engine itself. 8 | /// 9 | public sealed class JavaScriptEngineException : JavaScriptException 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// The error code returned. 15 | public JavaScriptEngineException(JavaScriptErrorCode code) : 16 | this(code, "A fatal exception has occurred in a JavaScript runtime") 17 | { 18 | } 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | /// The error code returned. 24 | /// The error message. 25 | public JavaScriptEngineException(JavaScriptErrorCode code, string message) : 26 | base(code, message) 27 | { 28 | } 29 | 30 | /// 31 | /// Initializes a new instance of the class. 32 | /// 33 | /// The serialization info. 34 | /// The streaming context. 35 | private JavaScriptEngineException(string message, Exception innerException) : 36 | base(message, innerException) 37 | { 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptErrorCode.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | /// 4 | /// An error code returned from a Chakra hosting API. 5 | /// 6 | public enum JavaScriptErrorCode : uint 7 | { 8 | /// 9 | /// Success error code. 10 | /// 11 | NoError = 0, 12 | 13 | /// 14 | /// Category of errors that relates to incorrect usage of the API itself. 15 | /// 16 | CategoryUsage = 0x10000, 17 | 18 | /// 19 | /// An argument to a hosting API was invalid. 20 | /// 21 | InvalidArgument, 22 | 23 | /// 24 | /// An argument to a hosting API was null in a context where null is not allowed. 25 | /// 26 | NullArgument, 27 | 28 | /// 29 | /// The hosting API requires that a context be current, but there is no current context. 30 | /// 31 | NoCurrentContext, 32 | 33 | /// 34 | /// The engine is in an exception state and no APIs can be called until the exception is 35 | /// cleared. 36 | /// 37 | InExceptionState, 38 | 39 | /// 40 | /// A hosting API is not yet implemented. 41 | /// 42 | NotImplemented, 43 | 44 | /// 45 | /// A hosting API was called on the wrong thread. 46 | /// 47 | WrongThread, 48 | 49 | /// 50 | /// A runtime that is still in use cannot be disposed. 51 | /// 52 | RuntimeInUse, 53 | 54 | /// 55 | /// A bad serialized script was used, or the serialized script was serialized by a 56 | /// different version of the Chakra engine. 57 | /// 58 | BadSerializedScript, 59 | 60 | /// 61 | /// The runtime is in a disabled state. 62 | /// 63 | InDisabledState, 64 | 65 | /// 66 | /// Runtime does not support reliable script interruption. 67 | /// 68 | CannotDisableExecution, 69 | 70 | /// 71 | /// A heap enumeration is currently underway in the script context. 72 | /// 73 | HeapEnumInProgress, 74 | 75 | /// 76 | /// A hosting API that operates on object values was called with a non-object value. 77 | /// 78 | ArgumentNotObject, 79 | 80 | /// 81 | /// A script context is in the middle of a profile callback. 82 | /// 83 | InProfileCallback, 84 | 85 | /// 86 | /// A thread service callback is currently underway. 87 | /// 88 | InThreadServiceCallback, 89 | 90 | /// 91 | /// Scripts cannot be serialized in debug contexts. 92 | /// 93 | CannotSerializeDebugScript, 94 | 95 | /// 96 | /// The context cannot be put into a debug state because it is already in a debug state. 97 | /// 98 | AlreadyDebuggingContext, 99 | 100 | /// 101 | /// The context cannot start profiling because it is already profiling. 102 | /// 103 | AlreadyProfilingContext, 104 | 105 | /// 106 | /// Idle notification given when the host did not enable idle processing. 107 | /// 108 | IdleNotEnabled, 109 | 110 | /// 111 | /// The context did not accept the enqueue callback. 112 | /// 113 | CannotSetProjectionEnqueueCallback, 114 | 115 | /// 116 | /// Failed to start projection. 117 | /// 118 | CannotStartProjection, 119 | 120 | /// 121 | /// The operation is not supported in an object before collect callback. 122 | /// 123 | InObjectBeforeCollectCallback, 124 | 125 | /// 126 | /// Object cannot be unwrapped to IInspectable pointer. 127 | /// 128 | ObjectNotInspectable, 129 | 130 | /// 131 | /// A hosting API that operates on symbol property ids but was called with a non-symbol property id. 132 | /// The error code is returned by JsGetSymbolFromPropertyId if the function is called with non-symbol property id. 133 | /// 134 | PropertyNotSymbol, 135 | 136 | /// 137 | /// A hosting API that operates on string property ids but was called with a non-string property id. 138 | /// The error code is returned by existing JsGetPropertyNamefromId if the function is called with non-string property id. 139 | /// 140 | PropertyNotString, 141 | 142 | /// 143 | /// Category of errors that relates to errors occurring within the engine itself. 144 | /// 145 | CategoryEngine = 0x20000, 146 | 147 | /// 148 | /// The Chakra engine has run out of memory. 149 | /// 150 | OutOfMemory, 151 | 152 | /// 153 | /// Category of errors that relates to errors in a script. 154 | /// 155 | CategoryScript = 0x30000, 156 | 157 | /// 158 | /// A JavaScript exception occurred while running a script. 159 | /// 160 | ScriptException, 161 | 162 | /// 163 | /// JavaScript failed to compile. 164 | /// 165 | ScriptCompile, 166 | 167 | /// 168 | /// A script was terminated due to a request to suspend a runtime. 169 | /// 170 | ScriptTerminated, 171 | 172 | /// 173 | /// A script was terminated because it tried to use eval or function and eval 174 | /// was disabled. 175 | /// 176 | ScriptEvalDisabled, 177 | 178 | /// 179 | /// Category of errors that are fatal and signify failure of the engine. 180 | /// 181 | CategoryFatal = 0x40000, 182 | 183 | /// 184 | /// A fatal error in the engine has occurred. 185 | /// 186 | Fatal, 187 | 188 | /// 189 | /// A hosting API was called with object created on different javascript runtime. 190 | /// 191 | WrongRuntime, 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptException.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | using System; 4 | using System.Runtime.Serialization; 5 | 6 | /// 7 | /// An exception returned from the Chakra engine. 8 | /// 9 | public class JavaScriptException : Exception 10 | { 11 | /// 12 | /// The error code. 13 | /// 14 | private readonly JavaScriptErrorCode code; 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | /// The error code returned. 20 | public JavaScriptException(JavaScriptErrorCode code) : 21 | this(code, "A fatal exception has occurred in a JavaScript runtime") 22 | { 23 | } 24 | 25 | /// 26 | /// Initializes a new instance of the class. 27 | /// 28 | /// The error code returned. 29 | /// The error message. 30 | public JavaScriptException(JavaScriptErrorCode code, string message) : 31 | base(message) 32 | { 33 | this.code = code; 34 | } 35 | 36 | /// 37 | /// Initializes a new instance of the class. 38 | /// 39 | /// The serialization info. 40 | /// The streaming context. 41 | protected JavaScriptException(string message, Exception innerException) : 42 | base(message, innerException) 43 | { 44 | if (message != null) 45 | { 46 | code = (JavaScriptErrorCode) base.HResult; 47 | } 48 | } 49 | 50 | /* 51 | /// 52 | /// Serializes the exception information. 53 | /// 54 | /// The serialization information. 55 | /// The streaming context. 56 | public override void GetObjectData(SerializationInfo info, StreamingContext context) 57 | { 58 | base.GetObjectData(info, context); 59 | info.AddValue("code", (uint)code); 60 | } 61 | */ 62 | /// 63 | /// Gets the error code. 64 | /// 65 | public JavaScriptErrorCode ErrorCode 66 | { 67 | get { return code; } 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptFatalException.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | using System; 4 | using System.Runtime.Serialization; 5 | 6 | /// 7 | /// A fatal exception occurred. 8 | /// 9 | public sealed class JavaScriptFatalException : JavaScriptException 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// The error code returned. 15 | public JavaScriptFatalException(JavaScriptErrorCode code) : 16 | this(code, "A fatal exception has occurred in a JavaScript runtime") 17 | { 18 | } 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | /// The error code returned. 24 | /// The error message. 25 | public JavaScriptFatalException(JavaScriptErrorCode code, string message) : 26 | base(code, message) 27 | { 28 | } 29 | 30 | /// 31 | /// Initializes a new instance of the class. 32 | /// 33 | /// The serialization info. 34 | /// The streaming context. 35 | private JavaScriptFatalException(string message, Exception innerException) : 36 | base(message, innerException) 37 | { 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptMemoryAllocationCallback.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | using System; 4 | 5 | /// 6 | /// User implemented callback routine for memory allocation events 7 | /// 8 | /// The state passed to SetRuntimeMemoryAllocationCallback. 9 | /// The type of type allocation event. 10 | /// The size of the allocation. 11 | /// 12 | /// For the Allocate event, returning true allows the runtime to continue with 13 | /// allocation. Returning false indicates the allocation request is rejected. The return value 14 | /// is ignored for other allocation events. 15 | /// 16 | public delegate bool JavaScriptMemoryAllocationCallback(IntPtr callbackState, JavaScriptMemoryEventType allocationEvent, UIntPtr allocationSize); 17 | } 18 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptMemoryEventType.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | /// 4 | /// Allocation callback event type. 5 | /// 6 | public enum JavaScriptMemoryEventType 7 | { 8 | /// 9 | /// Indicates a request for memory allocation. 10 | /// 11 | Allocate = 0, 12 | 13 | /// 14 | /// Indicates a memory freeing event. 15 | /// 16 | Free = 1, 17 | 18 | /// 19 | /// Indicates a failed allocation event. 20 | /// 21 | Failure = 2 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptNativeFunction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ChakraHost.Hosting 4 | { 5 | using System.Runtime.InteropServices; 6 | 7 | /// 8 | /// A function callback. 9 | /// 10 | /// 11 | /// A Function object that represents the function being invoked. 12 | /// 13 | /// Indicates whether this is a regular call or a 'new' call. 14 | /// The arguments to the call. 15 | /// The number of arguments. 16 | /// Callback data, if any. 17 | /// The result of the call, if any. 18 | public delegate JavaScriptValue JavaScriptNativeFunction(JavaScriptValue callee, [MarshalAs(UnmanagedType.U1)] bool isConstructCall, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] JavaScriptValue[] arguments, ushort argumentCount, IntPtr callbackData); 19 | } 20 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptObjectBeforeCollectCallback.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | using System; 4 | 5 | /// 6 | /// A callback called before collecting an object. 7 | /// 8 | /// 9 | /// Use JsSetObjectBeforeCollectCallback to register this callback. 10 | /// 11 | /// The object to be collected. 12 | /// The state passed to JsSetObjectBeforeCollectCallback. 13 | public delegate void JavaScriptObjectBeforeCollectCallback(JavaScriptValue reference, IntPtr callbackState); 14 | } 15 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptObjectFinalizeCallback.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | using System; 4 | 5 | /// 6 | /// A finalization callback. 7 | /// 8 | /// 9 | /// The external data that was passed in when creating the object being finalized. 10 | /// 11 | public delegate void JavaScriptObjectFinalizeCallback(IntPtr data); 12 | } 13 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptProjectionEnqueueCallback.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | using System; 4 | 5 | /// 6 | /// The context passed into application callback, JsProjectionEnqueueCallback, from Jsrt and 7 | /// then passed back to Jsrt in the provided callback, JsProjectionCallback, by the application 8 | /// on the correct thread. 9 | /// 10 | /// 11 | /// Requires calling JsSetProjectionEnqueueCallback to receive callbacks. 12 | /// 13 | public struct JavaScriptProjectionCallbackContext 14 | { 15 | /// 16 | /// The reference. 17 | /// 18 | private readonly IntPtr reference; 19 | } 20 | 21 | /// 22 | /// The Jsrt callback which should be called with the context passed to JsProjectionEnqueueCallback on 23 | /// the correct thread. 24 | /// 25 | /// 26 | /// Requires calling JsSetProjectionEnqueueCallback to receive callbacks. 27 | /// 28 | /// The context originally received by a call to JsProjectionEnqueueCallback. 29 | public delegate void JavaScriptProjectionCallback(JavaScriptProjectionCallbackContext jsContext); 30 | 31 | /// 32 | /// The application callback which is called by Jsrt when a projection API is completed on 33 | /// a different thread than the original. 34 | /// 35 | /// 36 | /// Requires calling JsSetProjectionEnqueueCallback to receive callbacks. 37 | /// 38 | /// The callback to be invoked on the original thread. 39 | /// The applications context. 40 | /// The Jsrt context that must be passed into jsCallback. 41 | public delegate void JavaScriptProjectionEnqueueCallback(JavaScriptProjectionCallback jsCallback, JavaScriptProjectionCallbackContext jsContext, IntPtr callbackState); 42 | } 43 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptPromiseContinuationCallback.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | using System; 4 | 5 | /// 6 | /// A promise continuation callback. 7 | /// 8 | /// 9 | /// The host can specify a promise continuation callback in JsSetPromiseContinuationCallback. If 10 | /// a script creates a task to be run later, then the promise continuation callback will be called with 11 | /// the task and the task should be put in a FIFO queue, to be run when the current script is 12 | /// done executing. 13 | /// 14 | /// The task, represented as a JavaScript function. 15 | /// The data argument to be passed to the callback. 16 | public delegate void JavaScriptPromiseContinuationCallback(JavaScriptValue task, IntPtr callbackState); 17 | } 18 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptPropertyId.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | using System; 4 | 5 | /// 6 | /// A property identifier. 7 | /// 8 | /// 9 | /// Property identifiers are used to refer to properties of JavaScript objects instead of using 10 | /// strings. 11 | /// 12 | public struct JavaScriptPropertyId : IEquatable 13 | { 14 | /// 15 | /// The id. 16 | /// 17 | private readonly IntPtr id; 18 | 19 | /// 20 | /// Initializes a new instance of the struct. 21 | /// 22 | /// The ID. 23 | internal JavaScriptPropertyId(IntPtr id) 24 | { 25 | this.id = id; 26 | } 27 | 28 | /// 29 | /// Gets an invalid ID. 30 | /// 31 | public static JavaScriptPropertyId Invalid 32 | { 33 | get { return new JavaScriptPropertyId(IntPtr.Zero); } 34 | } 35 | 36 | /// 37 | /// Gets the name associated with the property ID. 38 | /// 39 | /// 40 | /// 41 | /// Requires an active script context. 42 | /// 43 | /// 44 | public string Name 45 | { 46 | get 47 | { 48 | string name; 49 | Native.ThrowIfError(Native.JsGetPropertyNameFromId(this, out name)); 50 | return name; 51 | } 52 | } 53 | 54 | /// 55 | /// Gets the property ID associated with the name. 56 | /// 57 | /// 58 | /// 59 | /// Property IDs are specific to a context and cannot be used across contexts. 60 | /// 61 | /// 62 | /// Requires an active script context. 63 | /// 64 | /// 65 | /// 66 | /// The name of the property ID to get or create. The name may consist of only digits. 67 | /// 68 | /// The property ID in this runtime for the given name. 69 | public static JavaScriptPropertyId FromString(string name) 70 | { 71 | JavaScriptPropertyId id; 72 | Native.ThrowIfError(Native.JsGetPropertyIdFromName(name, out id)); 73 | return id; 74 | } 75 | 76 | /// 77 | /// The equality operator for property IDs. 78 | /// 79 | /// The first property ID to compare. 80 | /// The second property ID to compare. 81 | /// Whether the two property IDs are the same. 82 | public static bool operator ==(JavaScriptPropertyId left, JavaScriptPropertyId right) 83 | { 84 | return left.Equals(right); 85 | } 86 | 87 | /// 88 | /// The inequality operator for property IDs. 89 | /// 90 | /// The first property ID to compare. 91 | /// The second property ID to compare. 92 | /// Whether the two property IDs are not the same. 93 | public static bool operator !=(JavaScriptPropertyId left, JavaScriptPropertyId right) 94 | { 95 | return !left.Equals(right); 96 | } 97 | 98 | /// 99 | /// Checks for equality between property IDs. 100 | /// 101 | /// The other property ID to compare. 102 | /// Whether the two property IDs are the same. 103 | public bool Equals(JavaScriptPropertyId other) 104 | { 105 | return id == other.id; 106 | } 107 | 108 | /// 109 | /// Checks for equality between property IDs. 110 | /// 111 | /// The other property ID to compare. 112 | /// Whether the two property IDs are the same. 113 | public override bool Equals(object obj) 114 | { 115 | if (ReferenceEquals(null, obj)) 116 | { 117 | return false; 118 | } 119 | 120 | return obj is JavaScriptPropertyId && Equals((JavaScriptPropertyId)obj); 121 | } 122 | 123 | /// 124 | /// The hash code. 125 | /// 126 | /// The hash code of the property ID. 127 | public override int GetHashCode() 128 | { 129 | return id.ToInt32(); 130 | } 131 | 132 | /// 133 | /// Converts the property ID to a string. 134 | /// 135 | /// The name of the property ID. 136 | public override string ToString() 137 | { 138 | return Name; 139 | } 140 | } 141 | } -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptPropertyIdType.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | /// 4 | /// Type enumeration of a JavaScript property 5 | /// 6 | public enum JavaScriptPropertyIdType 7 | { 8 | /// 9 | /// Type enumeration of a JavaScript string property 10 | /// 11 | String, 12 | /// 13 | /// Type enumeration of a JavaScript symbol property 14 | /// 15 | Symbol 16 | }; 17 | } -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptRuntime.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | using System; 4 | 5 | /// 6 | /// A Chakra runtime. 7 | /// 8 | /// 9 | /// 10 | /// Each Chakra runtime has its own independent execution engine, JIT compiler, and garbage 11 | /// collected heap. As such, each runtime is completely isolated from other runtimes. 12 | /// 13 | /// 14 | /// Runtimes can be used on any thread, but only one thread can call into a runtime at any 15 | /// time. 16 | /// 17 | /// 18 | /// NOTE: A JavaScriptRuntime, unlike other objects in the Chakra hosting API, is not 19 | /// garbage collected since it contains the garbage collected heap itself. A runtime will 20 | /// continue to exist until Dispose is called. 21 | /// 22 | /// 23 | public struct JavaScriptRuntime : IDisposable 24 | { 25 | /// 26 | /// The handle. 27 | /// 28 | private IntPtr handle; 29 | 30 | /// 31 | /// Gets a value indicating whether the runtime is valid. 32 | /// 33 | public bool IsValid 34 | { 35 | get { return handle != IntPtr.Zero; } 36 | } 37 | 38 | /// 39 | /// Gets the current memory usage for a runtime. 40 | /// 41 | /// 42 | /// Memory usage can be always be retrieved, regardless of whether or not the runtime is active 43 | /// on another thread. 44 | /// 45 | public UIntPtr MemoryUsage 46 | { 47 | get 48 | { 49 | UIntPtr memoryUsage; 50 | Native.ThrowIfError(Native.JsGetRuntimeMemoryUsage(this, out memoryUsage)); 51 | return memoryUsage; 52 | } 53 | } 54 | 55 | /// 56 | /// Gets or sets the current memory limit for a runtime. 57 | /// 58 | /// 59 | /// The memory limit of a runtime can be always be retrieved, regardless of whether or not the 60 | /// runtime is active on another thread. 61 | /// 62 | public UIntPtr MemoryLimit 63 | { 64 | get 65 | { 66 | UIntPtr memoryLimit; 67 | Native.ThrowIfError(Native.JsGetRuntimeMemoryLimit(this, out memoryLimit)); 68 | return memoryLimit; 69 | } 70 | 71 | set 72 | { 73 | Native.ThrowIfError(Native.JsSetRuntimeMemoryLimit(this, value)); 74 | } 75 | } 76 | 77 | /// 78 | /// Gets or sets a value indicating whether script execution is disabled in the runtime. 79 | /// 80 | public bool Disabled 81 | { 82 | get 83 | { 84 | bool isDisabled; 85 | Native.ThrowIfError(Native.JsIsRuntimeExecutionDisabled(this, out isDisabled)); 86 | return isDisabled; 87 | } 88 | 89 | set 90 | { 91 | Native.ThrowIfError(value 92 | ? Native.JsDisableRuntimeExecution(this) 93 | : Native.JsEnableRuntimeExecution(this)); 94 | } 95 | } 96 | 97 | /// 98 | /// Creates a new runtime. 99 | /// 100 | /// The attributes of the runtime to be created. 101 | /// The version of the runtime to be created. 102 | /// The thread service for the runtime. Can be null. 103 | /// The runtime created. 104 | public static JavaScriptRuntime Create(JavaScriptRuntimeAttributes attributes, JavaScriptRuntimeVersion version, JavaScriptThreadServiceCallback threadServiceCallback) 105 | { 106 | JavaScriptRuntime handle; 107 | Native.ThrowIfError(Native.JsCreateRuntime(attributes, threadServiceCallback, out handle)); 108 | return handle; 109 | } 110 | 111 | /// 112 | /// Creates a new runtime. 113 | /// 114 | /// The attributes of the runtime to be created. 115 | /// The version of the runtime to be created. 116 | /// The runtime created. 117 | public static JavaScriptRuntime Create(JavaScriptRuntimeAttributes attributes, JavaScriptRuntimeVersion version) 118 | { 119 | return Create(attributes, version, null); 120 | } 121 | 122 | /// 123 | /// Creates a new runtime. 124 | /// 125 | /// The runtime created. 126 | public static JavaScriptRuntime Create() 127 | { 128 | return Create(JavaScriptRuntimeAttributes.None, JavaScriptRuntimeVersion.Version11, null); 129 | } 130 | 131 | /// 132 | /// Disposes a runtime. 133 | /// 134 | /// 135 | /// Once a runtime has been disposed, all resources owned by it are invalid and cannot be used. 136 | /// If the runtime is active (i.e. it is set to be current on a particular thread), it cannot 137 | /// be disposed. 138 | /// 139 | public void Dispose() 140 | { 141 | if (IsValid) 142 | { 143 | Native.ThrowIfError(Native.JsDisposeRuntime(this)); 144 | } 145 | 146 | handle = IntPtr.Zero; 147 | } 148 | 149 | /// 150 | /// Performs a full garbage collection. 151 | /// 152 | public void CollectGarbage() 153 | { 154 | Native.ThrowIfError(Native.JsCollectGarbage(this)); 155 | } 156 | 157 | /// 158 | /// Sets a memory allocation callback for specified runtime 159 | /// 160 | /// 161 | /// 162 | /// Registering a memory allocation callback will cause the runtime to call back to the host 163 | /// whenever it acquires memory from, or releases memory to, the OS. The callback routine is 164 | /// called before the runtime memory manager allocates a block of memory. The allocation will 165 | /// be rejected if the callback returns false. The runtime memory manager will also invoke the 166 | /// callback routine after freeing a block of memory, as well as after allocation failures. 167 | /// 168 | /// 169 | /// The callback is invoked on the current runtime execution thread, therefore execution is 170 | /// blocked until the callback completes. 171 | /// 172 | /// 173 | /// The return value of the callback is not stored; previously rejected allocations will not 174 | /// prevent the runtime from invoking the callback again later for new memory allocations. 175 | /// 176 | /// 177 | /// 178 | /// User provided state that will be passed back to the callback. 179 | /// 180 | /// 181 | /// Memory allocation callback to be called for memory allocation events. 182 | /// 183 | public void SetMemoryAllocationCallback(IntPtr callbackState, JavaScriptMemoryAllocationCallback allocationCallback) 184 | { 185 | Native.ThrowIfError(Native.JsSetRuntimeMemoryAllocationCallback(this, callbackState, allocationCallback)); 186 | } 187 | 188 | /// 189 | /// Sets a callback function that is called by the runtime before garbage collection. 190 | /// 191 | /// 192 | /// 193 | /// The callback is invoked on the current runtime execution thread, therefore execution is 194 | /// blocked until the callback completes. 195 | /// 196 | /// 197 | /// The callback can be used by hosts to prepare for garbage collection. For example, by 198 | /// releasing unnecessary references on Chakra objects. 199 | /// 200 | /// 201 | /// 202 | /// User provided state that will be passed back to the callback. 203 | /// 204 | /// The callback function being set. 205 | public void SetBeforeCollectCallback(IntPtr callbackState, JavaScriptBeforeCollectCallback beforeCollectCallback) 206 | { 207 | Native.ThrowIfError(Native.JsSetRuntimeBeforeCollectCallback(this, callbackState, beforeCollectCallback)); 208 | } 209 | 210 | /// 211 | /// Creates a script context for running scripts. 212 | /// 213 | /// 214 | /// Each script context has its own global object that is isolated from all other script 215 | /// contexts. 216 | /// 217 | /// The created script context. 218 | public JavaScriptContext CreateContext() 219 | { 220 | JavaScriptContext reference; 221 | Native.ThrowIfError(Native.JsCreateContext(this, out reference)); 222 | return reference; 223 | } 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptRuntimeAttributes.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | using System; 4 | using System.Diagnostics.CodeAnalysis; 5 | 6 | /// 7 | /// Attributes of a runtime. 8 | /// 9 | [Flags] 10 | public enum JavaScriptRuntimeAttributes 11 | { 12 | /// 13 | /// No special attributes. 14 | /// 15 | None = 0x00000000, 16 | 17 | /// 18 | /// The runtime will not do any work (such as garbage collection) on background threads. 19 | /// 20 | DisableBackgroundWork = 0x00000001, 21 | 22 | /// 23 | /// The runtime should support reliable script interruption. This increases the number of 24 | /// places where the runtime will check for a script interrupt request at the cost of a 25 | /// small amount of runtime performance. 26 | /// 27 | AllowScriptInterrupt = 0x00000002, 28 | 29 | /// 30 | /// Host will call Idle, so enable idle processing. Otherwise, the runtime will manage 31 | /// memory slightly more aggressively. 32 | /// 33 | EnableIdleProcessing = 0x00000004, 34 | 35 | /// 36 | /// Runtime will not generate native code. 37 | /// 38 | DisableNativeCodeGeneration = 0x00000008, 39 | 40 | /// 41 | /// Using Eval or Function constructor will throw an exception. 42 | /// 43 | [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "Eval is a valid function name.")] 44 | DisableEval = 0x00000010, 45 | 46 | /// 47 | /// Runtime will enable all experimental features. 48 | /// 49 | /// 50 | EnableExperimentalFeatures = 0x00000020, 51 | 52 | /// 53 | /// Calling JsSetException will also dispatch the exception to the script debugger 54 | /// (if any) giving the debugger a chance to break on the exception. 55 | /// 56 | DispatchSetExceptionsToDebugger = 0x00000040 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptRuntimeVersion.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | /// 4 | /// Version of the runtime. 5 | /// 6 | public enum JavaScriptRuntimeVersion 7 | { 8 | /// 9 | /// Create runtime with IE10 version. 10 | /// 11 | Version10 = 0, 12 | 13 | /// 14 | /// Create runtime with IE11 version. 15 | /// 16 | Version11 = 1, 17 | 18 | /// 19 | /// Create runtime with highest version present on the machine at runtime. 20 | /// 21 | VersionEdge = -1, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptScriptException.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | using System; 4 | using System.Runtime.Serialization; 5 | 6 | /// 7 | /// A script exception. 8 | /// 9 | public sealed class JavaScriptScriptException : JavaScriptException 10 | { 11 | /// 12 | /// The error. 13 | /// 14 | private readonly JavaScriptValue error; 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | /// The error code returned. 20 | /// The JavaScript error object. 21 | public JavaScriptScriptException(JavaScriptErrorCode code, JavaScriptValue error) : 22 | this(code, error, "JavaScript Exception") 23 | { 24 | } 25 | 26 | /// 27 | /// Initializes a new instance of the class. 28 | /// 29 | /// The error code returned. 30 | /// The JavaScript error object. 31 | /// The error message. 32 | public JavaScriptScriptException(JavaScriptErrorCode code, JavaScriptValue error, string message) : 33 | base(code, message) 34 | { 35 | this.error = error; 36 | } 37 | 38 | /// 39 | /// Initializes a new instance of the class. 40 | /// 41 | /// The serialization info. 42 | /// The streaming context. 43 | private JavaScriptScriptException(string message, Exception innerException) : 44 | base(message, innerException) 45 | { 46 | } 47 | 48 | /// 49 | /// Gets a JavaScript object representing the script error. 50 | /// 51 | public JavaScriptValue Error 52 | { 53 | get 54 | { 55 | return error; 56 | } 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptSerializedScriptLoadSourceCallback.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | using System; 4 | 5 | /// 6 | /// Called by the runtime to load the source code of the serialized script. 7 | /// The caller must keep the script buffer valid until the JsSerializedScriptUnloadCallback. 8 | /// 9 | /// The context passed to Js[Parse|Run]SerializedScriptWithCallback 10 | /// The script returned. 11 | /// 12 | /// true if the operation succeeded, false otherwise. 13 | /// 14 | public delegate bool JavaScriptSerializedScriptLoadSourceCallback(JavaScriptSourceContext sourceContext, out string scriptBuffer); 15 | } 16 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptSerializedScriptUnloadCallback.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | using System; 4 | 5 | /// 6 | /// Called by the runtime when it is finished with all resources related to the script execution. 7 | /// The caller should free the source if loaded, the byte code, and the context at this time. 8 | /// 9 | /// The context passed to Js[Parse|Run]SerializedScriptWithCallback 10 | public delegate void JavaScriptSerializedScriptUnloadCallback(JavaScriptSourceContext sourceContext); 11 | } 12 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptSourceContext.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | using System; 4 | 5 | /// 6 | /// A cookie that identifies a script for debugging purposes. 7 | /// 8 | public struct JavaScriptSourceContext : IEquatable 9 | { 10 | /// 11 | /// The context. 12 | /// 13 | private readonly IntPtr context; 14 | 15 | /// 16 | /// Initializes a new instance of the struct. 17 | /// 18 | /// The context. 19 | private JavaScriptSourceContext(IntPtr context) 20 | { 21 | this.context = context; 22 | } 23 | 24 | /// 25 | /// Gets an empty source context. 26 | /// 27 | public static JavaScriptSourceContext None 28 | { 29 | get { return new JavaScriptSourceContext(new IntPtr(-1)); } 30 | } 31 | 32 | /// 33 | /// The equality operator for source contexts. 34 | /// 35 | /// The first source context to compare. 36 | /// The second source context to compare. 37 | /// Whether the two source contexts are the same. 38 | public static bool operator ==(JavaScriptSourceContext left, JavaScriptSourceContext right) 39 | { 40 | return left.Equals(right); 41 | } 42 | 43 | /// 44 | /// The inequality operator for source contexts. 45 | /// 46 | /// The first source context to compare. 47 | /// The second source context to compare. 48 | /// Whether the two source contexts are not the same. 49 | public static bool operator !=(JavaScriptSourceContext left, JavaScriptSourceContext right) 50 | { 51 | return !left.Equals(right); 52 | } 53 | 54 | /// 55 | /// Subtracts an offset from the value of the source context. 56 | /// 57 | /// The source context to subtract the offset from. 58 | /// The offset to subtract. 59 | /// A new source context that reflects the subtraction of the offset from the context. 60 | public static JavaScriptSourceContext operator -(JavaScriptSourceContext context, int offset) 61 | { 62 | return FromIntPtr(context.context - offset); 63 | } 64 | 65 | /// 66 | /// Subtracts an offset from the value of the source context. 67 | /// 68 | /// The source context to subtract the offset from. 69 | /// The offset to subtract. 70 | /// A new source context that reflects the subtraction of the offset from the context. 71 | public static JavaScriptSourceContext Subtract(JavaScriptSourceContext left, int right) 72 | { 73 | return left - right; 74 | } 75 | 76 | /// 77 | /// Decrements the value of the source context. 78 | /// 79 | /// The source context to decrement. 80 | /// A new source context that reflects the decrementing of the context. 81 | public static JavaScriptSourceContext operator --(JavaScriptSourceContext context) 82 | { 83 | return FromIntPtr(context.context - 1); 84 | } 85 | 86 | /// 87 | /// Decrements the value of the source context. 88 | /// 89 | /// The source context to decrement. 90 | /// A new source context that reflects the decrementing of the context. 91 | public static JavaScriptSourceContext Decrement(JavaScriptSourceContext left) 92 | { 93 | return --left; 94 | } 95 | 96 | /// 97 | /// Adds an offset from the value of the source context. 98 | /// 99 | /// The source context to add the offset to. 100 | /// The offset to add. 101 | /// A new source context that reflects the addition of the offset to the context. 102 | public static JavaScriptSourceContext operator +(JavaScriptSourceContext context, int offset) 103 | { 104 | return FromIntPtr(context.context + offset); 105 | } 106 | 107 | /// 108 | /// Adds an offset from the value of the source context. 109 | /// 110 | /// The source context to add the offset to. 111 | /// The offset to add. 112 | /// A new source context that reflects the addition of the offset to the context. 113 | public static JavaScriptSourceContext Add(JavaScriptSourceContext left, int right) 114 | { 115 | return left + right; 116 | } 117 | 118 | /// 119 | /// Increments the value of the source context. 120 | /// 121 | /// The source context to increment. 122 | /// A new source context that reflects the incrementing of the context. 123 | public static JavaScriptSourceContext operator ++(JavaScriptSourceContext context) 124 | { 125 | return FromIntPtr(context.context + 1); 126 | } 127 | 128 | /// 129 | /// Increments the value of the source context. 130 | /// 131 | /// The source context to increment. 132 | /// A new source context that reflects the incrementing of the context. 133 | public static JavaScriptSourceContext Increment(JavaScriptSourceContext left) 134 | { 135 | return ++left; 136 | } 137 | 138 | /// 139 | /// Creates a new source context. 140 | /// 141 | /// 142 | /// The cookie for the source context. 143 | /// 144 | /// The new source context. 145 | public static JavaScriptSourceContext FromIntPtr(IntPtr cookie) 146 | { 147 | return new JavaScriptSourceContext(cookie); 148 | } 149 | 150 | /// 151 | /// Checks for equality between source contexts. 152 | /// 153 | /// The other source context to compare. 154 | /// Whether the two source contexts are the same. 155 | public bool Equals(JavaScriptSourceContext other) 156 | { 157 | return context == other.context; 158 | } 159 | 160 | /// 161 | /// Checks for equality between source contexts. 162 | /// 163 | /// The other source context to compare. 164 | /// Whether the two source contexts are the same. 165 | public override bool Equals(object obj) 166 | { 167 | if (ReferenceEquals(null, obj)) 168 | { 169 | return false; 170 | } 171 | 172 | return obj is JavaScriptSourceContext && Equals((JavaScriptSourceContext)obj); 173 | } 174 | 175 | /// 176 | /// The hash code. 177 | /// 178 | /// The hash code of the source context. 179 | public override int GetHashCode() 180 | { 181 | return context.ToInt32(); 182 | } 183 | } 184 | } -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptThreadServiceCallback.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | using System; 4 | 5 | /// 6 | /// A thread service callback. 7 | /// 8 | /// 9 | /// The host can specify a background thread service when creating a runtime. If 10 | /// specified, then background work items will be passed to the host using this callback. The 11 | /// host is expected to either begin executing the background work item immediately and return 12 | /// true or return false and the runtime will handle the work item in-thread. 13 | /// 14 | /// The callback for the background work item. 15 | /// The data argument to be passed to the callback. 16 | /// Whether the thread service will execute the callback. 17 | public delegate bool JavaScriptThreadServiceCallback(JavaScriptBackgroundWorkItemCallback callbackFunction, IntPtr callbackData); 18 | } 19 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptTypedArrayType.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | /// 4 | /// The type of a typed JavaScript array. 5 | /// 6 | public enum JavaScriptTypedArrayType 7 | { 8 | /// 9 | /// An int8 array. 10 | /// 11 | Int8, 12 | /// 13 | /// An uint8 array. 14 | /// 15 | Uint8, 16 | /// 17 | /// An uint8 clamped array. 18 | /// 19 | Uint8Clamped, 20 | /// 21 | /// An int16 array. 22 | /// 23 | Int16, 24 | /// 25 | /// An uint16 array. 26 | /// 27 | Uint16, 28 | /// 29 | /// An int32 array. 30 | /// 31 | Int32, 32 | /// 33 | /// An uint32 array. 34 | /// 35 | Uint32, 36 | /// 37 | /// A float32 array. 38 | /// 39 | Float32, 40 | /// 41 | /// A float64 array. 42 | /// 43 | Float64 44 | }; 45 | } -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptUsageException.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | using System; 4 | using System.Runtime.Serialization; 5 | 6 | /// 7 | /// An API usage exception occurred. 8 | /// 9 | public sealed class JavaScriptUsageException : JavaScriptException 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// The error code returned. 15 | public JavaScriptUsageException(JavaScriptErrorCode code) : 16 | this(code, "A fatal exception has occurred in a JavaScript runtime") 17 | { 18 | } 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | /// The error code returned. 24 | /// The error message. 25 | public JavaScriptUsageException(JavaScriptErrorCode code, string message) : 26 | base(code, message) 27 | { 28 | } 29 | 30 | /// 31 | /// Initializes a new instance of the class. 32 | /// 33 | /// The serialization info. 34 | /// The streaming context. 35 | private JavaScriptUsageException(string message, Exception innerException) : 36 | base(message, innerException) 37 | { 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Hosting/JavaScriptValueType.cs: -------------------------------------------------------------------------------- 1 | namespace ChakraHost.Hosting 2 | { 3 | /// 4 | /// The JavaScript type of a JavaScriptValue. 5 | /// 6 | public enum JavaScriptValueType 7 | { 8 | /// 9 | /// The value is the undefined value. 10 | /// 11 | Undefined = 0, 12 | 13 | /// 14 | /// The value is the null value. 15 | /// 16 | Null = 1, 17 | 18 | /// 19 | /// The value is a JavaScript number value. 20 | /// 21 | Number = 2, 22 | 23 | /// 24 | /// The value is a JavaScript string value. 25 | /// 26 | String = 3, 27 | 28 | /// 29 | /// The value is a JavaScript Boolean value. 30 | /// 31 | Boolean = 4, 32 | 33 | /// 34 | /// The value is a JavaScript object value. 35 | /// 36 | Object = 5, 37 | 38 | /// 39 | /// The value is a JavaScript function object value. 40 | /// 41 | Function = 6, 42 | 43 | /// 44 | /// The value is a JavaScript error object value. 45 | /// 46 | Error = 7, 47 | 48 | /// 49 | /// The value is a JavaScript array object value. 50 | /// 51 | Array = 8, 52 | 53 | /// 54 | /// The value is a JavaScript array object value. 55 | /// 56 | Symbol = 9, 57 | 58 | /// 59 | /// The value is a JavaScript ArrayBuffer object value. 60 | /// 61 | ArrayBuffer = 10, 62 | 63 | /// 64 | /// The value is a JavaScript typed array object value. 65 | /// 66 | TypedArray = 11, 67 | 68 | /// 69 | /// The value is a JavaScript DataView object value. 70 | /// 71 | DataView = 12, 72 | } 73 | } -------------------------------------------------------------------------------- /Electrino/win10/Electrino/JS/JSApp.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using ChakraHost.Hosting; 7 | using System.Diagnostics; 8 | 9 | namespace Electrino.JS 10 | { 11 | class JSApp : AbstractJSModule 12 | { 13 | private Dictionary>> listeners = new Dictionary>>(); 14 | private static JSApp instance; 15 | public JSApp() : base("app") 16 | { 17 | instance = this; 18 | AttachMethod(On, "on"); 19 | AttachMethod(Quit, "quit"); 20 | } 21 | 22 | public static JSApp GetInstance() 23 | { 24 | return instance; 25 | } 26 | 27 | private JavaScriptValue On(JavaScriptValue callee, bool isConstructCall, JavaScriptValue[] arguments, ushort argumentCount, IntPtr callbackData) 28 | { 29 | string key = JSValToString(arguments[1]); 30 | List> eventListeners; 31 | if (listeners.ContainsKey(key)) 32 | { 33 | listeners.TryGetValue(key, out eventListeners); 34 | } 35 | else 36 | { 37 | eventListeners = new List>(); 38 | listeners.Add(key, eventListeners); 39 | } 40 | eventListeners.Add(Tuple.Create(arguments[2], arguments[0])); 41 | arguments[2].AddRef(); 42 | return JavaScriptValue.Undefined; 43 | } 44 | 45 | public void Call(string key) 46 | { 47 | List> eventListeners; 48 | listeners.TryGetValue(key, out eventListeners); 49 | if (eventListeners != null) 50 | { 51 | foreach (Tuple listener in eventListeners) 52 | { 53 | listener.Item1.CallFunction(new JavaScriptValue[] { listener.Item2 }); 54 | } 55 | } 56 | } 57 | 58 | private JavaScriptValue Quit(JavaScriptValue callee, bool isConstructCall, JavaScriptValue[] arguments, ushort argumentCount, IntPtr callbackData) 59 | { 60 | Windows.UI.Xaml.Application.Current.Exit(); 61 | return JavaScriptValue.Undefined; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/JS/JSBrowserWindow.cs: -------------------------------------------------------------------------------- 1 | using ChakraHost.Hosting; 2 | using Newtonsoft.Json.Linq; 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | namespace Electrino.JS 7 | { 8 | class JSBrowserWindow : AbstractJSModule 9 | { 10 | private static JSBrowserWindow instance; 11 | private static List windows; 12 | 13 | public JSBrowserWindow() : base("BrowserWindow", true) 14 | { 15 | instance = this; 16 | windows = new List(); 17 | } 18 | 19 | public static JSBrowserWindow GetInstance() 20 | { 21 | return instance; 22 | } 23 | 24 | // TODO support sending event to specific browser window 25 | public void CallAll(string key) 26 | { 27 | foreach (JSBrowserWindowInstance window in windows) 28 | { 29 | window.Call(key); 30 | } 31 | } 32 | 33 | protected override JavaScriptValue Main(JavaScriptValue callee, bool isConstructCall, JavaScriptValue[] arguments, ushort argumentCount, IntPtr callbackData) 34 | { 35 | if (!isConstructCall) 36 | { 37 | return JavaScriptValue.CreateTypeError(JavaScriptValue.FromString("BrowserWindow must be constructed")); 38 | } 39 | 40 | JToken options; 41 | try 42 | { 43 | options = JavaScriptValueToJTokenConverter.Convert(arguments[1]); 44 | } 45 | catch (Exception) 46 | { 47 | // If no object is passed to the BrowserWindow constructor we'll provide a default one 48 | options = JObject.Parse("{ width: 800, height: 600 }"); 49 | } 50 | 51 | JSBrowserWindowInstance instance = new JSBrowserWindowInstance(options); 52 | windows.Add(instance); 53 | return instance.GetModule(); 54 | } 55 | } 56 | 57 | class JSBrowserWindowInstance : AbstractJSModule 58 | { 59 | private JToken options; 60 | private Dictionary>> listeners = new Dictionary>>(); 61 | 62 | public JSBrowserWindowInstance(JToken options) : base("BrowserWindowInstance") 63 | { 64 | const int defaultWindowWidth = 800, defaultWindowHeight = 600; 65 | int width = 0, height = 0; 66 | this.options = options; 67 | 68 | AttachMethod(LoadURL, "loadURL"); 69 | AttachMethod(On, "on"); 70 | 71 | Int32.TryParse(options["width"].ToString(), out width); 72 | Int32.TryParse(options["height"].ToString(), out height); 73 | 74 | if (width <= 0) width = defaultWindowWidth; 75 | if (height <= 0) height = defaultWindowHeight; 76 | 77 | App.NewWindow(width, height); 78 | } 79 | protected JavaScriptValue LoadURL(JavaScriptValue callee, bool isConstructCall, JavaScriptValue[] arguments, ushort argumentCount, IntPtr callbackData) 80 | { 81 | string url = JSValToString(arguments[1]); 82 | if (!MainPage.LoadURL(url)) 83 | { 84 | App.Log("Failed to load url " + url); 85 | } 86 | return JavaScriptValue.Undefined; 87 | } 88 | 89 | private JavaScriptValue On(JavaScriptValue callee, bool isConstructCall, JavaScriptValue[] arguments, ushort argumentCount, IntPtr callbackData) 90 | { 91 | string key = JSValToString(arguments[1]); 92 | List> eventListeners; 93 | if (listeners.ContainsKey(key)) 94 | { 95 | listeners.TryGetValue(key, out eventListeners); 96 | } 97 | else 98 | { 99 | eventListeners = new List>(); 100 | listeners.Add(key, eventListeners); 101 | } 102 | eventListeners.Add(Tuple.Create(arguments[2], arguments[0])); 103 | arguments[2].AddRef(); 104 | return JavaScriptValue.Undefined; 105 | } 106 | 107 | public void Call(string key) 108 | { 109 | List> eventListeners; 110 | listeners.TryGetValue(key, out eventListeners); 111 | if (eventListeners != null) 112 | { 113 | foreach (Tuple listener in eventListeners) 114 | { 115 | listener.Item1.CallFunction(new JavaScriptValue[] { listener.Item2 }); 116 | } 117 | } 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/JS/JSConsole.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Diagnostics; 7 | using ChakraHost.Hosting; 8 | 9 | namespace Electrino.JS 10 | { 11 | class JSConsole : AbstractJSModule 12 | { 13 | public JSConsole() : base("console") 14 | { 15 | AttachMethod(Log, "log"); 16 | } 17 | 18 | private static JavaScriptValue Log(JavaScriptValue callee, bool isConstructCall, JavaScriptValue[] arguments, ushort argumentCount, IntPtr callbackData) 19 | { 20 | string[] args = new string[arguments.Length - 1]; 21 | for (int i = 1; i < arguments.Length; i++) 22 | { 23 | args[i - 1] = JSValToString(arguments[i]); 24 | } 25 | App.Log(String.Join(", ", args)); 26 | return JavaScriptValue.Undefined; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/JS/JSElectrino.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using ChakraHost.Hosting; 7 | 8 | namespace Electrino.JS 9 | { 10 | class JSElectrino : AbstractJSModule 11 | { 12 | public JSElectrino() : base("electrino") 13 | { 14 | AttachModule(new JSApp()); 15 | AttachModule(new JSBrowserWindow()); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/JS/JSModule.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using ChakraHost.Hosting; 7 | using System.Diagnostics; 8 | using System.Runtime.InteropServices; 9 | 10 | namespace Electrino.JS 11 | { 12 | abstract class AbstractJSModule 13 | { 14 | private JavaScriptValue module; 15 | private string id; 16 | private bool asFunction; 17 | 18 | public static void AttachModule(JavaScriptValue module, AbstractJSModule subModule) 19 | { 20 | if (Native.JsSetProperty(module, JavaScriptPropertyId.FromString(subModule.GetId()), 21 | subModule.GetModule(), false) != JavaScriptErrorCode.NoError) 22 | { 23 | throw new Exception("Failed to attach module"); 24 | } 25 | } 26 | 27 | public static void AttachModule(AbstractJSModule module, AbstractJSModule subModule) 28 | { 29 | AttachModule(module.GetModule(), subModule); 30 | } 31 | 32 | 33 | public static void AttachMethod(JavaScriptValue module, JavaScriptNativeFunction method, string id) 34 | { 35 | JavaScriptValue requireToString; 36 | if (Native.JsCreateFunction(method, IntPtr.Zero, out requireToString) != JavaScriptErrorCode.NoError) 37 | { 38 | throw new Exception("Failed to create method"); 39 | } 40 | if (Native.JsSetProperty(module, JavaScriptPropertyId.FromString(id), requireToString, false) 41 | != JavaScriptErrorCode.NoError) 42 | { 43 | throw new Exception("Failed to define tostring on require"); 44 | } 45 | } 46 | 47 | public static void AttachMethod(AbstractJSModule module, JavaScriptNativeFunction method, string id) 48 | { 49 | AttachMethod(module.GetModule(), method, id); 50 | } 51 | 52 | 53 | public static void AttachProperty(JavaScriptValue module, JavaScriptValue property, string id) 54 | { 55 | if (Native.JsSetProperty(module, JavaScriptPropertyId.FromString(id), 56 | property, false) != JavaScriptErrorCode.NoError) 57 | { 58 | throw new Exception("Failed to attach property"); 59 | } 60 | } 61 | 62 | public static void AttachProperty(AbstractJSModule module, JavaScriptValue method, string id) 63 | { 64 | AttachProperty(module.GetModule(), method, id); 65 | } 66 | 67 | public static string JSValToString(JavaScriptValue val) 68 | { 69 | val = val.ConvertToString(); 70 | IntPtr returnValue = IntPtr.Zero; 71 | UIntPtr stringLength; 72 | if (Native.JsStringToPointer(val, out returnValue, out stringLength) != JavaScriptErrorCode.NoError) 73 | { 74 | throw new Exception("Failed to convert return value."); 75 | } 76 | return Marshal.PtrToStringUni(returnValue); 77 | } 78 | 79 | /// 80 | /// Construct a module either as an Object or function 81 | /// If function is used then the class must override the Main method 82 | /// 83 | /// 84 | /// 85 | public AbstractJSModule(string id, bool asFunction = false) 86 | { 87 | this.id = id; 88 | this.asFunction = asFunction; 89 | 90 | if (asFunction) 91 | { 92 | if (Native.JsCreateFunction(Main, IntPtr.Zero, out module) != JavaScriptErrorCode.NoError) 93 | { 94 | throw new Exception("Failed to create function"); 95 | } 96 | } 97 | else 98 | { 99 | if (Native.JsCreateObject(out module) != JavaScriptErrorCode.NoError) 100 | { 101 | throw new Exception("Failed to create module"); 102 | } 103 | } 104 | 105 | AttachMethod(ToString, "toString"); 106 | } 107 | 108 | public void AttachModule(AbstractJSModule subModule) 109 | { 110 | AttachModule(this, subModule); 111 | } 112 | 113 | public void AttachMethod(JavaScriptNativeFunction method, string id) 114 | { 115 | AttachMethod(this, method, id); 116 | } 117 | 118 | public void AttachProperty(JavaScriptValue property, string id) 119 | { 120 | AttachProperty(this, property, id); 121 | } 122 | 123 | public JavaScriptValue GetModule() 124 | { 125 | return module; 126 | } 127 | 128 | public string GetId() 129 | { 130 | return id; 131 | } 132 | 133 | protected JavaScriptValue ToString(JavaScriptValue callee, bool isConstructCall, JavaScriptValue[] arguments, ushort argumentCount, IntPtr callbackData) 134 | { 135 | // TODO: Track members and list recursively 136 | return JavaScriptValue.FromString("[" + (asFunction ? "Function" : "Module") + ": " + id + "]"); 137 | } 138 | 139 | protected virtual JavaScriptValue Main(JavaScriptValue callee, bool isConstructCall, JavaScriptValue[] arguments, ushort argumentCount, IntPtr callbackData) 140 | { 141 | return JavaScriptValue.Undefined; 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/JS/JSPath.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using ChakraHost.Hosting; 7 | 8 | namespace Electrino.JS 9 | { 10 | class JSPath : AbstractJSModule 11 | { 12 | public JSPath() : base("path") 13 | { 14 | AttachMethod(Join, "join"); 15 | } 16 | 17 | private static JavaScriptValue Join(JavaScriptValue callee, bool isConstructCall, JavaScriptValue[] arguments, ushort argumentCount, IntPtr callbackData) 18 | { 19 | string[] args = new string[arguments.Length - 1]; 20 | for (int i = 1; i < arguments.Length; i++) 21 | { 22 | args[i - 1] = JSValToString(arguments[i]); 23 | } 24 | return JavaScriptValue.FromString(String.Join("\\", args)); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/JS/JSProcess.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using ChakraHost.Hosting; 7 | using Windows.ApplicationModel; 8 | 9 | namespace Electrino.JS 10 | { 11 | class JSProcess : AbstractJSModule 12 | { 13 | private Dictionary modules = new Dictionary(); 14 | 15 | public JSProcess() : base("process") 16 | { 17 | AttachProperty(JavaScriptValue.FromString("win32"), "platform"); 18 | AttachProperty(JavaScriptValue.FromString(Package.Current.Id.Architecture.ToString()), "arch"); 19 | AttachModule(new JSProcessVersions()); 20 | } 21 | } 22 | 23 | class JSProcessVersions : AbstractJSModule 24 | { 25 | private Dictionary modules = new Dictionary(); 26 | 27 | public JSProcessVersions() : base("versions") 28 | { 29 | AttachProperty(JavaScriptValue.FromString("electrino"), "0.1.0"); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/JS/JSRequire.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using ChakraHost.Hosting; 7 | 8 | namespace Electrino.JS 9 | { 10 | class JSRequire : AbstractJSModule 11 | { 12 | private Dictionary modules = new Dictionary(); 13 | 14 | public JSRequire() : base("require", true) 15 | { 16 | AddModule(new JSPath()); 17 | AddModule(new JSUrl()); 18 | AddModule(new JSElectrino()); 19 | } 20 | 21 | private void AddModule(AbstractJSModule module) 22 | { 23 | modules.Add(module.GetId(), module); 24 | } 25 | 26 | protected override JavaScriptValue Main(JavaScriptValue callee, bool isConstructCall, JavaScriptValue[] arguments, ushort argumentCount, IntPtr callbackData) 27 | { 28 | string moduleKey = AbstractJSModule.JSValToString(arguments[1]); 29 | AbstractJSModule module; 30 | if (!modules.TryGetValue(moduleKey, out module)) 31 | { 32 | return JavaScriptValue.Undefined; 33 | } 34 | return module.GetModule(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/JS/JSUrl.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using ChakraHost.Hosting; 7 | 8 | namespace Electrino.JS 9 | { 10 | class JSUrl : AbstractJSModule 11 | { 12 | public JSUrl() : base("url") 13 | { 14 | AttachMethod(Format, "format"); 15 | } 16 | 17 | private static JavaScriptValue Format(JavaScriptValue callee, bool isConstructCall, JavaScriptValue[] arguments, ushort argumentCount, IntPtr callbackData) 18 | { 19 | JavaScriptValue obj = arguments[1]; 20 | string pathName = JSValToString(obj.GetProperty(JavaScriptPropertyId.FromString("pathname"))).Replace("\\", "/"); 21 | string protocol = JSValToString(obj.GetProperty(JavaScriptPropertyId.FromString("protocol"))); 22 | return JavaScriptValue.FromString(protocol + "//" + pathName); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/JS/JTokenToJavaScriptValueConverter.cs: -------------------------------------------------------------------------------- 1 | using ChakraHost.Hosting; 2 | using Newtonsoft.Json.Linq; 3 | using System; 4 | 5 | namespace Electrino.JS 6 | { 7 | // Borrowed from: https://www.microsoft.com/reallifecode/2016/06/02/hybrid-apps-using-c-and-javascript-with-chakracore/ 8 | public sealed class JTokenToJavaScriptValueConverter 9 | { 10 | private static readonly JTokenToJavaScriptValueConverter s_instance = 11 | new JTokenToJavaScriptValueConverter(); 12 | 13 | private JTokenToJavaScriptValueConverter() { } 14 | 15 | public static JavaScriptValue Convert(JToken token) 16 | { 17 | return s_instance.Visit(token); 18 | } 19 | 20 | private JavaScriptValue Visit(JToken token) 21 | { 22 | if (token == null) 23 | throw new ArgumentNullException(nameof(token)); 24 | 25 | switch (token.Type) 26 | { 27 | case JTokenType.Array: 28 | return VisitArray((JArray)token); 29 | case JTokenType.Boolean: 30 | return VisitBoolean((JValue)token); 31 | case JTokenType.Float: 32 | return VisitFloat((JValue)token); 33 | case JTokenType.Integer: 34 | return VisitInteger((JValue)token); 35 | case JTokenType.Null: 36 | return VisitNull(token); 37 | case JTokenType.Object: 38 | return VisitObject((JObject)token); 39 | case JTokenType.String: 40 | return VisitString((JValue)token); 41 | case JTokenType.Undefined: 42 | return VisitUndefined(token); 43 | default: 44 | throw new NotSupportedException(); 45 | } 46 | } 47 | 48 | private JavaScriptValue VisitArray(JArray token) 49 | { 50 | var n = token.Count; 51 | var array = AddRef(JavaScriptValue.CreateArray((uint)n)); 52 | for (var i = 0; i < n; ++i) 53 | { 54 | var value = Visit(token[i]); 55 | array.SetIndexedProperty(JavaScriptValue.FromInt32(i), value); 56 | value.Release(); 57 | } 58 | 59 | return array; 60 | } 61 | 62 | private JavaScriptValue VisitBoolean(JValue token) 63 | { 64 | return token.Value() 65 | ? JavaScriptValue.True 66 | : JavaScriptValue.False; 67 | } 68 | 69 | private JavaScriptValue VisitFloat(JValue token) 70 | { 71 | return AddRef(JavaScriptValue.FromDouble(token.Value())); 72 | } 73 | 74 | private JavaScriptValue VisitInteger(JValue token) 75 | { 76 | return AddRef(JavaScriptValue.FromDouble(token.Value())); 77 | } 78 | 79 | private JavaScriptValue VisitNull(JToken token) 80 | { 81 | return JavaScriptValue.Null; 82 | } 83 | 84 | private JavaScriptValue VisitObject(JObject token) 85 | { 86 | var jsonObject = AddRef(JavaScriptValue.CreateObject()); 87 | foreach (var entry in token) 88 | { 89 | var value = Visit(entry.Value); 90 | var propertyId = JavaScriptPropertyId.FromString(entry.Key); 91 | jsonObject.SetProperty(propertyId, value, true); 92 | value.Release(); 93 | } 94 | 95 | return jsonObject; 96 | } 97 | 98 | private JavaScriptValue VisitString(JValue token) 99 | { 100 | return AddRef(JavaScriptValue.FromString(token.Value())); 101 | } 102 | 103 | private JavaScriptValue VisitUndefined(JToken token) 104 | { 105 | return JavaScriptValue.Undefined; 106 | } 107 | 108 | private JavaScriptValue AddRef(JavaScriptValue value) 109 | { 110 | value.AddRef(); 111 | return value; 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/JS/JavaScriptValueToJTokenConverter.cs: -------------------------------------------------------------------------------- 1 | using ChakraHost.Hosting; 2 | using Newtonsoft.Json.Linq; 3 | using System; 4 | 5 | namespace Electrino.JS 6 | { 7 | // Borrowed from: https://www.microsoft.com/reallifecode/2016/06/02/hybrid-apps-using-c-and-javascript-with-chakracore/ 8 | public sealed class JavaScriptValueToJTokenConverter 9 | { 10 | private static readonly JToken s_true = new JValue(true); 11 | private static readonly JToken s_false = new JValue(false); 12 | private static readonly JToken s_null = JValue.CreateNull(); 13 | private static readonly JToken s_undefined = JValue.CreateUndefined(); 14 | 15 | private static readonly JavaScriptValueToJTokenConverter s_instance = 16 | new JavaScriptValueToJTokenConverter(); 17 | 18 | private JavaScriptValueToJTokenConverter() { } 19 | 20 | public static JToken Convert(JavaScriptValue value) 21 | { 22 | return s_instance.Visit(value); 23 | } 24 | 25 | private JToken Visit(JavaScriptValue value) 26 | { 27 | switch (value.ValueType) 28 | { 29 | case JavaScriptValueType.Array: 30 | return VisitArray(value); 31 | case JavaScriptValueType.Boolean: 32 | return VisitBoolean(value); 33 | case JavaScriptValueType.Null: 34 | return VisitNull(value); 35 | case JavaScriptValueType.Number: 36 | return VisitNumber(value); 37 | case JavaScriptValueType.Object: 38 | return VisitObject(value); 39 | case JavaScriptValueType.String: 40 | return VisitString(value); 41 | case JavaScriptValueType.Undefined: 42 | return VisitUndefined(value); 43 | case JavaScriptValueType.Function: 44 | case JavaScriptValueType.Error: 45 | default: 46 | throw new NotSupportedException(); 47 | } 48 | } 49 | 50 | private JToken VisitArray(JavaScriptValue value) 51 | { 52 | var array = new JArray(); 53 | var propertyId = JavaScriptPropertyId.FromString("length"); 54 | var length = (int)value.GetProperty(propertyId).ToDouble(); 55 | for (var i = 0; i < length; ++i) 56 | { 57 | var index = JavaScriptValue.FromInt32(i); 58 | var element = value.GetIndexedProperty(index); 59 | array.Add(Visit(element)); 60 | } 61 | 62 | return array; 63 | } 64 | 65 | private JToken VisitBoolean(JavaScriptValue value) 66 | { 67 | return value.ToBoolean() ? s_true : s_false; 68 | } 69 | 70 | private JToken VisitNull(JavaScriptValue value) 71 | { 72 | return s_null; 73 | } 74 | 75 | private JToken VisitNumber(JavaScriptValue value) 76 | { 77 | var number = value.ToDouble(); 78 | 79 | return number % 1 == 0 80 | ? new JValue((long)number) 81 | : new JValue(number); 82 | } 83 | 84 | private JToken VisitObject(JavaScriptValue value) 85 | { 86 | var jsonObject = new JObject(); 87 | var properties = Visit(value.GetOwnPropertyNames()).ToObject(); 88 | foreach (var property in properties) 89 | { 90 | var propertyId = JavaScriptPropertyId.FromString(property); 91 | var propertyValue = value.GetProperty(propertyId); 92 | jsonObject.Add(property, Visit(propertyValue)); 93 | } 94 | 95 | return jsonObject; 96 | } 97 | 98 | private JToken VisitString(JavaScriptValue value) 99 | { 100 | return JValue.CreateString(value.ToString()); 101 | } 102 | 103 | private JToken VisitUndefined(JavaScriptValue value) 104 | { 105 | return s_undefined; 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/JavaScriptApp.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Collections; 7 | using System.Runtime.InteropServices; 8 | using ChakraHost.Hosting; 9 | 10 | namespace Electrino 11 | { 12 | class JavaScriptApp 13 | { 14 | private JavaScriptSourceContext currentSourceContext = JavaScriptSourceContext.FromIntPtr(IntPtr.Zero); 15 | private JavaScriptRuntime runtime; 16 | private JavaScriptContext context; 17 | private JS.AbstractJSModule console; 18 | private JS.AbstractJSModule require; 19 | private JS.AbstractJSModule process; 20 | private JavaScriptValue jsAppGlobalObject; 21 | private static Queue taskQueue = new Queue(); 22 | private static readonly JavaScriptPromiseContinuationCallback promiseContinuationDelegate = PromiseContinuationCallback; 23 | 24 | private static void PromiseContinuationCallback(JavaScriptValue task, IntPtr callbackState) 25 | { 26 | taskQueue.Enqueue(task); 27 | task.AddRef(); 28 | } 29 | 30 | public string Init() 31 | { 32 | 33 | if (Native.JsCreateRuntime(JavaScriptRuntimeAttributes.EnableIdleProcessing, null, out runtime) != JavaScriptErrorCode.NoError) 34 | return "failed to create runtime."; 35 | 36 | if (Native.JsCreateContext(runtime, out context) != JavaScriptErrorCode.NoError) 37 | return "failed to create execution context."; 38 | 39 | if (Native.JsSetCurrentContext(context) != JavaScriptErrorCode.NoError) 40 | return "failed to set current context."; 41 | 42 | 43 | if (Native.JsSetPromiseContinuationCallback(promiseContinuationDelegate, IntPtr.Zero) != JavaScriptErrorCode.NoError) 44 | return "failed to setup callback for ES6 Promise"; 45 | 46 | if (Native.JsProjectWinRTNamespace("Windows") != JavaScriptErrorCode.NoError) 47 | return "failed to project windows namespace."; 48 | 49 | if (Native.JsStartDebugging() != JavaScriptErrorCode.NoError) 50 | return "failed to start debugging."; 51 | 52 | 53 | if (Native.JsGetGlobalObject(out jsAppGlobalObject) != JavaScriptErrorCode.NoError) 54 | return "failed to get global object"; 55 | 56 | console = new JS.JSConsole(); 57 | require = new JS.JSRequire(); 58 | process = new JS.JSProcess(); 59 | JS.AbstractJSModule.AttachModule(jsAppGlobalObject, require); 60 | JS.AbstractJSModule.AttachModule(jsAppGlobalObject, console); 61 | JS.AbstractJSModule.AttachModule(jsAppGlobalObject, process); 62 | 63 | return "NoError"; 64 | } 65 | 66 | public string RunScript(string script) 67 | { 68 | IntPtr returnValue; 69 | 70 | try 71 | { 72 | JavaScriptValue result; 73 | // failing because of "no context" 74 | if (Native.JsRunScript(script, currentSourceContext++, "", out result) != JavaScriptErrorCode.NoError) 75 | { 76 | // Get error message and clear exception 77 | JavaScriptValue exception; 78 | if (Native.JsGetAndClearException(out exception) != JavaScriptErrorCode.NoError) 79 | return "failed to get and clear exception"; 80 | 81 | JavaScriptPropertyId messageName; 82 | if (Native.JsGetPropertyIdFromName("message", 83 | out messageName) != JavaScriptErrorCode.NoError) 84 | return "failed to get error message id"; 85 | 86 | JavaScriptValue messageValue; 87 | if (Native.JsGetProperty(exception, messageName, out messageValue) 88 | != JavaScriptErrorCode.NoError) 89 | return "failed to get error message"; 90 | 91 | IntPtr message; 92 | UIntPtr length; 93 | if (Native.JsStringToPointer(messageValue, out message, out length) != JavaScriptErrorCode.NoError) 94 | return "failed to convert error message"; 95 | 96 | return Marshal.PtrToStringUni(message); 97 | } 98 | 99 | // Execute promise tasks stored in taskQueue 100 | while (taskQueue.Count != 0) 101 | { 102 | JavaScriptValue task = (JavaScriptValue)taskQueue.Dequeue(); 103 | JavaScriptValue promiseResult; 104 | JavaScriptValue[] args = new JavaScriptValue[1] { jsAppGlobalObject }; 105 | Native.JsCallFunction(task, args, 1, out promiseResult); 106 | task.Release(); 107 | } 108 | 109 | // Convert the return value. 110 | JavaScriptValue stringResult; 111 | UIntPtr stringLength; 112 | if (Native.JsConvertValueToString(result, out stringResult) != JavaScriptErrorCode.NoError) 113 | return "failed to convert value to string."; 114 | if (Native.JsStringToPointer(stringResult, out returnValue, out stringLength) != JavaScriptErrorCode.NoError) 115 | return "failed to convert return value."; 116 | } 117 | catch (Exception e) 118 | { 119 | return "chakrahost: fatal error: internal error: " + e.Message; 120 | } 121 | 122 | return Marshal.PtrToStringUni(returnValue); 123 | } 124 | 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/MainPage.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/MainPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices.WindowsRuntime; 6 | using Windows.Foundation; 7 | using Windows.Foundation.Collections; 8 | using Windows.UI.ViewManagement; 9 | using Windows.UI.Xaml; 10 | using Windows.UI.Xaml.Controls; 11 | using Windows.UI.Xaml.Controls.Primitives; 12 | using Windows.UI.Xaml.Data; 13 | using Windows.UI.Xaml.Input; 14 | using Windows.UI.Xaml.Media; 15 | using Windows.UI.Xaml.Navigation; 16 | 17 | // The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 18 | 19 | namespace Electrino 20 | { 21 | /// 22 | /// An empty page that can be used on its own or navigated to within a Frame. 23 | /// 24 | public sealed partial class MainPage : Page 25 | { 26 | private static MainPage instance = null; 27 | public MainPage() 28 | { 29 | instance = this; 30 | InitializeComponent(); 31 | webView1.ScriptNotify += ScriptNotify; 32 | webView1.ContainsFullScreenElementChanged += webView1_ContainsFullScreenElementChanged; 33 | 34 | //webView1.Navigate(new Uri("ms-appx-web:///test-app/index.html")); 35 | } 36 | 37 | public static bool LoadURL(string url) 38 | { 39 | if (instance == null) 40 | { 41 | return false; 42 | } 43 | instance.webView1.Navigate(new Uri(url)); 44 | return true; 45 | } 46 | 47 | private void WebView_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args) 48 | { 49 | AddRenderApis(); 50 | } 51 | 52 | void ScriptNotify(object sender, NotifyEventArgs e) 53 | { 54 | App.Log($"Event received from {e.CallingUri}: \"{e.Value}\""); 55 | } 56 | 57 | private void AddRenderApis() 58 | { 59 | webView1.AddWebAllowedObject("process", new RenderAPI.JSProcess()); 60 | webView1.AddWebAllowedObject("require", new RenderAPI.JSRequire().Main); 61 | } 62 | 63 | private void webView1_ContainsFullScreenElementChanged(WebView sender, object args) 64 | { 65 | var applicationView = ApplicationView.GetForCurrentView(); 66 | 67 | if (sender.ContainsFullScreenElement) 68 | { 69 | applicationView.TryEnterFullScreenMode(); 70 | } 71 | else if (applicationView.IsFullScreenMode) 72 | { 73 | applicationView.ExitFullScreenMode(); 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Electrino 7 | Thomas 8 | Assets\StoreLogo.png 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Electrino")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Electrino")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Version information for an assembly consists of the following four values: 18 | // 19 | // Major Version 20 | // Minor Version 21 | // Build Number 22 | // Revision 23 | // 24 | // You can specify all the values or you can default the Build and Revision Numbers 25 | // by using the '*' as shown below: 26 | // [assembly: AssemblyVersion("1.0.*")] 27 | [assembly: AssemblyVersion("1.0.0.0")] 28 | [assembly: AssemblyFileVersion("1.0.0.0")] 29 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /Electrino/win10/Electrino/Properties/Default.rd.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/test-app/index.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Hello World! 6 | 12 | 13 | 14 |

Hello World!

15 | We are using Electrino: 16 | 21 | 22 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/test-app/main.js: -------------------------------------------------------------------------------- 1 | const electrino = require('electrino') 2 | const app = electrino.app 3 | const BrowserWindow = electrino.BrowserWindow 4 | const path = require('path'); 5 | const url = require('url'); 6 | 7 | // Keep a global reference of the window object, if you don't, the window will 8 | // be closed automatically when the JavaScript object is garbage collected. 9 | var win = null; 10 | 11 | console.log("hello world starting, app is: ", app); 12 | 13 | function createWindow() { 14 | // Create the browser window. 15 | win = new BrowserWindow({ width: 800, height: 600 }); 16 | 17 | console.log("createWindow", BrowserWindow, win); 18 | // and load the index.html of the app. 19 | win.loadURL(url.format({ 20 | pathname: path.join("/test-app", 'index.html'), 21 | protocol: 'ms-appx-web:', 22 | slashes: true 23 | })); 24 | // Emitted when the window is closed. 25 | win.on('closed', function () { 26 | // Dereference the window object, usually you would store windows 27 | // in an array if your app supports multi windows, this is the time 28 | // when you should delete the corresponding element. 29 | win = null; 30 | }); 31 | } 32 | 33 | 34 | // This method will be called when Electron has finished 35 | // initialization and is ready to create browser windows. 36 | // Some APIs can only be used after this event occurs. 37 | app.on('ready', createWindow); 38 | 39 | // // Quit when all windows are closed. 40 | app.on('window-all-closed', function () { 41 | // On macOS it is common for applications and their menu bar 42 | // to stay active until the user quits explicitly with Cmd + Q 43 | if (process.platform !== 'darwin') { 44 | app.quit() 45 | } 46 | }); 47 | 48 | app.on('activate', function () { 49 | // On macOS it's common to re-create a window in the app when the 50 | // dock icon is clicked and there are no other windows open. 51 | if (win === null) { 52 | createWindow() 53 | } 54 | }); 55 | -------------------------------------------------------------------------------- /Electrino/win10/Electrino/test-app/test.js: -------------------------------------------------------------------------------- 1 | 2 | const path = require("path"); 3 | const url = require("url"); 4 | console.log(path); 5 | console.log(require.toString()); 6 | const fooPath = path.join('blah', 'foo'); 7 | console.log(fooPath); 8 | console.log(url.format({ pathname: fooPath, protocol: "file:" })); 9 | console.log(path.toString()); 10 | const electrino = require("electrino"); 11 | const BrowserWindow = electrino.BrowserWindow; 12 | const app = electrino.app; 13 | 14 | function ready() { 15 | const win = new BrowserWindow(); 16 | win.loadURL("ms-appx-web:///test-app/index.html"); 17 | } 18 | 19 | console.log(app.toString()); 20 | console.log(app.on("ready", ready)); 21 | /*app.on("ready", );*/ 22 | -------------------------------------------------------------------------------- /Electrino/win10/RenderAPI/JSOs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Windows.ApplicationModel; 7 | using Windows.Foundation.Metadata; 8 | using Windows.System.Profile; 9 | 10 | namespace RenderAPI 11 | { 12 | [AllowForWeb] 13 | public sealed class JSOs 14 | { 15 | public string Platform() 16 | { 17 | return "win32"; 18 | } 19 | 20 | public string Release() 21 | { 22 | string deviceFamilyVersion = AnalyticsInfo.VersionInfo.DeviceFamilyVersion; 23 | ulong version = ulong.Parse(deviceFamilyVersion); 24 | ulong major = (version & 0xFFFF000000000000L) >> 48; 25 | ulong minor = (version & 0x0000FFFF00000000L) >> 32; 26 | ulong build = (version & 0x00000000FFFF0000L) >> 16; 27 | ulong revision = (version & 0x000000000000FFFFL); 28 | return $"{major}.{minor}.{build}.{revision}"; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Electrino/win10/RenderAPI/JSProcess.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Windows.ApplicationModel; 7 | using Windows.Foundation.Metadata; 8 | 9 | namespace RenderAPI 10 | { 11 | [AllowForWeb] 12 | public sealed class JSProcess 13 | { 14 | public string Platform 15 | { 16 | get 17 | { 18 | return "win32"; 19 | } 20 | } 21 | 22 | public string Arch 23 | { 24 | get 25 | { 26 | return Package.Current.Id.Architecture.ToString(); 27 | } 28 | } 29 | 30 | private AppVersions _versions = new AppVersions(); 31 | 32 | public AppVersions Versions 33 | { 34 | get 35 | { 36 | return _versions; 37 | } 38 | } 39 | 40 | } 41 | 42 | [AllowForWeb] 43 | public sealed class AppVersions 44 | { 45 | public string Electrino 46 | { 47 | get 48 | { 49 | return "0.1.0"; 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Electrino/win10/RenderAPI/JSRequire.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Windows.Foundation.Metadata; 7 | 8 | namespace RenderAPI 9 | { 10 | public delegate object RequireFunc(string name); 11 | 12 | [AllowForWeb] 13 | public sealed class JSRequire 14 | { 15 | private Dictionary modules = new Dictionary(); 16 | 17 | public RequireFunc Main 18 | { 19 | get 20 | { 21 | RequireFunc del = (string name) => 22 | { 23 | modules.TryGetValue(name, out object module); 24 | return module; 25 | }; 26 | return del; 27 | } 28 | } 29 | 30 | public JSRequire() 31 | { 32 | modules.Add("os", new JSOs()); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Electrino/win10/RenderAPI/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("RenderAPI")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("RenderAPI")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Version information for an assembly consists of the following four values: 18 | // 19 | // Major Version 20 | // Minor Version 21 | // Build Number 22 | // Revision 23 | // 24 | // You can specify all the values or you can default the Build and Revision Numbers 25 | // by using the '*' as shown below: 26 | // [assembly: AssemblyVersion("1.0.*")] 27 | [assembly: AssemblyVersion("1.0.0.0")] 28 | [assembly: AssemblyFileVersion("1.0.0.0")] 29 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /Electrino/win10/RenderAPI/RenderAPI.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {77B6E3D3-17E6-46CB-B699-C118776F54DE} 8 | winmdobj 9 | Properties 10 | RenderAPI 11 | RenderAPI 12 | en-US 13 | UAP 14 | 10.0.15063.0 15 | 10.0.10586.0 16 | 14 17 | 512 18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 19 | false 20 | 21 | 22 | AnyCPU 23 | true 24 | full 25 | false 26 | bin\Debug\ 27 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 28 | prompt 29 | 4 30 | 31 | 32 | AnyCPU 33 | pdbonly 34 | true 35 | bin\Release\ 36 | TRACE;NETFX_CORE;WINDOWS_UWP 37 | prompt 38 | 4 39 | 40 | 41 | x86 42 | true 43 | bin\x86\Debug\ 44 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 45 | ;2008 46 | full 47 | x86 48 | false 49 | prompt 50 | 51 | 52 | x86 53 | bin\x86\Release\ 54 | TRACE;NETFX_CORE;WINDOWS_UWP 55 | true 56 | ;2008 57 | pdbonly 58 | x86 59 | false 60 | prompt 61 | 62 | 63 | ARM 64 | true 65 | bin\ARM\Debug\ 66 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 67 | ;2008 68 | full 69 | ARM 70 | false 71 | prompt 72 | 73 | 74 | ARM 75 | bin\ARM\Release\ 76 | TRACE;NETFX_CORE;WINDOWS_UWP 77 | true 78 | ;2008 79 | pdbonly 80 | ARM 81 | false 82 | prompt 83 | 84 | 85 | x64 86 | true 87 | bin\x64\Debug\ 88 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 89 | ;2008 90 | full 91 | x64 92 | false 93 | prompt 94 | 95 | 96 | x64 97 | bin\x64\Release\ 98 | TRACE;NETFX_CORE;WINDOWS_UWP 99 | true 100 | ;2008 101 | pdbonly 102 | x64 103 | false 104 | prompt 105 | 106 | 107 | PackageReference 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 5.2.4 118 | 119 | 120 | 121 | 14.0 122 | 123 | 124 | 131 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Pauli Ojala 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # electrino 2 | 3 | An experimental desktop runtime for apps built on web technologies, using the system's own web browser engine. The project is still young and accepting contributions. 4 | 5 | Electrino aims to be a featherweight alternative to the popular and powerful [Electron](https://github.com/electron/electron). It implements a minuscule portion of the APIs available in Electron, but the output app size is much smaller. 6 | 7 | A "Hello World" app takes 115 MB using Electron, but only 167 kB using Electrino: 8 | 9 | ![Screenshot from Mac Finder](docs/electron-and-electrino-helloworld-screenshot.png) 10 | 11 | Read more about Electrino in [this post on DailyJS](https://medium.com/dailyjs/put-your-electron-app-on-a-diet-with-electrino-c7ffdf1d6297) 12 | 13 | ### Comparison 14 | 15 | Feature | Electron | Electrino 16 | --- | --- | --- 17 | Comprehensive API | Yes | No 18 | Small output size | No | Yes 19 | Cross-platform support | Yes | Limited to macOS and Windows 10 at this time 20 | 21 | ### Contribute 22 | 23 | - [x] Integrate `WebView` 24 | - [ ] Support `require()` calls 25 | - [ ] Add Node.js backend 26 | 27 | ### API 28 | 29 | Electrino currently supports the following API implementations: 30 | 31 | * app 32 | * BrowserWindow 33 | * ipcMain 34 | * Tray 35 | * nativeImage 36 | 37 | ### Roadmap 38 | 39 | The plan is to examine API usage of real-world apps that use Electron but don't really need the full capabilities. Good candidates are desktop utilities, menu bar apps and other small apps that users typically leave open. (For large productivity-style apps, Electron is a better choice.) 40 | 41 | Jan Hovancik offered his [Stretchly](https://github.com/hovancik/stretchly) app as a candidate, so I'm going to start by mapping out the APIs used by Stretchly and see what it would take to implement it with Electrino. 42 | 43 | If you have a small Electron-based Mac app and you'd like to try putting it on an Electrino diet, let's give it a try! My contact info is below. 44 | 45 | ### Contact 46 | 47 | * Pauli Olavi Ojala / @pauliooj / pauli @ lacquer.fi 48 | * Amila Welihinda / @amilajack / amilajack @ gmail.com 49 | -------------------------------------------------------------------------------- /docs/electron-and-electrino-helloworld-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojala/electrino/0bf75954b56440f0a0ec6aa83f2ce50d56ab52e2/docs/electron-and-electrino-helloworld-screenshot.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "electrino", 3 | "version": "0.0.0", 4 | "description": "A desktop runtime for apps built on web technologies, using the system's own web browser engine.", 5 | "main": "index.js", 6 | "directories": { 7 | "doc": "docs" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/pojala/electrino.git" 15 | }, 16 | "keywords": [], 17 | "contributors": [ 18 | "Amila Welihinda (http://amilajack.com/)" 19 | ], 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/pojala/electrino/issues" 23 | }, 24 | "homepage": "https://github.com/pojala/electrino#readme" 25 | } 26 | -------------------------------------------------------------------------------- /test-app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hello World! 6 | 7 | 8 |

Hello World!

9 | We are using Electrino . 10 | 11 | 12 | -------------------------------------------------------------------------------- /test-app/main.js: -------------------------------------------------------------------------------- 1 | const {app, BrowserWindow} = require('electrino') 2 | const path = require('path') 3 | const url = require('url') 4 | 5 | // Keep a global reference of the window object, if you don't, the window will 6 | // be closed automatically when the JavaScript object is garbage collected. 7 | let win 8 | 9 | function createWindow () { 10 | // Create the browser window. 11 | win = new BrowserWindow({width: 800, height: 600}) 12 | 13 | // and load the index.html of the app. 14 | win.loadURL(url.format({ 15 | pathname: path.join(__dirname, 'index.html'), 16 | protocol: 'file:', 17 | slashes: true 18 | })) 19 | 20 | // Open the DevTools. 21 | win.webContents.openDevTools() 22 | 23 | // Emitted when the window is closed. 24 | win.on('closed', () => { 25 | // Dereference the window object, usually you would store windows 26 | // in an array if your app supports multi windows, this is the time 27 | // when you should delete the corresponding element. 28 | win = null 29 | }) 30 | } 31 | 32 | // This method will be called when Electron has finished 33 | // initialization and is ready to create browser windows. 34 | // Some APIs can only be used after this event occurs. 35 | app.on('ready', createWindow) 36 | 37 | // Quit when all windows are closed. 38 | app.on('window-all-closed', () => { 39 | // On macOS it is common for applications and their menu bar 40 | // to stay active until the user quits explicitly with Cmd + Q 41 | if (process.platform !== 'darwin') { 42 | app.quit() 43 | } 44 | }) 45 | 46 | app.on('activate', () => { 47 | // On macOS it's common to re-create a window in the app when the 48 | // dock icon is clicked and there are no other windows open. 49 | if (win === null) { 50 | createWindow() 51 | } 52 | }) 53 | -------------------------------------------------------------------------------- /test-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "your-app", 3 | "version" : "0.1.0", 4 | "main" : "main.js" 5 | } --------------------------------------------------------------------------------