HTML activities
One of the limitations with the current Sugar architecture is that GTK isn’t really a good toolkit to be creative with. I would like to write activities in HTML but still be able to access services like the icon theme, the datastore and the presence service. When I wrote hulahop I had this also in mind.
Years passed and I think we might now have the blocks to build something better. So I made a little experiment. I wrote a toy text editor. A really simple one, it can only save to a single file. But I hope it shows a possible way to tackle the issue. Anyway, code first (but not so much of it, don’t hold your breath)!
The engine, a web server, based on nodejs. It’s using http but I’d have probably used web sockets if I could get them to work. We will certainly need bidirectional communication. The example has load and save methods, the idea is that system services are exposed to applications at this level.
var http = require("http"); var fs = require('fs'); var static = require('node-static'); var savedPath = "/home/marcopg/Development/tmp/saved"; function load(request, response) { response.end(fs.readFileSync(savedPath, "binary")); } function save(request, response) { data = ""; request.setEncoding("binary"); request.on("data", function(chunk) { data += chunk; }) request.on("end", function() { fs.writeFileSync(savedPath, data, "binary"); }) } var file = new(static.Server)("./apps"); http.createServer(function (request, response) { if (request.url == "/save") { save(request, response); } else if (request.url == "/load") { load(request, response); } else { file.serve(request, response); } }).listen(8080, "localhost"); console.log('Server running at http://localhost:8080');
Then the editor application. Some trivial HTML And bits of javascript to talk to the server. On startup we load the current text by making an XMLHttpRequest to the engine. Similarly, when the “Save” button is pressed we send it to the server with a POST request.
<html> <head> <script type="text/javascript" src="editor.js"></script> </head> <body onLoad="load();"> <form> <textarea id="textArea" rows="10" cols="50"></textarea> <p> <input type="button" onClick="save();" value="Save"/> </p> </form> </body> </html>
function load() { var xhr = new XMLHttpRequest(); xhr.open("GET", "load"); xhr.send(); xhr.onreadystatechange = function (aEvt) { if (xhr.readyState == 4) { var textArea = document.getElementById("textArea"); textArea.value = this.responseText; } } } function save() { var textArea = document.getElementById("textArea"); var xhr = new XMLHttpRequest(); xhr.open("POST", "save"); xhr.send(textArea.value); }
Finally a viewer, based on WebKit2. As you can see their new API is pretty nice, it’s all C and it’s supposed to be stable. It should be a lot less painful to maintain than hulahop.
#include <WebKit2/WebKit2.h> #include <gtk/gtk.h> #define HOME_URL "http://localhost:8080/editor.html" int main(int argc, char *argv[]) { GtkWidget *window; GtkWidget *box; WKViewRef web_view; if (!g_thread_supported()) g_thread_init(NULL); gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); box = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(window), box); gtk_widget_show(box); web_view = WKViewCreate(WKContextGetSharedProcessContext(), 0); gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(web_view), TRUE, TRUE, 0); gtk_widget_show(GTK_WIDGET(web_view)); WKPageLoadURL(WKViewGetPage(web_view), WKURLCreateWithUTF8CString(HOME_URL)); gtk_widget_show(window); gtk_window_fullscreen(GTK_WINDOW(window)); gtk_main(); return 0; }
A few advantages over the standard activities framework are pretty obvious.
- You can be as creative as you like by writing the UI in HTML (and related web technologies).
- The activity is sandboxed by default, it only has access to the services exposed by the engine.
- You could run the same application on other platforms, as long as you have a viewer and an engine for it.
As I said this was just an experiment. I’m not sure I will have time to work on it again, but if I do these are the things I would probably be working on first.
- Write instructions on how to build and run the thing.
- Hack a Sugar HIG compliant UI. I will need to figure out how to share widgets and artwork between applications.
- Expose activity metadata in the viewer, so that it actually integrates with the Sugar shell.
- Add a datastore interface to the engine in place of the toy load/save methods.
The code is in a git repository if you want to play with it.