* 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:
parent
7ee2fddddd
commit
25644e0a88
2
TODO
2
TODO
|
@ -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
|
||||
|
|
|
@ -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 |
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -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")
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue