joliclic blog

Aller au contenu | Aller au menu | Aller à la recherche

jeudi, mai 16 2013

Music Toys: un synthétiseur dans Firefox

this post is also available in english

Prenez Firefox, FluidSynth, js-ctypes, une sf2 soundfont, secouez tout çà, et hop... un vrai synthétiseur, utilisable en temps réel ou comme séquenceur, à l'intérieur de mon navigateur :) .

FluidSynth est une bibliothèque multi-plateforme en C qui utilise des soundfonts sf2.
Au début, c'était une expérimentation, ouvrir cette lib via js-ctypes dans Firefox, et jouer avec.

Mais çà a si bien marché, que j'ai créé 3 petites applis, combinées en une collection nommée Music Toys, qui peut être utilisée comme extension Firefox, ou comme une appli XULRunner autonome (lançable avec Firefox).
Ces applis sont entièrement en JavaScript, utilisant une partie de l'API FluidSynth à travers js-ctypes.


  • La première appli est un Clavier, temps réel et polyphonique, avec 128 instruments disponibles. Vous pouvez jouer avec votre souris, ou le clavier physique de votre ordinateur.


  • La seconde appli est Drum Machine, une boite à rythme. Elle consiste en une liste de pistes, divisées en mesures, temps par mesures, et divisions par temps, contenant des boutons pour allumer les notes (avec vélocité variable).
    47 instruments de percussions sont disponibles, et vous pouvez changer de jeu d'instruments.
    Changer le tempo, jouer votre morceau en temps réel dans une boucle. Et vous pouvez enregistrer/ouvrir vos morceaux dans des fichiers.


  • La troisième appli est un lecteur de fichier Midi. Il peut lire des fichiers mid standard (SMF), encapsulés RMI ou non, et les fichiers kar.
    Il est possible de se déplacer dans le fichier, mettre en pause, changer le volume, modifier la tonalité.

Une petite vidéo de tout çà :

liens directs vers la vidéo :
musictoys.mp4 | musictoys.webm | musictoys.ogv

Si vous souhaitez l'essayer, vous pouvez télécharger çà depuis sa page dédiée : Music Toys. Il y a des versions autonomes pour Linux, Windows, et Mac OSX (avec inclus la lib FluidSynth et une soundfont par défaut), et l'extension Firefox.
Tout le code source est MPL 2.

On peut imaginer plus pour la suite.

Il est envisageable de créer une extension pour Firefox qui exposerait seulement le wrapper vers la lib FluidSynth, et les auteurs d'extensions pourraient y accéder.
Et plus, on pourrait exposer certains objets de base comme un synthé Synth aux pages web (mais la sécurité est à prendre en compte).

Ensuite, il est peut être possible de compiler FluidSynth sur Android, quelques recherche sur la toile montre que certains y seraient arrivé, donc une extension pour Firefox Mobile devrait être possible.
Et peut être qu'on peut compiler FluidSynth pour Firefox OS également (FluidSynth dépend de glib) ?

Mais pour l'instant, faites moi savoir ce que vous en pensez, et si cette beta marche chez vous, j'ai testé principalement sur Linux, donc vos retours depuis divers Windows, 32 ou 64 bit, et Mac, sera précieux ;) .

Music Toys: a synthesizer inside Firefox

ce billet existe aussi en français

Take Firefox, FluidSynth, js-ctypes, a sf2 soundfont, shake all of that, tadaaa... a real synthetizer, usable in real-time or as a sequencer, inside my browser :) .

FluidSynth is a cross platform C library that uses sf2 soundfonts.
At the beginning, it was an experiment, opening this lib via js-ctypes in Firefox, to play with it.

But it worked so well, so I have created 3 little apps, combined in a collection named Music Toys, which can be launched as a Firefox extension, or as a standalone XULRunner application (launchable with Firefox).
These apps are all in JavaScript, using part of the FluidSynth API through js-ctypes.


  • The first app is a Keyboard, real-time and polyphonic, with 128 available instruments. You can play with your mouse, or the physical keyboard of your computer.


  • The second app is a Drum Machine. It consists in a list of tracks, divided in bars, beats per bar, and divisions per beat, containing buttons to switch on notes (with variable velocity).
    47 different percussion instruments are available, and you can change the drumkit.
    Change the tempo, play in real time your pattern in a loop. And you can save/open your patterns in files.


  • The third app is a Midi Player. It can read standard mid files (SMF), RMI encapsulated or not, and kar files.
    You can seek in the file, pause, change the volume, modify the tonality.

A little screencast of all of that:

direct links to the video:
musictoys.mp4 | musictoys.webm | musictoys.ogv

If you want to try it, you can download it from its dedicated page: Music Toys.
There's standalone versions for Linux, Windows, and Mac OSX (with the FluidSynth lib embedded and a default soundfont), and the Firefox extension.
All the source code is MPL 2.

We can imagine more.

It is conceivable to create an extension for Firefox which expose only the FluidSynth wrapper lib, and extension authors can access it.
More, why not expose some basic objects like a Synth to web page, it should be possible (but need to be careful with security).

Secondly, perhaps it's possible to compile FluidSynth on Android, some Web research reveals that some seems able to, so an extension for Firefox Mobile may be possible.
And perhaps FluidSynth can be compiled for Firefox OS too (Fluidsynth need glib)?

But for now, let me know what you think about that, and if this beta works for you, I've tested mostly under Linux, so your feedback from various Windows, 32 or 64 bit, and Mac, will be precious ;) .

vendredi, juin 15 2012

Boox 3.1 alpha 1 for Firefox 13

  • en version
  • version fr

english version

Dear Boox users, here's a first alpha version for Firefox 13. [edit]alpha 2 available ;)

This is a work in progress, don't expect to retrieve all the functionalities for now. And I have not made a lot of tests. But at least, you should retrieve some features ;) . By installing this alpha, you'll have automatic updates for the next alphas/betas.

What should work:

  • the rich tooltips over normal and live bookmarks
  • the feed entry summary in the rich tooltip for live bookmark children
  • The Locate search result in the bookmarks sidebar.
  • Export of an individual bookmarks folder
  • [edit alpha 2]Mark as read feeds and feed entries

What doesn't work yet (deactivated partially for the moment):

  • Boox style (bold) for Live Bookmarks with new entries. This will be a hard part, and I suppose the main missing feature. Hopefully, read/unread live entries are now styled natively in Firefox 13.
  • Number of unread entries in the Live Bookmark labels
  • Usage the Boox own History (to track unread feed entries independently of the native History) have not been tested
  • The Boox feed viewer (with Boox Styles) doesn't work also.

Nevertheless, I hope this first alpha will be useful for some of you ;) .

Ah, and note the new behavior of Firefox 13, feeds are no more updated when Firefox starts, but when you want to see the content of a live bookmark.

version française

Chers utilisateurs de Boox, voici une première version alpha pour Firefox 13. [edit] alpha 2 disponible ;)

C'est un travail en cours, n'espérer pas retrouver toutes les fonctionnalités pour l'instant. Et je n'ai pas fait beaucoup de tests. Mais au moins vous devriez retrouver quelques fonctions. En installant cette alpha, les alphas/betas suivantes devraient s'installer automatiquement.

Ce qui devrait fonctionner :

  • Les infobulles personnalisées sur les marque-pages normaux et dynamiques
  • Les résumés d'entrées de flux dans les infobulles pour les entrées de marque-pages dynamiques
  • La localisation des résultats de recherche dans le panneau de marque-pages.
  • L'export d'un dossier de marque-page individuel
  • [edit alpha 2] Marquer comme lu les flux et leurs entrées

