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.

Specificites xul macosx

Le système MacOS X a une différence par rapport aux autres systèmes : le menu d'une application ne se trouve pas au niveau de la fenêtre de l'application, mais est toujours affiché en haut de l'écran.

Dans ce menu en haut de l'écran, il y a plusieurs items :

  • le menu pomme du système (accès aux préférences système, éteindre la machine, lancer des applications etc..)
  • ce que j'appelle le menu pomme de l'application. Il porte le nom de l'application et contient un certain nombre de chose : "à propos", "préférences", "services", "quitter" (l'application)...
  • Et tous les autres menus propres à l'application : Fichier, Édition, Fenêtre, Aide etc...

Autre spécificité : fermer la fenêtre d'une application, ne veut pas dire quitter l'application. Le menu est toujours là, en haut de l'écran, même si toutes les fenêtres sont fermées. On quitte en général l'application en allant dans le menu Pomme de l'application.

Enfin, il y a des conventions au niveau interfaces utilisateurs. Ainsi, les items de menu "préférences", "à propos", "quitter" sont dans le menu Pomme de l'application, et non dans l'un des menus propres à l'application. D'ailleurs, ce menu Pomme ne peut être défini en XUL

Quand on réalise une application standalone basée sur Gecko, il faut donc tenir compte de ces spécificités, et respecter quelques règles de développement dans les fichiers XUL.

À noter aussi que tout ceci n'est pas valable pour la réalisation d'extensions.

Ces informations sont valables pour Gecko 1.7, 1.8.x et 1.9.x.

Faire un menu compatible toute plateforme

Quand votre application est lancée sous MacOsX, Gecko va récupérer le contenu de la première <menubar> qu'il trouve dans votre fichier XUL, la cacher, et construire à l'identique un menu MacOSX natif qui sera affiché par le système en haut de l'écran. Il n'y a donc rien de spécifique à faire pour l'usage "normal".

Remplir le menu Pomme de l'application

Le menu Pomme de l'application, n'est pas généré avec du XUL, mais généré par le système. Pour suivre les conventions en matière d'interface utilisateur, le "à propos" et l'accès aux préférences et l'action "quitter" de l'application doivent être dans ce menu et doit être spécifié par l'application. Comme ce n'est pas du XUL, il y a une combine à suivre.

Gecko va rechercher dans votre menu XUL des items avec des ID spécifiques. Ceux-ci seront alors déplacés dans le menu Pomme de l'application lors de l'exécution.

id item correspondant
menu_!FileQuitItem item fichier/quitter
menu_!FileQuitSeparator <menuseparator/> précédent l'item fichier/quitter
menu_preferences item qui affiche les préférences de l'application
menu_!PrefsSeparator <menuseparator/> précédent l'item préférence
aboutName item "à propos"

hiddenWindow : la fenêtre cachée

Sous MacOSX, fermer une fenêtre ne veut pas dire fermer l'application. Tout se complique donc quand on ferme la fenêtre : l'application est toujours là, mais malheureusement, il n'y a plus de menu affiché en haut de l'écran puisque le XUL correspondant n'existe plus. Or il faut tout de même afficher le menu de l'application, pour rouvrir un nouveau document, accéder aux préférences etc, quand bien même il n'y a plus de fenêtre affichée.

L'astuce dans Gecko consiste alors de faire un fichier XUL pour une fenêtre "cachée", que l'on nomme généralement hiddenWindow.xul (mais on peut utiliser un autre nom). C'est un fichier qui ne contiendra qu'une barre de menu, avec éventuellement les déclarations de commandes correspondantes, les raccourcis claviers, et les liens vers les fichiers javascript utilisés par le menu etc. Ce fichier XUL sera affiché par gecko quand il n'y aura plus fenêtre ouverte, afin de pouvoir continuer à fournir une barre de menu.

Déclaration de hiddenWindow.xul

Votre fichier hiddenWindow.xul a une url chrome. par ex : chrome://myapp/content/hiddenWindow.xul.

Il faut le déclarer auprés de Gecko. Pour cela, il faut définir dans le fichier prefs.js de l'application la pref suivante :

 pref("browser.hiddenWindowChromeURL", "[[chrome://myapp/content/hiddenWindow.xul")]];

Contenu de hiddenWindow.xul

Le menu déclaré dans le hiddenWindow.xul peut être identique ou pas à celui déclaré dans la fenêtre principale. C'est comme bon vous semble. En général, c'est un menu à peu prés identique, avec des items de menus désactivés (ceux qui ne peuvent agir que sur une fenêtre ouverte).

Les scripts des commandes des menus de hiddenWindow.xul peuvent être les mêmes que ceux de la fenêtre principale, mais il faut qu'ils tiennent compte d'une chose : les scripts doivent vérifier si ils sont dans le hiddenWindow.xul ou votre fichier XUL principal (appelons le myapp.xul). En effet, si une commande de menu agit sur un élement de la fenêtre principal, si il n'y a pas vérification, elle va "buggée" quand elle sera lançée dans le hiddenWindow.xul, puisque ce fichier ne contient qu'un menu !

En général donc, dans le hiddenWindow.xul, on mettra un menu identique à myapp.xul, mais les items agissant directement sur le contenu de myapp.xul seront désactivés.

Pour connaître le fichier xul courant, utilisez window.location.href . Par exemple, imaginons le code pour la commande fichier/ouvrir

  var nsIFilePicker = Components.interfaces.nsIFilePicker;
  var fp = Components.classes["@mozilla.org/filepicker;1"]
       .createInstance(nsIFilePicker);
   ....
  var response = fp.show();
  if (response == nsIFilePicker.returnOK){
     // ok, on ouvre le fichier
     if( window.location.href == "[[chrome://myapp/content/hiddenWindow.xul")]]{
         window.openDialog("[[chrome://myapp/content/myapp.xul"]], "_blank", "chrome,all,dialog=no", fp.fileURL.spec);
     }else{
         // traitement normal...
     }
  }

Si on est dans la fenêtre cachée, et comme ici on ouvre un document, il faut donc d'abord ouvrir la fenêtre principale, qui affichera alors le document, et le menu de la fenêtre. Le fichier XUL de la fenêtre principale remplaçant alors le hiddenWindow.xul.

Ici on ouvre avec openDialog, en passant l'url du fichier à ouvrir en paramètre à la fenêtre. Donc il suffit de vérifier, sur le onload de myapp.xul, si on a un paramètre ou pas, et donc d'ouvrir le document correspondant.

  if ("arguments" in window && window.arguments.length >= 1 && window.arguments[0]){
     documentToLoad = window.arguments[0];
     ...
  }

Utiliser les constantes

Vous générez très probablement les fichiers jar via un makefile mozilla et un fichier jar.mn. Dans ce cas, vous pouvez utiliser la constante XP_MACOSX pour indiquer au preprocesseur d'inclure ou pas ce qui est spécifique à macosx. En particulier, pour l'exemple précédent, inutile d'inclure les tests sur hiddenWindow pour une version linux ou window :

  var response = fp.show();
  if (response == nsIFilePicker.returnOK){
     // ok, on ouvre le fichier
 #ifdef XP_MACOSX
     if( window.location.href == "[[chrome://myapp/content/hiddenWindow.xul")]]{
         window.openDialog("[[chrome://myapp/content/myapp.xul"]], "_blank", "chrome,all,dialog=no", fp.fileURL.spec);
     }else{
 #endif
         // traitement normal...
 #ifdef XP_MACOSX
     }
 #endif
  }

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.