From d8448f421bc5d965ba0535b24947ef72625b0a17 Mon Sep 17 00:00:00 2001 From: foudfou Date: Fri, 3 Aug 2012 13:53:40 +0200 Subject: [PATCH 01/18] refactor VersionChange handling --- src/modules/FiretrayHandler.jsm | 141 +++++++++++++++++--------------- src/modules/VersionChange.jsm | 33 +++++--- 2 files changed, 97 insertions(+), 77 deletions(-) diff --git a/src/modules/FiretrayHandler.jsm b/src/modules/FiretrayHandler.jsm index 8176467..c64469f 100644 --- a/src/modules/FiretrayHandler.jsm +++ b/src/modules/FiretrayHandler.jsm @@ -105,14 +105,9 @@ firetray.Handler = { Services.obs.addObserver(this, "xpcom-will-shutdown", false); Services.obs.addObserver(this, "profile-change-teardown", false); - let welcome = function(ver) { - firetray.Handler.openTab(FIRETRAY_SPLASH_PAGE+"#v"+ver); - firetray.Handler.tryEraseOldOptions(); - firetray.Handler.correctMailNotificationType(); - }; - VersionChange.setInstallHook(welcome); - VersionChange.setUpgradeHook(welcome); - VersionChange.setReinstallHook(welcome); + VersionChange.addHook(["install", "upgrade", "reinstall"], firetray.VersionChangeHandler.showReleaseNotes); + VersionChange.addHook(["upgrade", "reinstall"], firetray.VersionChangeHandler.tryEraseOldOptions); + VersionChange.addHook(["upgrade", "reinstall"], firetray.VersionChangeHandler.correctMailNotificationType); VersionChange.watch(); this.preventWarnOnClose(); @@ -292,10 +287,78 @@ firetray.Handler = { } catch (x) { F.ERROR(x); } }, + quitApplication: function() { + try { + firetray.Utils.timer(function() { + let appStartup = Cc['@mozilla.org/toolkit/app-startup;1'] + .getService(Ci.nsIAppStartup); + appStartup.quit(Ci.nsIAppStartup.eAttemptQuit); + }, FIRETRAY_DELAY_NOWAIT_MILLISECONDS, Ci.nsITimer.TYPE_ONE_SHOT); + } catch (x) { F.ERROR(x); } + }, + + preventWarnOnClose: function() { + if (!this.inBrowserApp) return; + let generalTabsPrefs = Services.prefs.getBranch("browser.tabs."); + this.warnOnCloseTmp = generalTabsPrefs.getBoolPref('warnOnClose'); + F.LOG("warnOnClose saved. was: "+this.warnOnCloseTmp); + generalTabsPrefs.setBoolPref('warnOnClose', false); + }, + restoreWarnOnClose: function() { + if (!this.inBrowserApp && !this.warnOnCloseTmp) return; + let generalTabsPrefs = Services.prefs.getBranch("browser.tabs."); + generalTabsPrefs.setBoolPref('warnOnClose', this.warnOnCloseTmp); + F.LOG("warnOnClose restored to: "+this.warnOnCloseTmp); + } + +}; // firetray.Handler + + +firetray.PrefListener = new PrefListener( + "extensions.firetray.", + function(branch, name) { + F.LOG('Pref changed: '+name); + switch (name) { + case 'hides_single_window': + firetray.Handler.showHidePopupMenuItems(); + break; + case 'show_icon_on_hide': + firetray.Handler.showHideIcon(); + break; + case 'new_mail_icon_names': + firetray.StatusIcon.loadThemedIcons(); + case 'message_count_type': + case 'folder_count_recursive': + firetray.Messaging.updateMsgCountWithCb(); + break; + case 'app_mail_icon_names': + case 'app_browser_icon_names': + case 'app_default_icon_names': + firetray.StatusIcon.loadThemedIcons(); + case 'app_icon_type': + if (firetray.Handler.inMailApp) + firetray.Messaging.updateMsgCountWithCb(); + else + firetray.Handler.setIconImageDefault(); + break; + default: + } + }); + + +firetray.VersionChangeHandler = { + + showReleaseNotes: function(ver) { + firetray.Handler.openTab(FIRETRAY_SPLASH_PAGE+"#v"+ver); + firetray.Handler.tryEraseOldOptions(); + firetray.Handler.correctMailNotificationType(); + }, + openTab: function(url) { - if (this.appId === F.THUNDERBIRD_ID) + if (firetray.Handler.appId === F.THUNDERBIRD_ID) this.openMailTab(url); - else if (this.appId === F.FIREFOX_ID || this.appId === F.SEAMONKEY_ID) + else if (firetray.Handler.appId === F.FIREFOX_ID || + firetray.Handler.appId === F.SEAMONKEY_ID) this.openBrowserTab(url); else F.ERROR("unsupported application"); @@ -359,62 +422,6 @@ firetray.Handler = { FIRETRAY_MESSAGE_COUNT_TYPE_NEW) firetray.Utils.prefService.setIntPref('mail_notification_type', FIRETRAY_NOTIFICATION_NEWMAIL_ICON); - }, - - quitApplication: function() { - try { - firetray.Utils.timer(function() { - let appStartup = Cc['@mozilla.org/toolkit/app-startup;1'] - .getService(Ci.nsIAppStartup); - appStartup.quit(Ci.nsIAppStartup.eAttemptQuit); - }, FIRETRAY_DELAY_NOWAIT_MILLISECONDS, Ci.nsITimer.TYPE_ONE_SHOT); - } catch (x) { F.ERROR(x); } - }, - - preventWarnOnClose: function() { - if (!this.inBrowserApp) return; - let generalTabsPrefs = Services.prefs.getBranch("browser.tabs."); - this.warnOnCloseTmp = generalTabsPrefs.getBoolPref('warnOnClose'); - F.LOG("warnOnClose saved. was: "+this.warnOnCloseTmp); - generalTabsPrefs.setBoolPref('warnOnClose', false); - }, - restoreWarnOnClose: function() { - if (!this.inBrowserApp && !this.warnOnCloseTmp) return; - let generalTabsPrefs = Services.prefs.getBranch("browser.tabs."); - generalTabsPrefs.setBoolPref('warnOnClose', this.warnOnCloseTmp); - F.LOG("warnOnClose restored to: "+this.warnOnCloseTmp); } -}; // firetray.Handler - - -firetray.PrefListener = new PrefListener( - "extensions.firetray.", - function(branch, name) { - F.LOG('Pref changed: '+name); - switch (name) { - case 'hides_single_window': - firetray.Handler.showHidePopupMenuItems(); - break; - case 'show_icon_on_hide': - firetray.Handler.showHideIcon(); - break; - case 'new_mail_icon_names': - firetray.StatusIcon.loadThemedIcons(); - case 'message_count_type': - case 'folder_count_recursive': - firetray.Messaging.updateMsgCountWithCb(); - break; - case 'app_mail_icon_names': - case 'app_browser_icon_names': - case 'app_default_icon_names': - firetray.StatusIcon.loadThemedIcons(); - case 'app_icon_type': - if (firetray.Handler.inMailApp) - firetray.Messaging.updateMsgCountWithCb(); - else - firetray.Handler.setIconImageDefault(); - break; - default: - } - }); +}; diff --git a/src/modules/VersionChange.jsm b/src/modules/VersionChange.jsm index dcf579b..8fa7730 100644 --- a/src/modules/VersionChange.jsm +++ b/src/modules/VersionChange.jsm @@ -10,7 +10,6 @@ Cu.import("resource://firetray/commons.js"); /** * handles version changes. - * use setInstallHook(), setUpgradeHook(), setReinstallHook() * http://mike.kaply.com/2011/02/02/running-add-on-code-at-first-run-and-upgrade/ */ var VersionChange = { @@ -50,7 +49,7 @@ var VersionChange = { if (firstrun) { F.LOG("FIRST RUN"); this.initPrefs(); - this.installHook(this.curVersion); + this._applyHooks("install"); } else { try { @@ -59,13 +58,13 @@ var VersionChange = { if (versionDelta > 0) { firetray.Utils.prefService.setCharPref("installedVersion", this.curVersion); F.LOG("UPGRADE"); - this.upgradeHook(this.curVersion); + this._applyHooks("upgrade"); } } catch (ex) { F.LOG("REINSTALL"); this.initPrefs(); - this.reinstallHook(this.curVersion); + this._applyHooks("reinstall"); } } }, @@ -75,11 +74,25 @@ var VersionChange = { firetray.Utils.prefService.setCharPref("installedVersion", VersionChange.curVersion); }, - installHook: function(ver){}, - upgradeHook: function(ver){}, - reinstallHook: function(ver){}, - setInstallHook: function(fun) {this.installHook = fun;}, - setUpgradeHook: function(fun) {this.upgradeHook = fun;}, - setReinstallHook: function(fun) {this.reinstallHook = fun;} + _hooks: [], // collection of callbacks {id: 1, categories: [], fun: function} + + addHook: function(categories, fun) { + if (!firetray.js.isArray(categories)) throw new CategoryError(); + let id = this._hooks.push({})-1; + this._hooks[id] = {id: id, categories: categories, fun: fun}; + return id; + }, + + removeHook: function(id) {return this._hooks[id].splice(id-1, 1);}, + removeCategoryFromHook: function(category, id) { + throw Components.results.NS_ERROR_NOT_IMPLEMENTED; + }, + + _applyHooks: function(category) { + for (let i=0,len=this._hooks.length; i Date: Fri, 3 Aug 2012 15:53:36 +0200 Subject: [PATCH 02/18] add 'im' to mail server types and have VersionChange hooks applied synchronously This forces us to hard code the addon version :( --- src/defaults/preferences/prefs.js | 2 +- src/install.rdf | 2 +- src/modules/FiretrayHandler.jsm | 47 ++++++++++++++--------- src/modules/FiretrayMessaging.jsm | 4 +- src/modules/VersionChange.jsm | 64 ++++++++++++++++++++----------- src/modules/commons.js | 20 +++++----- 6 files changed, 85 insertions(+), 54 deletions(-) diff --git a/src/defaults/preferences/prefs.js b/src/defaults/preferences/prefs.js index e02085b..89e27b5 100644 --- a/src/defaults/preferences/prefs.js +++ b/src/defaults/preferences/prefs.js @@ -31,4 +31,4 @@ pref("extensions.firetray.folder_count_recursive", true); // Ci.nsMsgFolderFlags.Archive|Drafts|Junk|Queue|SentMail|Trash|Virtual pref("extensions.firetray.excluded_folders_flags", 1077956384); // exposed in 1 tree, hence 2 branches: serverTypes, excludedAccounts -pref("extensions.firetray.mail_accounts", '{ "serverTypes": {"pop3":{"order":1,"excluded":false}, "imap":{"order":1,"excluded":false}, "movemail":{"order":2,"excluded":true}, "none":{"order":3,"excluded":false}, "rss":{"order":4,"excluded":true}, "nntp":{"order":5,"excluded":true}}, "excludedAccounts": [] }'); // JSON +pref("extensions.firetray.mail_accounts", '{ "serverTypes": {"pop3":{"order":1,"excluded":false}, "imap":{"order":1,"excluded":false}, "movemail":{"order":2,"excluded":true}, "none":{"order":3,"excluded":false}, "rss":{"order":4,"excluded":true}, "nntp":{"order":5,"excluded":true}, "im":{"order":6,"excluded":true}}, "excludedAccounts": [] }'); // JSON diff --git a/src/install.rdf b/src/install.rdf index e6aa128..b8f9633 100644 --- a/src/install.rdf +++ b/src/install.rdf @@ -5,7 +5,7 @@ true 2 FireTray - 0.4.2 + 0.4.2 Hua Luo, Francesco Solero, Foudil BRÉTEL Hua Luo, Francesco Solero (Firetray original authors) https://github.com/foudfou/firetray diff --git a/src/modules/FiretrayHandler.jsm b/src/modules/FiretrayHandler.jsm index c64469f..806318e 100644 --- a/src/modules/FiretrayHandler.jsm +++ b/src/modules/FiretrayHandler.jsm @@ -27,10 +27,7 @@ if ("undefined" == typeof(firetray)) { // other global functions // (https://developer.mozilla.org/en/XUL_School/JavaScript_Object_Management) firetray.Handler = { - FILENAME_DEFAULT: null, - FILENAME_SUFFIX: "32.png", FILENAME_BLANK: null, - FILENAME_NEWMAIL: null, initialized: false, inMailApp: false, @@ -77,12 +74,15 @@ firetray.Handler = { this.inBrowserApp = true; F.LOG('inMailApp: '+this.inMailApp+', inBrowserApp: '+this.inBrowserApp); - this.FILENAME_DEFAULT = firetray.Utils.chromeToPath( - "chrome://firetray/skin/" + this.appName.toLowerCase() + this.FILENAME_SUFFIX); this.FILENAME_BLANK = firetray.Utils.chromeToPath( "chrome://firetray/skin/blank-icon.png"); - this.FILENAME_NEWMAIL = firetray.Utils.chromeToPath( - "chrome://firetray/skin/message-mail-new.png"); + + VersionChange.init(FIRETRAY_ID, FIRETRAY_VERSION, FIRETRAY_PREF_BRANCH); + VersionChange.addHook(["install", "upgrade", "reinstall"], firetray.VersionChangeHandler.showReleaseNotes); + VersionChange.addHook(["upgrade", "reinstall"], firetray.VersionChangeHandler.tryEraseOldOptions); + VersionChange.addHook(["upgrade", "reinstall"], firetray.VersionChangeHandler.correctMailNotificationType); + VersionChange.addHook(["upgrade", "reinstall"], firetray.VersionChangeHandler.addIMServerTypePrefMaybe); + VersionChange.applyHooksAndWatchUninstall(); firetray.StatusIcon.init(); firetray.Handler.showHideIcon(); @@ -105,11 +105,6 @@ firetray.Handler = { Services.obs.addObserver(this, "xpcom-will-shutdown", false); Services.obs.addObserver(this, "profile-change-teardown", false); - VersionChange.addHook(["install", "upgrade", "reinstall"], firetray.VersionChangeHandler.showReleaseNotes); - VersionChange.addHook(["upgrade", "reinstall"], firetray.VersionChangeHandler.tryEraseOldOptions); - VersionChange.addHook(["upgrade", "reinstall"], firetray.VersionChangeHandler.correctMailNotificationType); - VersionChange.watch(); - this.preventWarnOnClose(); this.initialized = true; @@ -348,10 +343,10 @@ firetray.PrefListener = new PrefListener( firetray.VersionChangeHandler = { - showReleaseNotes: function(ver) { - firetray.Handler.openTab(FIRETRAY_SPLASH_PAGE+"#v"+ver); - firetray.Handler.tryEraseOldOptions(); - firetray.Handler.correctMailNotificationType(); + showReleaseNotes: function() { + firetray.VersionChangeHandler.openTab(FIRETRAY_SPLASH_PAGE+"#v"+FIRETRAY_VERSION); + firetray.VersionChangeHandler.tryEraseOldOptions(); + firetray.VersionChangeHandler.correctMailNotificationType(); }, openTab: function(url) { @@ -412,16 +407,32 @@ firetray.VersionChangeHandler = { for (let i = 0, length = oldOptions.length; i= 0) ) + if (serverTypes[accountServer.type].excluded || + (excludedAccounts.indexOf(accountServer.key) >= 0)) continue; let rootFolder = accountServer.rootFolder; // nsIMsgFolder diff --git a/src/modules/VersionChange.jsm b/src/modules/VersionChange.jsm index 8fa7730..04fd1b7 100644 --- a/src/modules/VersionChange.jsm +++ b/src/modules/VersionChange.jsm @@ -5,7 +5,8 @@ const Ci = Components.interfaces; const Cu = Components.utils; Cu.import("resource://gre/modules/AddonManager.jsm"); -Cu.import("resource://firetray/commons.js"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://firetray/logging.jsm"); /** @@ -14,14 +15,27 @@ Cu.import("resource://firetray/commons.js"); */ var VersionChange = { - curVersion: null, + initialized: false, + addonId: null, + addonVersion: null, + addOnPrefs: null, + + init: function(id, version, prefBranch) { + F.LOG("VersionChange got: id="+id+" ver="+version+" prefBranch="+prefBranch); + this.addOnId = id; + this.addonVersion = version; + this.addOnPrefs = Services.prefs.getBranch(prefBranch); + + this.initialized = true; + }, versionComparator: Cc["@mozilla.org/xpcom/version-comparator;1"] .getService(Ci.nsIVersionComparator), - watch: function() { + applyHooksAndWatchUninstall: function() { + if (!this.initialized) throw "VersionChange not initialized"; + this.onVersionChange(this.addonVersion); // AddonManager.getAddonByID() async, whereas we need sync call AddonManager.addAddonListener(this.uninstallListener); - AddonManager.getAddonByID(FIRETRAY_ID, this.onVersionChange.bind(this)); F.LOG("version change watching enabled"); }, @@ -29,22 +43,21 @@ var VersionChange = { // detect reinstall later uninstallListener: { onUninstalling: function(addon) { - if (addon.id !== FIRETRAY_ID) return; - firetray.Utils.prefService.clearUserPref("installedVersion"); + if (addon.id !== this.addonId) return; + this.addOnPrefs.clearUserPref("installedVersion"); }, onOperationCancelled: function(addon) { - if (addon.id !== FIRETRAY_ID) return; + if (addon.id !== this.addonId) return; let beingUninstalled = (addon.pendingOperations & AddonManager.PENDING_UNINSTALL) != 0; if (beingUninstalled) - firetray.Utils.prefService.clearUserPref("installedVersion"); + this.addOnPrefs.clearUserPref("installedVersion"); } }, - onVersionChange: function(addon) { - F.LOG("VERSION: "+addon.version); + onVersionChange: function() { + F.LOG("VERSION: "+this.addonVersion); - this.curVersion = addon.version; - var firstrun = firetray.Utils.prefService.getBoolPref("firstrun"); + var firstrun = this.addOnPrefs.getBoolPref("firstrun"); if (firstrun) { F.LOG("FIRST RUN"); @@ -53,10 +66,10 @@ var VersionChange = { } else { try { - var installedVersion = firetray.Utils.prefService.getCharPref("installedVersion"); - var versionDelta = this.versionComparator.compare(this.curVersion, installedVersion); + var installedVersion = this.addOnPrefs.getCharPref("installedVersion"); + var versionDelta = this.versionComparator.compare(this.addonVersion, installedVersion); if (versionDelta > 0) { - firetray.Utils.prefService.setCharPref("installedVersion", this.curVersion); + this.addOnPrefs.setCharPref("installedVersion", this.addonVersion); F.LOG("UPGRADE"); this._applyHooks("upgrade"); } @@ -67,17 +80,18 @@ var VersionChange = { this._applyHooks("reinstall"); } } + }, initPrefs: function() { - firetray.Utils.prefService.setBoolPref("firstrun", false); - firetray.Utils.prefService.setCharPref("installedVersion", VersionChange.curVersion); + this.addOnPrefs.setBoolPref("firstrun", false); + this.addOnPrefs.setCharPref("installedVersion", VersionChange.addonVersion); }, - _hooks: [], // collection of callbacks {id: 1, categories: [], fun: function} + _hooks: [], // collection of callbacks {id: 1, categories: [], fun: function} addHook: function(categories, fun) { - if (!firetray.js.isArray(categories)) throw new CategoryError(); + if (Object.prototype.toString.call(categories) !== "[object Array]") throw new TypeError(); let id = this._hooks.push({})-1; this._hooks[id] = {id: id, categories: categories, fun: fun}; return id; @@ -89,10 +103,14 @@ var VersionChange = { }, _applyHooks: function(category) { - for (let i=0,len=this._hooks.length; i Date: Fri, 3 Aug 2012 23:52:29 +0200 Subject: [PATCH 03/18] ignore 'im' server types for now, we'll be handling them later. --- src/defaults/preferences/prefs.js | 2 +- src/install.rdf | 6 +-- src/modules/FiretrayHandler.jsm | 28 ++++------- src/modules/FiretrayInstantMessaging.jsm | 60 ++++++++++++++++++++++++ src/modules/FiretrayMessaging.jsm | 11 ++++- src/modules/commons.js | 30 ++++++++++-- 6 files changed, 107 insertions(+), 30 deletions(-) create mode 100644 src/modules/FiretrayInstantMessaging.jsm diff --git a/src/defaults/preferences/prefs.js b/src/defaults/preferences/prefs.js index 89e27b5..e02085b 100644 --- a/src/defaults/preferences/prefs.js +++ b/src/defaults/preferences/prefs.js @@ -31,4 +31,4 @@ pref("extensions.firetray.folder_count_recursive", true); // Ci.nsMsgFolderFlags.Archive|Drafts|Junk|Queue|SentMail|Trash|Virtual pref("extensions.firetray.excluded_folders_flags", 1077956384); // exposed in 1 tree, hence 2 branches: serverTypes, excludedAccounts -pref("extensions.firetray.mail_accounts", '{ "serverTypes": {"pop3":{"order":1,"excluded":false}, "imap":{"order":1,"excluded":false}, "movemail":{"order":2,"excluded":true}, "none":{"order":3,"excluded":false}, "rss":{"order":4,"excluded":true}, "nntp":{"order":5,"excluded":true}, "im":{"order":6,"excluded":true}}, "excludedAccounts": [] }'); // JSON +pref("extensions.firetray.mail_accounts", '{ "serverTypes": {"pop3":{"order":1,"excluded":false}, "imap":{"order":1,"excluded":false}, "movemail":{"order":2,"excluded":true}, "none":{"order":3,"excluded":false}, "rss":{"order":4,"excluded":true}, "nntp":{"order":5,"excluded":true}}, "excludedAccounts": [] }'); // JSON diff --git a/src/install.rdf b/src/install.rdf index b8f9633..32cb77d 100644 --- a/src/install.rdf +++ b/src/install.rdf @@ -18,7 +18,7 @@ {ec8030f7-c20a-464f-9b0e-13a3a9e97384} - 7.0 + 13.0 15.0a1 @@ -26,8 +26,8 @@ {3550f703-e582-4d05-9a08-453d09bdfdc6} - 7.0 - 15.0a1 + 15.0 + 17.0a1 diff --git a/src/modules/FiretrayHandler.jsm b/src/modules/FiretrayHandler.jsm index 806318e..d89cec8 100644 --- a/src/modules/FiretrayHandler.jsm +++ b/src/modules/FiretrayHandler.jsm @@ -36,9 +36,11 @@ firetray.Handler = { windows: {}, windowsCount: 0, visibleWindowsCount: 0, + observedTopics: {}, appId: (function(){return Services.appinfo.ID;})(), appName: (function(){return Services.appinfo.name;})(), + appStartupTopic: null, runtimeABI: (function(){return Services.appinfo.XPCOMABI;})(), runtimeOS: (function(){return Services.appinfo.OS;})(), // "WINNT", "Linux", "Darwin" addonRootDir: (function(){ @@ -74,6 +76,8 @@ firetray.Handler = { this.inBrowserApp = true; F.LOG('inMailApp: '+this.inMailApp+', inBrowserApp: '+this.inBrowserApp); + this.appStartupTopic = this.getAppStartupTopic(this.appId); + this.FILENAME_BLANK = firetray.Utils.chromeToPath( "chrome://firetray/skin/blank-icon.png"); @@ -81,7 +85,6 @@ firetray.Handler = { VersionChange.addHook(["install", "upgrade", "reinstall"], firetray.VersionChangeHandler.showReleaseNotes); VersionChange.addHook(["upgrade", "reinstall"], firetray.VersionChangeHandler.tryEraseOldOptions); VersionChange.addHook(["upgrade", "reinstall"], firetray.VersionChangeHandler.correctMailNotificationType); - VersionChange.addHook(["upgrade", "reinstall"], firetray.VersionChangeHandler.addIMServerTypePrefMaybe); VersionChange.applyHooksAndWatchUninstall(); firetray.StatusIcon.init(); @@ -101,9 +104,8 @@ firetray.Handler = { } } - Services.obs.addObserver(this, this.getAppStartupTopic(this.appId), false); - Services.obs.addObserver(this, "xpcom-will-shutdown", false); - Services.obs.addObserver(this, "profile-change-teardown", false); + firetray.Utils.addObservers(firetray.Handler, [ this.appStartupTopic, + "xpcom-will-shutdown", "profile-change-teardown" ]); this.preventWarnOnClose(); @@ -120,9 +122,7 @@ firetray.Handler = { firetray.Window.shutdown(); // watchout order and sufficiency of lib closings (tryCloseLibs()) - Services.obs.removeObserver(this, this.getAppStartupTopic(this.appId), false); - Services.obs.removeObserver(this, "xpcom-will-shutdown", false); - Services.obs.removeObserver(this, "profile-change-teardown", false); + firetray.Utils.removeAllObservers(this); this.appStarted = false; this.initialized = false; @@ -134,6 +134,7 @@ firetray.Handler = { case "sessionstore-windows-restored": case "mail-startup-done": case "final-ui-startup": + firetray.Utils.addObservers(firetray.Handler, [this.appStartupTopic]); F.LOG("RECEIVED: "+topic+", launching timer"); // sessionstore-windows-restored does not come after the realization of // all windows... so we wait a little @@ -420,19 +421,6 @@ firetray.VersionChangeHandler = { FIRETRAY_NOTIFICATION_NEWMAIL_ICON); F.WARN("mail notification type set to newmail icon."); } - }, - - addIMServerTypePrefMaybe: function() { - let mailAccounts = firetray.Utils.getObjPref('mail_accounts'); - let serverTypes = mailAccounts["serverTypes"]; - - if (!serverTypes["im"]) - serverTypes["im"] = {"order":6,"excluded":true}; - - let prefObj = {"serverTypes":serverTypes, "excludedAccounts":mailAccounts["excludedAccounts"]}; - firetray.Utils.setObjPref('mail_accounts', prefObj); - - F.WARN("server type 'im' added to prefs."); } }; diff --git a/src/modules/FiretrayInstantMessaging.jsm b/src/modules/FiretrayInstantMessaging.jsm new file mode 100644 index 0000000..c2edb12 --- /dev/null +++ b/src/modules/FiretrayInstantMessaging.jsm @@ -0,0 +1,60 @@ +/* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +var EXPORTED_SYMBOLS = [ "firetray", "FLDRS_UNINTERESTING" ]; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; + +Cu.import("resource://firetray/commons.js"); + +firetray.InstantMessaging = { + initialized: false, + observedTopics: {}, + + init: function() { + if (this.initialized) { + F.WARN("InstantMessaging already initialized"); + return; + } + F.LOG("Enabling InstantMessaging"); + + firetray.Utils.addObservers(firetray.InstantMessaging, [ // "*" for debugging + "idle-time-changed", "new-directed-incoming-message", "new-text", + "new-ui-conversation", "status-changed", "unread-im-count-changed", + "visited-status-resolution" + ]); + + this.initialized = true; + }, + + shutdown: function() { + if (!this.initialized) return; + F.LOG("Disabling InstantMessaging"); + + Services.obs.removeAllObservers(firetray.InstantMessaging); + + this.initialized = false; + }, + + observe: function(subject, topic, data) { + F.WARN("RECEIVED InstantMessaging:"); + switch (topic) { + case "unread-im-count-changed": + F.WARN("received unread-im-count-changed: "+subject+" "+data); + break; + case "new-directed-incoming-message": // when PM or cited in channel: new-directed-incoming-message: [xpconnect wrapped (nsISupports, nsIClassInfo, prplIMessage)] null + F.WARN("new-directed-incoming-message: "+subject+" "+data); + break; + case "visited-status-resolution": + F.WARN("visited-status-resolution: "+subject+" "+data); + break; + case "status-changed": + case "idle-time-changed": + break; + default: + F.WARN("unhandled topic: "+topic); + } + } + +}; diff --git a/src/modules/FiretrayMessaging.jsm b/src/modules/FiretrayMessaging.jsm index 66dcf0e..dfd7acf 100644 --- a/src/modules/FiretrayMessaging.jsm +++ b/src/modules/FiretrayMessaging.jsm @@ -9,6 +9,7 @@ const Cu = Components.utils; Cu.import("resource:///modules/mailServices.js"); Cu.import("resource://gre/modules/PluralForm.jsm"); Cu.import("resource://firetray/commons.js"); +Cu.import("resource://firetray/FiretrayInstantMessaging.jsm"); const FLDRS_UNINTERESTING = { Archive: Ci.nsMsgFolderFlags.Archive, @@ -43,6 +44,9 @@ firetray.Messaging = { MailServices.mailSession.AddFolderListener(that.mailSessionListener, that.mailSessionListener.notificationFlags); + if (Services.prefs.getBoolPref("mail.chat.enabled")) + firetray.InstantMessaging.init(); + this.initialized = true; }, @@ -50,11 +54,11 @@ firetray.Messaging = { if (!this.initialized) return; F.LOG("Disabling Messaging"); - this.cleaningTimer.cancel(); - MailServices.mailSession.RemoveFolderListener(this.mailSessionListener); firetray.Handler.setIconImageDefault(); + this.cleaningTimer.cancel(); + this.initialized = false; }, @@ -89,6 +93,8 @@ firetray.Messaging = { } }, + // https://bugzilla.mozilla.org/show_bug.cgi?id=715799 for TB15+ + // mozINewMailNotificationService (alternative message counting) /* http://mxr.mozilla.org/comm-central/source/mailnews/base/public/nsIFolderListener.idl */ mailSessionListener: { notificationFlags: @@ -233,6 +239,7 @@ firetray.Messaging = { try { let accounts = new this.Accounts(); for (let accountServer in accounts) { + if (accountServer.type === 'im') continue; // IM messages are counted elsewhere F.LOG("is servertype excluded: "+serverTypes[accountServer.type].excluded+", account exclusion index: "+excludedAccounts.indexOf(accountServer.key)); if (serverTypes[accountServer.type].excluded || (excludedAccounts.indexOf(accountServer.key) >= 0)) diff --git a/src/modules/commons.js b/src/modules/commons.js index ac64ed6..6e32c04 100644 --- a/src/modules/commons.js +++ b/src/modules/commons.js @@ -1,10 +1,11 @@ /* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* for now, logging facilities (imported from logging.jsm) are automatically - provided by this module */ +/* for now, logging facilities (imported from logging.jsm) and Services are + automatically provided by this module */ var EXPORTED_SYMBOLS = - [ "firetray", "F", "FIRETRAY_ID", "FIRETRAY_VERSION", "FIRETRAY_PREF_BRANCH", - "FIRETRAY_SPLASH_PAGE", "FIRETRAY_APPLICATION_ICON_TYPE_THEMED", + [ "firetray", "F", "Services", "FIRETRAY_ID", "FIRETRAY_VERSION", + "FIRETRAY_PREF_BRANCH", "FIRETRAY_SPLASH_PAGE", + "FIRETRAY_APPLICATION_ICON_TYPE_THEMED", "FIRETRAY_APPLICATION_ICON_TYPE_CUSTOM", "FIRETRAY_NOTIFICATION_UNREAD_MESSAGE_COUNT", "FIRETRAY_NOTIFICATION_NEWMAIL_ICON", "FIRETRAY_NOTIFICATION_CUSTOM_ICON", @@ -62,6 +63,27 @@ firetray.Utils = { prefService: Services.prefs.getBranch(FIRETRAY_PREF_BRANCH), strings: Services.strings.createBundle("chrome://firetray/locale/overlay.properties"), + addObservers: function(handler, topics){ + topics.forEach(function(topic){ + Services.obs.addObserver(this, topic, false); + this.observedTopics[topic] = true; + F.LOG("registred "+topic+" for "+handler); + }, handler); + }, + + removeObservers: function(handler, topics) { + topics.forEach(function(topic){ + Services.obs.removeObserver(this, topic); + delete this.observedTopics[topic]; + }, handler); + }, + + removeAllObservers: function(handler) { + for (let topic in handler.observedTopics) + Services.obs.removeObserver(handler, topic); + handler.observedTopics = {}; + }, + getObjPref: function(prefStr) { try { var objPref = JSON.parse( From b3869630c23ee2984fa52553f2a6c6375537a94e Mon Sep 17 00:00:00 2001 From: foudfou Date: Sat, 4 Aug 2012 14:02:42 +0200 Subject: [PATCH 04/18] * observe "account-added", "account-removed", at last ! (see 75636723 and 8d0917ab) * auto-start InstantMessaging when needed --- src/modules/FiretrayInstantMessaging.jsm | 8 ++--- src/modules/FiretrayMessaging.jsm | 41 ++++++++++++++++++++---- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/modules/FiretrayInstantMessaging.jsm b/src/modules/FiretrayInstantMessaging.jsm index c2edb12..a4d78ad 100644 --- a/src/modules/FiretrayInstantMessaging.jsm +++ b/src/modules/FiretrayInstantMessaging.jsm @@ -19,7 +19,8 @@ firetray.InstantMessaging = { } F.LOG("Enabling InstantMessaging"); - firetray.Utils.addObservers(firetray.InstantMessaging, [ // "*" for debugging + firetray.Utils.addObservers(firetray.InstantMessaging, [ + // "*" // debugging "idle-time-changed", "new-directed-incoming-message", "new-text", "new-ui-conversation", "status-changed", "unread-im-count-changed", "visited-status-resolution" @@ -38,16 +39,13 @@ firetray.InstantMessaging = { }, observe: function(subject, topic, data) { - F.WARN("RECEIVED InstantMessaging:"); + F.LOG("RECEIVED InstantMessaging: "+topic+" subject="+subject+" data="+data); switch (topic) { case "unread-im-count-changed": - F.WARN("received unread-im-count-changed: "+subject+" "+data); break; case "new-directed-incoming-message": // when PM or cited in channel: new-directed-incoming-message: [xpconnect wrapped (nsISupports, nsIClassInfo, prplIMessage)] null - F.WARN("new-directed-incoming-message: "+subject+" "+data); break; case "visited-status-resolution": - F.WARN("visited-status-resolution: "+subject+" "+data); break; case "status-changed": case "idle-time-changed": diff --git a/src/modules/FiretrayMessaging.jsm b/src/modules/FiretrayMessaging.jsm index dfd7acf..b908253 100644 --- a/src/modules/FiretrayMessaging.jsm +++ b/src/modules/FiretrayMessaging.jsm @@ -27,6 +27,7 @@ firetray.Messaging = { initialized: false, cleaningTimer: null, currentMsgCount: null, + observedTopics: {}, init: function() { if (this.initialized) { @@ -35,16 +36,14 @@ firetray.Messaging = { } F.LOG("Enabling Messaging"); - // there is no means to detect account-removed event - this.cleaningTimer = firetray.Utils.timer(firetray.Messaging.cleanExcludedAccounts, - FIRETRAY_DELAY_PREF_CLEANING_MILLISECONDS, Ci.nsITimer.TYPE_REPEATING_SLACK); - F.LOG(this.cleaningTimer+"="+FIRETRAY_DELAY_PREF_CLEANING_MILLISECONDS); + firetray.Utils.addObservers(firetray.Messaging, [ "account-added", + "account-removed"]); let that = this; MailServices.mailSession.AddFolderListener(that.mailSessionListener, that.mailSessionListener.notificationFlags); - if (Services.prefs.getBoolPref("mail.chat.enabled")) + if (Services.prefs.getBoolPref("mail.chat.enabled") && this.existsIMAccount()) firetray.InstantMessaging.init(); this.initialized = true; @@ -54,14 +53,44 @@ firetray.Messaging = { if (!this.initialized) return; F.LOG("Disabling Messaging"); + firetray.InstantMessaging.shutdown(); + MailServices.mailSession.RemoveFolderListener(this.mailSessionListener); firetray.Handler.setIconImageDefault(); - this.cleaningTimer.cancel(); + Services.obs.removeAllObservers(firetray.Messaging); this.initialized = false; }, + existsIMAccount: function() { + let accounts = new this.Accounts(); + for (let accountServer in accounts) + if (accountServer.type === 'im') { + F.LOG("found im server: "+accountServer.prettyName); + return true; + } + + return false; + }, + + observe: function(subject, topic, data) { + F.LOG("RECEIVED Messaging: "+topic+" subject="+subject+" data="+data); + switch (topic) { + case "account-removed": + this.cleanExcludedAccounts(); + if (subject.QueryInterface(Ci.imIAccount) && !this.existsIMAccount()) + firetray.InstantMessaging.shutdown(); + break; + case "account-added": + if (subject.QueryInterface(Ci.imIAccount) && !firetray.InstantMessaging.initialized) + firetray.InstantMessaging.init(); + break; + default: + F.WARN("unhandled topic: "+topic); + } + }, + /* removes removed accounts from excludedAccounts pref. NOTE: Can't be called at shutdown because MailServices.accounts no longer available */ cleanExcludedAccounts: function() { From a9cc29925966539fbb9f54d29bcbd767a885f711 Mon Sep 17 00:00:00 2001 From: foudfou Date: Sat, 4 Aug 2012 14:58:58 +0200 Subject: [PATCH 05/18] extract from StatusIcon to GtkIcons code to share with IMStatusIcon --- src/modules/FiretrayHandler.jsm | 4 --- src/modules/linux/FiretrayGtkIcons.jsm | 45 ++++++++++++++++++++++++ src/modules/linux/FiretrayStatusIcon.jsm | 28 ++++++--------- 3 files changed, 56 insertions(+), 21 deletions(-) create mode 100644 src/modules/linux/FiretrayGtkIcons.jsm diff --git a/src/modules/FiretrayHandler.jsm b/src/modules/FiretrayHandler.jsm index d89cec8..63bfcfc 100644 --- a/src/modules/FiretrayHandler.jsm +++ b/src/modules/FiretrayHandler.jsm @@ -27,7 +27,6 @@ if ("undefined" == typeof(firetray)) { // other global functions // (https://developer.mozilla.org/en/XUL_School/JavaScript_Object_Management) firetray.Handler = { - FILENAME_BLANK: null, initialized: false, inMailApp: false, @@ -78,9 +77,6 @@ firetray.Handler = { this.appStartupTopic = this.getAppStartupTopic(this.appId); - this.FILENAME_BLANK = firetray.Utils.chromeToPath( - "chrome://firetray/skin/blank-icon.png"); - VersionChange.init(FIRETRAY_ID, FIRETRAY_VERSION, FIRETRAY_PREF_BRANCH); VersionChange.addHook(["install", "upgrade", "reinstall"], firetray.VersionChangeHandler.showReleaseNotes); VersionChange.addHook(["upgrade", "reinstall"], firetray.VersionChangeHandler.tryEraseOldOptions); diff --git a/src/modules/linux/FiretrayGtkIcons.jsm b/src/modules/linux/FiretrayGtkIcons.jsm new file mode 100644 index 0000000..5979f2a --- /dev/null +++ b/src/modules/linux/FiretrayGtkIcons.jsm @@ -0,0 +1,45 @@ +/* -*- 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://firetray/ctypes/linux/gtk.jsm"); +Cu.import("resource://firetray/commons.js"); + +if ("undefined" == typeof(firetray.StatusIcon)) + F.ERROR("This module MUST be imported from/after StatusIcon !"); + + +firetray.GtkIcons = { + initialized: false, + + GTK_THEME_ICON_PATH: null, + + init: function() { + try { + this.loadDefaultTheme(); + this.initialized = true; + return true; + } catch (x) { + F.ERROR(x); + return false; + } + }, + + shutdown: function() { + firetray.Utils.tryCloseLibs([gtk]); + this.initialized = false; + }, + + loadDefaultTheme: function() { + this.GTK_THEME_ICON_PATH = firetray.Utils.chromeToPath("chrome://firetray/skin/linux/icons"); + F.LOG(this.GTK_THEME_ICON_PATH); + let gtkIconTheme = gtk.gtk_icon_theme_get_default(); + F.LOG("gtkIconTheme="+gtkIconTheme); + gtk.gtk_icon_theme_append_search_path(gtkIconTheme, this.GTK_THEME_ICON_PATH); + } + +}; diff --git a/src/modules/linux/FiretrayStatusIcon.jsm b/src/modules/linux/FiretrayStatusIcon.jsm index 84b0710..24727e6 100644 --- a/src/modules/linux/FiretrayStatusIcon.jsm +++ b/src/modules/linux/FiretrayStatusIcon.jsm @@ -23,7 +23,7 @@ if ("undefined" == typeof(firetray.Handler)) firetray.StatusIcon = { - GTK_THEME_ICON_PATH: null, + FILENAME_BLANK: null, initialized: false, callbacks: {}, // pointers to JS functions. MUST LIVE DURING ALL THE EXECUTION @@ -36,26 +36,18 @@ firetray.StatusIcon = { defaultNewMailIconName: null, init: function() { + this.FILENAME_BLANK = firetray.Utils.chromeToPath( + "chrome://firetray/skin/blank-icon.png"); + this.defineIconNames(); - try { - this.GTK_THEME_ICON_PATH = firetray.Utils.chromeToPath("chrome://firetray/skin/linux/icons"); - F.LOG(this.GTK_THEME_ICON_PATH); - let gtkIconTheme = gtk.gtk_icon_theme_get_default(); - F.LOG("gtkIconTheme="+gtkIconTheme); - gtk.gtk_icon_theme_append_search_path(gtkIconTheme, this.GTK_THEME_ICON_PATH); + Cu.import("resource://firetray/linux/FiretrayGtkIcons.jsm"); + firetray.GtkIcons.init(); - this.loadThemedIcons(); - - this.trayIcon = gtk.gtk_status_icon_new(); - - } catch (x) { - F.ERROR(x); - return false; - } + this.loadThemedIcons(); + this.trayIcon = gtk.gtk_status_icon_new(); firetray.Handler.setIconImageDefault(); - firetray.Handler.setIconTooltipDefault(); Cu.import("resource://firetray/linux/FiretrayPopupMenu.jsm"); @@ -70,6 +62,7 @@ firetray.StatusIcon = { shutdown: function() { firetray.PopupMenu.shutdown(); + firetray.GtkIcons.shutdown(); firetray.Utils.tryCloseLibs([cairo, gobject, gdk, gio, gtk, pango, pangocairo]); this.initialized = false; }, @@ -243,7 +236,8 @@ firetray.Handler.setIconText = function(text, color) { // FIXME: function too lo try { // build background from image - let specialIcon = gdk.gdk_pixbuf_new_from_file(this.FILENAME_BLANK, null); // GError **error); + let specialIcon = gdk.gdk_pixbuf_new_from_file( + firetray.StatusIcon.FILENAME_BLANK, null); // GError **error); let dest = gdk.gdk_pixbuf_copy(specialIcon); let w = gdk.gdk_pixbuf_get_width(specialIcon); let h = gdk.gdk_pixbuf_get_height(specialIcon); From 6f95421a2f9205de99c86e31d85ea8a150245c46 Mon Sep 17 00:00:00 2001 From: foudfou Date: Sat, 4 Aug 2012 15:22:10 +0200 Subject: [PATCH 06/18] fix shutdown so ctypes libs are close cleanly + cleaning --- src/modules/FiretrayHandler.jsm | 1 + src/modules/FiretrayInstantMessaging.jsm | 2 +- src/modules/FiretrayMessaging.jsm | 3 ++- src/modules/linux/FiretrayGtkIcons.jsm | 2 ++ src/modules/linux/FiretrayPopupMenu.jsm | 1 + src/modules/linux/FiretrayStatusIcon.jsm | 7 +++---- 6 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/modules/FiretrayHandler.jsm b/src/modules/FiretrayHandler.jsm index 63bfcfc..5e83931 100644 --- a/src/modules/FiretrayHandler.jsm +++ b/src/modules/FiretrayHandler.jsm @@ -110,6 +110,7 @@ firetray.Handler = { }, shutdown: function() { + F.LOG("Disabling Handler"); firetray.PrefListener.unregister(); if (this.inMailApp) diff --git a/src/modules/FiretrayInstantMessaging.jsm b/src/modules/FiretrayInstantMessaging.jsm index a4d78ad..c485850 100644 --- a/src/modules/FiretrayInstantMessaging.jsm +++ b/src/modules/FiretrayInstantMessaging.jsm @@ -33,7 +33,7 @@ firetray.InstantMessaging = { if (!this.initialized) return; F.LOG("Disabling InstantMessaging"); - Services.obs.removeAllObservers(firetray.InstantMessaging); + firetray.Utils.removeAllObservers(firetray.InstantMessaging); this.initialized = false; }, diff --git a/src/modules/FiretrayMessaging.jsm b/src/modules/FiretrayMessaging.jsm index b908253..6ffda93 100644 --- a/src/modules/FiretrayMessaging.jsm +++ b/src/modules/FiretrayMessaging.jsm @@ -54,11 +54,12 @@ firetray.Messaging = { F.LOG("Disabling Messaging"); firetray.InstantMessaging.shutdown(); + F.LOG("HI THERE"); MailServices.mailSession.RemoveFolderListener(this.mailSessionListener); firetray.Handler.setIconImageDefault(); - Services.obs.removeAllObservers(firetray.Messaging); + firetray.Utils.removeAllObservers(firetray.Messaging); this.initialized = false; }, diff --git a/src/modules/linux/FiretrayGtkIcons.jsm b/src/modules/linux/FiretrayGtkIcons.jsm index 5979f2a..e7ab9ee 100644 --- a/src/modules/linux/FiretrayGtkIcons.jsm +++ b/src/modules/linux/FiretrayGtkIcons.jsm @@ -20,6 +20,8 @@ firetray.GtkIcons = { init: function() { try { + if (this.initialized) return true; + this.loadDefaultTheme(); this.initialized = true; return true; diff --git a/src/modules/linux/FiretrayPopupMenu.jsm b/src/modules/linux/FiretrayPopupMenu.jsm index 4e23c9b..f2a483a 100644 --- a/src/modules/linux/FiretrayPopupMenu.jsm +++ b/src/modules/linux/FiretrayPopupMenu.jsm @@ -60,6 +60,7 @@ firetray.PopupMenu = { }, shutdown: function() { + F.LOG("Disabling PopupMenu"); firetray.Utils.tryCloseLibs([gobject, gtk]); this.initialized = false; }, diff --git a/src/modules/linux/FiretrayStatusIcon.jsm b/src/modules/linux/FiretrayStatusIcon.jsm index 24727e6..4a7d9db 100644 --- a/src/modules/linux/FiretrayStatusIcon.jsm +++ b/src/modules/linux/FiretrayStatusIcon.jsm @@ -39,14 +39,12 @@ firetray.StatusIcon = { this.FILENAME_BLANK = firetray.Utils.chromeToPath( "chrome://firetray/skin/blank-icon.png"); - this.defineIconNames(); - Cu.import("resource://firetray/linux/FiretrayGtkIcons.jsm"); firetray.GtkIcons.init(); - + this.defineIconNames(); this.loadThemedIcons(); - this.trayIcon = gtk.gtk_status_icon_new(); + this.trayIcon = gtk.gtk_status_icon_new(); firetray.Handler.setIconImageDefault(); firetray.Handler.setIconTooltipDefault(); @@ -61,6 +59,7 @@ firetray.StatusIcon = { }, shutdown: function() { + F.LOG("Disabling StatusIcon"); firetray.PopupMenu.shutdown(); firetray.GtkIcons.shutdown(); firetray.Utils.tryCloseLibs([cairo, gobject, gdk, gio, gtk, pango, pangocairo]); From ceba669bcd14b402693e91a53f8b21c40708a912 Mon Sep 17 00:00:00 2001 From: foudfou Date: Sat, 4 Aug 2012 16:29:44 +0200 Subject: [PATCH 07/18] display IM icon when IM enabled --- README.md | 2 +- .../gnome/22x22/status/user-available.png | 1 + .../icons/gnome/22x22/status/user-away.png | 1 + .../icons/gnome/22x22/status/user-busy.png | 1 + .../icons/gnome/22x22/status/user-offline.png | 1 + src/chrome/skin/pidgin-tray-available.png | Bin 0 -> 1050 bytes src/chrome/skin/pidgin-tray-away.png | Bin 0 -> 1066 bytes src/chrome/skin/pidgin-tray-busy.png | Bin 0 -> 1052 bytes src/chrome/skin/pidgin-tray-offline.png | Bin 0 -> 1115 bytes src/modules/FiretrayInstantMessaging.jsm | 5 ++ src/modules/FiretrayMessaging.jsm | 2 - src/modules/ctypes/linux/gio.jsm | 1 + src/modules/linux/FiretrayIMStatusIcon.jsm | 65 ++++++++++++++++++ src/modules/linux/FiretrayStatusIcon.jsm | 1 + 14 files changed, 77 insertions(+), 3 deletions(-) create mode 120000 src/chrome/skin/linux/icons/gnome/22x22/status/user-available.png create mode 120000 src/chrome/skin/linux/icons/gnome/22x22/status/user-away.png create mode 120000 src/chrome/skin/linux/icons/gnome/22x22/status/user-busy.png create mode 120000 src/chrome/skin/linux/icons/gnome/22x22/status/user-offline.png create mode 100644 src/chrome/skin/pidgin-tray-available.png create mode 100644 src/chrome/skin/pidgin-tray-away.png create mode 100644 src/chrome/skin/pidgin-tray-busy.png create mode 100644 src/chrome/skin/pidgin-tray-offline.png create mode 100644 src/modules/linux/FiretrayIMStatusIcon.jsm diff --git a/README.md b/README.md index 2a543cf..400f9b4 100644 --- a/README.md +++ b/README.md @@ -89,4 +89,4 @@ Acknowledgment [Nils Maier](https://addons.mozilla.org/fr/firefox/addon/minimizetotray-revived/ "MinToTrayR addon page"). * kind support from Neil Deaking, Bobby Holley - +* default icons borrowed from Mozilla and Pidgin diff --git a/src/chrome/skin/linux/icons/gnome/22x22/status/user-available.png b/src/chrome/skin/linux/icons/gnome/22x22/status/user-available.png new file mode 120000 index 0000000..3329bf8 --- /dev/null +++ b/src/chrome/skin/linux/icons/gnome/22x22/status/user-available.png @@ -0,0 +1 @@ +../../../../../pidgin-tray-available.png \ No newline at end of file diff --git a/src/chrome/skin/linux/icons/gnome/22x22/status/user-away.png b/src/chrome/skin/linux/icons/gnome/22x22/status/user-away.png new file mode 120000 index 0000000..5580cb1 --- /dev/null +++ b/src/chrome/skin/linux/icons/gnome/22x22/status/user-away.png @@ -0,0 +1 @@ +../../../../../pidgin-tray-away.png \ No newline at end of file diff --git a/src/chrome/skin/linux/icons/gnome/22x22/status/user-busy.png b/src/chrome/skin/linux/icons/gnome/22x22/status/user-busy.png new file mode 120000 index 0000000..84c85ee --- /dev/null +++ b/src/chrome/skin/linux/icons/gnome/22x22/status/user-busy.png @@ -0,0 +1 @@ +../../../../../pidgin-tray-busy.png \ No newline at end of file diff --git a/src/chrome/skin/linux/icons/gnome/22x22/status/user-offline.png b/src/chrome/skin/linux/icons/gnome/22x22/status/user-offline.png new file mode 120000 index 0000000..5df30b0 --- /dev/null +++ b/src/chrome/skin/linux/icons/gnome/22x22/status/user-offline.png @@ -0,0 +1 @@ +../../../../../pidgin-tray-offline.png \ No newline at end of file diff --git a/src/chrome/skin/pidgin-tray-available.png b/src/chrome/skin/pidgin-tray-available.png new file mode 100644 index 0000000000000000000000000000000000000000..ce085bbf43d9f279e4a8aaa7d8e360b02a1783c0 GIT binary patch literal 1050 zcmV+#1m*jQP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iOP{ z4;>oR;BBw~00WvyL_t(I%e|CsXw_95$3N$P{qK73?%g9PX{iNDKHRxTovo0(s8EnE zf*=QC&yguL@Qw6l5WOg(Atm*q2pNH(?}RLyPATvq6(_?IR^+z0&gph{AN~*Loc}q! zXm?z5m<{R+KMv=`@5A@^JrD37NdUaI?|6GMUegmO^RN&Ojw2AlK?s3xrdHwLOzo>x zGshV-hMgboSbg{o`kVWDe-EU#vyoJh-P?0%OKI5x9&Ebs1E-Nmu5iu7LnlwWT2F+6@5fCrme zXj`%crB?6{8P5#9I(mvP&%Q+K(zR@SYzy=1UI8qlg(0pCpJpuC&6aMm$2vJt>2azv z(vi8NuH^dYx$rtWHowE>Ob3hVSK`_PPUO;@T)>mdxAN-KZ}}v`$JJE| z3Ve0$WjeCESdd4>rNHB!km>sM`Tu)^t_2D>rwTiFk3SyE4CaXs@I;xwjR za-|Aj#mW0~Jmj!%TCRg~Cl@G0PjkTMm4=-OVZhL0uM+dw> zJ<{Be;^=34&^lsZ7#klF_XCbC4b>bh0b`rO|3 z`Hkt~;bUj#_8j@)=laJZFE?@RiFCY?P(%7pl`KuJyz=rU6KC>>BgcRnN6hp>wN z>5MB%B;wo0CJL#K4}3EqRk+a@@%_N?85MI}3c)yeZ_jYhsmlH_Uj&R;Mz06s2;m`+@F=4vT4D{tEiZ`jPX~dUh0$C;qJp$+Js5P&VJohsGed&7unjHrXwAj-b&UcQ{)PR zOnBGPMv`z-EN;qBo|NqW00;x=0#X6 zf7}@2;-&NI_;)AsN}3lc(0c|0wC$$OFVZQj*ra?`M-njftHAa;F}eqjQsDp4pGE~! UMS6;;&Hw-a07*qoM6N<$f;}ns@c;k- literal 0 HcmV?d00001 diff --git a/src/chrome/skin/pidgin-tray-away.png b/src/chrome/skin/pidgin-tray-away.png new file mode 100644 index 0000000000000000000000000000000000000000..ab8b077e2bc7553ad5f3ce9677036c2102beab57 GIT binary patch literal 1066 zcmV+_1l9YAP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iOP{ z4;(vzl1#4v00XK?L_t(I%e|F-NL^(d$3N%g-gB?l*W6sbtby939J^yEf7O_Fapnrxigji6FWc?FF6k>+t{@TJ}nvNEXJDp2tbH2>osiT=*z257&_q^S6 z`Xlen>su1k7apFM^E{vD%kRhYJMbS#0C?y8Pqi6}yG=9gQb7<*ZdshOZBBmrw*SI9`ib+sLEW&Ne7W=4uvH)G*G!*8RF0YR+($qS_;e)$){h7xo$W_oyn|re= zH^;-=ni8ov-c>jH)sen6p)fYgcoKTHV~jIzRiar5#vg>ZGi72W5;#aymS#~_R7P9R z)WwS9T@6Y2hK`fqXw0Okb%ZmGl}ye?kZhHPs@)Xr$OhoS+!8-r8)w;a^YT-LzV`0B z9p!I+TRzc#EFx|c<7CFayD~%F!2(pnM6^_n9o|QIaXuM}iwwoZ<0U)TmmkKJhyxZC zC7v7-&M5#9z$FQjYFtNA6g(aevMeJ>5<`1UwuLDm2!hzSCY=AF2`!(AUgt(DVEXx9Ct6Jt@ znHDkK!ZzZh94B?))zh`R^0J~Aehipxm#&UTPGa!h@5|Uo%*=&T`@Z=6Ji`M4{M9u8 z1RsWxTy7RaiwKTBybkR3DvfiCk<8CpyM8lF{g9@qJ%hI&8u__7eBVEUW~4ua;eh}> zeV6(A(hZcXJf?#|T~{N$>EPyOQ8Ub11o7Q#d&R07ou4e(j@k0d;P{dnH&7EYAGcm* zz6jW4SWp`ma3(!g7(__>ejWYOs;D=p40 zEPhnU%+3Y}7DDq(PfqB;iLr>OYj1>x+WOLdP215UHScA66xS(P66#Ge?spOiB#~iL kkM~+qqGch_9^wDcpYTI-EnRAHUjP6A07*qoM6N<$f?Xo{6aWAK literal 0 HcmV?d00001 diff --git a/src/chrome/skin/pidgin-tray-busy.png b/src/chrome/skin/pidgin-tray-busy.png new file mode 100644 index 0000000000000000000000000000000000000000..aa8982b98052e06000936fdca4d20e2c7f44434f GIT binary patch literal 1052 zcmV+%1mpXOP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iOP{ z4;~+nr^@^Q00W#!L_t(I%e9q%NL6PT$3O3Tj`xRNQAx2e)3!9!fwpQ(WOEZof30mc zT7N|_l<8=&MIh0J5?iiq1O^clBg&073Wm_uFeTOv;u?WriP4&DG5-9~jNQ4jw8TUdW zTymIhi4%yAr)QUI9o^((+;$`@Coa;4(f(-p4< zoKTwZPiTetR9N)kL&i^>VD9>L=0-+9*U77?p=A4Zl(FG)t%zmZ@kBh;*T-;sI~yAt z+0xuh&i?%>(I-2Io`A3s9Cut-^Z^f4`ACiy+zMB z?|$>8xYyUm#MP^hrXXe3<7Fasoyxj8aw;nL>C~y;4p`RfI>7A6)bR0ZQO z*4oXRb6lmR*rTHm2RoJpwhdCERaY}RKhLc|Afz0pCpi^QveQC*lwVSEv}xZyuO|}0 z9vwx^%pf!kk)Mw&FJ~bf=E9jX;ZQL6UMKv#DlouFA>J3detg@G9p1H7RWi4*5M^2X zJw44I!^3vK?++Q4wWkvPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01ejw01ejxLMWSf00007bV*G`2iOP{ z4;&`qlpuBh00Y}eL_t(I%e|FdOq*30$N%TNg|2HE<)h-qg*po@ew2b);z(3TG-fnI zWY&aau&aUKjfvh&qUjAc%VGi-W+o;^Va}we7!b(B3>h0=A#Mq zLP59hJC$yrBIjs2d#b2&7rn7{U|v#GeLqr|rk`oQzHm3w006PA#N);^0kMSouSd=> z8L%a@$MyuPi~#^tjqfYZWd9yuWgD#T3(U6rcY#^bG2gFa<=&3jJsc~FjH^HYh~MUJ zVQFa*I@gi+$fJ0+un?-0hWli^H+c5f8T5SH0f(aiM_)LC?CjT|>pJd4qnHbaLFaFv z=44IP#g2VX_9ij1Cb+VOg&2S4=nf+-B^>+5*w$jQ#eW_%MKPle^njtifA zz1|_e-@iid-in5mcsNWn~qCU;s{s6ZNO-p~wnc zE*HY{VccH04ZHnGESgfX^>0IDQjSt6~&LPiw01syx5e$W3&9s6L zg3{8XIREMS6g&xSZEJd z)eXzXU-VvAm|QMN%DXp%fs)*u9HY&a3%A>i@O&6;ZEes2ywlhOr?U`tyB+b(IOf8? zGg(y!06<7leLiYiVl9Nw4=0>L9Q;8p;=eZ44f=EG*Q zp|8ImvvaeU4TX@O??87?e@s{8>V<`c1W9sTweOov+#-x!@NMjzqO!WW++sF$dn%5Z zMKOYdCKEsa&NXPNj`&s_hYnfM`Q7)Mt7~hulOrQtsUPHi@>F`tbs~IS^xQL6w5sGCmQL6}k48(b2wtd`%Ccva&LZ;XwL(gb1(7vf|QoP6;rjFg8FK hJ3BTuwt@dce*s2LBKw9bB?ABe002ovPDHLkV1l3j1e5>( literal 0 HcmV?d00001 diff --git a/src/modules/FiretrayInstantMessaging.jsm b/src/modules/FiretrayInstantMessaging.jsm index c485850..1870569 100644 --- a/src/modules/FiretrayInstantMessaging.jsm +++ b/src/modules/FiretrayInstantMessaging.jsm @@ -7,6 +7,7 @@ const Ci = Components.interfaces; const Cu = Components.utils; Cu.import("resource://firetray/commons.js"); +Cu.import("resource://firetray/linux/FiretrayIMStatusIcon.jsm"); firetray.InstantMessaging = { initialized: false, @@ -26,6 +27,8 @@ firetray.InstantMessaging = { "visited-status-resolution" ]); + firetray.IMStatusIcon.init(); + this.initialized = true; }, @@ -33,6 +36,8 @@ firetray.InstantMessaging = { if (!this.initialized) return; F.LOG("Disabling InstantMessaging"); + firetray.IMStatusIcon.shutdown(); + firetray.Utils.removeAllObservers(firetray.InstantMessaging); this.initialized = false; diff --git a/src/modules/FiretrayMessaging.jsm b/src/modules/FiretrayMessaging.jsm index 6ffda93..61e98d5 100644 --- a/src/modules/FiretrayMessaging.jsm +++ b/src/modules/FiretrayMessaging.jsm @@ -54,10 +54,8 @@ firetray.Messaging = { F.LOG("Disabling Messaging"); firetray.InstantMessaging.shutdown(); - F.LOG("HI THERE"); MailServices.mailSession.RemoveFolderListener(this.mailSessionListener); - firetray.Handler.setIconImageDefault(); firetray.Utils.removeAllObservers(firetray.Messaging); diff --git a/src/modules/ctypes/linux/gio.jsm b/src/modules/ctypes/linux/gio.jsm index f61f47e..c41aca7 100644 --- a/src/modules/ctypes/linux/gio.jsm +++ b/src/modules/ctypes/linux/gio.jsm @@ -16,6 +16,7 @@ function gio_defines(lib) { this.GIcon = ctypes.StructType("GIcon"); this.GThemedIcon = ctypes.StructType("GThemedIcon"); + lib.lazy_bind("g_themed_icon_new", this.GIcon.ptr, ctypes.char.ptr); lib.lazy_bind("g_themed_icon_new_from_names", this.GIcon.ptr, ctypes.char.ptr.ptr, ctypes.int); } diff --git a/src/modules/linux/FiretrayIMStatusIcon.jsm b/src/modules/linux/FiretrayIMStatusIcon.jsm new file mode 100644 index 0000000..14f5af4 --- /dev/null +++ b/src/modules/linux/FiretrayIMStatusIcon.jsm @@ -0,0 +1,65 @@ +/* -*- 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/linux/gobject.jsm"); +Cu.import("resource://firetray/ctypes/linux/gio.jsm"); +Cu.import("resource://firetray/ctypes/linux/gtk.jsm"); +Cu.import("resource://firetray/commons.js"); + +if ("undefined" == typeof(firetray.Handler)) + F.ERROR("This module MUST be imported from/after FiretrayHandler !"); + + +firetray.IMStatusIcon = { + GTK_THEME_ICON_PATH: null, + + initialized: false, + trayIcon: null, + themedIcons: { + "user-available": null, + "user-away": null, + "user-busy": null, + "user-offline": null + }, + + init: function() { + if (!firetray.Handler.inMailApp) throw "IMStatusIcon for mail app only"; + if (!firetray.GtkIcons.initialized) throw "GtkIcons should have been initialized by StatusIcon"; + + this.trayIcon = gtk.gtk_status_icon_new(); + this.loadThemedIcons(); + this.setIconImageFromGIcon(this.themedIcons["user-offline"]); + + this.initialized = true; + return true; + }, + + shutdown: function() { + gtk.gtk_status_icon_set_visible(this.trayIcon, false); + // FIXME: tryCloseLibs should be done by Handler only, submodules should + // just pass the imported ctypes modules to it + // firetray.Utils.tryCloseLibs([gobject, gio, gtk]); + this.initialized = false; + }, + + loadThemedIcons: function() { + for (let name in this.themedIcons) + this.themedIcons[name] = gio.g_themed_icon_new(name); + }, + + setIconImageFromGIcon: function(gicon) { + if (!firetray.IMStatusIcon.trayIcon || !gicon) + F.ERROR("Icon missing"); + F.LOG(gicon); + gtk.gtk_status_icon_set_from_gicon(firetray.IMStatusIcon.trayIcon, gicon); + } + +}; // firetray.IMStatusIcon diff --git a/src/modules/linux/FiretrayStatusIcon.jsm b/src/modules/linux/FiretrayStatusIcon.jsm index 4a7d9db..d38362f 100644 --- a/src/modules/linux/FiretrayStatusIcon.jsm +++ b/src/modules/linux/FiretrayStatusIcon.jsm @@ -61,6 +61,7 @@ firetray.StatusIcon = { shutdown: function() { F.LOG("Disabling StatusIcon"); firetray.PopupMenu.shutdown(); + // FIXME: should destroy/hide icon here firetray.GtkIcons.shutdown(); firetray.Utils.tryCloseLibs([cairo, gobject, gdk, gio, gtk, pango, pangocairo]); this.initialized = false; From ff7bcd4c9102ad0fffabd192e7003cb8834667d3 Mon Sep 17 00:00:00 2001 From: foudfou Date: Tue, 7 Aug 2012 22:34:02 +0200 Subject: [PATCH 08/18] destroy icons when shutting down IMStatusIcon --- src/modules/linux/FiretrayIMStatusIcon.jsm | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/modules/linux/FiretrayIMStatusIcon.jsm b/src/modules/linux/FiretrayIMStatusIcon.jsm index 14f5af4..26aa295 100644 --- a/src/modules/linux/FiretrayIMStatusIcon.jsm +++ b/src/modules/linux/FiretrayIMStatusIcon.jsm @@ -43,7 +43,7 @@ firetray.IMStatusIcon = { }, shutdown: function() { - gtk.gtk_status_icon_set_visible(this.trayIcon, false); + this.destroyIcons(); // FIXME: tryCloseLibs should be done by Handler only, submodules should // just pass the imported ctypes modules to it // firetray.Utils.tryCloseLibs([gobject, gio, gtk]); @@ -55,6 +55,14 @@ firetray.IMStatusIcon = { this.themedIcons[name] = gio.g_themed_icon_new(name); }, + destroyIcons: function() { + for (let name in this.themedIcons) { + let gicon = this.themedIcons[name]; + gicon = gobject.g_object_unref(gicon); + } + gobject.g_object_unref(this.trayIcon); + }, + setIconImageFromGIcon: function(gicon) { if (!firetray.IMStatusIcon.trayIcon || !gicon) F.ERROR("Icon missing"); From 82fae974d1d94cad06a18203efc08d2c0d881717 Mon Sep 17 00:00:00 2001 From: foudfou Date: Tue, 7 Aug 2012 23:37:32 +0200 Subject: [PATCH 09/18] ctypes libs are tracked by firetray.Handler. (sub)modules using ctypes libs just need to declare opened libs, which will be ultimately closed by the Handler. Not only is this fancier, but also useful in situations where we want to init()/shutdown() modules without closing libs used by others (ex: IMStatusIcon) --- src/modules/FiretrayHandler.jsm | 22 +++++++++++++++++++++- src/modules/commons.js | 9 --------- src/modules/ctypes/ctypes-utils.jsm | 4 +++- src/modules/linux/FiretrayGtkIcons.jsm | 2 +- src/modules/linux/FiretrayIMStatusIcon.jsm | 4 +--- src/modules/linux/FiretrayPopupMenu.jsm | 2 +- src/modules/linux/FiretrayStatusIcon.jsm | 2 +- src/modules/linux/FiretrayWindow.jsm | 2 +- 8 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/modules/FiretrayHandler.jsm b/src/modules/FiretrayHandler.jsm index 5e83931..4cdee21 100644 --- a/src/modules/FiretrayHandler.jsm +++ b/src/modules/FiretrayHandler.jsm @@ -36,6 +36,8 @@ firetray.Handler = { windowsCount: 0, visibleWindowsCount: 0, observedTopics: {}, + ctypesLibs: {}, // {"lib1": lib1, "lib2": lib2} + appId: (function(){return Services.appinfo.ID;})(), appName: (function(){return Services.appinfo.name;})(), @@ -117,7 +119,7 @@ firetray.Handler = { firetray.Messaging.shutdown(); firetray.StatusIcon.shutdown(); firetray.Window.shutdown(); - // watchout order and sufficiency of lib closings (tryCloseLibs()) + this.tryCloseLibs(); firetray.Utils.removeAllObservers(this); @@ -126,6 +128,24 @@ firetray.Handler = { return true; }, + tryCloseLibs: function() { + try { + for (libName in this.ctypesLibs) { + let lib = this.ctypesLibs[libName]; + if (lib.available()) + lib.close(); + }; + } catch(x) { F.ERROR(x); } + }, + + subscribeLibsForClosing: function(libs) { + for (let i=0, len=libs.length; i Date: Mon, 13 Aug 2012 12:07:57 +0200 Subject: [PATCH 10/18] IM icon changes according to IM global status --- src/modules/FiretrayInstantMessaging.jsm | 58 ++++++++++++++++++---- src/modules/FiretrayMessaging.jsm | 7 +++ src/modules/commons.js | 7 +++ src/modules/linux/FiretrayIMStatusIcon.jsm | 20 +++++--- 4 files changed, 74 insertions(+), 18 deletions(-) diff --git a/src/modules/FiretrayInstantMessaging.jsm b/src/modules/FiretrayInstantMessaging.jsm index 1870569..ee7304e 100644 --- a/src/modules/FiretrayInstantMessaging.jsm +++ b/src/modules/FiretrayInstantMessaging.jsm @@ -1,14 +1,16 @@ /* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -var EXPORTED_SYMBOLS = [ "firetray", "FLDRS_UNINTERESTING" ]; +var EXPORTED_SYMBOLS = [ "firetray" ]; const Cc = Components.classes; const Ci = Components.interfaces; const Cu = Components.utils; +Cu.import("resource:///modules/imServices.jsm"); Cu.import("resource://firetray/commons.js"); Cu.import("resource://firetray/linux/FiretrayIMStatusIcon.jsm"); +// FIXME: rename to firetray.Chat firetray.InstantMessaging = { initialized: false, observedTopics: {}, @@ -22,11 +24,10 @@ firetray.InstantMessaging = { firetray.Utils.addObservers(firetray.InstantMessaging, [ // "*" // debugging - "idle-time-changed", "new-directed-incoming-message", "new-text", - "new-ui-conversation", "status-changed", "unread-im-count-changed", - "visited-status-resolution" + "account-connected", "account-disconnected", "idle-time-changed", + "new-directed-incoming-message", "new-text", "new-ui-conversation", + "status-changed", "unread-im-count-changed", "visited-status-resolution" ]); - firetray.IMStatusIcon.init(); this.initialized = true; @@ -37,7 +38,6 @@ firetray.InstantMessaging = { F.LOG("Disabling InstantMessaging"); firetray.IMStatusIcon.shutdown(); - firetray.Utils.removeAllObservers(firetray.InstantMessaging); this.initialized = false; @@ -46,18 +46,54 @@ firetray.InstantMessaging = { observe: function(subject, topic, data) { F.LOG("RECEIVED InstantMessaging: "+topic+" subject="+subject+" data="+data); switch (topic) { + case "account-connected": + case "account-disconnected": + case "idle-time-changed": + case "status-changed": + // case "visited-status-resolution": + this.updateIcon(); + break; + case "unread-im-count-changed": break; + case "new-directed-incoming-message": // when PM or cited in channel: new-directed-incoming-message: [xpconnect wrapped (nsISupports, nsIClassInfo, prplIMessage)] null break; - case "visited-status-resolution": - break; - case "status-changed": - case "idle-time-changed": - break; + default: F.WARN("unhandled topic: "+topic); } + }, + + updateIcon: function() { + let userStatus = Services.core.globalUserStatus.statusType; + F.LOG("IM status="+userStatus); + + let iconName; + switch (userStatus) { + case Ci.imIStatusInfo.STATUS_OFFLINE: + iconName = FIRETRAY_IM_STATUS_OFFLINE; + break; + case Ci.imIStatusInfo.STATUS_IDLE: + case Ci.imIStatusInfo.STATUS_AWAY: + iconName = FIRETRAY_IM_STATUS_AWAY; + break; + case Ci.imIStatusInfo.STATUS_AVAILABLE: + iconName = FIRETRAY_IM_STATUS_AVAILABLE; + break; + case Ci.imIStatusInfo.STATUS_UNAVAILABLE: + iconName = FIRETRAY_IM_STATUS_BUSY; + break; + case Ci.imIStatusInfo.STATUS_UNKNOWN: + case Ci.imIStatusInfo.STATUS_INVISIBLE: + case Ci.imIStatusInfo.STATUS_MOBILE: + default: + // ignore + } + + F.LOG("IM status changed="+iconName); + if (iconName) + firetray.IMStatusIcon.setIconImage(iconName); } }; diff --git a/src/modules/FiretrayMessaging.jsm b/src/modules/FiretrayMessaging.jsm index 61e98d5..f7d3de4 100644 --- a/src/modules/FiretrayMessaging.jsm +++ b/src/modules/FiretrayMessaging.jsm @@ -62,6 +62,11 @@ firetray.Messaging = { this.initialized = false; }, + // FIXME: this should definetely be done in InstantMessaging, but IM accounts + // seem not be initialized at this stage (Exception... "'TypeError: + // this._items is undefined' when calling method: + // [nsISimpleEnumerator::hasMoreElements]"), and we're unsure if we should + // initAccounts() ourselves... existsIMAccount: function() { let accounts = new this.Accounts(); for (let accountServer in accounts) @@ -80,10 +85,12 @@ firetray.Messaging = { this.cleanExcludedAccounts(); if (subject.QueryInterface(Ci.imIAccount) && !this.existsIMAccount()) firetray.InstantMessaging.shutdown(); + // FIXME: clean InstantMessaging.accounts or just update (?) break; case "account-added": if (subject.QueryInterface(Ci.imIAccount) && !firetray.InstantMessaging.initialized) firetray.InstantMessaging.init(); + // FIXME: clean InstantMessaging.accounts or just update (?) break; default: F.WARN("unhandled topic: "+topic); diff --git a/src/modules/commons.js b/src/modules/commons.js index 1d66364..14a3dd3 100644 --- a/src/modules/commons.js +++ b/src/modules/commons.js @@ -9,6 +9,8 @@ var EXPORTED_SYMBOLS = "FIRETRAY_APPLICATION_ICON_TYPE_CUSTOM", "FIRETRAY_NOTIFICATION_UNREAD_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_DELAY_BROWSER_STARTUP_MILLISECONDS", "FIRETRAY_DELAY_NOWAIT_MILLISECONDS", "FIRETRAY_DELAY_PREF_CLEANING_MILLISECONDS", @@ -36,6 +38,11 @@ const FIRETRAY_NOTIFICATION_UNREAD_MESSAGE_COUNT = 0; const FIRETRAY_NOTIFICATION_NEWMAIL_ICON = 1; const FIRETRAY_NOTIFICATION_CUSTOM_ICON = 2; +const FIRETRAY_IM_STATUS_AVAILABLE = "user-available"; +const FIRETRAY_IM_STATUS_AWAY = "user-away"; +const FIRETRAY_IM_STATUS_BUSY = "user-busy"; +const FIRETRAY_IM_STATUS_OFFLINE = "user-offline"; + const FIRETRAY_DELAY_BROWSER_STARTUP_MILLISECONDS = 500; const FIRETRAY_DELAY_NOWAIT_MILLISECONDS = 0; const FIRETRAY_DELAY_PREF_CLEANING_MILLISECONDS = 15*60*1000; diff --git a/src/modules/linux/FiretrayIMStatusIcon.jsm b/src/modules/linux/FiretrayIMStatusIcon.jsm index ce803a2..4178215 100644 --- a/src/modules/linux/FiretrayIMStatusIcon.jsm +++ b/src/modules/linux/FiretrayIMStatusIcon.jsm @@ -24,12 +24,14 @@ firetray.IMStatusIcon = { initialized: false, trayIcon: null, - themedIcons: { - "user-available": null, - "user-away": null, - "user-busy": null, - "user-offline": null - }, + appId: (function(){return Services.appinfo.ID;})(), + themedIcons: (function(){let o = {}; + o[FIRETRAY_IM_STATUS_AVAILABLE] = null; + o[FIRETRAY_IM_STATUS_AWAY] = null; + o[FIRETRAY_IM_STATUS_BUSY] = null; + o[FIRETRAY_IM_STATUS_OFFLINE] = null; + return o; + })(), init: function() { if (!firetray.Handler.inMailApp) throw "IMStatusIcon for mail app only"; @@ -37,7 +39,7 @@ firetray.IMStatusIcon = { this.trayIcon = gtk.gtk_status_icon_new(); this.loadThemedIcons(); - this.setIconImageFromGIcon(this.themedIcons["user-offline"]); + this.setIconImage(FIRETRAY_IM_STATUS_OFFLINE); this.initialized = true; return true; @@ -66,6 +68,10 @@ firetray.IMStatusIcon = { F.ERROR("Icon missing"); F.LOG(gicon); gtk.gtk_status_icon_set_from_gicon(firetray.IMStatusIcon.trayIcon, gicon); + }, + + setIconImage: function(name) { + this.setIconImageFromGIcon(this.themedIcons[name]); } }; // firetray.IMStatusIcon From 9f46ef6343816580428e1b2f6fdce840b2a368db Mon Sep 17 00:00:00 2001 From: foudfou Date: Tue, 21 Aug 2012 22:10:56 +0200 Subject: [PATCH 11/18] IM icon blinking when private message or cited in channel --- src/modules/FiretrayHandler.jsm | 4 +- src/modules/FiretrayInstantMessaging.jsm | 68 ++++++++++++++++++++-- src/modules/FiretrayMessaging.jsm | 8 ++- src/modules/ctypes/linux/gdk.jsm | 6 ++ src/modules/ctypes/linux/gobject.jsm | 1 + src/modules/ctypes/linux/gtk.jsm | 8 ++- src/modules/linux/FiretrayIMStatusIcon.jsm | 28 +++++++++ src/modules/linux/FiretrayWindow.jsm | 24 +++++++- 8 files changed, 136 insertions(+), 11 deletions(-) diff --git a/src/modules/FiretrayHandler.jsm b/src/modules/FiretrayHandler.jsm index 4cdee21..36ef9a1 100644 --- a/src/modules/FiretrayHandler.jsm +++ b/src/modules/FiretrayHandler.jsm @@ -29,8 +29,9 @@ if ("undefined" == typeof(firetray)) { firetray.Handler = { initialized: false, - inMailApp: false, inBrowserApp: false, + inMailApp: false, + isIMEnabled: false, appStarted: false, windows: {}, windowsCount: 0, @@ -200,6 +201,7 @@ firetray.Handler = { showWindow: function(winId) {}, showHideAllWindows: function() {}, activateLastWindow: function(gtkStatusIcon, gdkEvent, userData) {}, + findActiveWindow: function() {}, showAllWindows: function() { F.LOG("showAllWindows"); diff --git a/src/modules/FiretrayInstantMessaging.jsm b/src/modules/FiretrayInstantMessaging.jsm index ee7304e..41730b7 100644 --- a/src/modules/FiretrayInstantMessaging.jsm +++ b/src/modules/FiretrayInstantMessaging.jsm @@ -14,6 +14,7 @@ Cu.import("resource://firetray/linux/FiretrayIMStatusIcon.jsm"); firetray.InstantMessaging = { initialized: false, observedTopics: {}, + acknowledgeOnFocus: {}, init: function() { if (this.initialized) { @@ -25,8 +26,8 @@ firetray.InstantMessaging = { firetray.Utils.addObservers(firetray.InstantMessaging, [ // "*" // debugging "account-connected", "account-disconnected", "idle-time-changed", - "new-directed-incoming-message", "new-text", "new-ui-conversation", - "status-changed", "unread-im-count-changed", "visited-status-resolution" + "new-directed-incoming-message", "status-changed", + "unread-im-count-changed" ]); firetray.IMStatusIcon.init(); @@ -50,14 +51,29 @@ firetray.InstantMessaging = { case "account-disconnected": case "idle-time-changed": case "status-changed": - // case "visited-status-resolution": this.updateIcon(); break; - case "unread-im-count-changed": + case "new-directed-incoming-message": // when PM or cited in channel + let conv = subject.QueryInterface(Ci.prplIMessage).conversation; + F.LOG("conversation name="+conv.name); // normalizedName shouldn't be necessary + + let convIsActiveTabInActiveWin = this.isConvActiveTabInActiveWindow(conv); + F.LOG("convIsActiveTabInActiveWin="+convIsActiveTabInActiveWin); + let [unreadTargettedCount, unreadTotalCount] = this.countUnreadMessages(); + F.LOG("unreadTotalCount="+unreadTotalCount); + if (!convIsActiveTabInActiveWin) { // don't blink when conv tab already on top + this.acknowledgeOnFocus.must = true; + this.acknowledgeOnFocus.conv = conv; + firetray.IMStatusIcon.setIconBlinking(true); + } break; - case "new-directed-incoming-message": // when PM or cited in channel: new-directed-incoming-message: [xpconnect wrapped (nsISupports, nsIClassInfo, prplIMessage)] null + case "unread-im-count-changed": + let unreadMsgCount = data; + if (unreadMsgCount == 0) + this.stopIconBlinkingMaybe(); + // FIXME: setToolTip break; default: @@ -65,6 +81,48 @@ firetray.InstantMessaging = { } }, + stopIconBlinkingMaybe: function() { + F.WARN("acknowledgeOnFocus.must="+this.acknowledgeOnFocus.must); + let convIsActiveTabInActiveWin = this.isConvActiveTabInActiveWindow( + this.acknowledgeOnFocus.conv); + + if (this.acknowledgeOnFocus.must && convIsActiveTabInActiveWin) { + firetray.IMStatusIcon.setIconBlinking(false); + this.acknowledgeOnFocus.must = false; + } + }, + + isConvActiveTabInActiveWindow: function(conv) { + let activeWin = firetray.Handler.findActiveWindow(), + activeChatTab = null; + if (!activeWin) return false; + + activeChatTab = this.findActiveChatTab(activeWin); + let convNameRegex = new RegExp(" - "+conv.name+"$"); + return activeChatTab ? convNameRegex.test(activeChatTab.title) : false; + }, + + findActiveChatTab: function(xid) { + let win = firetray.Handler.windows[xid].chromeWin; + let tabmail = win.document.getElementById("tabmail"); + let chatTabs = tabmail.tabModes.chat.tabs; + for each (let tab in chatTabs) + if (tab.tabNode.selected) return tab; + return null; + }, + + // lifted from chat-messenger-overlay.js + countUnreadMessages: function() { + let convs = Services.conversations.getUIConversations(); + let unreadTargettedCount = 0; + let unreadTotalCount = 0; + for each (let conv in convs) { + unreadTargettedCount += conv.unreadTargetedMessageCount; + unreadTotalCount += conv.unreadIncomingMessageCount; + } + return [unreadTargettedCount, unreadTotalCount]; + }, + updateIcon: function() { let userStatus = Services.core.globalUserStatus.statusType; F.LOG("IM status="+userStatus); diff --git a/src/modules/FiretrayMessaging.jsm b/src/modules/FiretrayMessaging.jsm index f7d3de4..e6c05d3 100644 --- a/src/modules/FiretrayMessaging.jsm +++ b/src/modules/FiretrayMessaging.jsm @@ -43,8 +43,12 @@ firetray.Messaging = { MailServices.mailSession.AddFolderListener(that.mailSessionListener, that.mailSessionListener.notificationFlags); - if (Services.prefs.getBoolPref("mail.chat.enabled") && this.existsIMAccount()) + // FIXME: add im-icon pref + // FIXME: watch out account-added !! + if (Services.prefs.getBoolPref("mail.chat.enabled") && this.existsIMAccount()) { firetray.InstantMessaging.init(); + firetray.Handler.isIMEnabled = true; + } this.initialized = true; }, @@ -283,7 +287,7 @@ firetray.Messaging = { let rootFolder = accountServer.rootFolder; // nsIMsgFolder if (rootFolder.hasSubFolders) { let subFolders = rootFolder.subFolders; - while(subFolders.hasMoreElements()) { + while (subFolders.hasMoreElements()) { let folder = subFolders.getNext().QueryInterface(Ci.nsIMsgFolder); if (!(folder.flags & excludedFoldersFlags)) { msgCount = folderCountFunction(folder, msgCount); diff --git a/src/modules/ctypes/linux/gdk.jsm b/src/modules/ctypes/linux/gdk.jsm index dda91fb..f437a86 100644 --- a/src/modules/ctypes/linux/gdk.jsm +++ b/src/modules/ctypes/linux/gdk.jsm @@ -237,6 +237,12 @@ function gdk_defines(lib) { { "x_root": gobject.gdouble }, { "y_root": gobject.gdouble } ]); + this.GdkEventFocus = ctypes.StructType("GdkEventFocus", [ + { "type": this.GdkEventType }, + { "window": this.GdkWindow.ptr }, + { "send_event": gobject.gint8 }, + { "in": gobject.gint16 }, + ]); this.GdkFilterFunc_t = ctypes.FunctionType( ctypes.default_abi, this.GdkFilterReturn, diff --git a/src/modules/ctypes/linux/gobject.jsm b/src/modules/ctypes/linux/gobject.jsm index eb773be..ddd3be3 100644 --- a/src/modules/ctypes/linux/gobject.jsm +++ b/src/modules/ctypes/linux/gobject.jsm @@ -89,6 +89,7 @@ function gobject_defines(lib) { this.guint16 = ctypes.uint16_t; this.gint = ctypes.int; this.gint8 = ctypes.int8_t; + this.gint16 = ctypes.int16_t; this.gchar = ctypes.char; this.guchar = ctypes.unsigned_char; this.gboolean = this.gint; diff --git a/src/modules/ctypes/linux/gtk.jsm b/src/modules/ctypes/linux/gtk.jsm index 55c62a1..60f3670 100644 --- a/src/modules/ctypes/linux/gtk.jsm +++ b/src/modules/ctypes/linux/gtk.jsm @@ -74,6 +74,10 @@ function gtk_defines(lib) { this.GCallbackWindowStateEvent_t = ctypes.FunctionType( ctypes.default_abi, gobject.gboolean, [this.GtkWidget.ptr, gdk.GdkEventWindowState.ptr, gobject.gpointer]).ptr; + this.GCallbackWidgetFocuEvent_t = ctypes.FunctionType( + ctypes.default_abi, gobject.gboolean, + [this.GtkWidget.ptr, gdk.GdkEventFocus.ptr, gobject.gpointer]).ptr; + lib.lazy_bind("gtk_icon_theme_get_default", this.GtkIconTheme.ptr); lib.lazy_bind("gtk_icon_theme_get_for_screen", this.GtkIconTheme.ptr, gdk.GdkScreen.ptr); @@ -85,6 +89,7 @@ function gtk_defines(lib) { lib.lazy_bind("gtk_status_icon_set_from_icon_name", ctypes.void_t, this.GtkStatusIcon.ptr, gobject.gchar.ptr); lib.lazy_bind("gtk_status_icon_set_from_gicon", ctypes.void_t, this.GtkStatusIcon.ptr, gio.GIcon.ptr); lib.lazy_bind("gtk_status_icon_set_tooltip_text", ctypes.void_t, this.GtkStatusIcon.ptr, ctypes.char.ptr); + lib.lazy_bind("gtk_status_icon_set_blinking", ctypes.void_t, this.GtkStatusIcon.ptr, gobject.gboolean); // deprecated in gtk3 lib.lazy_bind("gtk_status_icon_set_visible", ctypes.void_t, this.GtkStatusIcon.ptr, gobject.gboolean); lib.lazy_bind("gtk_menu_new", this.GtkMenu.ptr); lib.lazy_bind("gtk_menu_item_set_label", ctypes.void_t, this.GtkMenuItem.ptr, gobject.gchar.ptr); @@ -104,7 +109,8 @@ function gtk_defines(lib) { lib.lazy_bind("gtk_status_icon_set_from_pixbuf", ctypes.void_t, this.GtkStatusIcon.ptr, gdk.GdkPixbuf.ptr); lib.lazy_bind("gtk_window_list_toplevels", gobject.GList.ptr); lib.lazy_bind("gtk_window_get_title", gobject.gchar.ptr, this.GtkWindow.ptr); - + lib.lazy_bind("gtk_window_is_active", gobject.gboolean, this.GtkWindow.ptr); + lib.lazy_bind("gtk_window_has_toplevel_focus", gobject.gboolean, this.GtkWindow.ptr); lib.lazy_bind("gtk_widget_get_has_window", gobject.gboolean, this.GtkWidget.ptr); lib.lazy_bind("gtk_widget_get_window", gdk.GdkWindow.ptr, this.GtkWidget.ptr); lib.lazy_bind("gtk_widget_get_parent_window", gdk.GdkWindow.ptr, this.GtkWidget.ptr); diff --git a/src/modules/linux/FiretrayIMStatusIcon.jsm b/src/modules/linux/FiretrayIMStatusIcon.jsm index 4178215..008c7d3 100644 --- a/src/modules/linux/FiretrayIMStatusIcon.jsm +++ b/src/modules/linux/FiretrayIMStatusIcon.jsm @@ -11,7 +11,9 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/ctypes.jsm"); Cu.import("resource://firetray/ctypes/linux/gobject.jsm"); Cu.import("resource://firetray/ctypes/linux/gio.jsm"); +Cu.import("resource://firetray/ctypes/linux/gdk.jsm"); Cu.import("resource://firetray/ctypes/linux/gtk.jsm"); +Cu.import("resource://firetray/linux/FiretrayWindow.jsm"); Cu.import("resource://firetray/commons.js"); firetray.Handler.subscribeLibsForClosing([gobject, gio, gtk]); @@ -32,6 +34,7 @@ firetray.IMStatusIcon = { o[FIRETRAY_IM_STATUS_OFFLINE] = null; return o; })(), + callbacks: {onFocusIn: {}}, init: function() { if (!firetray.Handler.inMailApp) throw "IMStatusIcon for mail app only"; @@ -72,6 +75,31 @@ firetray.IMStatusIcon = { setIconImage: function(name) { this.setIconImageFromGIcon(this.themedIcons[name]); + }, + + setIconBlinking: function(blink) { + gtk.gtk_status_icon_set_blinking(this.trayIcon, blink); + }, + + /* we could also use x11.FocusIn... just wanted to try a different method */ + attachOnFocusInCallback: function(xid) { + F.LOG("attachOnFocusInCallback xid="+xid); + this.callbacks.onFocusIn[xid] = gtk.GCallbackWidgetFocuEvent_t(firetray.IMStatusIcon.onFocusIn); + gobject.g_signal_connect(firetray.Handler.gtkWindows.get(xid), + "focus-in-event", firetray.IMStatusIcon.callbacks.onFocusIn[xid], null); + }, + + // NOTE: fluxbox issues a FocusIn event when switching workspace by hotkey :( + // (http://sourceforge.net/tracker/index.php?func=detail&aid=3190205&group_id=35398&atid=413960) + onFocusIn: function(widget, event, data) { + F.LOG("onFocusIn"); + // let gdkEventFocus = ctypes.cast(event, gdk.GdkEventFocus.ptr); + // let gdkWin = gdkEventFocus.contents.window; + // let xid = firetray.Window.getXIDFromGdkWindow(gdkWin); + // F.LOG("xid="+xid+" in="+gdkEventFocus.contents["in"]); + firetray.InstantMessaging.stopIconBlinkingMaybe(); } + // FIXME: TODO: onclick/activate -> chatHandler.showCurrentConversation() + }; // firetray.IMStatusIcon diff --git a/src/modules/linux/FiretrayWindow.jsm b/src/modules/linux/FiretrayWindow.jsm index 4cbd6a4..2c54ddc 100644 --- a/src/modules/linux/FiretrayWindow.jsm +++ b/src/modules/linux/FiretrayWindow.jsm @@ -516,7 +516,7 @@ firetray.Window = { if (firetray.Handler.windows[xwin].visible && firetray.js.strEquals(xprop.contents.atom, x11.current.Atoms.WM_STATE) && firetray.js.strEquals(xprop.contents.state, x11.PropertyNewValue)) { - F.LOG("PropertyNotify: WM_STATE, send_event: "+xprop.contents.send_event+", state: "+xprop.contents.state); + F.LOG("xid="+xwin+" PropertyNotify: WM_STATE, send_event: "+xprop.contents.send_event+", state: "+xprop.contents.state); winStates = firetray.Window.getXWindowStates(xwin); isHidden = winStates & FIRETRAY_XWINDOW_HIDDEN; } @@ -536,7 +536,7 @@ firetray.Window = { if (hides_single_window) { firetray.Handler.hideWindow(xwin); } else - firetray.Handler.hideAllWindows(); + firetray.Handler.hideAllWindows(); } } @@ -595,6 +595,12 @@ firetray.Handler.registerWindow = function(win) { this.windows[xid].filterWindowCb = gdk.GdkFilterFunc_t(firetray.Window.filterWindow); gdk.gdk_window_add_filter(gdkWin, this.windows[xid].filterWindowCb, null); + // FIXME: isn't it (c)leaner to do it in x11 window filter ? + if (firetray.Handler.isIMEnabled) { + Cu.import("resource://firetray/linux/FiretrayIMStatusIcon.jsm"); + firetray.IMStatusIcon.attachOnFocusInCallback(xid); + } + } catch (x) { firetray.Window.unregisterWindowByXID(xid); F.ERROR(x); @@ -656,6 +662,20 @@ firetray.Handler.activateLastWindow = function(gtkStatusIcon, gdkEvent, userData return stopPropagation; }; +firetray.Handler.findActiveWindow = function() { + let activeWin = null; + for (let xid in firetray.Handler.windows) { + let gtkWin = firetray.Handler.gtkWindows.get(xid); + let isActive = gtk.gtk_window_is_active(gtkWin); + F.LOG(xid+" is active="+isActive); + if (isActive) { + activeWin = xid; + break; + } + } + return activeWin; +}; + /** * init X11 Display and handled XAtoms. From 5c12abb1ee5c3eb55905e11aa3a1d47dcd1d2f92 Mon Sep 17 00:00:00 2001 From: foudfou Date: Sat, 25 Aug 2012 19:02:14 +0200 Subject: [PATCH 12/18] =?UTF-8?q?*=20fix=20non-import=20of=20IM=20stuff=20?= =?UTF-8?q?in=20Firefox=20*=20add=20minimal=20tooltip=20for=20Chat=20icon?= =?UTF-8?q?=20*=20fix=20findActiveWindow()=20=E2=80=94=20gtk=5Fwindow=5Fis?= =?UTF-8?q?=5Factive()=20not=20reliable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/FiretrayHandler.jsm | 2 -- src/modules/FiretrayInstantMessaging.jsm | 28 ++++++++------------ src/modules/FiretrayMessaging.jsm | 7 +---- src/modules/ctypes/linux/gobject.jsm | 4 ++- src/modules/ctypes/linux/gtk.jsm | 2 ++ src/modules/linux/FiretrayIMStatusIcon.jsm | 12 ++++++++- src/modules/linux/FiretrayWindow.jsm | 30 ++++++++++++++-------- 7 files changed, 47 insertions(+), 38 deletions(-) diff --git a/src/modules/FiretrayHandler.jsm b/src/modules/FiretrayHandler.jsm index 36ef9a1..de531ad 100644 --- a/src/modules/FiretrayHandler.jsm +++ b/src/modules/FiretrayHandler.jsm @@ -31,7 +31,6 @@ firetray.Handler = { initialized: false, inBrowserApp: false, inMailApp: false, - isIMEnabled: false, appStarted: false, windows: {}, windowsCount: 0, @@ -39,7 +38,6 @@ firetray.Handler = { observedTopics: {}, ctypesLibs: {}, // {"lib1": lib1, "lib2": lib2} - appId: (function(){return Services.appinfo.ID;})(), appName: (function(){return Services.appinfo.name;})(), appStartupTopic: null, diff --git a/src/modules/FiretrayInstantMessaging.jsm b/src/modules/FiretrayInstantMessaging.jsm index 41730b7..57b3795 100644 --- a/src/modules/FiretrayInstantMessaging.jsm +++ b/src/modules/FiretrayInstantMessaging.jsm @@ -60,8 +60,6 @@ firetray.InstantMessaging = { let convIsActiveTabInActiveWin = this.isConvActiveTabInActiveWindow(conv); F.LOG("convIsActiveTabInActiveWin="+convIsActiveTabInActiveWin); - let [unreadTargettedCount, unreadTotalCount] = this.countUnreadMessages(); - F.LOG("unreadTotalCount="+unreadTotalCount); if (!convIsActiveTabInActiveWin) { // don't blink when conv tab already on top this.acknowledgeOnFocus.must = true; this.acknowledgeOnFocus.conv = conv; @@ -73,7 +71,12 @@ firetray.InstantMessaging = { let unreadMsgCount = data; if (unreadMsgCount == 0) this.stopIconBlinkingMaybe(); - // FIXME: setToolTip + + let localizedTooltip = PluralForm.get( + unreadMsgCount, + firetray.Utils.strings.GetStringFromName("tooltip.unread_messages")) + .replace("#1", unreadMsgCount); + firetray.IMStatusIcon.setIconTooltip(localizedTooltip); break; default: @@ -82,9 +85,12 @@ firetray.InstantMessaging = { }, stopIconBlinkingMaybe: function() { - F.WARN("acknowledgeOnFocus.must="+this.acknowledgeOnFocus.must); + F.LOG("acknowledgeOnFocus.must="+this.acknowledgeOnFocus.must); + // if (!this.acknowledgeOnFocus.must) return; + let convIsActiveTabInActiveWin = this.isConvActiveTabInActiveWindow( this.acknowledgeOnFocus.conv); + F.LOG("convIsActiveTabInActiveWin="+convIsActiveTabInActiveWin); if (this.acknowledgeOnFocus.must && convIsActiveTabInActiveWin) { firetray.IMStatusIcon.setIconBlinking(false); @@ -95,7 +101,7 @@ firetray.InstantMessaging = { isConvActiveTabInActiveWindow: function(conv) { let activeWin = firetray.Handler.findActiveWindow(), activeChatTab = null; - if (!activeWin) return false; + if (!firetray.Handler.windows[activeWin]) return false; activeChatTab = this.findActiveChatTab(activeWin); let convNameRegex = new RegExp(" - "+conv.name+"$"); @@ -111,18 +117,6 @@ firetray.InstantMessaging = { return null; }, - // lifted from chat-messenger-overlay.js - countUnreadMessages: function() { - let convs = Services.conversations.getUIConversations(); - let unreadTargettedCount = 0; - let unreadTotalCount = 0; - for each (let conv in convs) { - unreadTargettedCount += conv.unreadTargetedMessageCount; - unreadTotalCount += conv.unreadIncomingMessageCount; - } - return [unreadTargettedCount, unreadTotalCount]; - }, - updateIcon: function() { let userStatus = Services.core.globalUserStatus.statusType; F.LOG("IM status="+userStatus); diff --git a/src/modules/FiretrayMessaging.jsm b/src/modules/FiretrayMessaging.jsm index e6c05d3..effb594 100644 --- a/src/modules/FiretrayMessaging.jsm +++ b/src/modules/FiretrayMessaging.jsm @@ -44,11 +44,8 @@ firetray.Messaging = { that.mailSessionListener.notificationFlags); // FIXME: add im-icon pref - // FIXME: watch out account-added !! - if (Services.prefs.getBoolPref("mail.chat.enabled") && this.existsIMAccount()) { + if (Services.prefs.getBoolPref("mail.chat.enabled") && this.existsIMAccount()) firetray.InstantMessaging.init(); - firetray.Handler.isIMEnabled = true; - } this.initialized = true; }, @@ -89,12 +86,10 @@ firetray.Messaging = { this.cleanExcludedAccounts(); if (subject.QueryInterface(Ci.imIAccount) && !this.existsIMAccount()) firetray.InstantMessaging.shutdown(); - // FIXME: clean InstantMessaging.accounts or just update (?) break; case "account-added": if (subject.QueryInterface(Ci.imIAccount) && !firetray.InstantMessaging.initialized) firetray.InstantMessaging.init(); - // FIXME: clean InstantMessaging.accounts or just update (?) break; default: F.WARN("unhandled topic: "+topic); diff --git a/src/modules/ctypes/linux/gobject.jsm b/src/modules/ctypes/linux/gobject.jsm index ddd3be3..6362c20 100644 --- a/src/modules/ctypes/linux/gobject.jsm +++ b/src/modules/ctypes/linux/gobject.jsm @@ -1,4 +1,4 @@ -/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -152,6 +152,8 @@ function gobject_defines(lib) { lib.lazy_bind("g_signal_handler_block", ctypes.void_t, this.gpointer, this.gulong); lib.lazy_bind("g_signal_handler_unblock", ctypes.void_t, this.gpointer, this.gulong); + /* NOTE: we can't easily work with g_object_get_property() because it uses + GValue, which is an opaque struct, and thus can't be initialized by ctypes */ } new ctypes_library(GOBJECT_LIBNAME, GOBJECT_ABIS, gobject_defines, this); diff --git a/src/modules/ctypes/linux/gtk.jsm b/src/modules/ctypes/linux/gtk.jsm index 60f3670..962c183 100644 --- a/src/modules/ctypes/linux/gtk.jsm +++ b/src/modules/ctypes/linux/gtk.jsm @@ -116,6 +116,8 @@ function gtk_defines(lib) { lib.lazy_bind("gtk_widget_get_parent_window", gdk.GdkWindow.ptr, this.GtkWidget.ptr); lib.lazy_bind("gtk_window_set_decorated", ctypes.void_t, this.GtkWindow.ptr, gobject.gboolean); + 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_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); diff --git a/src/modules/linux/FiretrayIMStatusIcon.jsm b/src/modules/linux/FiretrayIMStatusIcon.jsm index 008c7d3..9e10547 100644 --- a/src/modules/linux/FiretrayIMStatusIcon.jsm +++ b/src/modules/linux/FiretrayIMStatusIcon.jsm @@ -43,6 +43,7 @@ firetray.IMStatusIcon = { this.trayIcon = gtk.gtk_status_icon_new(); this.loadThemedIcons(); this.setIconImage(FIRETRAY_IM_STATUS_OFFLINE); + this.setIconTooltipDefault(); this.initialized = true; return true; @@ -81,7 +82,16 @@ firetray.IMStatusIcon = { gtk.gtk_status_icon_set_blinking(this.trayIcon, blink); }, - /* we could also use x11.FocusIn... just wanted to try a different method */ + setIconTooltip: function(txt) { + if (!this.trayIcon) return false; + gtk.gtk_status_icon_set_tooltip_text(this.trayIcon, txt); + return true; + }, + + setIconTooltipDefault: function() { + this.setIconTooltip(firetray.Handler.appName+" Chat"); + }, + attachOnFocusInCallback: function(xid) { F.LOG("attachOnFocusInCallback xid="+xid); this.callbacks.onFocusIn[xid] = gtk.GCallbackWidgetFocuEvent_t(firetray.IMStatusIcon.onFocusIn); diff --git a/src/modules/linux/FiretrayWindow.jsm b/src/modules/linux/FiretrayWindow.jsm index 2c54ddc..090ddc0 100644 --- a/src/modules/linux/FiretrayWindow.jsm +++ b/src/modules/linux/FiretrayWindow.jsm @@ -595,8 +595,7 @@ firetray.Handler.registerWindow = function(win) { this.windows[xid].filterWindowCb = gdk.GdkFilterFunc_t(firetray.Window.filterWindow); gdk.gdk_window_add_filter(gdkWin, this.windows[xid].filterWindowCb, null); - // FIXME: isn't it (c)leaner to do it in x11 window filter ? - if (firetray.Handler.isIMEnabled) { + if (firetray.Handler.inMailApp && firetray.InstantMessaging.initialized) { // missing import ok Cu.import("resource://firetray/linux/FiretrayIMStatusIcon.jsm"); firetray.IMStatusIcon.attachOnFocusInCallback(xid); } @@ -662,17 +661,26 @@ firetray.Handler.activateLastWindow = function(gtkStatusIcon, gdkEvent, userData return stopPropagation; }; +/* gtk_window_is_active() not reliable */ firetray.Handler.findActiveWindow = function() { + let rootWin = x11.XDefaultRootWindow(x11.current.Display); + let [propsFound, nitems] = + firetray.Window.getXWindowProperties(rootWin, x11.current.Atoms._NET_ACTIVE_WINDOW); + + F.LOG("ACTIVE_WINDOW propsFound, nitems="+propsFound+", "+nitems); + if (!propsFound) return null; + let activeWin = null; - for (let xid in firetray.Handler.windows) { - let gtkWin = firetray.Handler.gtkWindows.get(xid); - let isActive = gtk.gtk_window_is_active(gtkWin); - F.LOG(xid+" is active="+isActive); - if (isActive) { - activeWin = xid; - break; - } - } + if (firetray.js.strEquals(nitems.value, 0)) + F.WARN("active window not found"); + else if (firetray.js.strEquals(nitems.value, 1)) + activeWin = propsFound.contents[0]; + else + throw new RangeError("more than one active window found"); + + x11.XFree(propsFound); + + F.LOG("ACTIVE_WINDOW="+activeWin); return activeWin; }; From 06349f15f4c2d46065282f0942f0a3806275b4fc Mon Sep 17 00:00:00 2001 From: foudfou Date: Sat, 25 Aug 2012 19:18:33 +0200 Subject: [PATCH 13/18] * rename all IM/Chat-related modules consistently with "Chat" keyword * stopIconBlinkingMaybe() only when acknowledgeOnFocus.must --- ...yInstantMessaging.jsm => FiretrayChat.jsm} | 30 +++++++++---------- src/modules/FiretrayMessaging.jsm | 14 ++++----- ...tusIcon.jsm => FiretrayChatStatusIcon.jsm} | 16 +++++----- src/modules/linux/FiretrayWindow.jsm | 6 ++-- 4 files changed, 33 insertions(+), 33 deletions(-) rename src/modules/{FiretrayInstantMessaging.jsm => FiretrayChat.jsm} (83%) rename src/modules/linux/{FiretrayIMStatusIcon.jsm => FiretrayChatStatusIcon.jsm} (88%) diff --git a/src/modules/FiretrayInstantMessaging.jsm b/src/modules/FiretrayChat.jsm similarity index 83% rename from src/modules/FiretrayInstantMessaging.jsm rename to src/modules/FiretrayChat.jsm index 57b3795..fd00b31 100644 --- a/src/modules/FiretrayInstantMessaging.jsm +++ b/src/modules/FiretrayChat.jsm @@ -8,44 +8,44 @@ const Cu = Components.utils; Cu.import("resource:///modules/imServices.jsm"); Cu.import("resource://firetray/commons.js"); -Cu.import("resource://firetray/linux/FiretrayIMStatusIcon.jsm"); +Cu.import("resource://firetray/linux/FiretrayChatStatusIcon.jsm"); // FIXME: rename to firetray.Chat -firetray.InstantMessaging = { +firetray.Chat = { initialized: false, observedTopics: {}, acknowledgeOnFocus: {}, init: function() { if (this.initialized) { - F.WARN("InstantMessaging already initialized"); + F.WARN("Chat already initialized"); return; } - F.LOG("Enabling InstantMessaging"); + F.LOG("Enabling Chat"); - firetray.Utils.addObservers(firetray.InstantMessaging, [ + firetray.Utils.addObservers(firetray.Chat, [ // "*" // debugging "account-connected", "account-disconnected", "idle-time-changed", "new-directed-incoming-message", "status-changed", "unread-im-count-changed" ]); - firetray.IMStatusIcon.init(); + firetray.ChatStatusIcon.init(); this.initialized = true; }, shutdown: function() { if (!this.initialized) return; - F.LOG("Disabling InstantMessaging"); + F.LOG("Disabling Chat"); - firetray.IMStatusIcon.shutdown(); - firetray.Utils.removeAllObservers(firetray.InstantMessaging); + firetray.ChatStatusIcon.shutdown(); + firetray.Utils.removeAllObservers(firetray.Chat); this.initialized = false; }, observe: function(subject, topic, data) { - F.LOG("RECEIVED InstantMessaging: "+topic+" subject="+subject+" data="+data); + F.LOG("RECEIVED Chat: "+topic+" subject="+subject+" data="+data); switch (topic) { case "account-connected": case "account-disconnected": @@ -63,7 +63,7 @@ firetray.InstantMessaging = { if (!convIsActiveTabInActiveWin) { // don't blink when conv tab already on top this.acknowledgeOnFocus.must = true; this.acknowledgeOnFocus.conv = conv; - firetray.IMStatusIcon.setIconBlinking(true); + firetray.ChatStatusIcon.setIconBlinking(true); } break; @@ -76,7 +76,7 @@ firetray.InstantMessaging = { unreadMsgCount, firetray.Utils.strings.GetStringFromName("tooltip.unread_messages")) .replace("#1", unreadMsgCount); - firetray.IMStatusIcon.setIconTooltip(localizedTooltip); + firetray.ChatStatusIcon.setIconTooltip(localizedTooltip); break; default: @@ -86,14 +86,14 @@ firetray.InstantMessaging = { stopIconBlinkingMaybe: function() { F.LOG("acknowledgeOnFocus.must="+this.acknowledgeOnFocus.must); - // if (!this.acknowledgeOnFocus.must) return; + if (!this.acknowledgeOnFocus.must) return; let convIsActiveTabInActiveWin = this.isConvActiveTabInActiveWindow( this.acknowledgeOnFocus.conv); F.LOG("convIsActiveTabInActiveWin="+convIsActiveTabInActiveWin); if (this.acknowledgeOnFocus.must && convIsActiveTabInActiveWin) { - firetray.IMStatusIcon.setIconBlinking(false); + firetray.ChatStatusIcon.setIconBlinking(false); this.acknowledgeOnFocus.must = false; } }, @@ -145,7 +145,7 @@ firetray.InstantMessaging = { F.LOG("IM status changed="+iconName); if (iconName) - firetray.IMStatusIcon.setIconImage(iconName); + firetray.ChatStatusIcon.setIconImage(iconName); } }; diff --git a/src/modules/FiretrayMessaging.jsm b/src/modules/FiretrayMessaging.jsm index effb594..a9f4012 100644 --- a/src/modules/FiretrayMessaging.jsm +++ b/src/modules/FiretrayMessaging.jsm @@ -9,7 +9,7 @@ const Cu = Components.utils; Cu.import("resource:///modules/mailServices.js"); Cu.import("resource://gre/modules/PluralForm.jsm"); Cu.import("resource://firetray/commons.js"); -Cu.import("resource://firetray/FiretrayInstantMessaging.jsm"); +Cu.import("resource://firetray/FiretrayChat.jsm"); const FLDRS_UNINTERESTING = { Archive: Ci.nsMsgFolderFlags.Archive, @@ -45,7 +45,7 @@ firetray.Messaging = { // FIXME: add im-icon pref if (Services.prefs.getBoolPref("mail.chat.enabled") && this.existsIMAccount()) - firetray.InstantMessaging.init(); + firetray.Chat.init(); this.initialized = true; }, @@ -54,7 +54,7 @@ firetray.Messaging = { if (!this.initialized) return; F.LOG("Disabling Messaging"); - firetray.InstantMessaging.shutdown(); + firetray.Chat.shutdown(); MailServices.mailSession.RemoveFolderListener(this.mailSessionListener); @@ -63,7 +63,7 @@ firetray.Messaging = { this.initialized = false; }, - // FIXME: this should definetely be done in InstantMessaging, but IM accounts + // FIXME: this should definetely be done in Chat, but IM accounts // seem not be initialized at this stage (Exception... "'TypeError: // this._items is undefined' when calling method: // [nsISimpleEnumerator::hasMoreElements]"), and we're unsure if we should @@ -85,11 +85,11 @@ firetray.Messaging = { case "account-removed": this.cleanExcludedAccounts(); if (subject.QueryInterface(Ci.imIAccount) && !this.existsIMAccount()) - firetray.InstantMessaging.shutdown(); + firetray.Chat.shutdown(); break; case "account-added": - if (subject.QueryInterface(Ci.imIAccount) && !firetray.InstantMessaging.initialized) - firetray.InstantMessaging.init(); + if (subject.QueryInterface(Ci.imIAccount) && !firetray.Chat.initialized) + firetray.Chat.init(); break; default: F.WARN("unhandled topic: "+topic); diff --git a/src/modules/linux/FiretrayIMStatusIcon.jsm b/src/modules/linux/FiretrayChatStatusIcon.jsm similarity index 88% rename from src/modules/linux/FiretrayIMStatusIcon.jsm rename to src/modules/linux/FiretrayChatStatusIcon.jsm index 9e10547..83d57f6 100644 --- a/src/modules/linux/FiretrayIMStatusIcon.jsm +++ b/src/modules/linux/FiretrayChatStatusIcon.jsm @@ -21,7 +21,7 @@ if ("undefined" == typeof(firetray.Handler)) F.ERROR("This module MUST be imported from/after FiretrayHandler !"); -firetray.IMStatusIcon = { +firetray.ChatStatusIcon = { GTK_THEME_ICON_PATH: null, initialized: false, @@ -37,7 +37,7 @@ firetray.IMStatusIcon = { callbacks: {onFocusIn: {}}, init: function() { - if (!firetray.Handler.inMailApp) throw "IMStatusIcon for mail app only"; + if (!firetray.Handler.inMailApp) throw "ChatStatusIcon for mail app only"; if (!firetray.GtkIcons.initialized) throw "GtkIcons should have been initialized by StatusIcon"; this.trayIcon = gtk.gtk_status_icon_new(); @@ -68,10 +68,10 @@ firetray.IMStatusIcon = { }, setIconImageFromGIcon: function(gicon) { - if (!firetray.IMStatusIcon.trayIcon || !gicon) + if (!firetray.ChatStatusIcon.trayIcon || !gicon) F.ERROR("Icon missing"); F.LOG(gicon); - gtk.gtk_status_icon_set_from_gicon(firetray.IMStatusIcon.trayIcon, gicon); + gtk.gtk_status_icon_set_from_gicon(firetray.ChatStatusIcon.trayIcon, gicon); }, setIconImage: function(name) { @@ -94,9 +94,9 @@ firetray.IMStatusIcon = { attachOnFocusInCallback: function(xid) { F.LOG("attachOnFocusInCallback xid="+xid); - this.callbacks.onFocusIn[xid] = gtk.GCallbackWidgetFocuEvent_t(firetray.IMStatusIcon.onFocusIn); + this.callbacks.onFocusIn[xid] = gtk.GCallbackWidgetFocuEvent_t(firetray.ChatStatusIcon.onFocusIn); gobject.g_signal_connect(firetray.Handler.gtkWindows.get(xid), - "focus-in-event", firetray.IMStatusIcon.callbacks.onFocusIn[xid], null); + "focus-in-event", firetray.ChatStatusIcon.callbacks.onFocusIn[xid], null); }, // NOTE: fluxbox issues a FocusIn event when switching workspace by hotkey :( @@ -107,9 +107,9 @@ firetray.IMStatusIcon = { // let gdkWin = gdkEventFocus.contents.window; // let xid = firetray.Window.getXIDFromGdkWindow(gdkWin); // F.LOG("xid="+xid+" in="+gdkEventFocus.contents["in"]); - firetray.InstantMessaging.stopIconBlinkingMaybe(); + firetray.Chat.stopIconBlinkingMaybe(); } // FIXME: TODO: onclick/activate -> chatHandler.showCurrentConversation() -}; // firetray.IMStatusIcon +}; // firetray.ChatStatusIcon diff --git a/src/modules/linux/FiretrayWindow.jsm b/src/modules/linux/FiretrayWindow.jsm index 090ddc0..c6424f0 100644 --- a/src/modules/linux/FiretrayWindow.jsm +++ b/src/modules/linux/FiretrayWindow.jsm @@ -595,9 +595,9 @@ firetray.Handler.registerWindow = function(win) { this.windows[xid].filterWindowCb = gdk.GdkFilterFunc_t(firetray.Window.filterWindow); gdk.gdk_window_add_filter(gdkWin, this.windows[xid].filterWindowCb, null); - if (firetray.Handler.inMailApp && firetray.InstantMessaging.initialized) { // missing import ok - Cu.import("resource://firetray/linux/FiretrayIMStatusIcon.jsm"); - firetray.IMStatusIcon.attachOnFocusInCallback(xid); + if (firetray.Handler.inMailApp && firetray.Chat.initialized) { // missing import ok + Cu.import("resource://firetray/linux/FiretrayChatStatusIcon.jsm"); + firetray.ChatStatusIcon.attachOnFocusInCallback(xid); } } catch (x) { From 693611c9942756432e4335a69e4b3ae79b32059f Mon Sep 17 00:00:00 2001 From: foudfou Date: Sat, 25 Aug 2012 21:45:00 +0200 Subject: [PATCH 14/18] * add chat_icon_enable pref * fix globaluserStatus with all IM accounts disconnected * cleaning --- src/chrome/content/options.js | 9 ++++++ src/chrome/content/options.xul | 45 +++++++++++++++++++---------- src/chrome/locale/en-US/options.dtd | 36 +++++++++++++---------- src/defaults/preferences/prefs.js | 1 + src/modules/FiretrayChat.jsm | 36 ++++++++++++++++------- src/modules/FiretrayMessaging.jsm | 9 +++--- 6 files changed, 90 insertions(+), 46 deletions(-) diff --git a/src/chrome/content/options.js b/src/chrome/content/options.js index 96402cd..2239b53 100644 --- a/src/chrome/content/options.js +++ b/src/chrome/content/options.js @@ -5,6 +5,7 @@ const Ci = Components.interfaces; const Cu = Components.utils; Cu.import("resource://firetray/FiretrayHandler.jsm"); +Cu.import("resource://firetray/FiretrayChat.jsm"); Cu.import("resource://firetray/commons.js"); const TREEROW_ACCOUNT_OR_SERVER_TYPE_NAME = 0; @@ -592,6 +593,14 @@ var firetrayUIOptions = { if (!/\d/.test(charStr)) event.preventDefault(); } + }, + + toggleChat: function(enabled) { + F.LOG("Chat icon enable="+enabled); + if (enabled) + firetray.Chat.init(); + else + firetray.Chat.shutdown(); } }; diff --git a/src/chrome/content/options.xul b/src/chrome/content/options.xul index c42002a..3fea56b 100644 --- a/src/chrome/content/options.xul +++ b/src/chrome/content/options.xul @@ -30,6 +30,7 @@ + @@ -44,6 +45,7 @@ + @@ -51,27 +53,27 @@ + label="&hides_single_window.label;" + accesskey="&hides_single_window.accesskey;" + tooltiptext="&hides_single_window.tooltip;"/> + label="&start_hidden.label;" + accesskey="&start_hidden.accesskey;"/> + label="&show_activates.label;" + accesskey="&show_activates.accesskey;" + tooltiptext="&show_activates.tooltip;"/> + label="&remember_desktop.label;" + accesskey="&remember_desktop.accesskey;"/> @@ -113,8 +115,8 @@ + label="&show_icon_on_hide.label;" + accesskey="&show_icon_on_hide.accesskey;"/> + + + + + + + + diff --git a/src/chrome/locale/en-US/options.dtd b/src/chrome/locale/en-US/options.dtd index 9dd80d1..6087848 100644 --- a/src/chrome/locale/en-US/options.dtd +++ b/src/chrome/locale/en-US/options.dtd @@ -7,24 +7,25 @@ + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + + @@ -77,3 +78,6 @@ + + + diff --git a/src/defaults/preferences/prefs.js b/src/defaults/preferences/prefs.js index e02085b..bdce715 100644 --- a/src/defaults/preferences/prefs.js +++ b/src/defaults/preferences/prefs.js @@ -20,6 +20,7 @@ pref("extensions.firetray.new_mail_icon_names", '["indicator-messages-new", "mai pref("extensions.firetray.show_icon_on_hide", false); pref("extensions.firetray.scroll_hides", true); pref("extensions.firetray.scroll_mode", "down_hides"); +pref("extensions.firetray.chat_icon_enable", true); pref("extensions.firetray.message_count_type", 0); pref("extensions.firetray.mail_notification_enabled", true); diff --git a/src/modules/FiretrayChat.jsm b/src/modules/FiretrayChat.jsm index fd00b31..0f7d756 100644 --- a/src/modules/FiretrayChat.jsm +++ b/src/modules/FiretrayChat.jsm @@ -10,7 +10,6 @@ Cu.import("resource:///modules/imServices.jsm"); Cu.import("resource://firetray/commons.js"); Cu.import("resource://firetray/linux/FiretrayChatStatusIcon.jsm"); -// FIXME: rename to firetray.Chat firetray.Chat = { initialized: false, observedTopics: {}, @@ -118,27 +117,32 @@ firetray.Chat = { }, updateIcon: function() { - let userStatus = Services.core.globalUserStatus.statusType; + let globalConnectedStatus = this.globalConnectedStatus(); + let userStatus; + if (globalConnectedStatus) + userStatus = Services.core.globalUserStatus.statusType; + else + userStatus = Ci.imIStatusInfo.STATUS_OFFLINE; F.LOG("IM status="+userStatus); let iconName; switch (userStatus) { - case Ci.imIStatusInfo.STATUS_OFFLINE: + case Ci.imIStatusInfo.STATUS_OFFLINE: // 1 iconName = FIRETRAY_IM_STATUS_OFFLINE; break; - case Ci.imIStatusInfo.STATUS_IDLE: - case Ci.imIStatusInfo.STATUS_AWAY: + case Ci.imIStatusInfo.STATUS_IDLE: // 4 + case Ci.imIStatusInfo.STATUS_AWAY: // 5 iconName = FIRETRAY_IM_STATUS_AWAY; break; - case Ci.imIStatusInfo.STATUS_AVAILABLE: + case Ci.imIStatusInfo.STATUS_AVAILABLE: // 7 iconName = FIRETRAY_IM_STATUS_AVAILABLE; break; - case Ci.imIStatusInfo.STATUS_UNAVAILABLE: + case Ci.imIStatusInfo.STATUS_UNAVAILABLE: // 6 iconName = FIRETRAY_IM_STATUS_BUSY; break; - case Ci.imIStatusInfo.STATUS_UNKNOWN: - case Ci.imIStatusInfo.STATUS_INVISIBLE: - case Ci.imIStatusInfo.STATUS_MOBILE: + case Ci.imIStatusInfo.STATUS_UNKNOWN: // 0 + case Ci.imIStatusInfo.STATUS_INVISIBLE: // 2 + case Ci.imIStatusInfo.STATUS_MOBILE: // 3 default: // ignore } @@ -146,6 +150,18 @@ firetray.Chat = { F.LOG("IM status changed="+iconName); if (iconName) firetray.ChatStatusIcon.setIconImage(iconName); + }, + + globalConnectedStatus: function() { + let accounts = Services.accounts.getAccounts(); + let globalConnected = false; + while (accounts.hasMoreElements()) { + let account = accounts.getNext().QueryInterface(Ci.imIAccount); + F.LOG("account="+account+" STATUS="+account.statusInfo.statusType+" connected="+account.connected); + globalConnected = globalConnected || account.connected; + } + F.LOG("globalConnected="+globalConnected); + return globalConnected; } }; diff --git a/src/modules/FiretrayMessaging.jsm b/src/modules/FiretrayMessaging.jsm index a9f4012..8938090 100644 --- a/src/modules/FiretrayMessaging.jsm +++ b/src/modules/FiretrayMessaging.jsm @@ -43,8 +43,9 @@ firetray.Messaging = { MailServices.mailSession.AddFolderListener(that.mailSessionListener, that.mailSessionListener.notificationFlags); - // FIXME: add im-icon pref - if (Services.prefs.getBoolPref("mail.chat.enabled") && this.existsIMAccount()) + if (Services.prefs.getBoolPref("mail.chat.enabled") && + firetray.Utils.prefService.getBoolPref("chat_icon_enable") && + this.existsChatAccount()) firetray.Chat.init(); this.initialized = true; @@ -68,7 +69,7 @@ firetray.Messaging = { // this._items is undefined' when calling method: // [nsISimpleEnumerator::hasMoreElements]"), and we're unsure if we should // initAccounts() ourselves... - existsIMAccount: function() { + existsChatAccount: function() { let accounts = new this.Accounts(); for (let accountServer in accounts) if (accountServer.type === 'im') { @@ -84,7 +85,7 @@ firetray.Messaging = { switch (topic) { case "account-removed": this.cleanExcludedAccounts(); - if (subject.QueryInterface(Ci.imIAccount) && !this.existsIMAccount()) + if (subject.QueryInterface(Ci.imIAccount) && !this.existsChatAccount()) firetray.Chat.shutdown(); break; case "account-added": From aaef6a1544a625732e3eb004991f9259037e324e Mon Sep 17 00:00:00 2001 From: foudfou Date: Wed, 29 Aug 2012 11:46:12 +0200 Subject: [PATCH 15/18] experimental handling of Exquilla accounts --- src/defaults/preferences/prefs.js | 2 +- src/modules/FiretrayHandler.jsm | 14 ++++++++++++-- src/modules/FiretrayMessaging.jsm | 5 ++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/defaults/preferences/prefs.js b/src/defaults/preferences/prefs.js index bdce715..13386fe 100644 --- a/src/defaults/preferences/prefs.js +++ b/src/defaults/preferences/prefs.js @@ -32,4 +32,4 @@ pref("extensions.firetray.folder_count_recursive", true); // Ci.nsMsgFolderFlags.Archive|Drafts|Junk|Queue|SentMail|Trash|Virtual pref("extensions.firetray.excluded_folders_flags", 1077956384); // exposed in 1 tree, hence 2 branches: serverTypes, excludedAccounts -pref("extensions.firetray.mail_accounts", '{ "serverTypes": {"pop3":{"order":1,"excluded":false}, "imap":{"order":1,"excluded":false}, "movemail":{"order":2,"excluded":true}, "none":{"order":3,"excluded":false}, "rss":{"order":4,"excluded":true}, "nntp":{"order":5,"excluded":true}}, "excludedAccounts": [] }'); // JSON +pref("extensions.firetray.mail_accounts", '{ "serverTypes": {"pop3":{"order":1,"excluded":false}, "imap":{"order":1,"excluded":false}, "movemail":{"order":2,"excluded":true}, "none":{"order":3,"excluded":false}, "rss":{"order":4,"excluded":true}, "nntp":{"order":5,"excluded":true}, "exquilla":{"order":6,"excluded":true}}, "excludedAccounts": [] }'); // JSON diff --git a/src/modules/FiretrayHandler.jsm b/src/modules/FiretrayHandler.jsm index de531ad..7529512 100644 --- a/src/modules/FiretrayHandler.jsm +++ b/src/modules/FiretrayHandler.jsm @@ -82,6 +82,7 @@ firetray.Handler = { VersionChange.addHook(["install", "upgrade", "reinstall"], firetray.VersionChangeHandler.showReleaseNotes); VersionChange.addHook(["upgrade", "reinstall"], firetray.VersionChangeHandler.tryEraseOldOptions); VersionChange.addHook(["upgrade", "reinstall"], firetray.VersionChangeHandler.correctMailNotificationType); + VersionChange.addHook(["upgrade", "reinstall"], firetray.VersionChangeHandler.correctMailServerTypes); VersionChange.applyHooksAndWatchUninstall(); firetray.StatusIcon.init(); @@ -363,8 +364,6 @@ firetray.VersionChangeHandler = { showReleaseNotes: function() { firetray.VersionChangeHandler.openTab(FIRETRAY_SPLASH_PAGE+"#v"+FIRETRAY_VERSION); - firetray.VersionChangeHandler.tryEraseOldOptions(); - firetray.VersionChangeHandler.correctMailNotificationType(); }, openTab: function(url) { @@ -438,6 +437,17 @@ firetray.VersionChangeHandler = { FIRETRAY_NOTIFICATION_NEWMAIL_ICON); F.WARN("mail notification type set to newmail icon."); } + }, + + correctMailServerTypes: function() { + let mailAccounts = firetray.Utils.getObjPref('mail_accounts'); + let serverTypes = mailAccounts["serverTypes"]; + if (!serverTypes["exquilla"]) { + serverTypes["exquilla"] = {"order":6,"excluded":true}; + let prefObj = {"serverTypes":serverTypes, "excludedAccounts":mailAccounts["excludedAccounts"]}; + firetray.Utils.setObjPref('mail_accounts', prefObj); + F.WARN("mail server types corrected"); + } } }; diff --git a/src/modules/FiretrayMessaging.jsm b/src/modules/FiretrayMessaging.jsm index 8938090..be9e6be 100644 --- a/src/modules/FiretrayMessaging.jsm +++ b/src/modules/FiretrayMessaging.jsm @@ -274,7 +274,10 @@ firetray.Messaging = { try { let accounts = new this.Accounts(); for (let accountServer in accounts) { - if (accountServer.type === 'im') continue; // IM messages are counted elsewhere + if (!serverTypes[accountServer.type]) { + F.WARN("'"+accountServer.type+"' server type is not handled"); + continue; + } F.LOG("is servertype excluded: "+serverTypes[accountServer.type].excluded+", account exclusion index: "+excludedAccounts.indexOf(accountServer.key)); if (serverTypes[accountServer.type].excluded || (excludedAccounts.indexOf(accountServer.key) >= 0)) From 29dac883b9d2579cf1d5f7eda1f23ebec8eba45e Mon Sep 17 00:00:00 2001 From: foudfou Date: Mon, 3 Sep 2012 08:23:37 +0200 Subject: [PATCH 16/18] ignore server type 'im' silently for message count --- src/modules/FiretrayMessaging.jsm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/FiretrayMessaging.jsm b/src/modules/FiretrayMessaging.jsm index be9e6be..b5199eb 100644 --- a/src/modules/FiretrayMessaging.jsm +++ b/src/modules/FiretrayMessaging.jsm @@ -274,7 +274,9 @@ firetray.Messaging = { try { let accounts = new this.Accounts(); for (let accountServer in accounts) { - if (!serverTypes[accountServer.type]) { + if (accountServer.type === 'im') { + continue; // IM messages are counted elsewhere + } else if (!serverTypes[accountServer.type]) { F.WARN("'"+accountServer.type+"' server type is not handled"); continue; } From 747ab637d987bbfd73573a5fd83d335045786edb Mon Sep 17 00:00:00 2001 From: foudfou Date: Mon, 3 Sep 2012 16:45:57 +0200 Subject: [PATCH 17/18] attempt to asynchronously get addon version from AddonManager --- src/modules/FiretrayHandler.jsm | 3 +-- src/modules/VersionChange.jsm | 38 ++++++++++++++------------------- 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/src/modules/FiretrayHandler.jsm b/src/modules/FiretrayHandler.jsm index 7529512..aab8a4b 100644 --- a/src/modules/FiretrayHandler.jsm +++ b/src/modules/FiretrayHandler.jsm @@ -78,12 +78,11 @@ firetray.Handler = { this.appStartupTopic = this.getAppStartupTopic(this.appId); - VersionChange.init(FIRETRAY_ID, FIRETRAY_VERSION, FIRETRAY_PREF_BRANCH); VersionChange.addHook(["install", "upgrade", "reinstall"], firetray.VersionChangeHandler.showReleaseNotes); VersionChange.addHook(["upgrade", "reinstall"], firetray.VersionChangeHandler.tryEraseOldOptions); VersionChange.addHook(["upgrade", "reinstall"], firetray.VersionChangeHandler.correctMailNotificationType); VersionChange.addHook(["upgrade", "reinstall"], firetray.VersionChangeHandler.correctMailServerTypes); - VersionChange.applyHooksAndWatchUninstall(); + VersionChange.launch(); firetray.StatusIcon.init(); firetray.Handler.showHideIcon(); diff --git a/src/modules/VersionChange.jsm b/src/modules/VersionChange.jsm index 04fd1b7..112ed40 100644 --- a/src/modules/VersionChange.jsm +++ b/src/modules/VersionChange.jsm @@ -6,8 +6,7 @@ const Cu = Components.utils; Cu.import("resource://gre/modules/AddonManager.jsm"); Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://firetray/logging.jsm"); - +Cu.import("resource://firetray/commons.js"); /** * handles version changes. @@ -15,26 +14,21 @@ Cu.import("resource://firetray/logging.jsm"); */ var VersionChange = { - initialized: false, - addonId: null, + initialized: false, + addonId: FIRETRAY_ID, addonVersion: null, - addOnPrefs: null, + addonPrefs: (function(){return Services.prefs.getBranch(FIRETRAY_PREF_BRANCH);})(), - init: function(id, version, prefBranch) { - F.LOG("VersionChange got: id="+id+" ver="+version+" prefBranch="+prefBranch); - this.addOnId = id; - this.addonVersion = version; - this.addOnPrefs = Services.prefs.getBranch(prefBranch); - - this.initialized = true; + launch: function() { + AddonManager.getAddonByID(FIRETRAY_ID, this.applyHooksAndWatchUninstall.bind(this)); }, versionComparator: Cc["@mozilla.org/xpcom/version-comparator;1"] .getService(Ci.nsIVersionComparator), - applyHooksAndWatchUninstall: function() { - if (!this.initialized) throw "VersionChange not initialized"; - this.onVersionChange(this.addonVersion); // AddonManager.getAddonByID() async, whereas we need sync call + applyHooksAndWatchUninstall: function(addon) { + this.addonVersion = addon.version; + this.onVersionChange(this.addonVersion); AddonManager.addAddonListener(this.uninstallListener); F.LOG("version change watching enabled"); }, @@ -44,20 +38,20 @@ var VersionChange = { uninstallListener: { onUninstalling: function(addon) { if (addon.id !== this.addonId) return; - this.addOnPrefs.clearUserPref("installedVersion"); + this.addonPrefs.clearUserPref("installedVersion"); }, onOperationCancelled: function(addon) { if (addon.id !== this.addonId) return; let beingUninstalled = (addon.pendingOperations & AddonManager.PENDING_UNINSTALL) != 0; if (beingUninstalled) - this.addOnPrefs.clearUserPref("installedVersion"); + this.addonPrefs.clearUserPref("installedVersion"); } }, onVersionChange: function() { F.LOG("VERSION: "+this.addonVersion); - var firstrun = this.addOnPrefs.getBoolPref("firstrun"); + var firstrun = this.addonPrefs.getBoolPref("firstrun"); if (firstrun) { F.LOG("FIRST RUN"); @@ -66,10 +60,10 @@ var VersionChange = { } else { try { - var installedVersion = this.addOnPrefs.getCharPref("installedVersion"); + var installedVersion = this.addonPrefs.getCharPref("installedVersion"); var versionDelta = this.versionComparator.compare(this.addonVersion, installedVersion); if (versionDelta > 0) { - this.addOnPrefs.setCharPref("installedVersion", this.addonVersion); + this.addonPrefs.setCharPref("installedVersion", this.addonVersion); F.LOG("UPGRADE"); this._applyHooks("upgrade"); } @@ -84,8 +78,8 @@ var VersionChange = { }, initPrefs: function() { - this.addOnPrefs.setBoolPref("firstrun", false); - this.addOnPrefs.setCharPref("installedVersion", VersionChange.addonVersion); + this.addonPrefs.setBoolPref("firstrun", false); + this.addonPrefs.setCharPref("installedVersion", VersionChange.addonVersion); }, _hooks: [], // collection of callbacks {id: 1, categories: [], fun: function} From c7b23ad7180429b2567d7353e8149aa7d4d56195 Mon Sep 17 00:00:00 2001 From: foudfou Date: Mon, 3 Sep 2012 16:46:01 +0200 Subject: [PATCH 18/18] Revert "attempt to asynchronously get addon version from AddonManager" This reverts commit 747ab637d987bbfd73573a5fd83d335045786edb. --- src/modules/FiretrayHandler.jsm | 3 ++- src/modules/VersionChange.jsm | 38 +++++++++++++++++++-------------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/modules/FiretrayHandler.jsm b/src/modules/FiretrayHandler.jsm index aab8a4b..7529512 100644 --- a/src/modules/FiretrayHandler.jsm +++ b/src/modules/FiretrayHandler.jsm @@ -78,11 +78,12 @@ firetray.Handler = { this.appStartupTopic = this.getAppStartupTopic(this.appId); + VersionChange.init(FIRETRAY_ID, FIRETRAY_VERSION, FIRETRAY_PREF_BRANCH); VersionChange.addHook(["install", "upgrade", "reinstall"], firetray.VersionChangeHandler.showReleaseNotes); VersionChange.addHook(["upgrade", "reinstall"], firetray.VersionChangeHandler.tryEraseOldOptions); VersionChange.addHook(["upgrade", "reinstall"], firetray.VersionChangeHandler.correctMailNotificationType); VersionChange.addHook(["upgrade", "reinstall"], firetray.VersionChangeHandler.correctMailServerTypes); - VersionChange.launch(); + VersionChange.applyHooksAndWatchUninstall(); firetray.StatusIcon.init(); firetray.Handler.showHideIcon(); diff --git a/src/modules/VersionChange.jsm b/src/modules/VersionChange.jsm index 112ed40..04fd1b7 100644 --- a/src/modules/VersionChange.jsm +++ b/src/modules/VersionChange.jsm @@ -6,7 +6,8 @@ const Cu = Components.utils; Cu.import("resource://gre/modules/AddonManager.jsm"); Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://firetray/commons.js"); +Cu.import("resource://firetray/logging.jsm"); + /** * handles version changes. @@ -14,21 +15,26 @@ Cu.import("resource://firetray/commons.js"); */ var VersionChange = { - initialized: false, - addonId: FIRETRAY_ID, + initialized: false, + addonId: null, addonVersion: null, - addonPrefs: (function(){return Services.prefs.getBranch(FIRETRAY_PREF_BRANCH);})(), + addOnPrefs: null, - launch: function() { - AddonManager.getAddonByID(FIRETRAY_ID, this.applyHooksAndWatchUninstall.bind(this)); + init: function(id, version, prefBranch) { + F.LOG("VersionChange got: id="+id+" ver="+version+" prefBranch="+prefBranch); + this.addOnId = id; + this.addonVersion = version; + this.addOnPrefs = Services.prefs.getBranch(prefBranch); + + this.initialized = true; }, versionComparator: Cc["@mozilla.org/xpcom/version-comparator;1"] .getService(Ci.nsIVersionComparator), - applyHooksAndWatchUninstall: function(addon) { - this.addonVersion = addon.version; - this.onVersionChange(this.addonVersion); + applyHooksAndWatchUninstall: function() { + if (!this.initialized) throw "VersionChange not initialized"; + this.onVersionChange(this.addonVersion); // AddonManager.getAddonByID() async, whereas we need sync call AddonManager.addAddonListener(this.uninstallListener); F.LOG("version change watching enabled"); }, @@ -38,20 +44,20 @@ var VersionChange = { uninstallListener: { onUninstalling: function(addon) { if (addon.id !== this.addonId) return; - this.addonPrefs.clearUserPref("installedVersion"); + this.addOnPrefs.clearUserPref("installedVersion"); }, onOperationCancelled: function(addon) { if (addon.id !== this.addonId) return; let beingUninstalled = (addon.pendingOperations & AddonManager.PENDING_UNINSTALL) != 0; if (beingUninstalled) - this.addonPrefs.clearUserPref("installedVersion"); + this.addOnPrefs.clearUserPref("installedVersion"); } }, onVersionChange: function() { F.LOG("VERSION: "+this.addonVersion); - var firstrun = this.addonPrefs.getBoolPref("firstrun"); + var firstrun = this.addOnPrefs.getBoolPref("firstrun"); if (firstrun) { F.LOG("FIRST RUN"); @@ -60,10 +66,10 @@ var VersionChange = { } else { try { - var installedVersion = this.addonPrefs.getCharPref("installedVersion"); + var installedVersion = this.addOnPrefs.getCharPref("installedVersion"); var versionDelta = this.versionComparator.compare(this.addonVersion, installedVersion); if (versionDelta > 0) { - this.addonPrefs.setCharPref("installedVersion", this.addonVersion); + this.addOnPrefs.setCharPref("installedVersion", this.addonVersion); F.LOG("UPGRADE"); this._applyHooks("upgrade"); } @@ -78,8 +84,8 @@ var VersionChange = { }, initPrefs: function() { - this.addonPrefs.setBoolPref("firstrun", false); - this.addonPrefs.setCharPref("installedVersion", VersionChange.addonVersion); + this.addOnPrefs.setBoolPref("firstrun", false); + this.addOnPrefs.setCharPref("installedVersion", VersionChange.addonVersion); }, _hooks: [], // collection of callbacks {id: 1, categories: [], fun: function}