1
0
mirror of https://github.com/moparisthebest/FireTray synced 2025-01-08 12:08:05 -05:00

* Handle custom icons on winnt.

* cleaning (createTextIcon() on winnt)

Harmonize custom icon handling (setIconImageDefault(), setIconImageCustom()).
Harmonize preference handling in prefwindow regardless if instantApply.
This commit is contained in:
foudfou 2014-03-22 01:15:19 +01:00
parent 9b2f2016aa
commit 2480ffbf85
8 changed files with 182 additions and 86 deletions

View File

@ -20,6 +20,7 @@ let log = firetray.Logging.getLogger("firetray.UIOptions");
var firetrayUIOptions = {
strings: null,
prefwindow: null,
listeners: {},
onLoad: function(e) {
log.debug("FULL FEATURED="+firetray.Handler.support['full_feat']);
@ -60,6 +61,7 @@ var firetrayUIOptions = {
onQuit: function(e) {
if (firetray.Handler.inMailApp) {
this.removeListeners();
this.removeMailAccountsObserver();
}
},
@ -232,10 +234,14 @@ var firetrayUIOptions = {
document.getElementById("ui_mail_notification_enabled").checked =
(firetray.Utils.prefService.getBoolPref("mail_notification_enabled"));
let radioMailNotify = document.getElementById("ui_radiogroup_mail_notification");
let mailNotifyRadio = document.getElementById("ui_radiogroup_mail_notification");
let prefMailNotificationType = firetray.Utils.prefService.getIntPref("mail_notification_type");
radioMailNotify.selectedIndex = this.radioGetIndexByValue(radioMailNotify, prefMailNotificationType);
mailNotifyRadio.selectedIndex = this.radioGetIndexByValue(mailNotifyRadio, prefMailNotificationType);
// this.disableNotificationMaybe(prefMailNotificationType); // done in toggleNotifications()
/* We need to ensure assigning selectedIndex in disableMessageCountMaybe()
does change the corresponding preference. */
let listener = {evt:'select', fn:firetrayUIOptions.userChangedValue, cap:true};
this.addListener(mailNotifyRadio, listener);
},
initMessageCountSettings: function() {
@ -261,6 +267,10 @@ var firetrayUIOptions = {
blinkStyle.selectedIndex = this.radioGetIndexByValue(blinkStyle, prefBlinkStyle);
},
userChangedValue: function(e) {
document.getElementById('pref-pane-mail').userChangedValue(e.originalTarget);
},
radioGetIndexByValue: function(radio, value) {
for (let i=0, len=radio.itemCount; i<len; ++i)
if (+radio.getItemAtIndex(i).value == value) return i;
@ -273,11 +283,9 @@ var firetrayUIOptions = {
updateNotificationSettings: function() {
log.debug("updateNotificationSettings");
let radioMailNotify = document.getElementById("ui_radiogroup_mail_notification");
let mailNotificationType = +radioMailNotify.getItemAtIndex(radioMailNotify.selectedIndex).value;
let mailNotifyRadio = document.getElementById("ui_radiogroup_mail_notification");
let mailNotificationType = +mailNotifyRadio.getItemAtIndex(mailNotifyRadio.selectedIndex).value;
this.disableNotificationMaybe(mailNotificationType);
firetray.Messaging.updateIcon();
},
updateMessageCountSettings: function() {
@ -311,10 +319,10 @@ var firetrayUIOptions = {
let notificationUnreadCount = document.getElementById("ui_mail_notification_unread_count");
this.disableElementsRecursive(notificationUnreadCount, msgCountTypeIsNewMessages);
let radioMailNotify = document.getElementById("ui_radiogroup_mail_notification");
let mailNotificationType = +radioMailNotify.getItemAtIndex(radioMailNotify.selectedIndex).value;
let mailNotifyRadio = document.getElementById("ui_radiogroup_mail_notification");
let mailNotificationType = +mailNotifyRadio.getItemAtIndex(mailNotifyRadio.selectedIndex).value;
if (msgCountTypeIsNewMessages && (mailNotificationType === FIRETRAY_NOTIFICATION_MESSAGE_COUNT)) {
radioMailNotify.selectedIndex = this.radioGetIndexByValue(radioMailNotify, FIRETRAY_NOTIFICATION_NEWMAIL_ICON);
mailNotifyRadio.selectedIndex = this.radioGetIndexByValue(mailNotifyRadio, FIRETRAY_NOTIFICATION_NEWMAIL_ICON);
if (firetray.Handler.support['full_feat']) {
let newMailIconNames = document.getElementById("newmail_icon_names");
this.disableNChildren(newMailIconNames, 2, false);
@ -385,6 +393,9 @@ var firetrayUIOptions = {
}};
filePicker.init(window, "Select Icon", nsIFilePicker.modeOpen); // FIXME: i18n
if (firetray.Handler.runtimeOS === "winnt")
filePicker.appendFilter("Icon", "*.bmp; *.ico"); // TODO: support more formats ?
else
filePicker.appendFilters(nsIFilePicker.filterImages);
filePicker.open(fpCallback);
},
@ -421,11 +432,10 @@ var firetrayUIOptions = {
}
}
// ...so we add onselect handler after the listbox is populated
excludedFoldersList.addEventListener(
'select', function(e) { // select also on unselect
document.getElementById('pref-pane-mail').userChangedValue(excludedFoldersList);
}, true);
// ...so we add onselect handler after the listbox is populated. 'select'
// also fired on unselect.
let listener = {evt:'select', fn:firetrayUIOptions.userChangedValue, cap:true};
this.addListener(excludedFoldersList, listener);
},
loadExcludedFoldersFlags: function(uiElt) {
@ -622,7 +632,21 @@ var firetrayUIOptions = {
}
let tree = document.getElementById("ui_tree_mail_accounts");
tree.addEventListener("keypress", that.onKeyPressTreeAccountsOrServerTypes, true);
let listener = {evt:'keypress', fn:firetrayUIOptions.onKeyPressTreeAccountsOrServerTypes, cap:true};
this.addListener(tree, listener);
},
addListener: function(elt, listenerData) {
elt.addEventListener(listenerData['evt'], listenerData['fn'], listenerData['cap']);
this.listeners[elt.id] = listenerData;
},
removeListeners: function() {
for (id in this.listeners) {
let listener = listeners[id];
document.getElementById(id)
.removeEventListener(listener['evt'], listener['fn'], listener['cap']);
}
},
onMutation: function(mutation) {

View File

@ -216,8 +216,7 @@
observes="broadcaster-notification-disabled" />
<hbox id="custom_mail_icon" align="center" flex="1" >
<textbox id="custom_mail_icon_filename" preference="pref_custom_mail_icon"
observes="broadcaster-notification-disabled"
onchange="firetray.Messaging.updateIcon();" flex="1" />
observes="broadcaster-notification-disabled" flex="1" />
<button id="custom_mail_icon_select" label="&choose;"
accesskey="&choose.accesskey;"
observes="broadcaster-notification-disabled"

View File

@ -328,7 +328,7 @@ firetray.Handler = {
// these get overridden in OS-specific Icon/Window handlers
setIconImageDefault: function() {},
setIconImageNewMail: function() {},
setIconImageFromFile: function(filename) {},
setIconImageCustom: function(prefname) {},
setIconText: function(text, color) {},
setIconTooltip: function(localizedMessage) {},
setIconTooltipDefault: function() {},
@ -515,7 +515,7 @@ firetray.Handler = {
firetray.PrefListener = new PrefListener(
FIRETRAY_PREF_BRANCH,
function(branch, name) {
log.debug('Pref changed: '+name);
log.debug('____Pref changed: '+name);
switch (name) {
case 'hides_single_window':
firetray.Handler.showHidePopupMenuItems();
@ -548,9 +548,11 @@ firetray.PrefListener = new PrefListener(
case 'app_mail_icon_names':
case 'app_browser_icon_names':
case 'app_default_icon_names':
case 'app_icon_type':
firetray.StatusIcon.loadThemedIcons();
firetray.StatusIcon.loadThemedIcons(); // linux
case 'app_icon_filename':
case 'custom_mail_icon':
firetray.StatusIcon.loadImageCustom(name);
case 'app_icon_type':
firetray.Handler.setIconImageDefault();
if (firetray.Handler.inMailApp)
firetray.Messaging.updateMsgCountWithCb();

View File

@ -238,8 +238,7 @@ firetray.Messaging = {
firetray.Handler.setIconImageNewMail();
break;
case FIRETRAY_NOTIFICATION_CUSTOM_ICON:
let prefCustomIconPath = firetray.Utils.prefService.getCharPref("custom_mail_icon");
firetray.Handler.setIconImageFromFile(prefCustomIconPath);
firetray.Handler.setIconImageCustom('custom_mail_icon');
break;
default:
log.error("Unknown notification mode: "+prefMailNotification);

View File

@ -111,6 +111,17 @@ function gdi32_defines(lib) {
this.ANTIALIASED_QUALITY = 4;
this.CLEARTYPE_QUALITY = 5;
this.CLEARTYPE_NATURAL_QUALITY = 6;
this.OUT_DEFAULT_PRECIS = 0;
this.OUT_STRING_PRECIS = 1;
this.OUT_CHARACTER_PRECIS = 2;
this.OUT_STROKE_PRECIS = 3;
this.OUT_TT_PRECIS = 4;
this.OUT_DEVICE_PRECIS = 5;
this.OUT_RASTER_PRECIS = 6;
this.OUT_TT_ONLY_PRECIS = 7;
this.OUT_OUTLINE_PRECIS = 8;
this.OUT_SCREEN_OUTLINE_PRECIS = 9;
this.OUT_PS_ONLY_PRECIS = 10;
lib.lazy_bind("GetTextFaceW", ctypes.int, win32.HDC, ctypes.int, win32.LPTSTR);
lib.lazy_bind("SetTextColor", win32.COLORREF, win32.HDC, win32.COLORREF);

View File

@ -97,6 +97,8 @@ firetray.StatusIcon = {
this.themedIconApp = this.initThemedIcon(appIconNames);
},
loadImageCustom: function() { }, // done in setIconImageCustom
getAppIconNames: function() {
let appIconNames = firetray.Utils.getArrayPref(this.prefAppIconNames);
appIconNames.push(this.defaultAppIconName);
@ -206,17 +208,18 @@ firetray.Handler.setIconImageDefault = function() {
let appIconType = firetray.Utils.prefService.getIntPref("app_icon_type");
if (appIconType === FIRETRAY_APPLICATION_ICON_TYPE_THEMED)
firetray.StatusIcon.setIconImageFromGIcon(firetray.StatusIcon.themedIconApp);
else if (appIconType === FIRETRAY_APPLICATION_ICON_TYPE_CUSTOM) {
let appIconFilename = firetray.Utils.prefService.getCharPref("app_icon_filename");
firetray.StatusIcon.setIconImageFromFile(appIconFilename);
}
else if (appIconType === FIRETRAY_APPLICATION_ICON_TYPE_CUSTOM)
firetray.Handler.setIconImageCustom("app_icon_filename");
};
firetray.Handler.setIconImageNewMail = function() {
firetray.StatusIcon.setIconImageFromGIcon(firetray.StatusIcon.themedIconNewMail);
};
firetray.Handler.setIconImageFromFile = firetray.StatusIcon.setIconImageFromFile;
firetray.Handler.setIconImageCustom = function(prefname) {
let prefCustomIconPath = firetray.Utils.prefService.getCharPref(prefname);
firetray.StatusIcon.setIconImageFromFile(prefCustomIconPath);
};
// GTK bug: Gdk-CRITICAL **: IA__gdk_window_get_root_coords: assertion `GDK_IS_WINDOW (window)' failed
firetray.Handler.setIconTooltip = function(toolTipStr) {

View File

@ -29,7 +29,7 @@ if ("undefined" == typeof(firetray.Handler))
FIRETRAY_ICON_CHROME_PATHS = {
'blank-icon': "chrome://firetray/skin/winnt/blank-icon.bmp",
'mail-unread': "chrome://firetray/skin/winnt/mail-unread.ico",
'mail-unread': "chrome://firetray/skin/winnt/mail-unread.ico"
};
firetray.StatusIcon = {
@ -41,11 +41,21 @@ firetray.StatusIcon = {
bitmaps: null,
WNDCLASS_NAME: "FireTrayHiddenWindowClass",
WNDCLASS_ATOM: null,
icons: (function(){return new ctypesMap(win32.HICON);})(),
bitmaps: (function(){return new ctypesMap(win32.HBITMAP);})(),
IMG_TYPES: {
ico: { win_t: win32.HICON, load_const: user32.IMAGE_ICON, map: 'icons' },
bmp: { win_t: win32.HBITMAP, load_const: user32.IMAGE_BITMAP, map: 'bitmaps' }
},
PREF_TO_ICON_NAME: {
app_icon_filename: 'app_custom',
custom_mail_icon: 'mail_custom' // FIXME: rename pref for consistency
},
init: function() {
this.loadImages();
// this.defineIconNames(); // FIXME: linux-only
this.create();
firetray.Handler.setIconImageDefault();
this.initialized = true;
return true;
@ -61,54 +71,82 @@ firetray.StatusIcon = {
return true;
},
defineIconNames: function() { // FIXME: linux-only
this.prefAppIconNames = (function() {
if (firetray.Handler.inMailApp) {
return "app_mail_icon_names";
} else if (firetray.Handler.inBrowserApp) {
return "app_browser_icon_names";
} else {
return "app_default_icon_names";
}
})();
this.defaultAppIconName = firetray.Handler.appName.toLowerCase();
this.prefNewMailIconNames = "new_mail_icon_names";
this.defaultNewMailIconName = "mail-unread";
},
loadThemedIcons: 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);
log.debug("=== hwnd_hidden_moz="+hwnd_hidden_moz);
this.icons.insert('app', this.getIconFromWindow(hwnd_hidden_moz));
['app_icon_filename', 'custom_mail_icon'].forEach(function(elt) {
firetray.StatusIcon.loadImageCustom(elt);
});
/* 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 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)) {
let img = this.loadImageFromFile(path);
if (img)
this[this.IMG_TYPES[img['type']]['map']].insert(imgName, img['himg']);
}
},
loadImageCustom: function(prefname) {
let filename = firetray.Utils.prefService.getCharPref(prefname);
if (!filename) return;
let img = this.loadImageFromFile(filename);
if (!img) return;
log.debug("loadImageCustom img type="+img['type']+" himg="+img['himg']);
let hicon = img['himg'];
if (img['type'] === 'bmp')
hicon = this.HBITMAPToHICON(img['himg']);
let name = this.PREF_TO_ICON_NAME[prefname];
log.debug(" name="+name);
this.icons.insert(name, hicon);
},
loadImageFromFile: function(path) {
let imgType = path.substr(-3, 3).toLowerCase();
if (!(imgType in this.IMG_TYPES)) {
throw Error("Unrecognized type '"+imgType+"'");
}
let imgTypeRec = imgTypeDict[imgType];
let imgTypeRec = this.IMG_TYPES[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);
log.error("Could not load '"+path+"'="+himg+" winLastError="+ctypes.winLastError);
return null;
}
return {type:imgType, himg:himg};
},
HBITMAPToHICON: function(hBitmap) {
log.debug("HBITMAPToHICON hBitmap="+hBitmap);
let hWnd = null; // firetray.StatusIcon.hwndProxy;
let hdc = user32.GetDC(hWnd);
let bitmap = new win32.BITMAP();
let err = gdi32.GetObjectW(hBitmap, win32.BITMAP.size, bitmap.address()); // get bitmap info
let hBitmapMask = gdi32.CreateCompatibleBitmap(hdc, bitmap.bmWidth, bitmap.bmHeight);
user32.ReleaseDC(hWnd, hdc);
let iconInfo = win32.ICONINFO();
iconInfo.fIcon = true;
iconInfo.xHotspot = 0;
iconInfo.yHotspot = 0;
iconInfo.hbmMask = hBitmapMask;
iconInfo.hbmColor = hBitmap;
let hIcon = user32.CreateIconIndirect(iconInfo.address());
log.debug(" CreateIconIndirect hIcon="+hIcon+" lastError="+ctypes.winLastError);
gdi32.DeleteObject(hBitmap);
gdi32.DeleteObject(hBitmapMask);
return hIcon;
},
// images loaded with LR_SHARED need't be destroyed
@ -284,32 +322,30 @@ firetray.StatusIcon = {
user32.ReleaseDC(hWnd, hdc);
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
function getFont(fnHeight) {
return gdi32.CreateFontW(
fnHeight, 0, 0, 0, gdi32.FW_SEMIBOLD, 0, 0, 0,
gdi32.ANSI_CHARSET, gdi32.OUT_OUTLINE_PRECIS, 0, gdi32.ANTIALIASED_QUALITY,
gdi32.FIXED_PITCH|gdi32.FF_SWISS, "Arial"
);
}
let fnHeight = firetray.js.floatToInt(height);
let hFont = gdi32.CreateFontW(fnHeight, 0, 0, 0, gdi32.FW_MEDIUM, 0, 0, 0,
gdi32.ANSI_CHARSET, 0, 0, 0, gdi32.FF_SWISS, "Sans"); // get font
ctypes.cast(gdi32.SelectObject(hdcMem, hFont), win32.HFONT); // replace font in bitmap by hFont
let faceName = ctypes.jschar.array()(32);
gdi32.GetTextFaceW(hdcMem, 32, faceName);
log.debug(" font="+faceName);
log.debug(" fnHeight initial="+fnHeight);
let hFont = getFont(fnHeight);
gdi32.SelectObject(hdcMem, hFont); // replace font in bitmap by hFont
{ let bufLen = 32, faceName = ctypes.jschar.array()(bufLen); gdi32.GetTextFaceW(hdcMem, bufLen, faceName); log.debug(" font="+faceName); }
let size = new gdi32.SIZE();
gdi32.GetTextExtentPoint32W(hdcMem, text, text.length, size.address()); // more reliable than DrawText(DT_CALCRECT)
while (size.cx > width - 6 || size.cy > height - 4) {
fnHeight -= 1;
hFont = gdi32.CreateFontW(fnHeight, 0, 0, 0, gdi32.FW_SEMIBOLD, 0, 0, 0,
gdi32.ANSI_CHARSET, 0, 0, gdi32.PROOF_QUALITY,
gdi32.FF_SWISS, "Arial");
ctypes.cast(gdi32.SelectObject(hdcMem, hFont), win32.HFONT);
gdi32.GetTextExtentPoint32W(hdcMem, text, text.length, size.address()); // more reliable than DrawText(DT_CALCRECT)
hFont = getFont(fnHeight);
gdi32.SelectObject(hdcMem, hFont);
gdi32.GetTextExtentPoint32W(hdcMem, text, text.length, size.address());
log.debug(" fnHeight="+fnHeight+" width="+size.cx);
}
gdi32.GetTextExtentPoint32W(hdcMem, text, text.length, size.address());
gdi32.SetTextColor(hdcMem, win32.COLORREF(this.cssColorToCOLORREF(color)));
gdi32.SetBkMode(hdcMem, gdi32.TRANSPARENT); // VERY IMPORTANT
@ -339,13 +375,29 @@ firetray.StatusIcon = {
gdi32.DeleteObject(hBitmapMask);
return hIcon; // to be destroyed (DestroyIcon)
},
getIconSafe: function(name) {
let hicon = null;
try {
hicon = firetray.StatusIcon.icons.get(name);
} catch(error) {
log.error("icon 'app_custom' not defined.");
}
return hicon;
}
}; // firetray.StatusIcon
firetray.Handler.setIconImageDefault = function() {
log.debug("setIconImageDefault");
let appIconType = firetray.Utils.prefService.getIntPref("app_icon_type");
if (appIconType === FIRETRAY_APPLICATION_ICON_TYPE_THEMED)
firetray.StatusIcon.setIcon({hicon:firetray.StatusIcon.icons.get('app')});
else if (appIconType === FIRETRAY_APPLICATION_ICON_TYPE_CUSTOM) {
firetray.StatusIcon.setIcon({hicon:firetray.StatusIcon.getIconSafe('app_custom')});
}
};
firetray.Handler.setIconImageNewMail = function() {
@ -353,6 +405,12 @@ firetray.Handler.setIconImageNewMail = function() {
firetray.StatusIcon.setIcon({hicon:firetray.StatusIcon.icons.get('mail-unread')});
};
firetray.Handler.setIconImageCustom = function(prefname) {
log.debug("setIconImageCustom");
let name = firetray.StatusIcon.PREF_TO_ICON_NAME[prefname];
firetray.StatusIcon.setIcon({hicon:firetray.StatusIcon.getIconSafe(name)});
};
// firetray.Handler.setIconImageFromFile = firetray.StatusIcon.setIconImageFromFile;
firetray.Handler.setIconTooltip = function(toolTipStr) {