Ce qui ne marche pas encore (désactivé partiellement pour le moment) :

  • Les styles Boox (gras) pour les marque-pages dynamique avec de nouvelles entrées. Ce sera une partie difficile, et je suppose la principale fonctionnalité manquante. Heureusement, les entrées lues/non lues sont maintenant stylées nativement dans Firefox 13.
  • L'indication du nombre de nouvelles entrées dans le label des marque-pages dynamiques.
  • L'utilisation de l'historique propre à Boox (pour connaître les entrées de flux non lues indépendamment de l'historique natif), n'a pas été testé.
  • Le lecteur de flux de Boox (avec les styles de Boox) ne marche pas non plus.

Néanmoins, j'espère que cette première alpha sera utile à quelques uns d'entre vous ;)

Ah, et prenez note du nouveau comportement de Firefox 13, les flux ne sont plus recharger au démarrage de Firefox, mais quand vous voulez voir le contenu d'un marque-page dynamique.

lundi, juin 11 2012

Boox is broken

  • en version
  • version fr

english version

A lot of people contact me about this, and yes, my extension Boox is really broken with Firefox 13.

I have to rewrite a big part. And I need to find time to do it. So please, be patient, follow this blog, I will announce here the next version, probably starting with a beta.

Sorry for the delay, I miss my extension too ;) .

version française

Pas mal de monde me contacte à ce propos, et oui, mon extension Boox est vraiment cassée avec Firefox 13.

Je dois réécrire une grosse partie. Et il me faut trouver du temps pour le faire. Soyez patient, suivez ce blog, j'y annoncerai la prochaine version, sûrement en commençant par une beta.

Désolé pour le retard, mon extension me manque également ;) .

vendredi, mai 27 2011

Distribuer votre appli XULRunner - 5 - Synthèse - toutes plateformes

This post exists also in english

Ce billet fait partie d'une série sur comment déployer une application XULRunner. Voir le préambule pour le contexte.

5 - Synthèse - toutes plateformes

5.1 Changements dans l'appli

