Tuesday, August 2, 2016

Nw.js system-wide installation

About a year ago I talked here on this blog about the nw.js framework, that allows to build desktop applications using web languages and technologies. In that post, I pointed out that in my opinion an annoying problem with this framework is the size of the binaries to distribute (about 60MB for a very simple application) when the official packaging method is used.
I thought about a workaround for this and I designed an alternative packaging method where the nw.js runtime files are installed globally on the system, like it's usually done with other application frameworks such as Java or .NET/Mono. I then built some tools to manage multiple system-wide installed versions of nw.js and to build installers (for Windows) and packages (for Linux distributions) for applications that use this packaging method. The produced installers/packages won't include the nw.js runtime, but will download it (in the correct version) during the installation only if the user hasn't a compatible version installed yet; the files are downloaded from the official nw.js website. Everything is released under the open source MIT license; here is the repository with more detailed documentation in the README. Everyone is welcome to contribute; if you have any suggestion or you found a bug, comment here on this post or file an issue. Alternatively, you can fork the repository and apply your improvement, then open a pull request.
Deploying nw.js applications using this method is made simple by the command line tool, written in Javascript; actually it can build Windows installers (based on NSIS) and .deb and .rpm packages for Linux distributions (Debian-like ones and RPM-based ones, using fpm). You can get the tool from npm (global installation is recommended since this is a cli tool; use npm install -g nw-global-build). See the README for documentation.

A screenshot taken on Windows during the installation of a simple nw.js app. The nw.js files are being downloaded.
On this other repository you can find an example application which is packaged with nw.js-global-install; on the Travis-CI log you can see the output of the build tool.

I admit there are some limitations with this packaging method, because people working on big and/or commercially-licensed applications probably don't want their product to rely on 3rd party tools and will still prefer to ship a full nw.js distribution together with the application, so it's self-contained and they will avoid problems with user support. However I think nw.js-global-install can be useful for smaller and/or open source projects where it's common to use 3rd party libraries and tools and support isn't a big issue.

Thursday, November 26, 2015

A starter kit for IUP, lightweight and cross-platform user interface library for C and Lua

