Compare commits

...

30 Commits

Author SHA1 Message Date
foudfou 0d209aa5ab Fix additional uk-UA locale declaration. 2015-01-02 11:52:49 +01:00
foudfou 9a1d80e00f Bump version to 0.5.4. 2014-12-31 15:43:38 +01:00
foudfou 56b88bb481 Add 'with_appindicator' hidden pref.
This may be useful for StatusNotifierItem-ready environments which still support
ICCCM/EWMH, whereby FireTray may be less limited.

We'll just make it a hidden pref for now as the related UI is a nightmare.
2014-12-31 01:45:52 +01:00
foudfou df4d0e8763 Update README. 2014-12-31 00:56:42 +01:00
foudfou 972f1c642c Fix check marks invisible in option 'Included accounts'.
Bug introduced in 9afa777c65.
2014-12-24 21:42:40 +01:00
foudfou 3e0ede74c7 Handle option renames properly. 2014-12-24 20:11:40 +01:00
foudfou d588605620 Notes. 2014-12-24 20:11:14 +01:00
foudfou a95709e544 Fix uk-UA locale (thx daveschaefer/checkloc). 2014-12-23 13:28:08 +01:00
foudfou e4318ed5d9 Merge branch 'appind' 2014-12-23 13:25:21 +01:00
foudfou 389e6cec51 Add 'middle_click' option.
Mainly intended for AppIndicator. Not used in winnt yet.
2014-11-22 18:47:51 +01:00
foudfou 58130c5a7d * AppIndicator: disable chat icon (TB).
* AppIndicator: disable new message count option (TB).
2014-11-21 11:13:12 +01:00
foudfou 9b8ab13265 Fix uk-UA locale (thx Sappa). 2014-11-20 02:11:06 +01:00
foudfou 9deaea08bb Further AppIndicator implementation:
* Refactoring: split StatusIcon into GtkStatusIcon and AppIndicator.
* Add AppIndicator-specific menu items (tooltip + ShowHide)
* Show/hide on scroll.
* Setting icon visibility.

Due to appindicator's limitations, we'll need to abandon these:
* Icon text (message count).
* Themed icons (multiple icon names).
2014-11-16 23:37:54 +01:00
foudfou 2b0084b69a * ctypes-utils: just log 'Info' if lib not found.
* Cleaning
2014-11-11 14:52:14 +01:00
foudfou f2acc43dce Minor refactoring. 2014-11-10 21:46:31 +01:00
foudfou 0dc0cc34b3 First step toward using libappindicator. 2014-11-10 18:11:44 +01:00
foudfou a0c0061cd6 * Linux: add debug for icon theme search path.
* Logging: fix superfluous newline, and expose Log module.