Résumons les changements que nous avons apporté à l'application elle-même, pour chaque plateforme :

  • Linux
    • Nous avons ajouté quelques icônes png dans le dossier myapp/chrome/icons/default/ .
      Ceci permet d'avoir notre icône pour nos fenêtres et dans la barre de tâche.
      En details, 16x16px, 32x32px et 48x48px.

      Nous pouvons conserver ces changements globalement, ils n'auront pas d'impact sur les autres plateformes.

  • Windows
    • De manière similaire à Linux, nous avons ajouté quelques icônes .ico dans le dossier myapp/chrome/icons/default/, pour les mêmes raisons.
      Et nous avons créer cette icône depuis Linux avec le programme icotool.

      Nous pouvons conserver ces changements globalement, ils n'auront pas d'impact sur les autres plateformes.

  • Mac OSX
    • Nous avons ajouté un élément menubar principal dans toutes nos fenêtres non modales, avec quelques entrées avec un id spécifique.
      Ceci nous permet d'avoir nos propres entrées dans le Menu principal Mac.
      Ces entrées sont masquées (d'un point de vue XUL) par défaut.

      Nous pouvons conserver ces changements globalement, ils n'auront pas d'impact sur les autres plateformes, parce ces éléments XUL sont masqués pour les autres plateformes.

    • Nous avons ajouté un peu de code JavaScript à notre fichier js principal. Parce que sur un Mac l'appli ne quitte pas quand on ferme toutes les fenêtres.

      Nous pouvons conserver ces changements globalement, le code est multi-plateforme. Mieux, nous pouvons l'utiliser également sur les autres plateformes.

    • Nous avons ajouté un nouveau fichier, une fenêtre XUL masquée. Cette fenêtre est utilisée pour granir le Menu Mac principal quand toutes nos fenêtres sont fermées.

      Nous pouvons conserver ces changements globalement, ils n'auront pas d'impact sur les autres plateformes.

    • Et nous avons ajouté une préférence (browser.hiddenWindowChromeURL), pour utiliser la fenêtre cachée précédente.

      Nous pouvons conserver ces changements globalement, ils n'auront pas d'impact sur les autres plateformes.

Donc, finalement, ce sont de petits changements, et tous peuvent être ajouté globalement, car ils ne perturbent pas les plateformes non ciblées.

5.2 Données ajoutées

Pour une meilleure intégration aux différentes platformes, nous avons ajouté quelques données supplémentaires :

  • Linux
    • Un script shell utilisé comme lanceur, qui utilise de XULRunner ou de Firefox
      Un lien symbolique vers ce lanceur dans /usr/bin/ est également créé par nos installeurs.

    • Un fichier .desktop, A .desktop file, pour l'intégration au bureau, compris par tous les gestionnaires de fenêtre principaux.

    • et quelques icônes (png et svg), utilisées par les fichiers desktop.

  • Windows
    • Un vrai lanceur en C, en fait XAL (XUL App Launcher), qui permet de lancer facilement notre appli avec Firefox, sans aucune fenêtre noire de commande, et qui peut être personnalisé avec noytre icône.
      Ce lanceur peut être compilé directement depuis Linux.

    • Un script batch comme lanceur est également possible, mais avec les défauts inhérents.

  • Mac OSX
    • Pour cette platforme, nous avons en fait encapsulé notre appli dans un dossier avec une structure spéciale, avec quelques données, un Application Bundle

    • Un script shell utilisé comme lanceur, qui utilise Firefox (en fait un lien symbolique vers lui, placé dans notre bundle)

    • Uneicône icns, utilisée par le bundle pour l'exécutable et dans le dock.
      et nous avons créer cette icône depuis Linux avec le programme png2icns.

    • Un fichier Info.plist et un fichier PkgInfo, décrivant le bundle.

5.3 Installeurs créés

  • Multi-plateformes

    Pas de réelle intégration au bureau, et avec quelques limitations importante sur Mac, mais un tar.gz fonctionne et est simple.

  • Linux

    Nous avons créé un paquet deb pour les distributions basées sur Debian/Ubuntu, un deb similaire pour Maemo, et un rpm pour les distributions basées sur Red Hat/Fedora.

  • Windows

    Nous avons créer un vrai installeur/désinstalleur, directement depuis Linux, basé sur NSIS.

  • Mac OSX

    Le mode de distribution le plus convivial sur Mac, est de créer un dmg. Nous avons pu le créer depuis Linux, et avec un programme expérimental, de le compresser.

    Un simple tar.gz a aussi été créé.

5.4 Un script global et réutilisable

Dans chaque chapitres, nous avons utilisés des scripts bash pour créer tous nos installeurs et autres données.
Je vous propose maintenant un script global pour réaliser toutes ces tâches en une fois.

Plus, ce script peut être utilisé pour tout autre application XULRunner, nous avons juste à modifier un fichier de configuration.

Je n'écris ce script ici, vous le trouverez dans l'archive jointe à ce chapitre, mais voilà le fichier de configuration :

#!/bin/bash

#_______________________________________________________________________________
#
# script version: 1.0
# date: 2011-05-20
#_______________________________________________________________________________

# exit the script on errors
set -e

#_______________________________________________________________________________
#
# common configuration
#_______________________________________________________________________________

# The name of the application, will be the name of the executable for example.
# It should contain only [a-zA-Z_-.] and no whitespace.
APP_NAME=myapp

# The name of the application displayed on screen.
APP_DISPLAY_NAME=MyApp

# The absolute path to the directory containing this script. Don't modify this
# variable if you don't know what you are doing.
CUR_DIR=$(dirname "$0")
CUR_DIR=$(readlink -f -- "$CUR_DIR")

# The main folder of the sources (absolute path), containing the app, data,...
# Can be defined before, in some other scripts.
if [ ! $MAIN_DIR ]; then
MAIN_DIR=$(readlink -f -- "$CUR_DIR/..")
fi

# The folder where all resulted builds (installers, archives,...) will be copied
DIST_DIR=$MAIN_DIR/dist

# The temporary folder where all build are done
TMP_DIR=$MAIN_DIR/tmp

# Folder which contains extra useful programs for the build script
TOOLS_DIR=$MAIN_DIR/tools

# Folder which contains all build scripts, and the current config file
BUILDERS_DIR=$MAIN_DIR/builders

# The folder of the real sources of the XULRunner application
APP_SRC_DIR=$MAIN_DIR/$APP_NAME

# The folder of the extra data of the app (icons,...)
APP_DATA_DIR=$MAIN_DIR/data

# The folder of the used icons
# This folder must contains:
# icon16.png, icon22.png, icon26.png, icon32.png, icon40.png, icon48.png,
# icon128.png, icon48.svg, icon.ico, icon.icns, icon48.txt
# You can find some shell scripts in the data/icons folder to create the ico,
# icns et base64 icons.
APP_ICON_DIR=$APP_DATA_DIR/icons

# The current version of the app
APP_VERSION=1.0

# You can use a file named version in the main directory too, and uncomment the
# following line to set this variable
#APP_VERSION=$(cat "$MAIN_DIR/version")

# if the app contains some compiled code, and so it's architecture dependent,
# uncomment the following line
#ARCH_DEPENDENT=1


#_______________________________________________________________________________
#
# Linux specific
#_______________________________________________________________________________

# the folder which contains the Linux specifics data
LINUX_DIR=$APP_DATA_DIR/linux

# the desktop file, will be renamed as $APP_NAME.desktop
DESKTOP_FILE=$LINUX_DIR/desktop

# If this variable is set, the desktop file will be adapted, i.e. the strings
# @@APP_VERSION@@, @@APP_NAME@@, @@APP_DISPLAY_NAME@@, and
# @@APP_DESKTOP_CATEGORIE@@,..., will be replaced by their values. Simply
# comment the following line to not use this feature.
OPT_ADAPT_DESKTOP=1

# this value is displayed in a tooltip by the desktop
APP_DESKTOP_COMMENT="a Hello World XULRunner app"

# A value chosen in http://standards.freedesktop.org/menu-spec/latest/apa.html
# If you use multiple value, use a semicolon (;) as separator
# DON'T forget the last semicolon, even if there is only one value
APP_DESKTOP_CATEGORIE='Utility;'

# You can use this variable to put extra lines to the Desktop file, for example
# a localized comment
APP_DESKTOP_EXTRA='Comment[fr]=un Bonjour Monde pour XULRunner.\n'

# the generic Linux launcher, a shell script, for our app. Will be renamed as
# $APP_NAME.sh
LINUX_LAUNCHER=$LINUX_DIR/launcher.sh


#_______________________________________________________________________________
#
# deb package specific
#_______________________________________________________________________________

# Comment the following line if you don't want to generate a deb package
OPT_BUILD_DEB=1

# the debian folder used to build our generic deb
DEBIAN_DIR=$APP_DATA_DIR/debian

# If this variable is set, the files 'changelog', 'control', 'menu',
# 'myapp.link', and 'copyright' of the debian folder will
# be adapted, i.e. the strings @@APP_VERSION@@, @@APP_NAME@@,
# @@APP_DISPLAY_NAME@@, @@DEB_CONTROL_VERSION@@, @@DEB_CONTROL_SECTION@@,
# @@DEB_MENU_SECTION@@, ..., will be replaced by their values. Simply comment
# the following line to not use this feature.
OPT_ADAPT_DEBIAN=1

# The version of the generated deb package.
DEB_CONTROL_VERSION=${APP_VERSION}-1

# the category of the app. See http://packages.debian.org/en/sid/
DEB_CONTROL_SECTION=Utilities

DEB_CONTROL_MAINTAINER='John Doe <johndoe@example.com>'

# author of the generated deb
DEB_CONTROL_AUTHOR=$DEB_CONTROL_MAINTAINER

DEB_CONTROL_HOMEPAGE='<http://example.com/myapp/>'

# name of the generated package
DEB_CONTROL_PACKAGE=$APP_NAME

# long description of the app for the generated deb. Can be multiline, see
# http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Description
# for the formatting (in short, add at least a space at the beginning of all
# lines apart the first)
DEB_CONTROL_DESCRIPTION='simple Hello World.
Powered by XULRunner.'

# if the app have other dependencies than Firefox, list them, separated by a
# comma. Important, this list MUST begin by a comma.
DEB_CONTROL_EXTRA_DEPENDENCIES=

# if the app contains some compiled code, and you want to use the
# ${shlibs:Depends} variable with debhelper, uncomment the following line
#DEB_CONTROL_USE_SHLIBS_DEPENDS=1

# the category for the Debian menu, see
# http://www.debian.org/doc/packaging-manuals/menu-policy/ch2.html#s2.1
DEB_MENU_SECTION='Applications/Programming'

DEB_DATE="$(date -R)"

DEB_COPYRIGHT='<Copyright (C) 2010 John Doe>'

# the short license for the generated deb
DEB_SHORT_LICENSE=$(cat "$LINUX_DIR/deb_short_license.txt")


#_______________________________________________________________________________
#
# maemo deb specific
#_______________________________________________________________________________

# Note that the debian specific variables are used as well to generate the
# maemo deb, so they must set.

# the APP_NAME specific for Maemo, can be the same as APP_NAME
MOBILE_APP_NAME=$APP_NAME

# the APP_DISPLAY_NAME specific for Maemo, can be the same as APP_DISPLAY_NAME
MOBILE_APP_DISPLAY_NAME=$APP_DISPLAY_NAME

# the name of the app for the package. Should be different than APP_NAME,
# otherwise there can be collision with the generic deb created by the other
# script
MAEMO_PKG_APPNAME=${APP_NAME}-mobile

# the desktop file for Maemo, will be renamed as $APP_NAME.desktop
MAEMO_DESKTOP_FILE=$LINUX_DIR/maemodesktop

# the launcher for Maemo, a shell script, for our app. Will be renamed as
# $APP_NAME.sh
MAEMO_LAUNCHER=$LINUX_DIR/maemolauncher.sh

# Comment the following line if you don't want to generate a deb package
OPT_BUILD_MAEMO_DEB=1

# the debian folder used to build our deb for Maemo
MAEMODEBIAN_DIR=$APP_DATA_DIR/maemodebian

# the categorie of the app for Maemo. See
# http://wiki.maemo.org/Packaging/Guidelines#Sections
DEB_CONTROL_SECTION_MAEMO=user/utilities

# the name of the generated deb for Maemo.
# Should really the same as MAEMO_PKG_APPNAME, see its comment.
DEB_CONTROL_PACKAGE_MAEMO=$MAEMO_PKG_APPNAME

# the description of the generated deb, especially for Maemo. See the comments
# for DEB_CONTROL_DESCRIPTION in this file for formatting.
DEB_CONTROL_DESCRIPTION_MAEMO=$DEB_CONTROL_DESCRIPTION

# like DEB_CONTROL_EXTRA_DEPENDENCIES, but for Maemo
DEB_CONTROL_EXTRA_DEPENDENCIES_MAEMO=

# the base64 file (text) of the icon for the Maemo deb.
# Can be generated by the script 'build_icon_base64.sh' in the data/icons dir.
MAEMO_BASE64_ICON="$APP_ICON_DIR/icon48.txt"


#_______________________________________________________________________________
#
# rpm package specific
#_______________________________________________________________________________

# Comment the following line if you don't want to generate a rpm package
OPT_BUILD_RPM=1

# path to the spec file used to generate the rpm
RPM_SPEC_FILE=$LINUX_DIR/rpmspec

# If this variable is set, the .spec file will
# be adapted, i.e. the strings @@APP_VERSION@@, @@APP_NAME@@,
# @@APP_DISPLAY_NAME@@, @@RPM_VERSION@@, @@RPM_RELEASE@@, @@RPM_GROUP@@,
# @@RPM_LICENSE@@, @@RPM_URL@@, @@RPM_SOURCE@@, @@RPM_DATE@@, ...
# will be replaced by their values. Simply comment the following line to not use
# this feature.
OPT_ADAPT_RPM=1

# version of the app for the spec file: must contain only integer and digit, no
# strings like 'beta'
RPM_VERSION=$APP_VERSION

# the version of the generated rpm, not the app version
RPM_RELEASE='1%{?dist}'

# the short version of the generated rpm, without any string relative to the
# distribution or architecture
#RPM_RELEASE_SHORT=1
RPM_RELEASE_SHORT=$(echo $RPM_RELEASE | sed "s/%.*$//")

# breve summary of the app for the package. One line only.
RPM_SUMMARY='simple Hello World powered by XULRunner.'

# the category of the app. See /usr/share/doc/rpm/GROUPS
RPM_GROUP=Development/Tools

# keyword license
RPM_LICENSE='MPLv1.1 or GPLv2+ or LGPLv2+'

# url where the source of our app can be found
RPM_URL='http://example.com/myapp/'

# the name of the dummy tar.gz source archive, it will be built by this script.
RPM_SOURCE=${APP_NAME}-${RPM_VERSION}.tar.gz

# If the app need some build dependencies, uncomment the following line and add
# them here, separated by a comma. BUT you shouldn't have to, the logic here is
# that the built should have been done before, this script simply package the
# result.
#RPM_BUILDREQUIRES=

# if the app have other dependencies than Firefox, list them, separated by a
# comma. Important, this list MUST begin by a comma.
RPM_EXTRA_REQUIRES=

# long description of the app for the generated rpm. Can be multiline.
RPM_DESCRIPTION='simple Hello World
Powered by XULRunner.'

LC_TIME_BUFFER=$LC_TIME
export LC_TIME="en_EN.utf8"
RPM_DATE=$(date +"%a %b %e %Y")
export LC_TIME="$LC_TIME_BUFFER"

RPM_MAINTAINER='John Doe <johndoe@example.com>'


#_______________________________________________________________________________
#
# Windows specific
#_______________________________________________________________________________

# the folder which contains the Windows specifics data
WIN_DIR=$APP_DATA_DIR/win

# the version of the app used by some other variables. String.
WIN_VERSION=$APP_VERSION

# comment this line if you don't want to build xal, the launcher in C
OPT_BUILD_WIN_XAL=1

# source directory of xal
XAL_SRC_DIR=$TOOLS_DIR/xal-src

# the rc file used to build xal
WIN_RESOURCE=$WIN_DIR/resource.rc

# If this variable is set, the resource (.rc) file for xal will
# be adapted, i.e. the strings @@APP_VERSION@@, @@APP_NAME@@,
# @@APP_DISPLAY_NAME@@, and @@WINRES_...@@
# will be replaced by their values. Simply comment the following line to not use
# this feature.
OPT_ADAPT_WINRES=1

WINRES_FILEVERSION='0,1,0,0'
# the FILEVERSION for Windows (<int,int,int,int>) will be deducted from the
# APP_VERSION. Comment this line if you don't want use this feature
OPT_CALC_WINRES_FVERSION=1

WINRES_PRODUCTVERSION='0,1,0,0'
# the PRODUCTVERSION for Windows (<int,int,int,int>) will be deducted from the
# APP_VERSION. Comment this line if you don't want use this feature
OPT_CALC_WINRES_PVERSION=1

WINRES_Comments='Published under the MPL 1.1/GPL 2.0/LGPL 2.1 licenses'
WINRES_CompanyName='John Doe Organization'
WINRES_FileDescription=$APP_DISPLAY_NAME
WINRES_FileVersion=$WIN_VERSION
WINRES_InternalName=$APP_NAME
WINRES_LegalCopyright='(c) 2010 John Doe'
WINRES_ProductName=$APP_DISPLAY_NAME
WINRES_ProductVersion=$WIN_VERSION

# Comment the following line if you don't want to generate the nsis installer
# for Windows
OPT_BUILD_WIN_INSTALLER=1

# the source folder of the nsis scripts used by this script
NSIS_SRC_DIR=$APP_DATA_DIR/nsis

# If this variable is set, the nsis script will
# be adapted, i.e. the strings @@APP_VERSION@@, @@APP_NAME@@,
# @@APP_DISPLAY_NAME@@, and @@NSIS_...@@
# will be replaced by their values. Simply comment the following line to not use
# this feature.
OPT_ADAPT_NSIS=1

NSIS_PRODUCT_NAME=$APP_DISPLAY_NAME
NSIS_PRODUCT_INTERNAL_NAME=$APP_NAME
NSIS_PRODUCT_VERSION=$WIN_VERSION
NSIS_PRODUCT_WIN_VERSION='1.0.0.0'
# for nsis, the PRODUCTVERSION for Windows (<int,int,int,int>) will be deducted
# from the APP_VERSION. Comment this line if you don't want use this feature
OPT_CALC_NSIS_WINVERSION=1

# The license file text MUST be in the main root app folder, so in $APP_SRC_DIR.
# Otherwise, you can edit the nsis script and adapt it
NSIS_LICENCE_NAME='LICENSE.txt'

# the name of the generated nsis installer
NSIS_INSTALLER_NAME="$APP_DISPLAY_NAME-$APP_VERSION-install.exe"


#_______________________________________________________________________________
#
# Mac OSX specific
#_______________________________________________________________________________

# the folder which contains the Mac OSX specifics data
MAC_DIR=$APP_DATA_DIR/mac

# the simple and basic shell launcher for Mac. Used only for the
# multiplatform tar.gz
MAC_BASIC_LAUNCHER=$MAC_DIR/basic_launcher.sh

# the previous basic launcher will be renamed with this value
# Trick: if the extension is 'command', the file can double-clicked in the Mac
# Finder, then a terminal will be opened and the script will be launched.
MAC_BASIC_LAUNCHER_NAME=${APP_NAME}-mac.command

# Comment the following line if you don't want to generate the Application
# Bundle of the app for Mac.
OPT_BUILD_MAC_BUNDLE=1

# path to the used skeleton of the bundle
DMG_SKELET_DIR=$MAC_DIR/bundle_skelet

# If this variable is set, the nsis script will
# be adapted, i.e. the strings @@APP_VERSION@@, @@APP_NAME@@,
# @@APP_DISPLAY_NAME@@, and @@MAC_...@@
# will be replaced by their values. Simply comment the following line to not use
# this feature.
OPT_ADAPT_MAC_INFO=1

MAC_BUNDLE_EXECUTABLE=${APP_NAME}-mac.sh
MAC_BUNDLE_INFOSTRING="$APP_DISPLAY_NAME $APP_VERSION"
MAC_BUNDLE_ICONFILE=$APP_NAME
MAC_BUNDLE_IDENTIFIER="net.yourcompany.${APP_NAME}"
MAC_BUNDLE_NAME=$APP_DISPLAY_NAME
MAC_BUNDLE_SHORTVERSIONSTRING=$APP_VERSION
MAC_BUNDLE_VERSION=$APP_VERSION

# with this option, the eventual icon 'myapp.icns' in the Contents/Resources
# folder of the used bundle skelet will be removed, and the icns icon of the
# icons folder will be added to the bundle renamed as MAC_BUNDLE_ICONFILE
MAC_BUNDLE_OVERWRITE_ICON=1

# comment the following line if you don't want to generate a dmg image
OPT_BUILD_MAC_DMG=1
# comment the following line if you don't want to customize the dmg image
OPT_CUSTOMIZE_DMG=1
# source folder of the data added to the dmg, to customize it
# Note that you have to recreate manually these customizations files if the
# DMG_VOLNAME is different than 'MyApp', in particular the background image
# will not be displayed. See the Howto.
# Comment the line to disabled this option.
DMG_CUSTOM_DATA_DIR=$MAC_DIR/dmg_extra_data

# the name of the mounted dmg disk image
DMG_VOLNAME="$APP_DISPLAY_NAME"
# the name of the generated dmg
DMG_NAME="$APP_NAME-$APP_VERSION.dmg"

# comment the following line if you don't want to compress the dmg. You need
# the <dmg> program to be able to do that
OPT_COMPRESS_DMG=1
# path to the dmg program, used to compress the dmg.
# see http://github.com/planetbeing/libdmg-hfsplus
# and http://shanemcc.co.uk/libdmg/
TOOL_DMG="$TOOLS_DIR/dmg"


#_______________________________________________________________________________
#
# Multi-platform tar.gz archive (usable on Linux, Windows, Mac OSX)
#_______________________________________________________________________________

# Note that al lot of previous variables (Linux, Windows, and Mac OSX specific)
# will be used to build this archive

# Comment the following line if you don't want to generate multi-platform tar.gz
# Note that if ARCH_DEPENDENT is active, this archive will NOT be built
OPT_BUILD_MULTI_TARGZ=1

# the name of the generated tar.gz
TARGZ_NAME=${APP_NAME}-${APP_VERSION}-multiplatform


#_______________________________________________________________________________

BUILD_CONFIG_INCLUDED=1

Pour utiliser ce script pour votre application, en raccourci vous devez remplacer toutes les données du dossier data, images, fichier... puis ouvrir et adapter le script build_config.sh pour votre appli.

En detail :

  • remplacer toutes les icônes du dossier data/icons par les votres.
    Si vous n'avez pas celles aux formats .ico et .icns, utilisez les scripts build_ico.sh et build_icns.sh pour les créer. Et utilisez le script build_base64.sh pour générer l'icône base64 pour le paquet Maemo.

  • Éditez et modifiez le fichier deb_short_license.txt dans le dossier data/linux.

  • Si vous voulez créer un dmg pour Mac OSX et le personnaliser, vous devez recréer les données utilisées, en particulier le fichier .DS_STORE, et remplacer celles du dossier data/mac/dmg_extra_data par les votres. Faites attention, il y a quelques fichiers cachés dans ce dossier sur Linux, parce que leur noms commencent par un point (.) (CTRL+H in Nautilus to show them ;).

  • Assurez vous d'avoir un fichier de licence dans le dossier principal de vottre appli, c'est nécessaire pour créer l'installeur Windows, et c'est vraiment une bonne pratique.

  • Toutes les autres données peuvent etre utilisées telles quelles, parce que leurs contenus sont parséx par les scripts et utilise le fichier de config, mais vous aussi pouvez les éditer et les modifier si vous le souhaitez.

  • Si vous voulez créer un dmg compressé pour Mac OSX, vous devez télécharger le programme libdmg depuis la page de l'auteur ou cette version modifiée, et le placer dans le dossier tools.

  • Enfin, éditer et adapter le fichier config.sh dans le dossier builders.
    Les paramètres les plus importants sont APP_NAME et APP_DISPLAY_NAME, beaucoup d'autres paramètres utilisent leurs valeurs.
    Et bien le chemin vers les sources de votre appli, çà peut être une bonne idée de les placer au même niveau que l'exemple myapp, mais ce n'est pas obligatoire.
    Remplacer bien sûr toutes les chaînes spécifiques à l'exemple myapp.

Puis dans un terminal :

  • cd myapp-src-global
  • sh ./build_all.sh

Et vous trouverez alors dans le dossier myapp-src-all/dist/ tous les installeurs créés.

5.5 Conclusions

Créer des applications XULRunner est facile, puissant et multi-plateforme, comme développer des extensions Firefox.

Vous pouvez utiliser des assistants sur mozdev.org pour générer des squelettes pour commencer une nouvelle appli (attention vous devrez adapter enregistrement chrome pour Firefox 4, l'assistant a besoin apparemment d'être mis à jour pour cette partie).

Nous avons vu dans ce tutoriel quelques petites parties auxquelles nous devons faire attention pour une meilleure intégration au bureau, et qu'il est relativement simple de créer des installeurs, depuis Linux, pour différentes plateformes cibles. Vous pouvez même réutiliser le script global, ou vous en inspirer, pour créer ces installeurs pour votre application.

Maintenant c'est à vous de faire de jolies applis, j'espère que ce tuto et le script global vous aideront.
Amusez vous bien ;) !