Some months ago I wrote a post about the NW.js runtime, a framework to develop desktop applications using web languages and technologies, which is, in my opinion, a very interesting platform but has an annoying problem: the only user-friendly way to ship your applications is to merge the NW.js runtime files with your application, resulting in an overhead of about 90 MBs for each NW-based application the users install on their machines. To get around this problem, I'm interested to develop a small tool to manage a global, system-wide, installation of the NW runtime files on users' computers (in different versions if necessary); this program should be GUI-based, as lightweight as possible, and cross-platform (Windows and Linux for now).
After reading information about various GUI toolkits, I found the IUP user interface toolkit to be the most suitable for my program. It can be used as a small (~1 MB) library (.dll on Windows or .so on Linux) which can be shipped with the application; you can use it in plain C programs or in Lua scripts (I choose C since Lua is interpreted and I don't want to increase the size of the program by embedding the interpreter into it).
IUP also has a custom language, LED, that can be used to define the layout of each application's window. LED files can either be loaded at runtime or compiled into a C file which you can then compile and link together with other source files of the application.
In my opinion, the main advantage of IUP against other well-known cross-platform frameworks like Qt is that it doesn't define its own controls, but instead it provides an abstraction layer over the platform's native controls, resulting in smaller binaries. IUP provides drivers for the native Win32 API (which is part of Windows), GTK (which, as far as I know, is actually installed by default on the majority of desktop Linux distributions) and Motif (a GUI toolkit used in other Unix-based systems).
A similar approach is used by wxWidgets, which is however available for C++ only and not for C.
To begin using IUP, I set up a starter kit to compile IUP-based applications on Linux for Linux itself and for Windows (using the mingw-w64 cross compiler); you can find it here: https://github.com/gianluca-nitti/iup-cp-boilerplate. This repository contains shell scripts and a Makefile to compile an example IUP application to three target platforms: linux64, linux32 and win32. Actually I didn't add the win64 target since (correct me if I'm wrong) thanks to WoW64, on 64-bit Windows installations 32-bit applications run out-of-the-box, and I don't plan to develop performance-critical applications (this target should be easy to add, though). This boilerplate is tested to compile out-of-the-box on Ubuntu 14.04, which is also the OS used by the Travis-CI continuous integration service (the repository, in fact, also includes a .travis.yml that allows the code to be automatically built by that service); for other distributions you may need to edit the get-packages.sh script to change the package names and/or the package manager command. In detail, this boilerplate contains:
  • C and LED source files for a minimal IUP application (two windows: a main dialog and an about dialog);
  • A shell script (get-packages.sh) that installs the required packages to compile the application for the three targets;
  • A shell script (get-libs.sh) that downloads the IUP library for the three targets to allow linking the application with it, and the LEDC compiler for LED interface definition files (which is used in the Makefile)
  • A Makefile that builds the binaries, using the tools downloaded from the scripts.
Here are some screenshots of the example application:
On Ubuntu 12.04 (64-bit)
On Windows 8.1 (64-bit)

On Fedora (32-bit)

You can find more information about how to use this boilerplate to build your cross-platform GUI application based on IUP in the README file of the repository.

Wednesday, August 19, 2015

Getting started with NW.js (a.k.a. node-webkit)

Recently, I discovered a very interesting project on GitHub: nw.js (previously known as node-webkit). As you can see from the README file in the repository, it is a runtime for desktop applications based on Chromium (the open source project which powers the popular Chrome browser by Google) and io.js (a fork of node.js, a Javascript platform originally designed for building server-side applications).
This platform makes possible to write desktop applications using Javascript, HTML, CSS and web technologies such as browser-side libraries and frameworks (like JQuery and AngularJS) and node modules (often designed to work on the server side of web applications), which can be used to access system resources such as the filesystem. Node modules can be called directly from the "browser" context using the require() function.
Nw.js also provides APIs to integrate the applications with the desktop, so you can add, for example, native menus or a tray icon. All the documentation is available in the wiki.

In my opinion, nw.js has mainly two big advantages: first of all, it allows developers to use powerful web frameworks on the desktop, making possible, for example, to build nice user interfaces with Bootstrap (maybe animated with animate.css) which can interact with the operating system. Secondly, nw.js is cross-platform, so the built applications can be easily deployed to the major desktop operating system (Windows, OSX and Linux distributions).

There is, however, a downside: the size of the "compiled" applications. Probably "compiling" isn't the correct term since as the wiki explains, the suggested method of deployment consists in zipping the applications files (such as Javascript, HTML, CSS, node modules, etc) and then merging the archive with the nw.js executable or distributing them together. This means that each application will include a full Chromium browser, which isn't exactly lightweight: I tried to package on Windows a very simple image viewer application I made to learn nw.js and I got an app.exe file of 59MB and the full application directory with all the DLLs of 98MB. The DLLs may be not all necessary to run the application (some of them are for GPU acceleration and other for media playback); I haven't tried to delete them, however 60MB for an application that is a little more than an hello world is, in my opinion, too heavy anyway.
A possible solution to this problem may be providing a user-friendly way to make a system-wide nw.js installation, like already happens with other runtimes such as Java; this way, an user would need to download and install the core nw.js files only once (and eventually re-download them when a new version is available) and then install only the JS/HTML/CSS/etc files for each application without having each app taking up so much space. Someone has suggested a similar approach here, but as you can see from the discussion it seems like people involved with the project isn't very interested in this way of deploying applications.

Apart from this problem I think nw.js is a great framework for building cross-platform desktop applications and I'm currently learning to use it. The first working app I built is a tool to view image files contained in a folder as thumbnails, details list or slideshow. Here is a screenshot on Windows:

You can download the source code here. To run the application you need the NPM package manager on your PATH (it's usually installed when you install node.js). Unzip the archive to a folder, then open a terminal/command prompt in that folder and run npm install. This will download all the application's dependencies (which are nw.js and some libraries, like Bootstrap, JQuery) to the node_modules subfolder: it will probably take some time since, as I already said, nw.js files are quite large. Wait for it to finish, then you can run npm start to launch the application.
Note: when I ran the application on Ubuntu, I needed to run sudo chmod 777 -R * to obtain the necessary permissions; you'll probably need to do the same if you want to try the application on Linux or OSX.
More information is available in the README file in the archive.

Wednesday, May 6, 2015

Review: Cubby by LogMeIn, a very flexible cloud storage service

There are lots of cloud storage services on the Internet; when interested to store their files in the cloud, usually people look for a service which offers lots of storage space for free (or cheap prices), is reliable, offers advanced sharing functions, or similar features.  I tried some of the most popular cloud storage services, and read reviews of others; I found them very useful, except for the following thing.
Usually, when you want to sync files between your computer and the cloud, you download and install a client to achieve this. When you install this program, it usually asks you where you want to keep the synchronized files, and you have to select a folder on your drive. This means that when you want to save a file in the cloud (for example to have a backup of it and/or synchronize with other computers or mobile devices) you have to put it in that folder. I find this annoying, because I want to store in the cloud some folders located in different places in my hard disks. Searching the Internet for a solution, I mainly found two alternatives:

  1. Use a "normal" cloud storage service with its client, and a utility (or the command line prompt) to set up symlinks to "cheat" with the client and make it believe that the file/folder you want to sync is in its own folder. There are some utilities and tutorials to do this listed here.
  2. Use Cubby by LogMeIn. This is the only cloud storage service I found that natively allows to choose what folders on your hard drive you want to synchronize. This is actually the service I use to store my files.
The Cubby client is available for Windows and Mac (and as an application for mobile iOS and Android devices), and once you have installed it, you can sync a folder with the cloud using the right-click menu or dragging the folder on the Cubby's window.

You can add any folder to the cloud using the context menu.
This service also has other typical features of other cloud storage services, like sharing and file versioning. Actually, the cloud space available for free amounts to 5 GB.

Monday, March 23, 2015

How to add a placeholder in a Windows Forms textbox

Recently, working on UniversalIDE, my current open source project, I encountered the necessity of adding a placeholder in a TextBox control. UniversalIDE is still based on the Windows Forms user interface instead of the newer WPF one, and the Windows Forms TextBox control doesn't provide natively the placeholder feature. So I decided to write a very simple class which extends the TextBox control and has a PlaceHolderText property that allows to set a placeholder to show when the field is empty.

Here is the Visual Basic .NET code:

Public Class PlaceHolderTextBox
    Inherits TextBox

    Dim isPlaceHolder As Boolean = True
    Dim _placeHolderText As String
    Public Property PlaceHolderText As String
            Return _placeHolderText
        End Get
        Set(value As String)
            _placeHolderText = value
        End Set
    End Property

    Private Sub setPlaceholder() Handles Me.LostFocus 'when the control loses focus, the placeholder is shown
        If Me.Text = "" Then
            Me.Text = PlaceHolderText
            Me.ForeColor = Color.Gray
            Me.Font = New Font(Me.Font, FontStyle.Italic)
            isPlaceHolder = True
        End If
    End Sub

    Private Sub removePlaceHolder() Handles Me.GotFocus 'when the control is focused, the placeholder is removed

        If isPlaceHolder Then
            Me.Text = ""
            Me.ForeColor = System.Drawing.SystemColors.WindowText
            Me.Font = New Font(Me.Font, FontStyle.Regular)
            isPlaceHolder = False
        End If
    End Sub
End Class

You can easily integrate this class in any VB.NET application; simply copy the code in a .vb file (a best practice is to name the file as the class, so PlaceHolderTextBox.vb); then, compile the project, and the PlaceHolderTextBox control will become available as the other normal controls in the Visual Studio Toolbox when you open a Windows Form in Design Mode. Simply drag the control on a form and set the PlaceHolderText property (this can be done from the Properties window, as in the screenshot below, or from code) and you'll get a TextBox with your placeholder.

The PlaceHolderText property in Visual Studio
Example of a PlaceHolderTextBox
Since the code is very simple, it can easily be customized (for example, you may want to change the font color or remove the italic decoration), and you can also translate it into C# if you have a basic knowledge of Visual Basic .NET and C#.

Thursday, January 15, 2015

MSBuild inline tasks: how to write .NET code which runs at compile time to automatize the build process

Recently, working on UniversalIDE, my current open source project, I thought that it would have been interesting to show the git commit ID in the title bar of the program when it's built from a code commit that doesn't represent a release (a nightly build).
But obviously I didn't want to hardcode the commit ID in the source code and change it each time before a new commit (this method is not only unhandy, but it's practically impossible to set up, because you don't know the commit ID before doing the commit itself); so I realized that the best (perhaps the only?) way to achieve this goal was to make the build script of the application to read the current commit ID from the file in .git/refs/heads/master, and put it in the source code before compiling.
After a bit of research I found that it's very simple to insert .NET code in a MSBuild script (which is the file that Visual Studio calls project file, extension .vbproj or .csproj), using MSBuild inline tasks.

These are the steps to follow to add a simple MSBuild inline task that runs before or after the compile process:

  • First of all open the build script: in Visual Studio use the Solution Explorer window to unload the project and to edit the project file (using the project's right-click menu).
  • Define your task(s), for example at the end of the file. Here is an example:
      <!-- replace "SetBuildInfo" with the name you want to give to your task -->
      <UsingTask TaskName="SetBuildInfo" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
        <ParameterGroup />
          <Using Namespace="System" />
          <Using Namespace="System.IO" />
          <Code Type="Fragment" Language="vb"><![CDATA[
              'replace the following example code with your code
              Dim code As String = My.Computer.FileSystem.ReadAllText("UniversalIDEbuildInfo.vb")
              My.Computer.FileSystem.WriteAllText("UniversalIDEbuildInfo_model.vb", code, False, Encoding.ASCII)
              Dim commitID As String = My.Computer.FileSystem.ReadAllText("..\.git\refs\heads\master").Substring(0, 6)
              Dim isNightly As Boolean = True
              For Each tagFile As String In My.Computer.FileSystem.GetFiles("..\.git\refs\tags")
                  If My.Computer.FileSystem.ReadAllText(tagFile).Substring(0, 6) = commitID Then
                      isNightly = False
                      Exit For
                  End If
              code = code.Replace("%IS_NIGHTLY%", isNightly.ToString())
              code = code.Replace("%COMMIT_ID%", commitID)
              My.Computer.FileSystem.WriteAllText("UniversalIDEbuildInfo.vb", code, False, Encoding.ASCII)
              'end of the code snippet
  • Scroll at the bottom of the file: there should be some commented lines which defines the BeforeBuild and AfterBuild tasks; un-comment one of them or both, depending when you want your task(s) to be executed, and call the task(s), using the name you gave at the previous step. Example:
      <Target Name="BeforeBuild">
        <SetBuildInfo />
  • Now save all and reload the project to run it. Note that if your solution has multiple projects and the edited script belongs to the startup project, Visual Studio may have set another project as startup one, so you need to manually re-set it.
You can see a full working example in the UniversalIDE git repository on Sourceforge. For further information, you may found useful the MSDN article about inline tasks.