Lab : Réduire une application AIR dans un dock ou dans le systray selon l'OS en AS3
Préliminaires
Les packages dont vous aurez besoin (en plus du reste
)
import flash.desktop.DockIcon; import flash.desktop.NativeApplication; import flash.desktop.NotificationType; import flash.desktop.SystemTrayIcon; import flash.display.NativeMenu; import flash.display.NativeMenuItem; import flash.events.Event; import flash.events.InvokeEvent; import flash.events.MouseEvent; ...
Détection du support dock ou systray & préparation de l'icône
Détection du support dock ou systray pour une application AIR
Rien de bien sorcier il y a deux détections possible celle du dock et celle du systray. Cette détection permettra de choisir l'objet à instancier (un dockIcon ou un SystrayIcon) mais les deux auront le même menu et l'icône pourra être gérée de la même façons. Par facilité je ferai tjrs référence au dock dans le nom de mes variables et fonction car il est plus compréhensible de dire 'dock' et 'undock' que 'gosystray' et 'gounsystray'
.
private function initDockSupport():void{
if(NativeApplication.supportsDockIcon){
debug('OS a un dock ');
var dockIcon:DockIcon = NativeApplication.nativeApplication.icon;
NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE,undock);
} else if (NativeApplication.supportsSystemTrayIcon){
debug('OS a un systray');
var sysTrayIcon:SystemTrayIcon = NativeApplication.nativeApplication.icon;
sysTrayIcon.tooltip = 'Tooltip lors du mouseover de la souris au-dessus du systray';
sysTrayIcon.addEventListener(MouseEvent.CLICK,undock);
}
else {
debug('no systray & no dock');
}
}
Les icônes à prévoir
En fait l'icône qui va apparaitre dans le systray ou le dock sera un bitmapData. AIR vous donne la possibiliter d'envoyer un array de bitmapData à l'OS qui choisira celui qu'il juge le plus adapter aux paramètres d'affichage du user.
Personnellement, je crée un mc avec les différents statuts de mon icone en 3 exemplaires avec +- de détails selon le type de résolution que je vais proposer (16x16 à 128x128). Je vais ensuite faire un draw() du mc avec le statut que je souhaite et l'envoye à l'OS :
/**
* Met à jour l'icone du systray en fonction du statut du user
* @param Boolean isOnline Si le user est online ou pas
* @return void
**/
private function updateDockIcon(isOnline:Boolean):void{
if(isOnline){
//Set Full detailed Icon (High def) to the online status
DocIcon_HD.gotoAndStop('online');
//Set Low def icon to online status
DocIcon_LD.gotoAndStop('online');
}
else {
DocIcon_HD.gotoAndStop('offline');
DocIcon_LD.gotoAndStop('offline');
}
var DocIcon_HD_bmpdata:BitmapData=new BitmapData(DocIcon_HD.width,DocIcon_HD.height,true,0x000000);
var DocIcon_LD_bmpdata:BitmapData=new BitmapData(DocIcon_LD.width,DocIcon_LD.height,true,0x000000);
DocIcon_HD_bmpdata.draw(DocIcon_HD);
DocIcon_LD_bmpdata.draw(DocIcon_LD);
//Change the DockIcon only if minimized in the systray or dock
if(stage.nativeWindow.visible==false){
NativeApplication.nativeApplication.icon.bitmaps = [DocIcon_HD_bmpdata,DocIcon_LD_bmpdata];
}
//Remove icon from systray or Dock
else {
NativeApplication.nativeApplication.icon.bitmaps = [];
}
}
Avec cet exemple je fais 3 actions :
- Si viens de cacher l'application, ça va faire apparaitre l'icone dans le dock ou le systray
- Si je viens de 'dédocker', réafficher la fenêtre de l'application, ça va faire disparaitre l'icone du dock ou du systray
- Si l'application est déjà réduite et que le statut du user a changé, l'icône va changer d'apparence
Avec un peu d'imagination on peut animer l'icône du dock/systray
Le menu qui affiche les commandes du clic droit sur l'icône
On a détecté le dock ou le systray et on sait maintenant ajouter/retirer l'icône du systray. Il ne reste plus que permettre certaines commande en faisant un clic droit sur l'icone du dock ou du systray.
/**
* Retourne le menu contextuel de l'icone du systray
* @return NativeMenu
**/
private function getDockMenu():NativeMenu{
var contextualIconMenu:NativeMenu = new NativeMenu();
//La commande qui va 'undocker' l'application
var unDockCommand: NativeMenuItem = new NativeMenuItem('Show Only4Access');
contextualIconMenu.addItem(unDockCommand);
unDockCommand.addEventListener(Event.SELECT, undock);
//pour Windows uniquement
if(NativeApplication.supportsSystemTrayIcon){
var exitCommand: NativeMenuItem = new NativeMenuItem('Exit Only4Access');
contextualIconMenu.addItem(exitCommand);
exitCommand.addEventListener(Event.SELECT, closeZeBox);
}
return iconMenu;
}
Et pour attribuer ce menu on fait :
//pour le dock dockIcon.menu = getDockMenu(); //pour le systray sysTrayIcon.menu = getDockMenu();
Le tout mélangé
Heu n'ayant pas Flash sur la machine où j'ai rédigé ce texte, je n'ai pas pu tester le code de cette page mais ça devrait le faire
.
Pour plus d'infos sur les commandes de bases (agrandir, minimiser,...) cf l'article du lab à ce sujet.
/**
* Détection et instanciation du dock
* @return void
**/
private function initDockSupport():void{
if(NativeApplication.supportsDockIcon){
debug('OS a un dock ');
var dockIcon:DockIcon = NativeApplication.nativeApplication.icon;
NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE,undock);
dockIcon.menu = getDockMenu();
} else if (NativeApplication.supportsSystemTrayIcon){
debug('OS a un systray');
var sysTrayIcon:SystemTrayIcon = NativeApplication.nativeApplication.icon;
sysTrayIcon.tooltip = 'Tooltip lors du mouseover de la souris au-dessus du systray';
sysTrayIcon.addEventListener(MouseEvent.CLICK,undock);
sysTrayIcon.menu = getDockMenu();
}
else {
debug('no systray & no dock');
}
}
/**
* Close the AIR Window
* @param * e The Event > set to * 'cause will be a MouseEvent or Event following the target (stage click (DisplayObject) or systray click (NativeMenuItem)).
* @return void
**/
private function closeZeBox(e:*):void{
stage.nativeWindow.close();
}
/**
* Réduit ds le systray
* @param * e The Event > set to * 'cause will be a MouseEvent or Event following the target (stage click (DisplayObject) or systray click (NativeMenuItem)).
* @return void
**/
private function dock(e:*):void{
debug('Docking...');
stage.nativeWindow.visible = false;
updateDockIcon();
}
/**
* Restaure la fenêtre et fait disparaitre l'icone du systray
* @param * e The Event > set to * 'cause will be a MouseEvent or Event following the target (stage click (DisplayObject) or systray click (NativeMenuItem)).
* @return void
**/
private function undock(e:*):void{
debug('Undocking...');
stage.nativeWindow.visible = true;
// ou utiliser NativeWindow.activate() ça force le premier plan en plus de le rendre visible
updateDockIcon();
}
/**
* Retourne le menu contextuel de l'icone du systray
* @return NativeMenu
**/
private function getDockMenu():NativeMenu{
var contextualIconMenu:NativeMenu = new NativeMenu();
//La commande qui va 'undocker' l'application
var unDockCommand: NativeMenuItem = new NativeMenuItem('Show MyAIRApp');
contextualIconMenu.addItem(unDockCommand);
unDockCommand.addEventListener(Event.SELECT, undock);
//pour Windows uniquement
if(NativeApplication.supportsSystemTrayIcon){
var exitCommand: NativeMenuItem = new NativeMenuItem('Exit MyAIRApp');
contextualIconMenu.addItem(exitCommand);
exitCommand.addEventListener(Event.SELECT, closeZeBox);
}
return iconMenu;
}
/**
* Met à jour l'icone du systray
* @return void
**/
private function updateDockIcon():void{
var DocIcon_bmpdata:BitmapData=new BitmapData(DocIcon_mc.width,DocIcon_mc.height,true,0x000000);
//Change the DockIcon only if minimized in the systray or dock
if(stage.nativeWindow.visible==false){
NativeApplication.nativeApplication.icon.bitmaps = [DocIcon_bmpdata];
}
//Remove icon from systray or Dock
else {
NativeApplication.nativeApplication.icon.bitmaps = [];
}
}