diff --git a/src/chrome/skin/winnt/blank-icon.bmp b/src/chrome/skin/winnt/blank-icon.bmp new file mode 100644 index 0000000..ce34799 Binary files /dev/null and b/src/chrome/skin/winnt/blank-icon.bmp differ diff --git a/src/modules/FiretrayMessaging.jsm b/src/modules/FiretrayMessaging.jsm index a8adfaf..6b06e89 100644 --- a/src/modules/FiretrayMessaging.jsm +++ b/src/modules/FiretrayMessaging.jsm @@ -206,6 +206,7 @@ firetray.Messaging = { }, updateIcon: function(msgCount) { + log.debug("updateIcon"); if ("undefined" === typeof(msgCount)) msgCount = this.currentMsgCount; let localizedTooltip; @@ -227,6 +228,7 @@ firetray.Messaging = { } else if (msgCount > 0) { let prefMailNotification = firetray.Utils.prefService.getIntPref('mail_notification_type'); + log.debug("msgCount prefMailNotification="+prefMailNotification); switch (prefMailNotification) { case FIRETRAY_NOTIFICATION_MESSAGE_COUNT: let prefIconTextColor = firetray.Utils.prefService.getCharPref("icon_text_color"); diff --git a/src/modules/ctypes/winnt/gdi32.jsm b/src/modules/ctypes/winnt/gdi32.jsm new file mode 100644 index 0000000..82b8fd0 --- /dev/null +++ b/src/modules/ctypes/winnt/gdi32.jsm @@ -0,0 +1,93 @@ +var EXPORTED_SYMBOLS = [ "gdi32" ]; + +const GDI32_LIBNAME = "gdi32"; +const GDI32_ABIS = [ "dll" ]; + +const Cu = Components.utils; + +Cu.import("resource://gre/modules/ctypes.jsm"); +Cu.import("resource://firetray/ctypes/ctypes-utils.jsm"); +Cu.import("resource://firetray/ctypes/winnt/win32.jsm"); + +function gdi32_defines(lib) { + + this.BITMAP = ctypes.StructType("BITMAP", [ + { "bmType": win32.LONG }, + { "bmWidth": win32.LONG }, + { "bmHeight": win32.LONG }, + { "bmWidthBytes": win32.LONG }, + { "bmPlanes": win32.WORD }, + { "bmBitsPixel": win32.WORD }, + { "bmBits": win32.LPVOID } + ]); + this.PBITMAP = this.BITMAP.ptr; + + lib.lazy_bind("CreateCompatibleDC", win32.HDC, win32.HDC); + lib.lazy_bind("DeleteDC", win32.BOOL, win32.HDC); + lib.lazy_bind("CreateCompatibleBitmap", win32.HBITMAP, win32.HDC, ctypes.int, ctypes.int); + lib.lazy_bind("SelectObject", win32.HGDIOBJ, win32.HDC, win32.HGDIOBJ); + lib.lazy_bind("DeleteObject", win32.BOOL, win32.HGDIOBJ); + lib.lazy_bind("PatBlt", win32.BOOL, win32.HDC, ctypes.int, ctypes.int, ctypes.int, ctypes.int, win32.DWORD); + this.BLACKNESS = win32.DWORD(0x00000042); /* dest = BLACK */ + this.WHITENESS = win32.DWORD(0x00FF0062); /* dest = WHITE */ + lib.lazy_bind("CreateFontW", win32.HFONT, ctypes.int, ctypes.int, ctypes.int, ctypes.int, ctypes.int, win32.DWORD, win32.DWORD, win32.DWORD, win32.DWORD, win32.DWORD, win32.DWORD, win32.DWORD, win32.DWORD, win32.LPCWSTR); + this.FW_DONTCARE = 0; + this.FW_THIN = 100; + this.FW_EXTRALIGHT = 200; + this.FW_LIGHT = 300; + this.FW_NORMAL = 400; + this.FW_MEDIUM = 500; + this.FW_SEMIBOLD = 600; + this.FW_BOLD = 700; + this.FW_EXTRABOLD = 800; + this.FW_HEAVY = 900; + this.FF_DONTCARE = (0<<4); /* Don't care or don't know. */ + this.FF_ROMAN = (1<<4); /* Variable stroke width, serifed. Times Roman, Century Schoolbook, etc. */ + this.FF_SWISS = (2<<4); /* Variable stroke width, sans-serifed. Helvetica, Swiss, etc. */ + this.FF_MODERN = (3<<4); /* Constant stroke width, serifed or sans-serifed. Pica, Elite, Courier, etc. */ + this.FF_SCRIPT = (4<<4); /* Cursive, etc. */ + this.FF_DECORATIVE = (5<<4); /* Old English, etc. */ + this.DEFAULT_PITCH = 0; + this.FIXED_PITCH = 1; + this.VARIABLE_PITCH = 2; + this.MONO_FONT = 8; + this.ANSI_CHARSET = 0; + this.DEFAULT_CHARSET = 1; + this.SYMBOL_CHARSET = 2; + this.SHIFTJIS_CHARSET = 128; + this.HANGEUL_CHARSET = 129; + this.HANGUL_CHARSET = 129; + this.GB2312_CHARSET = 134; + this.CHINESEBIG5_CHARSET = 136; + this.OEM_CHARSET = 255; + this.JOHAB_CHARSET = 130; + this.HEBREW_CHARSET = 177; + this.ARABIC_CHARSET = 178; + this.GREEK_CHARSET = 161; + this.TURKISH_CHARSET = 162; + this.VIETNAMESE_CHARSET = 163; + this.THAI_CHARSET = 222; + this.EASTEUROPE_CHARSET = 238; + this.RUSSIAN_CHARSET = 204; + lib.lazy_bind("SetTextColor", win32.COLORREF, win32.HDC, win32.COLORREF); + lib.lazy_bind("SetBkMode", ctypes.int, win32.HDC, ctypes.int); + this.TRANSPARENT = 1; + this.OPAQUE = 2; + this.BKMODE_LAST = 2; + + lib.lazy_bind("TextOutW", win32.BOOL, win32.HDC, ctypes.int, ctypes.int, win32.LPCTSTR, ctypes.int); + + lib.lazy_bind("GetTextAlign", win32.UINT, win32.HDC); + lib.lazy_bind("SetTextAlign", win32.UINT, win32.HDC, win32.UINT); + this.TA_LEFT = 0; + this.TA_RIGHT = 2; + this.TA_CENTER = 6; + this.TA_TOP = 0; + this.TA_BOTTOM = 8; + this.TA_BASELINE = 24; + this.TA_RTLREADING = 256; + this.TA_MASK =(this.TA_BASELINE+this.TA_CENTER+this.TA_UPDATECP+this.TA_RTLREADING); + +} + +new ctypes_library(GDI32_LIBNAME, GDI32_ABIS, gdi32_defines, this); diff --git a/src/modules/ctypes/winnt/user32.jsm b/src/modules/ctypes/winnt/user32.jsm index 8b2abbf..6a0702e 100644 --- a/src/modules/ctypes/winnt/user32.jsm +++ b/src/modules/ctypes/winnt/user32.jsm @@ -51,6 +51,9 @@ function user32_defines(lib) { this.IDI_EXCLAMATION = win32.MAKEINTRESOURCE(32515); this.IDI_ASTERISK = win32.MAKEINTRESOURCE(32516); lib.lazy_bind("LoadImageW", win32.HANDLE, win32.HINSTANCE, win32.LPCTSTR, win32.UINT, ctypes.int, ctypes.int, win32.UINT); + this.IMAGE_BITMAP = 0; + this.IMAGE_ICON = 1; + this.IMAGE_CURSOR = 2; this.LR_CREATEDIBSECTION = 0x00002000; this.LR_DEFAULTCOLOR = 0x00000000; this.LR_DEFAULTSIZE = 0x00000040; @@ -241,6 +244,10 @@ function user32_defines(lib) { this.SPI_GETFOREGROUNDFLASHCOUNT = 0x2004; lib.lazy_bind("GetForegroundWindow", win32.HWND); + lib.lazy_bind("GetDC", win32.HDC, win32.HWND); + lib.lazy_bind("ReleaseDC", ctypes.int, win32.HWND, win32.HDC); + lib.lazy_bind("CreateIconIndirect", win32.HICON, win32.PICONINFO); + } new ctypes_library(USER32_LIBNAME, USER32_ABIS, user32_defines, this); diff --git a/src/modules/ctypes/winnt/win32.jsm b/src/modules/ctypes/winnt/win32.jsm index 05f6234..ecb7266 100644 --- a/src/modules/ctypes/winnt/win32.jsm +++ b/src/modules/ctypes/winnt/win32.jsm @@ -41,6 +41,10 @@ var win32 = new function() { this.HBRUSH = this.HICON; this.HCURSOR = this.HANDLE; this.HHOOK = this.HANDLE; + this.HDC = this.HANDLE; + this.HGDIOBJ = this.HANDLE; + this.HBITMAP = this.HANDLE; + this.HFONT = this.HANDLE; this.TCHAR = ctypes.jschar, // Mozilla compiled with UNICODE/_UNICODE macros and wchar_t = jschar this.LPSTR = ctypes.char.ptr; this.LPCSTR = ctypes.char.ptr; @@ -52,6 +56,7 @@ var win32 = new function() { this.WPARAM = this.UINT_PTR; this.LPARAM = this.LONG_PTR; this.FARPROC = ctypes.voidptr_t; // typedef INT_PTR (FAR WINAPI *FARPROC)(); + this.COLORREF = this.DWORD; // 0x00bbggrr this.GUID = ctypes.StructType("GUID", [ { "Data1": ctypes.unsigned_long }, @@ -97,10 +102,18 @@ var win32 = new function() { this.WM_MOUSELAST = 0x020D; this.WM_MOUSELAST = 0x020A; + this.ICONINFO = ctypes.StructType("ICONINFO", [ + { "fIcon": this.BOOL }, + { "xHotspot": this.DWORD }, + { "yHotspot": this.DWORD }, + { "hbmMask": this.HBITMAP }, + { "hbmColor": this.HBITMAP } + ]); + this.PICONINFO = this.ICONINFO.ptr; }; // ShellAPI.h let nin_select = win32.WM_USER + 0; -win32.NIN_SELECT = nin_select; -win32.NINF_KEY = 0x1; +win32.NIN_SELECT = nin_select; +win32.NINF_KEY = 0x1; win32.NIN_KEYSELECT = (win32.NIN_SELECT | win32.NINF_KEY); diff --git a/src/modules/winnt/FiretrayStatusIcon.jsm b/src/modules/winnt/FiretrayStatusIcon.jsm index 1a8f5fa..8ae1d6a 100644 --- a/src/modules/winnt/FiretrayStatusIcon.jsm +++ b/src/modules/winnt/FiretrayStatusIcon.jsm @@ -14,6 +14,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/ctypes.jsm"); Cu.import("resource://firetray/ctypes/ctypesMap.jsm"); Cu.import("resource://firetray/ctypes/winnt/win32.jsm"); +Cu.import("resource://firetray/ctypes/winnt/gdi32.jsm"); Cu.import("resource://firetray/ctypes/winnt/kernel32.jsm"); Cu.import("resource://firetray/ctypes/winnt/shell32.jsm"); Cu.import("resource://firetray/ctypes/winnt/user32.jsm"); @@ -27,6 +28,7 @@ if ("undefined" == typeof(firetray.Handler)) log.error("This module MUST be imported from/after FiretrayHandler !"); FIRETRAY_ICON_CHROME_PATHS = { + 'blank-icon': "chrome://firetray/skin/winnt/blank-icon.bmp", 'mail-unread': "chrome://firetray/skin/winnt/mail-unread.ico", }; @@ -36,11 +38,12 @@ firetray.StatusIcon = { notifyIconData: null, hwndProxy: null, icons: null, + bitmaps: null, WNDCLASS_NAME: "FireTrayHiddenWindowClass", WNDCLASS_ATOM: null, init: function() { - this.loadIcons(); + this.loadImages(); // this.defineIconNames(); // FIXME: linux-only this.create(); @@ -52,7 +55,7 @@ firetray.StatusIcon = { log.debug("Disabling StatusIcon"); this.destroy(); - this.destroyIcons(); + this.destroyImages(); this.initialized = false; return true; @@ -74,8 +77,9 @@ firetray.StatusIcon = { this.defaultNewMailIconName = "mail-unread"; }, - loadIcons: function() { + loadImages: function() { this.icons = new ctypesMap(win32.HICON); + this.bitmaps = new ctypesMap(win32.HBITMAP); // the Mozilla hidden window has the default Mozilla icon let hwnd_hidden_moz = user32.FindWindowW("MozillaHiddenWindowClass", null); @@ -84,39 +88,39 @@ firetray.StatusIcon = { /* we'll take the first icon in the .ico file. To get the icon count in the file, pass ctypes.cast(ctypes.int(-1), win32.UINT); */ - for (let ico_name in FIRETRAY_ICON_CHROME_PATHS) { - let path = firetray.Utils.chromeToPath(FIRETRAY_ICON_CHROME_PATHS[ico_name]); - let hicon = shell32.ExtractIconW(null, path, 0); - // ERROR_INVALID_HANDLE(6) ignored (_Reserved_ HINSTANCE hInst ?) - this.icons.insert(ico_name, hicon); - log.debug("icon '"+ico_name+"'="+this.icons.get(ico_name)+" winLastError="+ctypes.winLastError); + for (let imgName in FIRETRAY_ICON_CHROME_PATHS) { + let path = firetray.Utils.chromeToPath(FIRETRAY_ICON_CHROME_PATHS[imgName]); + let imgType = path.substr(-3, 3); + let imgTypeDict = { + ico: { win_t: win32.HICON, load_const: user32.IMAGE_ICON, map: this.icons }, + bmp: { win_t: win32.HBITMAP, load_const: user32.IMAGE_BITMAP, map: this.bitmaps } + }; + if (!(imgType in imgTypeDict)) { + throw Error("Unrecognized type '"+imgType+"'"); + } + let imgTypeRec = imgTypeDict[imgType]; + let himg = ctypes.cast( + user32.LoadImageW(null, path, imgTypeRec['load_const'], 0, 0, + user32.LR_LOADFROMFILE|user32.LR_SHARED), + imgTypeRec['win_t']); + if (himg.isNull()) { + log.error("Could not load '"+imgName+"'="+himg+" winLastError="+ctypes.winLastError); + continue; + } + imgTypeRec['map'].insert(imgName, himg); } }, - destroyIcons: function() { - let success = true, errors = []; - let keys = this.icons.keys; - - // 'app' must not get DestroyIcon'd - var idx_app = keys.indexOf('app'); - if (idx_app > -1) keys.splice(idx_app, 1); - - for (let i=0, len=keys.length; i