Nicolas Martin

Vous pouvez télécharger tous les exemples de ce chapitre 5, le script global et XAL inclus, dans l'archive myapp-src-global.tar.gz .

Ou retrouver l'intégralité de ce tuto dans sa page dédiée, disponible en téléchargement avec tous les exemples compris.

L'application myapp, de developer.mozilla.org, est dans le Domaine Public.

L'icône utilisée est issue du Tango Desktop Project, et est dans le Domaine Public.

le lanceur C XUL App Launcher (XAL) est sous licence MIT.

Toutes les autres données ajoutées, et les fichiers en exemple, de ce chapitre 3, sont dans le Domain Public également.

Distribute your XULRunner app - 5 - Synthesis - all platforms

Ce billet existe aussi en français

This post is part of a series about how to package a XULRunner application.
See the preamble for the context case.

5 - Synthesis - all platforms

5.1 Changes to the app

Let summarize the changes we have made to the application itself, for each platform:

  • Linux
    • We have added some png icons into the myapp/chrome/icons/default/ folder.
      This allows to have our icon for our windows and taskbar.
      In details, 16x16px, 32x32px and 48x48px.

      We can keep this change globally, it will have no impact on other platforms.

  • Windows
    • Similarly as for Linux, we have added some .ico icon into the myapp/chrome/icons/default/ folder, for the same reasons.
      And we have built this icon from Linux with the icotool program.

      We can keep this change globally, it will have no impact on other platforms.

  • Mac OSX
    • We have added a main menubar in all our non-modal windows, with some entries with a special id.
      This allows to have our owns entries in the Main Menu of Mac.
      These entries are hidden (in XUL sens) by default.

      We can keep this change globally, it will have no impact on other platforms, because these XUL elements are hidden for other platforms.

    • We have added some JavaScript code to our main js file, to allow quitting properly our app. Because on a Mac the app doesn't quit when we close all windows.

      We can keep this change globally, this code is multi platform. More, we can use it on the other platform as well.

    • We have added a new file, an hidden XUL window. This window is used to populate the Main Mac Menu when all our windows are closed.

      We can keep this change globally, it will have no impact on other platforms.

    • And we have added a new preference (browser.hiddenWindowChromeURL), to use the previous hidden window.

      We can keep this change globally, it will have no impact on other platforms.

So, finally these are small changes, and all of them can be added globally, because they don't disturb the untargeted platforms.

5.2 Added data

For a better integration to each platforms, we have added some specific data:

  • Linux
    • A shell script used as launcher, which relies on XULRunner or Firefox.
      A symbolic link to this launcher into /usr/bin/ is also created by our installers.

    • A .desktop file, for desktop integration, understood by all main Window Manager.

    • And some icons (png and svg), used by the desktop files.

  • Windows
    • A real launcher in C, in fact XAL (XUL App Launcher), which allows to easily launch our app with Firefox, without any black command window, and can be customized with our icon.
      This launcher can be compiled directly from Linux.

    • A batch script as launcher, is possible too, but with some inherent defaults.

  • Mac OSX
    • For this platform, we have in fact encapsulated our app into a special folder structure with some data, an Application Bundle

    • A shell script used as launcher, which uses Firefox (in fact a symbolic link to it, placed in our bundle)

    • A icns icon, used by the bundle for the executable and in the dock.
      And we have built this icon from Linux with the png2icns program.

    • A Info.plist file and a PkgInfo file, describing the bundle.

5.3 Created installers

  • Multi-platform

    No real desktop integration, and with some real limitations on Mac, but a tar.gz works and is simple.

  • Linux

    We have created a deb package for Debian/Ubuntu based distributions, a similar deb for Maemo, and a rpm for Red Hat/Fedora based distributions.

  • Windows

    We have built a real installer/uninstaller, directly from Linux, based on NSIS.

  • Mac OSX

    The easiest distribution method on Mac, is to create a dmg. We have been able to build it from Linux, and with an experimental program, to compress it.

    A simple tar.gz was created too.

