* fix re-creation of text icon

* fix: unload gdi32.dll
This commit is contained in:
foudfou 2014-02-16 20:14:53 +01:00
parent 70f0c0a8e0
commit c52b9da609
6 changed files with 152 additions and 15 deletions

View File

@ -123,7 +123,7 @@ firetray.Handler = {
firetray.Chat.init();
} else {
let platforms = FIRETRAY_CHAT_SUPPORTED_OS.join(", ");
log.error("Only "+platforms+" platform(s) supported at this time. Firetray not loaded");
log.error("Only "+platforms+" platform(s) supported at this time. Chat not loaded");
}
}
@ -516,6 +516,9 @@ firetray.PrefListener = new PrefListener(
firetray.Handler.setIconImageDefault();
}
break;
case 'mail_notification_type':
firetray.Messaging.updateIcon();
break;
case 'new_mail_icon_names':
firetray.StatusIcon.loadThemedIcons();
case 'only_favorite_folders':

View File

@ -309,7 +309,10 @@ firetray.js = {
result = result.concat(Object.getOwnPropertyNames(objectToInspect));
}
return result;
}
},
floatToInt: function(nb) { return nb >> 0; } // bitwise ops on signed int
};
// http://stackoverflow.com/questions/18912/how-to-find-keys-of-a-hash

View File