The additional newline was introduced by Log.jsm in FF32 (see
https://bugzilla.mozilla.org/show_bug.cgi?id=966674).
2014-11-10 15:06:49 +01:00
foudfou 0fee978ec3 Bump version to 0.5.3. 2014-11-09 20:43:46 +01:00
foudfou 9a4d379e76 Merge branch 'run-miniminzed' 2014-11-09 20:32:19 +01:00
foudfou 4beb428492 Cleaning. 2014-11-09 20:32:07 +01:00
foudfou bd3f894a15 Winnt: fix start_hidden when startup minimized or maximized. 2014-11-09 20:28:16 +01:00
foudfou 6feb13e7e2 Linux: fix click on menuitems (bug introduced in 0cfe58e4). 2014-11-09 15:30:44 +01:00
foudfou 233e442a09 Add uk-UA localization (thx Володимир Савчук Volodymyr Savchuk!). 2014-11-09 14:26:30 +01:00
foudfou 08bc12e28c Avoid altering 'oncommand' and 'command' attributes (thx Kris Maglione).
Altering on* attributes is discouraged by AMO review, along with the use of
Function() — even if the code passed to Function() is not dynamic.
2014-10-16 00:15:00 +02:00
foudfou 4805e3b49b Bump to version 0.5.2. 2014-10-13 23:44:32 +02:00
foudfou 2cf236bf14 Cleaning.
...trying to less alter "oncommand" attributes, following AMO review.
addEventListener() won't help here (see
http://forums.mozillazine.org/viewtopic.php?f=19&t=2696969).

Note: There seem to be some cases where we would want to keep "oncommand" or
"command" attributes (setting them to "void(0);"), for ex. for <key> elements
(see http://stackoverflow.com/q/16779316/421846).
2014-10-13 23:44:00 +02:00
foudfou 0cfe58e410 * Linux: fix return value according to return type definitions for some
ctypes callbacks, thus avoiding "expected type int, got (void 0)".
* Cleaning.
2014-10-08 23:19:19 +02:00
foudfou e2448d4ae8 Remove Linux reference in description and locales. 2014-09-15 00:20:19 +02:00
foudfou d34f7d2eeb Fix naming changes in de-DE, hr-HR, ru-RU locales. 2014-09-14 23:57:31 +02:00
foudfou a7020999a8 Bump version to 0.5.0. 2014-09-14 23:32:36 +02:00
58 changed files with 1337 additions and 515 deletions

View File

@ -20,6 +20,7 @@ Features
* show icon only when hidden to tray
* mouse scroll on tray icon shows/hides
* GTK-themable icons
* StatusNotifierItem support (can be disabled by `with_appindicator` hidden pref)
* customizable tray icons
* popup menu (show/hide individual windows, open new windows, quit)
* command-line `-firetrayShowHide` option (useful for window manager's keyboard shortcuts)
@ -43,7 +44,10 @@ Features
Notes
-----
* requires GTK+ 2.20 and higher.
* Under Linux:
* GTK+ 2.20+ required.
* libappindicator3 can be used for StatusNotifierItem (KDE, Unity).
* Under Windows, few features are not yet implemented.
* Firetray temporarily unsets:
* the `tabs.warnOnClose` built-in preference, which otherwise disrupts the handeling of the close event
* `mail.biff.show_tray_icon` for mail applications

View File

@ -92,7 +92,7 @@ chrome_sources := $(chrome_sources_js) \
$(wildcard $(chrome_source_root)/content/*.xul) \
$(wildcard $(chrome_source_root)/content/*.xml) \
$(wildcard $(chrome_source_root)/content/*.css) \
$(wildcard $(chrome_source_root)/skin/icons/*.css) \
$(wildcard $(chrome_source_root)/skin/*.css) \
$(wildcard $(chrome_source_root)/skin/icons/*.gif) \
$(wildcard $(chrome_source_root)/skin/icons/*.png) \
$(wildcard $(chrome_source_root)/skin/icons/*.svg) \

View File

@ -11,6 +11,7 @@ locale firetray pl-PL chrome/locale/pl-PL/
locale firetray ru-RU chrome/locale/ru-RU/
locale firetray sk-SK chrome/locale/sk-SK/
locale firetray zh-TW chrome/locale/zh-TW/
locale firetray zh-TW chrome/locale/uk-UA/
resource firetray modules/
overlay chrome://browser/content/browser.xul chrome://firetray/content/overlay.xul

View File

@ -38,7 +38,8 @@ var firetrayUIOptions = {
}
if (firetray.Handler.isChatProvided() &&
FIRETRAY_CHAT_SUPPORTED_OS.indexOf(firetray.Handler.runtimeOS) > -1) {
firetray.Handler.support['chat'] &&
!firetray.AppIndicator) {
Cu.import("resource://firetray/"+firetray.Handler.runtimeOS+"/FiretrayChat.jsm");
this.initChatControls();
} else {
@ -48,13 +49,23 @@ var firetrayUIOptions = {
this.updateWindowAndIconOptions();
this.updateScrollOptions();
this.initAppIconType();
if (firetray.Handler.support['full_feat']) {
if (firetray.Handler.support['winnt']) {
this.hideUnsupportedOptions([
'ui_hides_last_only', 'ui_show_activates', 'ui_remember_desktop',
'app_icon_default', 'ui_show_icon_on_hide', 'ui_scroll_hides',
'ui_radiogroup_scroll', 'ui_scroll_hides', 'ui_middle_click',
'newmail_icon_names'
]);
} else if (firetray.AppIndicator) {
this.hideUnsupportedOptions([
'app_icon_default', 'ui_mail_notification_unread_count',
'newmail_icon_names'
]);
} else {
this.initAppIconNames();
if (firetray.Handler.inMailApp)
this.initNewMailIconNames();
} else {
this.hideUnsupportedOptions();
};
}
window.sizeToContent();
},
@ -66,26 +77,39 @@ var firetrayUIOptions = {
}
},
hideUnsupportedOptions: function() { // full_feat
// windows prefs
['ui_hides_last_only', 'ui_show_activates', 'ui_remember_desktop']
.forEach(function(id){
document.getElementById(id).hidden = true;
});
hideUnsupportedOptions: function(uiElts) {
uiElts.forEach(function(id){
switch(id){
// windows prefs
case 'ui_hides_last_only':
case 'ui_show_activates':
case 'ui_remember_desktop':
// icon prefs
case 'app_icon_default':
case 'ui_show_icon_on_hide':
case 'ui_scroll_hides':
case 'ui_radiogroup_scroll':
case 'ui_middle_click':
document.getElementById(id).hidden = true;
break;
case 'ui_scroll_hides':
document.getElementById(id).removeAttribute("oncommand");
break;
// mail prefs
case 'newmail_icon_names':
for (let i=1; i<4; ++i) {
document.getElementById("radio_mail_notification_newmail_icon_name"+i).
setAttribute("observes", void(0));
}
case 'ui_mail_notification_unread_count':
document.getElementById(id).hidden = true;
break;
default:
log.error("Unhandled id: "+id);
};
});
// icon prefs
['app_icon_default', 'ui_show_icon_on_hide', 'ui_scroll_hides',
'ui_radiogroup_scroll'].forEach(function(id){
document.getElementById(id).hidden = true;
});
document.getElementById("ui_scroll_hides").setAttribute("oncommand", void(0));
// mail prefs
document.getElementById("newmail_icon_names").hidden = true;
for (let i=1; i<4; ++i) {
document.getElementById("radio_mail_notification_newmail_icon_name"+i).
setAttribute("observes", void(0));
}
},
hidePrefPane: function(name){
@ -196,7 +220,7 @@ var firetrayUIOptions = {
},
disableIconTypeMaybe: function(appIconType) {
if (firetray.Handler.support['full_feat']) {
if (firetray.Handler.support['winnt']) {
let appIconDefaultGroup = document.getElementById("app_icon_default");
this.disableNChildren(appIconDefaultGroup, 2,
(appIconType !== FIRETRAY_APPLICATION_ICON_TYPE_THEMED));
@ -301,7 +325,7 @@ var firetrayUIOptions = {
this.disableChildren(iconTextColor,
(notificationSetting !== FIRETRAY_NOTIFICATION_MESSAGE_COUNT));
if (firetray.Handler.support['full_feat']) {
if (firetray.Handler.support['winnt']) {
let newMailIconNames = document.getElementById("newmail_icon_names");
this.disableNChildren(newMailIconNames, 2,
(notificationSetting !== FIRETRAY_NOTIFICATION_NEWMAIL_ICON));
@ -323,7 +347,7 @@ var firetrayUIOptions = {
let mailNotificationType = +mailNotifyRadio.getItemAtIndex(mailNotifyRadio.selectedIndex).value;
if (msgCountTypeIsNewMessages && (mailNotificationType === FIRETRAY_NOTIFICATION_MESSAGE_COUNT)) {
mailNotifyRadio.selectedIndex = this.radioGetIndexByValue(mailNotifyRadio, FIRETRAY_NOTIFICATION_NEWMAIL_ICON);
if (firetray.Handler.support['full_feat']) {
if (firetray.Handler.support['winnt']) {
let newMailIconNames = document.getElementById("newmail_icon_names");
this.disableNChildren(newMailIconNames, 2, false);
}

View File

@ -71,6 +71,7 @@
<preference id="pref_show_icon_on_hide" name="extensions.firetray.show_icon_on_hide" type="bool"/>
<preference id="pref_scroll_hides" name="extensions.firetray.scroll_hides" type="bool" />
<preference id="pref_scroll_mode" name="extensions.firetray.scroll_mode" type="string" />
<preference id="pref_middle_click" name="extensions.firetray.middle_click" type="int" />
</preferences>
<vbox pack="start" align="left" flex="1">
@ -120,6 +121,15 @@
<radio id="ui_radio_scroll_up_hides" label="&up;=&hide;, &down;=&restore;" value="up_hides" />
</radiogroup>
<radiogroup id="ui_middle_click" preference="pref_middle_click">
<hbox align="center" flex="1">
<label control="ui_middle_click" value="&middle_click.label;"
accesskey="&middle_click.accesskey;" />
<radio id="ui_middle_click_activate_last" label="&activate_last;" value="0" />
<radio id="ui_middle_click_show_hide" label="&show_hide;" value="1" />
</hbox>
</radiogroup>
</vbox>
</prefpane>

View File

@ -23,7 +23,7 @@ var firetrayChrome = { // each new window gets a new firetrayChrome !
firetray_log.debug("Handler initialized: "+firetray.Handler.initialized);
let init = firetray.Handler.initialized || firetray.Handler.init();
firetray_log.debug("ONLOAD"); firetray.Handler.dumpWindows();
firetray_log.debug("ONLOAD");
this.winId = firetray.Handler.registerWindow(win);
win.addEventListener('close', firetrayChrome.onClose, true);
@ -39,7 +39,7 @@ var firetrayChrome = { // each new window gets a new firetrayChrome !
onQuit: function(win) {
win.removeEventListener('close', firetrayChrome.onClose, true);
firetray.Handler.unregisterWindow(win);
firetray_log.info("windowsCount="+firetray.Handler.windowsCount+", visibleWindowsCount="+firetray.Handler.visibleWindowsCount);
firetray_log.debug("windowsCount="+firetray.Handler.windowsCount+", visibleWindowsCount="+firetray.Handler.visibleWindowsCount);
firetray_log.debug('Firetray UNLOADED !');
},
@ -75,72 +75,53 @@ var firetrayChrome = { // each new window gets a new firetrayChrome !
*/
hijackTitlebarButtons: function() {
Object.keys(this.titlebarDispatch).forEach(function(id) {
let button = this.titlebarDispatch[id];
let fInfo = firetrayChrome.replaceCommand(id, button.new);
if (fInfo) {
button.old = fInfo[0];
firetray_log.debug('replaced command='+button.id+' type='+fInfo[1]+' func='+fInfo[0]);
button.type = fInfo[1];
if (firetrayChrome.replaceCommand(id, this.titlebarDispatch[id])) {
firetray_log.debug('replaced command='+id);
}
}, this);
},
titlebarDispatch: {
"titlebar-min": { new: function(e){
firetray_log.debug(' titlebar-min clicked');
if (!firetray.Handler.onMinimize(firetrayChrome.winId))
firetrayChrome.applyDefaultCommand("titlebar-min");
}, old: null, type: null },
"titlebar-close": { new: function(e){
firetray_log.debug(' titlebar-close clicked');
if (!firetrayChrome.onClose(null)) {
firetrayChrome.applyDefaultCommand("titlebar-close");
}
}, old: null, type: null }
"titlebar-min": function() {
return firetray.Handler.onMinimize(firetrayChrome.winId);
},
"titlebar-close": function() {
return firetrayChrome.onClose(null);
}
},
replaceCommand: function(eltId, func) {
replaceCommand: function(eltId, gotHidden) {
let elt = document.getElementById(eltId);
if (!elt) {
firetray_log.debug("Element '"+eltId+"' not found. Command not replaced.");
return null;
return false;
}
let command = elt.command;
let oncommand = elt.getAttribute("oncommand");
let old = null, type = null;
if (command) {
firetray_log.debug('command');
type = FIRETRAY_XUL_ATTRIBUTE_COMMAND;
old = elt.command;
elt.command = null;
elt.addEventListener('click', func, false);
} else if (oncommand) {
firetray_log.debug('oncommand');
type = FIRETRAY_XUL_ATTRIBUTE_ONCOMMAND;
let prev = elt.getAttribute("oncommand");
old = new Function(prev);
elt.setAttribute("oncommand", void(0));
elt.addEventListener('command', func, false);
let prevent = null;
if (elt.command) {
prevent = { event: "click", func: function(e){e.preventDefault();} };
} else if (elt.getAttribute("oncommand")) {
prevent = { event: "command", func: function(e){e.stopPropagation();} };
} else {
firetray_log.warn('Could not replace oncommand on '+eltId);
return false;
}
return [old, type];
},
applyDefaultCommand: function(key) {
let callType = this.titlebarDispatch[key]['type'];
if (callType === FIRETRAY_XUL_ATTRIBUTE_COMMAND) {
let cmdName = firetrayChrome.titlebarDispatch[key]['old'];
let cmd = document.getElementById(cmdName);
cmd.doCommand();
let callback = function(event) {
if (event.target.id === eltId) {
firetray_log.debug(prevent.event +' on '+eltId);
if (gotHidden())
prevent.func(event);
}
};
/* We put listeners on the "titlebar" parent node, because:
- we can hardly short-circuit command/oncommand (probably because they are
registered first)
- we'd have otherwise to alter "oncommand"/"command" attribute and use
Function(), which do not pass review nowadays. */
elt.parentNode.addEventListener(prevent.event, callback, true);
} else if (callType === FIRETRAY_XUL_ATTRIBUTE_ONCOMMAND) {
firetrayChrome.titlebarDispatch[key]['old']();
} else {
firetray_log.error("Calling type undefined for "+key);
}
return true;
}
};

View File

@ -42,6 +42,10 @@
<!ENTITY down "↓" >
<!ENTITY hide "verstecken" >
<!ENTITY restore "wiederherstellen" >
<!ENTITY middle_click.label "Mouse middle click action :" >
<!ENTITY middle_click.accesskey "k" >
<!ENTITY show_hide "Show/hide" >
<!ENTITY activate_last "Activate last window" >
<!ENTITY mail_notification_enabled.label "Mailbenachrichtigung">
<!ENTITY mail_notification_enabled.accesskey "M">
@ -56,8 +60,8 @@
<!ENTITY mail_notification_unread_count.accesskey "A">
<!ENTITY mail_notification_newmail_icon.label "Icon aus dem Desktop-Theme">
<!ENTITY mail_notification_newmail_icon.accesskey "T">
<!ENTITY mail_notification_custom_mail_icon.label "Beliebiges Icon">
<!ENTITY mail_notification_custom_mail_icon.accesskey "I">
<!ENTITY mail_notification_mail_icon_custom.label "Beliebiges Icon">
<!ENTITY mail_notification_mail_icon_custom.accesskey "I">
<!ENTITY icon_text_color "Textfarbe">
<!ENTITY icon_text_color.accesskey "F">
<!ENTITY choose "Auswählen">
@ -86,8 +90,8 @@
<!ENTITY mail_change_trigger.accesskey "A">
<!ENTITY mail_change_trigger.placeholder "/bin/notify-send">
<!ENTITY mail_change_trigger.tooltip "absoluter Pfad eines Executables, das aufgerufen wird, falls sich die Anzahl der Mails ändert; die (neue) Anzahl der Mails wird als Argument übergeben.">
<!ENTITY mail_urgency_hint.label "»X11 urgency hint« absetzen">
<!ENTITY mail_urgency_hint.accesskey "X">
<!ENTITY mail_get_attention.label "»X11 urgency hint« absetzen">
<!ENTITY mail_get_attention.accesskey "X">
<!ENTITY chat_icon_enable.label "Chat-Icon aktivieren">
<!ENTITY chat_icon_enable.accesskey "A">

View File

@ -1 +1 @@
<!ENTITY firetray.label "My localized menuitem">

View File

@ -4,5 +4,7 @@ popupMenu.itemLabel.Preferences=Einstellungen
popupMenu.itemLabel.Quit=Beenden
popupMenu.itemLabel.NewWindow=Neues Fenster
popupMenu.itemLabel.NewMessage=Neue Nachricht
popupMenu.itemLabel.ShowHide=Show/Hide
popupMenu.itemLabel.ActivateLast=Activate last window
tooltip.unread_messages=#1 ungelesene Nachricht;#1 ungelesene Nachrichten
tooltip.new_messages=Neue Nachrichten!

View File

@ -43,6 +43,10 @@
<!ENTITY down "↓" >
<!ENTITY hide "hide" >
<!ENTITY restore "restore" >
<!ENTITY middle_click.label "Mouse middle click action :" >
<!ENTITY middle_click.accesskey "k" >
<!ENTITY show_hide "Show/hide" >
<!ENTITY activate_last "Activate last window" >
<!ENTITY mail_notification_enabled.label "Enable mail notification">
<!ENTITY mail_notification_enabled.accesskey "a">

View File

@ -1,8 +1,10 @@
extensions.{9533f794-00b4-4354-aa15-c2bbda6989f8}.description=A system tray extension for linux.
extensions.{9533f794-00b4-4354-aa15-c2bbda6989f8}.description=A system tray extension.
popupMenu.itemLabel.ResetIcon=Reset icon
popupMenu.itemLabel.Preferences=Preferences
popupMenu.itemLabel.Quit=Quit
popupMenu.itemLabel.NewWindow=New window
popupMenu.itemLabel.NewMessage=New message
popupMenu.itemLabel.ShowHide=Show/Hide
popupMenu.itemLabel.ActivateLast=Activate last window
tooltip.unread_messages=#1 unread message;#1 unread messages
tooltip.new_messages=New messages !

View File

@ -38,6 +38,10 @@
<!ENTITY down "↓">
<!ENTITY hide "ocultar">
<!ENTITY restore "restaurar">
<!ENTITY middle_click.label "Mouse middle click action :" >
<!ENTITY middle_click.accesskey "k" >
<!ENTITY show_hide "Show/hide" >
<!ENTITY activate_last "Activate last window" >
<!ENTITY mail_notification_enabled.label "Habilitar notificaciones por correo">
<!ENTITY mail_notification_enabled.accesskey "H">
<!ENTITY message_count_type.label "tipo de contador de mensajes:">

View File

@ -1,8 +1,10 @@
extensions.{9533f794-00b4-4354-aa15-c2bbda6989f8}.description=Una extensión para la bandeja del sistema en linux.
extensions.{9533f794-00b4-4354-aa15-c2bbda6989f8}.description=Una extensión para la bandeja del sistema.
popupMenu.itemLabel.ResetIcon=Ícono de reset
popupMenu.itemLabel.Preferences=Preferences
popupMenu.itemLabel.Quit=Salir
popupMenu.itemLabel.NewWindow=Nueva ventana
popupMenu.itemLabel.NewMessage=Nuevo mensaje
popupMenu.itemLabel.ShowHide=Show/Hide
popupMenu.itemLabel.ActivateLast=Activate last window
tooltip.unread_messages=#1 mensaje no leido;#1 mensajes no leídos
tooltip.new_messages=Nuevos mensajes !

View File

@ -38,6 +38,10 @@
<!ENTITY down "↓">
<!ENTITY hide "masquer">
<!ENTITY restore "restaurer">
<!ENTITY middle_click.label "Souris clic du milieu :" >
<!ENTITY middle_click.accesskey "m" >
<!ENTITY show_hide "Masquer/Restaurer" >
<!ENTITY activate_last "Activer la dernière fenêtre ouverte" >
<!ENTITY mail_notification_enabled.label "Autoriser la notification des courriers">
<!ENTITY mail_notification_enabled.accesskey "A">
<!ENTITY message_count_type.label "compter les messages :">

View File

@ -1,8 +1,10 @@
extensions.{9533f794-00b4-4354-aa15-c2bbda6989f8}.description=Une extension qui crée une zone de notification pour Linux
extensions.{9533f794-00b4-4354-aa15-c2bbda6989f8}.description=Une extension qui crée une zone de notification.
popupMenu.itemLabel.ResetIcon=Restaurer l'icône
popupMenu.itemLabel.Preferences=Préférences
popupMenu.itemLabel.Quit=Quitter
popupMenu.itemLabel.NewWindow=Nouvelle fenêtre
popupMenu.itemLabel.NewMessage=Nouveau message
popupMenu.itemLabel.ShowHide=Montrer/Cacher
popupMenu.itemLabel.ActivateLast=Activer la dernière fenêtre
tooltip.unread_messages=#1 mesage non lu;#1 messages non lus
tooltip.new_messages=Nouveaux messages !

View File

@ -38,6 +38,10 @@
<!ENTITY down "↓">
<!ENTITY hide "sakrij">
<!ENTITY restore "obnovi">
<!ENTITY middle_click.label "Mouse middle click action :" >
<!ENTITY middle_click.accesskey "k" >
<!ENTITY show_hide "Show/hide" >
<!ENTITY activate_last "Activate last window" >
<!ENTITY mail_notification_enabled.label "Omogući obavijesti pošte">
<!ENTITY mail_notification_enabled.accesskey "a">
<!ENTITY message_count_type.label "broj vrsta poruka:">
@ -51,8 +55,8 @@
<!ENTITY mail_notification_unread_count.accesskey "U">
<!ENTITY mail_notification_newmail_icon.label "prikaži ikonu pristigle pošte">
<!ENTITY mail_notification_newmail_icon.accesskey "N">
<!ENTITY mail_notification_custom_mail_icon.label "prikaži prilagođenu ikonu">
<!ENTITY mail_notification_custom_mail_icon.accesskey "I">
<!ENTITY mail_notification_mail_icon_custom.label "prikaži prilagođenu ikonu">
<!ENTITY mail_notification_mail_icon_custom.accesskey "I">
<!ENTITY icon_text_color "Boja teksta">
<!ENTITY icon_text_color.accesskey "T">
<!ENTITY choose "Odaberi">
@ -77,8 +81,8 @@
<!ENTITY mail_change_trigger.accesskey "L">
<!ENTITY mail_change_trigger.placeholder "/bin/pošalji-obavijest">
<!ENTITY mail_change_trigger.tooltip "Potpuna putanja programa koji će se pokrenuti kada se broj poruka promijeni. Taj program će dobiti novi broj poruka kao prvi argument.">
<!ENTITY mail_urgency_hint.label "Postavi X11 napomenu hitnosti">
<!ENTITY mail_urgency_hint.accesskey "X">
<!ENTITY mail_get_attention.label "Postavi X11 napomenu hitnosti">
<!ENTITY mail_get_attention.accesskey "X">
<!ENTITY chat_icon_enable.label "Omogući ikonu čavrljanja">
<!ENTITY chat_icon_enable.accesskey "E">
<!ENTITY chat_icon_blink.label "Ikona čavrljanja blinka kod pristigle poruke">

View File

@ -1,8 +1,10 @@
extensions.{9533f794-00b4-4354-aa15-c2bbda6989f8}.description=Proširenje za traku sustava u linuxu.
extensions.{9533f794-00b4-4354-aa15-c2bbda6989f8}.description=Proširenje za traku sustava.
popupMenu.itemLabel.ResetIcon=Ponovno pokreni ikonu
popupMenu.itemLabel.Preferences=Osobitosti
popupMenu.itemLabel.Quit=Zatvori
popupMenu.itemLabel.NewWindow=Novi prozor
popupMenu.itemLabel.NewMessage=Nova poruka
popupMenu.itemLabel.ShowHide=Show/Hide
popupMenu.itemLabel.ActivateLast=Activate last window
tooltip.unread_messages=#1 nepročitana poruka;#1 nepročitano poruka
tooltip.new_messages=Nove poruke!

View File

@ -38,6 +38,10 @@
<!ENTITY down "↓">
<!ENTITY hide "Nascondi">
<!ENTITY restore "Ripristina">
<!ENTITY middle_click.label "Mouse middle click action :" >
<!ENTITY middle_click.accesskey "k" >
<!ENTITY show_hide "Show/hide" >
<!ENTITY activate_last "Activate last window" >
<!ENTITY mail_notification_enabled.label "Attiva notifiche e-mail">
<!ENTITY mail_notification_enabled.accesskey "a">
<!ENTITY message_count_type.label "Tipo di contatore messaggi:">

View File

@ -1,8 +1,10 @@
extensions.{9533f794-00b4-4354-aa15-c2bbda6989f8}.description=Permette di ridurre l'applicazione nell'area di notifica di Linux
extensions.{9533f794-00b4-4354-aa15-c2bbda6989f8}.description=Permette di ridurre l'applicazione nell'area di notifica
popupMenu.itemLabel.ResetIcon=Ripristina icona
popupMenu.itemLabel.Preferences=Preferenze
popupMenu.itemLabel.Quit=Esci
popupMenu.itemLabel.NewWindow=Nuova finestra
popupMenu.itemLabel.NewMessage=Nuovo messaggio
popupMenu.itemLabel.ShowHide=Show/Hide
popupMenu.itemLabel.ActivateLast=Activate last window
tooltip.unread_messages=#1 messaggio non letto;#1 messaggi non letti
tooltip.new_messages=Nuovi messaggi

View File

@ -38,6 +38,10 @@
<!ENTITY down "↓">
<!ENTITY hide "verbergen">
<!ENTITY restore "herstellen">
<!ENTITY middle_click.label "Mouse middle click action :" >
<!ENTITY middle_click.accesskey "k" >
<!ENTITY show_hide "Show/hide" >
<!ENTITY activate_last "Activate last window" >
<!ENTITY mail_notification_enabled.label "E-mailnotificatie inschakelen">
<!ENTITY mail_notification_enabled.accesskey "a">
<!ENTITY message_count_type.label "type berichttelling:">

View File

@ -1,8 +1,10 @@
extensions.{9533f794-00b4-4354-aa15-c2bbda6989f8}.description=Een systeemvakextensie voor Linux.
extensions.{9533f794-00b4-4354-aa15-c2bbda6989f8}.description=Een systeemvakextensie.
popupMenu.itemLabel.ResetIcon=Pictogram resetten
popupMenu.itemLabel.Preferences=Preferences
popupMenu.itemLabel.Quit=Stoppen
popupMenu.itemLabel.NewWindow=Nieuw venster
popupMenu.itemLabel.NewMessage=Nieuw bericht
popupMenu.itemLabel.ShowHide=Show/Hide
popupMenu.itemLabel.ActivateLast=Activate last window
tooltip.unread_messages=#1 ongelezen bericht;#1 ongelezen berichten
tooltip.new_messages=Nieuwe berichten!

View File

@ -43,6 +43,10 @@
<!ENTITY down "↓" >
<!ENTITY hide "ukrywa" >
<!ENTITY restore "przywraca" >
<!ENTITY middle_click.label "Mouse middle click action :" >
<!ENTITY middle_click.accesskey "k" >
<!ENTITY show_hide "Show/hide" >
<!ENTITY activate_last "Activate last window" >
<!ENTITY mail_notification_enabled.label "Włącz powiadomienie o poczcie">
<!ENTITY mail_notification_enabled.accesskey "i">

View File

@ -1,8 +1,10 @@
extensions.{9533f794-00b4-4354-aa15-c2bbda6989f8}.description=Rozszerzenie zasobnika dla linuxa.
extensions.{9533f794-00b4-4354-aa15-c2bbda6989f8}.description=Rozszerzenie zasobnika.
popupMenu.itemLabel.ResetIcon=Resetuj ikonę
popupMenu.itemLabel.Preferences=Ustawienia
popupMenu.itemLabel.Quit=Wyjdź
popupMenu.itemLabel.NewWindow=Nowe okno
popupMenu.itemLabel.NewMessage=Nowa wiadomość
popupMenu.itemLabel.ShowHide=Show/Hide
popupMenu.itemLabel.ActivateLast=Activate last window
tooltip.unread_messages=#1 nieprzeczytana wiadomość;#1 nieprzeczytane wiadomości
tooltip.new_messages=Nowe wiadomości !

View File

@ -43,6 +43,10 @@
<!ENTITY down "↓" >
<!ENTITY hide "скрыть" >
<!ENTITY restore "показать" >
<!ENTITY middle_click.label "Mouse middle click action :" >
<!ENTITY middle_click.accesskey "k" >
<!ENTITY show_hide "Show/hide" >
<!ENTITY activate_last "Activate last window" >
<!ENTITY mail_notification_enabled.label "Включить оповещение о новых сообщениях">
<!ENTITY mail_notification_enabled.accesskey "a">
@ -57,8 +61,8 @@
<!ENTITY mail_notification_unread_count.accesskey "U">
<!ENTITY mail_notification_newmail_icon.label "показать значок новой почты">
<!ENTITY mail_notification_newmail_icon.accesskey "N">
<!ENTITY mail_notification_custom_mail_icon.label "показать выбранный значок">
<!ENTITY mail_notification_custom_mail_icon.accesskey "I">
<!ENTITY mail_notification_mail_icon_custom.label "показать выбранный значок">
<!ENTITY mail_notification_mail_icon_custom.accesskey "I">
<!ENTITY icon_text_color "Цвет текста">
<!ENTITY icon_text_color.accesskey "T">
<!ENTITY choose "Выбрать">
@ -87,8 +91,8 @@
<!ENTITY mail_change_trigger.accesskey "L">
<!ENTITY mail_change_trigger.placeholder "/bin/notify-send">
<!ENTITY mail_change_trigger.tooltip "Абсолютный путь к программе. В качестве первого аргумента будет передано количество сообщений">
<!ENTITY mail_urgency_hint.label "Установить срочное оповещение X11">
<!ENTITY mail_urgency_hint.accesskey "X">
<!ENTITY mail_get_attention.label "Установить срочное оповещение X11">
<!ENTITY mail_get_attention.accesskey "X">
<!ENTITY chat_icon_enable.label "Включить значок чата">
<!ENTITY chat_icon_enable.accesskey "E">

View File

@ -1,8 +1,10 @@
extensions.{9533f794-00b4-4354-aa15-c2bbda6989f8}.description=Значок в трее для GNU/Linux
extensions.{9533f794-00b4-4354-aa15-c2bbda6989f8}.description=Значок в трее
popupMenu.itemLabel.ResetIcon=Обновить
popupMenu.itemLabel.Preferences=Настройки
popupMenu.itemLabel.Quit=Выход
popupMenu.itemLabel.NewWindow=Новое окно
popupMenu.itemLabel.NewMessage=Создать сообщение
popupMenu.itemLabel.ShowHide=Show/Hide
popupMenu.itemLabel.ActivateLast=Activate last window
tooltip.unread_messages=#1 непрочитанных сообщений;#1 непрочитанных сообщений
tooltip.new_messages=Новые сообщения !

View File

@ -43,6 +43,10 @@
<!ENTITY down "↓" >
<!ENTITY hide "skryť" >
<!ENTITY restore "obnoviť" >
<!ENTITY middle_click.label "Mouse middle click action :" >
<!ENTITY middle_click.accesskey "k" >
<!ENTITY show_hide "Show/hide" >
<!ENTITY activate_last "Activate last window" >
<!ENTITY mail_notification_enabled.label "Zapnúť upozornenia pošty">
<!ENTITY mail_notification_enabled.accesskey "a">

View File

@ -1,8 +1,10 @@
extensions.{9533f794-00b4-4354-aa15-c2bbda6989f8}.description=Linuxové rozšírenie pre oznamovaciu lištu
extensions.{9533f794-00b4-4354-aa15-c2bbda6989f8}.description=Rozšírenie pre oznamovaciu lištu
popupMenu.itemLabel.ResetIcon=Obnoviť ikonu
popupMenu.itemLabel.Preferences=Preferences
popupMenu.itemLabel.Quit=Koniec
popupMenu.itemLabel.NewWindow=Nové okno
popupMenu.itemLabel.NewMessage=Nová správa
popupMenu.itemLabel.ShowHide=Show/Hide
popupMenu.itemLabel.ActivateLast=Activate last window
tooltip.unread_messages=#1 neprečítaná správa;#1 neprečítané správy;#1 neprečítaných správ
tooltip.new_messages=Nové správy!

View File

@ -0,0 +1,107 @@
<!-- if you need multiline/carriage return, use a .properties -->
<!ENTITY prefwindow.title "FireTray вподобання">
<!ENTITY NOT_IMPLEMENTED_YET "ЩЕ НЕ РЕАЛІЗОВАНО.">
<!ENTITY windows_options "Вікна">
<!ENTITY icon_options "Піктограма">
<!ENTITY mail_options "Пошта">
<!ENTITY chat_options "Чат">
<!ENTITY hides_on_close.label "Закрите вікно приховувати до трею">
<!ENTITY hides_on_close.accesskey "З">
<!ENTITY hides_on_minimize.label "Згорнуте вікно приховувати до трею">
<!ENTITY hides_on_minimize.accesskey "г">
<!ENTITY hides_single_window.label "Ховати вікна індівілуально">
<!ENTITY hides_single_window.tooltip "не всі вікна відразу">
<!ENTITY hides_single_window.accesskey "н">
<!ENTITY hides_last_only.label "Тільки останнє вікно може бути приховане">
<!ENTITY hides_last_only.tooltip "інші вікна будуть закриті (припинені)">
<!ENTITY hides_last_only.accesskey "і">
<!ENTITY start_hidden.label "Запуск додатка прихованим в трей">
<!ENTITY start_hidden.accesskey "п">
<!ENTITY show_activates.label "Активувате відновлені вікна">
<!ENTITY show_activates.accesskey "А">
<!ENTITY show_activates.tooltip "відновлені вікна підняти вгору та показати">
<!ENTITY remember_desktop.label "Відновити вікна у їх вихідному робочому столі">
<!ENTITY remember_desktop.accesskey "р">
<!ENTITY show_icon_on_hide.label "Показувати піктограму у треї тільки коли вікно приховане">
<!ENTITY show_icon_on_hide.accesskey "ї">
<!ENTITY app_icon_type "Тип значку розширення">
<!ENTITY app_icon_themed.label "Типова тема">
<!ENTITY app_icon_themed.accesskey "Т">
<!ENTITY app_icon_themed_name "Назва значку">
<!ENTITY icon_themed.tooltip "Назва значків, що надаються графічним середовищем">
<!ENTITY app_icon_custom.label "Власний">
<!ENTITY app_icon_custom.accesskey "с">
<!ENTITY mouse_wheel_options "Параметри коліщата миші">
<!ENTITY enable_mouse_scroll.label "Прокрутка миші на іконці трея">
<!ENTITY enable_mouse_scroll.accesskey "я">
<!ENTITY up "↑">
<!ENTITY down "↓">
<!ENTITY hide "сховати">
<!ENTITY restore "відновити">
<!ENTITY middle_click.label "Mouse middle click action :" >
<!ENTITY middle_click.accesskey "k" >
<!ENTITY show_hide "Show/hide" >
<!ENTITY activate_last "Activate last window" >
<!ENTITY mail_notification_enabled.label "Включити поштові повідомлення">
<!ENTITY mail_notification_enabled.accesskey "ю">
<!ENTITY message_count_type.label "тип лічильника повідомлень:">
<!ENTITY message_count_type.accesskey "л">
<!ENTITY message_count_type_unread "непрочитані повідомлення">
<!ENTITY message_count_type_new "нові повідомлення">
<!ENTITY message_count_type_new.tooltip "нові повідомлення з останнього заходу.">
<!ENTITY mail_notification_type.label "Тип поштових повідомлень">
<!ENTITY mail_notification_type.tooltip "aka. Biff">
<!ENTITY mail_notification_unread_count.label "показувати лічильник нових повідомлень">
<!ENTITY mail_notification_unread_count.accesskey "н">
<!ENTITY mail_notification_newmail_icon.label "показувати значок нових повідомлень">
<!ENTITY mail_notification_newmail_icon.accesskey "з">
<!ENTITY mail_notification_mail_icon_custom.label "показувати власний значок">
<!ENTITY mail_notification_mail_icon_custom.accesskey "в">
<!ENTITY icon_text_color "Колір тексту">
<!ENTITY icon_text_color.accesskey "К">
<!ENTITY choose "Обрати">
<!ENTITY choose.accesskey "О">
<!ENTITY unread_count_folder_exceptions.label "Включити спеціальні теки">
<!ENTITY unread_count_folder_exceptions.tooltip "Включити спеціальні теки до підрахунку непрочитаних повідомлень">
<!ENTITY excluded_folders_list.tooltip "Використовуйте CTRL + ліве клацання мишею, щоб вибрати/скасувати теки для лічильника нових повідомлень">
<!ENTITY unread_count_account_exceptions.label "Включені облікові записи">
<!ENTITY unread_count_account_exceptions.tooltip "Включені облікові записи для лічильника непрочитаних повідомлень">
<!ENTITY folder_count_recursive.label "включити вкладені теки">
<!ENTITY folder_count_recursive.accesskey "л">
<!ENTITY only_favorite_folders.label "Тільки обрані теки">
<!ENTITY only_favorite_folders.accesskey "о">
<!ENTITY only_favorite_folders.tooltip "Підрахунок повідомлень лише у обраних теках">
<!ENTITY account_or_server_type_name "Обліковий запис">
<!ENTITY account_or_server_type_name.tooltip "Ім'я чи тип облікового запису">
<!ENTITY account_or_server_type_excluded "Включені">
<!ENTITY account_or_server_type_excluded.tooltip "Включені облікові записи чи типи до лічильника непрочитаних повідомлень">
<!ENTITY account_or_server_type_order "Порядок">
<!ENTITY account_or_server_type_order.tooltip "Порядок в якому відображаються типи поштових серверів. Зробіть подвійне клацання, щоб редагувати.">
<!ENTITY mail_change_trigger.label "Запуск при зміні кількості:">
<!ENTITY mail_change_trigger.accesskey "З">
<!ENTITY mail_change_trigger.placeholder "/кошик/повідомити-відправити">
<!ENTITY mail_change_trigger.tooltip "Абсолютний шлях запуску програми при зміні кількості повідомлень. Ця програма буде отримувати нову кількість повідомлень як перший аргумент.">
<!ENTITY mail_get_attention.label "Вікно концентрується на нових повідомленнях">
<!ENTITY mail_get_attention.accesskey "х">
<!ENTITY chat_icon_enable.label "Включити значок чату">
<!ENTITY chat_icon_enable.accesskey "ч">
<!ENTITY chat_icon_blink.label "Значок чату блимає при наявності нових повідомлень">
<!ENTITY chat_icon_blink.accesskey "б">
<!ENTITY chat_icon_blink.tooltip "коли приватне повідомлення або цитата в каналі">
<!ENTITY chat_icon_blink_style.label "Стиль блимання">
<!ENTITY chat_icon_blink_style.accesskey "С">
<!ENTITY chat_icon_blink_style_normal "Звичайний">
<!ENTITY chat_icon_blink_style_fade "Затихаючий">

View File

@ -0,0 +1,8 @@
Archive=Архів
Drafts=Чернетки
Junk=Мотлох
Queue=Черга
SentMail=Надіслані
Templates=Тимчасові
Trash=Кошик
Virtual=Віртуальний

View File

@ -0,0 +1 @@
<!ENTITY firetray.label "Мій локалізований пункт меню">

View File

@ -0,0 +1,10 @@
extensions.{9533f794-00b4-4354-aa15-c2bbda6989f8}.description=Розширення системного лотка для Linux.
popupMenu.itemLabel.ResetIcon=Піктограма скидання
popupMenu.itemLabel.Preferences=Вподобання
popupMenu.itemLabel.Quit=Вийти
popupMenu.itemLabel.NewWindow=Нове вікно
popupMenu.itemLabel.NewMessage=Нове повідомлення
popupMenu.itemLabel.ShowHide=Show/Hide
popupMenu.itemLabel.ActivateLast=Activate last window
tooltip.unread_messages=#1 непрочитане повідомлення;#1 непрочитані повідомлення
tooltip.new_messages=Нові повідомлення!

View File

@ -38,6 +38,10 @@
<!ENTITY down "↓">
<!ENTITY hide "隱藏">
<!ENTITY restore "恢復">
<!ENTITY middle_click.label "Mouse middle click action :" >
<!ENTITY middle_click.accesskey "k" >
<!ENTITY show_hide "Show/hide" >
<!ENTITY activate_last "Activate last window" >
<!ENTITY mail_notification_enabled.label "啟用郵件通知">
<!ENTITY mail_notification_enabled.accesskey "A">
<!ENTITY message_count_type.label "郵件計數器類型:">

View File

@ -1,8 +1,10 @@
extensions.{9533f794-00b4-4354-aa15-c2bbda6989f8}.description=Linux 用的系統列套件。
extensions.{9533f794-00b4-4354-aa15-c2bbda6989f8}.description=用的系統列套件。
popupMenu.itemLabel.ResetIcon=重設圖示
popupMenu.itemLabel.Preferences=Preferences
popupMenu.itemLabel.Quit=結束
popupMenu.itemLabel.NewWindow=開新視窗
popupMenu.itemLabel.NewMessage=新增訊息
popupMenu.itemLabel.ShowHide=Show/Hide
popupMenu.itemLabel.ActivateLast=Activate last window
tooltip.unread_messages=#1 封未讀訊息;#1 封未讀訊息
tooltip.new_messages=有新訊息!

View File

@ -15,12 +15,12 @@ treechildren::-moz-tree-checkbox(checked, disabled) {
/* properties="disabled" */
treechildren::-moz-tree-cell-text(disabled) {
color: GrayText;
color: GrayText;
}
/*
treechildren::-moz-tree-cell(disabled) {
background-color: #eeeeee;
background-color: #eeeeee;
}
*/

View File

@ -21,6 +21,7 @@ pref("extensions.firetray.new_mail_icon_names", '["indicator-messages-new", "mai
pref("extensions.firetray.show_icon_on_hide", false);
pref("extensions.firetray.scroll_hides", true);
pref("extensions.firetray.scroll_mode", "down_hides");
pref("extensions.firetray.middle_click", 0);
pref("extensions.firetray.chat_icon_enable", true);
pref("extensions.firetray.chat_icon_blink", true);
pref("extensions.firetray.chat_icon_blink_style", 0);
@ -38,3 +39,5 @@ pref("extensions.firetray.excluded_folders_flags", 1077956384);
// exposed in 1 tree, hence 2 branches: serverTypes, excludedAccounts
pref("extensions.firetray.mail_accounts", '{ "serverTypes": {"pop3":{"order":1,"excluded":false}, "imap":{"order":1,"excluded":false}, "movemail":{"order":2,"excluded":true}, "none":{"order":3,"excluded":false}, "rss":{"order":4,"excluded":true}, "nntp":{"order":5,"excluded":true}, "exquilla":{"order":6,"excluded":true}}, "excludedAccounts": [] }'); // JSON
pref("extensions.firetray.only_favorite_folders", false);
pref("extensions.firetray.with_appindicator", true);

View File

@ -6,11 +6,11 @@
<em:unpack>true</em:unpack> <!-- needed for embedded icons -->
<em:type>2</em:type>
<em:name>FireTray</em:name>
<em:version>0.5.0b2</em:version> <!-- change FIRETRAY_VERSION accordingly ! -->
<em:version>0.5.4</em:version> <!-- change FIRETRAY_VERSION accordingly ! -->
<em:creator>Hua Luo, Francesco Solero, Foudil BRÉTEL</em:creator>
<em:contributor>Hua Luo, Francesco Solero (Firetray original authors)</em:contributor>
<em:homepageURL>https://github.com/foudfou/firetray</em:homepageURL>
<em:description>A system tray extension for linux.</em:description>
<em:description>A system tray extension.</em:description>
<em:optionsURL>chrome://firetray/content/options.xul</em:optionsURL>
<em:iconURL>chrome://firetray/skin/icons/firetray48.png</em:iconURL>
<em:icon64URL>chrome://firetray/skin/icons/firetray64.png</em:icon64URL>
@ -21,7 +21,7 @@
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <!-- Firefox -->
<em:minVersion>7.0</em:minVersion>
<em:maxVersion>35.0</em:maxVersion>
<em:maxVersion>38.0</em:maxVersion>
</Description>
</em:targetApplication>
@ -29,7 +29,7 @@
<Description>
<em:id>{3550f703-e582-4d05-9a08-453d09bdfdc6}</em:id>
<em:minVersion>7.0</em:minVersion>
<em:maxVersion>35.0</em:maxVersion>
<em:maxVersion>38.0</em:maxVersion>
</Description>
</em:targetApplication>
@ -37,7 +37,7 @@
<Description>
<em:id>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</em:id>
<em:minVersion>2.4</em:minVersion>
<em:maxVersion>2.32</em:maxVersion>
<em:maxVersion>2.35</em:maxVersion>
</Description>
</em:targetApplication>
@ -98,7 +98,7 @@
<Description>
<em:locale>de-DE</em:locale>
<em:translator>Florian Haftmann</em:translator>
<em:description>Tray-Erweiterung für GNU/Linux.</em:description>
<em:description>Tray-Erweiterung.</em:description>
</Description>
</em:localized>
@ -106,7 +106,7 @@
<Description>
<em:locale>es-AR</em:locale>
<em:translator>profediego@gmail.com</em:translator>
<em:description>Una extensión para la bandeja del sistema en linux.</em:description>
<em:description>Una extensión para la bandeja del sistema.</em:description>
</Description>
</em:localized>
@ -116,7 +116,7 @@
<em:translator>Goofy</em:translator>
<em:translator>Jojaba - BabelZilla</em:translator>
<em:translator>nico@nc</em:translator>
<em:description>Une extension qui crée une zone de notification pour Linux.</em:description>
<em:description>Une extension qui crée une zone de notification.</em:description>
</Description>
</em:localized>
@ -124,7 +124,7 @@
<Description>
<em:locale>hr-HR</em:locale>
<em:translator>Goran Vidović (gogo)</em:translator>
<em:description>Proširenje za traku sustava u linuxu.</em:description>
<em:description>Proširenje za traku sustava.</em:description>
</Description>
</em:localized>
@ -132,7 +132,7 @@
<Description>
<em:locale>it</em:locale>
<em:translator>Underpass (mozillaitalia.org)</em:translator>
<em:description>Permette di ridurre l'applicazione nell'area di notifica di Linux.</em:description>
<em:description>Permette di ridurre l'applicazione nell'area di notifica.</em:description>
</Description>
</em:localized>
@ -140,7 +140,7 @@
<Description>
<em:locale>nl</em:locale>
<em:translator>markh van BabelZilla.org</em:translator>
<em:description>Een systeemvakextensie voor Linux.</em:description>
<em:description>Een systeemvakextensie.</em:description>
</Description>
</em:localized>
@ -148,7 +148,7 @@
<Description>
<em:locale>pl-PL</em:locale>
<em:translator>AreYouLoco?</em:translator>
<em:description>Rozszerzenie zasobnika dla linuxa.</em:description>
<em:description>Rozszerzenie zasobnika.</em:description>
</Description>
</em:localized>
@ -156,7 +156,7 @@
<Description>
<em:locale>sk-SK</em:locale>
<em:translator>Slavko slavino.sk</em:translator>
<em:description>Linuxové rozšírenie pre oznamovaciu lištu.</em:description>
<em:description>Rozšírenie pre oznamovaciu lištu.</em:description>
</Description>
</em:localized>
@ -164,7 +164,15 @@
<Description>
<em:locale>ru-RU</em:locale>
<em:translator>VitalD</em:translator>
<em:description>Значок в трее для GNU/Linux.</em:description>
<em:description>Значок в трее.</em:description>
</Description>
</em:localized>
<em:localized>
<Description>
<em:locale>uk-UA</em:locale>
<em:translator>Володимир Савчук Volodymyr Savchuk</em:translator>
<em:description>Розширення системного лотка.</em:description>
</Description>
</em:localized>
@ -172,7 +180,7 @@
<Description>
<em:locale>zh-TW</em:locale>
<em:translator>Velociraptor</em:translator>
<em:description>Linux 用的系統列套件。</em:description>
<em:description>用的系統列套件。</em:description>
</Description>
</em:localized>

View File

@ -62,15 +62,15 @@ firetray.Handler = {
}
throw new Error("not resolved");
})(),
support: {chat: false, full_feat: false},
support: {chat: false, winnt: false},
init: function() { // does creates icon
firetray.PrefListener.register(false);
firetray.MailChatPrefListener.register(false);
log.info("OS=" + this.runtimeOS + ", ABI=" + this.runtimeABI + ", XULrunner=" + this.xulVer);
if (FIRETRAY_SUPPORTED_OS.indexOf(this.runtimeOS) < 0) {
let platforms = FIRETRAY_SUPPORTED_OS.join(", ");
if (FIRETRAY_OS_SUPPORT.indexOf(this.runtimeOS) < 0) {
let platforms = FIRETRAY_OS_SUPPORT.join(", ");
log.error("Only "+platforms+" platform(s) supported at this time. Firetray not loaded");
return false;
} else if (this.runtimeOS == "winnt" &&
@ -83,9 +83,8 @@ firetray.Handler = {
Cu.import("resource://firetray/"+this.runtimeOS+"/FiretrayWindow.jsm");
log.debug("FiretrayWindow "+this.runtimeOS+" imported");
this.support['chat'] = FIRETRAY_CHAT_SUPPORTED_OS
.indexOf(this.runtimeOS) > -1;
this.support['full_feat'] = FIRETRAY_FULL_FEAT_SUPPORTED_OS
this.support['chat'] = ['linux'].indexOf(this.runtimeOS) > -1;
this.support['winnt'] = ['winnt']
.indexOf(firetray.Handler.runtimeOS) > -1;
if (this.appId === FIRETRAY_APP_DB['thunderbird']['id'] ||
@ -131,8 +130,7 @@ firetray.Handler = {
this.existsChatAccount())
firetray.Chat.init();
} else {
let platforms = FIRETRAY_CHAT_SUPPORTED_OS.join(", ");
log.warn("Only "+platforms+" platform(s) supported at this time. Chat not loaded");
log.warn("Chat not supported for this platform. Chat not loaded");
}
}
@ -158,7 +156,7 @@ firetray.Handler = {
VersionChange.init(FIRETRAY_ID, FIRETRAY_VERSION, FIRETRAY_PREF_BRANCH);
let vc = VersionChange, vch = firetray.VersionChangeHandler;
vc.addHook(["install", "upgrade", "reinstall"], vch.showReleaseNotes);
vc.addHook(["upgrade", "reinstall"], vch.tryEraseOldOptions);
vc.addHook(["upgrade", "reinstall"], vch.deleteOrRenameOldOptions);
vc.addHook(["upgrade", "reinstall"], vch.correctMailNotificationType);
vc.addHook(["upgrade", "reinstall"], vch.correctMailServerTypes);
if (this.inMailApp) {
@ -201,6 +199,14 @@ firetray.Handler = {
return this.appHasChat && Services.prefs.getBoolPref("mail.chat.enabled");
},
subscribeLibsForClosing: function(libs) {
for (let i=0, len=libs.length; i<len; ++i) {
let lib = libs[i];
if (!this.ctypesLibs.hasOwnProperty(lib.name))
this.ctypesLibs[lib.name] = lib;
}
},
tryCloseLibs: function() {
try {
for (let libName in this.ctypesLibs) {
@ -211,14 +217,6 @@ firetray.Handler = {
} catch(x) { log.error(x); }
},
subscribeLibsForClosing: function(libs) {
for (let i=0, len=libs.length; i<len; ++i) {
let lib = libs[i];
if (!this.ctypesLibs.hasOwnProperty(lib.name))
this.ctypesLibs[lib.name] = lib;
}
},
readTBRestoreWindowsCount: function() {
Cu.import("resource:///modules/IOUtils.js");
let sessionFile = Services.dirsvc.get("ProfD", Ci.nsIFile);
@ -328,6 +326,7 @@ firetray.Handler = {
},
// these get overridden in OS-specific Icon/Window handlers
loadIcons: function() {},
setIconImageDefault: function() {},
setIconImageNewMail: function() {},
setIconImageCustom: function(prefname) {},
@ -376,11 +375,10 @@ firetray.Handler = {
},
onMinimize: function(wid) {
log.debug("onMinimize");
let hidden = false;
let hides_on_minimize = firetray.Utils.prefService.getBoolPref('hides_on_minimize');
if (hides_on_minimize) {
let hides_single_window = firetray.Utils.prefService.getBoolPref('hides_single_window');
if (hides_single_window)
if (firetray.Utils.prefService.getBoolPref('hides_on_minimize')) {
if (firetray.Utils.prefService.getBoolPref('hides_single_window'))
firetray.Handler.hideWindow(wid);
else
firetray.Handler.hideAllWindows();
@ -552,7 +550,7 @@ firetray.PrefListener = new PrefListener(
firetray.Messaging.updateIcon();
break;
case 'new_mail_icon_names':
firetray.StatusIcon.loadThemedIcons();
this.loadIcons();
case 'excluded_folders_flags':
case 'folder_count_recursive':
case 'mail_accounts':
@ -563,7 +561,7 @@ firetray.PrefListener = new PrefListener(
case 'app_mail_icon_names':
case 'app_browser_icon_names':
case 'app_default_icon_names':
firetray.StatusIcon.loadThemedIcons(); // linux
this.loadIcons(); // linux
case 'app_icon_custom':
case 'mail_icon_custom':
firetray.StatusIcon.loadImageCustom(name);
@ -573,6 +571,10 @@ firetray.PrefListener = new PrefListener(
firetray.Messaging.updateMsgCountWithCb();
break;
case 'middle_click':
firetray.StatusIcon.middleClickActionChanged();
break;
case 'chat_icon_enable':
firetray.Handler.toggleChat(firetray.Handler.isChatEnabled());
break;
@ -709,7 +711,7 @@ firetray.VersionChangeHandler = {
} catch (e) {log.error(e);}
},
tryEraseOldOptions: function() {
deleteOrRenameOldOptions: function() {
let v0_3_Opts = [
"close_to_tray", "minimize_to_tray", "start_minimized", "confirm_exit",
"restore_to_next_unread", "mail_count_type", "show_mail_count",
@ -720,8 +722,7 @@ firetray.VersionChangeHandler = {
"text_color", "scroll_to_hide", "scroll_action", "grab_multimedia_keys",
"hide_show_mm_key", "accounts_to_exclude" ];
let v0_4_0b2_Opts = [ 'mail_notification' ];
let v0_5_0b1_Opts = [ 'mail_urgency_hint', 'app_icon_filename', 'custom_mail_icon' ];
let oldOpts = v0_3_Opts.concat(v0_4_0b2_Opts).concat(v0_5_0b1_Opts);
let oldOpts = v0_3_Opts.concat(v0_4_0b2_Opts);
for (let i=0, len=oldOpts.length; i<len; ++i) {
try {
@ -729,6 +730,35 @@ firetray.VersionChangeHandler = {
firetray.Utils.prefService.clearUserPref(option);
} catch (x) {}
}
let v0_5_0b1_Renames = {
'mail_urgency_hint': 'mail_get_attention',
'app_icon_filename': 'app_icon_custom',
'custom_mail_icon': 'mail_icon_custom'
};
oldOpts = v0_5_0b1_Renames;
let prefSrv = firetray.Utils.prefService;
for (let opt in oldOpts) {
log.debug("opt rename: "+opt);
if (prefSrv.prefHasUserValue(opt)) {
let prefType = prefSrv.getPrefType(opt);
switch (prefType) {
case Ci.nsIPrefBranch.PREF_STRING:
prefSrv.setCharPref(oldOpts[opt], prefSrv.getCharPref(opt));
break;
case Ci.nsIPrefBranch.PREF_INT:
prefSrv.setIntPref(oldOpts[opt], prefSrv.getIntPref(opt));
break;
case Ci.nsIPrefBranch.PREF_BOOL:
prefSrv.setBoolPref(oldOpts[opt], prefSrv.getBoolPref(opt));
break;
default:
log.error("Unknow pref type: "+prefType);
}
}
try { prefSrv.clearUserPref(opt); } catch (x) {}
}
},
correctMailNotificationType: function() {

View File

@ -3,11 +3,11 @@
/* for now, logging facilities (imported from logging.jsm) and Services are
automatically provided by this module */
var EXPORTED_SYMBOLS =
[ "firetray", "FIRETRAY_VERSION", "FIRETRAY_SUPPORTED_OS",
"FIRETRAY_CHAT_SUPPORTED_OS", "FIRETRAY_FULL_FEAT_SUPPORTED_OS",
"FIRETRAY_ID", "FIRETRAY_PREF_BRANCH", "FIRETRAY_SPLASH_PAGE",
[ "firetray", "FIRETRAY_VERSION", "FIRETRAY_OS_SUPPORT", "FIRETRAY_ID",
"FIRETRAY_PREF_BRANCH", "FIRETRAY_SPLASH_PAGE",
"FIRETRAY_APPLICATION_ICON_TYPE_THEMED",
"FIRETRAY_APPLICATION_ICON_TYPE_CUSTOM",
"FIRETRAY_MIDDLE_CLICK_ACTIVATE_LAST", "FIRETRAY_MIDDLE_CLICK_SHOW_HIDE",
"FIRETRAY_NOTIFICATION_MESSAGE_COUNT",
"FIRETRAY_NOTIFICATION_NEWMAIL_ICON", "FIRETRAY_NOTIFICATION_CUSTOM_ICON",
"FIRETRAY_IM_STATUS_AVAILABLE", "FIRETRAY_IM_STATUS_AWAY",
@ -15,8 +15,8 @@ var EXPORTED_SYMBOLS =
"FIRETRAY_ACCOUNT_SERVER_TYPE_IM", "FIRETRAY_DELAY_STARTUP_MILLISECONDS",
"FIRETRAY_DELAY_NOWAIT_MILLISECONDS", "FIRETRAY_MESSAGE_COUNT_TYPE_UNREAD",
"FIRETRAY_MESSAGE_COUNT_TYPE_NEW", "FIRETRAY_CHAT_ICON_BLINK_STYLE_NORMAL",
"FIRETRAY_CHAT_ICON_BLINK_STYLE_FADE", "FIRETRAY_APP_DB",
"FIRETRAY_XUL_ATTRIBUTE_COMMAND", "FIRETRAY_XUL_ATTRIBUTE_ONCOMMAND" ];
"FIRETRAY_CHAT_ICON_BLINK_STYLE_FADE", "FIRETRAY_APPINDICATOR_ID",
"FIRETRAY_APP_DB", "FIRETRAY_CB_SENTINEL" ];
const Cc = Components.classes;
const Ci = Components.interfaces;
@ -25,17 +25,18 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://firetray/logging.jsm");
const FIRETRAY_VERSION = "0.5.0b2"; // needed for sync call of onVersionChange() :(
const FIRETRAY_SUPPORTED_OS = ['linux', 'winnt']; // install.rdf sync :(
const FIRETRAY_CHAT_SUPPORTED_OS = ['linux'];
const FIRETRAY_FULL_FEAT_SUPPORTED_OS = FIRETRAY_CHAT_SUPPORTED_OS;
const FIRETRAY_ID = "{9533f794-00b4-4354-aa15-c2bbda6989f8}";
const FIRETRAY_PREF_BRANCH = "extensions.firetray.";
const FIRETRAY_SPLASH_PAGE = "http://foudfou.github.com/FireTray/";
const FIRETRAY_VERSION = "0.5.4"; // needed for sync call of onVersionChange() :(
const FIRETRAY_OS_SUPPORT = ['linux', 'winnt']; // install.rdf sync :(
const FIRETRAY_ID = "{9533f794-00b4-4354-aa15-c2bbda6989f8}";
const FIRETRAY_PREF_BRANCH = "extensions.firetray.";
const FIRETRAY_SPLASH_PAGE = "http://foudfou.github.com/FireTray/";
const FIRETRAY_APPLICATION_ICON_TYPE_THEMED = 0;
const FIRETRAY_APPLICATION_ICON_TYPE_CUSTOM = 1;
const FIRETRAY_MIDDLE_CLICK_ACTIVATE_LAST = 0;
const FIRETRAY_MIDDLE_CLICK_SHOW_HIDE = 1;
const FIRETRAY_MESSAGE_COUNT_TYPE_UNREAD = 0;
const FIRETRAY_MESSAGE_COUNT_TYPE_NEW = 1;
@ -56,8 +57,7 @@ const FIRETRAY_DELAY_NOWAIT_MILLISECONDS = 0;
const FIRETRAY_CHAT_ICON_BLINK_STYLE_NORMAL = 0;
const FIRETRAY_CHAT_ICON_BLINK_STYLE_FADE = 1;
const FIRETRAY_XUL_ATTRIBUTE_COMMAND = 0;
const FIRETRAY_XUL_ATTRIBUTE_ONCOMMAND = 1;
const FIRETRAY_APPINDICATOR_ID = "firetray";
const FIRETRAY_APP_DB = {
@ -91,6 +91,28 @@ const FIRETRAY_APP_DB = {
};
/*
* Debugging purpose: if a callback fails (like "expected type int, got (void
* 0)"), there is no easy way to find out which (for ex. when called through
* g_signal_connect()). A possible way is to remove the sentinel definition on
* each callback definition one-by-one. For ex:
*
* let callback = gtk.GCallbackWidgetFocusEvent_t(
* firetray.Window.onFocusIn, null, FIRETRAY_CB_SENTINEL);
*
* becomes
*
* let callback = gtk.GCallbackWidgetFocusEvent_t(
* firetray.Window.onFocusIn);
*
* and see if the the message "JavaScript callback failed, and an error
* sentinel was not specified" appears in the console.
*
* Note: it's not possible to define a sentinel when the return type is void.
* Note: almost all return types end up as int's (even gboolean).
*/
const FIRETRAY_CB_SENTINEL = -1;
/**
* firetray namespace.
*/
@ -195,17 +217,7 @@ firetray.Utils = {
return protocolHandler.getFileFromURLSpec(aPath).path;
},
dumpObj: function(obj) {
let str = "";
for(let prop in firetray.js.listAllProperties(obj)) {
try {
str += "obj["+prop+"]: " + obj[prop] + "\n";
} catch(e) {
str += "obj["+prop+"]: Unavailable\n";
}
}
log.info(str);
},
dumpObj: function(obj) {}, // Use JSON.stringify(obj) instead.
_nsResolver: function(prefix) {
var ns = {

View File

@ -119,17 +119,15 @@ function ctypes_library(aName, aABIs, aDefines, aGlobal) {
for each (let abi in aABIs) {
// FIXME: ABI is in fact SO_VER. Now we're mixing .so versions and the
// .dll extension :(
let soname = abi === 'dll' ? aName :
let libname = abi === 'dll' ? aName :
"lib" + aName + ".so." + abi.toString();
log.debug("Trying " + soname);
log.debug("Trying " + libname);
try {
library = ctypes.open(soname);
library = ctypes.open(libname);
this.ABI = abi;
log.debug("Successfully loaded " + soname);
log.debug("Successfully loaded " + libname);
break;
} catch(e) {
log.error(soname+" unfound.");
}
} catch(e) {}
}
this.name = aName;
@ -153,7 +151,7 @@ function ctypes_library(aName, aABIs, aDefines, aGlobal) {
};
if (!library) {
log.debug("Failed to load library: " + aName);
log.info("Library does not exist: " + aName);
this.ABI = -1;
return;
}

View File

@ -0,0 +1,58 @@
/* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
var EXPORTED_SYMBOLS = [ "appind3" ];
const APPINDICATOR_LIBNAME = "appindicator3";
const APPINDICATOR_ABIS = [ 1 ];
const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;
Cu.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://firetray/ctypes/ctypes-utils.jsm");
Cu.import("resource://firetray/ctypes/linux/gobject.jsm");
Cu.import("resource://firetray/ctypes/linux/gtk.jsm");
function appindicator_defines(lib) {
this.AppIndicator = ctypes.StructType("AppIndicator");
this.INDICATOR_APPLICATION_DBUS_ADDR = "com.canonical.indicator.application";
this.INDICATOR_APPLICATION_DBUS_OBJ = "/com/canonical/indicator/application/service";
this.INDICATOR_APPLICATION_DBUS_IFACE = "com.canonical.indicator.application.service";
this.NOTIFICATION_WATCHER_DBUS_ADDR = "org.kde.StatusNotifierWatcher";
this.NOTIFICATION_WATCHER_DBUS_OBJ = "/StatusNotifierWatcher";
this.NOTIFICATION_WATCHER_DBUS_IFACE = "org.kde.StatusNotifierWatcher";
this.NOTIFICATION_ITEM_DBUS_IFACE = "org.kde.StatusNotifierItem";
this.NOTIFICATION_ITEM_DEFAULT_OBJ = "/StatusNotifierItem";
this.NOTIFICATION_APPROVER_DBUS_IFACE = "org.ayatana.StatusNotifierApprover";
this.AppIndicatorCategory = ctypes.int; // enum
this.APP_INDICATOR_CATEGORY_APPLICATION_STATUS = 0; /*< nick=ApplicationStatus >*/
this.APP_INDICATOR_CATEGORY_COMMUNICATIONS = 1; /*< nick=Communications >*/
this.APP_INDICATOR_CATEGORY_SYSTEM_SERVICES = 2; /*< nick=SystemServices >*/
this.APP_INDICATOR_CATEGORY_HARDWARE = 3; /*< nick=Hardware >*/
this.APP_INDICATOR_CATEGORY_OTHER = 4; /*< nick=Other >*/
this.AppIndicatorStatus = ctypes.int; // enum
this.APP_INDICATOR_STATUS_PASSIVE = 0; /*< nick=Passive >*/
this.APP_INDICATOR_STATUS_ACTIVE = 1; /*< nick=Active >*/
this.APP_INDICATOR_STATUS_ATTENTION = 2; /*< nick=NeedsAttention >*/
lib.lazy_bind("app_indicator_new", this.AppIndicator.ptr, gobject.gchar.ptr, gobject.gchar.ptr, this.AppIndicatorCategory);
lib.lazy_bind("app_indicator_set_status", ctypes.void_t, this.AppIndicator.ptr, this.AppIndicatorStatus);
lib.lazy_bind("app_indicator_get_status", this.AppIndicatorStatus, this.AppIndicator.ptr);
lib.lazy_bind("app_indicator_set_menu", ctypes.void_t, this.AppIndicator.ptr, gtk.GtkMenu.ptr);
lib.lazy_bind("app_indicator_set_icon", ctypes.void_t, this.AppIndicator.ptr, gobject.gchar.ptr);
lib.lazy_bind("app_indicator_set_attention_icon", ctypes.void_t, this.AppIndicator.ptr, gobject.gchar.ptr);
lib.lazy_bind("app_indicator_set_label", ctypes.void_t, this.AppIndicator.ptr, gobject.gchar.ptr, gobject.gchar.ptr);
lib.lazy_bind("app_indicator_set_secondary_activate_target", ctypes.void_t, this.AppIndicator.ptr, gtk.GtkWidget.ptr);
this.ConnectionChangedCb_t = ctypes.FunctionType(
ctypes.default_abi, ctypes.void_t, [this.AppIndicator.ptr, gobject.gboolean, gobject.gpointer]).ptr;
this.OnScrollCb_t = ctypes.FunctionType(
ctypes.default_abi, ctypes.void_t, [this.AppIndicator.ptr, gobject.gint, gobject.guint, gobject.gpointer]).ptr;
};
var appind3 = new ctypes_library(APPINDICATOR_LIBNAME, APPINDICATOR_ABIS, appindicator_defines, this);

View File

@ -11,6 +11,7 @@ const Ci = Components.interfaces;
Cu.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://firetray/ctypes/ctypes-utils.jsm");
Cu.import("resource://firetray/ctypes/linux/glib.jsm");
Cu.import("resource://firetray/ctypes/linux/gobject.jsm");
function gio_defines(lib) {
@ -21,6 +22,25 @@ function gio_defines(lib) {
lib.lazy_bind("g_themed_icon_new_from_names", this.GIcon.ptr, ctypes.char.ptr.ptr, ctypes.int);
lib.lazy_bind("g_themed_icon_get_names", gobject.gchar.ptr.ptr, this.GThemedIcon.ptr);
this.GBusType = ctypes.int; // enum
this.G_BUS_TYPE_STARTER = -1;
this.G_BUS_TYPE_NONE = 0;
this.G_BUS_TYPE_SYSTEM = 1;
this.G_BUS_TYPE_SESSION = 2;
this.GDBusProxyFlags = ctypes.int; // enum
this.G_DBUS_PROXY_FLAGS_NONE = 0;
this.G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES = (1<<0);
this.G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS = (1<<1);
this.G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START = (1<<2);
this.GDBusConnection = ctypes.StructType("GDBusConnection");
this.GCancellable = ctypes.StructType("GCancellable");
this.GDBusProxy = ctypes.StructType("GDBusProxy");
this.GDBusInterfaceInfo = ctypes.StructType("GDBusInterfaceInfo");
lib.lazy_bind("g_bus_get_sync", this.GDBusConnection.ptr, this.GBusType, this.GCancellable.ptr, glib.GError.ptr.ptr);
lib.lazy_bind("g_dbus_proxy_new_for_bus_sync", this.GDBusProxy.ptr, this.GBusType, this.GDBusProxyFlags, this.GDBusInterfaceInfo.ptr, gobject.gchar.ptr, gobject.gchar.ptr, gobject.gchar.ptr, this.GCancellable.ptr, glib.GError.ptr.ptr);
lib.lazy_bind("g_dbus_proxy_get_name_owner", gobject.gchar.ptr, this.GDBusProxy.ptr);
}
new ctypes_library(GIO_LIBNAME, GIO_ABIS, gio_defines, this);

View File

@ -15,7 +15,13 @@ Cu.import("resource://firetray/ctypes/ctypes-utils.jsm");
function glib_defines(lib) {
/* mutual inclusion not possible */
this.GQuark = ctypes.uint32_t; // this.GQuark = gobject.guint32;
this.GError = ctypes.StructType("GError");
this.GError = ctypes.StructType("GError", [
{ domain: this.GQuark },
{ code: ctypes.int }, // gint
{ message: ctypes.char.ptr } // gchar.ptr
]);
lib.lazy_bind("g_error_free", ctypes.void_t, this.GError.ptr);
lib.lazy_bind("g_strfreev", ctypes.void_t, ctypes.char.ptr.ptr);
};
new ctypes_library(GLIB_LIBNAME, GLIB_ABIS, glib_defines, this);

View File

@ -70,6 +70,7 @@ function gobject_defines(lib) {
this.gchar = ctypes.char;
this.guchar = ctypes.unsigned_char;
this.gboolean = this.gint;
this.FALSE = this.gboolean(0);
this.gfloat = ctypes.float;
this.gdouble = ctypes.double;
this.gsize = ctypes.unsigned_long;
@ -131,6 +132,9 @@ function gobject_defines(lib) {
/* NOTE: we can't easily work with g_object_get_property() because it uses
GValue, which is an opaque struct, and thus can't be initialized by ctypes */
this.GValue = ctypes.StructType("GValue");
lib.lazy_bind("g_object_get_property", ctypes.void_t, this.GObject.ptr, this.gchar.ptr, this.GValue.ptr);
lib.lazy_bind("g_object_get", ctypes.void_t, this.gpointer, this.gchar.ptr, "...");
}
new ctypes_library(GOBJECT_LIBNAME, GOBJECT_ABIS, gobject_defines, this);

View File

@ -101,6 +101,7 @@ function gtk_defines(lib) {
lib.lazy_bind("gtk_icon_theme_get_default", this.GtkIconTheme.ptr);
lib.lazy_bind("gtk_icon_theme_get_for_screen", this.GtkIconTheme.ptr, gdk.GdkScreen.ptr);
lib.lazy_bind("gtk_icon_theme_get_search_path", ctypes.void_t, this.GtkIconTheme.ptr, gobject.gchar.ptr.ptr.array(), gobject.gint.ptr);
lib.lazy_bind("gtk_icon_theme_append_search_path", ctypes.void_t, this.GtkIconTheme.ptr, gobject.gchar.ptr);
lib.lazy_bind("gtk_icon_theme_prepend_search_path", ctypes.void_t, this.GtkIconTheme.ptr, gobject.gchar.ptr);
lib.lazy_bind("gtk_icon_theme_choose_icon", this.GtkIconInfo.ptr, this.GtkIconTheme.ptr, gobject.gchar.ptr.array(), gobject.gint, this.GtkIconLookupFlags);
@ -122,6 +123,7 @@ function gtk_defines(lib) {
lib.lazy_bind("gtk_image_menu_item_set_image", ctypes.void_t, this.GtkImageMenuItem.ptr, this.GtkWidget.ptr);
lib.lazy_bind("gtk_menu_shell_append", ctypes.void_t, this.GtkMenuShell.ptr, this.GtkWidget.ptr);
lib.lazy_bind("gtk_menu_shell_prepend", ctypes.void_t, this.GtkMenuShell.ptr, this.GtkWidget.ptr);
lib.lazy_bind("gtk_menu_shell_insert", ctypes.void_t, this.GtkMenuShell.ptr, this.GtkWidget.ptr, gobject.gint);
lib.lazy_bind("gtk_menu_popup", ctypes.void_t, this.GtkMenu.ptr, this.GtkWidget.ptr, this.GtkWidget.ptr, this.GtkMenuPositionFunc_t, gobject.gpointer, gobject.guint, gobject.guint);
lib.lazy_bind("gtk_status_icon_position_menu", ctypes.void_t, this.GtkMenu.ptr, gobject.gint.ptr, gobject.gint.ptr, gobject.gboolean.ptr, gobject.gpointer);
lib.lazy_bind("gtk_separator_menu_item_new", this.GtkWidget.ptr);
@ -154,6 +156,7 @@ function gtk_defines(lib) {
lib.lazy_bind("gtk_widget_get_events", gobject.gint, this.GtkWidget.ptr);
lib.lazy_bind("gtk_widget_add_events", ctypes.void_t, this.GtkWidget.ptr, gobject.gint);
lib.lazy_bind("gtk_widget_get_toplevel", this.GtkWidget.ptr, this.GtkWidget.ptr);
lib.lazy_bind("gtk_widget_set_sensitive", ctypes.void_t, this.GtkWidget.ptr, gobject.gboolean);
lib.lazy_bind("gtk_window_get_type", gobject.GType);
lib.lazy_bind("gtk_window_get_position", ctypes.void_t, this.GtkWindow.ptr, gobject.gint.ptr, gobject.gint.ptr);
lib.lazy_bind("gtk_window_move", ctypes.void_t, this.GtkWindow.ptr, gobject.gint, gobject.gint);

View File

@ -35,6 +35,30 @@ function kernel32_defines(lib) {
lib.lazy_bind("GetProcAddress", win32.FARPROC, win32.HMODULE, win32.LPCSTR);
lib.lazy_bind("GetCurrentThreadId", win32.DWORD);
this.STARTUPINFO = ctypes.StructType("STARTUPINFO", [
{ "cb": win32.DWORD },
{ "lpReserved": win32.LPTSTR },
{ "lpDesktop": win32.LPTSTR },
{ "lpTitle": win32.LPTSTR },
{ "dwX": win32.DWORD },
{ "dwY": win32.DWORD },
{ "dwXSize": win32.DWORD },
{ "dwYSize": win32.DWORD },
{ "dwXCountChars": win32.DWORD },
{ "dwYCountChars": win32.DWORD },
{ "dwFillAttribute": win32.DWORD },
{ "dwFlags": win32.DWORD },
{ "wShowWindow": win32.WORD },
{ "cbReserved2": win32.WORD },
{ "lpReserved2": win32.LPBYTE },
{ "hStdInput": win32.HANDLE },
{ "hStdOutput": win32.HANDLE },
{ "hStdError": win32.HANDLE }
]);
this.LPSTARTUPINFO = ctypes.PointerType(this.STARTUPINFO);
lib.lazy_bind("GetStartupInfoW", ctypes.void_t, this.LPSTARTUPINFO);
}
new ctypes_library(KERNEL32_LIBNAME, KERNEL32_ABIS, kernel32_defines, this);

View File

@ -372,6 +372,22 @@ function user32_defines(lib) {
lib.lazy_bind("GetCursorPos", win32.BOOL, win32.LPPOINT);
lib.lazy_bind("GetMessagePos", win32.DWORD);
this.WINDOWINFO = ctypes.StructType("WINDOWINFO", [
{ "cbSize": win32.DWORD },
{ "rcWindow": win32.RECT },
{ "rcClient": win32.RECT },
{ "dwStyle": win32.DWORD },
{ "dwExStyle": win32.DWORD },
{ "dwWindowStatus": win32.DWORD },
{ "cxWindowBorders": win32.UINT },
{ "cyWindowBorders": win32.UINT },
{ "atomWindowType": win32.ATOM },
{ "wCreatorVersion": win32.WORD }
]);
this.PWINDOWINFO = this.LPWINDOWINFO = this.WINDOWINFO.ptr;
lib.lazy_bind("GetWindowInfo", win32.BOOL, win32.HWND, this.WINDOWINFO.ptr);
this.WINDOWPLACEMENT = ctypes.StructType("WINDOWPLACEMENT", [
{ "length": win32.UINT },
{ "flags": win32.UINT },
@ -411,6 +427,7 @@ function user32_defines(lib) {
this.SWP_NOREPOSITION = this.SWP_NOOWNERZORDER;
this.SWP_DEFERERASE = 0x2000;
this.SWP_ASYNCWINDOWPOS = 0x4000;
this.SWP_STATECHANGED = 0x8000; /* Undocumented */
lib.lazy_bind("GetSysColor", win32.DWORD, ctypes.int);
this.COLOR_MENU = 4;

View File

@ -21,6 +21,7 @@ var win32 = new function() {
this.BOOL = ctypes.bool;
this.BYTE = ctypes.unsigned_char;
this.LPBYTE = this.BYTE.ptr;
this.INT_PTR = is64bit ? ctypes.int64_t : ctypes.int;
this.UINT = ctypes.unsigned_int;
this.UINT_PTR = is64bit ? ctypes.uint64_t : ctypes.unsigned_int;
@ -48,6 +49,7 @@ var win32 = new function() {
this.HGDIOBJ = this.HANDLE;
this.HBITMAP = this.HANDLE;
this.HFONT = this.HANDLE;
// FIXME: jschar renamed to char16_t (FF35+)
this.TCHAR = ctypes.jschar, // Mozilla compiled with UNICODE/_UNICODE macros and wchar_t = jschar
this.LPSTR = ctypes.char.ptr;
this.LPCSTR = ctypes.char.ptr;

View File

@ -0,0 +1,157 @@
/* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
var EXPORTED_SYMBOLS = [ "firetray" ];
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/ctypes.jsm");
// FIXME: can't subscribeLibsForClosing([appind3])
// https://bugs.launchpad.net/ubuntu/+source/firefox/+bug/1393256
Cu.import("resource://firetray/ctypes/linux/appindicator.jsm");
Cu.import("resource://firetray/ctypes/linux/gobject.jsm");
Cu.import("resource://firetray/ctypes/linux/gtk.jsm");
Cu.import("resource://firetray/commons.js");
firetray.Handler.subscribeLibsForClosing([gobject, gtk]);
let log = firetray.Logging.getLogger("firetray.AppIndicator");
if ("undefined" == typeof(firetray.StatusIcon))
log.error("This module MUST be imported from/after FiretrayStatusIcon !");
firetray.AppIndicator = {
initialized: false,
callbacks: {},
indicator: null,
init: function() {
this.indicator = appind3.app_indicator_new(
FIRETRAY_APPINDICATOR_ID,
firetray.StatusIcon.defaultAppIconName,
appind3.APP_INDICATOR_CATEGORY_COMMUNICATIONS
);
appind3.app_indicator_set_status(this.indicator,
appind3.APP_INDICATOR_STATUS_ACTIVE);
appind3.app_indicator_set_menu(this.indicator,
firetray.PopupMenu.menu); // mandatory
log.debug("indicator="+this.indicator);
this.addCallbacks();
for (let item in firetray.PopupMenu.menuItem) {
firetray.PopupMenu.showItem(firetray.PopupMenu.menuItem[item]);
}
this.attachMiddleClickCallback();
firetray.Handler.setIconTooltipDefault();
this.initialized = true;
return true;
},
shutdown: function() {
log.debug("Disabling AppIndicator");
gobject.g_object_unref(this.indicator);
this.initialized = false;
},
addCallbacks: function() {
this.callbacks.connChanged = appind3.ConnectionChangedCb_t(
firetray.AppIndicator.onConnectionChanged); // void return, no sentinel
gobject.g_signal_connect(this.indicator, "connection-changed",
firetray.AppIndicator.callbacks.connChanged, null);
this.callbacks.onScroll = appind3.OnScrollCb_t(
firetray.AppIndicator.onScroll); // void return, no sentinel
gobject.g_signal_connect(this.indicator, "scroll-event",
firetray.AppIndicator.callbacks.onScroll, null);
},
attachMiddleClickCallback: function(pref) {
let pref = firetray.Utils.prefService.getIntPref("middle_click");
if (pref === FIRETRAY_MIDDLE_CLICK_ACTIVATE_LAST) {
item = firetray.PopupMenu.menuItem.activateLast;
firetray.PopupMenu.showItem(firetray.PopupMenu.menuItem.activateLast);
} else if (pref === FIRETRAY_MIDDLE_CLICK_SHOW_HIDE) {
item = firetray.PopupMenu.menuItem.showHide;
firetray.PopupMenu.hideItem(firetray.PopupMenu.menuItem.activateLast);
} else {
log.error("Unknown pref value for 'middle_click': "+pref);
return false;
}
let menuItemShowHideWidget = ctypes.cast(item, gtk.GtkWidget.ptr);
appind3.app_indicator_set_secondary_activate_target(
this.indicator, menuItemShowHideWidget);
return true;
},
onConnectionChanged: function(indicator, connected, data) {
log.debug("AppIndicator connection-changed: "+connected);
},
// https://bugs.kde.org/show_bug.cgi?id=340978 broken under KDE4
onScroll: function(indicator, delta, direction, data) { // AppIndicator*, gint, GdkScrollDirection, gpointer
log.debug("onScroll: "+direction);
firetray.StatusIcon.onScroll(direction);
},
}; // AppIndicator
firetray.StatusIcon.initImpl =
firetray.AppIndicator.init.bind(firetray.AppIndicator);
firetray.StatusIcon.shutdownImpl =
firetray.AppIndicator.shutdown.bind(firetray.AppIndicator);
firetray.StatusIcon.middleClickActionChanged = function() {
log.debug("middleClickActionChanged");
firetray.AppIndicator.attachMiddleClickCallback();
};
firetray.Handler.setIconImageDefault = function() {
log.debug("setIconImageDefault");
appind3.app_indicator_set_icon(firetray.AppIndicator.indicator,
firetray.StatusIcon.defaultAppIconName);
};
firetray.Handler.setIconImageNewMail = function() {
log.debug("setIconImageNewMail");
appind3.app_indicator_set_icon(firetray.AppIndicator.indicator,
firetray.StatusIcon.defaultNewMailIconName);
};
firetray.Handler.setIconImageCustom = function(prefname) {
let prefCustomIconPath = firetray.Utils.prefService.getCharPref(prefname);
// Undocumented: ok to pass a *path* instead of an icon name! Otherwise we
// should be changing the default icons (which is maybe a better
// implementation anyway)...
appind3.app_indicator_set_icon(firetray.AppIndicator.indicator, prefCustomIconPath);
};
// No tooltips in AppIndicator
// https://bugs.launchpad.net/indicator-application/+bug/527458
firetray.Handler.setIconTooltip = function(toolTipStr) {
log.debug("setIconTooltip");
if (!firetray.AppIndicator.indicator)
return false;
firetray.PopupMenu.setItemLabel(firetray.PopupMenu.menuItem.tip,
toolTipStr);
return true;
};
// AppIndicator doesn't support pixbuf https://bugs.launchpad.net/bugs/812067
firetray.Handler.setIconText = function(text, color) { };
firetray.Handler.setIconVisibility = function(visible) {
if (!firetray.AppIndicator.indicator)
return false;
let status = visible ?
appind3.APP_INDICATOR_STATUS_ACTIVE :
appind3.APP_INDICATOR_STATUS_PASSIVE;
appind3.app_indicator_set_status(firetray.AppIndicator.indicator, status);
return true;
};

View File

@ -10,13 +10,13 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://firetray/ctypes/ctypesMap.jsm");
Cu.import("resource://firetray/ctypes/linux/gobject.jsm");
Cu.import("resource://firetray/ctypes/linux/gio.jsm");
Cu.import("resource://firetray/ctypes/linux/gdk.jsm");
Cu.import("resource://firetray/ctypes/linux/gio.jsm");
Cu.import("resource://firetray/ctypes/linux/gobject.jsm");
Cu.import("resource://firetray/ctypes/linux/gtk.jsm");
Cu.import("resource://firetray/linux/FiretrayWindow.jsm");
Cu.import("resource://firetray/commons.js");
firetray.Handler.subscribeLibsForClosing([gobject, gio, gtk]);
firetray.Handler.subscribeLibsForClosing([gdk, gio, gobject, gtk]);
if ("undefined" == typeof(firetray.Handler))
log.error("This module MUST be imported from/after FiretrayHandler !");
@ -51,7 +51,7 @@ firetray.ChatStatusIcon = {
init: function() {
if (!firetray.Handler.appHasChat) throw "ChatStatusIcon for chat app only";
if (!firetray.GtkIcons.initialized) throw "GtkIcons should have been initialized by StatusIcon";
firetray.GtkIcons.init();
this.trayIcon = gtk.gtk_status_icon_new();
this.loadThemedIcons();

View File

@ -25,7 +25,7 @@ firetray.GtkIcons = {
try {
if (this.initialized) return true;
this.loadDefaultTheme();
this.appendSearchPath();
this.initialized = true;
return true;
} catch (x) {
@ -35,15 +35,33 @@ firetray.GtkIcons = {
},
shutdown: function() {
// FIXME: XXX destroy icon here
this.initialized = false;
},
loadDefaultTheme: function() {
appendSearchPath: function() {
this.GTK_THEME_ICON_PATH = firetray.Utils.chromeToPath("chrome://firetray/skin/icons/linux");
log.debug(this.GTK_THEME_ICON_PATH);
let gtkIconTheme = gtk.gtk_icon_theme_get_default();
log.debug("gtkIconTheme="+gtkIconTheme);
gtk.gtk_icon_theme_append_search_path(gtkIconTheme, this.GTK_THEME_ICON_PATH);
if (log.level <= firetray.Logging.LogMod.Level.Debug) {
Cu.import("resource://firetray/ctypes/linux/glib.jsm");
Cu.import("resource://firetray/ctypes/linux/gobject.jsm");
firetray.Handler.subscribeLibsForClosing([glib, gobject]);
let path = new gobject.gchar.ptr.ptr;
let n_elements = new gobject.gint;
gtk.gtk_icon_theme_get_search_path(gtkIconTheme, path.address(), n_elements.address());
log.debug("n_elements="+n_elements+" path="+path);
let pathIt = path;
for (let i=0, len=n_elements.value; i<len || pathIt.isNull(); ++i) {
log.debug("path["+i+"]="+pathIt.contents.readString());
pathIt = pathIt.increment();
}
log.debug("path="+path+" pathIt="+pathIt);
glib.g_strfreev(path);
}
}
};

View File

@ -0,0 +1,341 @@
/* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
var EXPORTED_SYMBOLS = [ "firetray" ];
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://firetray/ctypes/linux/cairo.jsm");
Cu.import("resource://firetray/ctypes/linux/gdk.jsm");
Cu.import("resource://firetray/ctypes/linux/gio.jsm");
Cu.import("resource://firetray/ctypes/linux/gobject.jsm");
Cu.import("resource://firetray/ctypes/linux/gtk.jsm");
Cu.import("resource://firetray/ctypes/linux/pango.jsm");
Cu.import("resource://firetray/ctypes/linux/pangocairo.jsm");
Cu.import("resource://firetray/linux/FiretrayGtkIcons.jsm");
Cu.import("resource://firetray/commons.js");
firetray.Handler.subscribeLibsForClosing([cairo, gdk, gio, gobject, gtk, pango,
pangocairo]);
let log = firetray.Logging.getLogger("firetray.GtkStatusIcon");
if ("undefined" == typeof(firetray.Handler))
log.error("This module MUST be imported from/after FiretrayStatusIcon !");
firetray.GtkStatusIcon = {
MIN_FONT_SIZE: 4,
FILENAME_BLANK: null,
GTK_THEME_ICON_PATH: null,
initialized: false,
callbacks: {},
trayIcon: null,
themedIconApp: null,
themedIconNewMail: null,
init: function() {
this.FILENAME_BLANK = firetray.Utils.chromeToPath(
"chrome://firetray/skin/icons/blank-icon.png");
firetray.GtkIcons.init();
this.loadThemedIcons();
this.trayIcon = gtk.gtk_status_icon_new();
firetray.Handler.setIconImageDefault();
firetray.Handler.setIconTooltipDefault();
this.addCallbacks();
this.initialized = true;
return true;
},
shutdown: function() {
log.debug("Disabling GtkStatusIcon");
firetray.GtkIcons.shutdown();
// FIXME: XXX destroy icon here
this.initialized = false;
},
loadThemedIcons: function() {
if (firetray.Handler.inMailApp) {
let newMailIconNames = firetray.StatusIcon.getNewMailIconNames();
if (this.themedIconNewMail) gobject.g_object_unref(this.themedIconNewMail);
this.themedIconNewMail = this.initThemedIcon(newMailIconNames);
}
let appIconNames = firetray.StatusIcon.getAppIconNames();
if (this.themedIconApp) gobject.g_object_unref(this.themedIconApp);
this.themedIconApp = this.initThemedIcon(appIconNames);
},
initThemedIcon: function(names) {
if (!firetray.js.isArray(names)) throw new TypeError();
log.debug("themedIconNames="+names);
let namesLen = names.length;
log.debug("themedIconNamesLen="+namesLen);
let themedIconNames = ctypes.char.ptr.array(namesLen)();
for (let i=0; i<namesLen; ++i)
themedIconNames[i] = ctypes.char.array()(names[i]);
log.debug("themedIconNames="+themedIconNames);
let themedIcon = gio.g_themed_icon_new_from_names(themedIconNames, namesLen);
log.debug("themedIcon="+themedIcon);
return themedIcon;
},
addCallbacks: function() {
Cu.import("resource://firetray/linux/FiretrayPopupMenu.jsm");
/* NOTE: here we do use a function handler (instead of a function
definition) because we need the args passed to it ! As a consequence, we
need to abandon 'this' in PopupMenu.popup() */
this.callbacks.menuPopup = gtk.GCallbackMenuPopup_t(firetray.PopupMenu.popup); // void return, no sentinel
gobject.g_signal_connect(this.trayIcon, "popup-menu",
firetray.GtkStatusIcon.callbacks.menuPopup, firetray.PopupMenu.menu);
this.callbacks.onScroll = gtk.GCallbackOnScroll_t(
firetray.GtkStatusIcon.onScroll, null, FIRETRAY_CB_SENTINEL);
gobject.g_signal_connect(this.trayIcon, "scroll-event",
firetray.GtkStatusIcon.callbacks.onScroll, null);
log.debug("showHideAllWindows: "+firetray.Handler.hasOwnProperty("showHideAllWindows"));
this.callbacks.iconActivate = gtk.GCallbackStatusIconActivate_t(
firetray.GtkStatusIcon.onClick, null, FIRETRAY_CB_SENTINEL);
let handlerId = gobject.g_signal_connect(firetray.GtkStatusIcon.trayIcon,
"activate", firetray.GtkStatusIcon.callbacks.iconActivate, null);
log.debug("g_connect activate="+handlerId);
let pref = firetray.Utils.prefService.getIntPref("middle_click");
this.attachMiddleClickCallback(pref);
},
attachMiddleClickCallback: function(pref) {
log.debug("attachMiddleClickCallback pref="+pref);
if (pref === FIRETRAY_MIDDLE_CLICK_ACTIVATE_LAST) {
this.callbacks.iconMiddleClick = gtk.GCallbackStatusIconMiddleClick_t(
firetray.Handler.activateLastWindowCb, null, FIRETRAY_CB_SENTINEL);
} else if (pref === FIRETRAY_MIDDLE_CLICK_SHOW_HIDE) {
this.callbacks.iconMiddleClick = gtk.GCallbackStatusIconMiddleClick_t(
function(widget, event, data) {firetray.Handler.showHideAllWindows(); return true;},
null, FIRETRAY_CB_SENTINEL);
} else {
log.error("Unknown pref value for 'middle_click': "+pref);
return;
}
this.callbacks.iconMiddleClickId = gobject.g_signal_connect(
firetray.GtkStatusIcon.trayIcon,
"button-press-event", firetray.GtkStatusIcon.callbacks.iconMiddleClick,
null);
log.debug("g_connect middleClick="+this.callbacks.iconMiddleClickId);
},
detachMiddleClickCallback: function() {
log.debug("detachMiddleClickCallback");
gobject.g_signal_handler_disconnect(
firetray.GtkStatusIcon.trayIcon,
gobject.gulong(this.callbacks.iconMiddleClickId)
);
delete this.callbacks.iconMiddleClickId;
},
onScroll: function(icon, event, data) {
let gdkEventScroll = ctypes.cast(event, gdk.GdkEventScroll.ptr);
let direction = gdkEventScroll.contents.direction;
firetray.StatusIcon.onScroll(direction);
let stopPropagation = false;
return stopPropagation;
},
onClick: function(gtkStatusIcon, userData) {
firetray.Handler.showHideAllWindows();
let stopPropagation = true;
return stopPropagation;
},
setIconImageFromFile: function(filename) {
if (!firetray.GtkStatusIcon.trayIcon)
log.error("Icon missing");
log.debug(filename);
gtk.gtk_status_icon_set_from_file(firetray.GtkStatusIcon.trayIcon,
filename);
},
setIconImageFromGIcon: function(gicon) {
if (!firetray.GtkStatusIcon.trayIcon || !gicon)
log.error("Icon missing");
log.debug(gicon);
gtk.gtk_status_icon_set_from_gicon(firetray.GtkStatusIcon.trayIcon, gicon);
},
}; // GtkStatusIcon
firetray.StatusIcon.initImpl =
firetray.GtkStatusIcon.init.bind(firetray.GtkStatusIcon);
firetray.StatusIcon.shutdownImpl =
firetray.GtkStatusIcon.shutdown.bind(firetray.GtkStatusIcon);
firetray.StatusIcon.middleClickActionChanged = function() {
log.debug("middleClickActionChanged");
let pref = firetray.Utils.prefService.getIntPref("middle_click");
firetray.GtkStatusIcon.detachMiddleClickCallback();
firetray.GtkStatusIcon.attachMiddleClickCallback(pref);
};
firetray.Handler.loadIcons = firetray.GtkStatusIcon.loadThemedIcons;
firetray.Handler.setIconImageDefault = function() {
log.debug("setIconImageDefault");
if (!firetray.GtkStatusIcon.themedIconApp)
throw "Default application themed icon not set";
let appIconType = firetray.Utils.prefService.getIntPref("app_icon_type");
if (appIconType === FIRETRAY_APPLICATION_ICON_TYPE_THEMED) {
firetray.GtkStatusIcon.setIconImageFromGIcon(
firetray.GtkStatusIcon.themedIconApp);
} else if (appIconType === FIRETRAY_APPLICATION_ICON_TYPE_CUSTOM) {
firetray.Handler.setIconImageCustom("app_icon_custom");
}
};
firetray.Handler.setIconImageNewMail = function() {
firetray.GtkStatusIcon.setIconImageFromGIcon(
firetray.GtkStatusIcon.themedIconNewMail);
};
firetray.Handler.setIconImageCustom = function(prefname) {
let prefCustomIconPath = firetray.Utils.prefService.getCharPref(prefname);
firetray.GtkStatusIcon.setIconImageFromFile(prefCustomIconPath);
};
// GTK bug: Gdk-CRITICAL **: IA__gdk_window_get_root_coords: assertion `GDK_IS_WINDOW (window)' failed
firetray.Handler.setIconTooltip = function(toolTipStr) {
if (!firetray.GtkStatusIcon.trayIcon)
return false;
log.debug("setIconTooltip, toolTipStr="+toolTipStr);
try {
gtk.gtk_status_icon_set_tooltip_text(firetray.GtkStatusIcon.trayIcon,
toolTipStr);
} catch (x) {
log.error(x);
return false;
}
return true;
};
firetray.Handler.setIconText = function(text, color) { // FIXME: function too long
log.debug("setIconText, color="+color);
if (typeof(text) != "string")
throw new TypeError();
try {
// build background from image
let specialIcon = gdk.gdk_pixbuf_new_from_file(
firetray.GtkStatusIcon.FILENAME_BLANK, null); // GError **error);
let dest = gdk.gdk_pixbuf_copy(specialIcon);
let w = gdk.gdk_pixbuf_get_width(specialIcon);
let h = gdk.gdk_pixbuf_get_height(specialIcon);
// prepare colors/alpha
let colorMap = gdk.gdk_screen_get_system_colormap(gdk.gdk_screen_get_default());
let visual = gdk.gdk_colormap_get_visual(colorMap);
let visualDepth = visual.contents.depth;
log.debug("colorMap="+colorMap+" visual="+visual+" visualDepth="+visualDepth);
let fore = new gdk.GdkColor;
fore.pixel = fore.red = fore.green = fore.blue = 0;
let alpha = new gdk.GdkColor;
alpha.pixel = alpha.red = alpha.green = alpha.blue = 0xFFFF;
if (!fore || !alpha)
log.warn("Undefined GdkColor fore or alpha");
gdk.gdk_color_parse(color, fore.address());
if(fore.red == alpha.red && fore.green == alpha.green && fore.blue == alpha.blue) {
alpha.red=0; // make sure alpha is different from fore
}
gdk.gdk_colormap_alloc_color(colorMap, fore.address(), true, true);
gdk.gdk_colormap_alloc_color(colorMap, alpha.address(), true, true);
// build pixmap with rectangle
let pm = gdk.gdk_pixmap_new(null, w, h, visualDepth);
let pmDrawable = ctypes.cast(pm, gdk.GdkDrawable.ptr);
let cr = gdk.gdk_cairo_create(pmDrawable);
gdk.gdk_cairo_set_source_color(cr, alpha.address());
cairo.cairo_rectangle(cr, 0, 0, w, h);
cairo.cairo_set_source_rgb(cr, 1, 1, 1);
cairo.cairo_fill(cr);
// build text
let scratch = gtk.gtk_window_new(gtk.GTK_WINDOW_TOPLEVEL);
let layout = gtk.gtk_widget_create_pango_layout(scratch, null);
gtk.gtk_widget_destroy(scratch);
let fnt = pango.pango_font_description_from_string("Sans 18");
pango.pango_font_description_set_weight(fnt,pango.PANGO_WEIGHT_SEMIBOLD);
pango.pango_layout_set_spacing(layout,0);
pango.pango_layout_set_font_description(layout, fnt);
log.debug("layout="+layout);
log.debug("text="+text);
pango.pango_layout_set_text(layout, text,-1);
let tw = new ctypes.int;
let th = new ctypes.int;
let sz;
let border = 4;
pango.pango_layout_get_pixel_size(layout, tw.address(), th.address());
log.debug("tw="+tw.value+" th="+th.value);
// fit text to the icon by decreasing font size
while ( tw.value > (w - border) || th.value > (h - border) ) {
sz = pango.pango_font_description_get_size(fnt);
if(sz < firetray.GtkStatusIcon.MIN_FONT_SIZE) {
sz = firetray.GtkStatusIcon.MIN_FONT_SIZE;
break;
}
sz -= pango.PANGO_SCALE;
pango.pango_font_description_set_size(fnt,sz);
pango.pango_layout_set_font_description(layout, fnt);
pango.pango_layout_get_pixel_size(layout, tw.address(), th.address());
}
log.debug("tw="+tw.value+" th="+th.value);
pango.pango_font_description_free(fnt);
// center text
let px = (w-tw.value)/2;
let py = (h-th.value)/2;
// draw text on pixmap
gdk.gdk_cairo_set_source_color(cr, fore.address());
cairo.cairo_move_to(cr, px, py);
pangocairo.pango_cairo_show_layout(cr, layout);
cairo.cairo_destroy(cr);
gobject.g_object_unref(layout);
let buf = gdk.gdk_pixbuf_get_from_drawable(null, pmDrawable, null, 0, 0, 0, 0, w, h);
gobject.g_object_unref(pm);
log.debug("alpha="+alpha);
let alphaRed = gobject.guint16(alpha.red);
let alphaRed_guchar = ctypes.cast(alphaRed, gobject.guchar);
let alphaGreen = gobject.guint16(alpha.green);
let alphaGreen_guchar = ctypes.cast(alphaGreen, gobject.guchar);
let alphaBlue = gobject.guint16(alpha.blue);
let alphaBlue_guchar = ctypes.cast(alphaBlue, gobject.guchar);
let bufAlpha = gdk.gdk_pixbuf_add_alpha(buf, true, alphaRed_guchar, alphaGreen_guchar, alphaBlue_guchar);
gobject.g_object_unref(buf);
// merge the rendered text on top
gdk.gdk_pixbuf_composite(bufAlpha,dest,0,0,w,h,0,0,1,1,gdk.GDK_INTERP_BILINEAR,255);
gobject.g_object_unref(bufAlpha);
log.debug("gtk_status_icon_set_from_pixbuf="+dest);
gtk.gtk_status_icon_set_from_pixbuf(firetray.GtkStatusIcon.trayIcon, dest);
} catch (x) {
log.error(x);
return false;
}
return true;
};
firetray.Handler.setIconVisibility = function(visible) {
if (!firetray.GtkStatusIcon.trayIcon)
return false;
gtk.gtk_status_icon_set_visible(firetray.GtkStatusIcon.trayIcon, visible);
return true;
};

View File

@ -21,11 +21,14 @@ if ("undefined" == typeof(firetray.StatusIcon))
firetray.PopupMenu = {
MENU_ITEM_WINDOWS_POSITION: 4,
initialized: false,
callbacks: {menuItemWindowActivate: {}}, // FIXME: try to store them into a ctypes array/struct.
menu: null,
menuShell: null,
menuSeparatorWindows: null,
menuItem: {tip: null, showHide: null, activateLast: null, sep: null},
init: function() {
this.menu = gtk.gtk_menu_new();
@ -33,34 +36,46 @@ firetray.PopupMenu = {
var addMenuSeparator = false;
if (firetray.Handler.inMailApp) {
this.addItem("ResetIcon", "gtk-apply", "activate", firetray.Handler.setIconImageDefault);
this.addItem("NewMessage", "gtk-edit", "activate", firetray.Handler.openMailMessage);
this.addItem({itemName:"ResetIcon", iconName:"gtk-apply",
action:"activate", callback: firetray.Handler.setIconImageDefault});
this.addItem({itemName:"NewMessage", iconName:"gtk-edit",
action:"activate", callback: firetray.Handler.openMailMessage});
addMenuSeparator = true;
}
if (firetray.Handler.inBrowserApp) {
this.addItem("NewWindow", "gtk-new", "activate", firetray.Handler.openBrowserWindow);
this.addItem({itemName:"NewWindow", iconName:"gtk-new",
action:"activate", callback: firetray.Handler.openBrowserWindow});
addMenuSeparator = true;
}
var menuSeparator;
if (addMenuSeparator) {
menuSeparator = gtk.gtk_separator_menu_item_new();
gtk.gtk_menu_shell_append(this.menuShell, ctypes.cast(menuSeparator, gtk.GtkWidget.ptr));
gtk.gtk_menu_shell_append(this.menuShell, ctypes.cast(menuSeparator,
gtk.GtkWidget.ptr));
}
this.addItem("Preferences", "gtk-preferences", "activate", firetray.Handler.openPrefWindow);
this.addItem({itemName:"Preferences", iconName:"gtk-preferences",
action:"activate", callback: firetray.Handler.openPrefWindow});
menuSeparator = gtk.gtk_separator_menu_item_new();
gtk.gtk_menu_shell_append(this.menuShell, ctypes.cast(menuSeparator, gtk.GtkWidget.ptr));
gtk.gtk_menu_shell_append(this.menuShell, ctypes.cast(menuSeparator,
gtk.GtkWidget.ptr));
this.addItem("Quit", "gtk-quit", "activate", firetray.Handler.quitApplication);
this.addItem({itemName:"Quit", iconName:"gtk-quit",
action:"activate", callback: firetray.Handler.quitApplication});
var menuWidget = ctypes.cast(this.menu, gtk.GtkWidget.ptr);
gtk.gtk_widget_show_all(menuWidget);
var menuSeparatorWindows = gtk.gtk_separator_menu_item_new();
gtk.gtk_menu_shell_prepend(this.menuShell, ctypes.cast(menuSeparatorWindows, gtk.GtkWidget.ptr));
this.menuSeparatorWindows = menuSeparatorWindows;
// for hidden windows, not shown otherwise
this.menuSeparatorWindows = gtk.gtk_separator_menu_item_new();
gtk.gtk_menu_shell_prepend(
this.menuShell, ctypes.cast(this.menuSeparatorWindows, gtk.GtkWidget.ptr));
// FIXME: we better use a submenu for this: gtk_menu_new(), gtk_menu_item_set_submenu();
// for AppIndicator, not shown otherwise
this.prependAppIndicatorItems();
this.initialized = true;
return true;
@ -71,56 +86,88 @@ firetray.PopupMenu = {
this.initialized = false;
},
addItem: function(itemName, iconName, action, callback) {
var menuItemLabel = firetray.Utils.strings.GetStringFromName("popupMenu.itemLabel."+itemName); // shouldn't need to convert to utf8 later thank to js-ctypes
addItem: function(it) {
var menuItemLabel = firetray.Utils.strings.GetStringFromName("popupMenu.itemLabel."+it.itemName); // shouldn't need to convert to utf8 later thank to js-ctypes
var menuItem = gtk.gtk_image_menu_item_new_with_label(menuItemLabel);
var menuItemIcon = gtk.gtk_image_new_from_stock(iconName, gtk.GTK_ICON_SIZE_MENU);
var menuItemIcon = gtk.gtk_image_new_from_stock(it.iconName, gtk.GTK_ICON_SIZE_MENU);
gtk.gtk_image_menu_item_set_image(menuItem, menuItemIcon);
gtk.gtk_menu_shell_append(this.menuShell, ctypes.cast(menuItem, gtk.GtkWidget.ptr));
var menuItemWidget = ctypes.cast(menuItem, gtk.GtkWidget.ptr);
if (it.inFront)
gtk.gtk_menu_shell_prepend(this.menuShell, menuItemWidget);
else
gtk.gtk_menu_shell_append(this.menuShell, menuItemWidget);
function capitalizeFirst(str) {
return str.charAt(0).toUpperCase() + str.substring(1);
}
let cbName = "menuItem"+capitalizeFirst(itemName)+capitalizeFirst(action);
log.debug("cbName="+cbName);
this.callbacks[cbName] = gobject.GCallback_t(callback);
gobject.g_signal_connect(menuItem, action,
let cbName = "menuItem"+capitalizeFirst(it.itemName)+capitalizeFirst(it.action);
if (this.callbacks.hasOwnProperty(cbName))
log.warn("callback '"+cbName+"' already registered");
else
log.debug("cbName="+cbName);
this.callbacks[cbName] = gobject.GCallback_t(it.callback); // void return, no sentinel
gobject.g_signal_connect(menuItem, it.action,
firetray.PopupMenu.callbacks[cbName], null);
return menuItem;
},
prependAppIndicatorItems: function() {
this.menuItem.sep = gtk.gtk_separator_menu_item_new();
gtk.gtk_menu_shell_prepend(this.menuShell, ctypes.cast(this.menuItem.sep,
gtk.GtkWidget.ptr));
this.menuItem.activateLast = this.addItem({
itemName:"ActivateLast", iconName:null, action:"activate", callback:
firetray.Handler.showAllWindowsAndActivate, inFront: true});
this.menuItem.showHide = this.addItem({
itemName:"ShowHide", iconName:"gtk-go-down", action:"activate", callback:
firetray.Handler.showHideAllWindows, inFront: true});
this.menuItem.tip = this.createAndAddItemToMenuAt(0);
gtk.gtk_widget_set_sensitive(
ctypes.cast(this.menuItem.tip, gtk.GtkWidget.ptr), false);
},
popup: function(icon, button, activateTime, menu) {
log.debug("menu-popup");
log.debug("ARGS="+icon+", "+button+", "+activateTime+", "+menu);
try {
var gtkMenuPtr = ctypes.cast(menu, gtk.GtkMenu.ptr);
var iconGpointer = ctypes.cast(icon, gobject.gpointer);
gtk.gtk_menu_popup(
gtkMenuPtr, null, null, gtk.gtk_status_icon_position_menu,
iconGpointer, button, activateTime);
} catch (x) { log.error(x); }
var gtkMenuPtr = ctypes.cast(menu, gtk.GtkMenu.ptr);
var iconGpointer = ctypes.cast(icon, gobject.gpointer);
gtk.gtk_menu_popup(
gtkMenuPtr, null, null, gtk.gtk_status_icon_position_menu,
iconGpointer, button, activateTime);
let stopPropagation = false;
return stopPropagation;
},
// we'll be creating menuItems for windows (and not showing them) even if
// hides_single_window is false, because if hides_single_window becomes true,
// we'll just have to show the menuItems
addWindowItem: function(xid) { // on registerWindow
var menuItemWindow = this.createAndAddItemToMenu();
log.debug("addWindowItem");
var menuItemWindow = this.createAndAddItemToMenuAt(
this.MENU_ITEM_WINDOWS_POSITION);
firetray.Handler.gtkPopupMenuWindowItems.insert(xid, menuItemWindow);
this.setWindowItemLabel(menuItemWindow, xid.toString()); // default to xid
this.setItemLabel(menuItemWindow, xid.toString()); // default to xid
this.callbacks.menuItemWindowActivate[xid] = gobject.GCallback_t(
function(){firetray.Handler.showWindow(xid);});
gobject.g_signal_connect(menuItemWindow, "activate",
firetray.PopupMenu.callbacks.menuItemWindowActivate[xid], null);
let callback = gobject.GCallback_t(
function(){firetray.Handler.showWindow(xid);}); // void return, no sentinel
this.callbacks.menuItemWindowActivate[xid] = callback,
gobject.g_signal_connect(menuItemWindow, "activate", callback, null);
log.debug("added gtkPopupMenuWindowItems: "+firetray.Handler.gtkPopupMenuWindowItems.count);
},
createAndAddItemToMenu: function() {
createAndAddItemToMenuAt: function(pos) {
var menuItem = gtk.gtk_image_menu_item_new();
gtk.gtk_menu_shell_prepend(this.menuShell, ctypes.cast(menuItem, gtk.GtkWidget.ptr));
gtk.gtk_menu_shell_insert(this.menuShell,
ctypes.cast(menuItem, gtk.GtkWidget.ptr),
pos);
return menuItem;
},
@ -147,7 +194,7 @@ firetray.PopupMenu = {
log.debug("showWindowItem");
let menuItemWindow = firetray.Handler.gtkPopupMenuWindowItems.get(xid);
this.showItem(menuItemWindow);
this.setWindowItemLabel(menuItemWindow, firetray.Window.getWindowTitle(xid));
this.setItemLabel(menuItemWindow, firetray.Window.getWindowTitle(xid));
this.showWindowSeparator();
},
@ -155,7 +202,7 @@ firetray.PopupMenu = {
gtk.gtk_widget_show(ctypes.cast(menuItem, gtk.GtkWidget.ptr));
},
setWindowItemLabel: function(menuItem, label) {
setItemLabel: function(menuItem, label) {
log.debug("about to set title: "+label);
if (label)
gtk.gtk_menu_item_set_label(ctypes.cast(menuItem, gtk.GtkMenuItem.ptr), label);

View File

@ -6,18 +6,12 @@ const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://firetray/ctypes/linux/cairo.jsm");
Cu.import("resource://firetray/ctypes/linux/gobject.jsm");
Cu.import("resource://firetray/ctypes/linux/gdk.jsm");
Cu.import("resource://firetray/ctypes/linux/gio.jsm");
Cu.import("resource://firetray/ctypes/linux/gtk.jsm");
Cu.import("resource://firetray/ctypes/linux/pango.jsm");
Cu.import("resource://firetray/ctypes/linux/pangocairo.jsm");
Cu.import("resource://firetray/ctypes/linux/glib.jsm");
Cu.import("resource://firetray/ctypes/linux/gobject.jsm");
Cu.import("resource://firetray/commons.js");
firetray.Handler.subscribeLibsForClosing([cairo, gobject, gdk, gio, gtk, pango, pangocairo]);
firetray.Handler.subscribeLibsForClosing([gdk, gio, glib, gobject]);
let log = firetray.Logging.getLogger("firetray.StatusIcon");
@ -26,37 +20,41 @@ if ("undefined" == typeof(firetray.Handler))
firetray.StatusIcon = {
MIN_FONT_SIZE: 4,
FILENAME_BLANK: null,
initialized: false,
callbacks: {}, // pointers to JS functions. MUST LIVE DURING ALL THE EXECUTION
trayIcon: null,
themedIconApp: null,
themedIconNewMail: null,
prefAppIconNames: null,
prefNewMailIconNames: null,
defaultAppIconName: null,
defaultNewMailIconName: null,
canAppIndicator: null,
init: function() {
this.FILENAME_BLANK = firetray.Utils.chromeToPath(
"chrome://firetray/skin/icons/blank-icon.png");
Cu.import("resource://firetray/linux/FiretrayGtkIcons.jsm");
firetray.GtkIcons.init();
this.defineIconNames();
this.loadThemedIcons();
this.trayIcon = gtk.gtk_status_icon_new();
firetray.Handler.setIconImageDefault();
firetray.Handler.setIconTooltipDefault();
// PopupMenu g_connect's some Handler functions. As these are overridden is
// StatusIcon implementations, PopupMenu must be initialized *after*
// implemenations are imported.
Cu.import("resource://firetray/ctypes/linux/appindicator.jsm");
this.canAppIndicator =
(appind3.available() && this.dbusNotificationWatcherReady());
log.info("canAppIndicator="+this.canAppIndicator);
if (firetray.Utils.prefService.getBoolPref('with_appindicator') &&
this.canAppIndicator) {
/* FIXME: Ubuntu14.04/Unity: successfully closing appind3 crashes FF/TB
during exit, in Ubuntu's unity-menubar.patch's code.
https://bugs.launchpad.net/ubuntu/+source/firefox/+bug/1393256 */
// firetray.Handler.subscribeLibsForClosing([appind3]);
Cu.import("resource://firetray/linux/FiretrayAppIndicator.jsm");
} else {
Cu.import("resource://firetray/linux/FiretrayGtkStatusIcon.jsm");
}
Cu.import("resource://firetray/linux/FiretrayPopupMenu.jsm");
if (!firetray.PopupMenu.init())
return false;
this.addCallbacks();
if (!firetray.StatusIcon.initImpl())
return false;
this.initialized = true;
return true;
@ -64,9 +62,8 @@ firetray.StatusIcon = {
shutdown: function() {
log.debug("Disabling StatusIcon");
firetray.StatusIcon.shutdownImpl();
firetray.PopupMenu.shutdown();
// FIXME: should destroy/hide icon here
firetray.GtkIcons.shutdown();
this.initialized = false;
},
@ -86,78 +83,71 @@ firetray.StatusIcon = {
this.defaultNewMailIconName = "mail-unread";
},
loadThemedIcons: function() {
if (firetray.Handler.inMailApp) {
let newMailIconNames = this.getNewMailIconNames();
if (this.themedIconNewMail) gobject.g_object_unref(this.themedIconNewMail);
this.themedIconNewMail = this.initThemedIcon(newMailIconNames);
}
let appIconNames = this.getAppIconNames();
if (this.themedIconApp) gobject.g_object_unref(this.themedIconApp);
this.themedIconApp = this.initThemedIcon(appIconNames);
getAppIconNames: function() {
let appIconNames = firetray.Utils.getArrayPref(
firetray.StatusIcon.prefAppIconNames);
appIconNames.push(firetray.StatusIcon.defaultAppIconName);
return appIconNames;
},
getNewMailIconNames: function() {
let newMailIconNames = firetray.Utils.getArrayPref(
firetray.StatusIcon.prefNewMailIconNames);
newMailIconNames.push(firetray.StatusIcon.defaultNewMailIconName);
return newMailIconNames;
},
loadImageCustom: function() { }, // done in setIconImageCustom
getAppIconNames: function() {
let appIconNames = firetray.Utils.getArrayPref(this.prefAppIconNames);
appIconNames.push(this.defaultAppIconName);
return appIconNames;
},
getNewMailIconNames: function() {
let newMailIconNames = firetray.Utils.getArrayPref(this.prefNewMailIconNames);
newMailIconNames.push(this.defaultNewMailIconName);
return newMailIconNames;
dbusNotificationWatcherReady: function() {
let watcherReady = false;
function error(e) {
if (!e.isNull()) {
log.error(e.contents.message);
glib.g_error_free(e);
}
}
let conn = new gio.GDBusConnection.ptr;
let err = new glib.GError.ptr(null);
conn = gio.g_bus_get_sync(gio.G_BUS_TYPE_SESSION, null, err.address());
if (error(err)) return watcherReady;
if (!conn.isNull()) {
let flags = gio.G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
gio.G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
gio.G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS;
let proxy = gio.g_dbus_proxy_new_for_bus_sync(
gio.G_BUS_TYPE_SESSION,
flags,
null, /* GDBusInterfaceInfo */
appind3.NOTIFICATION_WATCHER_DBUS_ADDR,
appind3.NOTIFICATION_WATCHER_DBUS_OBJ,
appind3.NOTIFICATION_WATCHER_DBUS_IFACE,
null, /* GCancellable */
err.address());
if (error(err)) return watcherReady;
if (!proxy.isNull()) {
let owner = gio.g_dbus_proxy_get_name_owner(proxy);
if (!owner.isNull()) {
watcherReady = true;
}
gobject.g_object_unref(proxy);
}
gobject.g_object_unref(conn);
}
return watcherReady;
},
initThemedIcon: function(names) {
if (!firetray.js.isArray(names)) throw new TypeError();
log.debug("themedIconNames="+names);
let namesLen = names.length;
log.debug("themedIconNamesLen="+namesLen);
let themedIconNames = ctypes.char.ptr.array(namesLen)();
for (let i=0; i<namesLen; ++i)
themedIconNames[i] = ctypes.char.array()(names[i]);
log.debug("themedIconNames="+themedIconNames);
let themedIcon = gio.g_themed_icon_new_from_names(themedIconNames, namesLen);
log.debug("themedIcon="+themedIcon);
return themedIcon;
},
addCallbacks: function() {
/* NOTE: here we do use a function handler (instead of a function
definition) because we need the args passed to it ! As a consequence, we
need to abandon 'this' in PopupMenu.popup() */
this.callbacks.menuPopup = gtk.GCallbackMenuPopup_t(firetray.PopupMenu.popup);
gobject.g_signal_connect(this.trayIcon, "popup-menu",
firetray.StatusIcon.callbacks.menuPopup, firetray.PopupMenu.menu);
this.callbacks.onScroll = gtk.GCallbackOnScroll_t(firetray.StatusIcon.onScroll);
gobject.g_signal_connect(this.trayIcon, "scroll-event",
firetray.StatusIcon.callbacks.onScroll, null);
log.debug("showHideAllWindows: "+firetray.Handler.hasOwnProperty("showHideAllWindows"));
this.callbacks.iconActivate = gtk.GCallbackStatusIconActivate_t(
firetray.StatusIcon.onClick);
let handlerId = gobject.g_signal_connect(firetray.StatusIcon.trayIcon,
"activate", firetray.StatusIcon.callbacks.iconActivate, null);
log.debug("g_connect activate="+handlerId);
this.callbacks.iconMiddleClick = gtk.GCallbackStatusIconMiddleClick_t(
firetray.Handler.activateLastWindowCb);
handlerId = gobject.g_signal_connect(firetray.StatusIcon.trayIcon,
"button-press-event", firetray.StatusIcon.callbacks.iconMiddleClick, null);
log.debug("g_connect middleClick="+handlerId);
},
onScroll: function(icon, event, data) {
onScroll: function(direction) {
if (!firetray.Utils.prefService.getBoolPref("scroll_hides"))
return;
return false;
let iconGpointer = ctypes.cast(icon, gobject.gpointer);
let gdkEventScroll = ctypes.cast(event, gdk.GdkEventScroll.ptr);
let scroll_mode = firetray.Utils.prefService.getCharPref("scroll_mode");
let direction = gdkEventScroll.contents.direction;
switch(direction) {
case gdk.GDK_SCROLL_UP:
log.debug("SCROLL UP");
@ -176,65 +166,12 @@ firetray.StatusIcon = {
default:
log.error("SCROLL UNKNOWN");
}
},
onClick: function(gtkStatusIcon, userData) {
firetray.Handler.showHideAllWindows();
let stopPropagation = true;
return stopPropagation;
},
setIconImageFromFile: function(filename) {
if (!firetray.StatusIcon.trayIcon)
log.error("Icon missing");
log.debug(filename);
gtk.gtk_status_icon_set_from_file(firetray.StatusIcon.trayIcon,
filename);
},
setIconImageFromGIcon: function(gicon) {
if (!firetray.StatusIcon.trayIcon || !gicon)
log.error("Icon missing");
log.debug(gicon);
gtk.gtk_status_icon_set_from_gicon(firetray.StatusIcon.trayIcon, gicon);
return true;
}
}; // firetray.StatusIcon
firetray.Handler.setIconImageDefault = function() {
log.debug("setIconImageDefault");
if (!firetray.StatusIcon.themedIconApp)
throw "Default application themed icon not set";
let appIconType = firetray.Utils.prefService.getIntPref("app_icon_type");
if (appIconType === FIRETRAY_APPLICATION_ICON_TYPE_THEMED)
firetray.StatusIcon.setIconImageFromGIcon(firetray.StatusIcon.themedIconApp);
else if (appIconType === FIRETRAY_APPLICATION_ICON_TYPE_CUSTOM)
firetray.Handler.setIconImageCustom("app_icon_custom");
};
firetray.Handler.setIconImageNewMail = function() {
firetray.StatusIcon.setIconImageFromGIcon(firetray.StatusIcon.themedIconNewMail);
};
firetray.Handler.setIconImageCustom = function(prefname) {
let prefCustomIconPath = firetray.Utils.prefService.getCharPref(prefname);
firetray.StatusIcon.setIconImageFromFile(prefCustomIconPath);
};
// GTK bug: Gdk-CRITICAL **: IA__gdk_window_get_root_coords: assertion `GDK_IS_WINDOW (window)' failed
firetray.Handler.setIconTooltip = function(toolTipStr) {
if (!firetray.StatusIcon.trayIcon)
return false;
try {
gtk.gtk_status_icon_set_tooltip_text(firetray.StatusIcon.trayIcon,
toolTipStr);
} catch (x) {
log.error(x);
return false;
}
return true;
};
firetray.Handler.setIconTooltipDefault = function() {
if (!this.appName)
@ -242,117 +179,4 @@ firetray.Handler.setIconTooltipDefault = function() {
this.setIconTooltip(this.appName);
};
firetray.Handler.setIconText = function(text, color) { // FIXME: function too long
log.debug("setIconText, color="+color);
if (typeof(text) != "string")
throw new TypeError();
try {
// build background from image
let specialIcon = gdk.gdk_pixbuf_new_from_file(
firetray.StatusIcon.FILENAME_BLANK, null); // GError **error);
let dest = gdk.gdk_pixbuf_copy(specialIcon);
let w = gdk.gdk_pixbuf_get_width(specialIcon);
let h = gdk.gdk_pixbuf_get_height(specialIcon);
// prepare colors/alpha
let colorMap = gdk.gdk_screen_get_system_colormap(gdk.gdk_screen_get_default());
let visual = gdk.gdk_colormap_get_visual(colorMap);
let visualDepth = visual.contents.depth;
log.debug("colorMap="+colorMap+" visual="+visual+" visualDepth="+visualDepth);
let fore = new gdk.GdkColor;
fore.pixel = fore.red = fore.green = fore.blue = 0;
let alpha = new gdk.GdkColor;
alpha.pixel = alpha.red = alpha.green = alpha.blue = 0xFFFF;
if (!fore || !alpha)
log.warn("Undefined GdkColor fore or alpha");
gdk.gdk_color_parse(color, fore.address());
if(fore.red == alpha.red && fore.green == alpha.green && fore.blue == alpha.blue) {
alpha.red=0; // make sure alpha is different from fore
}
gdk.gdk_colormap_alloc_color(colorMap, fore.address(), true, true);
gdk.gdk_colormap_alloc_color(colorMap, alpha.address(), true, true);
// build pixmap with rectangle
let pm = gdk.gdk_pixmap_new(null, w, h, visualDepth);
let pmDrawable = ctypes.cast(pm, gdk.GdkDrawable.ptr);
let cr = gdk.gdk_cairo_create(pmDrawable);
gdk.gdk_cairo_set_source_color(cr, alpha.address());
cairo.cairo_rectangle(cr, 0, 0, w, h);
cairo.cairo_set_source_rgb(cr, 1, 1, 1);
cairo.cairo_fill(cr);
// build text
let scratch = gtk.gtk_window_new(gtk.GTK_WINDOW_TOPLEVEL);
let layout = gtk.gtk_widget_create_pango_layout(scratch, null);
gtk.gtk_widget_destroy(scratch);
let fnt = pango.pango_font_description_from_string("Sans 18");
pango.pango_font_description_set_weight(fnt,pango.PANGO_WEIGHT_SEMIBOLD);
pango.pango_layout_set_spacing(layout,0);
pango.pango_layout_set_font_description(layout, fnt);
log.debug("layout="+layout);
log.debug("text="+text);
pango.pango_layout_set_text(layout, text,-1);
let tw = new ctypes.int;
let th = new ctypes.int;
let sz;
let border = 4;
pango.pango_layout_get_pixel_size(layout, tw.address(), th.address());
log.debug("tw="+tw.value+" th="+th.value);
// fit text to the icon by decreasing font size
while ( tw.value > (w - border) || th.value > (h - border) ) {
sz = pango.pango_font_description_get_size(fnt);
if(sz < firetray.StatusIcon.MIN_FONT_SIZE) {
sz = firetray.StatusIcon.MIN_FONT_SIZE;
break;
}
sz -= pango.PANGO_SCALE;
pango.pango_font_description_set_size(fnt,sz);
pango.pango_layout_set_font_description(layout, fnt);
pango.pango_layout_get_pixel_size(layout, tw.address(), th.address());
}
log.debug("tw="+tw.value+" th="+th.value);
pango.pango_font_description_free(fnt);
// center text
let px = (w-tw.value)/2;
let py = (h-th.value)/2;
// draw text on pixmap
gdk.gdk_cairo_set_source_color(cr, fore.address());
cairo.cairo_move_to(cr, px, py);
pangocairo.pango_cairo_show_layout(cr, layout);
cairo.cairo_destroy(cr);
gobject.g_object_unref(layout);
let buf = gdk.gdk_pixbuf_get_from_drawable(null, pmDrawable, null, 0, 0, 0, 0, w, h);
gobject.g_object_unref(pm);
log.debug("alpha="+alpha);
let alphaRed = gobject.guint16(alpha.red);
let alphaRed_guchar = ctypes.cast(alphaRed, gobject.guchar);
let alphaGreen = gobject.guint16(alpha.green);
let alphaGreen_guchar = ctypes.cast(alphaGreen, gobject.guchar);
let alphaBlue = gobject.guint16(alpha.blue);
let alphaBlue_guchar = ctypes.cast(alphaBlue, gobject.guchar);
let bufAlpha = gdk.gdk_pixbuf_add_alpha(buf, true, alphaRed_guchar, alphaGreen_guchar, alphaBlue_guchar);
gobject.g_object_unref(buf);
// merge the rendered text on top
gdk.gdk_pixbuf_composite(bufAlpha,dest,0,0,w,h,0,0,1,1,gdk.GDK_INTERP_BILINEAR,255);
gobject.g_object_unref(bufAlpha);
log.debug("gtk_status_icon_set_from_pixbuf="+dest);
gtk.gtk_status_icon_set_from_pixbuf(firetray.StatusIcon.trayIcon, dest);
} catch (x) {
log.error(x);
return false;
}
return true;
};
firetray.Handler.setIconVisibility = function(visible) {
if (!firetray.StatusIcon.trayIcon)
return false;
gtk.gtk_status_icon_set_visible(firetray.StatusIcon.trayIcon, visible);
return true;
};
firetray.Handler.setIconTooltip = function(toolTipStr) { };

View File

@ -86,7 +86,7 @@ firetray.Window.shutdown = function() {
* Iterate over all Gtk toplevel windows to find a window. We rely on
* Service.wm to watch windows correctly: we should find only one window.
*
* @author Nils Maier (stolen from MiniTrayR)
* @author Nils Maier (stolen from MiniTrayR), himself inspired by Windows docs
* @param window nsIDOMWindow from Services.wm
* @return a gtk.GtkWindow.ptr
*/
@ -105,7 +105,7 @@ firetray.Window.getGtkWindowFromChromeWindow = function(window) {
// Search the window by the *temporary* title
let widgets = gtk.gtk_window_list_toplevels();
let that = this;
let findGtkWindowByTitleCb = gobject.GFunc_t(that._findGtkWindowByTitle);
let findGtkWindowByTitleCb = gobject.GFunc_t(that._findGtkWindowByTitle); // void return, no sentinel
var userData = new _find_data_t(
ctypes.char.array()(baseWindow.title),
null
@ -391,6 +391,7 @@ firetray.Window.xSendClientMessgeEvent = function(xid, atom, data, dataSize) {
* raises window on top and give focus.
*/
firetray.Window.activate = function(xid) {
// broken in KDE ?
gtk.gtk_window_present(firetray.Handler.gtkWindows.get(xid));
log.debug("window raised");
};
@ -590,18 +591,22 @@ firetray.Window.showAllWindowsAndActivate = function() {
firetray.Window.attachOnFocusInCallback = function(xid) {
log.debug("attachOnFocusInCallback xid="+xid);
this.signals['focus-in'].callback[xid] =
gtk.GCallbackWidgetFocusEvent_t(firetray.Window.onFocusIn);
this.signals['focus-in'].handler[xid] = gobject.g_signal_connect(
firetray.Handler.gtkWindows.get(xid), "focus-in-event",
firetray.Window.signals['focus-in'].callback[xid], null);
log.debug("focus-in handler="+this.signals['focus-in'].handler[xid]);
let callback = gtk.GCallbackWidgetFocusEvent_t(
firetray.Window.onFocusIn, null, FIRETRAY_CB_SENTINEL);
this.signals['focus-in'].callback[xid] = callback;
let handlerId = gobject.g_signal_connect(
firetray.Handler.gtkWindows.get(xid), "focus-in-event", callback, null);
log.debug("focus-in handler="+handlerId);
this.signals['focus-in'].handler[xid] = handlerId;
};
firetray.Window.detachOnFocusInCallback = function(xid) {
log.debug("detachOnFocusInCallback xid="+xid);
let gtkWin = firetray.Handler.gtkWindows.get(xid);
gobject.g_signal_handler_disconnect(gtkWin, this.signals['focus-in'].handler[xid]);
gobject.g_signal_handler_disconnect(
gtkWin,
gobject.gulong(this.signals['focus-in'].handler[xid])
);
delete this.signals['focus-in'].callback[xid];
delete this.signals['focus-in'].handler[xid];
};
@ -619,6 +624,9 @@ firetray.Window.onFocusIn = function(widget, event, data) {
if (firetray.Handler.isChatEnabled() && firetray.Chat.initialized) {
firetray.Chat.stopGetAttentionMaybe(xid);
}
let stopPropagation = false;
return stopPropagation;
};
@ -660,10 +668,12 @@ firetray.Handler.registerWindow = function(win) {
// delete_event_cb (in gtk2/nsWindow.cpp), but we prefer to use the
// provided 'close' JS event
this.windows[xid].filterWindowCb = gdk.GdkFilterFunc_t(firetray.Window.filterWindow);
this.windows[xid].filterWindowCb = gdk.GdkFilterFunc_t(
firetray.Window.filterWindow, null, FIRETRAY_CB_SENTINEL);
gdk.gdk_window_add_filter(gdkWin, this.windows[xid].filterWindowCb, null);
if (!firetray.Handler.appStarted) {
this.windows[xid].startupFilterCb = gdk.GdkFilterFunc_t(firetray.Window.startupFilter);
this.windows[xid].startupFilterCb = gdk.GdkFilterFunc_t(
firetray.Window.startupFilter, null, FIRETRAY_CB_SENTINEL);
gdk.gdk_window_add_filter(gdkWin, this.windows[xid].startupFilterCb, null);
}
@ -673,8 +683,8 @@ firetray.Handler.registerWindow = function(win) {
}
} catch (x) {
firetray.Window.unregisterWindowByXID(xid);
log.error(x);
firetray.Window.unregisterWindowByXID(xid);
return null;
}

View File

@ -335,7 +335,7 @@ BasicFormatter.prototype = Object.create(Formatter.prototype);
BasicFormatter.prototype.constructor = BasicFormatter;
BasicFormatter.prototype.format = function BF_format(message) {
return message.time + "\t" + message.loggerName + "\t" + message.levelDesc
+ "\t" + message.message + "\n";
+ "\t" + message.message;
};
/*
@ -373,7 +373,7 @@ function DumpAppender(formatter) {
DumpAppender.prototype = Object.create(Appender.prototype);
DumpAppender.prototype.constructor = DumpAppender;
DumpAppender.prototype.doAppend = function DApp_doAppend(message) {
dump(message);
dump(message + "\n");
};
/*

View File

@ -47,11 +47,11 @@ var colorTermLogColors = {
if ("undefined" == typeof(firetray)) {
var firetray = {};
};
var LogMod;
// https://wiki.mozilla.org/Labs/JS_Modules#Logging
firetray.Logging = {
initialized: false,
LogMod: null,
init: function() {
if (this.initialized) return;
@ -65,9 +65,9 @@ firetray.Logging = {
}, this);
if ("undefined" != typeof(Log)) {
LogMod = Log;
this.LogMod = Log;
} else if ("undefined" != typeof(Log4Moz)) {
LogMod = Log4Moz;
this.LogMod = Log4Moz;
} else {
let errMsg = "Log module not found";
dump(errMsg+"\n");
@ -85,8 +85,8 @@ firetray.Logging = {
setupLogging: function(loggerName) {
// lifted from log4moz.js
function SimpleFormatter() {LogMod.Formatter.call(this);}
SimpleFormatter.prototype = Object.create(LogMod.Formatter.prototype);
function SimpleFormatter() {firetray.Logging.LogMod.Formatter.call(this);}
SimpleFormatter.prototype = Object.create(firetray.Logging.LogMod.Formatter.prototype);
SimpleFormatter.prototype.constructor = SimpleFormatter;
SimpleFormatter.prototype.format = function(message) {
let messageString = "";
@ -104,7 +104,7 @@ firetray.Logging = {
date.getSeconds() + "." + date.getMilliseconds();
let stringLog = dateStr + " " +
message.levelDesc + " " + message.loggerName + " " +
messageString + "\n";
messageString;
if (message.exception)
stringLog += message.stackTrace + "\n";
@ -124,14 +124,14 @@ firetray.Logging = {
};
// Loggers are hierarchical, affiliation is handled by a '.' in the name.
this._logger = LogMod.repository.getLogger(loggerName);
this._logger = this.LogMod.repository.getLogger(loggerName);
// Lowering this log level will affect all of our addon output
this._logger.level = LogMod.Level[FIRETRAY_LOG_LEVEL];
this._logger.level = this.LogMod.Level[FIRETRAY_LOG_LEVEL];
// A console appender outputs to the JS Error Console
let simpleFormatter = new SimpleFormatter();
let capp = new LogMod.ConsoleAppender(simpleFormatter);
capp.level = LogMod.Level["Debug"];
let capp = new this.LogMod.ConsoleAppender(simpleFormatter);
capp.level = this.LogMod.Level["Debug"];
this._logger.addAppender(capp);
// A dump appender outputs to standard out
@ -141,13 +141,13 @@ firetray.Logging = {
} else {
dumpFormatter = new SimpleFormatter();
}
let dapp = new LogMod.DumpAppender(dumpFormatter);
dapp.level = LogMod.Level["Debug"];
let dapp = new this.LogMod.DumpAppender(dumpFormatter);
dapp.level = this.LogMod.Level["Debug"];
this._logger.addAppender(dapp);
},
getLogger: function(loggerName){
return LogMod.repository.getLogger(loggerName);
return this.LogMod.repository.getLogger(loggerName);
}
}; // firetray.Logging

View File

@ -81,8 +81,6 @@ firetray.StatusIcon = {
return true;
},
loadThemedIcons: function() { },
loadImages: function() {
let topmost = firetray.Handler.getWindowInterface(
Services.wm.getMostRecentWindow(null), "nsIBaseWindow");
@ -260,6 +258,14 @@ firetray.StatusIcon = {
user32.SetForegroundWindow(hWnd);
user32.TrackPopupMenu(firetray.PopupMenu.menu, user32.TPM_RIGHTALIGN|user32.TPM_BOTTOMALIGN, xPos, yPos, 0, hWnd, null);
break;
case win32.WM_MBUTTONUP:
log.debug("WM_MBUTTONUP");
break;
// case win32.WM_VSCROLL:
// case win32.WM_MOUSEWHEEL:
/* getting scroll event from the icon is not straight-forward:
SetWindowsHookEx, http://stackoverflow.com/a/90793/421846,
http://www.codeproject.com/Articles/21218/Tray-Me */
default:
}

View File

@ -70,7 +70,8 @@ firetray.Window.wndProc = function(hWnd, uMsg, wParam, lParam) { // filterWindow
}
let procPrev = firetray.Handler.wndProcsOrig.get(wid);
return user32.CallWindowProcW(user32.WNDPROC(procPrev), hWnd, uMsg, wParam, lParam); // or DefWindowProcW
return user32.CallWindowProcW(
user32.WNDPROC(procPrev), hWnd, uMsg, wParam, lParam); // or DefWindowProcW
};
/*
@ -81,22 +82,27 @@ firetray.Window.wndProc = function(hWnd, uMsg, wParam, lParam) { // filterWindow
* - a WH_CALLWNDPROC hook doesn't catch SWP_SHOWWINDOW
* - chaining WNDPROCs crashes the app (UserCallWinProcCheckWow or ffi_call)
*/
firetray.Window.startupShowCount = 0;
firetray.Window.wndProcStartup = function(hWnd, uMsg, wParam, lParam) {
let wid = firetray.Win32.hwndToHexStr(hWnd);
if (uMsg === win32.WM_WINDOWPOSCHANGING) {
let posStruct = ctypes.cast(win32.LPARAM(lParam), user32.WINDOWPOS.ptr).contents;
let posStruct = ctypes.cast(win32.LPARAM(lParam),
user32.WINDOWPOS.ptr).contents;
let isShowing = ((posStruct.flags & user32.SWP_SHOWWINDOW) != 0);
if (isShowing) {
log.debug("wndProcStartup CALLED with WM_WINDOWPOSCHANGING/SWP_SHOWWINDOW");
firetray.Window.startupShowCount += 1;
firetray.Window.startup.showCount += 1;
if (firetray.Window.startupShowCount < 2) { // hide
if (firetray.Window.startup.showCount < 2) { // hide
log.debug("start_hidden");
// Modifying a JS posStruct field does really modify the WINDOWPOS C
// struct behind lParam !
posStruct.flags &= ~user32.SWP_SHOWWINDOW;
// Modifying posStruct is modifying lParam, which is passed onwards!
if (firetray.Window.startup.showSpecial) {
posStruct.flags &= user32.SWP_NOSIZE|user32.SWP_NOMOVE;
}
else {
posStruct.flags &= ~user32.SWP_SHOWWINDOW;
}
let force = true;
firetray.Handler.addPopupMenuWindowItemAndSeparatorMaybe(wid, force);
}
@ -108,8 +114,17 @@ firetray.Window.wndProcStartup = function(hWnd, uMsg, wParam, lParam) {
mapBak: null
});
firetray.Handler.wndProcsStartup.remove(wid);
if (firetray.Window.startup.showSpecial) {
let placement = new user32.WINDOWPLACEMENT;
let ret = user32.GetWindowPlacement(hWnd, placement.address());
firetray.js.assert(ret, "GetWindowPlacement failed.");
placement.showCmd = firetray.Window.startup.showSpecial;
user32.SetWindowPlacement(hWnd, placement.address());
}
}
}
}
let procPrev = firetray.Handler.wndProcsOrig.get(wid);
@ -197,6 +212,13 @@ firetray.Handler.registerWindow = function(win) {
let proc, map;
if (!firetray.Handler.appStarted &&
firetray.Utils.prefService.getBoolPref('start_hidden')) {
let startupInfo = new kernel32.STARTUPINFO;
kernel32.GetStartupInfoW(startupInfo.address());
let showSpecial = ([
user32.SW_SHOWMINNOACTIVE, user32.SW_SHOWMINIMIZED,
user32.SW_SHOWMAXIMIZED
].indexOf(startupInfo.wShowWindow) > -1) ? startupInfo.wShowWindow : 0;
firetray.Window.startup = {showCount: 0, showSpecial: showSpecial};
proc = firetray.Window.wndProcStartup; map = firetray.Handler.wndProcsStartup;
} else {
proc = firetray.Window.wndProc; map = firetray.Handler.wndProcs;