5.4 A global and reusable script

In each chapters, we have used some dedicated bash scripts to create all our installers and other data.
I propose now a global script to performs all the tasks in one shot.

More, this script can be used with any other XULRunner application, we only have to adapt a config file.

I don't write this script here, you'll find it in the joined archive of this chapter, but here's the config file:

#!/bin/bash

#_______________________________________________________________________________
#
# script version: 1.0
# date: 2011-05-20
#_______________________________________________________________________________

# exit the script on errors
set -e

#_______________________________________________________________________________
#
# common configuration
#_______________________________________________________________________________

# The name of the application, will be the name of the executable for example.
# It should contain only [a-zA-Z_-.] and no whitespace.
APP_NAME=myapp

# The name of the application displayed on screen.
APP_DISPLAY_NAME=MyApp

# The absolute path to the directory containing this script. Don't modify this
# variable if you don't know what you are doing.
CUR_DIR=$(dirname "$0")
CUR_DIR=$(readlink -f -- "$CUR_DIR")

# The main folder of the sources (absolute path), containing the app, data,...
# Can be defined before, in some other scripts.
if [ ! $MAIN_DIR ]; then
MAIN_DIR=$(readlink -f -- "$CUR_DIR/..")
fi

# The folder where all resulted builds (installers, archives,...) will be copied
DIST_DIR=$MAIN_DIR/dist

# The temporary folder where all build are done
TMP_DIR=$MAIN_DIR/tmp

# Folder which contains extra useful programs for the build script
TOOLS_DIR=$MAIN_DIR/tools

# Folder which contains all build scripts, and the current config file
BUILDERS_DIR=$MAIN_DIR/builders

# The folder of the real sources of the XULRunner application
APP_SRC_DIR=$MAIN_DIR/$APP_NAME

# The folder of the extra data of the app (icons,...)
APP_DATA_DIR=$MAIN_DIR/data

# The folder of the used icons
# This folder must contains:
# icon16.png, icon22.png, icon26.png, icon32.png, icon40.png, icon48.png,
# icon128.png, icon48.svg, icon.ico, icon.icns, icon48.txt
# You can find some shell scripts in the data/icons folder to create the ico,
# icns et base64 icons.
APP_ICON_DIR=$APP_DATA_DIR/icons

# The current version of the app
APP_VERSION=1.0

# You can use a file named version in the main directory too, and uncomment the
# following line to set this variable
#APP_VERSION=$(cat "$MAIN_DIR/version")

# if the app contains some compiled code, and so it's architecture dependent,
# uncomment the following line
#ARCH_DEPENDENT=1


#_______________________________________________________________________________
#
# Linux specific
#_______________________________________________________________________________

# the folder which contains the Linux specifics data
LINUX_DIR=$APP_DATA_DIR/linux

# the desktop file, will be renamed as $APP_NAME.desktop
DESKTOP_FILE=$LINUX_DIR/desktop

# If this variable is set, the desktop file will be adapted, i.e. the strings
# @@APP_VERSION@@, @@APP_NAME@@, @@APP_DISPLAY_NAME@@, and
# @@APP_DESKTOP_CATEGORIE@@,..., will be replaced by their values. Simply
# comment the following line to not use this feature.
OPT_ADAPT_DESKTOP=1

# this value is displayed in a tooltip by the desktop
APP_DESKTOP_COMMENT="a Hello World XULRunner app"

# A value chosen in http://standards.freedesktop.org/menu-spec/latest/apa.html
# If you use multiple value, use a semicolon (;) as separator
# DON'T forget the last semicolon, even if there is only one value
APP_DESKTOP_CATEGORIE='Utility;'

# You can use this variable to put extra lines to the Desktop file, for example
# a localized comment
APP_DESKTOP_EXTRA='Comment[fr]=un Bonjour Monde pour XULRunner.\n'

# the generic Linux launcher, a shell script, for our app. Will be renamed as
# $APP_NAME.sh
LINUX_LAUNCHER=$LINUX_DIR/launcher.sh


#_______________________________________________________________________________
#
# deb package specific
#_______________________________________________________________________________

# Comment the following line if you don't want to generate a deb package
OPT_BUILD_DEB=1

# the debian folder used to build our generic deb
DEBIAN_DIR=$APP_DATA_DIR/debian

# If this variable is set, the files 'changelog', 'control', 'menu',
# 'myapp.link', and 'copyright' of the debian folder will
# be adapted, i.e. the strings @@APP_VERSION@@, @@APP_NAME@@,
# @@APP_DISPLAY_NAME@@, @@DEB_CONTROL_VERSION@@, @@DEB_CONTROL_SECTION@@,
# @@DEB_MENU_SECTION@@, ..., will be replaced by their values. Simply comment
# the following line to not use this feature.
OPT_ADAPT_DEBIAN=1

# The version of the generated deb package.
DEB_CONTROL_VERSION=${APP_VERSION}-1

# the category of the app. See http://packages.debian.org/en/sid/
DEB_CONTROL_SECTION=Utilities

DEB_CONTROL_MAINTAINER='John Doe <johndoe@example.com>'

# author of the generated deb
DEB_CONTROL_AUTHOR=$DEB_CONTROL_MAINTAINER

DEB_CONTROL_HOMEPAGE='<http://example.com/myapp/>'

# name of the generated package
DEB_CONTROL_PACKAGE=$APP_NAME

# long description of the app for the generated deb. Can be multiline, see
# http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Description
# for the formatting (in short, add at least a space at the beginning of all
# lines apart the first)
DEB_CONTROL_DESCRIPTION='simple Hello World.
Powered by XULRunner.'

# if the app have other dependencies than Firefox, list them, separated by a
# comma. Important, this list MUST begin by a comma.
DEB_CONTROL_EXTRA_DEPENDENCIES=

# if the app contains some compiled code, and you want to use the
# ${shlibs:Depends} variable with debhelper, uncomment the following line
#DEB_CONTROL_USE_SHLIBS_DEPENDS=1

