Merge branch 'winnt'
@ -111,7 +111,9 @@ modules_sources := $(wildcard $(modules_dir)/*.js) \
|
||||
$(wildcard $(modules_dir)/*.jsm) \
|
||||
$(wildcard $(modules_dir)/ctypes/*.jsm) \
|
||||
$(wildcard $(modules_dir)/ctypes/linux/*.jsm) \
|
||||
$(wildcard $(modules_dir)/linux/*.jsm)
|
||||
$(wildcard $(modules_dir)/ctypes/winnt/*.jsm) \
|
||||
$(wildcard $(modules_dir)/linux/*.jsm) \
|
||||
$(wildcard $(modules_dir)/winnt/*.jsm)
|
||||
|
||||
# The components (JSM) dir.
|
||||
components_dir := components
|
||||
@ -142,7 +144,7 @@ $(xpi_built): check_version check_loglevel $(build_dir) $(build_includes)
|
||||
.PHONY: build
|
||||
build: $(xpi_built)
|
||||
@echo
|
||||
@echo "Build finished successfully."
|
||||
@echo "Build finished successfully in $(build_dir)."
|
||||
@echo
|
||||
|
||||
# This cleans all temporary files and directories created by 'make'.
|
||||
|
@ -15,14 +15,15 @@ const TREELEVEL_EXCLUDED_ACCOUNTS = 1;
|
||||
|
||||
const PREF_DEFAULT_PANE = "pref-pane-windows";
|
||||
|
||||
|
||||
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']);
|
||||
this.strings = document.getElementById("firetray-options-strings");
|
||||
this.prefwindow = document.getElementById("firetray-preferences");
|
||||
if (!this.prefwindow)
|
||||
@ -36,40 +37,54 @@ var firetrayUIOptions = {
|
||||
this.hidePrefPane("pref-pane-mail");
|
||||
}
|
||||
|
||||
if (firetray.Handler.isChatProvided()) {
|
||||
Cu.import("resource://firetray/FiretrayChat.jsm");
|
||||
if (firetray.Handler.isChatProvided() &&
|
||||
FIRETRAY_CHAT_SUPPORTED_OS.indexOf(firetray.Handler.runtimeOS) > -1) {
|
||||
Cu.import("resource://firetray/"+firetray.Handler.runtimeOS+"/FiretrayChat.jsm");
|
||||
this.initChatControls();
|
||||
} else
|
||||
} else {
|
||||
this.hidePrefPane("pref-pane-chat");
|
||||
};
|
||||
|
||||
this.updateWindowAndIconOptions();
|
||||
this.updateScrollOptions();
|
||||
this.initAppIconType();
|
||||
if (firetray.Handler.support['full_feat']) {
|
||||
this.initAppIconNames();
|
||||
if (firetray.Handler.inMailApp)
|
||||
this.initNewMailIconNames();
|
||||
} else {
|
||||
this.hideUnsupportedOptions();
|
||||
};
|
||||
|
||||
window.sizeToContent();
|
||||
},
|
||||
|
||||
onQuit: function(e) {
|
||||
// cleaning: removeEventListener on cells
|
||||
// NOTE: not sure this is necessary on window close
|
||||
let tree = document.getElementById("ui_tree_mail_accounts");
|
||||
let that = this;
|
||||
for (let i=0, len=tree.view.rowCount; i<len ; ++i) {
|
||||
let cells = tree.view.getItemAtIndex(i).getElementsByTagName("treecell");
|
||||
if (tree.view.getLevel(i) === TREELEVEL_SERVER_TYPES) {
|
||||
// account_or_server_type_excluded, account_or_server_type_order
|
||||
[cells[1], cells[2]].map(
|
||||
function(c) {
|
||||
c.removeEventListener(
|
||||
'DOMAttrModified', that._userChangeValueTreeServerTypes, true);
|
||||
});
|
||||
} else if (tree.view.getLevel(i) === TREELEVEL_EXCLUDED_ACCOUNTS) {
|
||||
cells[1].removeEventListener(
|
||||
'DOMAttrModified', that._userChangeValueTree, true);
|
||||
if (firetray.Handler.inMailApp) {
|
||||
this.removeListeners();
|
||||
this.removeMailAccountsObserver();
|
||||
}
|
||||
},
|
||||
|
||||
hideUnsupportedOptions: function() { // full_feat
|
||||
// windows prefs
|
||||
['ui_hides_last_only', 'ui_show_activates', 'ui_remember_desktop']
|
||||
.forEach(function(id){
|
||||
document.getElementById(id).hidden = true;
|
||||
});
|
||||
|
||||
// icon prefs
|
||||
['app_icon_default', 'ui_show_icon_on_hide', 'ui_scroll_hides',
|
||||
'ui_radiogroup_scroll'].forEach(function(id){
|
||||
document.getElementById(id).hidden = true;
|
||||
});
|
||||
document.getElementById("ui_scroll_hides").setAttribute("oncommand", void(0));
|
||||
|
||||
// mail prefs
|
||||
document.getElementById("newmail_icon_names").hidden = true;
|
||||
for (let i=1; i<4; ++i) {
|
||||
document.getElementById("radio_mail_notification_newmail_icon_name"+i).
|
||||
setAttribute("observes", void(0));
|
||||
}
|
||||
},
|
||||
|
||||
@ -80,8 +95,10 @@ var firetrayUIOptions = {
|
||||
radio.hidden = true;
|
||||
},
|
||||
|
||||
hideElement: function(targetNode, hiddenval) {
|
||||
targetNode.hidden = hiddenval;
|
||||
hideChildren: function(group, hiddenval) {
|
||||
let children = group.childNodes;
|
||||
for (let i=0, len=children.length; i<len ; ++i)
|
||||
children[i].hidden = hiddenval;
|
||||
},
|
||||
|
||||
disableChildren: function(group, disableval) {
|
||||
@ -119,8 +136,9 @@ var firetrayUIOptions = {
|
||||
},
|
||||
|
||||
updateScrollOptions: function() {
|
||||
let scroll_hides = document.getElementById("ui_scroll_hides").checked;
|
||||
this.disableChildren(document.getElementById("ui_radiogroup_scroll"), !scroll_hides);
|
||||
let ui_scroll_hides = document.getElementById("ui_scroll_hides");
|
||||
this.disableChildren(document.getElementById("ui_radiogroup_scroll"),
|
||||
!ui_scroll_hides.checked);
|
||||
},
|
||||
|
||||
initAppIconType: function() {
|
||||
@ -174,26 +192,28 @@ var firetrayUIOptions = {
|
||||
if (val) iconNames.push(val);
|
||||
}
|
||||
log.debug("iconNames="+iconNames);
|
||||
firetray.Utils.setArrayPref(prefIconNames, iconNames);
|
||||
firetray.Utils.setArrayPref(prefIconNames, iconNames); // FIXME: should be a <preference>
|
||||
},
|
||||
|
||||
disableIconTypeMaybe: function(appIconType) {
|
||||
let appIconCustomGroup = document.getElementById("app_icon_custom");
|
||||
this.disableChildren(appIconCustomGroup,
|
||||
(appIconType !== FIRETRAY_APPLICATION_ICON_TYPE_CUSTOM));
|
||||
|
||||
if (firetray.Handler.support['full_feat']) {
|
||||
let appIconDefaultGroup = document.getElementById("app_icon_default");
|
||||
this.disableNChildren(appIconDefaultGroup, 2,
|
||||
(appIconType !== FIRETRAY_APPLICATION_ICON_TYPE_THEMED));
|
||||
}
|
||||
|
||||
let appIconCustomGroup = document.getElementById("app_icon_custom");
|
||||
this.disableChildren(appIconCustomGroup,
|
||||
(appIconType !== FIRETRAY_APPLICATION_ICON_TYPE_CUSTOM));
|
||||
},
|
||||
|
||||
initMailControls: function() {
|
||||
this.populateExcludedFoldersList();
|
||||
this.populateTreeAccountsOrServerTypes();
|
||||
this.addMailAccountsObserver();
|
||||
|
||||
this.initMessageCountSettings();
|
||||
this.initNotificationSettings();
|
||||
this.initMailTrigger();
|
||||
|
||||
this.toggleNotifications(firetray.Utils.prefService.getBoolPref("mail_notification_enabled"));
|
||||
},
|
||||
@ -208,16 +228,20 @@ var firetrayUIOptions = {
|
||||
FIRETRAY_NOTIFICATION_MESSAGE_COUNT;
|
||||
document.getElementById("ui_radio_mail_notification_newmail_icon").value =
|
||||
FIRETRAY_NOTIFICATION_NEWMAIL_ICON;
|
||||
document.getElementById("ui_radio_mail_notification_custom_mail_icon").value =
|
||||
document.getElementById("ui_radio_mail_notification_mail_icon_custom").value =
|
||||
FIRETRAY_NOTIFICATION_CUSTOM_ICON;
|
||||
|
||||
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() {
|
||||
@ -243,30 +267,25 @@ 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;
|
||||
return -1;
|
||||
},
|
||||
|
||||
initMailTrigger: function() {
|
||||
document.getElementById("ui_mail_change_trigger").value =
|
||||
firetray.Utils.prefService.getCharPref("mail_change_trigger");
|
||||
},
|
||||
|
||||
updateMailTrigger: function() {
|
||||
let mailTrigger = document.getElementById("ui_mail_change_trigger").value.trim();
|
||||
firetray.Utils.prefService.setCharPref("mail_change_trigger", mailTrigger);
|
||||
saveMailChangeTrigger: function(uiElt) {
|
||||
return uiElt.value.trim();
|
||||
},
|
||||
|
||||
updateNotificationSettings: function() {
|
||||
log.debug("updateNotificationSettings");
|
||||
let radioMailNotify = document.getElementById("ui_radiogroup_mail_notification");
|
||||
let mailNotificationType = +radioMailNotify.getItemAtIndex(radioMailNotify.selectedIndex).value;
|
||||
firetray.Utils.prefService.setIntPref("mail_notification_type", mailNotificationType);
|
||||
let mailNotifyRadio = document.getElementById("ui_radiogroup_mail_notification");
|
||||
let mailNotificationType = +mailNotifyRadio.getItemAtIndex(mailNotifyRadio.selectedIndex).value;
|
||||
this.disableNotificationMaybe(mailNotificationType);
|
||||
|
||||
firetray.Messaging.updateIcon();
|
||||
},
|
||||
|
||||
updateMessageCountSettings: function() {
|
||||
@ -275,12 +294,6 @@ var firetrayUIOptions = {
|
||||
this.disableMessageCountMaybe(messageCountType);
|
||||
},
|
||||
|
||||
updateChatBlinkSettings: function() {
|
||||
let radioBlinkStyle = document.getElementById("ui_chat_icon_blink_style");
|
||||
let blinkStyle = +radioBlinkStyle.getItemAtIndex(radioBlinkStyle.selectedIndex).value;
|
||||
firetray.Utils.prefService.setIntPref("chat_icon_blink_style", blinkStyle);
|
||||
},
|
||||
|
||||
disableNotificationMaybe: function(notificationSetting) {
|
||||
log.debug("disableNotificationMaybe: "+notificationSetting);
|
||||
|
||||
@ -288,11 +301,13 @@ var firetrayUIOptions = {
|
||||
this.disableChildren(iconTextColor,
|
||||
(notificationSetting !== FIRETRAY_NOTIFICATION_MESSAGE_COUNT));
|
||||
|
||||
if (firetray.Handler.support['full_feat']) {
|
||||
let newMailIconNames = document.getElementById("newmail_icon_names");
|
||||
this.disableNChildren(newMailIconNames, 2,
|
||||
(notificationSetting !== FIRETRAY_NOTIFICATION_NEWMAIL_ICON));
|
||||
}
|
||||
|
||||
let customIconGroup = document.getElementById("custom_mail_icon");
|
||||
let customIconGroup = document.getElementById("mail_icon_custom");
|
||||
this.disableChildren(customIconGroup,
|
||||
(notificationSetting !== FIRETRAY_NOTIFICATION_CUSTOM_ICON));
|
||||
},
|
||||
@ -304,13 +319,14 @@ 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);
|
||||
firetray.Utils.prefService.setIntPref("mail_notification_type", FIRETRAY_NOTIFICATION_NEWMAIL_ICON);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -357,7 +373,7 @@ var firetrayUIOptions = {
|
||||
|
||||
chooseMailIconFile: function() {
|
||||
let updateIcon = firetray.Messaging.updateIcon.bind(firetray.Messaging);
|
||||
this._chooseIconFile("custom_mail_icon_filename", updateIcon);
|
||||
this._chooseIconFile("mail_icon_custom_filename", updateIcon);
|
||||
},
|
||||
|
||||
_chooseIconFile: function(elementId, callback) {
|
||||
@ -377,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);
|
||||
},
|
||||
@ -389,44 +408,52 @@ var firetrayUIOptions = {
|
||||
},
|
||||
|
||||
/**
|
||||
* NOTE: folder exceptions for unread messages count are *stored* in
|
||||
* preferences as excluded, but *shown* as "not included"
|
||||
* NOTE: we store folder type *exceptions* for unread messages count. This is
|
||||
* easier than storing all possible included folder types. The drawback is
|
||||
* that we must inverse the selection in the UI: we show exceptions as "not
|
||||
* included".
|
||||
*/
|
||||
populateExcludedFoldersList: function() {
|
||||
let excludedFoldersList = document.getElementById('excluded_folders_list');
|
||||
|
||||
let prefExcludedFoldersFlags = firetray.Utils.prefService
|
||||
.getIntPref("excluded_folders_flags");
|
||||
log.debug("prefExcludedFoldersFlags="+prefExcludedFoldersFlags.toString(16));
|
||||
for (let folderType in FLDRS_UNINTERESTING) {
|
||||
let localizedFolderType = this.strings.getString(folderType);
|
||||
let item = excludedFoldersList.appendItem(localizedFolderType, folderType);
|
||||
let folderTypeVal = FLDRS_UNINTERESTING[folderType];
|
||||
let item = excludedFoldersList.appendItem(localizedFolderType, folderTypeVal);
|
||||
item.setAttribute("observes", "broadcaster-notification-disabled");
|
||||
log.debug("folder: "+folderType);
|
||||
if (!(FLDRS_UNINTERESTING[folderType] & prefExcludedFoldersFlags)) {
|
||||
let folderTypeSet = (folderTypeVal & prefExcludedFoldersFlags);
|
||||
log.debug("folder: "+folderType+" folderTypeVal="+folderTypeVal+" folderTypeSet="+folderTypeSet);
|
||||
if (!folderTypeSet) {
|
||||
excludedFoldersList.ensureElementIsVisible(item); // bug 326445
|
||||
excludedFoldersList.addItemToSelection(item); // doesn't trigger onselect
|
||||
excludedFoldersList.addItemToSelection(item); // does trigger onselect...
|
||||
}
|
||||
}
|
||||
|
||||
// ...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);
|
||||
},
|
||||
|
||||
updateExcludedFoldersPref: function() {
|
||||
let excludedFoldersList = document.getElementById('excluded_folders_list');
|
||||
loadExcludedFoldersFlags: function(uiElt) {
|
||||
// we can't do much here since onLoad() not yet applied at onsyncfrompreference...
|
||||
},
|
||||
|
||||
log.debug("LAST SELECTED: "+excludedFoldersList.currentItem.label);
|
||||
let excludedFoldersFlags = null;
|
||||
for (let i = 0, len=excludedFoldersList.itemCount; i<len; ++i) {
|
||||
let folder = excludedFoldersList.getItemAtIndex(i);
|
||||
saveExcludedFoldersFlags: function(uiElt) {
|
||||
log.debug("LAST SELECTED: "+uiElt.currentItem.label);
|
||||
let excludedFoldersFlags = 0;
|
||||
for (let i = 0, len=uiElt.itemCount; i<len; ++i) {
|
||||
let folder = uiElt.getItemAtIndex(i);
|
||||
if (folder.selected)
|
||||
excludedFoldersFlags &= ~FLDRS_UNINTERESTING[folder.value];
|
||||
excludedFoldersFlags &= ~folder.value; // clear
|
||||
else
|
||||
excludedFoldersFlags |= FLDRS_UNINTERESTING[folder.value];
|
||||
excludedFoldersFlags |= folder.value; // set
|
||||
}
|
||||
log.debug("excluded folders flags: "+excludedFoldersFlags);
|
||||
|
||||
firetray.Utils.prefService.setIntPref("excluded_folders_flags",
|
||||
excludedFoldersFlags);
|
||||
|
||||
firetray.Messaging.updateMsgCountWithCb();
|
||||
log.debug("excluded folders flags: "+excludedFoldersFlags.toString(16));
|
||||
return excludedFoldersFlags;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -442,15 +469,11 @@ var firetrayUIOptions = {
|
||||
if (disable === true) {
|
||||
cells[i].setAttribute('properties', "disabled");
|
||||
if (i === TREEROW_ACCOUNT_OR_SERVER_TYPE_EXCLUDED) {
|
||||
cells[i].removeEventListener(
|
||||
'DOMAttrModified', that._userChangeValueTree, true);
|
||||
cells[i].setAttribute('editable', "false");
|
||||
}
|
||||
} else {
|
||||
cells[i].removeAttribute('properties');
|
||||
if (i === TREEROW_ACCOUNT_OR_SERVER_TYPE_EXCLUDED) {
|
||||
cells[i].addEventListener(
|
||||
'DOMAttrModified', that._userChangeValueTree, true);
|
||||
cells[i].setAttribute('editable', "true");
|
||||
}
|
||||
}
|
||||
@ -460,39 +483,6 @@ var firetrayUIOptions = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* needed for triggering actual preference change and saving
|
||||
*/
|
||||
_userChangeValueTree: function(event) {
|
||||
if (event.attrName == "label") log.debug("label changed!");
|
||||
if (event.attrName == "value") log.debug("value changed!");
|
||||
document.getElementById("pref-pane-mail")
|
||||
.userChangedValue(document.getElementById("ui_tree_mail_accounts"));
|
||||
|
||||
firetray.Messaging.updateMsgCountWithCb();
|
||||
},
|
||||
|
||||
_userChangeValueTreeServerTypes: function(event) {
|
||||
if (event.attrName === "value") { // checkbox
|
||||
let checkboxCell = event.originalTarget;
|
||||
let tree = document.getElementById("ui_tree_mail_accounts");
|
||||
|
||||
let subRows = firetray.Utils.XPath(
|
||||
checkboxCell,
|
||||
'ancestor::xul:treeitem[1]/child::xul:treechildren/xul:treeitem/xul:treerow');
|
||||
log.debug("subRows="+subRows);
|
||||
for (let i=0, len=subRows.length; i<len; ++i) {
|
||||
firetrayUIOptions._disableTreeRow(
|
||||
subRows[i], (checkboxCell.getAttribute("value") === "false"));
|
||||
}
|
||||
|
||||
} else if (event.attrName == "label") { // text
|
||||
log.warn("NOT IMPLEMENTED YET: move row to new rank"); // TODO
|
||||
}
|
||||
|
||||
this._userChangeValueTree(event);
|
||||
},
|
||||
|
||||
/**
|
||||
* NOTE: account exceptions for unread messages count are *stored* in
|
||||
* preferences as excluded, but *shown* as "not included"
|
||||
@ -541,15 +531,11 @@ var firetrayUIOptions = {
|
||||
// account_or_server_type_excluded => checkbox
|
||||
let cellExcluded = document.createElement('treecell');
|
||||
cellExcluded.setAttribute('value',!serverTypes[serverTypeName].excluded);
|
||||
cellExcluded.addEventListener( // CAUTION: removeEventListener in onQuit()
|
||||
'DOMAttrModified', that._userChangeValueTreeServerTypes, true);
|
||||
typeRow.appendChild(cellExcluded);
|
||||
|
||||
// account_or_server_type_order
|
||||
let cellOrder = document.createElement('treecell');
|
||||
cellOrder.setAttribute('label',serverTypes[serverTypeName].order);
|
||||
cellOrder.addEventListener( // CAUTION: removeEventListener in onQuit()
|
||||
'DOMAttrModified', that._userChangeValueTreeServerTypes, true);
|
||||
typeRow.appendChild(cellOrder);
|
||||
|
||||
target.appendChild(typeItem);
|
||||
@ -585,9 +571,6 @@ var firetrayUIOptions = {
|
||||
if (rowDisabled === true) {
|
||||
accountCell.setAttribute('properties', "disabled");
|
||||
accountCell.setAttribute('editable', "false");
|
||||
} else {
|
||||
accountCell.addEventListener( // CAUTION: removeEventListener in onQuit()
|
||||
'DOMAttrModified', that._userChangeValueTree, true);
|
||||
}
|
||||
accountRow.appendChild(accountCell);
|
||||
|
||||
@ -649,14 +632,72 @@ 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) {
|
||||
log.debug("mutation: type="+mutation.type+" node="+mutation.target.nodeName+" attr="+mutation.attributeName);
|
||||
if (mutation.type !== "attributes") return;
|
||||
|
||||
if (mutation.attributeName === "value") { // checkbox
|
||||
log.debug("value changed!");
|
||||
let checkboxCell = mutation.target;
|
||||
let tree = document.getElementById("ui_tree_mail_accounts");
|
||||
|
||||
let subRows = firetray.Utils.XPath(
|
||||
checkboxCell,
|
||||
'ancestor::xul:treeitem[1]/child::xul:treechildren/xul:treeitem/xul:treerow');
|
||||
log.debug("subRows="+subRows);
|
||||
for (let i=0, len=subRows.length; i<len; ++i) {
|
||||
firetrayUIOptions._disableTreeRow(
|
||||
subRows[i], (checkboxCell.getAttribute("value") === "false"));
|
||||
}
|
||||
|
||||
} else if (mutation.attributeName == "label") { // text
|
||||
log.debug("label changed!");
|
||||
log.warn("NOT IMPLEMENTED YET: move row to new rank"); // TODO
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById("pref-pane-mail")
|
||||
.userChangedValue(document.getElementById("ui_tree_mail_accounts"));
|
||||
|
||||
},
|
||||
|
||||
addMailAccountsObserver: function() {
|
||||
this.mutationObserver = new MutationObserver(function(mutations) {
|
||||
mutations.forEach(firetrayUIOptions.onMutation);
|
||||
});
|
||||
let config = { attributes: true, childList: true, characterData: false, subtree: true };
|
||||
let target = document.querySelector('#ui_mail_accounts');
|
||||
this.mutationObserver.observe(target, config);
|
||||
},
|
||||
|
||||
removeMailAccountsObserver: function() {
|
||||
this.mutationObserver.disconnect();
|
||||
this.mutationobserver = null;
|
||||
},
|
||||
|
||||
/*
|
||||
* Save the "mail_accounts" preference. This is called by the pref's system
|
||||
* when the GUI element is altered.
|
||||
*/
|
||||
saveTreeAccountsOrServerTypes: function() {
|
||||
saveTreeAccountsOrServerTypes: function() { // FIXME: broken ?
|
||||
let tree = document.getElementById("ui_tree_mail_accounts");
|
||||
|
||||
log.debug("VIEW="+ tree.view + ", rowCount="+tree.view.rowCount);
|
||||
|
@ -67,7 +67,7 @@
|
||||
|
||||
<preferences>
|
||||
<preference id="pref_app_icon_type" name="extensions.firetray.app_icon_type" type="int"/>
|
||||
<preference id="pref_app_icon_filename" name="extensions.firetray.app_icon_filename" type="string"/>
|
||||
<preference id="pref_app_icon_custom" name="extensions.firetray.app_icon_custom" type="string"/>
|
||||
<preference id="pref_show_icon_on_hide" name="extensions.firetray.show_icon_on_hide" type="bool"/>
|
||||
<preference id="pref_scroll_hides" name="extensions.firetray.scroll_hides" type="bool" />
|
||||
<preference id="pref_scroll_mode" name="extensions.firetray.scroll_mode" type="string" />
|
||||
@ -97,7 +97,7 @@
|
||||
<radio id="ui_app_icon_type_custom" label="&app_icon_custom.label;"
|
||||
accesskey="&app_icon_custom.accesskey;" />
|
||||
<hbox id="app_icon_custom" align="center" flex="1" >
|
||||
<textbox id="app_icon_custom_filename" preference="pref_app_icon_filename" flex="1" />
|
||||
<textbox id="app_icon_custom_filename" preference="pref_app_icon_custom" flex="1" />
|
||||
<button id="app_icon_custom_select" label="&choose;"
|
||||
accesskey="&choose.accesskey;"
|
||||
oncommand="firetrayUIOptions.chooseAppIconFile()" />
|
||||
@ -129,14 +129,17 @@
|
||||
|
||||
<preferences>
|
||||
<preference id="pref_mail_notification_enabled" name="extensions.firetray.mail_notification_enabled" type="bool" />
|
||||
<preference id="pref_mail_notification_type" name="extensions.firetray.mail_notification_type" type="int" />
|
||||
<preference id="pref_message_count_type" name="extensions.firetray.message_count_type" type="int" />
|
||||
<preference id="pref_icon_text_color" name="extensions.firetray.icon_text_color" type="string" />
|
||||
<preference id="pref_custom_mail_icon" name="extensions.firetray.custom_mail_icon" type="string" />
|
||||
<preference id="pref_mail_icon_custom" name="extensions.firetray.mail_icon_custom" type="string" />
|
||||
<preference id="pref_excluded_folders_flags" name="extensions.firetray.excluded_folders_flags" type="int" />
|
||||
<preference id="pref_mail_change_trigger" name="extensions.firetray.mail_change_trigger" type="string"/>
|
||||
<preference id="pref_mail_accounts" name="extensions.firetray.mail_accounts" type="string"/>
|
||||
<preference id="pref_folder_count_recursive" name="extensions.firetray.folder_count_recursive" type="bool" />
|
||||
<preference id="pref_only_favorite_folders" name="extensions.firetray.only_favorite_folders" type="bool" />
|
||||
<preference id="pref_mail_urgency_hint" name="extensions.firetray.mail_urgency_hint" type="bool" />
|
||||
<preference id="pref_mail_change_trigger" name="extensions.firetray.mail_change_trigger" type="string" />
|
||||
<preference id="pref_mail_get_attention" name="extensions.firetray.mail_get_attention" type="bool" />
|
||||
</preferences>
|
||||
|
||||
<vbox align="left" flex="1">
|
||||
@ -169,7 +172,7 @@
|
||||
observes="broadcaster-notification-disabled" />
|
||||
</caption>
|
||||
|
||||
<radiogroup id="ui_radiogroup_mail_notification">
|
||||
<radiogroup id="ui_radiogroup_mail_notification" preference="pref_mail_notification_type">
|
||||
<hbox id="ui_mail_notification_unread_count">
|
||||
<radio id="ui_radio_mail_notification_unread_count" label="&mail_notification_unread_count.label;"
|
||||
accesskey="&mail_notification_unread_count.accesskey;"
|
||||
@ -207,15 +210,14 @@
|
||||
</hbox>
|
||||
</hbox>
|
||||
<hbox>
|
||||
<radio id="ui_radio_mail_notification_custom_mail_icon" label="&mail_notification_custom_mail_icon.label;"
|
||||
accesskey="&mail_notification_custom_mail_icon.accesskey;"
|
||||
<radio id="ui_radio_mail_notification_mail_icon_custom" label="&mail_notification_mail_icon_custom.label;"
|
||||
accesskey="&mail_notification_mail_icon_custom.accesskey;"
|
||||
oncommand="firetrayUIOptions.updateNotificationSettings()"
|
||||
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" />
|
||||
<button id="custom_mail_icon_select" label="&choose;"
|
||||
<hbox id="mail_icon_custom" align="center" flex="1" >
|
||||
<textbox id="mail_icon_custom_filename" preference="pref_mail_icon_custom"
|
||||
observes="broadcaster-notification-disabled" flex="1" />
|
||||
<button id="mail_icon_custom_select" label="&choose;"
|
||||
accesskey="&choose.accesskey;"
|
||||
observes="broadcaster-notification-disabled"
|
||||
oncommand="firetrayUIOptions.chooseMailIconFile()" />
|
||||
@ -238,7 +240,8 @@
|
||||
|
||||
<listbox id="excluded_folders_list" rows="7" flex="1" seltype="multiple"
|
||||
tooltiptext="&excluded_folders_list.tooltip;"
|
||||
onselect="firetrayUIOptions.updateExcludedFoldersPref()"
|
||||
preference="pref_excluded_folders_flags"
|
||||
onsynctopreference="return firetrayUIOptions.saveExcludedFoldersFlags(this);"
|
||||
observes="broadcaster-notification-disabled" />
|
||||
</groupbox>
|
||||
|
||||
@ -295,15 +298,16 @@
|
||||
<label control="ui_mail_change_trigger" value="&mail_change_trigger.label;"
|
||||
accesskey="&mail_change_trigger.accesskey;" />
|
||||
<textbox id="ui_mail_change_trigger" size="18" placeholder="&mail_change_trigger.placeholder;"
|
||||
onchange="firetrayUIOptions.updateMailTrigger();" flex="1"
|
||||
tooltiptext="&mail_change_trigger.tooltip;"
|
||||
tooltiptext="&mail_change_trigger.tooltip;" flex="1"
|
||||
preference="pref_mail_change_trigger"
|
||||
onsynctopreference="return firetrayUIOptions.saveMailChangeTrigger(this);"
|
||||
observes="broadcaster-notification-disabled" />
|
||||
</hbox>
|
||||
|
||||
<checkbox id="ui_mail_urgency_hint"
|
||||
label="&mail_urgency_hint.label;"
|
||||
accesskey="&mail_urgency_hint.accesskey;"
|
||||
preference="pref_mail_urgency_hint"
|
||||
<checkbox id="ui_mail_get_attention"
|
||||
label="&mail_get_attention.label;"
|
||||
accesskey="&mail_get_attention.accesskey;"
|
||||
preference="pref_mail_get_attention"
|
||||
observes="broadcaster-notification-disabled"/>
|
||||
|
||||
</vbox>
|
||||
@ -338,10 +342,8 @@
|
||||
<label control="ui_chat_icon_blink_style" observes="broadcaster-chat-icon-disabled"
|
||||
value="&chat_icon_blink_style.label;" accesskey="&chat_icon_blink_style.accesskey;" />
|
||||
<radio id="ui_chat_icon_blink_style_normal" label="&chat_icon_blink_style_normal;"
|
||||
oncommand="firetrayUIOptions.updateChatBlinkSettings()"
|
||||
observes="broadcaster-chat-icon-disabled"/>
|
||||
<radio id="ui_chat_icon_blink_style_fade" label="&chat_icon_blink_style_fade;"
|
||||
oncommand="firetrayUIOptions.updateChatBlinkSettings()"
|
||||
observes="broadcaster-chat-icon-disabled"/>
|
||||
</hbox>
|
||||
</radiogroup>
|
||||
|
@ -27,16 +27,17 @@ var firetrayChrome = { // each new window gets a new firetrayChrome !
|
||||
this.winId = firetray.Handler.registerWindow(win);
|
||||
|
||||
win.addEventListener('close', firetrayChrome.onClose, true);
|
||||
this.hijackTitlebarButtons();
|
||||
|
||||
firetray_log.debug('Firetray LOADED: ' + init);
|
||||
return true;
|
||||
},
|
||||
|
||||
|
||||
/* NOTE: don't do firetray.Handler.initialized=false here, otherwise after a
|
||||
window close, a new window will create a new handler (and hence, a new tray
|
||||
icon) */
|
||||
onQuit: function(win) {
|
||||
win.removeEventListener('close', firetrayChrome.onClose, true);
|
||||
firetray.Handler.unregisterWindow(win);
|
||||
firetray_log.info("windowsCount="+firetray.Handler.windowsCount+", visibleWindowsCount="+firetray.Handler.visibleWindowsCount);
|
||||
firetray_log.debug('Firetray UNLOADED !');
|
||||
@ -49,24 +50,96 @@ var firetrayChrome = { // each new window gets a new firetrayChrome !
|
||||
called *after* the popup */
|
||||
onClose: function(event) {
|
||||
firetray_log.debug('Firetray CLOSE');
|
||||
let win = event.originalTarget;
|
||||
if (!win instanceof ChromeWindow)
|
||||
throw new TypeError('originalTarget not a ChromeWindow');
|
||||
|
||||
let hides_on_close = firetray.Utils.prefService.getBoolPref('hides_on_close');
|
||||
firetray_log.debug('hides_on_close: '+hides_on_close);
|
||||
if (hides_on_close) {
|
||||
if (!hides_on_close) return false;
|
||||
|
||||
let hides_single_window = firetray.Utils.prefService.getBoolPref('hides_single_window');
|
||||
let hides_last_only = firetray.Utils.prefService.getBoolPref('hides_last_only');
|
||||
firetray_log.debug('hides_single_window='+hides_single_window+', windowsCount='+firetray.Handler.windowsCount);
|
||||
if (hides_last_only && (firetray.Handler.windowsCount > 1)) return;
|
||||
if (hides_last_only && (firetray.Handler.windowsCount > 1)) return true;
|
||||
|
||||
if (hides_single_window)
|
||||
firetray.Handler.hideWindow(firetrayChrome.winId);
|
||||
else
|
||||
firetray.Handler.hideAllWindows();
|
||||
|
||||
event && event.preventDefault();
|
||||
if (event) event.preventDefault();
|
||||
return true;
|
||||
},
|
||||
|
||||
/*
|
||||
* Minimize/Restore/Close buttons can be overlayed by titlebar (fake) buttons
|
||||
* which do not fire the events that we rely on (see Bug 827880). This is why
|
||||
* we override the fake buttons' default actions.
|
||||
*/
|
||||
hijackTitlebarButtons: function() {
|
||||
Object.keys(this.titlebarDispatch).map(function(val, idx) {
|
||||
let fInfo = firetrayChrome.replaceCommand(val, firetrayChrome.titlebarDispatch[val]['new']);
|
||||
if (fInfo) {
|
||||
firetrayChrome.titlebarDispatch[val]['old'] = fInfo[0];
|
||||
firetray_log.debug('replaced command='+val+' type='+fInfo[1]+' func='+fInfo[0]);
|
||||
firetrayChrome.titlebarDispatch[val]['type'] = fInfo[1];
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
titlebarDispatch: {
|
||||
"titlebar-min": {new: function(e){
|
||||
firetray_log.debug(' titlebar-min clicked');
|
||||
if (!firetray.Handler.onMinimize(firetrayChrome.winId))
|
||||
firetrayChrome.applyDefaultCommand("titlebar-min");
|
||||
}, old: null, type: null},
|
||||
|
||||
"titlebar-close": {new: function(e){
|
||||
firetray_log.debug(' titlebar-close clicked');
|
||||
if (!firetrayChrome.onClose(null)) {
|
||||
firetrayChrome.applyDefaultCommand("titlebar-close");
|
||||
}
|
||||
}, old: null, type: null}
|
||||
},
|
||||
|
||||
replaceCommand: function(eltId, func) {
|
||||
let elt = document.getElementById(eltId);
|
||||
if (!elt) {
|
||||
firetray_log.info("Element '"+eltId+"' not found. Command not replaced.");
|
||||
return null;
|
||||
}
|
||||
|
||||
let command = elt.command;
|
||||
let oncommand = elt.getAttribute("oncommand");
|
||||
let old = null, type = null;
|
||||
if (command) {
|
||||
firetray_log.debug('command');
|
||||
type = FIRETRAY_XUL_ATTRIBUTE_COMMAND;
|
||||
old = elt.command;
|
||||
elt.command = null;
|
||||
elt.addEventListener('click', func, false);
|
||||
} else if (oncommand) {
|
||||
firetray_log.debug('oncommand');
|
||||
type = FIRETRAY_XUL_ATTRIBUTE_ONCOMMAND;
|
||||
let prev = elt.getAttribute("oncommand");
|
||||
old = new Function(prev);
|
||||
elt.setAttribute("oncommand", void(0));
|
||||
elt.addEventListener('command', func, false);
|
||||
} else {
|
||||
firetray_log.warn('Could not replace oncommand on '+eltId);
|
||||
}
|
||||
|
||||
return [old, type];
|
||||
},
|
||||
applyDefaultCommand: function(key) {
|
||||
let callType = this.titlebarDispatch[key]['type'];
|
||||
if (callType === FIRETRAY_XUL_ATTRIBUTE_COMMAND) {
|
||||
let cmdName = firetrayChrome.titlebarDispatch[key]['old'];
|
||||
let cmd = document.getElementById(cmdName);
|
||||
cmd.doCommand();
|
||||
|
||||
} else if (callType === FIRETRAY_XUL_ATTRIBUTE_ONCOMMAND) {
|
||||
firetrayChrome.titlebarDispatch[key]['old']();
|
||||
|
||||
} else {
|
||||
firetray_log.error("Calling type undefined for "+key);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
<?xml-stylesheet href="chrome://firetray/skin/overlay.css" type="text/css"?>
|
||||
<!DOCTYPE overlay SYSTEM "chrome://firetray/locale/overlay.dtd">
|
||||
<overlay id="firetray-overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript;version=1.7" src="overlay.js"/>
|
||||
<script type="application/javascript;version=1.8" src="overlay.js"/>
|
||||
|
||||
<stringbundleset id="stringbundleset">
|
||||
<stringbundle id="firetray-strings" src="chrome://firetray/locale/overlay.properties"/>
|
||||
|
@ -57,8 +57,8 @@
|
||||
<!ENTITY mail_notification_unread_count.accesskey "U">
|
||||
<!ENTITY mail_notification_newmail_icon.label "display newmail icon">
|
||||
<!ENTITY mail_notification_newmail_icon.accesskey "N">
|
||||
<!ENTITY mail_notification_custom_mail_icon.label "display custom icon">
|
||||
<!ENTITY mail_notification_custom_mail_icon.accesskey "I">
|
||||
<!ENTITY mail_notification_mail_icon_custom.label "display custom icon">
|
||||
<!ENTITY mail_notification_mail_icon_custom.accesskey "I">
|
||||
<!ENTITY icon_text_color "Text color">
|
||||
<!ENTITY icon_text_color.accesskey "T">
|
||||
<!ENTITY choose "Choose">
|
||||
@ -87,8 +87,8 @@
|
||||
<!ENTITY mail_change_trigger.accesskey "L">
|
||||
<!ENTITY mail_change_trigger.placeholder "/bin/notify-send">
|
||||
<!ENTITY mail_change_trigger.tooltip "Absolute path of the program to run when the message count changes. This program will get the new message count as the first argument.">
|
||||
<!ENTITY mail_urgency_hint.label "Set X11 urgency hint">
|
||||
<!ENTITY mail_urgency_hint.accesskey "X">
|
||||
<!ENTITY mail_get_attention.label "Window draws attention on new messages">
|
||||
<!ENTITY mail_get_attention.accesskey "g">
|
||||
|
||||
<!ENTITY chat_icon_enable.label "Enable chat icon">
|
||||
<!ENTITY chat_icon_enable.accesskey "E">
|
||||
|
@ -51,8 +51,8 @@
|
||||
<!ENTITY mail_notification_unread_count.accesskey "U">
|
||||
<!ENTITY mail_notification_newmail_icon.label "visualizar ícono de correo nuevo">
|
||||
<!ENTITY mail_notification_newmail_icon.accesskey "n">
|
||||
<!ENTITY mail_notification_custom_mail_icon.label "visualizar ícono personalizado">
|
||||
<!ENTITY mail_notification_custom_mail_icon.accesskey "p">
|
||||
<!ENTITY mail_notification_mail_icon_custom.label "visualizar ícono personalizado">
|
||||
<!ENTITY mail_notification_mail_icon_custom.accesskey "p">
|
||||
<!ENTITY icon_text_color "Color de texto">
|
||||
<!ENTITY icon_text_color.accesskey "C">
|
||||
<!ENTITY choose "Seleccionar">
|
||||
@ -77,8 +77,8 @@
|
||||
<!ENTITY mail_change_trigger.accesskey "L">
|
||||
<!ENTITY mail_change_trigger.placeholder "/bin/notify-send">
|
||||
<!ENTITY mail_change_trigger.tooltip "Ruta absoluta del programa para correr cuando la cuenta de mensajes cambia. Este programa obtendrá recibira el contador de nuevos mensajes como primer argumento.">
|
||||
<!ENTITY mail_urgency_hint.label "Set X11 urgency hint">
|
||||
<!ENTITY mail_urgency_hint.accesskey "X">
|
||||
<!ENTITY mail_get_attention.label "Window draws attention on new messages">
|
||||
<!ENTITY mail_get_attention.accesskey "g">
|
||||
<!ENTITY chat_icon_enable.label "Habilitar ícono de chat">
|
||||
<!ENTITY chat_icon_enable.accesskey "H">
|
||||
<!ENTITY chat_icon_blink.label "Icono de chat parpadea con mensajes nuevos.">
|
||||
|
@ -51,8 +51,8 @@
|
||||
<!ENTITY mail_notification_unread_count.accesskey "N">
|
||||
<!ENTITY mail_notification_newmail_icon.label "afficher l'icône de nouveau message">
|
||||
<!ENTITY mail_notification_newmail_icon.accesskey "f">
|
||||
<!ENTITY mail_notification_custom_mail_icon.label "afficher l'icône personnalisée">
|
||||
<!ENTITY mail_notification_custom_mail_icon.accesskey "i">
|
||||
<!ENTITY mail_notification_mail_icon_custom.label "afficher l'icône personnalisée">
|
||||
<!ENTITY mail_notification_mail_icon_custom.accesskey "i">
|
||||
<!ENTITY icon_text_color "Couleur du texte">
|
||||
<!ENTITY icon_text_color.accesskey "T">
|
||||
<!ENTITY choose "Choisir">
|
||||
@ -77,10 +77,10 @@
|
||||
<!ENTITY mail_change_trigger.accesskey "L">
|
||||
<!ENTITY mail_change_trigger.placeholder "/bin/notify-send">
|
||||
<!ENTITY mail_change_trigger.tooltip "Chemin absolu du programme à lancer lorsque le compte des messages a changé. Ce programme prendra pour base le nouveau décompte de messages">
|
||||
<!ENTITY mail_urgency_hint.label "Activer l'indice d'urgence X11">
|
||||
<!ENTITY mail_urgency_hint.accesskey "X">
|
||||
<!ENTITY mail_get_attention.label "La fenêtre attire l'attention lors de nouveaux messages">
|
||||
<!ENTITY mail_get_attention.accesskey "e">
|
||||
<!ENTITY chat_icon_enable.label "Activer l'icône du chat">
|
||||
<!ENTITY chat_icon_enable.accesskey "A">
|
||||
<!ENTITY chat_icon_enable.accesskey "h">
|
||||
<!ENTITY chat_icon_blink.label "L'icône du chat clignote à l'arrivée de nouveaux messages">
|
||||
<!ENTITY chat_icon_blink.accesskey "i">
|
||||
<!ENTITY chat_icon_blink.tooltip "quand un message privé est cité sur un canal">
|
||||
|
@ -51,8 +51,8 @@
|
||||
<!ENTITY mail_notification_unread_count.accesskey "U">
|
||||
<!ENTITY mail_notification_newmail_icon.label "Visualizza l'icona per i nuovi messaggi">
|
||||
<!ENTITY mail_notification_newmail_icon.accesskey "N">
|
||||
<!ENTITY mail_notification_custom_mail_icon.label "Visualizza icona personalizzata">
|
||||
<!ENTITY mail_notification_custom_mail_icon.accesskey "I">
|
||||
<!ENTITY mail_notification_mail_icon_custom.label "Visualizza icona personalizzata">
|
||||
<!ENTITY mail_notification_mail_icon_custom.accesskey "I">
|
||||
<!ENTITY icon_text_color "Colore del testo">
|
||||
<!ENTITY icon_text_color.accesskey "T">
|
||||
<!ENTITY choose "Scegli">
|
||||
@ -77,8 +77,8 @@
|
||||
<!ENTITY mail_change_trigger.accesskey "L">
|
||||
<!ENTITY mail_change_trigger.placeholder "/bin/notify-send">
|
||||
<!ENTITY mail_change_trigger.tooltip "Percorso assoluto del programma da lanciare quando viene incrementato il contatore dei messaggi non letti. Il programma utilizzerà il contatore dei nuovi messaggi come primo argomento.">
|
||||
<!ENTITY mail_urgency_hint.label "Set X11 urgency hint">
|
||||
<!ENTITY mail_urgency_hint.accesskey "X">
|
||||
<!ENTITY mail_get_attention.label "Window draws attention on new messages">
|
||||
<!ENTITY mail_get_attention.accesskey "g">
|
||||
<!ENTITY chat_icon_enable.label "Attiva icona della chat">
|
||||
<!ENTITY chat_icon_enable.accesskey "E">
|
||||
<!ENTITY chat_icon_blink.label "Lampeggiamento dell'icona della chat per nuovi messaggi">
|
||||
|
@ -51,8 +51,8 @@
|
||||
<!ENTITY mail_notification_unread_count.accesskey "O">
|
||||
<!ENTITY mail_notification_newmail_icon.label "pictogram nieuw bericht weergeven">
|
||||
<!ENTITY mail_notification_newmail_icon.accesskey "N">
|
||||
<!ENTITY mail_notification_custom_mail_icon.label "aangepast pictogram weergeven">
|
||||
<!ENTITY mail_notification_custom_mail_icon.accesskey "i">
|
||||
<!ENTITY mail_notification_mail_icon_custom.label "aangepast pictogram weergeven">
|
||||
<!ENTITY mail_notification_mail_icon_custom.accesskey "i">
|
||||
<!ENTITY icon_text_color "Tekstkleur">
|
||||
<!ENTITY icon_text_color.accesskey "T">
|
||||
<!ENTITY choose "Kiezen">
|
||||
@ -77,8 +77,8 @@
|
||||
<!ENTITY mail_change_trigger.accesskey "S">
|
||||
<!ENTITY mail_change_trigger.placeholder "/bin/notify-send">
|
||||
<!ENTITY mail_change_trigger.tooltip "Absoluut pad van het uit te voeren programma wanneer het aantal wijzigt. Dit programma krijgt het aantal nieuwe berichten als het eerste argument.">
|
||||
<!ENTITY mail_urgency_hint.label "Set X11 urgency hint">
|
||||
<!ENTITY mail_urgency_hint.accesskey "X">
|
||||
<!ENTITY mail_get_attention.label "Window draws attention on new messages">
|
||||
<!ENTITY mail_get_attention.accesskey "g">
|
||||
<!ENTITY chat_icon_enable.label "Chatpictogram inschakelen">
|
||||
<!ENTITY chat_icon_enable.accesskey "s">
|
||||
<!ENTITY chat_icon_blink.label "Chatpictogram knippert bij nieuwe berichten">
|
||||
|
@ -57,8 +57,8 @@
|
||||
<!ENTITY mail_notification_unread_count.accesskey "P">
|
||||
<!ENTITY mail_notification_newmail_icon.label "zobraziť ikonu novej pošty">
|
||||
<!ENTITY mail_notification_newmail_icon.accesskey "N">
|
||||
<!ENTITY mail_notification_custom_mail_icon.label "zobraziť vlastnú ikonu">
|
||||
<!ENTITY mail_notification_custom_mail_icon.accesskey "V">
|
||||
<!ENTITY mail_notification_mail_icon_custom.label "zobraziť vlastnú ikonu">
|
||||
<!ENTITY mail_notification_mail_icon_custom.accesskey "V">
|
||||
<!ENTITY icon_text_color "Farba textu">
|
||||
<!ENTITY icon_text_color.accesskey "T">
|
||||
<!ENTITY choose "Vyberte">
|
||||
@ -87,8 +87,8 @@
|
||||
<!ENTITY mail_change_trigger.accesskey "S">
|
||||
<!ENTITY mail_change_trigger.placeholder "/bin/notify-send">
|
||||
<!ENTITY mail_change_trigger.tooltip "Absolútna cesta programu, ktorý bude spustený pri zmene počtu správ. Prvý argument je počet nových správ.">
|
||||
<!ENTITY mail_urgency_hint.label "Set X11 urgency hint">
|
||||
<!ENTITY mail_urgency_hint.accesskey "X">
|
||||
<!ENTITY mail_get_attention.label "Window draws attention on new messages">
|
||||
<!ENTITY mail_get_attention.accesskey "g">
|
||||
|
||||
<!ENTITY chat_icon_enable.label "Zapnúť ikonu chatu">
|
||||
<!ENTITY chat_icon_enable.accesskey "E">
|
||||
|
@ -51,8 +51,8 @@
|
||||
<!ENTITY mail_notification_unread_count.accesskey "U">
|
||||
<!ENTITY mail_notification_newmail_icon.label "顯示新郵件圖示">
|
||||
<!ENTITY mail_notification_newmail_icon.accesskey "N">
|
||||
<!ENTITY mail_notification_custom_mail_icon.label "顯示自訂圖示">
|
||||
<!ENTITY mail_notification_custom_mail_icon.accesskey "I">
|
||||
<!ENTITY mail_notification_mail_icon_custom.label "顯示自訂圖示">
|
||||
<!ENTITY mail_notification_mail_icon_custom.accesskey "I">
|
||||
<!ENTITY icon_text_color "文字色彩">
|
||||
<!ENTITY icon_text_color.accesskey "T">
|
||||
<!ENTITY choose "選擇">
|
||||
@ -77,8 +77,8 @@
|
||||
<!ENTITY mail_change_trigger.accesskey "L">
|
||||
<!ENTITY mail_change_trigger.placeholder "/bin/notify-send">
|
||||
<!ENTITY mail_change_trigger.tooltip "要在訊息數改變時執行程式的絕對路徑。程式會將新的訊息數作為第一個參數。">
|
||||
<!ENTITY mail_urgency_hint.label "Set X11 urgency hint">
|
||||
<!ENTITY mail_urgency_hint.accesskey "X">
|
||||
<!ENTITY mail_get_attention.label "Window draws attention on new messages">
|
||||
<!ENTITY mail_get_attention.accesskey "g">
|
||||
<!ENTITY chat_icon_enable.label "啟用聊天圖示">
|
||||
<!ENTITY chat_icon_enable.accesskey "E">
|
||||
<!ENTITY chat_icon_blink.label "有新訊息時閃爍聊天圖示">
|
||||
|
BIN
src/chrome/skin/winnt/application-exit.bmp
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
src/chrome/skin/winnt/blank-icon.bmp
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
src/chrome/skin/winnt/document-new.bmp
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
src/chrome/skin/winnt/gtk-apply.bmp
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
src/chrome/skin/winnt/gtk-edit.bmp
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
src/chrome/skin/winnt/gtk-preferences.bmp
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
src/chrome/skin/winnt/mail-unread.ico
Normal file
After Width: | Height: | Size: 2.0 KiB |
@ -16,7 +16,7 @@ pref("extensions.firetray.app_icon_type", 0);
|
||||
pref("extensions.firetray.app_browser_icon_names", '["web-browser", "internet-web-browser"]');
|
||||
pref("extensions.firetray.app_mail_icon_names", '["indicator-messages", "applications-email-panel"]');
|
||||
pref("extensions.firetray.app_default_icon_names", '[]');
|
||||
pref("extensions.firetray.app_icon_filename", "");
|
||||
pref("extensions.firetray.app_icon_custom", "");
|
||||
pref("extensions.firetray.new_mail_icon_names", '["indicator-messages-new", "mail-message-new"]');
|
||||
pref("extensions.firetray.show_icon_on_hide", false);
|
||||
pref("extensions.firetray.scroll_hides", true);
|
||||
@ -25,12 +25,12 @@ pref("extensions.firetray.chat_icon_enable", true);
|
||||
pref("extensions.firetray.chat_icon_blink", true);
|
||||
pref("extensions.firetray.chat_icon_blink_style", 0);
|
||||
|
||||
pref("extensions.firetray.mail_urgency_hint", true);
|
||||
pref("extensions.firetray.mail_get_attention", true);
|
||||
pref("extensions.firetray.message_count_type", 0);
|
||||
pref("extensions.firetray.mail_notification_enabled", true);
|
||||
pref("extensions.firetray.mail_notification_type", 0);
|
||||
pref("extensions.firetray.icon_text_color", "#000000");
|
||||
pref("extensions.firetray.custom_mail_icon", "");
|
||||
pref("extensions.firetray.mail_icon_custom", "");
|
||||
pref("extensions.firetray.mail_change_trigger", "");
|
||||
pref("extensions.firetray.folder_count_recursive", true);
|
||||
// Ci.nsMsgFolderFlags.Archive|Drafts|Junk|Queue|SentMail|Trash|Virtual
|
||||
|
@ -6,7 +6,7 @@
|
||||
<em:unpack>true</em:unpack> <!-- needed for embedded icons -->
|
||||
<em:type>2</em:type>
|
||||
<em:name>FireTray</em:name>
|
||||
<em:version>0.4.8</em:version> <!-- change FIRETRAY_VERSION accordingly ! -->
|
||||
<em:version>0.5.0b1</em:version> <!-- change FIRETRAY_VERSION accordingly ! -->
|
||||
<em:creator>Hua Luo, Francesco Solero, Foudil BRÉTEL</em:creator>
|
||||
<em:contributor>Hua Luo, Francesco Solero (Firetray original authors)</em:contributor>
|
||||
<em:homepageURL>https://github.com/foudfou/firetray</em:homepageURL>
|
||||
@ -14,21 +14,22 @@
|
||||
<em:optionsURL>chrome://firetray/content/options.xul</em:optionsURL>
|
||||
<em:iconURL>chrome://firetray/skin/firetray48.png</em:iconURL>
|
||||
<em:icon64URL>chrome://firetray/skin/firetray64.png</em:icon64URL>
|
||||
<em:targetPlatform>Linux</em:targetPlatform> <!-- only Linux supported for now -->
|
||||
<em:targetPlatform>Linux</em:targetPlatform>
|
||||
<em:targetPlatform>WINNT</em:targetPlatform>
|
||||
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <!-- Firefox -->
|
||||
<em:minVersion>7.0</em:minVersion>
|
||||
<em:maxVersion>27.0</em:maxVersion>
|
||||
<em:minVersion>27.0</em:minVersion>
|
||||
<em:maxVersion>30.0</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
<em:targetApplication> <!-- Thunderbird -->
|
||||
<Description>
|
||||
<em:id>{3550f703-e582-4d05-9a08-453d09bdfdc6}</em:id>
|
||||
<em:minVersion>7.0</em:minVersion>
|
||||
<em:maxVersion>27.0</em:maxVersion>
|
||||
<em:minVersion>27.0</em:minVersion>
|
||||
<em:maxVersion>30.0</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = [ "firetray" ];
|
||||
|
||||
@ -37,8 +38,14 @@ firetray.Handler = {
|
||||
appHasChat: false,
|
||||
appStarted: false,
|
||||
windows: {},
|
||||
windowsCount: 0,
|
||||
visibleWindowsCount: 0,
|
||||
get windowsCount() {return Object.keys(this.windows).length;},
|
||||
get visibleWindowsCount() {
|
||||
let count = 0;
|
||||
for (let wid in firetray.Handler.windows) {
|
||||
if (firetray.Handler.windows[wid].visible) count += 1;
|
||||
}
|
||||
return count;
|
||||
},
|
||||
observedTopics: {},
|
||||
ctypesLibs: {}, // {"lib1": lib1, "lib2": lib2}
|
||||
|
||||
@ -46,7 +53,7 @@ firetray.Handler = {
|
||||
appName: (function(){return Services.appinfo.name;})(),
|
||||
xulVer: (function(){return Services.appinfo.platformVersion;})(), // Services.vc.compare(xulVer,"2.0a")>=0
|
||||
runtimeABI: (function(){return Services.appinfo.XPCOMABI;})(),
|
||||
runtimeOS: (function(){return Services.appinfo.OS;})(), // "WINNT", "Linux", "Darwin"
|
||||
runtimeOS: (function(){return Services.appinfo.OS.toLowerCase();})(), // "WINNT", "Linux", "Darwin"
|
||||
addonRootDir: (function(){
|
||||
let uri = Services.io.newURI(Components.stack.filename, null, null);
|
||||
if (uri instanceof Ci.nsIFileURL) {
|
||||
@ -55,6 +62,7 @@ firetray.Handler = {
|
||||
}
|
||||
throw new Error("not resolved");
|
||||
})(),
|
||||
support: {chat: false, full_feat: false},
|
||||
|
||||
init: function() { // does creates icon
|
||||
firetray.PrefListener.register(false);
|
||||
@ -62,17 +70,20 @@ firetray.Handler = {
|
||||
|
||||
// version checked during install, so we shouldn't need to care
|
||||
log.info("OS=" + this.runtimeOS + ", ABI=" + this.runtimeABI + ", XULrunner=" + this.xulVer);
|
||||
switch (this.runtimeOS) {
|
||||
case "Linux":
|
||||
Cu.import("resource://firetray/linux/FiretrayStatusIcon.jsm");
|
||||
log.debug('FiretrayStatusIcon imported');
|
||||
Cu.import("resource://firetray/linux/FiretrayWindow.jsm");
|
||||
log.debug('FiretrayWindow imported');
|
||||
break;
|
||||
default:
|
||||
log.error("FIRETRAY: only Linux platform supported at this time. Firetray not loaded");
|
||||
if (FIRETRAY_SUPPORTED_OS.indexOf(this.runtimeOS) < 0) {
|
||||
let platforms = FIRETRAY_SUPPORTED_OS.join(", ");
|
||||
log.error("Only "+platforms+" platform(s) supported at this time. Firetray not loaded");
|
||||
return false;
|
||||
}
|
||||
Cu.import("resource://firetray/"+this.runtimeOS+"/FiretrayStatusIcon.jsm");
|
||||
log.debug("FiretrayStatusIcon "+this.runtimeOS+" imported");
|
||||
Cu.import("resource://firetray/"+this.runtimeOS+"/FiretrayWindow.jsm");
|
||||
log.debug("FiretrayWindow "+this.runtimeOS+" imported");
|
||||
|
||||
this.support['chat'] = FIRETRAY_CHAT_SUPPORTED_OS
|
||||
.indexOf(this.runtimeOS) > -1;
|
||||
this.support['full_feat'] = FIRETRAY_FULL_FEAT_SUPPORTED_OS
|
||||
.indexOf(firetray.Handler.runtimeOS) > -1;
|
||||
|
||||
if (this.appId === FIRETRAY_APP_DB['thunderbird']['id'] ||
|
||||
this.appId === FIRETRAY_APP_DB['seamonkey']['id'])
|
||||
@ -108,13 +119,18 @@ firetray.Handler = {
|
||||
let chatIsProvided = this.isChatProvided();
|
||||
log.info('isChatProvided='+chatIsProvided);
|
||||
if (chatIsProvided) {
|
||||
if (this.support['chat']) {
|
||||
Cu.import("resource://firetray/FiretrayMessaging.jsm"); // needed for existsChatAccount
|
||||
Cu.import("resource://firetray/FiretrayChat.jsm");
|
||||
Cu.import("resource://firetray/"+this.runtimeOS+"/FiretrayChat.jsm");
|
||||
firetray.Utils.addObservers(firetray.Handler, [
|
||||
"account-added", "account-removed"]);
|
||||
if (firetray.Utils.prefService.getBoolPref("chat_icon_enable") &&
|
||||
this.existsChatAccount())
|
||||
firetray.Chat.init();
|
||||
} else {
|
||||
let platforms = FIRETRAY_CHAT_SUPPORTED_OS.join(", ");
|
||||
log.warn("Only "+platforms+" platform(s) supported at this time. Chat not loaded");
|
||||
}
|
||||
}
|
||||
|
||||
firetray.Utils.addObservers(firetray.Handler,
|
||||
@ -153,7 +169,8 @@ firetray.Handler = {
|
||||
|
||||
shutdown: function() {
|
||||
log.debug("Disabling Handler");
|
||||
if (firetray.Handler.isChatProvided() && firetray.Chat.initialized)
|
||||
if (firetray.Handler.isChatProvided() && firetray.Handler.support['chat']
|
||||
&& firetray.Chat.initialized)
|
||||
firetray.Chat.shutdown();
|
||||
|
||||
if (this.inMailApp)
|
||||
@ -183,7 +200,7 @@ firetray.Handler = {
|
||||
|
||||
tryCloseLibs: function() {
|
||||
try {
|
||||
for (libName in this.ctypesLibs) {
|
||||
for (let libName in this.ctypesLibs) {
|
||||
let lib = this.ctypesLibs[libName];
|
||||
if (lib.available())
|
||||
lib.close();
|
||||
@ -302,7 +319,7 @@ firetray.Handler = {
|
||||
} else {
|
||||
for (let winId in firetray.Handler.windows) {
|
||||
firetray.Chat.detachSelectListeners(firetray.Handler.windows[winId].chromeWin);
|
||||
firetray.ChatStatusIcon.detachOnFocusInCallback(winId);
|
||||
firetray.ChatStatusIcon.detachOnFocusInCallback(winId); // FIXME: to be removed
|
||||
}
|
||||
firetray.Chat.shutdown();
|
||||
}
|
||||
@ -311,19 +328,21 @@ 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() {},
|
||||
setIconVisibility: function(visible) {},
|
||||
registerWindow: function(win) {},
|
||||
unregisterWindow: function(win) {},
|
||||
getWindowIdFromChromeWindow: function(win) {},
|
||||
hideWindow: function(winId) {},
|
||||
showWindow: function(winId) {},
|
||||
showHideAllWindows: function() {},
|
||||
activateLastWindowCb: function(gtkStatusIcon, gdkEvent, userData) {},
|
||||
getActiveWindow: function() {},
|
||||
windowGetAttention: function(winId) {},
|
||||
showHidePopupMenuItems: function() {}, // linux
|
||||
addPopupWindowItemAndSeparatorMaybe: function(wid) {}, // winnt
|
||||
removePopupWindowItemAndSeparatorMaybe: function(wid) {}, // winnt
|
||||
|
||||
showAllWindows: function() {
|
||||
log.debug("showAllWindows");
|
||||
@ -340,6 +359,34 @@ firetray.Handler = {
|
||||
}
|
||||
},
|
||||
|
||||
showHideAllWindows: function() {
|
||||
log.debug("showHideAllWindows");
|
||||
log.debug(" visibleWindowsCount="+firetray.Handler.visibleWindowsCount+" / windowsCount="+firetray.Handler.windowsCount);
|
||||
let visibilityRate = firetray.Handler.visibleWindowsCount /
|
||||
firetray.Handler.windowsCount;
|
||||
log.debug(" visibilityRate="+visibilityRate);
|
||||
if ((0.5 < visibilityRate) && (visibilityRate < 1)
|
||||
|| visibilityRate === 0) { // TODO: should be configurable
|
||||
firetray.Handler.showAllWindows();
|
||||
} else {
|
||||
firetray.Handler.hideAllWindows();
|
||||
}
|
||||
},
|
||||
|
||||
onMinimize: function(wid) {
|
||||
let hidden = false;
|
||||
let hides_on_minimize = firetray.Utils.prefService.getBoolPref('hides_on_minimize');
|
||||
if (hides_on_minimize) {
|
||||
let hides_single_window = firetray.Utils.prefService.getBoolPref('hides_single_window');
|
||||
if (hides_single_window)
|
||||
firetray.Handler.hideWindow(wid);
|
||||
else
|
||||
firetray.Handler.hideAllWindows();
|
||||
hidden = true;
|
||||
}
|
||||
return hidden;
|
||||
},
|
||||
|
||||
showHideIcon: function() {
|
||||
if (firetray.Utils.prefService.getBoolPref('show_icon_on_hide'))
|
||||
firetray.Handler.setIconVisibility(
|
||||
@ -471,7 +518,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();
|
||||
@ -488,19 +535,27 @@ firetray.PrefListener = new PrefListener(
|
||||
firetray.Handler.setIconImageDefault();
|
||||
}
|
||||
break;
|
||||
case 'mail_notification_type':
|
||||
case 'icon_text_color':
|
||||
firetray.Messaging.updateIcon();
|
||||
break;
|
||||
case 'new_mail_icon_names':
|
||||
firetray.StatusIcon.loadThemedIcons();
|
||||
case 'only_favorite_folders':
|
||||
case 'message_count_type':
|
||||
case 'excluded_folders_flags':
|
||||
case 'folder_count_recursive':
|
||||
case 'mail_accounts':
|
||||
case 'message_count_type':
|
||||
case 'only_favorite_folders':
|
||||
firetray.Messaging.updateMsgCountWithCb();
|
||||
break;
|
||||
case 'app_mail_icon_names':
|
||||
case 'app_browser_icon_names':
|
||||
case 'app_default_icon_names':
|
||||
firetray.StatusIcon.loadThemedIcons(); // linux
|
||||
case 'app_icon_custom':
|
||||
case 'mail_icon_custom':
|
||||
firetray.StatusIcon.loadImageCustom(name);
|
||||
case 'app_icon_type':
|
||||
firetray.StatusIcon.loadThemedIcons();
|
||||
case 'app_icon_filename':
|
||||
firetray.Handler.setIconImageDefault();
|
||||
if (firetray.Handler.inMailApp)
|
||||
firetray.Messaging.updateMsgCountWithCb();
|
||||
@ -542,13 +597,14 @@ firetray.MailChatPrefListener = new PrefListener(
|
||||
case 'enabled':
|
||||
let enableChatCond =
|
||||
(firetray.Handler.appHasChat &&
|
||||
firetray.Utils.prefService.getBoolPref("chat_icon_enable"));
|
||||
firetray.Utils.prefService.getBoolPref("chat_icon_enable") &&
|
||||
firetray.Handler.support['chat']);
|
||||
if (!enableChatCond) return;
|
||||
|
||||
if (Services.prefs.getBoolPref("mail.chat.enabled")) {
|
||||
if (!firetray.Chat) {
|
||||
Cu.import("resource://firetray/FiretrayMessaging.jsm"); // needed for existsChatAccount
|
||||
Cu.import("resource://firetray/FiretrayChat.jsm");
|
||||
Cu.import("resource://firetray/linux/FiretrayChat.jsm");
|
||||
firetray.Utils.addObservers(firetray.Handler, [
|
||||
"account-added", "account-removed"]);
|
||||
}
|
||||
@ -642,7 +698,7 @@ firetray.VersionChangeHandler = {
|
||||
},
|
||||
|
||||
tryEraseOldOptions: function() {
|
||||
let v03Options = [
|
||||
let v0_3_Opts = [
|
||||
"close_to_tray", "minimize_to_tray", "start_minimized", "confirm_exit",
|
||||
"restore_to_next_unread", "mail_count_type", "show_mail_count",
|
||||
"dont_count_spam", "dont_count_archive", "dont_count_drafts",
|
||||
@ -651,12 +707,13 @@ firetray.VersionChangeHandler = {
|
||||
"use_custom_special_icon", "custom_normal_icon", "custom_special_icon",
|
||||
"text_color", "scroll_to_hide", "scroll_action", "grab_multimedia_keys",
|
||||
"hide_show_mm_key", "accounts_to_exclude" ];
|
||||
let v040b2Options = [ 'mail_notification' ];
|
||||
let oldOptions = v03Options.concat(v040b2Options);
|
||||
let v0_4_0b2_Opts = [ 'mail_notification' ];
|
||||
let v0_5_0b1_Opts = [ 'mail_urgency_hint', 'app_icon_filename', 'custom_mail_icon' ];
|
||||
let oldOpts = v0_3_Opts.concat(v0_4_0b2_Opts).concat(v0_5_0b1_Opts);
|
||||
|
||||
for (let i = 0, length = oldOptions.length; i<length; ++i) {
|
||||
for (let i = 0, length = oldOpts.length; i<length; ++i) {
|
||||
try {
|
||||
let option = oldOptions[i];
|
||||
let option = oldOpts[i];
|
||||
firetray.Utils.prefService.clearUserPref(option);
|
||||
} catch (x) {}
|
||||
}
|
||||
|
@ -13,14 +13,14 @@ Cu.import("resource://gre/modules/PluralForm.jsm");
|
||||
Cu.import("resource://firetray/commons.js");
|
||||
|
||||
const FLDRS_UNINTERESTING = {
|
||||
Archive: Ci.nsMsgFolderFlags.Archive,
|
||||
Drafts: Ci.nsMsgFolderFlags.Drafts,
|
||||
Junk: Ci.nsMsgFolderFlags.Junk,
|
||||
Queue: Ci.nsMsgFolderFlags.Queue,
|
||||
SentMail: Ci.nsMsgFolderFlags.SentMail,
|
||||
Templates: Ci.nsMsgFolderFlags.Templates,
|
||||
Trash: Ci.nsMsgFolderFlags.Trash,
|
||||
Virtual: Ci.nsMsgFolderFlags.Virtual
|
||||
Archive: Ci.nsMsgFolderFlags.Archive, // 0x00004000
|
||||
Drafts: Ci.nsMsgFolderFlags.Drafts, // 0x00000400
|
||||
Junk: Ci.nsMsgFolderFlags.Junk, // 0x40000000
|
||||
Queue: Ci.nsMsgFolderFlags.Queue, // 0x00000800
|
||||
SentMail: Ci.nsMsgFolderFlags.SentMail, // 0x00000200
|
||||
Templates: Ci.nsMsgFolderFlags.Templates, // 0x00400000
|
||||
Trash: Ci.nsMsgFolderFlags.Trash, // 0x00000100
|
||||
Virtual: Ci.nsMsgFolderFlags.Virtual // 0x00000020
|
||||
};
|
||||
|
||||
const ACCOUNTS_PREF_BRANCH = "mail.accountmanager.accounts";
|
||||
@ -73,8 +73,7 @@ firetray.Messaging = {
|
||||
|
||||
/* could also use a PrefListener, but let's keep it simple for now */
|
||||
observe: function(subject, topic, data) {
|
||||
if (topic === "nsPref:changed" &&
|
||||
data === ACCOUNTS_PREF_BRANCH) {
|
||||
if (topic === "nsPref:changed" && data === ACCOUNTS_PREF_BRANCH) {
|
||||
log.debug(ACCOUNTS_PREF_BRANCH+"="+subject.QueryInterface(Ci.nsIPrefBranch).getCharPref(ACCOUNTS_PREF_BRANCH));
|
||||
this.cleanExcludedAccounts();
|
||||
}
|
||||
@ -183,10 +182,10 @@ firetray.Messaging = {
|
||||
if (mailChangeTriggerFile)
|
||||
firetray.Messaging.runProcess(mailChangeTriggerFile, [newMsgCount.toString()]);
|
||||
|
||||
let setUrgency = firetray.Utils.prefService.getBoolPref("mail_urgency_hint");
|
||||
if (setUrgency && (newMsgCount > currentMsgCount))
|
||||
let getAttention = firetray.Utils.prefService.getBoolPref("mail_get_attention");
|
||||
if (getAttention && (newMsgCount > currentMsgCount))
|
||||
for (let winId in firetray.Handler.windows)
|
||||
firetray.Window.setUrgency(winId, true);
|
||||
firetray.Handler.windowGetAttention(winId);
|
||||
}
|
||||
};
|
||||
|
||||
@ -206,6 +205,7 @@ firetray.Messaging = {
|
||||
},
|
||||
|
||||
updateIcon: function(msgCount) {
|
||||
log.debug("updateIcon");
|
||||
if ("undefined" === typeof(msgCount)) msgCount = this.currentMsgCount;
|
||||
|
||||
let localizedTooltip;
|
||||
@ -227,6 +227,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");
|
||||
@ -236,8 +237,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('mail_icon_custom');
|
||||
break;
|
||||
default:
|
||||
log.error("Unknown notification mode: "+prefMailNotification);
|
||||
|
43
src/modules/FiretrayWindow.jsm
Normal file
@ -0,0 +1,43 @@
|
||||
/* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
// https://developer.mozilla.org/en/Code_snippets/Preferences
|
||||
|
||||
var EXPORTED_SYMBOLS = [ "FiretrayWindow" ];
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://firetray/commons.js");
|
||||
|
||||
let log = firetray.Logging.getLogger("firetray.FiretrayWindow");
|
||||
|
||||
if ("undefined" == typeof(firetray.Handler))
|
||||
log.error("This module MUST be imported from/after FiretrayHandler !");
|
||||
|
||||
function FiretrayWindow () {}
|
||||
FiretrayWindow.prototype = {
|
||||
|
||||
getRegisteredWinIdFromChromeWindow: function(win) {
|
||||
for (let wid in firetray.Handler.windows)
|
||||
if (firetray.Handler.windows[wid].chromeWin === win) return wid;
|
||||
log.error("unknown window while lookup");
|
||||
return null;
|
||||
},
|
||||
|
||||
getWindowTitle: function(wid) {
|
||||
let title = firetray.Handler.windows[wid].baseWin.title;
|
||||
log.debug("|baseWin.title="+title+"|");
|
||||
let tailIndex;
|
||||
tailIndex = title.indexOf(" - Mozilla "+firetray.Handler.appName);
|
||||
if (tailIndex === -1)
|
||||
tailIndex = title.indexOf(" - "+firetray.Handler.appName);
|
||||
|
||||
if (tailIndex !== -1)
|
||||
return title.substring(0, tailIndex);
|
||||
else if (title === "Mozilla "+firetray.Handler.appName)
|
||||
return title;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
@ -3,20 +3,20 @@
|
||||
/* for now, logging facilities (imported from logging.jsm) and Services are
|
||||
automatically provided by this module */
|
||||
var EXPORTED_SYMBOLS =
|
||||
[ "firetray", "FIRETRAY_ID", "FIRETRAY_VERSION", "FIRETRAY_PREF_BRANCH",
|
||||
"FIRETRAY_SPLASH_PAGE", "FIRETRAY_APPLICATION_ICON_TYPE_THEMED",
|
||||
[ "firetray", "FIRETRAY_VERSION", "FIRETRAY_SUPPORTED_OS",
|
||||
"FIRETRAY_CHAT_SUPPORTED_OS", "FIRETRAY_FULL_FEAT_SUPPORTED_OS",
|
||||
"FIRETRAY_ID", "FIRETRAY_PREF_BRANCH", "FIRETRAY_SPLASH_PAGE",
|
||||
"FIRETRAY_APPLICATION_ICON_TYPE_THEMED",
|
||||
"FIRETRAY_APPLICATION_ICON_TYPE_CUSTOM",
|
||||
"FIRETRAY_NOTIFICATION_MESSAGE_COUNT",
|
||||
"FIRETRAY_NOTIFICATION_NEWMAIL_ICON", "FIRETRAY_NOTIFICATION_CUSTOM_ICON",
|
||||
"FIRETRAY_IM_STATUS_AVAILABLE", "FIRETRAY_IM_STATUS_AWAY",
|
||||
"FIRETRAY_IM_STATUS_BUSY", "FIRETRAY_IM_STATUS_OFFLINE",
|
||||
"FIRETRAY_ACCOUNT_SERVER_TYPE_IM",
|
||||
"FIRETRAY_DELAY_STARTUP_MILLISECONDS",
|
||||
"FIRETRAY_DELAY_NOWAIT_MILLISECONDS",
|
||||
"FIRETRAY_MESSAGE_COUNT_TYPE_UNREAD", "FIRETRAY_MESSAGE_COUNT_TYPE_NEW",
|
||||
"FIRETRAY_CHAT_ICON_BLINK_STYLE_NORMAL",
|
||||
"FIRETRAY_CHAT_ICON_BLINK_STYLE_FADE",
|
||||
"FIRETRAY_APP_DB" ];
|
||||
"FIRETRAY_ACCOUNT_SERVER_TYPE_IM", "FIRETRAY_DELAY_STARTUP_MILLISECONDS",
|
||||
"FIRETRAY_DELAY_NOWAIT_MILLISECONDS", "FIRETRAY_MESSAGE_COUNT_TYPE_UNREAD",
|
||||
"FIRETRAY_MESSAGE_COUNT_TYPE_NEW", "FIRETRAY_CHAT_ICON_BLINK_STYLE_NORMAL",
|
||||
"FIRETRAY_CHAT_ICON_BLINK_STYLE_FADE", "FIRETRAY_APP_DB",
|
||||
"FIRETRAY_XUL_ATTRIBUTE_COMMAND", "FIRETRAY_XUL_ATTRIBUTE_ONCOMMAND" ];
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
@ -25,7 +25,10 @@ const Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://firetray/logging.jsm");
|
||||
|
||||
const FIRETRAY_VERSION = "0.4.8"; // needed for sync call of onVersionChange() :(
|
||||
const FIRETRAY_VERSION = "0.5.0b1"; // needed for sync call of onVersionChange() :(
|
||||
const FIRETRAY_SUPPORTED_OS = ['linux', 'winnt']; // install.rdf sync :(
|
||||
const FIRETRAY_CHAT_SUPPORTED_OS = ['linux'];
|
||||
const FIRETRAY_FULL_FEAT_SUPPORTED_OS = FIRETRAY_CHAT_SUPPORTED_OS;
|
||||
const FIRETRAY_ID = "{9533f794-00b4-4354-aa15-c2bbda6989f8}";
|
||||
const FIRETRAY_PREF_BRANCH = "extensions.firetray.";
|
||||
const FIRETRAY_SPLASH_PAGE = "http://foudfou.github.com/FireTray/";
|
||||
@ -53,6 +56,9 @@ const FIRETRAY_DELAY_NOWAIT_MILLISECONDS = 0;
|
||||
const FIRETRAY_CHAT_ICON_BLINK_STYLE_NORMAL = 0;
|
||||
const FIRETRAY_CHAT_ICON_BLINK_STYLE_FADE = 1;
|
||||
|
||||
const FIRETRAY_XUL_ATTRIBUTE_COMMAND = 0;
|
||||
const FIRETRAY_XUL_ATTRIBUTE_ONCOMMAND = 1;
|
||||
|
||||
const FIRETRAY_APP_DB = {
|
||||
|
||||
firefox: {
|
||||
@ -72,7 +78,7 @@ const FIRETRAY_APP_DB = {
|
||||
},
|
||||
|
||||
sunbird: {
|
||||
id: "718e30fb-e89b-41dd-9da7-e25a45638b28}",
|
||||
id: "{718e30fb-e89b-41dd-9da7-e25a45638b28}",
|
||||
},
|
||||
|
||||
chatzilla: {
|
||||
@ -144,11 +150,13 @@ firetray.Utils = {
|
||||
|
||||
getArrayPref: function(prefStr) {
|
||||
let arrayPref = this.getObjPref(prefStr);
|
||||
if (!firetray.js.isArray(arrayPref)) throw new TypeError();
|
||||
if (!firetray.js.isArray(arrayPref))
|
||||
throw new TypeError("'"+prefStr+"' preference is not array.");
|
||||
return arrayPref;
|
||||
},
|
||||
setArrayPref: function(prefStr, aArray) {
|
||||
if (!firetray.js.isArray(aArray)) throw new TypeError();
|
||||
if (!firetray.js.isArray(aArray))
|
||||
throw new TypeError("'"+aArray+"' is not array.");
|
||||
this.setObjPref(prefStr, aArray);
|
||||
},
|
||||
|
||||
@ -189,11 +197,11 @@ firetray.Utils = {
|
||||
|
||||
dumpObj: function(obj) {
|
||||
let str = "";
|
||||
for(i in obj) {
|
||||
for(let prop in firetray.js.listAllProperties(obj)) {
|
||||
try {
|
||||
str += "obj["+i+"]: " + obj[i] + "\n";
|
||||
str += "obj["+prop+"]: " + obj[prop] + "\n";
|
||||
} catch(e) {
|
||||
str += "obj["+i+"]: Unavailable\n";
|
||||
str += "obj["+prop+"]: Unavailable\n";
|
||||
}
|
||||
}
|
||||
log.info(str);
|
||||
@ -262,6 +270,17 @@ firetray.Utils = {
|
||||
timer.initWithCallback({ notify: callback },
|
||||
delay, timerType);
|
||||
return timer;
|
||||
},
|
||||
|
||||
/*
|
||||
* Extracts statements from functions. Intended for feeding a 'oncommand'
|
||||
* attribute.
|
||||
* BUG: |let| assignations break oncommand inline callback under TB27
|
||||
* The statements should probably be limited to a single function call.
|
||||
*/
|
||||
bodyToString: function(func) {
|
||||
let matches = func.toSource().match(/\{([\s\S]*)\}/m);
|
||||
return matches ? matches[1] : matches;
|
||||
}
|
||||
|
||||
};
|
||||
@ -291,7 +310,26 @@ firetray.js = {
|
||||
// https://developer.mozilla.org/en/js-ctypes/Using_js-ctypes/Working_with_data#Quirks_in_equality
|
||||
strEquals: function(obj1, obj2) {
|
||||
return obj1.toString() === obj2.toString();
|
||||
},
|
||||
|
||||
assert: function(condition, message) {
|
||||
if (!condition) {
|
||||
throw new Error(message || "Assertion failed");
|
||||
}
|
||||
},
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#Enumerating_all_properties_of_an_object
|
||||
listAllProperties: function(obj){
|
||||
var objectToInspect;
|
||||
var result = [];
|
||||
for(objectToInspect = obj; objectToInspect !== null; objectToInspect = Object.getPrototypeOf(objectToInspect)){
|
||||
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
|
||||
|
@ -36,13 +36,18 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
var EXPORTED_SYMBOLS = [ "ctypes_library", "is64bit", "WinCbABI" ];
|
||||
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/ctypes.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://firetray/logging.jsm");
|
||||
|
||||
var EXPORTED_SYMBOLS = [ "ctypes_library" ];
|
||||
const is64bit = ctypes.size_t.size == 8; // firetray.Handler.runtimeABI.indexOf('_64') > -1;
|
||||
|
||||
const WinABI = is64bit ? ctypes.default_abi : ctypes.winapi_abi;
|
||||
const WinCbABI = is64bit ? ctypes.default_abi : ctypes.stdcall_abi;
|
||||
|
||||
let log = firetray.Logging.getLogger("firetray.ctypes-utils");
|
||||
|
||||
@ -111,7 +116,10 @@ function ctypes_library(aName, aABIs, aDefines, aGlobal) {
|
||||
|
||||
var library;
|
||||
for each (let abi in aABIs) {
|
||||
let soname = "lib" + aName + ".so." + abi.toString();
|
||||
// FIXME: ABI is in fact SO_VER. Now we're mixing .so versions and the
|
||||
// .dll extension :(
|
||||
let soname = abi === 'dll' ? aName :
|
||||
"lib" + aName + ".so." + abi.toString();
|
||||
log.debug("Trying " + soname);
|
||||
try {
|
||||
library = ctypes.open(soname);
|
||||
@ -155,7 +163,12 @@ function ctypes_library(aName, aABIs, aDefines, aGlobal) {
|
||||
try {
|
||||
args = [];
|
||||
args.push(arguments[0]);
|
||||
// FIXME: ugly hack. We'll see when we need WinCbABI
|
||||
if (this.ABI === 'dll') {
|
||||
args.push(WinABI);
|
||||
} else {
|
||||
args.push(ctypes.default_abi);
|
||||
}
|
||||
for each (let arg in Array.prototype.slice.call(arguments, 1)) {
|
||||
args.push(arg);
|
||||
}
|
||||
|
@ -32,6 +32,10 @@ ctypesMap.prototype.get = function(key) {
|
||||
return this.array[this.map[key]];
|
||||
};
|
||||
|
||||
Object.defineProperties(ctypesMap.prototype, {
|
||||
"keys": {get: function(){return Object.keys(this.map);} }
|
||||
});
|
||||
|
||||
ctypesMap.prototype.insert = function(key, item) {
|
||||
if (this.map.hasOwnProperty(key)) {
|
||||
log.debug("REPLACE");
|
||||
|
@ -145,6 +145,7 @@ function gtk_defines(lib) {
|
||||
|
||||
lib.lazy_bind("gtk_widget_is_focus", gobject.gboolean, this.GtkWidget.ptr);
|
||||
lib.lazy_bind("gtk_widget_has_focus", gobject.gboolean, this.GtkWidget.ptr);
|
||||
lib.lazy_bind("gtk_widget_get_visible", gobject.gboolean, this.GtkWidget.ptr);
|
||||
lib.lazy_bind("gtk_widget_hide_on_delete", gobject.gboolean, this.GtkWidget.ptr);
|
||||
lib.lazy_bind("gtk_widget_hide", ctypes.void_t, this.GtkWidget.ptr);
|
||||
lib.lazy_bind("gtk_widget_show", ctypes.void_t, this.GtkWidget.ptr);
|
||||
|
182
src/modules/ctypes/winnt/gdi32.jsm
Normal file
@ -0,0 +1,182 @@
|
||||
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("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);
|
||||
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;
|
||||
this.DEFAULT_QUALITY = 0;
|
||||
this.DRAFT_QUALITY = 1;
|
||||
this.PROOF_QUALITY = 2;
|
||||
this.NONANTIALIASED_QUALITY = 3;
|
||||
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);
|
||||
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);
|
||||
|
||||
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;
|
||||
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);
|
||||
|
||||
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);
|
49
src/modules/ctypes/winnt/kernel32.jsm
Normal file
@ -0,0 +1,49 @@
|
||||
var EXPORTED_SYMBOLS = [ "kernel32" ];
|
||||
|
||||
const KERNEL32_LIBNAME = "kernel32";
|
||||
const KERNEL32_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 kernel32_defines(lib) {
|
||||
|
||||
this.OSVERSIONINFOEXW = ctypes.StructType("OSVERSIONINFOEXW", [
|
||||
{ "dwOSVersionInfoSize": win32.DWORD },
|
||||
{ "dwMajorVersion": win32.DWORD },
|
||||
{ "dwMinorVersion": win32.DWORD },
|
||||
{ "dwBuildNumber": win32.DWORD },
|
||||
{ "dwPlatformId": win32.DWORD },
|
||||
{ "szCSDVersion": ctypes.ArrayType(win32.TCHAR, 128) },
|
||||
{ "wServicePackMajor": win32.WORD },
|
||||
{ "wServicePackMinor": win32.WORD },
|
||||
{ "wSuiteMask": win32.WORD },
|
||||
{ "wProductType": win32.BYTE },
|
||||
{ "wReserved": win32.BYTE }
|
||||
]);
|
||||
|
||||
// lib.lazy_bind("GetLastError", win32.DWORD); // use ctypes.winLastError instead
|
||||
lib.lazy_bind("GetVersionExW", win32.BOOL, this.OSVERSIONINFOEXW.ptr);
|
||||
lib.lazy_bind("GetConsoleWindow", win32.HWND);
|
||||
lib.lazy_bind("GetConsoleTitleW", win32.DWORD, win32.LPTSTR, win32.DWORD);
|
||||
lib.lazy_bind("GetModuleHandleW", win32.HMODULE, win32.LPCTSTR);
|
||||
|
||||
lib.lazy_bind("LoadLibraryW", win32.HMODULE, win32.LPCTSTR);
|
||||
lib.lazy_bind("GetProcAddress", win32.FARPROC, win32.HMODULE, win32.LPCSTR);
|
||||
lib.lazy_bind("GetCurrentThreadId", win32.DWORD);
|
||||
|
||||
}
|
||||
|
||||
new ctypes_library(KERNEL32_LIBNAME, KERNEL32_ABIS, kernel32_defines, this);
|
||||
|
||||
|
||||
let osvi = new kernel32.OSVERSIONINFOEXW();
|
||||
osvi.dwOSVersionInfoSize = kernel32.OSVERSIONINFOEXW.size;
|
||||
if (kernel32.GetVersionExW(osvi.address())) {
|
||||
win32.WINVER = (+osvi.dwMajorVersion)*10 + (+osvi.dwMinorVersion); // ctypes.UInt64 objects!
|
||||
} else {
|
||||
Cu.reportError("win version not found");
|
||||
}
|
96
src/modules/ctypes/winnt/shell32.jsm
Normal file
@ -0,0 +1,96 @@
|
||||
var EXPORTED_SYMBOLS = [ "shell32" ];
|
||||
|
||||
const SHELL32_LIBNAME = "shell32";
|
||||
const SHELL32_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 shell32_defines(lib) {
|
||||
|
||||
this.NOTIFYICONDATAW = ctypes.StructType("NOTIFYICONDATAW", [
|
||||
{ "cbSize": win32.DWORD },
|
||||
{ "hWnd": win32.HWND },
|
||||
{ "uID": win32.UINT },
|
||||
{ "uFlags": win32.UINT },
|
||||
{ "uCallbackMessage": win32.UINT },
|
||||
{ "hIcon": win32.HICON },
|
||||
{ "szTip": ctypes.ArrayType(win32.TCHAR, 128) },
|
||||
{ "dwState": win32.DWORD },
|
||||
{ "dwStateMask": win32.DWORD },
|
||||
{ "szInfo": ctypes.ArrayType(win32.TCHAR, 256) },
|
||||
{ "uTimeoutOrVersion": win32.UINT }, // union
|
||||
{ "szInfoTitle": ctypes.ArrayType(win32.TCHAR, 64) },
|
||||
{ "dwInfoFlags": win32.DWORD },
|
||||
{ "guidItem": win32.GUID },
|
||||
{ "hBalloonIcon": win32.HICON }
|
||||
]);
|
||||
this.NOTIFY_VERSION = 3; // 2K+
|
||||
this.NOTIFYICON_VERSION_4 = 4; // Vista+
|
||||
|
||||
// #define FIELD_OFFSET(t,f) ((LONG)&(((t*)0)->f))
|
||||
function FIELD_OFFSET(aType, aField, aPos) {
|
||||
function addr2nb(a) {
|
||||
return ctypes.cast(a, ctypes.unsigned_long).value;
|
||||
}
|
||||
|
||||
// 'would be nice to use aType.ptr(1) (0 raises null pointer error) but we
|
||||
// can't access fields (or their size) from a StructType.
|
||||
let s = new aType();
|
||||
let addr_base = addr2nb(s.address());
|
||||
let addr_field;
|
||||
if (typeof(aPos) == "undefined") {
|
||||
addr_field = addr2nb(s.addressOfField(aField)); // s[aField].address() also fine
|
||||
} else {
|
||||
addr_field = addr2nb(s[aField].addressOfElement(aPos)); // pfew! nice feature!
|
||||
}
|
||||
return addr_field - addr_base;
|
||||
}
|
||||
|
||||
this.NOTIFYICONDATAW_V1_SIZE = FIELD_OFFSET(this.NOTIFYICONDATAW, 'szTip', 64); // FIELD_OFFSET(NOTIFYICONDATAW, szTip[64])
|
||||
this.NOTIFYICONDATAW_V2_SIZE = FIELD_OFFSET(this.NOTIFYICONDATAW, 'guidItem'); // 2K
|
||||
this.NOTIFYICONDATAW_V3_SIZE = FIELD_OFFSET(this.NOTIFYICONDATAW, 'hBalloonIcon'); // XP
|
||||
|
||||
this.NOTIFYICONDATAW_SIZE = function() {
|
||||
let cbSize = this.NOTIFYICONDATAW.size;
|
||||
if (!win32.WINVER) {
|
||||
Cu.reportError("WINVER not defined! shell32 should be initialized before using WINVER.");
|
||||
} else if (win32.WINVER >= win32.WIN_VERSIONS["Vista"]) {
|
||||
cbSize = this.NOTIFYICONDATAW.size;
|
||||
} else if (win32.WINVER >= win32.WIN_VERSIONS["XP"]) {
|
||||
cbSize = this.NOTIFYICONDATAW_V3_SIZE;
|
||||
} else if (win32.WINVER >= win32.WIN_VERSIONS["2K"]) {
|
||||
cbSize = this.NOTIFYICONDATAW_V2_SIZE;
|
||||
} else {
|
||||
cbSize = this.NOTIFYICONDATAW_V1_SIZE;
|
||||
}
|
||||
return cbSize;
|
||||
};
|
||||
|
||||
lib.lazy_bind("Shell_NotifyIconW", win32.BOOL, win32.DWORD, this.NOTIFYICONDATAW.ptr);
|
||||
|
||||
// notify icon message
|
||||
this.NIM_ADD = 0x00000000;
|
||||
this.NIM_MODIFY = 0x00000001;
|
||||
this.NIM_DELETE = 0x00000002;
|
||||
this.NIM_SETFOCUS = 0x00000003;
|
||||
this.NIM_SETVERSION = 0x00000004;
|
||||
|
||||
// for NOTIFYICONDATAW.uFlags
|
||||
this.NIF_MESSAGE = 0x00000001;
|
||||
this.NIF_ICON = 0x00000002;
|
||||
this.NIF_TIP = 0x00000004;
|
||||
this.NIF_STATE = 0x00000008;
|
||||
this.NIF_INFO = 0x00000010;
|
||||
this.NIF_GUID = 0x00000020;
|
||||
this.NIF_REALTIME = 0x00000040;
|
||||
this.NIF_SHOWTIP = 0x00000080;
|
||||
|
||||
lib.lazy_bind("ExtractIconW", win32.HICON, win32.HINSTANCE, win32.LPCTSTR, win32.UINT);
|
||||
lib.lazy_bind("ExtractIconExW", win32.UINT, win32.LPCTSTR, ctypes.int, win32.HICON.ptr, win32.HICON.ptr, win32.UINT);
|
||||
}
|
||||
|
||||
new ctypes_library(SHELL32_LIBNAME, SHELL32_ABIS, shell32_defines, this);
|
380
src/modules/ctypes/winnt/user32.jsm
Normal file
@ -0,0 +1,380 @@
|
||||
var EXPORTED_SYMBOLS = [ "user32" ];
|
||||
|
||||
const USER32_LIBNAME = "user32";
|
||||
const USER32_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 user32_defines(lib) {
|
||||
|
||||
this.CHANGEFILTERSTRUCT = ctypes.StructType("CHANGEFILTERSTRUCT", [
|
||||
{ "cbSize": win32.DWORD },
|
||||
{ "ExtStatus": win32.DWORD }
|
||||
]);
|
||||
this.MSGFLTINFO_NONE = 0;
|
||||
this.MSGFLTINFO_ALLOWED_HIGHER = 3;
|
||||
this.MSGFLTINFO_ALREADYALLOWED_FORWND = 1;
|
||||
this.MSGFLTINFO_ALREADYDISALLOWED_FORWND = 2;
|
||||
|
||||
lib.lazy_bind("ChangeWindowMessageFilter", win32.BOOL, win32.UINT, win32.DWORD);
|
||||
this.MSGFLT_ADD = 1;
|
||||
this.MSGFLT_REMOVE = 2;
|
||||
lib.lazy_bind("ChangeWindowMessageFilterEx", win32.BOOL, win32.HWND, win32.UINT, win32.DWORD, this.CHANGEFILTERSTRUCT.ptr);
|
||||
this.MSGFLT_ALLOW = 1;
|
||||
this.MSGFLT_DISALLOW = 2;
|
||||
this.MSGFLT_RESET = 0;
|
||||
|
||||
lib.lazy_bind("RegisterWindowMessageW", win32.UINT, win32.LPCTSTR);
|
||||
lib.lazy_bind("GetWindowTextW", ctypes.int, win32.HWND, win32.LPTSTR, ctypes.int);
|
||||
lib.lazy_bind("FindWindowW", win32.HWND, win32.LPCTSTR, win32.LPCTSTR);
|
||||
|
||||
lib.lazy_bind("SendMessageW", win32.LRESULT, win32.HWND, win32.UINT, win32.WPARAM, win32.LPARAM);
|
||||
this.WM_GETICON = 0x007F;
|
||||
this.WM_SETICON = 0x0080;
|
||||
this.ICON_SMALL = 0;
|
||||
this.ICON_BIG = 1;
|
||||
this.ICON_SMALL2 = 2;
|
||||
|
||||
lib.lazy_bind("GetClassLongPtrW", win32.ULONG_PTR, win32.HWND, ctypes.int);
|
||||
lib.lazy_bind("GetClassLongW", win32.DWORD, win32.HWND, ctypes.int); // 32-bits
|
||||
this.GetClassLong = is64bit ? this.GetClassLongPtrW : this.GetClassLongW;
|
||||
this.GCLP_HICONSM = -34;
|
||||
|
||||
lib.lazy_bind("LoadIconW", win32.HICON, win32.HINSTANCE, win32.LPCTSTR); // superseeded by LoadImage
|
||||
this.IDI_APPLICATION = win32.MAKEINTRESOURCE(32512);
|
||||
this.IDI_HAND = win32.MAKEINTRESOURCE(32513);
|
||||
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;
|
||||
this.IMAGE_CURSOR = 2;
|
||||
this.LR_CREATEDIBSECTION = 0x00002000;
|
||||
this.LR_DEFAULTCOLOR = 0x00000000;
|
||||
this.LR_DEFAULTSIZE = 0x00000040;
|
||||
this.LR_LOADFROMFILE = 0x00000010;
|
||||
this.LR_LOADMAP3DCOLORS = 0x00001000;
|
||||
this.LR_LOADTRANSPARENT = 0x00000020;
|
||||
this.LR_MONOCHROME = 0x00000001;
|
||||
this.LR_SHARED = 0x00008000;
|
||||
this.LR_VGACOLOR = 0x00000080;
|
||||
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);
|
||||
lib.lazy_bind("RemovePropW", win32.HANDLE, win32.HWND, win32.LPCTSTR);
|
||||
|
||||
lib.lazy_bind("GetWindowLongW", win32.LONG_PTR, win32.HWND, ctypes.int);
|
||||
lib.lazy_bind("SetWindowLongW", win32.LONG_PTR , win32.HWND, ctypes.int, win32.LONG_PTR);
|
||||
// SetWindowLongPtrW aliases SetWindowLongW with the correct signature thank
|
||||
// win32.LONG_PTR
|
||||
this.GWLP_WNDPROC = -4;
|
||||
this.GWLP_HINSTANCE = -6;
|
||||
this.GWLP_ID = -12;
|
||||
this.GWL_STYLE = -16;
|
||||
this.GWL_EXSTYLE = -20;
|
||||
this.GWLP_USERDATA = -21;
|
||||
lib.lazy_bind("SetClassLongW", win32.DWORD , win32.HWND, ctypes.int, win32.LONG); // superseeded by SetClassLongPtrW
|
||||
this.GCL_MENUNAME = -8;
|
||||
this.GCL_HBRBACKGROUND = -10;
|
||||
this.GCL_HCURSOR = -12;
|
||||
this.GCL_HICON = -14;
|
||||
this.GCL_HMODULE = -16;
|
||||
this.GCL_CBWNDEXTRA = -18;
|
||||
this.GCL_CBCLSEXTRA = -20;
|
||||
this.GCL_WNDPROC = -24;
|
||||
this.GCL_HICONSM = -34;
|
||||
|
||||
this.WNDPROC = ctypes.FunctionType(
|
||||
WinCbABI, win32.LRESULT,
|
||||
[win32.HWND, win32.UINT, win32.WPARAM, win32.LPARAM]).ptr;
|
||||
|
||||
// lib.lazy_bind("CallWindowProcW", win32.LRESULT, this.WNDPROC, win32.HWND, win32.UINT, win32.WPARAM, win32.LPARAM);
|
||||
lib.lazy_bind("CallWindowProcW", win32.LRESULT, ctypes.voidptr_t, win32.HWND, win32.UINT, win32.WPARAM, win32.LPARAM);
|
||||
lib.lazy_bind("DefWindowProcW", win32.LRESULT, win32.HWND, win32.UINT, win32.WPARAM, win32.LPARAM);
|
||||
|
||||
this.WNDCLASSEXW = ctypes.StructType("WNDCLASSEXW", [
|
||||
{ "cbSize": win32.UINT },
|
||||
{ "style": win32.UINT },
|
||||
{ "lpfnWndProc": this.WNDPROC },
|
||||
{ "cbClsExtra": ctypes.int },
|
||||
{ "cbWndExtra": ctypes.int },
|
||||
{ "hInstance": win32.HINSTANCE },
|
||||
{ "hIcon": win32.HICON },
|
||||
{ "hCursor": win32.HCURSOR },
|
||||
{ "hbrBackground": win32.HBRUSH },
|
||||
{ "lpszMenuName": win32.LPCTSTR },
|
||||
{ "lpszClassName": win32.LPCTSTR },
|
||||
{ "hIconSm": win32.HICON }
|
||||
]);
|
||||
|
||||
lib.lazy_bind("RegisterClassExW", win32.ATOM, this.WNDCLASSEXW.ptr);
|
||||
lib.lazy_bind("UnregisterClassW", win32.BOOL, win32.LPCTSTR, win32.HINSTANCE);
|
||||
lib.lazy_bind("CreateWindowExW", win32.HWND, win32.DWORD, win32.LPCTSTR, win32.LPCTSTR, win32.DWORD, ctypes.int, ctypes.int, ctypes.int, ctypes.int, win32.HWND, win32.HMENU, win32.HINSTANCE, win32.LPVOID);
|
||||
lib.lazy_bind("DestroyWindow", win32.BOOL, win32.HWND);
|
||||
lib.lazy_bind("ShowWindow", win32.BOOL, win32.HWND, ctypes.int);
|
||||
lib.lazy_bind("IsWindowVisible", win32.BOOL, win32.HWND);
|
||||
|
||||
this.SW_HIDE = 0;
|
||||
this.SW_SHOWNORMAL = 1;
|
||||
this.SW_NORMAL = 1;
|
||||
this.SW_SHOWMINIMIZED = 2;
|
||||
this.SW_SHOWMAXIMIZED = 3;
|
||||
this.SW_MAXIMIZE = 3;
|
||||
this.SW_SHOWNOACTIVATE = 4;
|
||||
this.SW_SHOW = 5;
|
||||
this.SW_MINIMIZE = 6;
|
||||
this.SW_SHOWMINNOACTIVE = 7;
|
||||
this.SW_SHOWNA = 8;
|
||||
this.SW_RESTORE = 9;
|
||||
this.SW_SHOWDEFAULT = 10;
|
||||
this.SW_FORCEMINIMIZE = 11;
|
||||
this.SW_MAX = 11;
|
||||
|
||||
this.CW_USEDEFAULT = ctypes.int(0x80000000); // -2147483648
|
||||
|
||||
this.HWND_BROADCAST = win32.HWND(0xffff);
|
||||
this.HWND_MESSAGE = win32.HWND(-3); // WINVER >= 0x0500
|
||||
|
||||
// need to be win32.DWORD()'d after binray operations are applied !
|
||||
this.WS_BORDER = 0x00800000;
|
||||
this.WS_CAPTION = 0x00C00000;
|
||||
this.WS_CHILD = 0x40000000;
|
||||
this.WS_CHILDWINDOW = 0x40000000;
|
||||
this.WS_CLIPCHILDREN = 0x02000000;
|
||||
this.WS_CLIPSIBLINGS = 0x04000000;
|
||||
this.WS_DISABLED = 0x08000000;
|
||||
this.WS_DLGFRAME = 0x00400000;
|
||||
this.WS_GROUP = 0x00020000;
|
||||
this.WS_HSCROLL = 0x00100000;
|
||||
this.WS_ICONIC = 0x20000000;
|
||||
this.WS_MAXIMIZE = 0x01000000;
|
||||
this.WS_MAXIMIZEBOX = 0x00010000;
|
||||
this.WS_MINIMIZE = 0x20000000;
|
||||
this.WS_MINIMIZEBOX = 0x00020000;
|
||||
this.WS_OVERLAPPED = 0x00000000;
|
||||
this.WS_POPUP = 0x80000000;
|
||||
this.WS_SIZEBOX = 0x00040000;
|
||||
this.WS_SYSMENU = 0x00080000;
|
||||
this.WS_TABSTOP = 0x00010000;
|
||||
this.WS_THICKFRAME = 0x00040000;
|
||||
this.WS_TILED = 0x00000000;
|
||||
this.WS_VISIBLE = 0x10000000;
|
||||
this.WS_VSCROLL = 0x00200000;
|
||||
this.WS_POPUPWINDOW = (this.WS_POPUP | this.WS_BORDER | this.WS_SYSMENU);
|
||||
this.WS_OVERLAPPEDWINDOW = (this.WS_OVERLAPPED | this.WS_CAPTION | this.WS_SYSMENU | this.WS_THICKFRAME | this.WS_MINIMIZEBOX | this.WS_MAXIMIZEBOX);
|
||||
this.WS_TILEDWINDOW = (this.WS_OVERLAPPED | this.WS_CAPTION | this.WS_SYSMENU | this.WS_THICKFRAME | this.WS_MINIMIZEBOX | this.WS_MAXIMIZEBOX);
|
||||
|
||||
this.CWPSTRUCT = ctypes.StructType("CWPSTRUCT", [
|
||||
{ "lParam": win32.LPARAM },
|
||||
{ "wParam": win32.WPARAM },
|
||||
{ "message": win32.UINT },
|
||||
{ "hwnd": win32.HWND }
|
||||
]);
|
||||
|
||||
this.CWPRETSTRUCT = ctypes.StructType("CWPRETSTRUCT", [
|
||||
{ "lResult": win32.LRESULT },
|
||||
{ "lParam": win32.LPARAM },
|
||||
{ "wParam": win32.WPARAM },
|
||||
{ "message": win32.UINT },
|
||||
{ "hwnd": win32.HWND }
|
||||
]);
|
||||
|
||||
this.HOOKPROC = ctypes.FunctionType(
|
||||
WinCbABI, win32.LRESULT,
|
||||
[ctypes.int, win32.WPARAM, win32.LPARAM]).ptr;
|
||||
|
||||
lib.lazy_bind("SetWindowsHookExW", win32.HHOOK, ctypes.int, this.HOOKPROC, win32.HINSTANCE, win32.DWORD);
|
||||
lib.lazy_bind("CallNextHookEx", win32.LRESULT, win32.HHOOK, ctypes.int, win32.WPARAM, win32.LPARAM);
|
||||
lib.lazy_bind("UnhookWindowsHookEx", win32.BOOL, win32.HHOOK);
|
||||
|
||||
this.WH_MIN = (-1);
|
||||
this.WH_MSGFILTER = (-1);
|
||||
this.WH_JOURNALRECORD = 0;
|
||||
this.WH_JOURNALPLAYBACK = 1;
|
||||
this.WH_KEYBOARD = 2;
|
||||
this.WH_GETMESSAGE = 3;
|
||||
this.WH_CALLWNDPROC = 4;
|
||||
this.WH_CBT = 5;
|
||||
this.WH_SYSMSGFILTER = 6;
|
||||
this.WH_MOUSE = 7;
|
||||
this.WH_HARDWARE = 8;
|
||||
this.WH_DEBUG = 9;
|
||||
this.WH_SHELL = 10;
|
||||
this.WH_FOREGROUNDIDLE = 11;
|
||||
this.WH_CALLWNDPROCRET = 12;
|
||||
this.WH_KEYBOARD_LL = 13;
|
||||
this.WH_MOUSE_LL = 14;
|
||||
|
||||
this.HC_ACTION = 0;
|
||||
this.HC_GETNEXT = 1;
|
||||
this.HC_SKIP = 2;
|
||||
this.HC_NOREMOVE = 3;
|
||||
this.HC_NOREM = this.HC_NOREMOVE;
|
||||
this.HC_SYSMODALON = 4;
|
||||
this.HC_SYSMODALOFF = 5;
|
||||
|
||||
lib.lazy_bind("GetWindowThreadProcessId", win32.DWORD, win32.HWND, win32.LPDWORD);
|
||||
|
||||
this.FLASHWINFO = ctypes.StructType("FLASHWINFO", [
|
||||
{ "cbSize": win32.UINT },
|
||||
{ "hwnd": win32.HWND },
|
||||
{ "dwFlags": win32.DWORD },
|
||||
{ "uCount": win32.UINT },
|
||||
{ "dwTimeout": win32.DWORD }
|
||||
]);
|
||||
this.PFLASHWINFO = this.FLASHWINFO.ptr;
|
||||
|
||||
lib.lazy_bind("FlashWindow", win32.BOOL, win32.HWND, win32.BOOL);
|
||||
lib.lazy_bind("FlashWindowEx", win32.BOOL, this.PFLASHWINFO);
|
||||
|
||||
this.FLASHW_STOP = 0;
|
||||
this.FLASHW_CAPTION = 0x00000001;
|
||||
this.FLASHW_TRAY = 0x00000002;
|
||||
this.FLASHW_ALL =(this.FLASHW_CAPTION | this.FLASHW_TRAY);
|
||||
this.FLASHW_TIMER = 0x00000004;
|
||||
this.FLASHW_TIMERNOFG = 0x0000000C;
|
||||
|
||||
lib.lazy_bind("SystemParametersInfoW", win32.BOOL, win32.UINT, win32.UINT, win32.PVOID, win32.UINT);
|
||||
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);
|
||||
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;
|
||||
|
||||
lib.lazy_bind("CreatePopupMenu", win32.HMENU);
|
||||
lib.lazy_bind("DestroyMenu", win32.BOOL, win32.HMENU);
|
||||
|
||||
this.MENUITEMINFOW = ctypes.StructType("MENUITEMINFOW", [
|
||||
{ "cbSize": win32.UINT },
|
||||
{ "fMask": win32.UINT },
|
||||
{ "fType": win32.UINT },
|
||||
{ "fState": win32.UINT },
|
||||
{ "wID": win32.UINT },
|
||||
{ "hSubMenu": win32.HMENU },
|
||||
{ "hbmpChecked": win32.HBITMAP },
|
||||
{ "hbmpUnchecked": win32.HBITMAP },
|
||||
{ "dwItemData": win32.ULONG_PTR },
|
||||
{ "dwTypeData": win32.LPWSTR },
|
||||
{ "cch": win32.UINT },
|
||||
{ "hbmpItem": win32.HBITMAP }
|
||||
]);
|
||||
this.LPCMENUITEMINFO = this.LPMENUITEMINFOW = this.MENUITEMINFOW.ptr;
|
||||
|
||||
lib.lazy_bind("InsertMenuItemW", win32.BOOL, win32.HMENU, win32.UINT, win32.BOOL, this.LPCMENUITEMINFO);
|
||||
lib.lazy_bind("GetMenuItemInfoW", win32.BOOL, win32.HMENU, win32.UINT, win32.BOOL, this.LPCMENUITEMINFO);
|
||||
|
||||
this.MIIM_STATE = 0x00000001;
|
||||
this.MIIM_ID = 0x00000002;
|
||||
this.MIIM_SUBMENU = 0x00000004;
|
||||
this.MIIM_CHECKMARKS = 0x00000008;
|
||||
this.MIIM_TYPE = 0x00000010;
|
||||
this.MIIM_DATA = 0x00000020;
|
||||
this.MIIM_STRING = 0x00000040;
|
||||
this.MIIM_BITMAP = 0x00000080;
|
||||
this.MIIM_FTYPE = 0x00000100;
|
||||
|
||||
lib.lazy_bind("InsertMenuW", win32.BOOL, win32.HMENU, win32.UINT, win32.UINT, win32.UINT_PTR, win32.LPCTSTR);
|
||||
lib.lazy_bind("DeleteMenu", win32.BOOL, win32.HMENU, win32.UINT, win32.UINT);
|
||||
|
||||
this.MF_INSERT = 0x00000000;
|
||||
this.MF_CHANGE = 0x00000080;
|
||||
this.MF_APPEND = 0x00000100;
|
||||
this.MF_DELETE = 0x00000200;
|
||||
this.MF_REMOVE = 0x00001000;
|
||||
this.MF_BYCOMMAND = 0x00000000;
|
||||
this.MF_BYPOSITION = 0x00000400;
|
||||
this.MF_SEPARATOR = 0x00000800;
|
||||
this.MF_ENABLED = 0x00000000;
|
||||
this.MF_GRAYED = 0x00000001;
|
||||
this.MF_DISABLED = 0x00000002;
|
||||
this.MF_UNCHECKED = 0x00000000;
|
||||
this.MF_CHECKED = 0x00000008;
|
||||
this.MF_USECHECKBITMAPS = 0x00000200;
|
||||
this.MF_STRING = 0x00000000;
|
||||
this.MF_BITMAP = 0x00000004;
|
||||
this.MF_OWNERDRAW = 0x00000100;
|
||||
this.MF_POPUP = 0x00000010;
|
||||
this.MF_MENUBARBREAK = 0x00000020;
|
||||
this.MF_MENUBREAK = 0x00000040;
|
||||
this.MF_UNHILITE = 0x00000000;
|
||||
this.MF_HILITE = 0x00000080;
|
||||
this.MF_DEFAULT = 0x00001000;
|
||||
this.MF_RIGHTJUSTIFY = 0x00004000;
|
||||
this.MFT_STRING = this.MF_STRING;
|
||||
this.MFT_BITMAP = this.MF_BITMAP;
|
||||
this.MFT_MENUBARBREAK = this.MF_MENUBARBREAK;
|
||||
this.MFT_MENUBREAK = this.MF_MENUBREAK;
|
||||
this.MFT_OWNERDRAW = this.MF_OWNERDRAW;
|
||||
this.MFT_RADIOCHECK = 0x00000200;
|
||||
this.MFT_SEPARATOR = this.MF_SEPARATOR;
|
||||
this.MFT_RIGHTORDER = 0x00002000;
|
||||
this.MFT_RIGHTJUSTIFY = this.MF_RIGHTJUSTIFY;
|
||||
this.MFS_GRAYED = 0x00000003;
|
||||
this.MFS_DISABLED = this.MFS_GRAYED;
|
||||
this.MFS_CHECKED = this.MF_CHECKED;
|
||||
this.MFS_HILITE = this.MF_HILITE;
|
||||
this.MFS_ENABLED = this.MF_ENABLED;
|
||||
this.MFS_UNCHECKED = this.MF_UNCHECKED;
|
||||
this.MFS_UNHILITE = this.MF_UNHILITE;
|
||||
this.MFS_DEFAULT = this.MF_DEFAULT;
|
||||
|
||||
this.TPM_LEFTBUTTON = 0x0000;
|
||||
this.TPM_RIGHTBUTTON = 0x0002;
|
||||
this.TPM_LEFTALIGN = 0x0000;
|
||||
this.TPM_CENTERALIGN = 0x0004;
|
||||
this.TPM_RIGHTALIGN = 0x0008;
|
||||
this.TPM_TOPALIGN = 0x0000;
|
||||
this.TPM_VCENTERALIGN = 0x0010;
|
||||
this.TPM_BOTTOMALIGN = 0x0020;
|
||||
this.TPM_HORIZONTAL = 0x0000;
|
||||
this.TPM_VERTICAL = 0x0040;
|
||||
|
||||
lib.lazy_bind("GetMenuItemCount", ctypes.int, win32.HMENU);
|
||||
|
||||
lib.lazy_bind("CalculatePopupWindowPosition", win32.BOOL, win32.POINT.ptr, win32.SIZE, win32.UINT, win32.RECT.ptr, win32.RECT.ptr);
|
||||
lib.lazy_bind("TrackPopupMenu", win32.BOOL, win32.HMENU, win32.UINT, ctypes.int, ctypes.int, ctypes.int, win32.HWND, win32.RECT.ptr);
|
||||
lib.lazy_bind("SetForegroundWindow", win32.BOOL, win32.HWND);
|
||||
lib.lazy_bind("GetCursorPos", win32.BOOL, win32.LPPOINT);
|
||||
lib.lazy_bind("GetMessagePos", win32.DWORD);
|
||||
|
||||
this.WINDOWPLACEMENT = ctypes.StructType("WINDOWPLACEMENT", [
|
||||
{ "length": win32.UINT },
|
||||
{ "flags": win32.UINT },
|
||||
{ "showCmd": win32.UINT },
|
||||
{ "ptMinPosition": win32.POINT },
|
||||
{ "ptMaxPosition": win32.POINT },
|
||||
{ "rcNormalPosition": win32.RECT }
|
||||
]);
|
||||
this.PWINDOWPLACEMENT = this.LPWINDOWPLACEMENT = this.WINDOWPLACEMENT.ptr;
|
||||
|
||||
lib.lazy_bind("GetWindowPlacement", win32.BOOL, win32.HWND, this.WINDOWPLACEMENT.ptr);
|
||||
lib.lazy_bind("SetWindowPlacement", win32.BOOL, win32.HWND, this.WINDOWPLACEMENT.ptr);
|
||||
|
||||
}
|
||||
|
||||
new ctypes_library(USER32_LIBNAME, USER32_ABIS, user32_defines, this);
|
210
src/modules/ctypes/winnt/win32.jsm
Normal file
@ -0,0 +1,210 @@
|
||||
var EXPORTED_SYMBOLS = [ "win32" ];
|
||||
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/ctypes.jsm");
|
||||
Cu.import("resource://firetray/ctypes/ctypes-utils.jsm");
|
||||
|
||||
|
||||
var win32 = new function() {
|
||||
|
||||
this.WIN_VERSIONS = { // maj*10 + min
|
||||
'8': 62, // 2012
|
||||
'7': 61, // 2009
|
||||
'Vista': 60, // 2007
|
||||
'XP': 51, // 2001
|
||||
'2K': 50, // 2000
|
||||
};
|
||||
// could also parse Cc["@mozilla.org/network/protocol;1?name=http"].
|
||||
// getService(Ci.nsIHttpProtocolHandler).oscpu
|
||||
this.WINVER = null; // initialized in kernel32.jsm
|
||||
|
||||
this.BOOL = ctypes.bool;
|
||||
this.BYTE = ctypes.unsigned_char;
|
||||
this.INT_PTR = is64bit ? ctypes.int64_t : ctypes.int;
|
||||
this.UINT = ctypes.unsigned_int;
|
||||
this.UINT_PTR = is64bit ? ctypes.uint64_t : ctypes.unsigned_int;
|
||||
this.WORD = ctypes.unsigned_short;
|
||||
this.DWORD = ctypes.unsigned_long;
|
||||
this.LPDWORD = this.DWORD.ptr;
|
||||
this.PVOID = ctypes.voidptr_t;
|
||||
this.LPVOID = ctypes.voidptr_t;
|
||||
this.LONG = ctypes.long;
|
||||
this.LONG_PTR = is64bit ? ctypes.int64_t : ctypes.long;
|
||||
this.ULONG_PTR = is64bit ? ctypes.uint64_t : ctypes.unsigned_long;
|
||||
this.SIZE_T = this.ULONG_PTR;
|
||||
this.DWORD_PTR = this.ULONG_PTR;
|
||||
this.ATOM = this.WORD;
|
||||
this.HANDLE = ctypes.voidptr_t;
|
||||
this.HWND = this.HANDLE;
|
||||
this.HICON = this.HANDLE;
|
||||
this.HINSTANCE = this.HANDLE;
|
||||
this.HMODULE = this.HANDLE;
|
||||
this.HMENU = this.HANDLE;
|
||||
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;
|
||||
this.LPTSTR = ctypes.jschar.ptr; // UNICODE
|
||||
this.LPCTSTR = ctypes.jschar.ptr;
|
||||
this.LPCWSTR = ctypes.jschar.ptr;
|
||||
this.LPWSTR = ctypes.jschar.ptr; // WCHAR
|
||||
this.LRESULT = this.LONG_PTR;
|
||||
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 },
|
||||
{ "Data2": ctypes.unsigned_short },
|
||||
{ "Data3": ctypes.unsigned_short },
|
||||
{ "Data4": ctypes.char.array(8) }
|
||||
]);
|
||||
|
||||
/*
|
||||
* #define MAKEINTRESOURCEA(i) ((LPSTR)((ULONG_PTR)((WORD)(i))))
|
||||
* #define MAKEINTRESOURCEW(i) ((LPWSTR)((ULONG_PTR)((WORD)(i))))
|
||||
*/
|
||||
this.MAKEINTRESOURCE = function(i) {return this.LPWSTR(i);};
|
||||
|
||||
this._T = function(str) {
|
||||
return ctypes.jschar.array()(str);
|
||||
};
|
||||
|
||||
/*
|
||||
* #define LOWORD(l) ((WORD)((DWORD_PTR)(l) & 0xffff))
|
||||
* #define HIWORD(l) ((WORD)((DWORD_PTR)(l) >> 16))
|
||||
* #define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
|
||||
* #define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
|
||||
*/
|
||||
this.LOWORD = function(l) {return l & 0x0000ffff;};
|
||||
this.HIWORD = function(l) {return l >> 16;};
|
||||
/* Although we shouldn't use LO-/HIWORD to get coords, because of negative
|
||||
coords on multi-monitor displays, I'm not sure how to express the
|
||||
GET_?_LPARAM macros with ctypes. */
|
||||
this.GET_X_LPARAM = this.LOWORD;
|
||||
this.GET_Y_LPARAM = this.HIWORD;
|
||||
|
||||
this.ERROR_INVALID_PARAMETER = 87;
|
||||
this.ERROR_INVALID_WINDOW_HANDLE = 1400;
|
||||
this.ERROR_RESOURCE_TYPE_NOT_FOUND = 1813;
|
||||
|
||||
// WinUser.h
|
||||
this.WM_NULL = 0x0000;
|
||||
this.WM_CREATE = 0x0001;
|
||||
this.WM_DESTROY = 0x0002;
|
||||
this.WM_MOVE = 0x0003;
|
||||
this.WM_SIZE = 0x0005;
|
||||
this.WM_ACTIVATE = 0x0006;
|
||||
this.WA_INACTIVE = 0;
|
||||
this.WA_ACTIVE = 1;
|
||||
this.WA_CLICKACTIVE = 2;
|
||||
this.WM_SETFOCUS = 0x0007;
|
||||
this.WM_KILLFOCUS = 0x0008;
|
||||
this.WM_ENABLE = 0x000A;
|
||||
this.WM_SETREDRAW = 0x000B;
|
||||
this.WM_SETTEXT = 0x000C;
|
||||
this.WM_GETTEXT = 0x000D;
|
||||
this.WM_GETTEXTLENGTH = 0x000E;
|
||||
this.WM_PAINT = 0x000F;
|
||||
this.WM_CLOSE = 0x0010;
|
||||
this.WM_QUIT = 0x0012;
|
||||
this.WM_ERASEBKGND = 0x0014;
|
||||
this.WM_SYSCOLORCHANGE = 0x0015;
|
||||
this.WM_SHOWWINDOW = 0x0018;
|
||||
this.WM_WININICHANGE = 0x001A;
|
||||
this.WM_SETTINGCHANGE = this.WM_WININICHANGE;
|
||||
this.WM_DEVMODECHANGE = 0x001B;
|
||||
this.WM_ACTIVATEAPP = 0x001C;
|
||||
this.WM_FONTCHANGE = 0x001D;
|
||||
this.WM_TIMECHANGE = 0x001E;
|
||||
this.WM_CANCELMODE = 0x001F;
|
||||
this.WM_SETCURSOR = 0x0020;
|
||||
this.WM_MOUSEACTIVATE = 0x0021;
|
||||
this.WM_CHILDACTIVATE = 0x0022;
|
||||
this.WM_QUEUESYNC = 0x0023;
|
||||
this.WM_COMMAND = 0x0111;
|
||||
this.WM_SYSCOMMAND = 0x0112;
|
||||
this.WM_HSCROLL = 0x0114;
|
||||
this.WM_VSCROLL = 0x0115;
|
||||
this.WM_MOUSEWHEEL = 0x020A;
|
||||
|
||||
this.WM_USER = 0x0400;
|
||||
this.WM_APP = 0x8000;
|
||||
|
||||
this.WM_CONTEXTMENU = 0x007B;
|
||||
|
||||
this.WM_MOUSEFIRST = 0x0200;
|
||||
this.WM_MOUSEMOVE = 0x0200;
|
||||
this.WM_LBUTTONDOWN = 0x0201;
|
||||
this.WM_LBUTTONUP = 0x0202;
|
||||
this.WM_LBUTTONDBLCLK = 0x0203;
|
||||
this.WM_RBUTTONDOWN = 0x0204;
|
||||
this.WM_RBUTTONUP = 0x0205;
|
||||
this.WM_RBUTTONDBLCLK = 0x0206;
|
||||
this.WM_MBUTTONDOWN = 0x0207;
|
||||
this.WM_MBUTTONUP = 0x0208;
|
||||
this.WM_MBUTTONDBLCLK = 0x0209;
|
||||
this.WM_MOUSEWHEEL = 0x020A;
|
||||
this.WM_XBUTTONDOWN = 0x020B;
|
||||
this.WM_XBUTTONUP = 0x020C;
|
||||
this.WM_XBUTTONDBLCLK = 0x020D;
|
||||
this.WM_MOUSELAST = 0x020D;
|
||||
this.WM_MOUSELAST = 0x020A;
|
||||
|
||||
this.SC_MINIMIZE = 0xF020;
|
||||
this.SC_CLOSE = 0xF060;
|
||||
|
||||
this.SIZE_RESTORED = 0;
|
||||
this.SIZE_MINIMIZED = 1;
|
||||
this.SIZE_MAXIMIZED = 2;
|
||||
this.SIZE_MAXSHOW = 3;
|
||||
this.SIZE_MAXHIDE = 4;
|
||||
|
||||
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 },
|
||||
{ "yHotspot": this.DWORD },
|
||||
{ "hbmMask": this.HBITMAP },
|
||||
{ "hbmColor": this.HBITMAP }
|
||||
]);
|
||||
this.PICONINFO = this.ICONINFO.ptr;
|
||||
|
||||
this.POINT = ctypes.StructType("POINT", [
|
||||
{ "x": this.LONG },
|
||||
{ "y": this.LONG }
|
||||
]);
|
||||
this.PPOINT = this.LPPOINT =this.POINT.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
|
||||
let nin_select = win32.WM_USER + 0;
|
||||
win32.NIN_SELECT = nin_select;
|
||||
win32.NINF_KEY = 0x1;
|
||||
win32.NIN_KEYSELECT = (win32.NIN_SELECT | win32.NINF_KEY);
|
@ -24,7 +24,7 @@ firetray.Chat = {
|
||||
init: function() {
|
||||
if (this.initialized) {
|
||||
log.warn("Chat already initialized");
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
log.debug("Enabling Chat");
|
||||
|
||||
@ -42,10 +42,11 @@ firetray.Chat = {
|
||||
this.updateIcon();
|
||||
|
||||
this.initialized = true;
|
||||
return true;
|
||||
},
|
||||
|
||||
shutdown: function() {
|
||||
if (!this.initialized) return;
|
||||
if (!this.initialized) return false;
|
||||
log.debug("Disabling Chat");
|
||||
|
||||
if (firetray.Chat.convsToAcknowledge.length())
|
||||
@ -55,6 +56,7 @@ firetray.Chat = {
|
||||
firetray.Utils.removeAllObservers(firetray.Chat);
|
||||
|
||||
this.initialized = false;
|
||||
return true;
|
||||
},
|
||||
|
||||
// FIXME: the listener should probably attached on the conv entry in the
|
@ -204,7 +204,6 @@ firetray.ChatStatusIcon = {
|
||||
{ notify: firetray.ChatStatusIcon.fadeStep },
|
||||
ALPHA_STEP_SLEEP_MILLISECONDS, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
|
||||
|
||||
} catch (e if e instanceof StopIteration) {
|
||||
|
||||
if (firetray.ChatStatusIcon.events['stop-fade']) {
|
||||
|
@ -172,8 +172,7 @@ firetray.PopupMenu = {
|
||||
},
|
||||
|
||||
hideWindowItemAndSeparatorMaybe: function(xid) {
|
||||
if (!this.windowItemsHandled())
|
||||
return;
|
||||
if (!this.windowItemsHandled()) return;
|
||||
|
||||
this.hideWindowItem(xid);
|
||||
if (firetray.Handler.visibleWindowsCount === firetray.Handler.windowsCount)
|
||||
@ -212,4 +211,5 @@ firetray.PopupMenu = {
|
||||
|
||||
}; // firetray.PopupMenu
|
||||
|
||||
firetray.Handler.showHidePopupMenuItems = firetray.PopupMenu.showHideWindowItems;
|
||||
firetray.Handler.showHidePopupMenuItems =
|
||||
firetray.PopupMenu.showHideWindowItems.bind(firetray.PopupMenu);
|
||||
|
@ -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);
|
||||
@ -135,7 +137,7 @@ firetray.StatusIcon = {
|
||||
|
||||
log.debug("showHideAllWindows: "+firetray.Handler.hasOwnProperty("showHideAllWindows"));
|
||||
this.callbacks.iconActivate = gtk.GCallbackStatusIconActivate_t(
|
||||
firetray.Handler.showHideAllWindows);
|
||||
firetray.StatusIcon.onClick);
|
||||
let handlerId = gobject.g_signal_connect(firetray.StatusIcon.trayIcon,
|
||||
"activate", firetray.StatusIcon.callbacks.iconActivate, null);
|
||||
log.debug("g_connect activate="+handlerId);
|
||||
@ -176,6 +178,12 @@ firetray.StatusIcon = {
|
||||
}
|
||||
},
|
||||
|
||||
onClick: function(gtkStatusIcon, userData) {
|
||||
firetray.Handler.showHideAllWindows();
|
||||
let stopPropagation = true;
|
||||
return stopPropagation;
|
||||
},
|
||||
|
||||
setIconImageFromFile: function(filename) {
|
||||
if (!firetray.StatusIcon.trayIcon)
|
||||
log.error("Icon missing");
|
||||
@ -200,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_custom");
|
||||
};
|
||||
|
||||
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) {
|
||||
|
@ -22,6 +22,7 @@ Cu.import("resource://firetray/ctypes/linux/gdk.jsm");
|
||||
Cu.import("resource://firetray/ctypes/linux/gtk.jsm");
|
||||
Cu.import("resource://firetray/ctypes/linux/libc.jsm");
|
||||
Cu.import("resource://firetray/ctypes/linux/x11.jsm");
|
||||
Cu.import("resource://firetray/FiretrayWindow.jsm");
|
||||
Cu.import("resource://firetray/commons.js");
|
||||
firetray.Handler.subscribeLibsForClosing([gobject, gdk, gtk, libc, x11, glib]);
|
||||
|
||||
@ -52,15 +53,15 @@ var _find_data_t = ctypes.StructType("_find_data_t", [
|
||||
// NOTE: storing ctypes pointers into a JS object doesn't work: pointers are
|
||||
// "evolving" after a while (maybe due to back and forth conversion). So we
|
||||
// need to store them into a real ctypes array !
|
||||
firetray.Handler.gtkWindows = new ctypesMap(gtk.GtkWindow.ptr),
|
||||
firetray.Handler.gdkWindows = new ctypesMap(gdk.GdkWindow.ptr),
|
||||
firetray.Handler.gtkPopupMenuWindowItems = new ctypesMap(gtk.GtkImageMenuItem.ptr),
|
||||
firetray.Handler.gtkWindows = new ctypesMap(gtk.GtkWindow.ptr);
|
||||
firetray.Handler.gdkWindows = new ctypesMap(gdk.GdkWindow.ptr);
|
||||
firetray.Handler.gtkPopupMenuWindowItems = new ctypesMap(gtk.GtkImageMenuItem.ptr);
|
||||
|
||||
|
||||
firetray.Window = {
|
||||
signals: {'focus-in': {callback: {}, handler: {}}},
|
||||
firetray.Window = new FiretrayWindow();
|
||||
firetray.Window.signals = {'focus-in': {callback: {}, handler: {}}};
|
||||
|
||||
init: function() {
|
||||
firetray.Window.init = function() {
|
||||
let gtkVersionCheck = gtk.gtk_check_version(
|
||||
gtk.FIRETRAY_REQUIRED_GTK_MAJOR_VERSION,
|
||||
gtk.FIRETRAY_REQUIRED_GTK_MINOR_VERSION,
|
||||
@ -70,16 +71,16 @@ firetray.Window = {
|
||||
log.error("gtk_check_version="+gtkVersionCheck.readString());
|
||||
|
||||
if (firetray.Handler.isChatEnabled()) {
|
||||
Cu.import("resource://firetray/FiretrayChat.jsm");
|
||||
Cu.import("resource://firetray/linux/FiretrayChat.jsm");
|
||||
Cu.import("resource://firetray/linux/FiretrayChatStatusIcon.jsm");
|
||||
}
|
||||
|
||||
this.initialized = true;
|
||||
},
|
||||
};
|
||||
|
||||
shutdown: function() {
|
||||
firetray.Window.shutdown = function() {
|
||||
this.initialized = false;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterate over all Gtk toplevel windows to find a window. We rely on
|
||||
@ -89,7 +90,7 @@ firetray.Window = {
|
||||
* @param window nsIDOMWindow from Services.wm
|
||||
* @return a gtk.GtkWindow.ptr
|
||||
*/
|
||||
getGtkWindowFromChromeWindow: function(window) {
|
||||
firetray.Window.getGtkWindowFromChromeWindow = function(window) {
|
||||
let baseWindow = window
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
@ -125,14 +126,14 @@ firetray.Window = {
|
||||
}
|
||||
|
||||
return userData.contents.outWindow;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* compares a GtkWindow's title with a string passed in userData
|
||||
* @param gtkWidget: GtkWidget from gtk_window_list_toplevels()
|
||||
* @param userData: _find_data_t
|
||||
*/
|
||||
_findGtkWindowByTitle: function(gtkWidget, userData) {
|
||||
firetray.Window._findGtkWindowByTitle = function(gtkWidget, userData) {
|
||||
let data = ctypes.cast(userData, _find_data_t.ptr);
|
||||
let inTitle = data.contents.inTitle;
|
||||
|
||||
@ -144,9 +145,9 @@ firetray.Window = {
|
||||
if (libc.strcmp(inTitle, winTitle) == 0)
|
||||
data.contents.outWindow = gtkWin;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
getGdkWindowFromGtkWindow: function(gtkWin) {
|
||||
firetray.Window.getGdkWindowFromGtkWindow = function(gtkWin) {
|
||||
try {
|
||||
let gtkWid = ctypes.cast(gtkWin, gtk.GtkWidget.ptr);
|
||||
return gtk.gtk_widget_get_window(gtkWid);
|
||||
@ -154,39 +155,39 @@ firetray.Window = {
|
||||
log.error(x);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
};
|
||||
|
||||
getXIDFromGdkWindow: function(gdkWin) {
|
||||
firetray.Window.getXIDFromGdkWindow = function(gdkWin) {
|
||||
return gdk.gdk_x11_drawable_get_xid(ctypes.cast(gdkWin, gdk.GdkDrawable.ptr));
|
||||
},
|
||||
};
|
||||
|
||||
getXIDFromGtkWidget: function(gtkWid) {
|
||||
firetray.Window.getXIDFromGtkWidget = function(gtkWid) {
|
||||
let gdkWin = gtk.gtk_widget_get_window(gtkWid);
|
||||
return gdk.gdk_x11_drawable_get_xid(ctypes.cast(gdkWin, gdk.GdkDrawable.ptr));
|
||||
},
|
||||
};
|
||||
|
||||
addrPointedByInHex: function(ptr) {
|
||||
firetray.Window.addrPointedByInHex = function(ptr) {
|
||||
return "0x"+ctypes.cast(ptr, ctypes.uintptr_t.ptr).contents.toString(16);
|
||||
},
|
||||
};
|
||||
|
||||
getGdkWindowFromNativeHandle: function(nativeHandle) {
|
||||
firetray.Window.getGdkWindowFromNativeHandle = function(nativeHandle) {
|
||||
let gdkw = new gdk.GdkWindow.ptr(ctypes.UInt64(nativeHandle)); // a new pointer to the GdkWindow
|
||||
gdkw = gdk.gdk_window_get_toplevel(gdkw);
|
||||
log.debug("gdkw="+gdkw+" *gdkw="+this.addrPointedByInHex(gdkw));
|
||||
return gdkw;
|
||||
},
|
||||
};
|
||||
|
||||
getGtkWindowFromGdkWindow: function(gdkWin) {
|
||||
firetray.Window.getGtkWindowFromGdkWindow = function(gdkWin) {
|
||||
let gptr = new gobject.gpointer;
|
||||
gdk.gdk_window_get_user_data(gdkWin, gptr.address());
|
||||
log.debug("gptr="+gptr+" *gptr="+this.addrPointedByInHex(gptr));
|
||||
let gtkw = ctypes.cast(gptr, gtk.GtkWindow.ptr);
|
||||
log.debug("gtkw="+gtkw+" *gtkw="+this.addrPointedByInHex(gtkw));
|
||||
return gtkw;
|
||||
},
|
||||
};
|
||||
|
||||
/* consider using getXIDFromChromeWindow() if you only need the XID */
|
||||
getWindowsFromChromeWindow: function(win) {
|
||||
/* consider using getRegisteredWinIdFromChromeWindow() if you only need the XID */
|
||||
firetray.Window.getWindowsFromChromeWindow = function(win) {
|
||||
let baseWin = firetray.Handler.getWindowInterface(win, "nsIBaseWindow");
|
||||
let nativeHandle = baseWin.nativeHandle; // Moz' private pointer to the GdkWindow
|
||||
log.debug("nativeHandle="+nativeHandle);
|
||||
@ -201,16 +202,9 @@ firetray.Window = {
|
||||
let xid = firetray.Window.getXIDFromGdkWindow(gdkWin);
|
||||
log.debug("XID="+xid);
|
||||
return [baseWin, gtkWin, gdkWin, xid];
|
||||
},
|
||||
};
|
||||
|
||||
getXIDFromChromeWindow: function(win) {
|
||||
for (let xid in firetray.Handler.windows)
|
||||
if (firetray.Handler.windows[xid].chromeWin === win) return xid;
|
||||
log.error("unknown window while lookup");
|
||||
return null;
|
||||
},
|
||||
|
||||
unregisterWindowByXID: function(xid) {
|
||||
firetray.Window.unregisterWindowByXID = function(xid) {
|
||||
if (!firetray.Handler.windows.hasOwnProperty(xid)) {
|
||||
log.error("can't unregister unknown window "+xid);
|
||||
return false;
|
||||
@ -225,16 +219,14 @@ firetray.Window = {
|
||||
throw new DeleteError();
|
||||
firetray.Handler.gtkWindows.remove(xid);
|
||||
firetray.Handler.gdkWindows.remove(xid);
|
||||
firetray.Handler.windowsCount -= 1;
|
||||
firetray.Handler.visibleWindowsCount -= 1;
|
||||
|
||||
firetray.PopupMenu.removeWindowItem(xid);
|
||||
|
||||
log.debug("window "+xid+" unregistered");
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
show: function(xid) {
|
||||
firetray.Window.show = function(xid) {
|
||||
log.debug("show xid="+xid);
|
||||
|
||||
// try to restore previous state. TODO: z-order respected ?
|
||||
@ -252,11 +244,11 @@ firetray.Window = {
|
||||
|
||||
firetray.PopupMenu.hideWindowItemAndSeparatorMaybe(xid);
|
||||
firetray.Handler.showHideIcon();
|
||||
},
|
||||
};
|
||||
|
||||
/* FIXME: hiding windows should also hide child windows, like message windows
|
||||
in Thunderbird */
|
||||
hide: function(xid) {
|
||||
firetray.Window.hide = function(xid) {
|
||||
log.debug("hide");
|
||||
|
||||
firetray.Window.savePositionAndSize(xid);
|
||||
@ -267,9 +259,9 @@ firetray.Window = {
|
||||
|
||||
firetray.PopupMenu.showWindowItem(xid);
|
||||
firetray.Handler.showHideIcon();
|
||||
},
|
||||
};
|
||||
|
||||
startupHide: function(xid) {
|
||||
firetray.Window.startupHide = function(xid) {
|
||||
log.debug('startupHide: '+xid);
|
||||
|
||||
// also it seems cleaner, baseWin.visibility=false removes the possibility
|
||||
@ -278,9 +270,9 @@ firetray.Window = {
|
||||
|
||||
firetray.PopupMenu.showWindowItem(xid);
|
||||
firetray.Handler.showHideIcon();
|
||||
},
|
||||
};
|
||||
|
||||
savePositionAndSize: function(xid) {
|
||||
firetray.Window.savePositionAndSize = function(xid) {
|
||||
let gx = {}, gy = {}, gwidth = {}, gheight = {};
|
||||
firetray.Handler.windows[xid].baseWin.getPositionAndSize(gx, gy, gwidth, gheight);
|
||||
firetray.Handler.windows[xid].savedX = gx.value;
|
||||
@ -288,9 +280,9 @@ firetray.Window = {
|
||||
firetray.Handler.windows[xid].savedWidth = gwidth.value;
|
||||
firetray.Handler.windows[xid].savedHeight = gheight.value;
|
||||
log.debug("save: gx="+gx.value+", gy="+gy.value+", gwidth="+gwidth.value+", gheight="+gheight.value);
|
||||
},
|
||||
};
|
||||
|
||||
restorePositionAndSize: function(xid) {
|
||||
firetray.Window.restorePositionAndSize = function(xid) {
|
||||
if ("undefined" === typeof(firetray.Handler.windows[xid].savedX))
|
||||
return; // windows[xid].saved* may not be initialized
|
||||
|
||||
@ -305,17 +297,17 @@ firetray.Window = {
|
||||
['savedX', 'savedX', 'savedWidth', 'savedHeight'].forEach(function(element) {
|
||||
delete firetray.Handler.windows[xid][element];
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
saveStates: function(xid) {
|
||||
firetray.Window.saveStates = function(xid) {
|
||||
let winStates = firetray.Window.getXWindowStates(x11.Window(xid));
|
||||
firetray.Handler.windows[xid].savedStates = winStates;
|
||||
log.debug("save: windowStates="+winStates);
|
||||
},
|
||||
};
|
||||
|
||||
// NOTE: fluxbox bug probably: if hidden and restored iconified, then
|
||||
// switching to desktop de-iconifies it ?!
|
||||
restoreStates: function(xid) {
|
||||
firetray.Window.restoreStates = function(xid) {
|
||||
let winStates = firetray.Handler.windows[xid].savedStates;
|
||||
log.debug("restored WindowStates: " + winStates);
|
||||
|
||||
@ -336,18 +328,18 @@ firetray.Window = {
|
||||
}
|
||||
|
||||
delete firetray.Handler.windows[xid].savedStates;
|
||||
},
|
||||
};
|
||||
|
||||
saveDesktop: function(xid) {
|
||||
firetray.Window.saveDesktop = function(xid) {
|
||||
if (!firetray.Utils.prefService.getBoolPref('remember_desktop'))
|
||||
return;
|
||||
|
||||
let winDesktop = firetray.Window.getXWindowDesktop(x11.Window(xid));
|
||||
firetray.Handler.windows[xid].savedDesktop = winDesktop;
|
||||
log.debug("save: windowDesktop="+winDesktop);
|
||||
},
|
||||
};
|
||||
|
||||
restoreDesktop: function(xid) {
|
||||
firetray.Window.restoreDesktop = function(xid) {
|
||||
if (!firetray.Utils.prefService.getBoolPref('remember_desktop'))
|
||||
return;
|
||||
|
||||
@ -361,32 +353,24 @@ firetray.Window = {
|
||||
|
||||
log.debug("restored to desktop: "+desktopDest);
|
||||
delete firetray.Handler.windows[xid].savedDesktop;
|
||||
},
|
||||
};
|
||||
|
||||
setVisibility: function(xid, visibility) {
|
||||
firetray.Window.getVisibility = function(xid) {
|
||||
let gtkWidget = ctypes.cast(firetray.Handler.gtkWindows.get(xid), gtk.GtkWidget.ptr);
|
||||
// nsIBaseWin.visibility always true
|
||||
return gtk.gtk_widget_get_visible(gtkWidget);
|
||||
};
|
||||
|
||||
firetray.Window.setVisibility = function(xid, visibility) {
|
||||
log.debug("setVisibility="+visibility);
|
||||
let gtkWidget = ctypes.cast(firetray.Handler.gtkWindows.get(xid), gtk.GtkWidget.ptr);
|
||||
if (visibility)
|
||||
gtk.gtk_widget_show_all(gtkWidget);
|
||||
else
|
||||
gtk.gtk_widget_hide(gtkWidget);
|
||||
};
|
||||
|
||||
this.updateVisibility(xid, visibility);
|
||||
},
|
||||
|
||||
updateVisibility: function(xid, visibility) {
|
||||
let win = firetray.Handler.windows[xid];
|
||||
if (win.visible === visibility)
|
||||
log.warn("window (xid="+xid+") was already visible="+win.visible);
|
||||
|
||||
firetray.Handler.visibleWindowsCount = visibility ?
|
||||
firetray.Handler.visibleWindowsCount + 1 :
|
||||
firetray.Handler.visibleWindowsCount - 1 ;
|
||||
|
||||
win.visible = visibility; // nsIBaseWin.visibility always true :-(
|
||||
},
|
||||
|
||||
xSendClientMessgeEvent: function(xid, atom, data, dataSize) {
|
||||
firetray.Window.xSendClientMessgeEvent = function(xid, atom, data, dataSize) {
|
||||
let xev = new x11.XClientMessageEvent;
|
||||
xev.type = x11.ClientMessage;
|
||||
xev.window = x11.Window(xid);
|
||||
@ -401,27 +385,27 @@ firetray.Window = {
|
||||
// fortunately, it's OK not to cast xev. ctypes.cast to a void_t doesn't work (length pb)
|
||||
let status = x11.XSendEvent(x11.current.Display, rootWin, propagate, mask, xev.address());
|
||||
// always returns 1 (BadRequest as a coincidence)
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* raises window on top and give focus.
|
||||
*/
|
||||
activate: function(xid) {
|
||||
firetray.Window.activate = function(xid) {
|
||||
gtk.gtk_window_present(firetray.Handler.gtkWindows.get(xid));
|
||||
log.debug("window raised");
|
||||
},
|
||||
};
|
||||
|
||||
setUrgency: function(xid, urgent) {
|
||||
firetray.Window.setUrgency = function(xid, urgent) {
|
||||
log.debug("setUrgency: "+urgent);
|
||||
gtk.gtk_window_set_urgency_hint(firetray.Handler.gtkWindows.get(xid), urgent);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* YOU MUST x11.XFree() THE VARIABLE RETURNED BY THIS FUNCTION
|
||||
* @param xwin: a x11.Window
|
||||
* @param prop: a x11.Atom
|
||||
*/
|
||||
getXWindowProperties: function(xwin, prop) {
|
||||
firetray.Window.getXWindowProperties = function(xwin, prop) {
|
||||
// infos returned by XGetWindowProperty() - FIXME: should be freed ?
|
||||
let actual_type = new x11.Atom;
|
||||
let actual_format = new ctypes.int;
|
||||
@ -458,7 +442,7 @@ firetray.Window = {
|
||||
log.debug("props="+props+", size="+props.constructor.size);
|
||||
|
||||
return [props, nitems];
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* check the state of a window by its EWMH window state. This is more
|
||||
@ -466,7 +450,7 @@ firetray.Window = {
|
||||
* based on WM_STATE. For instance, WM_STATE becomes 'Iconic' on virtual
|
||||
* desktop change...
|
||||
*/
|
||||
getXWindowStates: function(xwin) {
|
||||
firetray.Window.getXWindowStates = function(xwin) {
|
||||
let winStates = 0;
|
||||
|
||||
let [propsFound, nitems] =
|
||||
@ -492,9 +476,9 @@ firetray.Window = {
|
||||
x11.XFree(propsFound);
|
||||
|
||||
return winStates;
|
||||
},
|
||||
};
|
||||
|
||||
getXWindowDesktop: function(xwin) {
|
||||
firetray.Window.getXWindowDesktop = function(xwin) {
|
||||
let desktop = null;
|
||||
|
||||
let [propsFound, nitems] =
|
||||
@ -512,25 +496,9 @@ firetray.Window = {
|
||||
x11.XFree(propsFound);
|
||||
|
||||
return desktop;
|
||||
},
|
||||
};
|
||||
|
||||
getWindowTitle: function(xid) {
|
||||
let title = firetray.Handler.windows[xid].baseWin.title;
|
||||
log.debug("|baseWin.title="+title+"|");
|
||||
let tailIndex;
|
||||
tailIndex = title.indexOf(" - Mozilla "+firetray.Handler.appName);
|
||||
if (tailIndex === -1)
|
||||
tailIndex = title.indexOf(" - "+firetray.Handler.appName);
|
||||
|
||||
if (tailIndex !== -1)
|
||||
return title.substring(0, tailIndex);
|
||||
else if (title === "Mozilla "+firetray.Handler.appName)
|
||||
return title;
|
||||
else
|
||||
return null;
|
||||
},
|
||||
|
||||
checkSubscribedEventMasks: function(xid) {
|
||||
firetray.Window.checkSubscribedEventMasks = function(xid) {
|
||||
let xWindowAttributes = new x11.XWindowAttributes;
|
||||
let status = x11.XGetWindowAttributes(x11.current.Display, xid, xWindowAttributes.address());
|
||||
log.debug("xWindowAttributes: "+xWindowAttributes);
|
||||
@ -541,9 +509,9 @@ firetray.Window = {
|
||||
if ((xEventMask & xEventMaskNeeded) !== xEventMaskNeeded) {
|
||||
log.error("missing mandatory event-masks"); // change with gdk_window_set_events()
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
filterWindow: function(xev, gdkEv, data) {
|
||||
firetray.Window.filterWindow = function(xev, gdkEv, data) {
|
||||
if (!xev)
|
||||
return gdk.GDK_FILTER_CONTINUE;
|
||||
|
||||
@ -561,7 +529,6 @@ firetray.Window = {
|
||||
// when app hidden at startup, then called from command line without
|
||||
// any argument (not through FireTray that is)
|
||||
log.warn("window not visible, correcting visibility");
|
||||
firetray.Window.updateVisibility(xid, true);
|
||||
log.debug("visibleWindowsCount="+firetray.Handler.visibleWindowsCount);
|
||||
}
|
||||
break;
|
||||
@ -572,17 +539,12 @@ firetray.Window = {
|
||||
let winStates = firetray.Window.getXWindowStates(xid);
|
||||
let isHidden = winStates & FIRETRAY_XWINDOW_HIDDEN;
|
||||
log.debug("winStates="+winStates+", isHidden="+isHidden);
|
||||
// NOTE: Gecko 8.0 provides the 'sizemodechange' event
|
||||
// NOTE: Gecko 8.0 provides the 'sizemodechange' event, which comes once
|
||||
// the window is minimized. i.e. preventDefault() or returning false won't
|
||||
// prevent the event.
|
||||
if (isHidden) {
|
||||
log.debug("GOT ICONIFIED");
|
||||
let hides_on_minimize = firetray.Utils.prefService.getBoolPref('hides_on_minimize');
|
||||
let hides_single_window = firetray.Utils.prefService.getBoolPref('hides_single_window');
|
||||
if (hides_on_minimize) {
|
||||
if (hides_single_window)
|
||||
firetray.Handler.hideWindow(xid);
|
||||
else
|
||||
firetray.Handler.hideAllWindows();
|
||||
}
|
||||
firetray.Handler.onMinimize(xid);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -592,15 +554,18 @@ firetray.Window = {
|
||||
}
|
||||
|
||||
return gdk.GDK_FILTER_CONTINUE;
|
||||
},
|
||||
};
|
||||
|
||||
startupFilter: function(xev, gdkEv, data) {
|
||||
firetray.Window.startupFilter = function(xev, gdkEv, data) {
|
||||
if (!xev)
|
||||
return gdk.GDK_FILTER_CONTINUE;
|
||||
|
||||
let xany = ctypes.cast(xev, x11.XAnyEvent.ptr);
|
||||
let xid = xany.contents.window;
|
||||
|
||||
// MapRequest already taken by window manager. Not sure we could be notified
|
||||
// *before* the window is actually mapped, in order to minimize it before
|
||||
// it's shown.
|
||||
if (xany.contents.type === x11.MapNotify) {
|
||||
gdk.gdk_window_remove_filter(firetray.Handler.gdkWindows.get(xid),
|
||||
firetray.Handler.windows[xid].startupFilterCb, null);
|
||||
@ -611,9 +576,9 @@ firetray.Window = {
|
||||
}
|
||||
|
||||
return gdk.GDK_FILTER_CONTINUE;
|
||||
},
|
||||
};
|
||||
|
||||
showAllWindowsAndActivate: function() {
|
||||
firetray.Window.showAllWindowsAndActivate = function() {
|
||||
let visibilityRate = firetray.Handler.visibleWindowsCount/firetray.Handler.windowsCount;
|
||||
log.debug("visibilityRate="+visibilityRate);
|
||||
if (visibilityRate < 1)
|
||||
@ -621,9 +586,9 @@ firetray.Window = {
|
||||
|
||||
for(var key in firetray.Handler.windows); // FIXME: this is not the proper way for finding the last registered window !
|
||||
firetray.Window.activate(key);
|
||||
},
|
||||
};
|
||||
|
||||
attachOnFocusInCallback: function(xid) {
|
||||
firetray.Window.attachOnFocusInCallback = function(xid) {
|
||||
log.debug("attachOnFocusInCallback xid="+xid);
|
||||
this.signals['focus-in'].callback[xid] =
|
||||
gtk.GCallbackWidgetFocusEvent_t(firetray.Window.onFocusIn);
|
||||
@ -631,20 +596,20 @@ firetray.Window = {
|
||||
firetray.Handler.gtkWindows.get(xid), "focus-in-event",
|
||||
firetray.Window.signals['focus-in'].callback[xid], null);
|
||||
log.debug("focus-in handler="+this.signals['focus-in'].handler[xid]);
|
||||
},
|
||||
};
|
||||
|
||||
detachOnFocusInCallback: function(xid) {
|
||||
firetray.Window.detachOnFocusInCallback = function(xid) {
|
||||
log.debug("detachOnFocusInCallback xid="+xid);
|
||||
let gtkWin = firetray.Handler.gtkWindows.get(xid);
|
||||
gobject.g_signal_handler_disconnect(gtkWin, this.signals['focus-in'].handler[xid]);
|
||||
delete this.signals['focus-in'].callback[xid];
|
||||
delete this.signals['focus-in'].handler[xid];
|
||||
},
|
||||
};
|
||||
|
||||
// NOTE: fluxbox issues a FocusIn event when switching workspace
|
||||
// by hotkey, which means 2 FocusIn events when switching to a moz app :(
|
||||
// (http://sourceforge.net/tracker/index.php?func=detail&aid=3190205&group_id=35398&atid=413960)
|
||||
onFocusIn: function(widget, event, data) {
|
||||
firetray.Window.onFocusIn = function(widget, event, data) {
|
||||
log.debug("onFocusIn");
|
||||
let xid = firetray.Window.getXIDFromGtkWidget(widget);
|
||||
log.debug("xid="+xid);
|
||||
@ -654,9 +619,7 @@ firetray.Window = {
|
||||
if (firetray.Handler.isChatEnabled() && firetray.Chat.initialized) {
|
||||
firetray.Chat.stopGetAttentionMaybe(xid);
|
||||
}
|
||||
}
|
||||
|
||||
}; // firetray.Window
|
||||
};
|
||||
|
||||
|
||||
///////////////////////// firetray.Handler overriding /////////////////////////
|
||||
@ -667,8 +630,6 @@ firetray.Handler.dumpWindows = function() {
|
||||
for (let winId in firetray.Handler.windows) log.info(winId+"="+firetray.Handler.gtkWindows.get(winId));
|
||||
};
|
||||
|
||||
firetray.Handler.getWindowIdFromChromeWindow = firetray.Window.getXIDFromChromeWindow;
|
||||
|
||||
firetray.Handler.registerWindow = function(win) {
|
||||
log.debug("register window");
|
||||
|
||||
@ -677,6 +638,9 @@ firetray.Handler.registerWindow = function(win) {
|
||||
this.windows[xid] = {};
|
||||
this.windows[xid].chromeWin = win;
|
||||
this.windows[xid].baseWin = baseWin;
|
||||
Object.defineProperties(this.windows[xid], {
|
||||
"visible": { get: function(){return firetray.Window.getVisibility(xid);} }
|
||||
});
|
||||
firetray.Window.checkSubscribedEventMasks(xid);
|
||||
try {
|
||||
this.gtkWindows.insert(xid, gtkWin);
|
||||
@ -688,10 +652,6 @@ firetray.Handler.registerWindow = function(win) {
|
||||
+" windows open. This breaks FireTray and most probably "
|
||||
+firetray.Handler.appName+".");
|
||||
}
|
||||
this.windowsCount += 1;
|
||||
// NOTE: no need to check for window state to set visibility because all
|
||||
// windows *are* shown at startup
|
||||
firetray.Window.updateVisibility(xid, true);
|
||||
log.debug("window "+xid+" registered");
|
||||
// NOTE: shouldn't be necessary to gtk_widget_add_events(gtkWin, gdk.GDK_ALL_EVENTS_MASK);
|
||||
|
||||
@ -724,33 +684,13 @@ firetray.Handler.registerWindow = function(win) {
|
||||
|
||||
firetray.Handler.unregisterWindow = function(win) {
|
||||
log.debug("unregister window");
|
||||
let xid = firetray.Window.getXIDFromChromeWindow(win);
|
||||
let xid = firetray.Window.getRegisteredWinIdFromChromeWindow(win);
|
||||
return firetray.Window.unregisterWindowByXID(xid);
|
||||
};
|
||||
|
||||
firetray.Handler.showWindow = firetray.Window.show;
|
||||
firetray.Handler.hideWindow = firetray.Window.hide;
|
||||
|
||||
firetray.Handler.showHideAllWindows = function(gtkStatusIcon, userData) {
|
||||
log.debug("showHideAllWindows: "+userData);
|
||||
// NOTE: showHideAllWindows being a callback, we need to use
|
||||
// 'firetray.Handler' explicitely instead of 'this'
|
||||
|
||||
log.debug("visibleWindowsCount="+firetray.Handler.visibleWindowsCount);
|
||||
log.debug("windowsCount="+firetray.Handler.windowsCount);
|
||||
let visibilityRate = firetray.Handler.visibleWindowsCount/firetray.Handler.windowsCount;
|
||||
log.debug("visibilityRate="+visibilityRate);
|
||||
if ((0.5 < visibilityRate) && (visibilityRate < 1)
|
||||
|| visibilityRate === 0) { // TODO: should be configurable
|
||||
firetray.Handler.showAllWindows();
|
||||
} else {
|
||||
firetray.Handler.hideAllWindows();
|
||||
}
|
||||
|
||||
let stopPropagation = true;
|
||||
return stopPropagation;
|
||||
};
|
||||
|
||||
firetray.Handler.showAllWindowsAndActivate = firetray.Window.showAllWindowsAndActivate;
|
||||
firetray.Handler.activateLastWindowCb = function(gtkStatusIcon, gdkEvent, userData) {
|
||||
log.debug("activateLastWindowCb");
|
||||
@ -778,6 +718,10 @@ firetray.Handler.getActiveWindow = function() {
|
||||
return activeWin;
|
||||
};
|
||||
|
||||
firetray.Handler.windowGetAttention = function(winId) {
|
||||
firetray.Window.setUrgency(winId, true);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* init X11 Display and handled XAtoms.
|
||||
|
@ -6,7 +6,9 @@ const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
const FIRETRAY_LOG_LEVEL = "Warn"; // "All" for debugging
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const FIRETRAY_LOG_LEVEL = "All"; // "All" for debugging
|
||||
|
||||
const COLOR_NORMAL = "";
|
||||
const COLOR_RESET = "\033[m";
|
||||
@ -45,6 +47,7 @@ var colorTermLogColors = {
|
||||
if ("undefined" == typeof(firetray)) {
|
||||
var firetray = {};
|
||||
};
|
||||
var LogMod;
|
||||
|
||||
// https://wiki.mozilla.org/Labs/JS_Modules#Logging
|
||||
firetray.Logging = {
|
||||
@ -53,17 +56,22 @@ firetray.Logging = {
|
||||
init: function() {
|
||||
if (this.initialized) return;
|
||||
|
||||
["resource://services-common/log4moz.js", // FF
|
||||
["resource://gre/modules/Log.jsm", // FF 27+
|
||||
"resource://services-common/log4moz.js", // FF
|
||||
"resource:///app/modules/gloda/log4moz.js", // TB
|
||||
"resource://firetray/log4moz.js"] // default
|
||||
.forEach(function(file){
|
||||
try {Cu.import(file);} catch(x) {}
|
||||
}, this);
|
||||
|
||||
if ("undefined" == typeof(Log4Moz)) {
|
||||
let errMsg = "log4moz.js not found";
|
||||
if ("undefined" != typeof(Log)) {
|
||||
LogMod = Log;
|
||||
} else if ("undefined" != typeof(Log4Moz)) {
|
||||
LogMod = Log4Moz;
|
||||
} else {
|
||||
let errMsg = "Log module not found";
|
||||
dump(errMsg+"\n");
|
||||
Cu.ReportError(errMsg);
|
||||
Cu.reportError(errMsg);
|
||||
};
|
||||
|
||||
this.setupLogging("firetray");
|
||||
@ -77,24 +85,9 @@ firetray.Logging = {
|
||||
setupLogging: function(loggerName) {
|
||||
|
||||
// lifted from log4moz.js
|
||||
function SimpleFormatter(dateFormat) {
|
||||
if (dateFormat)
|
||||
this.dateFormat = dateFormat;
|
||||
}
|
||||
function SimpleFormatter() {}
|
||||
SimpleFormatter.prototype = {
|
||||
__proto__: Log4Moz.Formatter.prototype,
|
||||
|
||||
_dateFormat: null,
|
||||
|
||||
get dateFormat() {
|
||||
if (!this._dateFormat)
|
||||
this._dateFormat = "%Y-%m-%d %H:%M:%S";
|
||||
return this._dateFormat;
|
||||
},
|
||||
|
||||
set dateFormat(format) {
|
||||
this._dateFormat = format;
|
||||
},
|
||||
__proto__: LogMod.Formatter.prototype,
|
||||
|
||||
format: function(message) {
|
||||
let messageString = "";
|
||||
@ -108,7 +101,9 @@ firetray.Logging = {
|
||||
([,mo] in Iterator(message.messageObjects))].join(" ");
|
||||
|
||||
let date = new Date(message.time);
|
||||
let stringLog = date.toLocaleFormat(this.dateFormat) + " " +
|
||||
let dateStr = date.getHours() + ":" + date.getMinutes() + ":" +
|
||||
date.getSeconds() + "." + date.getMilliseconds();
|
||||
let stringLog = dateStr + " " +
|
||||
message.levelDesc + " " + message.loggerName + " " +
|
||||
messageString + "\n";
|
||||
|
||||
@ -119,10 +114,7 @@ firetray.Logging = {
|
||||
}
|
||||
};
|
||||
|
||||
function ColorTermFormatter(dateFormat) {
|
||||
if (dateFormat)
|
||||
this.dateFormat = dateFormat;
|
||||
}
|
||||
function ColorTermFormatter() {}
|
||||
ColorTermFormatter.prototype = {
|
||||
__proto__: SimpleFormatter.prototype,
|
||||
|
||||
@ -136,26 +128,30 @@ firetray.Logging = {
|
||||
};
|
||||
|
||||
// Loggers are hierarchical, affiliation is handled by a '.' in the name.
|
||||
this._logger = Log4Moz.repository.getLogger(loggerName);
|
||||
this._logger = LogMod.repository.getLogger(loggerName);
|
||||
// Lowering this log level will affect all of our addon output
|
||||
this._logger.level = Log4Moz.Level[FIRETRAY_LOG_LEVEL];
|
||||
this._logger.level = LogMod.Level[FIRETRAY_LOG_LEVEL];
|
||||
|
||||
// A console appender outputs to the JS Error Console
|
||||
let dateFormat = "%T";
|
||||
let simpleFormatter = new SimpleFormatter(dateFormat);
|
||||
let capp = new Log4Moz.ConsoleAppender(simpleFormatter);
|
||||
capp.level = Log4Moz.Level["Debug"];
|
||||
let simpleFormatter = new SimpleFormatter();
|
||||
let capp = new LogMod.ConsoleAppender(simpleFormatter);
|
||||
capp.level = LogMod.Level["Debug"];
|
||||
this._logger.addAppender(capp);
|
||||
|
||||
// A dump appender outputs to standard out
|
||||
let colorFormatter = new ColorTermFormatter(dateFormat);
|
||||
let dapp = new Log4Moz.DumpAppender(colorFormatter);
|
||||
dapp.level = Log4Moz.Level["Debug"];
|
||||
let dumpFormatter;
|
||||
if (Services.appinfo.OS.match(/(^Linux|^Darwin|BSD$)/)) {
|
||||
dumpFormatter = new ColorTermFormatter();
|
||||
} else {
|
||||
dumpFormatter = new SimpleFormatter();
|
||||
}
|
||||
let dapp = new LogMod.DumpAppender(dumpFormatter);
|
||||
dapp.level = LogMod.Level["Debug"];
|
||||
this._logger.addAppender(dapp);
|
||||
},
|
||||
|
||||
getLogger: function(loggerName){
|
||||
return Log4Moz.repository.getLogger(loggerName);
|
||||
return LogMod.repository.getLogger(loggerName);
|
||||
}
|
||||
|
||||
}; // firetray.Logging
|
||||
|
160
src/modules/winnt/FiretrayPopupMenu.jsm
Normal file
@ -0,0 +1,160 @@
|
||||
/* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
var EXPORTED_SYMBOLS = [ "firetray" ];
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/ctypes.jsm");
|
||||
Cu.import("resource://firetray/ctypes/winnt/win32.jsm");
|
||||
Cu.import("resource://firetray/ctypes/winnt/user32.jsm");
|
||||
Cu.import("resource://firetray/commons.js");
|
||||
firetray.Handler.subscribeLibsForClosing([user32]);
|
||||
|
||||
let log = firetray.Logging.getLogger("firetray.PopupMenu");
|
||||
|
||||
if ("undefined" == typeof(firetray.StatusIcon))
|
||||
log.error("This module MUST be imported from/after StatusIcon !");
|
||||
|
||||
// popupmenu items
|
||||
const IDM_PREF = 100;
|
||||
const IDM_QUIT = 200;
|
||||
const IDM_NEW_MSG = 300;
|
||||
const IDM_NEW_WND = 400;
|
||||
const IDM_RESET = 500;
|
||||
|
||||
|
||||
firetray.PopupMenu = {
|
||||
initialized: false,
|
||||
menu: null,
|
||||
|
||||
init: function() {
|
||||
this.create();
|
||||
|
||||
this.initialized = true;
|
||||
return true;
|
||||
},
|
||||
|
||||
shutdown: function() {
|
||||
this.destroy();
|
||||
|
||||
log.debug("Disabling PopupMenu");
|
||||
this.initialized = false;
|
||||
},
|
||||
|
||||
create: function() {
|
||||
this.menu = user32.CreatePopupMenu();
|
||||
log.debug("menu="+this.menu);
|
||||
|
||||
this.insertMenuItem('Quit', 'quit', IDM_QUIT);
|
||||
this.insertSeparator();
|
||||
this.insertMenuItem('Preferences', 'prefs', IDM_PREF);
|
||||
|
||||
let menuSeparatorAdded = false;
|
||||
if (firetray.Handler.inBrowserApp) {
|
||||
this.insertSeparator();
|
||||
menuSeparatorAdded = true;
|
||||
this.insertMenuItem('NewWindow', 'new-wnd', IDM_NEW_WND);
|
||||
}
|
||||
|
||||
if (firetray.Handler.inMailApp) {
|
||||
if (!menuSeparatorAdded) {
|
||||
this.insertSeparator();
|
||||
}
|
||||
this.insertMenuItem('NewMessage', 'new-msg', IDM_NEW_MSG);
|
||||
this.insertMenuItem('ResetIcon', 'reset', IDM_RESET);
|
||||
}
|
||||
|
||||
log.debug("PopupMenu created");
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
user32.DestroyMenu(this.menu);
|
||||
log.debug("PopupMenu destroyed");
|
||||
},
|
||||
|
||||
insertMenuItem: function(itemName, iconName, actionId) {
|
||||
var menuItemLabel = firetray.Utils.strings.GetStringFromName("popupMenu.itemLabel."+itemName);
|
||||
let mii = new user32.MENUITEMINFOW();
|
||||
// BUG: ctypes doesn't detect wrong field assignments mii.size = ... ('size' undefined)
|
||||
mii.cbSize = user32.MENUITEMINFOW.size;
|
||||
mii.fMask = user32.MIIM_ID | user32.MIIM_STRING | user32.MIIM_DATA;
|
||||
mii.wID = actionId;
|
||||
// mii.dwItemData = win32.ULONG_PTR(actionId);
|
||||
mii.dwTypeData = win32._T(menuItemLabel);
|
||||
/* Under XP, putting a bitmap into hbmpItem results in ugly icons. We
|
||||
should probably use HBMMENU_CALLBACK as explained in
|
||||
http://www.nanoant.com/programming/themed-menus-icons-a-complete-vista-xp-solution.
|
||||
But for now, we just don't display icons in XP-. */
|
||||
if (win32.WINVER >= win32.WIN_VERSIONS["Vista"]) {
|
||||
mii.fMask |= user32.MIIM_BITMAP;
|
||||
mii.hbmpItem = firetray.StatusIcon.bitmaps.get(iconName);
|
||||
}
|
||||
log.debug("mii="+mii);
|
||||
if (!user32.InsertMenuItemW(this.menu, 0, true, mii.address())) {
|
||||
log.error("InsertMenuItemW failed winLastError="+ctypes.winLastError);
|
||||
}
|
||||
},
|
||||
|
||||
insertSeparator: function() {
|
||||
user32.InsertMenuW(this.menu, 0, user32.MF_BYPOSITION|user32.MF_SEPARATOR,
|
||||
0, null);
|
||||
},
|
||||
|
||||
// FIXME: need to handle hides_single_window=false
|
||||
addWindowItemAndSeparatorMaybe: function(wid) {
|
||||
if (firetray.Handler.visibleWindowsCount === firetray.Handler.windowsCount)
|
||||
this.insertSeparator();
|
||||
this.addWindowItem(wid);
|
||||
},
|
||||
removeWindowItemAndSeparatorMaybe: function(wid) {
|
||||
this.removeWindowItem(wid);
|
||||
if (firetray.Handler.visibleWindowsCount === firetray.Handler.windowsCount - 1)
|
||||
user32.DeleteMenu(this.menu, 0, user32.MF_BYPOSITION);
|
||||
},
|
||||
|
||||
addWindowItem: function(wid) {
|
||||
let title = firetray.Window.getWindowTitle(wid);
|
||||
let mii = new user32.MENUITEMINFOW();
|
||||
mii.cbSize = user32.MENUITEMINFOW.size;
|
||||
mii.fMask = user32.MIIM_ID | user32.MIIM_STRING | user32.MIIM_DATA;
|
||||
mii.wID = ctypes.UInt64(wid);
|
||||
mii.dwTypeData = win32._T(title);
|
||||
if (!user32.InsertMenuItemW(this.menu, 0, true, mii.address())) {
|
||||
log.error("InsertMenuItemW failed winLastError="+ctypes.winLastError);
|
||||
}
|
||||
},
|
||||
removeWindowItem: function(wid) {
|
||||
let itemId = ctypes.UInt64(wid);
|
||||
if (!user32.DeleteMenu(this.menu, itemId, user32.MF_BYCOMMAND)) {
|
||||
log.error("DeleteMenu failed winLastError="+ctypes.winLastError);
|
||||
}
|
||||
},
|
||||
|
||||
processMenuItem: function(itemId) {
|
||||
let wid = firetray.Win32.hwndToHexStr(win32.HWND(itemId));
|
||||
if (firetray.Handler.windows[wid]) {
|
||||
firetray.Handler.showWindow(wid);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (itemId) {
|
||||
case IDM_PREF: firetray.Handler.openPrefWindow(); break;
|
||||
case IDM_QUIT: firetray.Handler.quitApplication(); break;
|
||||
case IDM_NEW_MSG: firetray.Handler.openMailMessage(); break;
|
||||
case IDM_NEW_WND: firetray.Handler.openBrowserWindow(); break;
|
||||
case IDM_RESET: firetray.Handler.setIconImageDefault(); break;
|
||||
default:
|
||||
log.error("no action for itemId ("+itemId+")");
|
||||
}
|
||||
}
|
||||
|
||||
}; // firetray.PopupMenu
|
||||
|
||||
firetray.Handler.addPopupMenuWindowItemAndSeparatorMaybe =
|
||||
firetray.PopupMenu.addWindowItemAndSeparatorMaybe.bind(firetray.PopupMenu);
|
||||
firetray.Handler.removePopupMenuWindowItemAndSeparatorMaybe =
|
||||
firetray.PopupMenu.removeWindowItemAndSeparatorMaybe.bind(firetray.PopupMenu);
|
467
src/modules/winnt/FiretrayStatusIcon.jsm
Normal file
@ -0,0 +1,467 @@
|
||||
/* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
/* The tray icon for the main app. We need a hidden proxy window as (1) we want
|
||||
a unique icon, (2) the icon sends notifications to a single window. */
|
||||
|
||||
var EXPORTED_SYMBOLS = [ "firetray" ];
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
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");
|
||||
Cu.import("resource://firetray/winnt/FiretrayWin32.jsm");
|
||||
Cu.import("resource://firetray/commons.js");
|
||||
firetray.Handler.subscribeLibsForClosing([gdi32, kernel32, shell32, user32]);
|
||||
|
||||
let log = firetray.Logging.getLogger("firetray.StatusIcon");
|
||||
|
||||
if ("undefined" == typeof(firetray.Handler))
|
||||
log.error("This module MUST be imported from/after FiretrayHandler !");
|
||||
|
||||
const ICON_CHROME_PATHS = {
|
||||
'blank-icon': "chrome://firetray/skin/winnt/blank-icon.bmp",
|
||||
'mail-unread': "chrome://firetray/skin/winnt/mail-unread.ico",
|
||||
// these are for the popup menu:
|
||||
'prefs': "chrome://firetray/skin/winnt/gtk-preferences.bmp",
|
||||
'quit': "chrome://firetray/skin/winnt/application-exit.bmp",
|
||||
'new-wnd': "chrome://firetray/skin/winnt/document-new.bmp",
|
||||
'new-msg': "chrome://firetray/skin/winnt/gtk-edit.bmp",
|
||||
'reset': "chrome://firetray/skin/winnt/gtk-apply.bmp"
|
||||
};
|
||||
|
||||
|
||||
firetray.StatusIcon = {
|
||||
initialized: false,
|
||||
callbacks: {}, // pointers to JS functions. MUST LIVE DURING ALL THE EXECUTION
|
||||
notifyIconData: null,
|
||||
hwndProxy: 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_custom: 'app-custom',
|
||||
mail_icon_custom: 'mail-custom'
|
||||
},
|
||||
|
||||
init: function() {
|
||||
this.loadImages();
|
||||
this.create();
|
||||
firetray.Handler.setIconImageDefault();
|
||||
|
||||
Cu.import("resource://firetray/winnt/FiretrayPopupMenu.jsm");
|
||||
if (!firetray.PopupMenu.init())
|
||||
return false;
|
||||
|
||||
this.initialized = true;
|
||||
return true;
|
||||
},
|
||||
|
||||
shutdown: function() {
|
||||
log.debug("Disabling StatusIcon");
|
||||
firetray.PopupMenu.shutdown();
|
||||
|
||||
this.destroy();
|
||||
this.destroyImages();
|
||||
|
||||
this.initialized = false;
|
||||
return true;
|
||||
},
|
||||
|
||||
loadThemedIcons: function() { },
|
||||
|
||||
loadImages: function() {
|
||||
// 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_custom', 'mail_icon_custom'].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 ICON_CHROME_PATHS) {
|
||||
let path = firetray.Utils.chromeToPath(ICON_CHROME_PATHS[imgName]);
|
||||
let img = this.loadImageFromFile(path);
|
||||
if (img)
|
||||
this[this.IMG_TYPES[img['type']]['map']].insert(imgName, img['himg']);
|
||||
}
|
||||
},
|
||||
|
||||
loadImageCustom: function(prefname) {
|
||||
log.debug("loadImageCustom pref="+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 = 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 '"+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
|
||||
destroyImages: function() {
|
||||
[this.icons, this.bitmaps].forEach(function(map, idx, ary) {
|
||||
let keys = map.keys;
|
||||
for (let i=0, len=keys.length; i<len; ++i) {
|
||||
let imgName = keys[i];
|
||||
map.remove(imgName);
|
||||
}
|
||||
});
|
||||
log.debug("Icons destroyed");
|
||||
},
|
||||
|
||||
create: function() {
|
||||
let hwnd_hidden = this.createProxyWindow();
|
||||
|
||||
nid = new shell32.NOTIFYICONDATAW();
|
||||
nid.cbSize = shell32.NOTIFYICONDATAW_SIZE();
|
||||
log.debug("SIZE="+nid.cbSize);
|
||||
nid.szTip = firetray.Handler.appName;
|
||||
nid.hIcon = this.icons.get('app');
|
||||
nid.hWnd = hwnd_hidden;
|
||||
nid.uCallbackMessage = firetray.Win32.WM_TRAYMESSAGE;
|
||||
nid.uFlags = shell32.NIF_ICON | shell32.NIF_MESSAGE | shell32.NIF_TIP;
|
||||
nid.uVersion = shell32.NOTIFYICON_VERSION_4;
|
||||
|
||||
// Install the icon
|
||||
rv = shell32.Shell_NotifyIconW(shell32.NIM_ADD, nid.address());
|
||||
log.debug("Shell_NotifyIcon ADD="+rv+" winLastError="+ctypes.winLastError); // ERROR_INVALID_WINDOW_HANDLE(1400)
|
||||
rv = shell32.Shell_NotifyIconW(shell32.NIM_SETVERSION, nid.address());
|
||||
log.debug("Shell_NotifyIcon SETVERSION="+rv+" winLastError="+ctypes.winLastError);
|
||||
|
||||
this.notifyIconData = nid;
|
||||
this.hwndProxy = hwnd_hidden;
|
||||
},
|
||||
|
||||
createProxyWindow: function() {
|
||||
this.registerWindowClass();
|
||||
|
||||
let hwnd_hidden = user32.CreateWindowExW(
|
||||
0, win32.LPCTSTR(this.WNDCLASS_ATOM), // lpClassName can also be _T(WNDCLASS_NAME)
|
||||
"Firetray Message Window", 0,
|
||||
user32.CW_USEDEFAULT, user32.CW_USEDEFAULT, user32.CW_USEDEFAULT, user32.CW_USEDEFAULT,
|
||||
null, null, firetray.Win32.hInstance, null);
|
||||
log.debug("CreateWindow="+!hwnd_hidden.isNull()+" winLastError="+ctypes.winLastError);
|
||||
|
||||
this.callbacks.proxyWndProc = user32.WNDPROC(firetray.StatusIcon.proxyWndProc);
|
||||
let procPrev = user32.SetWindowLongW(hwnd_hidden, user32.GWLP_WNDPROC,
|
||||
ctypes.cast(this.callbacks.proxyWndProc, win32.LONG_PTR));
|
||||
log.debug("procPrev="+procPrev+" winLastError="+ctypes.winLastError);
|
||||
|
||||
firetray.Win32.acceptAllMessages(hwnd_hidden);
|
||||
|
||||
return hwnd_hidden;
|
||||
},
|
||||
|
||||
registerWindowClass: function() {
|
||||
let wndClass = new user32.WNDCLASSEXW();
|
||||
wndClass.cbSize = user32.WNDCLASSEXW.size;
|
||||
wndClass.lpfnWndProc = ctypes.cast(user32.DefWindowProcW, user32.WNDPROC);
|
||||
wndClass.hInstance = firetray.Win32.hInstance;
|
||||
wndClass.lpszClassName = win32._T(this.WNDCLASS_NAME);
|
||||
this.WNDCLASS_ATOM = user32.RegisterClassExW(wndClass.address());
|
||||
log.debug("WNDCLASS_ATOM="+this.WNDCLASS_ATOM);
|
||||
},
|
||||
|
||||
proxyWndProc: function(hWnd, uMsg, wParam, lParam) {
|
||||
// log.debug("ProxyWindowProc CALLED: hWnd="+hWnd+", uMsg="+uMsg+", wParam="+wParam+", lParam="+lParam);
|
||||
|
||||
// FIXME: WM_TASKBARCREATED is needed in case of explorer crash
|
||||
// http://twigstechtips.blogspot.fr/2011/02/c-detect-when-windows-explorer-has.html
|
||||
if (uMsg === firetray.Win32.WM_TASKBARCREATED) {
|
||||
log.info("____________TASKBARCREATED");
|
||||
|
||||
} else if (uMsg === firetray.Win32.WM_TRAYMESSAGE) {
|
||||
|
||||
switch (win32.LOWORD(lParam)) {
|
||||
case win32.WM_LBUTTONUP:
|
||||
log.debug("WM_LBUTTONUP");
|
||||
firetray.Handler.showHideAllWindows();
|
||||
break;
|
||||
case win32.WM_RBUTTONUP:
|
||||
log.debug("WM_RBUTTONUP");
|
||||
case win32.WM_CONTEXTMENU:
|
||||
log.debug("WM_CONTEXTMENU");
|
||||
/* Can't determine tray icon position precisely: the mouse cursor can
|
||||
move between WM_RBUTTONDOWN and WM_RBUTTONUP, or the icon can have
|
||||
been moved inside the notification area... so we opt for the easy
|
||||
solution. */
|
||||
let pos = user32.GetMessagePos();
|
||||
let xPos = win32.GET_X_LPARAM(pos), yPos = win32.GET_Y_LPARAM(pos);
|
||||
log.debug(" x="+xPos+" y="+yPos);
|
||||
user32.SetForegroundWindow(hWnd);
|
||||
user32.TrackPopupMenu(firetray.PopupMenu.menu, user32.TPM_RIGHTALIGN|user32.TPM_BOTTOMALIGN, xPos, yPos, 0, hWnd, null);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
} else {
|
||||
switch (uMsg) {
|
||||
case win32.WM_SYSCOMMAND:
|
||||
log.debug("WM_SYSCOMMAND wParam="+wParam+", lParam="+lParam);
|
||||
break;
|
||||
case win32.WM_COMMAND:
|
||||
log.debug("WM_COMMAND wParam="+wParam+", lParam="+lParam);
|
||||
firetray.PopupMenu.processMenuItem(wParam);
|
||||
break;
|
||||
case win32.WM_MENUCOMMAND:
|
||||
log.debug("WM_MENUCOMMAND wParam="+wParam+", lParam="+lParam);
|
||||
break;
|
||||
case win32.WM_MENUCHAR:
|
||||
log.debug("WM_MENUCHAR wParam="+wParam+", lParam="+lParam);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return user32.DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
||||
},
|
||||
|
||||
getIconFromWindow: function(hwnd) {
|
||||
let rv = user32.SendMessageW(hwnd, user32.WM_GETICON, user32.ICON_SMALL, 0);
|
||||
log.debug("SendMessageW winLastError="+ctypes.winLastError);
|
||||
// result is a ctypes.Int64. So we need to create a CData from it before
|
||||
// casting it to a HICON.
|
||||
let icon = ctypes.cast(win32.LRESULT(rv), win32.HICON);
|
||||
if (icon.isNull()) { // from the window class
|
||||
rv = user32.GetClassLong(hwnd, user32.GCLP_HICONSM);
|
||||
icon = ctypes.cast(win32.ULONG_PTR(rv), win32.HICON);
|
||||
log.debug("GetClassLong winLastError="+ctypes.winLastError);
|
||||
}
|
||||
if (icon.isNull()) { // from the first resource -> ERROR_RESOURCE_TYPE_NOT_FOUND(1813)
|
||||
icon = user32.LoadIconW(firetray.Win32.hInstance, win32.MAKEINTRESOURCE(0));
|
||||
log.debug("LoadIconW module winLastError="+ctypes.winLastError);
|
||||
}
|
||||
if (icon.isNull()) { // OS default icon
|
||||
icon = user32.LoadIconW(null, win32.MAKEINTRESOURCE(user32.IDI_APPLICATION));
|
||||
log.debug("LoadIconW default winLastError="+ctypes.winLastError);
|
||||
}
|
||||
log.debug("=== icon="+icon);
|
||||
return icon;
|
||||
},
|
||||
|
||||
destroyProxyWindow: function() {
|
||||
let rv = user32.DestroyWindow(this.hwndProxy);
|
||||
|
||||
rv = this.unregisterWindowClass();
|
||||
log.debug("Hidden window removed");
|
||||
},
|
||||
|
||||
unregisterWindowClass: function() {
|
||||
return user32.UnregisterClassW(win32.LPCTSTR(this.WNDCLASS_ATOM), firetray.Win32.hInstance);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
let rv = shell32.Shell_NotifyIconW(shell32.NIM_DELETE, this.notifyIconData.address());
|
||||
log.debug("Shell_NotifyIcon DELETE="+rv+" winLastError="+ctypes.winLastError);
|
||||
this.destroyProxyWindow();
|
||||
},
|
||||
|
||||
setIcon: function(iconinfo) {
|
||||
let nid = firetray.StatusIcon.notifyIconData;
|
||||
if (iconinfo.hicon)
|
||||
nid.hIcon = iconinfo.hicon;
|
||||
if (iconinfo.tip)
|
||||
nid.szTip = iconinfo.tip;
|
||||
rv = shell32.Shell_NotifyIconW(shell32.NIM_MODIFY, nid.address());
|
||||
log.debug("Shell_NotifyIcon MODIFY="+rv+" winLastError="+ctypes.winLastError);
|
||||
},
|
||||
|
||||
// rgb colors encoded in *bbggrr*
|
||||
cssColorToCOLORREF: function(csscolor) {
|
||||
let rgb = csscolor.substr(1);
|
||||
let rr = rgb.substr(0, 2);
|
||||
let gg = rgb.substr(2, 2);
|
||||
let bb = rgb.substr(4, 2);
|
||||
return parseInt("0x"+bb+gg+rr);
|
||||
},
|
||||
|
||||
// http://stackoverflow.com/questions/457050/how-to-display-text-in-system-tray-icon-with-win32-api
|
||||
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 = user32.CopyImage(blank, user32.IMAGE_BITMAP, width, height, 0);
|
||||
let hBitmapMask = gdi32.CreateCompatibleBitmap(hdc, width, height);
|
||||
user32.ReleaseDC(hWnd, hdc);
|
||||
|
||||
let hBitmapOrig = gdi32.SelectObject(hdcMem, hBitmap);
|
||||
|
||||
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);
|
||||
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 = getFont(fnHeight);
|
||||
gdi32.SelectObject(hdcMem, hFont);
|
||||
gdi32.GetTextExtentPoint32W(hdcMem, text, text.length, size.address());
|
||||
log.debug(" fnHeight="+fnHeight+" width="+size.cx);
|
||||
}
|
||||
|
||||
gdi32.SetTextColor(hdcMem, win32.COLORREF(this.cssColorToCOLORREF(color)));
|
||||
gdi32.SetBkMode(hdcMem, gdi32.TRANSPARENT); // VERY IMPORTANT
|
||||
gdi32.SetTextAlign(hdcMem, gdi32.TA_TOP|gdi32.TA_CENTER);
|
||||
log.debug(" ___ALIGN=(winLastError="+ctypes.winLastError+") "+gdi32.GetTextAlign(hdcMem));
|
||||
|
||||
let nXStart = firetray.js.floatToInt((width - size.cx)/2),
|
||||
nYStart = firetray.js.floatToInt((height - size.cy)/2);
|
||||
gdi32.TextOutW(hdcMem, width/2, nYStart+2, text, text.length); // ref point for alignment
|
||||
|
||||
gdi32.SelectObject(hdcMem, hBitmapOrig);
|
||||
|
||||
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(gdi32.SelectObject(hdcMem, hFont));
|
||||
gdi32.DeleteDC(hdcMem);
|
||||
// gdi32.DeleteDC(hdc); // already ReleaseDC's
|
||||
gdi32.DeleteObject(hBitmap);
|
||||
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 '"+name+"' 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() {
|
||||
log.debug("setIconImageDefault");
|
||||
firetray.StatusIcon.setIcon({hicon:firetray.StatusIcon.icons.get('mail-unread')});
|
||||
};
|
||||
|
||||
firetray.Handler.setIconImageCustom = function(prefname) {
|
||||
log.debug("setIconImageCustom pref="+prefname);
|
||||
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) {
|
||||
log.debug("setIconTooltip");
|
||||
firetray.StatusIcon.setIcon({tip:toolTipStr});
|
||||
};
|
||||
|
||||
firetray.Handler.setIconTooltipDefault = function() {
|
||||
log.debug("setIconTooltipDefault");
|
||||
firetray.StatusIcon.setIcon({tip:this.appName});
|
||||
};
|
||||
|
||||
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.setIcon({hicon:hicon});
|
||||
};
|
||||
|
||||
firetray.Handler.setIconVisibility = function(visible) {
|
||||
};
|
61
src/modules/winnt/FiretrayWin32.jsm
Normal file
@ -0,0 +1,61 @@
|
||||
/* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
var EXPORTED_SYMBOLS = [ "firetray" ];
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/ctypes.jsm");
|
||||
Cu.import("resource://firetray/ctypes/winnt/win32.jsm");
|
||||
Cu.import("resource://firetray/ctypes/winnt/kernel32.jsm");
|
||||
Cu.import("resource://firetray/ctypes/winnt/user32.jsm");
|
||||
Cu.import("resource://firetray/commons.js");
|
||||
firetray.Handler.subscribeLibsForClosing([kernel32, user32]);
|
||||
|
||||
let log = firetray.Logging.getLogger("firetray.Win32");
|
||||
|
||||
const kMessageTray = "_FIRETRAY_Tray";
|
||||
|
||||
if ("undefined" == typeof(firetray.Handler))
|
||||
log.error("This module MUST be imported from/after FiretrayHandler !");
|
||||
|
||||
|
||||
function Win32Env() {
|
||||
|
||||
this.hInstance = kernel32.GetModuleHandleW("xul"); // ordinary windows are created from xul.dll
|
||||
log.debug("hInstance="+this.hInstance);
|
||||
|
||||
// we use our own messages because we create a different window class than Moz
|
||||
this.WM_TASKBARCREATED = user32.RegisterWindowMessageW("TaskbarCreated");
|
||||
this.WM_TRAYMESSAGE = user32.RegisterWindowMessageW(kMessageTray);
|
||||
log.debug("WM_*="+this.WM_TASKBARCREATED+" "+this.WM_TRAYMESSAGE+" "+this.WM_TRAYCALLBACK);
|
||||
|
||||
/* if Administrator, accept messages from applications running in a lower
|
||||
privilege level */
|
||||
this.acceptAllMessages = function(hwnd) {
|
||||
let rv = null;
|
||||
log.debug(win32.WINVER+" >= "+win32.WIN_VERSIONS["7"]);
|
||||
if (win32.WINVER >= win32.WIN_VERSIONS["7"]) {
|
||||
rv = user32.ChangeWindowMessageFilterEx(hwnd, firetray.Win32.WM_TASKBARCREATED, user32.MSGFLT_ALLOW, null);
|
||||
log.debug("ChangeWindowMessageFilterEx res="+rv+" winLastError="+ctypes.winLastError);
|
||||
} else if (win32.WINVER >= win32.WINVER["Vista"]) {
|
||||
rv = user32.ChangeWindowMessageFilter(firetray.Win32.WM_TASKBARCREATED, user32.MSGFLT_ADD);
|
||||
log.debug("ChangeWindowMessageFilter res="+rv+" winLastError="+ctypes.winLastError);
|
||||
} else {
|
||||
// no UIPI
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
|
||||
// wid will be used as a string most of the time (through f.Handler.windows mainly)
|
||||
this.hwndToHexStr = function(hWnd) {
|
||||
return "0x" + ctypes.cast(hWnd, ctypes.uintptr_t).value.toString(16);
|
||||
};
|
||||
this.hexStrToHwnd = function(wid) {
|
||||
return win32.HWND(ctypes.UInt64(wid));
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
firetray.Win32 = new Win32Env();
|
294
src/modules/winnt/FiretrayWindow.jsm
Normal file
@ -0,0 +1,294 @@
|
||||
/* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
var EXPORTED_SYMBOLS = [ "firetray" ];
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/ctypes.jsm");
|
||||
Cu.import("resource://firetray/ctypes/ctypesMap.jsm");
|
||||
Cu.import("resource://firetray/ctypes/winnt/kernel32.jsm");
|
||||
Cu.import("resource://firetray/ctypes/winnt/user32.jsm");
|
||||
Cu.import("resource://firetray/ctypes/winnt/win32.jsm");
|
||||
Cu.import("resource://firetray/winnt/FiretrayWin32.jsm");
|
||||
Cu.import("resource://firetray/FiretrayWindow.jsm");
|
||||
Cu.import("resource://firetray/commons.js");
|
||||
firetray.Handler.subscribeLibsForClosing([user32, kernel32]);
|
||||
|
||||
let log = firetray.Logging.getLogger("firetray.Window");
|
||||
|
||||
if ("undefined" == typeof(firetray.Handler))
|
||||
log.error("This module MUST be imported from/after FiretrayHandler !");
|
||||
|
||||
const FIRETRAY_XWINDOW_HIDDEN = 1 << 0; // when minimized also
|
||||
const FIRETRAY_XWINDOW_MAXIMIZED = 1 << 1;
|
||||
|
||||
// We need to keep long-living references to wndProcs callbacks. As they also
|
||||
// happen to be ctypes pointers, we store them into real ctypes arrays.
|
||||
firetray.Handler.wndProcs = new ctypesMap(user32.WNDPROC);
|
||||
firetray.Handler.wndProcsOrig = new ctypesMap(user32.WNDPROC);
|
||||
firetray.Handler.procHooks = new ctypesMap(win32.HHOOK);
|
||||
firetray.Handler.procHooksRegistred = new ctypesMap(win32.HHOOK);
|
||||
|
||||
|
||||
firetray.Window = new FiretrayWindow();
|
||||
|
||||
firetray.Window.init = function() {
|
||||
this.initialized = true;
|
||||
};
|
||||
|
||||
firetray.Window.shutdown = function() {
|
||||
this.initialized = false;
|
||||
};
|
||||
|
||||
firetray.Window.getVisibility = function(wid) {
|
||||
let hwnd = firetray.Win32.hexStrToHwnd(wid);
|
||||
let style = user32.GetWindowLongW(hwnd, user32.GWL_STYLE);
|
||||
return ((style & user32.WS_VISIBLE) != 0); // user32.IsWindowVisible(hwnd);
|
||||
};
|
||||
|
||||
// firetray.Window.{show,hide} useless as we don't need to restore position and size
|
||||
firetray.Window.setVisibility = function(wid, visible) {
|
||||
log.debug("setVisibility="+visible);
|
||||
let hwnd = firetray.Win32.hexStrToHwnd(wid);
|
||||
let ret = user32.ShowWindow(hwnd, visible ? user32.SW_SHOW : user32.SW_HIDE);
|
||||
log.debug(" ShowWindow="+ret+" winLastError="+ctypes.winLastError);
|
||||
};
|
||||
|
||||
firetray.Window.wndProc = function(hWnd, uMsg, wParam, lParam) { // filterWindow
|
||||
// log.debug("wndProc CALLED: hWnd="+hWnd+", uMsg=0x"+uMsg.toString(16)+", wParam="+wParam+", lParam="+lParam);
|
||||
let wid = firetray.Win32.hwndToHexStr(hWnd);
|
||||
|
||||
if (uMsg === win32.WM_SYSCOMMAND) {
|
||||
log.debug("wndProc CALLED with WM_SYSCOMMAND wParam="+wParam);
|
||||
if (wParam === win32.SC_MINIMIZE) {
|
||||
log.debug("GOT ICONIFIED");
|
||||
if (firetray.Handler.hideOnMinimizeMaybe(wid)) {
|
||||
return 0; // processed => preventDefault
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let procPrev = firetray.Handler.wndProcsOrig.get(wid);
|
||||
return user32.CallWindowProcW(procPrev, hWnd, uMsg, wParam, lParam); // or DefWindowProcW
|
||||
};
|
||||
|
||||
// We could chain wndProcs, but adding a hook looks simpler.
|
||||
firetray.Window.showCount = 0;
|
||||
firetray.Window.startupHook = function(nCode, wParam, lParam) { // WH_CALLWNDPROC, WH_GETMESSAGE
|
||||
// log.debug("startupHook CALLED: nCode="+nCode+", wParam="+wParam+", lParam="+lParam);
|
||||
if (nCode < 0) return user32.CallNextHookEx(null, nCode, wParam, lParam); // user32.HC_ACTION
|
||||
|
||||
let cwpstruct = ctypes.cast(win32.LPARAM(lParam), user32.CWPSTRUCT.ptr).contents;
|
||||
let uMsg = cwpstruct.message;
|
||||
let hwnd = cwpstruct.hwnd;
|
||||
let wid = firetray.Win32.hwndToHexStr(hwnd);
|
||||
let wparam = cwpstruct.wParam;
|
||||
let lparam = cwpstruct.lParam;
|
||||
|
||||
if (uMsg === win32.WM_SHOWWINDOW && wparam == 1 && lparam == 0) { // shown and ShowWindow called
|
||||
log.debug("startupHook CALLED with WM_SHOWWINDOW wparam="+wparam+" lparam="+lparam);
|
||||
firetray.Window.showCount += 1;
|
||||
|
||||
if (firetray.Utils.prefService.getBoolPref('start_hidden')) {
|
||||
log.debug("start_hidden");
|
||||
|
||||
/* Compared to ShowWindow, SetWindowPlacement seems to bypass window
|
||||
animations. http://stackoverflow.com/a/6087214 */
|
||||
let placement = new user32.WINDOWPLACEMENT;
|
||||
let ret = user32.GetWindowPlacement(hwnd, placement.address());
|
||||
log.debug(" GetWindowPlacement="+ret+" winLastError="+ctypes.winLastError);
|
||||
log.debug(" PLACEMENT="+placement);
|
||||
|
||||
if (firetray.Window.showCount < 2) {
|
||||
// we can't prevent ShowWindow, so we mitigate the effect by minimizing
|
||||
// it before. This is why we'll have to restore it when unhidden.
|
||||
placement.showCmd = user32.SW_SHOWMINNOACTIVE;
|
||||
ret = user32.SetWindowPlacement(hwnd, placement.address());
|
||||
log.debug(" SetWindowPlacement="+ret+" winLastError="+ctypes.winLastError);
|
||||
|
||||
firetray.Utils.timer(
|
||||
FIRETRAY_DELAY_NOWAIT_MILLISECONDS,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT, function(){firetray.Handler.hideWindow(wid);}
|
||||
); // looks like CData (hwnd) cannot be closured
|
||||
|
||||
} else { // restore
|
||||
firetray.Window.detachHook(wid);
|
||||
|
||||
placement.showCmd = user32.SW_RESTORE;
|
||||
user32.SetWindowPlacement(hwnd, placement.address());
|
||||
}
|
||||
|
||||
} else {
|
||||
firetray.Window.detachHook(wid);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return user32.CallNextHookEx(null, nCode, wParam, lParam);
|
||||
};
|
||||
|
||||
firetray.Window.attachWndProc = function(wid, hwnd) {
|
||||
try {
|
||||
let wndProc = user32.WNDPROC(firetray.Window.wndProc);
|
||||
log.debug("proc="+wndProc);
|
||||
firetray.Handler.wndProcs.insert(wid, wndProc);
|
||||
let procPrev = user32.WNDPROC(
|
||||
user32.SetWindowLongW(hwnd, user32.GWLP_WNDPROC,
|
||||
ctypes.cast(wndProc, win32.LONG_PTR))
|
||||
);
|
||||
log.debug("procPrev="+procPrev+" winLastError="+ctypes.winLastError);
|
||||
/* we can't store WNDPROC callbacks (JS ctypes objects) with SetPropW(), as
|
||||
we need long-living refs. */
|
||||
firetray.Handler.wndProcsOrig.insert(wid, procPrev);
|
||||
|
||||
} catch (x) {
|
||||
if (x.name === "RangeError") { // instanceof not working :-(
|
||||
let msg = x+"\n\nYou seem to have more than "+FIRETRAY_WINDOW_COUNT_MAX
|
||||
+" windows open. This breaks FireTray and most probably "
|
||||
+firetray.Handler.appName+".";
|
||||
log.error(msg);
|
||||
Cu.reportError(msg);
|
||||
}else {
|
||||
log.error(x);
|
||||
Cu.reportError(x);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
firetray.Window.detachWndProc = function(wid) {
|
||||
let procPrev = firetray.Handler.wndProcsOrig.get(wid);
|
||||
let hwnd = firetray.Win32.hexStrToHwnd(wid);
|
||||
log.debug("hwnd="+hwnd);
|
||||
let proc = user32.WNDPROC(
|
||||
user32.SetWindowLongW(hwnd, user32.GWLP_WNDPROC,
|
||||
ctypes.cast(procPrev, win32.LONG_PTR))
|
||||
);
|
||||
firetray.js.assert(firetray.js.strEquals(proc, firetray.Handler.wndProcs.get(wid)),
|
||||
"Wrong WndProc replaced.");
|
||||
firetray.Handler.wndProcs.remove(wid);
|
||||
firetray.Handler.wndProcsOrig.remove(wid);
|
||||
};
|
||||
|
||||
firetray.Window.attachHook = function(wid) { // detaches itself alone
|
||||
let startupHook = user32.HOOKPROC(firetray.Window.startupHook);
|
||||
log.debug("callhk="+startupHook);
|
||||
firetray.Handler.procHooks.insert(wid, startupHook);
|
||||
// Global hooks must reside in a dll (hence hInst). This is important for
|
||||
// the scope of variables.
|
||||
let hhook = user32.SetWindowsHookExW(
|
||||
user32.WH_CALLWNDPROC, startupHook, null, kernel32.GetCurrentThreadId());
|
||||
log.debug(" hhook="+hhook+" winLastError="+ctypes.winLastError);
|
||||
firetray.Handler.procHooksRegistred.insert(wid, hhook);
|
||||
};
|
||||
|
||||
firetray.Window.detachHook = function(wid) { // detaches itself alone
|
||||
let hook = firetray.Handler.procHooksRegistred.get(wid);
|
||||
if (!user32.UnhookWindowsHookEx(hook)) {
|
||||
log.error("UnhookWindowsHookEx for window "+wid+" failed: winLastError="+ctypes.winLastError);
|
||||
return;
|
||||
}
|
||||
firetray.Handler.procHooks.remove(wid);
|
||||
firetray.Handler.procHooksRegistred.remove(wid);
|
||||
};
|
||||
|
||||
|
||||
///////////////////////// firetray.Handler overriding /////////////////////////
|
||||
|
||||
/** debug facility */
|
||||
firetray.Handler.dumpWindows = function() {
|
||||
let dumpStr = ""+firetray.Handler.windowsCount;
|
||||
for (let wid in firetray.Handler.windows) {
|
||||
dumpStr += " "+wid;
|
||||
}
|
||||
log.info(dumpStr);
|
||||
};
|
||||
|
||||
firetray.Handler.registerWindow = function(win) {
|
||||
log.debug("register window");
|
||||
|
||||
let baseWin = firetray.Handler.getWindowInterface(win, "nsIBaseWindow");
|
||||
let nativeHandle = baseWin.nativeHandle;
|
||||
let hwnd = nativeHandle ?
|
||||
firetray.Win32.hexStrToHwnd(nativeHandle) :
|
||||
user32.FindWindowW("MozillaWindowClass", win.document.title);
|
||||
let wid = firetray.Win32.hwndToHexStr(hwnd);
|
||||
log.debug("=== hwnd="+hwnd+" wid="+wid+" win.document.title: "+win.document.title);
|
||||
|
||||
if (this.windows.hasOwnProperty(wid)) {
|
||||
let msg = "Window ("+wid+") already registered.";
|
||||
log.error(msg);
|
||||
Cu.reportError(msg);
|
||||
return false;
|
||||
}
|
||||
this.windows[wid] = {};
|
||||
this.windows[wid].chromeWin = win;
|
||||
this.windows[wid].baseWin = baseWin;
|
||||
Object.defineProperties(this.windows[wid], {
|
||||
"visible": { get: function(){return firetray.Window.getVisibility(wid);} }
|
||||
});
|
||||
log.debug("window "+wid+" registered");
|
||||
|
||||
firetray.Window.attachWndProc(wid, hwnd);
|
||||
if (!firetray.Handler.appStarted) {
|
||||
firetray.Window.attachHook(wid);
|
||||
}
|
||||
|
||||
firetray.Win32.acceptAllMessages(hwnd);
|
||||
|
||||
log.debug("AFTER"); firetray.Handler.dumpWindows();
|
||||
return wid;
|
||||
};
|
||||
|
||||
firetray.Handler.unregisterWindow = function(win) {
|
||||
log.debug("unregister window");
|
||||
|
||||
let wid = firetray.Window.getRegisteredWinIdFromChromeWindow(win);
|
||||
if (!firetray.Handler.windows.hasOwnProperty(wid)) {
|
||||
log.error("can't unregister unknown window "+wid);
|
||||
return false;
|
||||
}
|
||||
|
||||
firetray.Window.detachWndProc(wid);
|
||||
|
||||
if (!delete firetray.Handler.windows[wid])
|
||||
throw new DeleteError();
|
||||
|
||||
firetray.Handler.dumpWindows();
|
||||
log.debug("window "+wid+" unregistered");
|
||||
return true;
|
||||
};
|
||||
|
||||
firetray.Handler.showWindow = function(wid) {
|
||||
firetray.Handler.removePopupMenuWindowItemAndSeparatorMaybe(wid);
|
||||
return firetray.Window.setVisibility(wid, true);
|
||||
};
|
||||
firetray.Handler.hideWindow = function(wid) {
|
||||
firetray.Handler.addPopupMenuWindowItemAndSeparatorMaybe(wid);
|
||||
return firetray.Window.setVisibility(wid, false);
|
||||
};
|
||||
|
||||
firetray.Handler.windowGetAttention = function(wid) { // see nsWindow.cpp
|
||||
for (var first in this.windows) break;
|
||||
wid = wid || first;
|
||||
let hwnd = firetray.Win32.hexStrToHwnd(wid);
|
||||
let fgWnd = user32.GetForegroundWindow();
|
||||
log.debug(hwnd+" === "+fgWnd);
|
||||
if (firetray.js.strEquals(hwnd, fgWnd) ||
|
||||
!this.windows[wid].visible)
|
||||
return;
|
||||
|
||||
let defaultCycleCount = new win32.DWORD;
|
||||
user32.SystemParametersInfoW(user32.SPI_GETFOREGROUNDFLASHCOUNT, 0,
|
||||
defaultCycleCount.address(), 0);
|
||||
log.debug("defaultCycleCount="+defaultCycleCount);
|
||||
|
||||
let flashInfo = new user32.FLASHWINFO;
|
||||
flashInfo.cbSize = user32.FLASHWINFO.size;
|
||||
flashInfo.hwnd = hwnd;
|
||||
flashInfo.dwFlags = user32.FLASHW_ALL;
|
||||
flashInfo.uCount = defaultCycleCount;
|
||||
flashInfo.dwTimeout = 0;
|
||||
user32.FlashWindowEx(flashInfo.address());
|
||||
};
|
@ -7,6 +7,7 @@
|
||||
int main(int argc, char **argv) {
|
||||
printf("sizeof(void*)=%d\n",sizeof(void*));
|
||||
printf("sizeof(char)=%d\n",sizeof(char));
|
||||
printf("sizeof(short)=%d\n",sizeof(short));
|
||||
printf("sizeof(int)=%d\n",sizeof(int));
|
||||
printf("sizeof(long)=%d\n",sizeof(long));
|
||||
printf("sizeof(unsigned_long)=%d\n",sizeof(unsigned long));
|
||||
|