Skip to content

Commit 609525c

Browse files
committed
Added new mail count to Appindicator
1 parent 30250a9 commit 609525c

File tree

3 files changed

+165
-23
lines changed

3 files changed

+165
-23
lines changed

src/defaults/preferences/prefs.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,4 @@ pref("extensions.firetray.excluded_folders_flags", 1077956384);
4141
pref("extensions.firetray.mail_accounts", '{ "serverTypes": {"pop3":{"order":1,"excluded":false}, "imap":{"order":1,"excluded":false}, "movemail":{"order":2,"excluded":true}, "none":{"order":3,"excluded":false}, "rss":{"order":4,"excluded":true}, "nntp":{"order":5,"excluded":true}, "exquilla":{"order":6,"excluded":true}}, "excludedAccounts": [] }'); // JSON
4242
pref("extensions.firetray.only_favorite_folders", false);
4343

44-
pref("extensions.firetray.with_appindicator", false);
44+
pref("extensions.firetray.with_appindicator", true);

src/modules/ctypes/linux/gdk23.jsm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ function gdk23_defines(lib) {
228228
lib.lazy_bind("gdk_pixbuf_get_rowstride", ctypes.int, this.GdkPixbuf.ptr);
229229
lib.lazy_bind("gdk_pixbuf_get_byte_length", gobject.gsize, this.GdkPixbuf.ptr);
230230
lib.lazy_bind("gdk_pixbuf_copy", this.GdkPixbuf.ptr, this.GdkPixbuf.ptr);
231+
lib.lazy_bind("gdk_pixbuf_save", gobject.gboolean, this.GdkPixbuf.ptr, gobject.gchar.ptr, gobject.gchar.ptr, glib.GError.ptr.ptr, gobject.gchar.ptr);
231232

232233
lib.lazy_bind("gdk_screen_get_system_visual", this.GdkVisual.ptr, this.GdkScreen.ptr);
233234
lib.lazy_bind("gdk_screen_get_system_colormap", this.GdkColormap.ptr, this.GdkScreen.ptr);

src/modules/linux/FiretrayAppIndicator.jsm

Lines changed: 163 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,18 @@ const Ci = Components.interfaces;
77
const Cu = Components.utils;
88

99
Cu.import("resource://gre/modules/ctypes.jsm");
10+
Cu.import("resource://gre/modules/osfile.jsm")
1011
Cu.import("resource://firetray/commons.js"); // first for Handler.app !
1112
Cu.import("resource://firetray/ctypes/linux/gobject.jsm");
1213
// FIXME: can't subscribeLibsForClosing([appind])
1314
// https://bugs.launchpad.net/ubuntu/+source/firefox/+bug/1393256
1415
Cu.import("resource://firetray/ctypes/linux/"+firetray.Handler.app.widgetTk+"/appindicator.jsm");
16+
Cu.import("resource://firetray/ctypes/linux/"+firetray.Handler.app.widgetTk+"/gdk.jsm");
1517
Cu.import("resource://firetray/ctypes/linux/"+firetray.Handler.app.widgetTk+"/gtk.jsm");
16-
firetray.Handler.subscribeLibsForClosing([gobject, gtk]);
18+
Cu.import("resource://firetray/ctypes/linux/cairo.jsm");
19+
Cu.import("resource://firetray/ctypes/linux/pango.jsm");
20+
Cu.import("resource://firetray/ctypes/linux/pangocairo.jsm");
21+
firetray.Handler.subscribeLibsForClosing([gobject, gdk, gtk, cairo, pango, pangocairo]);
1722

1823
let log = firetray.Logging.getLogger("firetray.AppIndicator");
1924

@@ -25,22 +30,19 @@ firetray.AppIndicator = {
2530
initialized: false,
2631
callbacks: {},
2732
indicator: null,
28-
33+
tempfile: null,
34+
MIN_FONT_SIZE: 4,
35+
2936
init: function() {
3037
this.indicator = appind.app_indicator_new(
3138
FIRETRAY_APPINDICATOR_ID,
3239
firetray.StatusIcon.defaultAppIconName,
3340
appind.APP_INDICATOR_CATEGORY_COMMUNICATIONS
3441
);
3542

36-
37-
//appind.app_indicator_set_icon_theme_path(this.indicator, firetray.StatusIcon.THEME_ICON_PATH);
38-
appind.app_indicator_set_icon_theme_path(this.indicator,
39-
Components.classes["@mozilla.org/file/directory_service;1"].getService( Components.interfaces.nsIProperties).get("ProfD", Components.interfaces.nsIFile).path
40-
+ "/extensions/{9533f794-00b4-4354-aa15-c2bbda6989f8}/chrome/skin/icons/"
41-
);
42-
43-
43+
this.tempfile = Components.classes["@mozilla.org/file/directory_service;1"].getService( Components.interfaces.nsIProperties).get("TmpD", Components.interfaces.nsIFile).path
44+
+ "/thunderbird.png";
45+
4446
appind.app_indicator_set_status(this.indicator,
4547
appind.APP_INDICATOR_STATUS_ACTIVE);
4648
appind.app_indicator_set_menu(this.indicator,
@@ -64,6 +66,7 @@ firetray.AppIndicator = {
6466
log.debug("Disabling AppIndicator");
6567
gobject.g_object_unref(this.indicator);
6668
this.initialized = false;
69+
OS.File.remove(this.tempfile);
6770
},
6871

6972
addCallbacks: function() {
@@ -82,11 +85,13 @@ firetray.AppIndicator = {
8285
let pref = firetray.Utils.prefService.getIntPref("middle_click");
8386
let item;
8487
if (pref === FIRETRAY_MIDDLE_CLICK_ACTIVATE_LAST) {
88+
log.debug("MiddleClick=Last");
8589
item = firetray.PopupMenu.menuItem.activateLast;
86-
firetray.PopupMenu.showItem(firetray.PopupMenu.menuItem.activateLast);
90+
// firetray.PopupMenu.showItem(firetray.PopupMenu.menuItem.activateLast);
8791
} else if (pref === FIRETRAY_MIDDLE_CLICK_SHOW_HIDE) {
92+
log.debug("MiddleClick=ShowHide");
8893
item = firetray.PopupMenu.menuItem.showHide;
89-
firetray.PopupMenu.hideItem(firetray.PopupMenu.menuItem.activateLast);
94+
// firetray.PopupMenu.hideItem(firetray.PopupMenu.menuItem.showHide);
9095
} else {
9196
log.error("Unknown pref value for 'middle_click': "+pref);
9297
return false;
@@ -156,16 +161,152 @@ firetray.Handler.setIconTooltip = function(toolTipStr) {
156161
//
157162
// sajan
158163
firetray.Handler.setIconText = function(text, color) {
159-
//log.error("NOT SUPPORTED: " + text);
160-
161-
if (text > 99) {
162-
text = "max";
163-
}
164-
165-
appind.app_indicator_set_icon_full(
166-
firetray.AppIndicator.indicator,
167-
"unread-" + text,
168-
firetray.Handler.app.name);
164+
log.debug("setIconText: " + text);
165+
166+
log.debug("setIconText, Name: " + firetray.StatusIcon.defaultNewMailIconName);
167+
168+
log.debug("setIconText, Temp: " + firetray.AppIndicator.tempfile);
169+
170+
let icon_theme = gtk.gtk_icon_theme_get_for_screen(gdk.gdk_screen_get_default());
171+
let arry = gobject.gchar.ptr.array()(2);
172+
arry[0] = gobject.gchar.array()(firetray.StatusIcon.defaultNewMailIconName);
173+
arry[1] = null;
174+
let icon_info = gtk.gtk_icon_theme_choose_icon(icon_theme, arry, 22, gtk.GTK_ICON_LOOKUP_FORCE_SIZE);
175+
let dest = gdk.gdk_pixbuf_copy(gtk.gtk_icon_info_load_icon(icon_info, null));
176+
177+
178+
179+
let w = gdk.gdk_pixbuf_get_width(dest);
180+
let h = gdk.gdk_pixbuf_get_height(dest);
181+
182+
// prepare colors/alpha
183+
/* FIXME: draw everything with cairo when dropping gtk2 support. Use
184+
gdk_pixbuf_get_from_surface(). */
185+
if (firetray.Handler.app.widgetTk == "gtk2") {
186+
var colorMap = gdk.gdk_screen_get_system_colormap(gdk.gdk_screen_get_default());
187+
var visual = gdk.gdk_colormap_get_visual(colorMap);
188+
var visualDepth = visual.contents.depth;
189+
log.debug("colorMap="+colorMap+" visual="+visual+" visualDepth="+visualDepth);
190+
}
191+
let fore = new gdk.GdkColor;
192+
fore.pixel = fore.red = fore.green = fore.blue = 0;
193+
let back = new gdk.GdkColor;
194+
back.pixel = back.red = back.green = back.blue = 0xFEFE;
195+
let alpha = new gdk.GdkColor;
196+
alpha.pixel = alpha.red = alpha.green = alpha.blue = 0xFFFF;
197+
if (!fore || !alpha)
198+
log.warn("Undefined fore or alpha GdkColor");
199+
gdk.gdk_color_parse(color, fore.address());
200+
if(fore.red == alpha.red && fore.green == alpha.green && fore.blue == alpha.blue) {
201+
alpha.red=0; // make sure alpha is different from fore
202+
}
203+
if (firetray.Handler.app.widgetTk == "gtk2") {
204+
gdk.gdk_colormap_alloc_color(colorMap, fore.address(), true, true);
205+
gdk.gdk_colormap_alloc_color(colorMap, back.address(), true, true);
206+
gdk.gdk_colormap_alloc_color(colorMap, alpha.address(), true, true);
207+
}
208+
209+
// build text rectangle
210+
let cr;
211+
if (firetray.Handler.app.widgetTk == "gtk2") {
212+
var pm = gdk.gdk_pixmap_new(null, w, h, visualDepth);
213+
var pmDrawable = ctypes.cast(pm, gdk.GdkDrawable.ptr);
214+
cr = gdk.gdk_cairo_create(pmDrawable);
215+
} else {
216+
// FIXME: gtk3 text position is incorrect.
217+
var surface = cairo.cairo_image_surface_create(cairo.CAIRO_FORMAT_ARGB32, w, h);
218+
cr = cairo.cairo_create(surface);
219+
}
220+
221+
gdk.gdk_cairo_set_source_color(cr, alpha.address());
222+
cairo.cairo_rectangle(cr, 0, 0, w, h);
223+
cairo.cairo_set_source_rgb(cr, 1, 1, 1);
224+
cairo.cairo_fill(cr);
225+
226+
// gdk.gdk_cairo_set_source_color(cr, back.address());
227+
// cairo.cairo_rectangle(cr, 0, 0, w/2, h/2);
228+
// cairo.cairo_fill(cr);
229+
230+
// build text
231+
let scratch = gtk.gtk_window_new(gtk.GTK_WINDOW_TOPLEVEL);
232+
let layout = gtk.gtk_widget_create_pango_layout(scratch, null);
233+
gtk.gtk_widget_destroy(scratch);
234+
let fnt = pango.pango_font_description_from_string("Sans 32");
235+
pango.pango_font_description_set_weight(fnt, pango.PANGO_WEIGHT_SEMIBOLD);
236+
pango.pango_layout_set_spacing(layout, 0);
237+
pango.pango_layout_set_font_description(layout, fnt);
238+
log.debug("layout="+layout);
239+
log.debug("text="+text);
240+
pango.pango_layout_set_text(layout, text,-1);
241+
let tw = new ctypes.int;
242+
let th = new ctypes.int;
243+
let sz;
244+
let border = 4;
245+
pango.pango_layout_get_pixel_size(layout, tw.address(), th.address());
246+
log.debug("tw="+tw.value+" th="+th.value);
247+
// fit text to the icon by decreasing font size
248+
while ( tw.value > (w - border) || th.value > (h - border) ) {
249+
sz = pango.pango_font_description_get_size(fnt);
250+
if (sz < firetray.AppIndicator.MIN_FONT_SIZE) {
251+
sz = firetray.AppIndicator.MIN_FONT_SIZE;
252+
break;
253+
}
254+
sz -= pango.PANGO_SCALE;
255+
pango.pango_font_description_set_size(fnt, sz);
256+
pango.pango_layout_set_font_description(layout, fnt);
257+
pango.pango_layout_get_pixel_size(layout, tw.address(), th.address());
258+
}
259+
log.debug("tw="+tw.value+" th="+th.value+" sz="+sz);
260+
pango.pango_font_description_free(fnt);
261+
// center text
262+
let px = (w-tw.value)/2;
263+
let py = (h-th.value)/2;
264+
log.debug("px="+px+" py="+py);
265+
266+
// draw text on pixmap
267+
gdk.gdk_cairo_set_source_color(cr, fore.address());
268+
cairo.cairo_move_to(cr, px, py);
269+
pangocairo.pango_cairo_show_layout(cr, layout);
270+
cairo.cairo_destroy(cr);
271+
gobject.g_object_unref(layout);
272+
273+
let buf = null;
274+
if (firetray.Handler.app.widgetTk == "gtk2") {
275+
buf = gdk.gdk_pixbuf_get_from_drawable(null, pmDrawable, null, 0, 0, 0, 0, w, h);
276+
gobject.g_object_unref(pm);
277+
}
278+
else {
279+
buf = gdk.gdk_pixbuf_get_from_surface(surface, 0, 0, w, h);
280+
cairo.cairo_surface_destroy(surface);
281+
}
282+
log.debug("alpha="+alpha);
283+
let alphaRed = gobject.guint16(alpha.red);
284+
let alphaRed_guchar = ctypes.cast(alphaRed, gobject.guchar);
285+
let alphaGreen = gobject.guint16(alpha.green);
286+
let alphaGreen_guchar = ctypes.cast(alphaGreen, gobject.guchar);
287+
let alphaBlue = gobject.guint16(alpha.blue);
288+
let alphaBlue_guchar = ctypes.cast(alphaBlue, gobject.guchar);
289+
let bufAlpha = gdk.gdk_pixbuf_add_alpha(buf, true, alphaRed_guchar, alphaGreen_guchar, alphaBlue_guchar);
290+
gobject.g_object_unref(buf);
291+
292+
// merge the rendered text on top
293+
gdk.gdk_pixbuf_composite(bufAlpha,dest,0,0,w,h,0,0,1,1,gdk.GDK_INTERP_BILINEAR,255);
294+
gobject.g_object_unref(bufAlpha);
295+
296+
// Workaround
297+
gdk.gdk_pixbuf_save(dest, firetray.AppIndicator.tempfile, "png", null, null);
298+
299+
appind.app_indicator_set_icon_full(
300+
firetray.AppIndicator.indicator,
301+
firetray.StatusIcon.defaultNewMailIconName,
302+
firetray.Handler.app.name);
303+
304+
appind.app_indicator_set_icon_full(
305+
firetray.AppIndicator.indicator,
306+
firetray.AppIndicator.tempfile,
307+
firetray.Handler.app.name);
308+
309+
return true;
169310
};
170311

171312
firetray.Handler.setIconVisibility = function(visible) {

0 commit comments

Comments
 (0)