[Pkg-mozext-commits] [firetray] 35/399: * 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

David Prévot taffit at alioth.debian.org
Tue Oct 29 18:23:09 UTC 2013


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to branch dfsg-clean
in repository firetray.

commit 25644e0a88cc4ed1e83a8b4f1ee5f6d0cf968a81
Author: foudfou <foudil.newbie+git at gmail.com>
Date:   Wed Sep 7 23:50:18 2011 +0200

    * 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
---
 TODO                                       |    2 -
 src/chrome/locale/en-US/overlay.properties |    1 +
 src/chrome/skin/message-mail-new.png       |  Bin 0 -> 770 bytes
 src/modules/LibGtkStatusIcon.jsm           |  350 +++++++++++++++++-----------
 src/modules/MoztHandler.jsm                |   78 +------
 src/modules/MoztIconLinux.jsm              |  123 ++++++++++
 src/modules/MoztMessaging.jsm              |   17 +-
 src/modules/commons.js                     |    4 +-
 8 files changed, 360 insertions(+), 215 deletions(-)

diff --git a/TODO b/TODO
index 3b38c85..c56d9d0 100644
--- a/TODO
+++ b/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
diff --git a/src/chrome/locale/en-US/overlay.properties b/src/chrome/locale/en-US/overlay.properties
index 2d4f601..81bd21d 100644
--- a/src/chrome/locale/en-US/overlay.properties
+++ b/src/chrome/locale/en-US/overlay.properties
@@ -1,2 +1,3 @@
 extensions.moztray at foudil.fr.description=A system tray extension for linux.
 popupMenu.itemLabel.Quit=Quit
+icon.tooltip.unread_messages=#1 unread message;#1 unread messages
diff --git a/src/chrome/skin/message-mail-new.png b/src/chrome/skin/message-mail-new.png
new file mode 100644
index 0000000..3691cb7
Binary files /dev/null and b/src/chrome/skin/message-mail-new.png differ
diff --git a/src/modules/LibGtkStatusIcon.jsm b/src/modules/LibGtkStatusIcon.jsm
index 02342d6..0da7157 100644
--- a/src/modules/LibGtkStatusIcon.jsm
+++ b/src/modules/LibGtkStatusIcon.jsm
@@ -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";
-
-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(
+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,
-      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);
-
-  }
+      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 = {
+  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
 };
diff --git a/src/modules/MoztHandler.jsm b/src/modules/MoztHandler.jsm
index 1c9a28c..3d1fce6 100644
--- a/src/modules/MoztHandler.jsm
+++ b/src/modules/MoztHandler.jsm
@@ -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;
diff --git a/src/modules/MoztIconLinux.jsm b/src/modules/MoztIconLinux.jsm
new file mode 100644
index 0000000..fba42df
--- /dev/null
+++ b/src/modules/MoztIconLinux.jsm
@@ -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
diff --git a/src/modules/MoztMessaging.jsm b/src/modules/MoztMessaging.jsm
index 6318126..e290e09 100644
--- a/src/modules/MoztMessaging.jsm
+++ b/src/modules/MoztMessaging.jsm
@@ -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();
+    }
   }
 
 };
diff --git a/src/modules/commons.js b/src/modules/commons.js
index 9f31578..0ff85c8 100644
--- a/src/modules/commons.js
+++ b/src/modules/commons.js
@@ -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")
 };

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/firetray.git



More information about the Pkg-mozext-commits mailing list