Showing posts with label JavaScript. Show all posts
Showing posts with label JavaScript. Show all posts

Thursday, November 8, 2012

Porting Brackets to a new platform

Brackets is a code editor for HTML, CSS and JavaScript that is built in HTML, CSS and JavaScript. That makes it a fully featured desktop application written using Web technologies. Brackets embeds a browser to show and run the entire editor and extends it with additional functionality used by JavaScript. There are more and more applications using this kind of mixed platform - HTML/JavaScript becomes first class User Interface (UI) (and not only) for Window 8 applications, other tools from Adobe such as Edge Animate, Icenium - a new cloud IDE, recently announced by Telerik. Sencha Animator also is an HTML5 application, running inside QT WebKit. Even the UI of most browsers is written in HTML.
This approach has several advantages:
  • fully cross-platform UI - as long as the browser is running on a platform, the UI is going to be running on that platform too
  • full UI customization using CSS lots of available application frameworks MVC, MVVM - Backbone.js, knockout.js, you name it
  • lots of UI libraries - Kendo UI, jQuery UI, mochaui
  • easy development of the UI using Chrome Dev Tools, Firebug, etc.
  • Live reload of the UI, without restarting the whole application!
  • native access to filesystem and everything without sandboxing
  • use existing native APIs
  • native performance where necessary
  • only single browser to support - this is a huge relief for the HTML/JavaScript developers
Given the advantages, I am sure that more and more mixed native and HTML applications are going to appear.

Brackets Architecture

Brackets consists of two applications running together - an HTML/JavaScript application and a native C++ shell that runs the HTML application. The native shell consists of two processes - one running the HTML application inside a browser, and one running the heavy native part like filesystem operations and number crunching. The communication between the two processes is asynchronous, using JavaScript callbacks and request / response for the native code.

  • The shell extends the standard HTML DOM with the following functions:
  • Open file or directory using the OS dialog
  • Read file
  • Write file
  • Create directory
  • Rename file or directory
  • Get file last modification time
  • List directory contents
  • Open and close browser for Live Preview
  • Open extensions directory in OS file browser
  • Open developer tools for brackets itself
  • Get the system default language
  • Time since the application start
  • Get the application support directory


Brackets Shell implements the asynchronous communication between the HTML render process and the browser in a very simplistic way: JavaScript executes a function appshell.fs.readdir(path, callback), the render process stores the callback in a mapping from a request id to callback and calls the native process with the name of the function. When the native process is ready it sends back any result of the call together with the request id. The HTML process finds the callback by the request id and executes it with any result.



This architecture is the same as for any good GUI application - the UI never executes any expensive functions and is always responsive and all data manipulation is in a separate thread.

Running Brackets in Coherent UI

Making Brackets run inside Coherent UI is really easy. We start by creating a view that loads www/index.html relatively to the executable. To support Coherent UI we have to include some JavaScript files in the index.html of Brackets

These scripts are Coherent UI dependencies, Coherent UI itself and the abstraction layer between all JavaScript code of Brackets and Coherent UI. Then we have to register our native callbacks for the asynchronous calls:

Brackets native functions always return an error code as first argument to the JavaScript callback. This mechanism can be implemented in Coherent UI, but then the callbacks always have to do two things - handle the correct result and handle the error, which is kind of annoying. engine.Call might take two callbacks - one for the successful result and one for error. Therefore we have to wrap the normal callback in an object with separate handlers for success and error.
gist: javascript callback wrapper
All that is left now is to wrap the callbacks and use engine.Call instead of native function.

and to write the native function

Handling synchronous calls  

Brackets has and some synchronous methods that return to JavaScript immediately. These methods are:
  • Get the application support directory
  • Get the system default language
  • Time since the application start
Coherent UI does not support providing synchronous JavaScript functions by design, so we will have to work around that.

The application support directory remains constant through a single run of Brackets, so we can set it once and for all during application initialization:

Getting the system default language might be implemented in the same way. The last method left is time since the application start and is used only in Show Performance Data menu. This method might be implemented entirely in JavaScript, assuming Brackets is not going to be reloaded during the performance test run.

Porting Bracket to Linux

Since Coherent UI already runs on Linux and we have implemented most of the native functions using the cross-platform boost::filesystem library, all we have to do to get is showing an open file dialog, creating and closing a chrome instance opening an URL and folder in the default OS HTML browser and file manager.

We use the GtkFileChooserDialog and the xdg-open tool. Unfortunately, the Live Preview doesn't work under Linux. Live Preview in Brackets creates a new Google Chrome instance with enabled remote debugger, attaches to the debugger using XmlHttpRequest and WebSockets and controls the instance via the debugger. What happens on Linux is that one of the XmlHttpRequests fails with "DOM Exception" and the debugger is unable to attach to the instance.

Another Linux related issue is that I couldn't find a way to close a Google Chrome  tab on Linux gracefully, so when the developer tools are closed you get the "Ow, Snap" page. In a future version we will stop using Google Chrome for Live Preview and for showing the developer tools, which will fix this problem.

Here is a short video of Brackets running on Linux:

Get a prebuild package or get Coherent UI and start hacking!

Monday, October 22, 2012

Introducing on-demand views in Coherent UI

Coherent UI is designed as a multi-process multi-threaded module to allow leveraging on modern processors and GPUs. Up until now it supported what we call 'buffered' views. All UI rendering is performed in an apposite rendering process that allows sand-boxing the interface's operations, hence all commands are executed asynchronously.

This kind of views allow for perfectly smooth animations and user experience and are the natural choice for dynamic UIs and in-game browser views. However, if you need to have interface elements correlate per-frame with in-game entities, buffered views might not be suitable.

Take for instance enemy players in an MMO - their nameplates must always be perfectly snapped in every frame over their heads. The same applies to RTS games - health indicators must be glued on the units and never lag behind.

On-demand views

Coherent UI is now the only HTML5-based solution that solves all these problems. We have created what we call 'on-demand' views. They allow exact synchronization between the game frame and the out-of-process UI rendering without sacrificing any performance. Everything is still asynchronous but we make strong guarantees on the content of frames you receive at any point.
With on-demand views the game can explicitly request the rendering of UI frames and is guaranteed that all events prior to the request will be executed in that frame.

The typical frame of a game that uses on-demand views looks like this:
  • update frame (move players, AI, etc.)
  • trigger UI events (i.e. set the new nameplates positions, player health, etc.)
  • request UI frame 
  • draw game frame
  • fetch UI frame
  • compose UI on the game frame
This flow ensures that the game is in perfect sync with the UI and while the game renders it's frame the UI gets simultaneously drawn in Coherent UI's internals.
This video shows the new view in action. Please, do not mind the programmer art.


As you can see buffered views might introduce some delay that is noticeable if interface elements are related to in-game events as the position of the units. On-demand views remain always in-sync.

Buffered views will remain part of Coherent UI as they are very easy to use and should be the default choice when no frame-perfect visual synchronization is required between the game and the UI. For instance if have an FPS game and the UI only shows mini-map, player health and ammo you should probably use buffered views as no delay will ever be noticeable on the elements you are showing. The same applies to in-game browsers.

In other cases however on-demand views come to aid. They will be available for use in the next version of Coherent UI.

Monday, October 1, 2012

Documenting JavaScript with Doxygen

As you already know (Coherent UI announcement) we are developing a large C++ and JavaScript project. We have documentation for both programming languages. The main requirements for the documentation are:
  • Application Programming Interface (API) references and general documentation such as quick start and detailed guides
  • cross references between the API references and the guides
  • accessible online and off line
  • easy markup language
There are a lot documentation tools for each language - DoxygenSandcastle for C++, YUIDocJSDuck for JavaScript. Our project API is primary in C++, so we choose Doxygen. It is great for C++projects, but it doesn't support JavaScript. There are some scripts that solve this by converting JavaScript to C++ or Java. Unfortunately they do not support the modules pattern or have inconvenient syntax for the documentation. Our JavaScript API consists mostly of modules, so we wrote a simple doxygen filter for our documentation. A doxygen filter is a program that is invoked with the name of a file, and its output is used by doxygen to create the documentation for that file. To enable filters for specific file extension add in the doxygen configuration file. Lets say we want to document the following module:
The filtered output looks like:
A nice surprise is that when you want to link to Sync.load you can use `Sync.load`. The only annoying C++ artifacts in the JavaScript documentation are the "Sync namespace" and using "::" as resolution operator, but they can be fixed by a simple find / replace script. The doxygen.js filter is available at https://gist.github.com/3767879.