# the category for the Debian menu, see
# http://www.debian.org/doc/packaging-manuals/menu-policy/ch2.html#s2.1
DEB_MENU_SECTION='Applications/Programming'

DEB_DATE="$(date -R)"

DEB_COPYRIGHT='<Copyright (C) 2010 John Doe>'

# the short license for the generated deb
DEB_SHORT_LICENSE=$(cat "$LINUX_DIR/deb_short_license.txt")


#_______________________________________________________________________________
#
# maemo deb specific
#_______________________________________________________________________________

# Note that the debian specific variables are used as well to generate the
# maemo deb, so they must set.

# the APP_NAME specific for Maemo, can be the same as APP_NAME
MOBILE_APP_NAME=$APP_NAME

# the APP_DISPLAY_NAME specific for Maemo, can be the same as APP_DISPLAY_NAME
MOBILE_APP_DISPLAY_NAME=$APP_DISPLAY_NAME

# the name of the app for the package. Should be different than APP_NAME,
# otherwise there can be collision with the generic deb created by the other
# script
MAEMO_PKG_APPNAME=${APP_NAME}-mobile

# the desktop file for Maemo, will be renamed as $APP_NAME.desktop
MAEMO_DESKTOP_FILE=$LINUX_DIR/maemodesktop

# the launcher for Maemo, a shell script, for our app. Will be renamed as
# $APP_NAME.sh
MAEMO_LAUNCHER=$LINUX_DIR/maemolauncher.sh

# Comment the following line if you don't want to generate a deb package
OPT_BUILD_MAEMO_DEB=1

# the debian folder used to build our deb for Maemo
MAEMODEBIAN_DIR=$APP_DATA_DIR/maemodebian

# the categorie of the app for Maemo. See
# http://wiki.maemo.org/Packaging/Guidelines#Sections
DEB_CONTROL_SECTION_MAEMO=user/utilities

# the name of the generated deb for Maemo.
# Should really the same as MAEMO_PKG_APPNAME, see its comment.
DEB_CONTROL_PACKAGE_MAEMO=$MAEMO_PKG_APPNAME

# the description of the generated deb, especially for Maemo. See the comments
# for DEB_CONTROL_DESCRIPTION in this file for formatting.
DEB_CONTROL_DESCRIPTION_MAEMO=$DEB_CONTROL_DESCRIPTION

# like DEB_CONTROL_EXTRA_DEPENDENCIES, but for Maemo
DEB_CONTROL_EXTRA_DEPENDENCIES_MAEMO=

# the base64 file (text) of the icon for the Maemo deb.
# Can be generated by the script 'build_icon_base64.sh' in the data/icons dir.
MAEMO_BASE64_ICON="$APP_ICON_DIR/icon48.txt"


#_______________________________________________________________________________
#
# rpm package specific
#_______________________________________________________________________________

# Comment the following line if you don't want to generate a rpm package
OPT_BUILD_RPM=1

# path to the spec file used to generate the rpm
RPM_SPEC_FILE=$LINUX_DIR/rpmspec

# If this variable is set, the .spec file will
# be adapted, i.e. the strings @@APP_VERSION@@, @@APP_NAME@@,
# @@APP_DISPLAY_NAME@@, @@RPM_VERSION@@, @@RPM_RELEASE@@, @@RPM_GROUP@@,
# @@RPM_LICENSE@@, @@RPM_URL@@, @@RPM_SOURCE@@, @@RPM_DATE@@, ...
# will be replaced by their values. Simply comment the following line to not use
# this feature.
OPT_ADAPT_RPM=1

# version of the app for the spec file: must contain only integer and digit, no
# strings like 'beta'
RPM_VERSION=$APP_VERSION

# the version of the generated rpm, not the app version
RPM_RELEASE='1%{?dist}'

# the short version of the generated rpm, without any string relative to the
# distribution or architecture
#RPM_RELEASE_SHORT=1
RPM_RELEASE_SHORT=$(echo $RPM_RELEASE | sed "s/%.*$//")

# breve summary of the app for the package. One line only.
RPM_SUMMARY='simple Hello World powered by XULRunner.'

# the category of the app. See /usr/share/doc/rpm/GROUPS
RPM_GROUP=Development/Tools

# keyword license
RPM_LICENSE='MPLv1.1 or GPLv2+ or LGPLv2+'

# url where the source of our app can be found
RPM_URL='http://example.com/myapp/'

# the name of the dummy tar.gz source archive, it will be built by this script.
RPM_SOURCE=${APP_NAME}-${RPM_VERSION}.tar.gz

# If the app need some build dependencies, uncomment the following line and add
# them here, separated by a comma. BUT you shouldn't have to, the logic here is
# that the built should have been done before, this script simply package the
# result.
#RPM_BUILDREQUIRES=

# if the app have other dependencies than Firefox, list them, separated by a
# comma. Important, this list MUST begin by a comma.
RPM_EXTRA_REQUIRES=

# long description of the app for the generated rpm. Can be multiline.
RPM_DESCRIPTION='simple Hello World
Powered by XULRunner.'

LC_TIME_BUFFER=$LC_TIME
export LC_TIME="en_EN.utf8"
RPM_DATE=$(date +"%a %b %e %Y")
export LC_TIME="$LC_TIME_BUFFER"

RPM_MAINTAINER='John Doe <johndoe@example.com>'


#_______________________________________________________________________________
#
# Windows specific
#_______________________________________________________________________________

# the folder which contains the Windows specifics data
WIN_DIR=$APP_DATA_DIR/win

# the version of the app used by some other variables. String.
WIN_VERSION=$APP_VERSION

# comment this line if you don't want to build xal, the launcher in C
OPT_BUILD_WIN_XAL=1

# source directory of xal
XAL_SRC_DIR=$TOOLS_DIR/xal-src

# the rc file used to build xal
WIN_RESOURCE=$WIN_DIR/resource.rc

# If this variable is set, the resource (.rc) file for xal will
# be adapted, i.e. the strings @@APP_VERSION@@, @@APP_NAME@@,
# @@APP_DISPLAY_NAME@@, and @@WINRES_...@@
# will be replaced by their values. Simply comment the following line to not use
# this feature.
OPT_ADAPT_WINRES=1

WINRES_FILEVERSION='0,1,0,0'
# the FILEVERSION for Windows (<int,int,int,int>) will be deducted from the
# APP_VERSION. Comment this line if you don't want use this feature
OPT_CALC_WINRES_FVERSION=1

WINRES_PRODUCTVERSION='0,1,0,0'
# the PRODUCTVERSION for Windows (<int,int,int,int>) will be deducted from the
# APP_VERSION. Comment this line if you don't want use this feature
OPT_CALC_WINRES_PVERSION=1

WINRES_Comments='Published under the MPL 1.1/GPL 2.0/LGPL 2.1 licenses'
WINRES_CompanyName='John Doe Organization'
WINRES_FileDescription=$APP_DISPLAY_NAME
WINRES_FileVersion=$WIN_VERSION
WINRES_InternalName=$APP_NAME
WINRES_LegalCopyright='(c) 2010 John Doe'
WINRES_ProductName=$APP_DISPLAY_NAME
WINRES_ProductVersion=$WIN_VERSION

# Comment the following line if you don't want to generate the nsis installer
# for Windows
OPT_BUILD_WIN_INSTALLER=1

# the source folder of the nsis scripts used by this script
NSIS_SRC_DIR=$APP_DATA_DIR/nsis

