1
0
mirror of https://github.com/moparisthebest/FireTray synced 2024-12-22 05:48:49 -05:00

* refactoring: Icon management exposed only through firetray.Handler

* fix mailSessionListener removal
This commit is contained in:
foudfou 2011-11-06 19:32:46 +01:00
parent 3c881dbb9d
commit 2fabe37d0c
5 changed files with 240 additions and 217 deletions

2
TODO
View File

@ -11,8 +11,6 @@
Not easily feasible since newmailalerts are hard-coded
http://mxr.mozilla.org/comm-central/find?string=content/newmailalert
* 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
see ../restartless-restart-ffext/ and

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -20,7 +20,7 @@ if ("undefined" == typeof(firetray)) {
};
/**
* Singleton object for tray icon management
* Singleton object and abstraction for tray icon management.
*/
// NOTE: modules work outside of the window scope. Unlike scripts in the
// chrome, modules don't have access to objects such as window, document, or
@ -28,11 +28,92 @@ if ("undefined" == typeof(firetray)) {
// (https://developer.mozilla.org/en/XUL_School/JavaScript_Object_Management)
firetray.Handler = {
initialized: false,
appName: null,
FILENAME_DEFAULT: null,
FILENAME_SUFFIX: "32.png",
FILENAME_BLANK: null,
FILENAME_NEWMAIL: null,
runtimeOS: null,
inMailApp: false,
_windowsHidden: false,
_handledDOMWindows: [],
init: function() { // creates icon
this.appName = Services.appinfo.name.toLowerCase();
this.FILENAME_DEFAULT = firetray.Utils.chromeToPath(
"chrome://firetray/skin/" + this.appName + this.FILENAME_SUFFIX);
this.FILENAME_BLANK = firetray.Utils.chromeToPath(
"chrome://firetray/skin/blank-icon.png");
this.FILENAME_NEWMAIL = firetray.Utils.chromeToPath(
"chrome/skin/message-mail-new.png");
// init all handled windows
this._updateHandledDOMWindows();
// OS/platform checks
this.runtimeOS = Services.appinfo.OS; // "WINNT", "Linux", "Darwin"
// version checked during install, so we shouldn't need to care
let xulVer = Services.appinfo.platformVersion; // Services.vc.compare(xulVer,"2.0a")>=0
LOG("OS=" + this.runtimeOS + ", XULrunner=" + xulVer);
switch (this.runtimeOS) {
case "Linux":
Cu.import("resource://firetray/FiretrayIconLinux.jsm");
LOG('FiretrayIconLinux imported');
// instanciate tray icon
firetray.IconLinux.init();
LOG('IconLinux initialized');
break;
default:
ERROR("FIRETRAY: only Linux platform supported at this time. Firetray not loaded");
return false;
}
// check if in mail app
var mozAppId = Services.appinfo.ID;
if (mozAppId === THUNDERBIRD_ID || mozAppId === SEAMONKEY_ID) {
this.inMailApp = true;
try {
Cu.import("resource://firetray/FiretrayMessaging.jsm");
let prefMailNotification = firetray.Utils.prefService.getIntPref("mail_notification");
if (prefMailNotification !== NOTIFICATION_DISABLED)
firetray.Messaging.enable();
} catch (x) {
ERROR(x);
return false;
}
}
LOG('inMailApp: '+this.inMailApp);
this.initialized = true;
return true;
},
shutdown: function() {
if (this.inMailApp)
firetray.Messaging.disable();
switch (this.runtimeOS) {
case "Linux":
firetray.IconLinux.shutdown();
break;
default:
ERROR("runtimeOS unknown or undefined.");
return false;
}
return true;
},
// these get overridden in OS-specific Icon handlers
setImage: function(filename) {},
setImageDefault: function() {},
setText: function(text, color) {},
setTooltip: function(localizedMessage) {},
setTooltipDefault: function() {},
_getBaseOrXULWindowFromDOMWindow: function(win, winType) {
let winInterface, winOut;
try { // thx Neil Deakin !!
@ -147,54 +228,6 @@ firetray.Handler = {
ERROR(x);
return;
}
},
init: function() { // creates icon
// platform checks
let runtimeOS = Services.appinfo.OS; // "WINNT", "Linux", "Darwin"
// version checked during install, so we shouldn't need to care
let xulVer = Services.appinfo.platformVersion; // Services.vc.compare(xulVer,"2.0a")>=0
LOG("OS=" + runtimeOS + ", XULrunner=" + xulVer);
if (runtimeOS != "Linux") {
ERROR("FIRETRAY: only Linux platform supported at this time. Firetray not loaded");
return false;
}
Cu.import("resource://firetray/FiretrayIconLinux.jsm");
LOG('FiretrayIconLinux imported');
// init all handled windows
this._updateHandledDOMWindows();
// instanciate tray icon
firetray.IconLinux.init();
LOG('IconLinux initialized');
// check if in mail app
var mozAppId = Services.appinfo.ID;
if (mozAppId === THUNDERBIRD_ID || mozAppId === SEAMONKEY_ID) {
this.inMailApp = true;
try {
Cu.import("resource://firetray/FiretrayMessaging.jsm");
let prefMailNotification = firetray.Utils.prefService.getIntPref("mail_notification");
if (prefMailNotification !== NOTIFICATION_DISABLED)
firetray.Messaging.enable();
} catch (x) {
ERROR(x);
return false;
}
}
LOG('inMailApp: '+this.inMailApp);
this.initialized = true;
return true;
},
shutdown: function() { // NOT USED YET
if (this.inMailApp)
firetray.Messaging.disable();
firetray.IconLinux.shutdown();
}
}; // firetray.Handler

View File

@ -47,31 +47,22 @@ var _find_data_t = ctypes.StructType("_find_data_t", [
firetray.IconLinux = {
tryIcon: null,
menu: null,
appName: null,
FILENAME_DEFAULT: null,
FILENAME_SUFFIX: "32.png",
FILENAME_NEWMAIL: "newmail.png",
MIN_FONT_SIZE: 4,
init: function() {
try {
// init tray icon, some variables
this.trayIcon = gtk.gtk_status_icon_new();
this.appName = Services.appinfo.name.toLowerCase();
this.FILENAME_DEFAULT = firetray.Utils.chromeToPath(
"chrome://firetray/skin/" + this.appName + this.FILENAME_SUFFIX);
this.FILENAME_NEWMAIL = firetray.Utils.chromeToPath(
"chrome://firetray/skin/newmail.png");
} catch (x) {
ERROR(x);
return false;
}
this.setImageDefault();
firetray.Handler.setImageDefault();
this._buildPopupMenu();
this.setTooltipDefault();
firetray.Handler.setTooltipDefault();
// attach popupMenu to trayIcon
try {
@ -144,154 +135,6 @@ firetray.IconLinux = {
},
setImage: function(filename) {
if (!this.trayIcon)
return false;
LOG(filename);
try {
gtk.gtk_status_icon_set_from_file(this.trayIcon,
filename);
} catch (x) {
ERROR(x);
return false;
}
return true;
},
setImageDefault: function() {
if (!this.FILENAME_DEFAULT)
throw "Default application icon filename not set";
this.setImage(this.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;
try {
gtk.gtk_status_icon_set_tooltip_text(this.trayIcon,
toolTipStr);
} catch (x) {
ERROR(x);
return false;
}
return true;
},
setTooltipDefault: function() {
if (!this.appName)
throw "application name not initialized";
this.setTooltip(this.appName);
},
setText: function(text, color) { // TODO: split into smaller functions;
LOG("setText");
if (typeof(text) != "string")
throw new TypeError();
try {
// build background from image
let specialIcon = gdk.gdk_pixbuf_new_from_file(this.FILENAME_NEWMAIL, 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("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)
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("layout="+layout);
LOG("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("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 < this.MIN_FONT_SIZE) {
sz = this.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("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("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_NEAREST,255);
gobject.g_object_unref(bufAlpha);
gtk.gtk_status_icon_set_from_pixbuf(this.trayIcon, dest);
} catch (x) {
ERROR(x);
return false;
}
return true;
},
/**
* 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.
@ -394,3 +237,152 @@ firetray.IconLinux = {
}
}; // firetray.IconLinux
firetray.Handler.setImage = function(filename) {
if (!firetray.IconLinux.trayIcon)
return false;
LOG(filename);
try {
gtk.gtk_status_icon_set_from_file(firetray.IconLinux.trayIcon,
filename);
} catch (x) {
ERROR(x);
return false;
}
return true;
};
firetray.Handler.setImageDefault = function() {
if (!this.FILENAME_DEFAULT)
throw "Default application icon filename not set";
this.setImage(this.FILENAME_DEFAULT);
};
// GTK bug: Gdk-CRITICAL **: IA__gdk_window_get_root_coords: assertion `GDK_IS_WINDOW (window)' failed
firetray.Handler.setTooltip = function(toolTipStr) {
if (!firetray.IconLinux.trayIcon)
return false;
try {
gtk.gtk_status_icon_set_tooltip_text(firetray.IconLinux.trayIcon,
toolTipStr);
} catch (x) {
ERROR(x);
return false;
}
return true;
};
firetray.Handler.setTooltipDefault = function() {
if (!this.appName)
throw "application name not initialized";
this.setTooltip(this.appName);
};
firetray.Handler.setText = function(text, color) { // TODO: split into smaller functions;
LOG("setText");
if (typeof(text) != "string")
throw new TypeError();
try {
// build background from image
let specialIcon = gdk.gdk_pixbuf_new_from_file(this.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("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)
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("layout="+layout);
LOG("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("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.IconLinux.MIN_FONT_SIZE) {
sz = firetray.IconLinux.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("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("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_NEAREST,255);
gobject.g_object_unref(bufAlpha);
gtk.gtk_status_icon_set_from_pixbuf(firetray.IconLinux.trayIcon, dest);
} catch (x) {
ERROR(x);
return false;
}
return true;
};

View File

@ -8,7 +8,7 @@ const Cu = Components.utils;
Cu.import("resource:///modules/mailServices.js");
Cu.import("resource://gre/modules/PluralForm.jsm");
Cu.import("resource://firetray/FiretrayIconLinux.jsm");
// Cu.import("resource://firetray/FiretrayHandler.jsm");
Cu.import("resource://firetray/commons.js");
const FLDR_UNINTERESTING =
@ -52,8 +52,8 @@ firetray.Messaging = {
if (!this.enabled)
return;
MailServices.mailSession.RemoveFolderListener(this);
firetray.IconLinux.setImageDefault();
MailServices.mailSession.RemoveFolderListener(this.mailSessionListener);
firetray.Handler.setImageDefault();
this.enabled = false;
},
@ -110,16 +110,16 @@ firetray.Messaging = {
// update icon
if (this._unreadMsgCount == 0) {
firetray.IconLinux.setImageDefault();
firetray.IconLinux.setTooltipDefault();
firetray.Handler.setImageDefault();
firetray.Handler.setTooltipDefault();
} else if (this._unreadMsgCount > 0) {
let prefIconTextColor = firetray.Utils.prefService.getCharPref("icon_text_color");
firetray.IconLinux.setText(this._unreadMsgCount.toString(), prefIconTextColor);
firetray.Handler.setText(this._unreadMsgCount.toString(), prefIconTextColor);
let localizedMessage = PluralForm.get(
this._unreadMsgCount,
firetray.Utils.strings.GetStringFromName("tooltip.unread_messages"))
.replace("#1", this._unreadMsgCount);;
firetray.IconLinux.setTooltip(localizedMessage);
firetray.Handler.setTooltip(localizedMessage);
} else {
throw "negative message count"; // should never happen
}