Attention : Le contenu de ces pages n'a pas été mis à jour depuis longtemps. Il est probablement obsolète pour Firefox 4.0/Gecko 4.0 et supérieur. Pour du contenu plus récent, allez consulter developer.mozilla.org.

Application autonome

Cette section contient des informations pour réaliser des applications indépendantes de Mozilla ou Firefox, mais embarquant le toolkit/framework et le moteur de Mozilla/Firefox.

Embarquer gecko dans un logiciel non XUL

Voir par exemple : http://dsoulayrol.free.fr/articles/mozil(..)

Tutoriel de création d'une appli standalone utilisant le framework de Mozilla

Bon, pour réaliser un Hello World autonome, basé sur le source de nvu-0.60 J'ai fait comme ça, en prenant comme modèle Nvu lui-même. La plupart des exemples qui suivent sortent de Nvu, avec juste des modifications pour adapter (nom, CID; etc.).

Créer une arborescence dans le dossier racine (mozilla/):

Répertoire StandAloneApp/

On va tout mettre dedans

Répertoire StandAloneApp/app/

c'est la partie qui contient la base: nsStandAloneApp.cpp contient main() et il contient le nom du dossier (.mozilla dans Mozilla) des préférences utilisateur ! Le Makefile.in contient également le nom de l'exécutable.

nsStandAloneApp.cpp

 #include "nsXULAppAPI.h"
 #ifdef XP_WIN
 #include <windows.h>
 #endif
 int main(int argc, char** argv)
 {
   nsXREAppData appData;
   appData.SetSplashEnabled(PR_FALSE);
   appData.SetProductName(NS_LITERAL_CSTRING( "HelloWorld" ));
   appData.SetUseStartupPrefs(PR_TRUE);
   return xre_main(argc, argv, appData);
 }
 #if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_GTK2)
 char* splash_xpm[] = {0};
 #endif
 #if defined( XP_WIN ) && defined( WIN32 ) && !defined(''''_''''_''''GNUC''''_''''_'''')
 // We need WinMain in order to not be a console app.  This function is
 // unused if we are a console application.
 int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR args, int )
 {
     // Do the real work.
     return main( _''''_argc, _''''_argv );
 }
 #endif

Le "appData.SetProductName(NS_LITERAL_CSTRING( "HelloWorld" ))" définit le nom du répertoire utilisateur (.helloworld)

Répertoire StandAloneApp/app/profile/

contient les préférences utilisateurs par défaut. Le fichier all.js contient en particulier des lignes comme ça.

 pref("general.startup.browser",             false);
 pref("general.startup.mail",                false);
 pref("general.startup.news",                false);
 pref("general.startup.editor",              false);
 pref("general.startup.compose",             false);
 pref("general.startup.addressbook",         false);

C'est utilisé pour décider quelle application démarre par défaut. Il faudra en ajouter une pour notre application, qui sera enregistrée dans le composant XPCOM définissant le service (nsStandAloneService).

 pref("general.startup.helloworld",         true);

Répertoire StandAloneApp/base/

contient la définition de l'interface, avec ses fichiers xul et js. Plus un jar.mn pour créer le fichier .jar correspondant. Le fichier xul "principal" sera associé au démarrage de l'application définit par le general.startup.helloworld de tout à l'heure par le Service XPCom.

Répertoire StandAloneApp/components

J'ai regroupé là les composants XPCom de l'application. Il y en a un d'obligatoire, si on veut une application autonome: celui qui s'enregistre comme implémentant l'interface CmdLineHandler, celle qui s'occupe de lancer le bon fichier xul au démarrage.

Répertoire StandAloneApp/components/StandAloneService/

Pour les fichiers du module XPCom implantant le service principal: associer le démarrage avec pref("general.startup.helloworld", true);, et avec "-helloworld" comme option de démarrage, au fichier xul adéquat.

Répertoire StandAloneApp/components/StandAloneService/src/

nsStandAloneService.h

 #ifndef nsStandAloneService_h___
 #define nsStandAloneService_h_''''_''''_
 #include "nsICmdLineHandler.h"
 class nsStandAloneService : public nsICmdLineHandler
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSICMDLINEHANDLER
   nsStandAloneService();
   virtual ~nsStandAloneService();
   CMDLINEHANDLER_REGISTERPROC_DECLS
 };
 #define NS_STANDALONESERVICE_CONTRACT_CID ="@mozilla.org/helloworld/helloworldservice;1"
 #define NS_STANDALONESERVICE_CID 
 {/* {9477b791-3f37-4b97-952e-fc0c1f733442}*/ 
 0x9477b791, 0x3f37, 0x4b97, 
 { 0x95, 0x2e, 0xfc, 0x0c, 0x1f, 0x73, 0x34, 0x42} }
 #endif /* nsStandAloneService_h_''''_''''_ */