# If this variable is set, the nsis script will
# be adapted, i.e. the strings @@APP_VERSION@@, @@APP_NAME@@,
# @@APP_DISPLAY_NAME@@, and @@NSIS_...@@
# will be replaced by their values. Simply comment the following line to not use
# this feature.
OPT_ADAPT_NSIS=1

NSIS_PRODUCT_NAME=$APP_DISPLAY_NAME
NSIS_PRODUCT_INTERNAL_NAME=$APP_NAME
NSIS_PRODUCT_VERSION=$WIN_VERSION
NSIS_PRODUCT_WIN_VERSION='1.0.0.0'
# for nsis, the PRODUCTVERSION for Windows (<int,int,int,int>) will be deducted
# from the APP_VERSION. Comment this line if you don't want use this feature
OPT_CALC_NSIS_WINVERSION=1

# The license file text MUST be in the main root app folder, so in $APP_SRC_DIR.
# Otherwise, you can edit the nsis script and adapt it
NSIS_LICENCE_NAME='LICENSE.txt'

# the name of the generated nsis installer
NSIS_INSTALLER_NAME="$APP_DISPLAY_NAME-$APP_VERSION-install.exe"


#_______________________________________________________________________________
#
# Mac OSX specific
#_______________________________________________________________________________

# the folder which contains the Mac OSX specifics data
MAC_DIR=$APP_DATA_DIR/mac

# the simple and basic shell launcher for Mac. Used only for the
# multiplatform tar.gz
MAC_BASIC_LAUNCHER=$MAC_DIR/basic_launcher.sh

# the previous basic launcher will be renamed with this value
# Trick: if the extension is 'command', the file can double-clicked in the Mac
# Finder, then a terminal will be opened and the script will be launched.
MAC_BASIC_LAUNCHER_NAME=${APP_NAME}-mac.command

# Comment the following line if you don't want to generate the Application
# Bundle of the app for Mac.
OPT_BUILD_MAC_BUNDLE=1

# path to the used skeleton of the bundle
DMG_SKELET_DIR=$MAC_DIR/bundle_skelet

# If this variable is set, the nsis script will
# be adapted, i.e. the strings @@APP_VERSION@@, @@APP_NAME@@,
# @@APP_DISPLAY_NAME@@, and @@MAC_...@@
# will be replaced by their values. Simply comment the following line to not use
# this feature.
OPT_ADAPT_MAC_INFO=1

MAC_BUNDLE_EXECUTABLE=${APP_NAME}-mac.sh
MAC_BUNDLE_INFOSTRING="$APP_DISPLAY_NAME $APP_VERSION"
MAC_BUNDLE_ICONFILE=$APP_NAME
MAC_BUNDLE_IDENTIFIER="net.yourcompany.${APP_NAME}"
MAC_BUNDLE_NAME=$APP_DISPLAY_NAME
MAC_BUNDLE_SHORTVERSIONSTRING=$APP_VERSION
MAC_BUNDLE_VERSION=$APP_VERSION

# with this option, the eventual icon 'myapp.icns' in the Contents/Resources
# folder of the used bundle skelet will be removed, and the icns icon of the
# icons folder will be added to the bundle renamed as MAC_BUNDLE_ICONFILE
MAC_BUNDLE_OVERWRITE_ICON=1

# comment the following line if you don't want to generate a dmg image
OPT_BUILD_MAC_DMG=1
# comment the following line if you don't want to customize the dmg image
OPT_CUSTOMIZE_DMG=1
# source folder of the data added to the dmg, to customize it
# Note that you have to recreate manually these customizations files if the
# DMG_VOLNAME is different than 'MyApp', in particular the background image
# will not be displayed. See the Howto.
# Comment the line to disabled this option.
DMG_CUSTOM_DATA_DIR=$MAC_DIR/dmg_extra_data

# the name of the mounted dmg disk image
DMG_VOLNAME="$APP_DISPLAY_NAME"
# the name of the generated dmg
DMG_NAME="$APP_NAME-$APP_VERSION.dmg"

# comment the following line if you don't want to compress the dmg. You need
# the <dmg> program to be able to do that
OPT_COMPRESS_DMG=1
# path to the dmg program, used to compress the dmg.
# see http://github.com/planetbeing/libdmg-hfsplus
# and http://shanemcc.co.uk/libdmg/
TOOL_DMG="$TOOLS_DIR/dmg"


#_______________________________________________________________________________
#
# Multi-platform tar.gz archive (usable on Linux, Windows, Mac OSX)
#_______________________________________________________________________________

# Note that al lot of previous variables (Linux, Windows, and Mac OSX specific)
# will be used to build this archive

# Comment the following line if you don't want to generate multi-platform tar.gz
# Note that if ARCH_DEPENDENT is active, this archive will NOT be built
OPT_BUILD_MULTI_TARGZ=1

# the name of the generated tar.gz
TARGZ_NAME=${APP_NAME}-${APP_VERSION}-multiplatform


#_______________________________________________________________________________

BUILD_CONFIG_INCLUDED=1

To use this script for your own application, in short you have to overwrite all data included in the data folder, image, files... then open and adapt the build_config.sh script to your own.

In detail:

  • replace all icons in the data/icons folder by your owns.
    If you don't have the .ico and .icns ones, use the scripts build_ico.sh and build_icns.sh to build them. And use the build_base64.sh script to generate the base64 icon for the Maemo package.

  • Edit and modify the file deb_short_license.txt in the data/linux folder.

  • If you want to create a dmg for Mac OSX and customize it, you should recreate the used data, in particular the .DS_STORE file, and overwrite them in the data/mac/dmg_extra_data folder. Be careful, there're some hidden files in this folder on Linux, because their names begin with a dot (.) (CTRL+H in Nautilus to show them ;).

  • Be sure to have a license file into the main folder of your app, this is required to build the Windows installer, and this is really a good practice.

  • All other data could be used as is, because their contents will parsed by the scripts and use the config file, but you can edit and change them as well.

  • If you want to create a compressed dmg for Mac OSX, you have to download the libdmg program from the author page or this modified version, and place it in the tools folder.

  • Finally, edit and adapt the config.sh file in the builders folder.
    The most important parameters are APP_NAME and APP_DISPLAY_NAME, a lot of others parameters use them.
    And of course the path to the sources of your app, it could be a good idea to place them at the same level of the myapp example, but that's not required.
    Replace of course all strings specifics to the myapp example.

Then, in a terminal:

  • cd myapp-src-global
  • sh ./build_all.sh

And you will find into the myapp-src-all/dist/ folder all the created installers.

5.5 Conclusions

Creating XULRunner applications is easy, powerful, and multiplatform, like developing Firefox extensions.

You can use some wizards from mozdev.org to generate a skeleton to begin a new app (be careful, you will have to adapt the chrome registration for Firefox 4, the wizard need apparently to be updated for this part).

We have seen in this how-to some small parts that we need to taking care for a better desktop integration, and that it is relatively easy to create installers, from Linux, for several platforms. You can even reuse the global script, or get inspiration from it, to create these installers for your own application.

Now it's up to you to make some nice apps, I hope this how-to and the global script will help you.
Have fun ;) !

Nicolas Martin

You can download all the samples of this chapter 5, the global script and XAL included, in the myapp-src-global.tar.gz archive.

Or retrieve this entire how-to in its dedicated page, downloadable with all the examples.

The myapp application, from developer.mozilla.org is in the Public Domain.

The icon used is from the Tango Desktop Project, and is in the Public Domain.

The C launcher XUL App Launcher (XAL) is under the MIT license.

All other added data, and sample files, of this chapter 5, are under Public Domains too.

- page 1 de 12