* rewrite LibGtkStatusIcon.jsm with XPCOMUtils (will need to watch for

xpcom-shutdown for closing libs !)
* icon handling moved to MoztIconLinux.jsm
* tray icon changes (icon+tooltip) according to unreadMsgCount
* strings (localization) provided by commons.js
This commit is contained in:
foudfou 2011-09-07 23:50:18 +02:00
parent 7ee2fddddd
commit 25644e0a88
8 changed files with 360 additions and 215 deletions

2
TODO
View File

@ -1,5 +1,3 @@
* change tray icon according to unreadMsgCount
* make multi-platform. At least have js-ctypes library call dependant on OS detection. (best would be to have the OS-dependant modules loaded at startup)
* convert to a https://developer.mozilla.org/en/Extensions/Bootstrapped_extensions

View File

@ -1,2 +1,3 @@
extensions.moztray@foudil.fr.description=A system tray extension for linux.
popupMenu.itemLabel.Quit=Quit
icon.tooltip.unread_messages=#1 unread message;#1 unread messages

Binary file not shown.

After

Width:  |  Height:  |  Size: 770 B

View File

@ -2,145 +2,225 @@
var EXPORTED_SYMBOLS = ["LibGtkStatusIcon"];
const LIB_GTK = "libgtk-x11-2.0.so.0";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const LIB_GTK = "libgtk-x11-2.0.so.0";
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://moztray/LibGObject.jsm");
Cu.import("resource://moztray/LibGdkWindow.jsm");
XPCOMUtils.defineLazyGetter(this, "libgtk", function() {
var libgtk = ctypes.open(LIB_GTK);
if (!libgtk)
throw "libgtk is unavailable";
return libgtk;
});
// Structures
XPCOMUtils.defineLazyGetter(this, "GCallback", function() {
return ctypes.void_t.ptr;
});
XPCOMUtils.defineLazyGetter(this, "GtkStatusIcon", function() {
return ctypes.StructType("GtkStatusIcon");
});
XPCOMUtils.defineLazyGetter(this, "GtkStyle", function() {
return ctypes.StructType("GtkStyle");
});
XPCOMUtils.defineLazyGetter(this, "GtkRequisition", function() {
return ctypes.StructType(
"GtkRequisition", [
{ width: LibGObject.gint },
{ height: LibGObject.gint }
]);
});
XPCOMUtils.defineLazyGetter(this, "GtkAllocation", function() {
return ctypes.StructType(
"GtkAllocation", [
{ x: LibGObject.gint },
{ y: LibGObject.gint },
{ width: LibGObject.gint },
{ height: LibGObject.gint }
]);
});
/* NOTE: recursive struct needs define() and included structs MUST be
* defined ! */
XPCOMUtils.defineLazyGetter(this, "GtkWidget", function() {
var GtkWidget = ctypes.StructType("GtkWidget");
GtkWidget.define([
{ "style": GtkStyle.ptr },
{ "requisition": GtkRequisition },
{ "allocation": GtkAllocation },
{ "window": LibGdkWindow.GdkWindow.ptr },
{ "parent": GtkWidget.ptr }
]);
return GtkWidget;
});
XPCOMUtils.defineLazyGetter(this, "GtkMenu", function() {
return ctypes.StructType("GtkMenu");
});
// use ctypes.cast(menu, LibGtkStatusIcon.GtkMenuShell.ptr);
XPCOMUtils.defineLazyGetter(this, "GtkMenuShell", function() {
return ctypes.StructType("GtkMenuShell");
});
XPCOMUtils.defineLazyGetter(this, "GtkImageMenuItem", function() {
return ctypes.StructType("GtkImageMenuItem");
});
XPCOMUtils.defineLazyGetter(this, "GtkMenuPositionFunc", function() {
return ctypes.FunctionType(
ctypes.default_abi, ctypes.void_t,
[GtkMenu.ptr, LibGObject.gint.ptr, LibGObject.gint.ptr,
LibGObject.gboolean.ptr, LibGObject.gpointer]).ptr;
});
XPCOMUtils.defineLazyGetter(this, "GCallbackMenuPopup_t", function() {
return ctypes.FunctionType(
ctypes.default_abi, ctypes.void_t,
[GtkStatusIcon.ptr, LibGObject.guint, LibGObject.guint,
LibGObject.gpointer]).ptr;
});
// Functions
XPCOMUtils.defineLazyGetter(this, "gtk_status_icon_new", function() {
var gtk_status_icon_new = libgtk.declare(
"gtk_status_icon_new", ctypes.default_abi, GtkStatusIcon.ptr);
if (!gtk_status_icon_new)
throw "gtk_status_icon_new is unavailable";
return gtk_status_icon_new;
});
XPCOMUtils.defineLazyGetter(this, "gtk_status_icon_set_from_file", function() {
var gtk_status_icon_set_from_file = libgtk.declare(
"gtk_status_icon_set_from_file", ctypes.default_abi, ctypes.void_t,
GtkStatusIcon.ptr, ctypes.char.ptr);
if (!gtk_status_icon_set_from_file)
throw "gtk_status_icon_set_from_file is unavailable";
return gtk_status_icon_set_from_file;
});
XPCOMUtils.defineLazyGetter(this, "gtk_status_icon_set_tooltip_text", function() {
var gtk_status_icon_set_tooltip_text = libgtk.declare(
"gtk_status_icon_set_tooltip_text", ctypes.default_abi, ctypes.void_t,
GtkStatusIcon.ptr, ctypes.char.ptr);
if (!gtk_status_icon_set_tooltip_text)
throw "gtk_status_icon_set_tooltip_text unavailable";
return gtk_status_icon_set_tooltip_text;
});
XPCOMUtils.defineLazyGetter(this, "gtk_menu_new", function() {
var gtk_menu_new = libgtk.declare(
"gtk_menu_new", ctypes.default_abi, GtkMenu.ptr);
if (!gtk_menu_new)
throw "gtk_menu_new is unavailable";
return gtk_menu_new;
});
XPCOMUtils.defineLazyGetter(this, "gtk_image_menu_item_new_with_label", function() {
var gtk_image_menu_item_new_with_label = libgtk.declare(
"gtk_image_menu_item_new_with_label", ctypes.default_abi, GtkImageMenuItem.ptr,
LibGObject.gchar.ptr);
if (!gtk_image_menu_item_new_with_label)
throw "gtk_image_menu_item_new_with_label is unavailable";
return gtk_image_menu_item_new_with_label;
});
XPCOMUtils.defineLazyGetter(this, "gtk_image_new_from_stock", function() {
var gtk_image_new_from_stock = libgtk.declare(
"gtk_image_new_from_stock", ctypes.default_abi, GtkWidget.ptr,
LibGObject.gchar.ptr, ctypes.int); // enum
if (!gtk_image_new_from_stock)
throw "gtk_image_new_from_stock is unavailable";
return gtk_image_new_from_stock;
});
XPCOMUtils.defineLazyGetter(this, "gtk_image_menu_item_set_image", function() {
var gtk_image_menu_item_set_image = libgtk.declare(
"gtk_image_menu_item_set_image", ctypes.default_abi, ctypes.void_t,
GtkImageMenuItem.ptr, GtkWidget.ptr);
if (!gtk_image_menu_item_set_image)
throw "gtk_image_menu_item_set_image is unavailable";
return gtk_image_menu_item_set_image;
});
XPCOMUtils.defineLazyGetter(this, "gtk_menu_shell_append", function() {
var gtk_menu_shell_append = libgtk.declare(
"gtk_menu_shell_append", ctypes.default_abi, ctypes.void_t,
GtkMenuShell.ptr, GtkImageMenuItem.ptr);
if (!gtk_menu_shell_append)
throw "gtk_menu_shell_append is unavailable";
return gtk_menu_shell_append;
});
XPCOMUtils.defineLazyGetter(this, "gtk_widget_show_all", function() {
var gtk_widget_show_all = libgtk.declare(
"gtk_widget_show_all", ctypes.default_abi, ctypes.void_t,
GtkWidget.ptr);
if (!gtk_widget_show_all)
throw "gtk_widget_show_all is unavailable";
return gtk_widget_show_all;
});
XPCOMUtils.defineLazyGetter(this, "gtk_menu_popup", function() {
var gtk_menu_popup = libgtk.declare(
"gtk_menu_popup", ctypes.default_abi, ctypes.void_t,
GtkMenu.ptr, GtkWidget.ptr, GtkWidget.ptr,
GtkMenuPositionFunc, LibGObject.gpointer, LibGObject.guint,
LibGObject.guint);
if (!gtk_menu_popup)
throw "gtk_menu_popup is unavailable is unavailable";
return gtk_menu_popup;
});
XPCOMUtils.defineLazyGetter(this, "gtk_status_icon_position_menu", function() {
var gtk_status_icon_position_menu = libgtk.declare(
"gtk_status_icon_position_menu", ctypes.default_abi, ctypes.void_t,
GtkMenu.ptr, LibGObject.gint.ptr, LibGObject.gint.ptr,
LibGObject.gboolean.ptr, LibGObject.gpointer);
if (!gtk_status_icon_position_menu)
throw "gtk_status_icon_position_menu is unavailable";
return gtk_status_icon_position_menu;
});
var LibGtkStatusIcon = {
_lib: null,
init: function() {
// If ctypes doesn't exist, try to get it
Cu.import("resource://gre/modules/ctypes.jsm");
// If we still don't have ctypes, this isn't going to work...
if (typeof(ctypes) == "undefined") {
throw ("Could not load JS-Ctypes");
}
Cu.import("resource://moztray/LibGObject.jsm");
Cu.import("resource://moztray/LibGdkWindow.jsm");
try {
// Try to start up dependencies - if they fail, they'll throw
// exceptions. ex: LibGObject.init();
this._lib = ctypes.open(LIB_GTK);
if (!this._lib)
throw ("Could not load " + LIB_GTK);
} catch (e) {
this.shutdown();
throw(e);
}
// Ok, we got everything - let's declare.
this._declare();
},
shutdown: function() {
// Close our connection to the library.
if (this._lib)
this._lib.close();
},
_declare: function() {
// Types
this.GtkStatusIcon = ctypes.StructType("GtkStatusIcon");
this.GtkStyle = ctypes.StructType("GtkStyle");
this.GtkRequisition = ctypes.StructType(
"GtkRequisition", [
{ width: LibGObject.gint },
{ height: LibGObject.gint }
]);
this.GtkAllocation = ctypes.StructType(
"GtkAllocation", [
{ x: LibGObject.gint },
{ y: LibGObject.gint },
{ width: LibGObject.gint },
{ height: LibGObject.gint }
]);
/* NOTE: recursive struct needs define() and included structs MUST be
* defined ! */
this.GtkWidget = ctypes.StructType("GtkWidget");
this.GtkWidget.define([
{ "style": this.GtkStyle.ptr },
{ "requisition": this.GtkRequisition },
{ "allocation": this.GtkAllocation },
{ "window": LibGdkWindow.GdkWindow.ptr },
{ "parent": this.GtkWidget.ptr }
]);
this.GtkMenu = ctypes.StructType("GtkMenu");
this.GtkMenuShell = ctypes.StructType("GtkMenuShell");
// use ctypes.cast(menu, LibGtkStatusIcon.GtkMenuShell.ptr);
this.GtkImageMenuItem = ctypes.StructType("GtkImageMenuItem");
this.GtkMenuPositionFunc = ctypes.FunctionType(
ctypes.default_abi, ctypes.void_t,
[this.GtkMenu.ptr, LibGObject.gint.ptr, LibGObject.gint.ptr,
LibGObject.gboolean.ptr, LibGObject.gpointer]).ptr;
this.GCallbackMenuPopup_t = ctypes.FunctionType(
ctypes.default_abi, ctypes.void_t,
[this.GtkStatusIcon.ptr, LibGObject.guint, LibGObject.guint,
LibGObject.gpointer]).ptr;
// Consts
this.GTK_ICON_SIZE_MENU = 1;
// Functions
this.gtk_status_icon_new = this._lib.declare(
"gtk_status_icon_new", ctypes.default_abi, this.GtkStatusIcon.ptr);
this.gtk_status_icon_set_from_file = this._lib.declare(
"gtk_status_icon_set_from_file", ctypes.default_abi, ctypes.void_t,
this.GtkStatusIcon.ptr, ctypes.char.ptr);
this.gtk_status_icon_set_tooltip_text = this._lib.declare(
"gtk_status_icon_set_tooltip_text", ctypes.default_abi, ctypes.void_t,
this.GtkStatusIcon.ptr, ctypes.char.ptr);
this.gtk_menu_new = this._lib.declare(
"gtk_menu_new", ctypes.default_abi, this.GtkMenu.ptr);
this.gtk_image_menu_item_new_with_label = this._lib.declare(
"gtk_image_menu_item_new_with_label", ctypes.default_abi, this.GtkImageMenuItem.ptr,
LibGObject.gchar.ptr);
this.gtk_image_new_from_stock = this._lib.declare(
"gtk_image_new_from_stock", ctypes.default_abi, this.GtkWidget.ptr,
LibGObject.gchar.ptr, ctypes.int); // enum
this.gtk_image_menu_item_set_image = this._lib.declare(
"gtk_image_menu_item_set_image", ctypes.default_abi, ctypes.void_t,
this.GtkImageMenuItem.ptr, this.GtkWidget.ptr);
this.gtk_menu_shell_append = this._lib.declare(
"gtk_menu_shell_append", ctypes.default_abi, ctypes.void_t,
this.GtkMenuShell.ptr, this.GtkImageMenuItem.ptr);
this.gtk_widget_show_all = this._lib.declare(
"gtk_widget_show_all", ctypes.default_abi, ctypes.void_t,
this.GtkWidget.ptr);
this.gtk_menu_popup = this._lib.declare(
"gtk_menu_popup", ctypes.default_abi, ctypes.void_t,
this.GtkMenu.ptr, this.GtkWidget.ptr, this.GtkWidget.ptr,
this.GtkMenuPositionFunc, LibGObject.gpointer, LibGObject.guint,
LibGObject.guint);
this.gtk_status_icon_position_menu = this._lib.declare(
"gtk_status_icon_position_menu", ctypes.default_abi, ctypes.void_t,
this.GtkMenu.ptr, LibGObject.gint.ptr, LibGObject.gint.ptr,
LibGObject.gboolean.ptr, LibGObject.gpointer);
}
GTK_ICON_SIZE_MENU: 1,
libgtk: libgtk,
GCallback: GCallback,
GtkStatusIcon: GtkStatusIcon,
GtkStyle: GtkStyle,
GtkRequisition: GtkRequisition,
GtkAllocation: GtkAllocation,
GtkWidget: GtkWidget,
GtkMenu: GtkMenu,
GtkMenuShell: GtkMenuShell,
GtkImageMenuItem: GtkImageMenuItem,
GtkMenuPositionFunc: GtkMenuPositionFunc,
GCallbackMenuPopup_t: GCallbackMenuPopup_t,
gtk_status_icon_new: gtk_status_icon_new,
gtk_status_icon_set_from_file: gtk_status_icon_set_from_file,
gtk_status_icon_set_tooltip_text: gtk_status_icon_set_tooltip_text,
gtk_menu_new: gtk_menu_new,
gtk_image_menu_item_new_with_label: gtk_image_menu_item_new_with_label,
gtk_image_new_from_stock: gtk_image_new_from_stock,
gtk_image_menu_item_set_image: gtk_image_menu_item_set_image,
gtk_menu_shell_append: gtk_menu_shell_append,
gtk_widget_show_all: gtk_widget_show_all,
gtk_menu_popup: gtk_menu_popup,
gtk_status_icon_position_menu: gtk_status_icon_position_menu
};

View File

@ -12,9 +12,6 @@ Cu.import("resource://moztray/LibGObject.jsm");
Cu.import("resource://moztray/LibGtkStatusIcon.jsm");
Cu.import("resource://moztray/commons.js");
const MOZT_ICON_DIR = "chrome/skin/";
const MOZT_ICON_SUFFIX = "32.png";
/**
* mozt namespace.
*/
@ -22,12 +19,6 @@ if ("undefined" == typeof(mozt)) {
var mozt = {};
};
// pointers to JS functions. should *not* be eaten by GC ("Running global
// cleanup code from study base classes" ?)
var mozt_iconActivateCb;
var mozt_popupMenuCb;
var mozt_menuItemQuitActivateCb;
/**
* Singleton object for tray icon management
*/
@ -37,9 +28,6 @@ var mozt_menuItemQuitActivateCb;
// (https://developer.mozilla.org/en/XUL_School/JavaScript_Object_Management)
mozt.Handler = {
initialized: false,
strings: null,
tryIcon: null,
menu: null,
_windowsHidden: false,
_handledDOMWindows: [],
@ -156,13 +144,11 @@ mozt.Handler = {
LOG("ARGS="+icon+", "+button+", "+activateTime+", "+menu);
try {
LibGtkStatusIcon.init(); // before anything !!!
var gtkMenuPtr = ctypes.cast(menu, LibGtkStatusIcon.GtkMenu.ptr);
var iconGpointer = ctypes.cast(icon, LibGObject.gpointer);
LibGtkStatusIcon.gtk_menu_popup(
gtkMenuPtr, null, null, LibGtkStatusIcon.gtk_status_icon_position_menu,
iconGpointer, button, activateTime);
LibGtkStatusIcon.shutdown();
} catch (x) {
LOG(x);
}
@ -181,10 +167,6 @@ mozt.Handler = {
init: function() { // creates icon
// initialize l10n
this.strings = Services.strings
.createBundle("chrome://moztray/locale/overlay.properties");
// platform checks
let runtimeOS = Services.appinfo.OS; // "WINNT", "Linux", "Darwin"
// version checked during install, so we shouldn't need to care
@ -193,68 +175,14 @@ mozt.Handler = {
if (runtimeOS != "Linux") {
Components.utils.reportError("MOZTRAY: only Linux platform supported at this time. Moztray not loaded");
return false;
// Cu.import("resource://moztray/MoztHandler-Linux.jsm");
}
Cu.import("resource://moztray/MoztIconLinux.jsm");
// init all handled windows
this._updateHandledDOMWindows();
try {
// instanciate tray icon
LibGtkStatusIcon.init();
this.trayIcon = LibGtkStatusIcon.gtk_status_icon_new();
let mozApp = Services.appinfo.name.toLowerCase();
let iconFilename = MOZT_ICON_DIR + mozApp + MOZT_ICON_SUFFIX;
LibGtkStatusIcon.gtk_status_icon_set_from_file(this.trayIcon,
iconFilename);
// build icon popup menu
this.menu = LibGtkStatusIcon.gtk_menu_new();
// shouldn't need to convert to utf8 thank to js-ctypes
var menuItemQuitLabel = this.strings.GetStringFromName("popupMenu.itemLabel.Quit");
var menuItemQuit = LibGtkStatusIcon.gtk_image_menu_item_new_with_label(
menuItemQuitLabel);
var menuItemQuitIcon = LibGtkStatusIcon.gtk_image_new_from_stock(
"gtk-quit", LibGtkStatusIcon.GTK_ICON_SIZE_MENU);
LibGtkStatusIcon.gtk_image_menu_item_set_image(menuItemQuit, menuItemQuitIcon);
var menuShell = ctypes.cast(this.menu, LibGtkStatusIcon.GtkMenuShell.ptr);
LibGtkStatusIcon.gtk_menu_shell_append(menuShell, menuItemQuit);
mozt_menuItemQuitActivateCb = LibGObject.GCallback_t(
function(){mozt.Handler.quitApplication();});
LibGObject.g_signal_connect(menuItemQuit, "activate",
mozt_menuItemQuitActivateCb, null);
var menuWidget = ctypes.cast(this.menu, LibGtkStatusIcon.GtkWidget.ptr);
LibGtkStatusIcon.gtk_widget_show_all(menuWidget);
// here we do use a function handler because we need the args passed to
// it ! But we need to abandon 'this' in popupMenu()
mozt_popupMenuCb =
LibGtkStatusIcon.GCallbackMenuPopup_t(mozt.Handler.popupMenu);
LibGObject.g_signal_connect(this.trayIcon, "popup-menu",
mozt_popupMenuCb, this.menu);
// set tooltip. bugs on hover:
// Gdk-CRITICAL **: IA__gdk_window_get_root_coords: assertion `GDK_IS_WINDOW (window)' failed
LibGtkStatusIcon.gtk_status_icon_set_tooltip_text(this.trayIcon,
mozApp);
// close lib
LibGtkStatusIcon.shutdown();
// watch out for binding problems ! here we prefer to keep 'this' in
// showHideToTray() and abandon the args.
mozt_iconActivateCb = LibGObject.GCallback_t(
function(){mozt.Handler.showHideToTray();});
LibGObject.g_signal_connect(this.trayIcon, "activate",
mozt_iconActivateCb, null);
} catch (x) {
Components.utils.reportError(x);
return false;
}
// instanciate tray icon
mozt.IconLinux.init();
// check if in mail app
var mozAppId = Services.appinfo.ID;

View File

@ -0,0 +1,123 @@
/* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
var EXPORTED_SYMBOLS = [ "mozt" ];
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://moztray/LibGObject.jsm");
Cu.import("resource://moztray/LibGtkStatusIcon.jsm");
Cu.import("resource://moztray/commons.js");
if ("undefined" == typeof(mozt.Handler))
ERROR("MoztIcon*.jsm MUST be imported from/after MoztHandler !");
// pointers to JS functions. should *not* be eaten by GC ("Running global
// cleanup code from study base classes" ?)
var mozt_iconActivateCb;
var mozt_popupMenuCb;
var mozt_menuItemQuitActivateCb;
mozt.IconLinux = {
tryIcon: null,
menu: null,
appName: null,
ICON_FILENAME_DEFAULT: null,
ICON_DIR: "chrome/skin/", // FIXME: retrieve from chromeregistery
ICON_SUFFIX: "32.png",
init: function() {
try {
// init tray icon, some variables
this.trayIcon = LibGtkStatusIcon.gtk_status_icon_new();
this.appName = Services.appinfo.name.toLowerCase();
this.ICON_FILENAME_DEFAULT = this.ICON_DIR + this.appName + this.ICON_SUFFIX;
this.setDefaultImage();
// build icon popup menu
this.menu = LibGtkStatusIcon.gtk_menu_new();
// shouldn't need to convert to utf8 thank to js-ctypes
var menuItemQuitLabel = mozt.Utils.strings.GetStringFromName("popupMenu.itemLabel.Quit");
var menuItemQuit = LibGtkStatusIcon.gtk_image_menu_item_new_with_label(
menuItemQuitLabel);
var menuItemQuitIcon = LibGtkStatusIcon.gtk_image_new_from_stock(
"gtk-quit", LibGtkStatusIcon.GTK_ICON_SIZE_MENU);
LibGtkStatusIcon.gtk_image_menu_item_set_image(menuItemQuit, menuItemQuitIcon);
var menuShell = ctypes.cast(this.menu, LibGtkStatusIcon.GtkMenuShell.ptr);
LibGtkStatusIcon.gtk_menu_shell_append(menuShell, menuItemQuit);
mozt_menuItemQuitActivateCb = LibGObject.GCallback_t(
function(){mozt.Handler.quitApplication();});
LibGObject.g_signal_connect(menuItemQuit, "activate",
mozt_menuItemQuitActivateCb, null);
var menuWidget = ctypes.cast(this.menu, LibGtkStatusIcon.GtkWidget.ptr);
LibGtkStatusIcon.gtk_widget_show_all(menuWidget);
// here we do use a function handler because we need the args passed to
// it ! But we need to abandon 'this' in popupMenu()
mozt_popupMenuCb =
LibGtkStatusIcon.GCallbackMenuPopup_t(mozt.Handler.popupMenu);
LibGObject.g_signal_connect(this.trayIcon, "popup-menu",
mozt_popupMenuCb, this.menu);
this.setDefaultTooltip();
// watch out for binding problems ! here we prefer to keep 'this' in
// showHideToTray() and abandon the args.
mozt_iconActivateCb = LibGObject.GCallback_t(
function(){mozt.Handler.showHideToTray();});
LibGObject.g_signal_connect(this.trayIcon, "activate",
mozt_iconActivateCb, null);
} catch (x) {
Components.utils.reportError(x);
return false;
}
return true;
},
setImage: function(filename) {
if (!this.trayIcon)
return false;
try {
LibGtkStatusIcon.gtk_status_icon_set_from_file(this.trayIcon,
filename);
} catch (x) {
ERROR(x);
return false;
}
return true;
},
setDefaultImage: function() {
if (!this.ICON_FILENAME_DEFAULT)
throw "Default application icon filename not set";
LOG(this.ICON_FILENAME_DEFAULT);
this.setImage(this.ICON_FILENAME_DEFAULT);
},
// GTK bug: Gdk-CRITICAL **: IA__gdk_window_get_root_coords: assertion `GDK_IS_WINDOW (window)' failed
setTooltip: function(toolTipStr) {
if (!this.trayIcon)
return false;
LibGtkStatusIcon.gtk_status_icon_set_tooltip_text(this.trayIcon,
toolTipStr);
return true;
},
setDefaultTooltip: function() {
if (!this.appName)
throw "application name not initialized";
this.setTooltip(this.appName);
}
}; // mozt.IconLinux

View File

@ -7,6 +7,8 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource:///modules/mailServices.js");
Cu.import("resource://gre/modules/PluralForm.jsm");
Cu.import("resource://moztray/MoztIconLinux.jsm");
Cu.import("resource://moztray/commons.js");
const FLDR_UNINTERESTING =
@ -61,8 +63,6 @@ mozt.Messaging = {
*/
// TODO: check count correctly updated if folder/account creation/deletion
OnItemIntPropertyChanged: function(folder, property, oldValue, newValue) {
LOG("OnItemIntPropertyChanged fired with property: "+property);
if (property.toString() === "TotalUnreadMessages" &&
!(folder.flags & FLDR_UNINTERESTING)) {
LOG("Unread msgs for folder "+folder.prettyName+" was "+oldValue+" became "+newValue);
@ -98,6 +98,19 @@ mozt.Messaging = {
ERROR(x);
}
LOG("TotalUnread="+this._unreadMsgCount);
// update icon
if (this._unreadMsgCount > 0) {
mozt.IconLinux.setImage(mozt.IconLinux.ICON_DIR + "message-mail-new.png");
let localizedMessage = PluralForm.get(
this._unreadMsgCount, mozt.Utils.strings.GetStringFromName("icon.tooltip.unread_messages"))
.replace("#1", this._unreadMsgCount);;
mozt.IconLinux.setTooltip(localizedMessage);
}
else {
mozt.IconLinux.setDefaultImage();
mozt.IconLinux.setDefaultTooltip();
}
}
};

View File

@ -33,6 +33,8 @@ if ("undefined" == typeof(mozt)) {
});
}, this);
mozt.Utils = {
prefService: Services.prefs.getBranch("extensions.moztray.")
prefService: Services.prefs.getBranch("extensions.moztray."),
strings: Services.strings.createBundle("chrome://moztray/locale/overlay.properties")
};