nsStandaloneService.cpp

 #include "nsStandAloneService.h"
 #include "nsString.h"
 #include "plstr.h"
 nsStandAloneService::nsStandAloneService()
 {
 }
 nsStandAloneService::~nsStandAloneService()
 {
 }
 NS_IMPL_ISUPPORTS1(nsStandAloneService, nsICmdLineHandler)
 CMDLINEHANDLER_IMPL(nsStandAloneService, "-helloworld", "general.startup.helloworld",
  ""[[chrome://helloworld/content/helloworld.xul"]], "Start with helloworld.",
  "@mozilla.org/commandlinehandler/general-startup;1?type=helloworld", "HelloWorld App Startup Handler", PR_TRUE,"[[about:blank"]], P
 R_TRUE)

C'est là que le démarrage est associé au bon fichier XUL! Dans le CMDLINEHANDLER_IMPL ! Il faut veiller que le nom du chrome pour l'application soit le même que le .jar créé par le StandAloneApp/base/jar.mn

Et enfin nsStandAloneRegistration.cpp

 #include "nsIGenericFactory.h"
 #include "nsStandAloneService.h"
 ////////////////////////////////////////////////////////////////////////
 // Define the contructor function for the objects
 //
 // NOTE: This creates an instance of objects by using the default constructor
 //
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsStandAloneService)
 ////////////////////////////////////////////////////////////////////////
 // Define a table of CIDs implemented by this module along with other
 // information like the function to create an instance, contractid, and
 // class name.
 //
 static const nsModuleComponentInfo components[] = {
     { "HelloWorld Service", NS_STANDALONESERVICE_CID,
       NS_STANDALONESERVICE_CONTRACT_CID, nsStandAloneServiceConstructor,},
     { "HelloWorld App Startup Handler",  NS_STANDALONESERVICE_CID,
       "@mozilla.org/commandlinehandler/general-startup;1?type=helloworld",
       nsStandAloneServiceConstructor,
       nsStandAloneService::RegisterProc,
       nsStandAloneService::UnregisterProc, },
 };
 ////////////////////////////////////////////////////////////////////////
 // Implement the NSGetModule() exported function for your module
 // and the entire implementation of the module object.
 //
 NS_IMPL_NSGETMODULE( MOZ_STANDALONE_SERVICE_MODULE_NAME, components)

Ce fichier là sert à construire le module et son point d'entrée, avec les interfaces associées. Si j'ai bien compris XPCom, ce qui n'est pas sûr.

Compilation

Voilà l'essentiel est dit: il reste à compiler! Donc ajout de variable adéquate dans le .mozconfig, et modification du configure.in et du Makefile.in pour les traiter et descendre dans le bon répertoire. Il faudra aussi modifier allMakefiles.sh (pour qu'il traite les Makefile.in de notre dossier) toolkit/components/Makefile.in et xpfe/components/Makefile.in pour qu'ils compilent les bons modules, les mêmes que ceux pour MOZ_STANDALONE_COMPOSER=1 (C'est ceux de Nvu).

Makefile.in, ligne 338 on ajoute ceci:

  tier_99_dirs   += composer
  endif
 +ifdef MOZ_STANDALONE_APP
 +tier_99_dirs   += $(MOZ_STANDALONE_APP_DIRNAME)
 +endif
 +
  ifdef MOZ_XUL_APP

Bon le configure.in doit gérer les variables MOZ_STANDALONE_APP et MOZ_STANDALONE_APP_DIRNAME, la première pour controler la compilation d'une application STANDALONE à part et la seconde pour le nom du répertoire ou elle se trouve.

Configure.in, ligne 3394:

 AC_SUBST(MOZ_STANDALONE_COMPOSER)
 AC_SUBST(MOZ_XUL_APP)
 +
 +
 +dnl ========================================================
 +dnl = Standalone Application
 +dnl ========================================================
 +if test "$MOZ_STANDALONE_APP"; then
 +   AC_DEFINE(MOZ_STANDALONE_APP)
 +
 +   MOZ_XUL_APP=1
 +   AC_DEFINE(MOZ_XUL_APP)
 +   MOZ_APP_NAME=$MOZ_STANDALONE_APP_NAME
 +   MOZ_APP_VERSION=0.01
 +
 +   AC_SUBST(MOZ_STANDALONE_APP)
 +   AC_SUBST(MOZ_STANDALONE_APP_DIRNAME)
 +fi
  dnl ========================================================
  dnl = FreeType2

Le AC_SUBST est utilisé pour que les Makefile reconnaissent la variable en la mettant dans config/autoconf.mk.in:

config/autoconf.mk.in (à la fin):

 # Nvu options
  LINSPIRE        = @LINSPIRE@
  SITE_MANAGER_KDE_ICON_STYLE = @SITE_MANAGER_KDE_ICON_STYLE@
 +
 +# Mozilla Standalone options
 +MOZ_STANDALONE_APP= @MOZ_STANDALONE_APP@
 +MOZ_STANDALONE_APP_DIRNAME= @MOZ_STANDALONE_APP_DIRNAME@

Reste à profiter de ces variables pour adapter deux autres Makefile qui en ont besoin: xpfe/components/Makefile.in

 @@ -32,6 +32,9 @@
  ifdef MOZ_STANDALONE_COMPOSER
  MOZ_STANDALONE_NONBROWSER_XULAPP=1
  endif
 +ifdef MOZ_STANDALONE_APP
 +MOZ_STANDALONE_NONBROWSER_XULAPP=1
 +endif
  ifndef MOZ_STANDALONE_NONBROWSER_XULAPP
  DIRS   = 

Cela permet de compiler les composants pour les applications autres que FireFox.

toolkit/components/Makefile.in

         viewsource 
         $(NULL)
  else
 +ifdef MOZ_STANDALONE_APP
 +# I am keeping Nvu One because i am not sure what's needed
 +DIRS =                 
 +       console 
 +       filepicker 
 +       printing 
 +       viewsource 
 +       $(NULL)
 +else
  DIRS =                 
         autocomplete 
         console 
 @@ -75,6 +84,6 @@
  endif
  endif
 -
 +endif

Là j'ai gardé les mêmes composants que Nvu, mais à priori il faut adapter à ses besoins.

Voici les modifs du .mozconfig:

  export MOZILLA_OFFICIAL=1
  export BUILD_OFFICIAL=1
 -export MOZ_STANDALONE_COMPOSER=1
 -mk_add_options MOZ_STANDALONE_COMPOSER=1
 +#export MOZ_STANDALONE_COMPOSER=1
 +#mk_add_options MOZ_STANDALONE_COMPOSER=1
 +
 +#This is for generic sandalone application
 +export MOZ_STANDALONE_APP=1
 +mk_add_options MOZ_STANDALONE_APP=1
 +
 +# name of the application
 +export MOZ_STANDALONE_APP_NAME="helloworld"
 +mk_add_options MOZ_STANDALONE_APP_NAME="helloworld"
 +
 +# name of the source application directory
 +export MOZ_STANDALONE_APP_DIRNAME="StandAloneApp"
 +mk_add_options MOZ_STANDALONE_APP_DIRNAME="StandAloneApp"

Ne me demandez pas pourquoi ces lignes doublées avec export puis mk_add_options, je ne sais pas j'ai gardé comme c'était dans le .mozconfig de Nvu.

On y est presque, il reste à ajouter tous les Makefile.in qui sont sous le répertoire de l'application (StandAloneApp/) dans la liste des fichiers à passer à la moulinette pour les transformer en Makefile. C'est allmakefiles.sh qui s'occupe de ça:

allmakefiles.sh

 @@ -975,6 +975,23 @@
 xpfe/components/build2/Makefile
 "
 +if [ "$MOZ_STANDALONE_APP" ]; then
 +MAKEFILES_standalone_app="
 +$(cd $srcdir && find $MOZ_STANDALONE_APP_DIRNAME -name Makefile.in | sed -e 's/\.\///g'  | sed -e 's/Makefile\.in/Makefile/g' )
 +xpfe/components/build2/Makefile
 +"
 +fi
 +
 MAKEFILES_sql="
 extensions/sql/Makefile
 extensions/sql/base/Makefile
 @@ -1464,6 +1481,10 @@
      add_makefiles "$MAKEFILES_standalone_composer"
 fi
 +if test -n "$MOZ_STANDALONE_APP"; then
 +    add_makefiles "$MAKEFILES_standalone_app"
 +fi
 +
 if test -n "$MOZ_IPCD"; then
    add_makefiles "$MAKEFILES_ipcd"
 fi

On peut mettre la liste à la main, Mais ma solution a l'avantage de permettre d'ajouter des composants sans avoir à rien retoucher en dehors.

La compilation se fait par make -f client.mk build tout ce qu'il y a de normal.

Ensuite il reste à élaguer, on compile surement beaucoup de choses inutiles. Mais là ça dépend de ce qu'on veut utiliser.

Les fichiers de l'exemple détaillé ci dessus sont là: http://fynl.free.fr/vrac/MozStandAloneAp(..) , avec tous les Makefiles.in, et le répertoire base/ complet, et avec quelques complications en plus.

En particulier il y a un deuxième composant, nsSample, basé sur cet exemple là , et qui est utilisé pour stocker le nom à afficher après le hello. C'est rigoureusement inutile, une variable javascript suffit, mais c'est pour illustrer l'ajout d'un composant.


Copyright © 2003-2013 association xulfr, 2013-2016 Laurent Jouanneau - Informations légales.

Mozilla® est une marque déposée de la fondation Mozilla.
Mozilla.org™, Firefox™, Thunderbird™, Mozilla Suite™ et XUL™ sont des marques de la fondation Mozilla.