@ -24,7 +24,42 @@ function gdi32_defines(lib) {
lib.lazy_bind("CreateCompatibleDC", win32.HDC, win32.HDC);
lib.lazy_bind("DeleteDC", win32.BOOL, win32.HDC);
lib.lazy_bind("BitBlt", win32.BOOL, win32.HDC, ctypes.int, ctypes.int, ctypes.int, ctypes.int, win32.HDC, ctypes.int, ctypes.int, win32.DWORD);
this.SRCCOPY = win32.DWORD(0x00CC0020); /* dest = source */
this.SRCPAINT = win32.DWORD(0x00EE0086); /* dest = source OR dest */
this.SRCAND = win32.DWORD(0x008800C6); /* dest = source AND dest */
this.SRCINVERT = win32.DWORD(0x00660046); /* dest = source XOR dest */
this.SRCERASE = win32.DWORD(0x00440328); /* dest = source AND (NOT dest ) */
this.NOTSRCCOPY = win32.DWORD(0x00330008); /* dest = (NOT source) */
this.NOTSRCERASE = win32.DWORD(0x001100A6); /* dest = (NOT src) AND (NOT dest) */
this.MERGECOPY = win32.DWORD(0x00C000CA); /* dest = (source AND pattern) */
this.MERGEPAINT = win32.DWORD(0x00BB0226); /* dest = (NOT source) OR dest */
this.PATCOPY = win32.DWORD(0x00F00021); /* dest = pattern */
this.PATPAINT = win32.DWORD(0x00FB0A09); /* dest = DPSnoo */
this.PATINVERT = win32.DWORD(0x005A0049); /* dest = pattern XOR dest */
this.DSTINVERT = win32.DWORD(0x00550009); /* dest = (NOT dest) */
this.BLACKNESS = win32.DWORD(0x00000042); /* dest = BLACK */
this.WHITENESS = win32.DWORD(0x00FF0062); /* dest = WHITE */
this.NOMIRRORBITMAP = win32.DWORD(0x80000000); /* Do not Mirror the bitmap in this call */
this.CAPTUREBLT = win32.DWORD(0x40000000); /* Include layered windows */
lib.lazy_bind("CreateCompatibleBitmap", win32.HBITMAP, win32.HDC, ctypes.int, ctypes.int);
lib.lazy_bind("CreateBitmapIndirect", win32.HBITMAP, win32.BITMAP.ptr);
lib.lazy_bind("GetObjectW", ctypes.int, win32.HGDIOBJ, ctypes.int, win32.LPVOID);
lib.lazy_bind("GetCurrentObject", win32.HGDIOBJ, win32.HDC, win32.UINT);
this.OBJ_PEN = 1;
this.OBJ_BRUSH = 2;
this.OBJ_DC = 3;
this.OBJ_METADC = 4;
this.OBJ_PAL = 5;
this.OBJ_FONT = 6;
this.OBJ_BITMAP = 7;
this.OBJ_REGION = 8;
this.OBJ_METAFILE = 9;
this.OBJ_MEMDC = 10;
this.OBJ_EXTPEN = 11;
this.OBJ_ENHMETADC = 12;
this.OBJ_ENHMETAFILE = 13;
this.OBJ_COLORSPACE = 14;
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);
@ -77,6 +112,13 @@ function gdi32_defines(lib) {
lib.lazy_bind("TextOutW", win32.BOOL, win32.HDC, ctypes.int, ctypes.int, win32.LPCTSTR, ctypes.int);
this.SIZE = ctypes.StructType("SIZE", [
{ "cx": win32.LONG },
{ "cy": win32.LONG }
]);
this.LPSIZE = this.SIZE.ptr;
lib.lazy_bind("GetTextExtentPoint32W", win32.BOOL, win32.HDC, win32.LPCTSTR, ctypes.int, this.LPSIZE);
lib.lazy_bind("GetTextAlign", win32.UINT, win32.HDC);
lib.lazy_bind("SetTextAlign", win32.UINT, win32.HDC, win32.UINT);
this.TA_LEFT = 0;
@ -88,6 +130,33 @@ function gdi32_defines(lib) {
this.TA_RTLREADING = 256;
this.TA_MASK =(this.TA_BASELINE+this.TA_CENTER+this.TA_UPDATECP+this.TA_RTLREADING);
this.BITMAPINFOHEADER = ctypes.StructType("BITMAPINFOHEADER", [
{ "biSize": win32.DWORD },
{ "biWidth": win32.LONG },
{ "biHeight": win32.LONG },
{ "biPlanes": win32.WORD },
{ "biBitCount": win32.WORD },
{ "biCompression": win32.DWORD },
{ "biSizeImage": win32.DWORD },
{ "biXPelsPerMeter": win32.LONG },
{ "biYPelsPerMeter": win32.LONG },
{ "biClrUsed": win32.DWORD },
{ "biClrImportant": win32.DWORD }
]);
this.PBITMAPINFOHEADER = this.BITMAPINFOHEADER.ptr;
this.RGBQUAD = ctypes.StructType("RGBQUAD", [
{ "rgbBlue": win32.BYTE },
{ "rgbGreen": win32.BYTE },
{ "rgbRed": win32.BYTE },
{ "rgbReserved": win32.BYTE }
]);
this.BITMAPINFO = ctypes.StructType("BITMAPINFO", [
{ "bmiHeader": this.BITMAPINFOHEADER },
{ "bmiColors": this.RGBQUAD.array(1) }
]);
this.PBITMAPINFO = this.BITMAPINFO.ptr;
lib.lazy_bind("SetDIBits", ctypes.int, win32.HDC, win32.HBITMAP, win32.UINT, win32.UINT, ctypes.voidptr_t, this.BITMAPINFO.ptr, win32.UINT);
}
new ctypes_library(GDI32_LIBNAME, GDI32_ABIS, gdi32_defines, this);

View File

@ -50,6 +50,7 @@ function user32_defines(lib) {
this.IDI_QUESTION = win32.MAKEINTRESOURCE(32514);
this.IDI_EXCLAMATION = win32.MAKEINTRESOURCE(32515);
this.IDI_ASTERISK = win32.MAKEINTRESOURCE(32516);
lib.lazy_bind("DestroyIcon", win32.BOOL, win32.HICON);
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;
@ -63,7 +64,7 @@ function user32_defines(lib) {
this.LR_MONOCHROME = 0x00000001;
this.LR_SHARED = 0x00008000;
this.LR_VGACOLOR = 0x00000080;
lib.lazy_bind("DestroyIcon", win32.BOOL, win32.HICON);
lib.lazy_bind("CopyImage", win32.HANDLE, win32.HANDLE, win32.UINT, ctypes.int, ctypes.int, win32.UINT);
lib.lazy_bind("GetPropW", win32.HANDLE, win32.HWND, win32.LPCTSTR);
lib.lazy_bind("SetPropW", win32.BOOL, win32.HWND, win32.LPCTSTR, win32.HANDLE);
@ -247,6 +248,23 @@ function user32_defines(lib) {
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);
lib.lazy_bind("GetClientRect", win32.BOOL, win32.HWND, win32.PRECT);
lib.lazy_bind("DrawTextW", ctypes.int, win32.HDC, win32.LPCTSTR, ctypes.int, win32.PRECT, win32.UINT);
this.DT_TOP = 0x00000000;
this.DT_LEFT = 0x00000000;
this.DT_CENTER = 0x00000001;
this.DT_RIGHT = 0x00000002;
this.DT_VCENTER = 0x00000004;
this.DT_BOTTOM = 0x00000008;
this.DT_WORDBREAK = 0x00000010;
this.DT_SINGLELINE = 0x00000020;
this.DT_EXPANDTABS = 0x00000040;
this.DT_TABSTOP = 0x00000080;
this.DT_NOCLIP = 0x00000100;
this.DT_EXTERNALLEADING = 0x00000200;
this.DT_CALCRECT = 0x00000400;
this.DT_NOPREFIX = 0x00000800;
this.DT_INTERNAL = 0x00001000;
}

View File

@ -102,6 +102,16 @@ var win32 = new function() {
this.WM_MOUSELAST = 0x020D;
this.WM_MOUSELAST = 0x020A;
this.BITMAP = ctypes.StructType("BITMAP", [
{ "bmType": this.LONG },
{ "bmWidth": this.LONG },
{ "bmHeight": this.LONG },
{ "bmWidthBytes": this.LONG },
{ "bmPlanes": this.WORD },
{ "bmBitsPixel": this.WORD },
{ "bmBits": this.LPVOID }
]);
this.ICONINFO = ctypes.StructType("ICONINFO", [
{ "fIcon": this.BOOL },
{ "xHotspot": this.DWORD },
@ -110,6 +120,15 @@ var win32 = new function() {
{ "hbmColor": this.HBITMAP }
]);
this.PICONINFO = this.ICONINFO.ptr;
this.RECT = ctypes.StructType("RECT", [
{ "left": this.LONG },
{ "top": this.LONG },
{ "right": this.LONG },
{ "bottom": this.LONG }
]);
this.PRECT = this.RECT.ptr;
};
// ShellAPI.h

View File

@ -20,7 +20,7 @@ Cu.import("resource://firetray/ctypes/winnt/shell32.jsm");
Cu.import("resource://firetray/ctypes/winnt/user32.jsm");
Cu.import("resource://firetray/winnt/FiretrayWin32.jsm");
Cu.import("resource://firetray/commons.js");
firetray.Handler.subscribeLibsForClosing([kernel32, shell32, user32]);
firetray.Handler.subscribeLibsForClosing([gdi32, kernel32, shell32, user32]);
let log = firetray.Logging.getLogger("firetray.StatusIcon");
@ -194,9 +194,6 @@ firetray.StatusIcon = {
break;
case win32.WM_RBUTTONUP:
log.debug("WM_RBUTTONUP");
let hicon = firetray.StatusIcon.createSmallIcon(hWnd, "100", "#990000");
log.debug("%%%%%%%%%% ICON="+hicon);
firetray.StatusIcon.setImageFromIcon(hicon);
break;
case win32.WM_CONTEXTMENU:
log.debug("WM_CONTEXTMENU");
@ -269,29 +266,50 @@ firetray.StatusIcon = {
},
// http://stackoverflow.com/questions/457050/how-to-display-text-in-system-tray-icon-with-win32-api
createSmallIcon: function(hWnd, text, color) {
createTextIcon: function(hWnd, text, color) {
log.debug("createTextIcon hWnd="+hWnd+" text="+text+" color="+color);
let blank = this.bitmaps.get('blank-icon');
let bitmap = new win32.BITMAP();
let err = gdi32.GetObjectW(blank, win32.BITMAP.size, bitmap.address()); // get bitmap info
let width = bitmap.bmWidth, height = bitmap.bmHeight;
let hdc = user32.GetDC(hWnd); // get device context (DC) for hWnd
let hdcMem = gdi32.CreateCompatibleDC(hdc); // creates a memory device context (DC) compatible with hdc (need a bitmap)
let hBitmap = this.bitmaps.get('blank-icon');
let hBitmapMask = gdi32.CreateCompatibleBitmap(hdc, 32, 32);
let hBitmap = user32.CopyImage(blank, user32.IMAGE_BITMAP, width, height, 0);
let hBitmapMask = gdi32.CreateCompatibleBitmap(hdc, width, height);
user32.ReleaseDC(hWnd, hdc);
let hOldBitmap = ctypes.cast(gdi32.SelectObject(hdcMem, hBitmap), // replace bitmap in hdcMem by hBitmap
win32.HBITMAP);
let hBitmapOrig = gdi32.SelectObject(hdcMem, hBitmap);
// gdi32.PatBlt(hdcMem, 0, 0, 16, 16, gdi32.BLACKNESS); // paint black rectangle
// http://forums.codeguru.com/showthread.php?379565-Windows-SDK-GDI-How-do-I-choose-a-font-size-to-exactly-fit-a-string-in-a
let nHeight = 32, fnWeight = gdi32.FW_BOLD;
let hFont = gdi32.CreateFontW(nHeight, 0, 0, 0, fnWeight, 0, 0, 0,
gdi32.ANSI_CHARSET, 0, 0, 0, gdi32.FF_SWISS, "Sans"); // get font
hFont = ctypes.cast(gdi32.SelectObject(hdcMem, hFont), win32.HFONT); // replace font in bitmap by hFont
gdi32.SetTextColor(hdcMem, win32.COLORREF(this.cssColorToCOLORREF(color)));
// gdi32.SetBkMode(hdcMem, gdi32.TRANSPARENT); // VERY IMPORTANT
gdi32.SetBkMode(hdcMem, gdi32.TRANSPARENT); // VERY IMPORTANT
// gdi32.SetTextAlign(hdcMem, gdi32.GetTextAlign(hdcMem) & (~gdi32.TA_CENTER));
// gdi32.SetTextAlign(hdcMem, gdi32.TA_CENTER);
log.debug(" ___ALIGN=(winLastError="+ctypes.winLastError+") "+gdi32.GetTextAlign(hdcMem));
gdi32.TextOutW(hdcMem, 0, 0, text, text.length);
gdi32.SelectObject(hdcMem, hOldBitmap); // always replace new hBitmap with original one
let size = new gdi32.SIZE();
// GetTextExtentPoint32 is known as more reliable than DrawText(DT_CALCRECT)
gdi32.GetTextExtentPoint32W(hdcMem, text, text.length, size.address());
let nWidth = size.cx;
log.debug(" WIDTH="+nWidth);
// let rect = new win32.RECT();
// let height = user32.DrawTextW(hdcMem, text, text.length, rect.address(), user32.DT_SINGLELINE | user32.DT_CENTER | user32.DT_VCENTER | user32.DT_CALCRECT);
// log.debug(" HEIGHT="+height+", rect="+rect);
let nXStart = firetray.js.floatToInt((width - nWidth)/2),
nYStart = firetray.js.floatToInt((height - nHeight)/2);
gdi32.TextOutW(hdcMem, nXStart, nYStart, text, text.length); // ref point for alignment
gdi32.SelectObject(hdcMem, hBitmapOrig);
let iconInfo = win32.ICONINFO();
iconInfo.fIcon = true;
@ -301,6 +319,7 @@ firetray.StatusIcon = {
iconInfo.hbmColor = hBitmap;
let hIcon = user32.CreateIconIndirect(iconInfo.address());
log.debug(" CreateIconIndirect hIcon="+hIcon+" lastError="+ctypes.winLastError);
gdi32.DeleteObject(gdi32.SelectObject(hdcMem, hFont));
gdi32.DeleteDC(hdcMem);
@ -332,6 +351,12 @@ firetray.Handler.setIconTooltipDefault = function() {
};
firetray.Handler.setIconText = function(text, color) {
let hicon = firetray.StatusIcon.createTextIcon(
firetray.StatusIcon.hwndProxy, text, color);
log.debug("setIconText icon="+hicon);
if (hicon.isNull())
log.error("Could not create hicon");
firetray.StatusIcon.setImageFromIcon(hicon);
};
firetray.Handler.setIconVisibility = function(visible) {